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