Home | History | Annotate | Line # | Download | only in ldpd
      1 /* $NetBSD: label.c,v 1.11 2013/07/31 06:58:23 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 <stddef.h>
     36 #include <stdlib.h>
     37 #include <string.h>
     38 
     39 #include "ldp.h"
     40 #include "tlv_stack.h"
     41 #include "mpls_routes.h"
     42 #include "label.h"
     43 #include "ldp_errors.h"
     44 
     45 static int labels_compare(void*, const void*, const void*);
     46 
     47 int min_label = MIN_LABEL, max_label = MAX_LABEL;
     48 
     49 static rb_tree_t labels_tree;
     50 static const rb_tree_ops_t tree_ops = {
     51 	.rbto_compare_nodes = labels_compare,
     52 	.rbto_compare_key = labels_compare,
     53 	.rbto_node_offset = offsetof(struct label, lbtree),
     54 	.rbto_context = NULL
     55 };
     56 
     57 void
     58 label_init()
     59 {
     60 
     61 	rb_tree_init(&labels_tree, &tree_ops);
     62 }
     63 
     64 static int
     65 labels_compare(void *context, const void *node1, const void *node2)
     66 {
     67 	const struct label *l1 = node1, *l2 = node2;
     68 	int ret;
     69 
     70 	if (__predict_false(l1->so_dest.sa.sa_family !=
     71 	    l2->so_dest.sa.sa_family))
     72 		return l1->so_dest.sa.sa_family > l2->so_dest.sa.sa_family ?
     73 		    1 : -1;
     74 
     75 	assert(l1->so_dest.sa.sa_len == l2->so_dest.sa.sa_len);
     76 	assert(l1->so_pref.sa.sa_len == l2->so_pref.sa.sa_len);
     77 
     78 	if ((ret = memcmp(&l1->so_dest.sa, &l2->so_dest.sa,
     79 	    l1->so_dest.sa.sa_len)) != 0)
     80 		return ret;
     81 	else
     82 		return memcmp(&l1->so_pref.sa, &l2->so_pref.sa,
     83 		    l1->so_pref.sa.sa_len);
     84 }
     85 
     86 /*
     87  * if binding == 0 it receives a free one
     88  */
     89 struct label   *
     90 label_add(const union sockunion * so_dest, const union sockunion * so_pref,
     91 	  const union sockunion * so_gate, uint32_t binding,
     92 	  const struct ldp_peer * p, uint32_t label, bool host)
     93 {
     94 	struct label   *l;
     95 	char	spreftmp[INET_ADDRSTRLEN];
     96 
     97 	l = calloc(1, sizeof(*l));
     98 
     99 	if (!l) {
    100 		fatalp("label_add: malloc problem\n");
    101 		return NULL;
    102 	}
    103 
    104 	assert(so_dest);
    105 	assert(so_pref);
    106 	assert(so_dest->sa.sa_family == so_pref->sa.sa_family);
    107 	assert(label_get(so_dest, so_pref) == NULL);
    108 
    109 	memcpy(&l->so_dest, so_dest, so_dest->sa.sa_len);
    110 	memcpy(&l->so_pref, so_pref, so_pref->sa.sa_len);
    111 
    112 	if (so_gate)
    113 		memcpy(&l->so_gate, so_gate, so_gate->sa.sa_len);
    114 	if (binding)
    115 		l->binding = binding;
    116 	else
    117 		l->binding = get_free_local_label();
    118 	l->p = p;
    119 	l->label = label;
    120 	l->host = host;
    121 
    122 	if (rb_tree_insert_node(&labels_tree, l) != l)
    123 		fatalp("label already in tree");
    124 
    125 	strlcpy(spreftmp, satos(&so_pref->sa), INET_ADDRSTRLEN);
    126 	warnp("[label_add] added binding %d for %s/%s\n", l->binding,
    127 	    satos(&so_dest->sa), spreftmp);
    128 
    129 	send_label_tlv_to_all(&(so_dest->sa),
    130 	    from_union_to_cidr(so_pref), l->binding);
    131 	return l;
    132 }
    133 
    134 /* Unlink a label */
    135 void
    136 label_del(struct label * l)
    137 {
    138 	warnp("[label_del] deleted binding %d for %s\n", l->binding,
    139 	   satos(&l->so_dest.sa));
    140 	rb_tree_remove_node(&labels_tree, l);
    141 	free(l);
    142 }
    143 
    144 /*
    145  * Delete or Reuse the old IPv4 route, delete MPLS route
    146  * readd = REATT_INET_CHANGE -> delete and recreate the INET route
    147  * readd = REATT_INET_DEL -> deletes INET route
    148  * readd = REATT_INET_NODEL -> doesn't touch the INET route
    149  */
    150 void
    151 label_reattach_route(struct label *l, int readd)
    152 {
    153 
    154 	warnp("[label_reattach_route] binding %d deleted\n",
    155 		l->binding);
    156 
    157 	/* No gateway ? */
    158 	if (l->so_gate.sa.sa_len == 0)
    159 		return;
    160 
    161 	if (readd == REATT_INET_CHANGE) {
    162 		/* Delete the tagged route and re-add IPv4 route */
    163 		delete_route(&l->so_dest,
    164 		    l->host ? NULL : &l->so_pref, NO_FREESO);
    165 		add_route(&l->so_dest,
    166 		    l->host ? NULL : &l->so_pref, &l->so_gate,
    167 		    NULL, NULL, NO_FREESO, RTM_READD);
    168 	} else if (readd == REATT_INET_DEL)
    169 		delete_route(&l->so_dest, l->host ? NULL : &l->so_pref,
    170 		    NO_FREESO);
    171 
    172 	/* Deletes the MPLS route */
    173 	if (l->binding >= min_label)
    174 		delete_route(make_mpls_union(l->binding), NULL, FREESO);
    175 
    176 	l->binding = MPLS_LABEL_IMPLNULL;
    177 	l->p = NULL;
    178 	l->label = 0;
    179 }
    180 /*
    181  * Get a label by dst and pref
    182  */
    183 struct label*
    184 label_get(const union sockunion *sodest, const union sockunion *sopref)
    185 {
    186 	struct label l;
    187 
    188 	memset(&l, 0, sizeof(l));
    189 	memcpy(&l.so_dest, sodest, sodest->sa.sa_len);
    190 	memcpy(&l.so_pref, sopref, sopref->sa.sa_len);
    191 
    192 	return rb_tree_find_node(&labels_tree, &l);
    193 }
    194 
    195 /*
    196  * Find all labels that points to a peer
    197  * and reattach them to IPv4
    198  */
    199 void
    200 label_reattach_all_peer_labels(const struct ldp_peer *p, int readd)
    201 {
    202 	struct label   *l;
    203 
    204 	RB_TREE_FOREACH(l, &labels_tree)
    205 		if (l->p == p)
    206 			label_reattach_route(l, readd);
    207 }
    208 
    209 /*
    210  * Find all labels that points to a peer
    211  * and delete them
    212  */
    213 void
    214 del_all_peer_labels(const struct ldp_peer * p, int readd)
    215 {
    216 	struct label   *l, *lnext;
    217 
    218 	RB_TREE_FOREACH(l, &labels_tree) {
    219 back_delete:
    220 		if(l->p != p)
    221 			continue;
    222 		label_reattach_route(l, readd);
    223 		lnext = rb_tree_iterate(&labels_tree, l, RB_DIR_RIGHT);
    224 		label_del(l);
    225 		if (lnext == NULL)
    226 			break;
    227 		l = lnext;
    228 		goto back_delete;
    229 	}
    230 }
    231 
    232 /*
    233  * Finds a label by its binding and deletes it
    234  */
    235 void
    236 label_del_by_binding(uint32_t binding, int readd)
    237 {
    238 	struct label   *l;
    239 
    240 	RB_TREE_FOREACH(l, &labels_tree)
    241 		if ((uint32_t)l->binding == binding) {
    242 			label_reattach_route(l, readd);
    243 			label_del(l);
    244 			break;
    245 		}
    246 }
    247 
    248 /*
    249  * For Compatibility with old bindinds code
    250  */
    251 struct label*
    252 label_get_by_prefix(const struct sockaddr *a, int prefixlen)
    253 {
    254 	const union sockunion *so_dest;
    255 	union sockunion *so_pref;
    256 	struct label *l;
    257 
    258 	so_dest = (const union sockunion *)a;
    259 	so_pref = from_cidr_to_union(prefixlen);
    260 
    261 	l = label_get(so_dest, so_pref);
    262 
    263 	free(so_pref);
    264 
    265 	return l;
    266 }
    267 
    268 /*
    269  * Get a free binding
    270  */
    271 uint32_t
    272 get_free_local_label()
    273 {
    274 	struct label *l;
    275 	int lbl;
    276 
    277 	for (lbl = min_label; lbl <= max_label; lbl++) {
    278 		RB_TREE_FOREACH(l, &labels_tree)
    279 			if (l->binding == lbl)
    280 				break;
    281 		if (l == NULL)
    282 			return lbl;
    283 	}
    284 	return 0;
    285 }
    286 
    287 /*
    288  * Announce peers that a label has changed its binding
    289  * by withdrawing it and reannouncing it
    290  */
    291 void
    292 announce_label_change(struct label *l)
    293 {
    294 	send_withdraw_tlv_to_all(&(l->so_dest.sa),
    295 		from_union_to_cidr(&(l->so_pref)));
    296 	send_label_tlv_to_all(&(l->so_dest.sa),
    297 		from_union_to_cidr(&(l->so_pref)),
    298 		l->binding);
    299 }
    300 
    301 void
    302 label_check_assoc(struct ldp_peer *p)
    303 {
    304 	struct label *l;
    305 	struct ldp_peer_address *wp;
    306 
    307 	RB_TREE_FOREACH(l, &labels_tree)
    308 		if (l->p == NULL && l->so_gate.sa.sa_family != 0)
    309 			SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses)
    310 				if (sockaddr_cmp(&l->so_gate.sa,
    311 				    &wp->address.sa) == 0) {
    312 					l->p = p;
    313 					l->label = MPLS_LABEL_IMPLNULL;
    314 					break;
    315 				}
    316 }
    317 
    318 struct label *
    319 label_get_right(struct label *l)
    320 {
    321 	if (l == NULL)
    322 		return RB_TREE_MIN(&labels_tree);
    323 	else
    324 		return rb_tree_iterate(&labels_tree, l, RB_DIR_RIGHT);
    325 }
    326