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