Home | History | Annotate | Line # | Download | only in ldpd
label.c revision 1.10
      1 /* $NetBSD: label.c,v 1.10 2013/07/24 09:05:53 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, bool host)
     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 	l->host = host;
     87 
     88 	SLIST_INSERT_HEAD(&label_head, l, labels);
     89 
     90 	strlcpy(spreftmp, satos(&so_pref->sa), INET_ADDRSTRLEN);
     91 	warnp("[label_add] added binding %d for %s/%s\n", l->binding,
     92 	    satos(&so_dest->sa), spreftmp);
     93 
     94 	send_label_tlv_to_all(&(so_dest->sa),
     95 	    from_union_to_cidr(so_pref), l->binding);
     96 	return l;
     97 }
     98 
     99 /* Unlink a label */
    100 void
    101 label_del(struct label * l)
    102 {
    103 	warnp("[label_del] deleted binding %d for %s\n", l->binding,
    104 	   satos(&l->so_dest.sa));
    105 	SLIST_REMOVE(&label_head, l, label, labels);
    106 	free(l);
    107 }
    108 
    109 /*
    110  * Delete or Reuse the old IPv4 route, delete MPLS route
    111  * readd = REATT_INET_CHANGE -> delete and recreate the INET route
    112  * readd = REATT_INET_DEL -> deletes INET route
    113  * readd = REATT_INET_NODEL -> doesn't touch the INET route
    114  */
    115 void
    116 label_reattach_route(struct label *l, int readd)
    117 {
    118 
    119 	warnp("[label_reattach_route] binding %d deleted\n",
    120 		l->binding);
    121 
    122 	/* No gateway ? */
    123 	if (l->so_gate.sa.sa_len == 0)
    124 		return;
    125 
    126 	if (readd == REATT_INET_CHANGE) {
    127 		/* Delete the tagged route and re-add IPv4 route */
    128 		delete_route(&l->so_dest,
    129 		    l->host ? NULL : &l->so_pref, NO_FREESO);
    130 		add_route(&l->so_dest,
    131 		    l->host ? NULL : &l->so_pref, &l->so_gate,
    132 		    NULL, NULL, NO_FREESO, RTM_READD);
    133 	} else if (readd == REATT_INET_DEL)
    134 		delete_route(&l->so_dest, l->host ? NULL : &l->so_pref,
    135 		    NO_FREESO);
    136 
    137 	/* Deletes the MPLS route */
    138 	if (l->binding >= min_label)
    139 		delete_route(make_mpls_union(l->binding), NULL, FREESO);
    140 
    141 	l->binding = MPLS_LABEL_IMPLNULL;
    142 	l->p = NULL;
    143 	l->label = 0;
    144 }
    145 /*
    146  * Get a label by dst and pref
    147  */
    148 struct label*
    149 label_get(const union sockunion *sodest, const union sockunion *sopref)
    150 {
    151 	struct label *l;
    152 
    153 	SLIST_FOREACH (l, &label_head, labels)
    154 	    if (sodest->sin.sin_addr.s_addr ==
    155 		    l->so_dest.sin.sin_addr.s_addr &&
    156 		sopref->sin.sin_addr.s_addr ==
    157 		    l->so_pref.sin.sin_addr.s_addr)
    158 			return l;
    159 	return NULL;
    160 }
    161 
    162 /*
    163  * Find all labels that points to a peer
    164  * and reattach them to IPv4
    165  */
    166 void
    167 label_reattach_all_peer_labels(const struct ldp_peer *p, int readd)
    168 {
    169 	struct label   *l;
    170 
    171 	SLIST_FOREACH(l, &label_head, labels)
    172 		if (l->p == p)
    173 			label_reattach_route(l, readd);
    174 }
    175 
    176 /*
    177  * Find all labels that points to a peer
    178  * and delete them
    179  */
    180 void
    181 del_all_peer_labels(const struct ldp_peer * p, int readd)
    182 {
    183 	struct label   *l, *lnext;
    184 
    185 	SLIST_FOREACH_SAFE(l, &label_head, labels, lnext) {
    186 		if(l->p != p)
    187 			continue;
    188 		label_reattach_route(l, readd);
    189 		label_del(l);
    190 		SLIST_REMOVE(&label_head, l, label, labels);
    191 	}
    192 }
    193 
    194 /*
    195  * Finds a label by its binding and deletes it
    196  */
    197 void
    198 label_del_by_binding(uint32_t binding, int readd)
    199 {
    200 	struct label   *l;
    201 
    202 	SLIST_FOREACH(l, &label_head, labels)
    203 		if ((uint32_t)l->binding == binding) {
    204 			label_reattach_route(l, readd);
    205 			label_del(l);
    206 			SLIST_REMOVE(&label_head, l, label, labels);
    207 			break;
    208 		}
    209 }
    210 
    211 /*
    212  * For Compatibility with old bindinds code
    213  */
    214 struct label*
    215 label_get_by_prefix(const struct sockaddr *a, int prefixlen)
    216 {
    217 	const union sockunion *so_dest;
    218 	union sockunion *so_pref;
    219 	struct label *l;
    220 
    221 	so_dest = (const union sockunion *)a;
    222 	so_pref = from_cidr_to_union(prefixlen);
    223 
    224 	l = label_get(so_dest, so_pref);
    225 
    226 	free(so_pref);
    227 
    228 	return l;
    229 }
    230 
    231 /*
    232  * Get a free binding
    233  */
    234 uint32_t
    235 get_free_local_label()
    236 {
    237 	struct label *l;
    238 	int lbl;
    239 
    240 	for (lbl = min_label; lbl <= max_label; lbl++) {
    241 		SLIST_FOREACH(l, &label_head, labels)
    242 			if (l->binding == lbl)
    243 				break;
    244 		if (l == NULL)
    245 			return lbl;
    246 	}
    247 	return 0;
    248 }
    249 
    250 /*
    251  * Announce peers that a label has changed its binding
    252  * by withdrawing it and reannouncing it
    253  */
    254 void
    255 announce_label_change(struct label *l)
    256 {
    257 	send_withdraw_tlv_to_all(&(l->so_dest.sa),
    258 		from_union_to_cidr(&(l->so_pref)));
    259 	send_label_tlv_to_all(&(l->so_dest.sa),
    260 		from_union_to_cidr(&(l->so_pref)),
    261 		l->binding);
    262 }
    263 
    264 void
    265 label_check_assoc(struct ldp_peer *p)
    266 {
    267 	struct label *l;
    268 	struct ldp_peer_address *wp;
    269 
    270 	SLIST_FOREACH (l, &label_head, labels)
    271 		if (l->p == NULL && l->so_gate.sa.sa_family != 0)
    272 			SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses)
    273 				if (sockaddr_cmp(&l->so_gate.sa,
    274 				    &wp->address.sa) == 0){
    275 					l->p = p;
    276 					l->label = MPLS_LABEL_IMPLNULL;
    277 					break;
    278 				}
    279 }
    280