Home | History | Annotate | Line # | Download | only in ldpd
label.c revision 1.8
      1 /* $NetBSD: label.c,v 1.8 2013/07/18 06:07:45 kefren Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Mihai Chelaru <kefren (at) NetBSD.org>
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <netmpls/mpls.h>
     33 
     34 #include <assert.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 
     38 #include "ldp.h"
     39 #include "tlv_stack.h"
     40 #include "mpls_routes.h"
     41 #include "label.h"
     42 #include "ldp_errors.h"
     43 
     44 int	min_label = MIN_LABEL, max_label = MAX_LABEL;
     45 
     46 void
     47 label_init()
     48 {
     49 	SLIST_INIT(&label_head);
     50 }
     51 
     52 /*
     53  * if binding == 0 it receives a free one
     54  */
     55 struct label   *
     56 label_add(const union sockunion * so_dest, const union sockunion * so_pref,
     57 	  const union sockunion * so_gate, uint32_t binding,
     58 	  const struct ldp_peer * p, uint32_t label)
     59 {
     60 	struct label   *l;
     61 	char	spreftmp[INET_ADDRSTRLEN];
     62 
     63 	l = calloc(1, sizeof(*l));
     64 
     65 	if (!l) {
     66 		fatalp("label_add: malloc problem\n");
     67 		return NULL;
     68 	}
     69 
     70 	assert(so_dest);
     71 	assert(so_pref);
     72 	assert(so_dest->sa.sa_family == so_pref->sa.sa_family);
     73 	assert(label_get(so_dest, so_pref) == NULL);
     74 
     75 	memcpy(&l->so_dest, so_dest, so_dest->sa.sa_len);
     76 	memcpy(&l->so_pref, so_pref, so_pref->sa.sa_len);
     77 
     78 	if (so_gate)
     79 		memcpy(&l->so_gate, so_gate, so_gate->sa.sa_len);
     80 	if (binding)
     81 		l->binding = binding;
     82 	else
     83 		l->binding = get_free_local_label();
     84 	l->p = p;
     85 	l->label = label;
     86 
     87 	SLIST_INSERT_HEAD(&label_head, l, labels);
     88 
     89 	strlcpy(spreftmp, satos(&so_pref->sa), INET_ADDRSTRLEN);
     90 	warnp("[label_add] added binding %d for %s/%s\n", l->binding,
     91 	    satos(&so_dest->sa), spreftmp);
     92 
     93 	send_label_tlv_to_all(&(so_dest->sa),
     94 	    from_union_to_cidr(so_pref), l->binding);
     95 	return l;
     96 }
     97 
     98 /* Unlink a label */
     99 void
    100 label_del(struct label * l)
    101 {
    102 	warnp("[label_del] deleted binding %d for %s\n", l->binding,
    103 	   satos(&l->so_dest.sa));
    104 	SLIST_REMOVE(&label_head, l, label, labels);
    105 	free(l);
    106 }
    107 
    108 /*
    109  * Delete or Reuse the old IPv4 route, delete MPLS route (if any)
    110  */
    111 void
    112 label_reattach_route(struct label *l, int readd)
    113 {
    114 	union sockunion *u;
    115 	union sockunion emptysu;
    116 	struct rt_msg rg;
    117 	int oldbinding = l->binding;
    118 
    119 	warnp("[label_reattach_route] binding %d deleted\n",
    120 		l->binding);
    121 
    122 	l->p = NULL;
    123 	l->binding = MPLS_LABEL_IMPLNULL;
    124 
    125 	/* No gateway ? */
    126 	memset(&emptysu, 0, sizeof (union sockunion));
    127 	if (memcmp(&l->so_gate, &emptysu, sizeof(union sockunion)) == 0)
    128 		return;
    129 
    130 	if (l->label != MPLS_LABEL_IMPLNULL && readd == LDP_READD_CHANGE) {
    131 	/* Delete and re-add IPv4 route */
    132 		if (get_route(&rg, &l->so_dest, &l->so_pref, 1) == LDP_E_OK) {
    133 			delete_route(&l->so_dest, &l->so_pref, NO_FREESO);
    134 			add_route(&l->so_dest, &l->so_pref, &l->so_gate, NULL,
    135 			    NULL, NO_FREESO, RTM_READD);
    136 		} else if (from_union_to_cidr(&l->so_pref) == 32 &&
    137 		    l->so_dest.sa.sa_family == AF_INET &&
    138 		    get_route(&rg, &l->so_dest, NULL, 1) == LDP_E_OK) {
    139 			delete_route(&l->so_dest, NULL, NO_FREESO);
    140 			add_route(&l->so_dest, NULL, &l->so_gate, NULL, NULL,
    141 			    NO_FREESO, RTM_READD);
    142 		} else
    143 			add_route(&l->so_dest, &l->so_pref,
    144 			    &l->so_gate, NULL, NULL, NO_FREESO, RTM_READD);
    145 	} else
    146 		if (readd != LDP_READD_NODEL)
    147 			delete_route(&l->so_dest, &l->so_pref, NO_FREESO);
    148 
    149 	l->label = 0;
    150 
    151 	/* Deletes pure MPLS route */
    152 	if (oldbinding >= min_label) {
    153 		u = make_mpls_union(oldbinding);
    154 		delete_route(u, NULL, FREESO);
    155 	}
    156 }
    157 /*
    158  * Get a label by dst and pref
    159  */
    160 struct label*
    161 label_get(const union sockunion *sodest, const union sockunion *sopref)
    162 {
    163 	struct label *l;
    164 
    165 	SLIST_FOREACH (l, &label_head, labels)
    166 	    if (sodest->sin.sin_addr.s_addr ==
    167 		    l->so_dest.sin.sin_addr.s_addr &&
    168 		sopref->sin.sin_addr.s_addr ==
    169 		    l->so_pref.sin.sin_addr.s_addr)
    170 			return l;
    171 	return NULL;
    172 }
    173 
    174 /*
    175  * Find all labels that points to a peer
    176  * and reattach them to IPv4
    177  */
    178 void
    179 label_reattach_all_peer_labels(const struct ldp_peer *p, int readd)
    180 {
    181 	struct label   *l;
    182 
    183 	SLIST_FOREACH(l, &label_head, labels)
    184 		if (l->p == p)
    185 			label_reattach_route(l, readd);
    186 }
    187 
    188 /*
    189  * Find all labels that points to a peer
    190  * and delete them
    191  */
    192 void
    193 del_all_peer_labels(const struct ldp_peer * p, int readd)
    194 {
    195 	struct label   *l, *lnext;
    196 
    197 	SLIST_FOREACH_SAFE(l, &label_head, labels, lnext) {
    198 		if(l->p != p)
    199 			continue;
    200 		label_reattach_route(l, readd);
    201 		label_del(l);
    202 		SLIST_REMOVE(&label_head, l, label, labels);
    203 	}
    204 }
    205 
    206 /*
    207  * Finds a label by its binding and deletes it
    208  */
    209 void
    210 label_del_by_binding(uint32_t binding, int readd)
    211 {
    212 	struct label   *l;
    213 
    214 	SLIST_FOREACH(l, &label_head, labels)
    215 		if ((uint32_t)l->binding == binding) {
    216 			label_reattach_route(l, readd);
    217 			label_del(l);
    218 			SLIST_REMOVE(&label_head, l, label, labels);
    219 			break;
    220 		}
    221 }
    222 
    223 /*
    224  * For Compatibility with old bindinds code
    225  */
    226 struct label*
    227 label_get_by_prefix(const struct sockaddr *a, int prefixlen)
    228 {
    229 	const union sockunion *so_dest;
    230 	union sockunion *so_pref;
    231 	struct label *l;
    232 
    233 	so_dest = (const union sockunion *)a;
    234 	so_pref = from_cidr_to_union(prefixlen);
    235 
    236 	l = label_get(so_dest, so_pref);
    237 
    238 	free(so_pref);
    239 
    240 	return l;
    241 }
    242 
    243 /*
    244  * Get a free binding
    245  */
    246 uint32_t
    247 get_free_local_label()
    248 {
    249 	struct label *l;
    250 	int lbl;
    251 
    252 	for (lbl = min_label; lbl <= max_label; lbl++) {
    253 		SLIST_FOREACH(l, &label_head, labels)
    254 			if (l->binding == lbl)
    255 				break;
    256 		if (l == NULL)
    257 			return lbl;
    258 	}
    259 	return 0;
    260 }
    261 
    262 /*
    263  * Change local binding
    264  */
    265 void
    266 change_local_label(struct label *l, uint32_t newbind)
    267 {
    268 	send_withdraw_tlv_to_all(&(l->so_dest.sa),
    269 		from_union_to_cidr(&(l->so_pref)));
    270 	l->binding = newbind;
    271 	send_label_tlv_to_all(&(l->so_dest.sa),
    272 		from_union_to_cidr(&(l->so_pref)),
    273 		l->binding);
    274 }
    275 
    276 void
    277 label_check_assoc(struct ldp_peer *p)
    278 {
    279 	struct label *l;
    280 	struct ldp_peer_address *wp;
    281 
    282 	SLIST_FOREACH (l, &label_head, labels)
    283 		if (l->p == NULL && l->so_gate.sa.sa_family != 0)
    284 			SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses)
    285 				if (sockaddr_cmp(&l->so_gate.sa,
    286 				    &wp->address.sa) == 0){
    287 					l->p = p;
    288 					l->label = MPLS_LABEL_IMPLNULL;
    289 					break;
    290 				}
    291 }
    292