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