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