Home | History | Annotate | Line # | Download | only in ldpd
      1  1.11    kefren /* $NetBSD: label.c,v 1.11 2013/07/31 06:58:23 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.11    kefren #include <stddef.h>
     36   1.1    kefren #include <stdlib.h>
     37   1.1    kefren #include <string.h>
     38   1.1    kefren 
     39   1.1    kefren #include "ldp.h"
     40   1.1    kefren #include "tlv_stack.h"
     41   1.1    kefren #include "mpls_routes.h"
     42   1.1    kefren #include "label.h"
     43   1.1    kefren #include "ldp_errors.h"
     44   1.1    kefren 
     45  1.11    kefren static int labels_compare(void*, const void*, const void*);
     46  1.11    kefren 
     47  1.11    kefren int min_label = MIN_LABEL, max_label = MAX_LABEL;
     48  1.11    kefren 
     49  1.11    kefren static rb_tree_t labels_tree;
     50  1.11    kefren static const rb_tree_ops_t tree_ops = {
     51  1.11    kefren 	.rbto_compare_nodes = labels_compare,
     52  1.11    kefren 	.rbto_compare_key = labels_compare,
     53  1.11    kefren 	.rbto_node_offset = offsetof(struct label, lbtree),
     54  1.11    kefren 	.rbto_context = NULL
     55  1.11    kefren };
     56   1.3    kefren 
     57   1.1    kefren void
     58   1.1    kefren label_init()
     59   1.1    kefren {
     60  1.11    kefren 
     61  1.11    kefren 	rb_tree_init(&labels_tree, &tree_ops);
     62  1.11    kefren }
     63  1.11    kefren 
     64  1.11    kefren static int
     65  1.11    kefren labels_compare(void *context, const void *node1, const void *node2)
     66  1.11    kefren {
     67  1.11    kefren 	const struct label *l1 = node1, *l2 = node2;
     68  1.11    kefren 	int ret;
     69  1.11    kefren 
     70  1.11    kefren 	if (__predict_false(l1->so_dest.sa.sa_family !=
     71  1.11    kefren 	    l2->so_dest.sa.sa_family))
     72  1.11    kefren 		return l1->so_dest.sa.sa_family > l2->so_dest.sa.sa_family ?
     73  1.11    kefren 		    1 : -1;
     74  1.11    kefren 
     75  1.11    kefren 	assert(l1->so_dest.sa.sa_len == l2->so_dest.sa.sa_len);
     76  1.11    kefren 	assert(l1->so_pref.sa.sa_len == l2->so_pref.sa.sa_len);
     77  1.11    kefren 
     78  1.11    kefren 	if ((ret = memcmp(&l1->so_dest.sa, &l2->so_dest.sa,
     79  1.11    kefren 	    l1->so_dest.sa.sa_len)) != 0)
     80  1.11    kefren 		return ret;
     81  1.11    kefren 	else
     82  1.11    kefren 		return memcmp(&l1->so_pref.sa, &l2->so_pref.sa,
     83  1.11    kefren 		    l1->so_pref.sa.sa_len);
     84   1.1    kefren }
     85   1.1    kefren 
     86   1.1    kefren /*
     87   1.1    kefren  * if binding == 0 it receives a free one
     88   1.1    kefren  */
     89   1.1    kefren struct label   *
     90   1.6    kefren label_add(const union sockunion * so_dest, const union sockunion * so_pref,
     91   1.6    kefren 	  const union sockunion * so_gate, uint32_t binding,
     92  1.10    kefren 	  const struct ldp_peer * p, uint32_t label, bool host)
     93   1.1    kefren {
     94   1.1    kefren 	struct label   *l;
     95   1.1    kefren 	char	spreftmp[INET_ADDRSTRLEN];
     96   1.1    kefren 
     97   1.2  christos 	l = calloc(1, sizeof(*l));
     98   1.1    kefren 
     99   1.1    kefren 	if (!l) {
    100   1.1    kefren 		fatalp("label_add: malloc problem\n");
    101   1.1    kefren 		return NULL;
    102   1.2  christos 	}
    103   1.1    kefren 
    104   1.1    kefren 	assert(so_dest);
    105   1.1    kefren 	assert(so_pref);
    106   1.1    kefren 	assert(so_dest->sa.sa_family == so_pref->sa.sa_family);
    107   1.8    kefren 	assert(label_get(so_dest, so_pref) == NULL);
    108   1.1    kefren 
    109   1.8    kefren 	memcpy(&l->so_dest, so_dest, so_dest->sa.sa_len);
    110   1.8    kefren 	memcpy(&l->so_pref, so_pref, so_pref->sa.sa_len);
    111   1.1    kefren 
    112   1.1    kefren 	if (so_gate)
    113   1.8    kefren 		memcpy(&l->so_gate, so_gate, so_gate->sa.sa_len);
    114   1.1    kefren 	if (binding)
    115   1.1    kefren 		l->binding = binding;
    116   1.1    kefren 	else
    117   1.1    kefren 		l->binding = get_free_local_label();
    118   1.1    kefren 	l->p = p;
    119   1.1    kefren 	l->label = label;
    120  1.10    kefren 	l->host = host;
    121   1.1    kefren 
    122  1.11    kefren 	if (rb_tree_insert_node(&labels_tree, l) != l)
    123  1.11    kefren 		fatalp("label already in tree");
    124   1.1    kefren 
    125   1.7    kefren 	strlcpy(spreftmp, satos(&so_pref->sa), INET_ADDRSTRLEN);
    126   1.1    kefren 	warnp("[label_add] added binding %d for %s/%s\n", l->binding,
    127   1.7    kefren 	    satos(&so_dest->sa), spreftmp);
    128   1.1    kefren 
    129   1.4    kefren 	send_label_tlv_to_all(&(so_dest->sa),
    130   1.1    kefren 	    from_union_to_cidr(so_pref), l->binding);
    131   1.1    kefren 	return l;
    132   1.1    kefren }
    133   1.1    kefren 
    134   1.1    kefren /* Unlink a label */
    135   1.1    kefren void
    136   1.1    kefren label_del(struct label * l)
    137   1.1    kefren {
    138   1.1    kefren 	warnp("[label_del] deleted binding %d for %s\n", l->binding,
    139   1.7    kefren 	   satos(&l->so_dest.sa));
    140  1.11    kefren 	rb_tree_remove_node(&labels_tree, l);
    141   1.1    kefren 	free(l);
    142   1.1    kefren }
    143   1.1    kefren 
    144   1.1    kefren /*
    145   1.9    kefren  * Delete or Reuse the old IPv4 route, delete MPLS route
    146   1.9    kefren  * readd = REATT_INET_CHANGE -> delete and recreate the INET route
    147   1.9    kefren  * readd = REATT_INET_DEL -> deletes INET route
    148   1.9    kefren  * readd = REATT_INET_NODEL -> doesn't touch the INET route
    149   1.1    kefren  */
    150   1.1    kefren void
    151   1.1    kefren label_reattach_route(struct label *l, int readd)
    152   1.1    kefren {
    153   1.1    kefren 
    154   1.1    kefren 	warnp("[label_reattach_route] binding %d deleted\n",
    155   1.1    kefren 		l->binding);
    156   1.1    kefren 
    157   1.1    kefren 	/* No gateway ? */
    158   1.9    kefren 	if (l->so_gate.sa.sa_len == 0)
    159   1.1    kefren 		return;
    160   1.1    kefren 
    161   1.9    kefren 	if (readd == REATT_INET_CHANGE) {
    162   1.9    kefren 		/* Delete the tagged route and re-add IPv4 route */
    163   1.9    kefren 		delete_route(&l->so_dest,
    164  1.10    kefren 		    l->host ? NULL : &l->so_pref, NO_FREESO);
    165   1.9    kefren 		add_route(&l->so_dest,
    166  1.10    kefren 		    l->host ? NULL : &l->so_pref, &l->so_gate,
    167   1.9    kefren 		    NULL, NULL, NO_FREESO, RTM_READD);
    168   1.9    kefren 	} else if (readd == REATT_INET_DEL)
    169  1.10    kefren 		delete_route(&l->so_dest, l->host ? NULL : &l->so_pref,
    170  1.10    kefren 		    NO_FREESO);
    171   1.9    kefren 
    172   1.9    kefren 	/* Deletes the MPLS route */
    173   1.9    kefren 	if (l->binding >= min_label)
    174   1.9    kefren 		delete_route(make_mpls_union(l->binding), NULL, FREESO);
    175   1.1    kefren 
    176   1.9    kefren 	l->binding = MPLS_LABEL_IMPLNULL;
    177   1.9    kefren 	l->p = NULL;
    178   1.1    kefren 	l->label = 0;
    179   1.1    kefren }
    180   1.1    kefren /*
    181   1.1    kefren  * Get a label by dst and pref
    182   1.1    kefren  */
    183   1.1    kefren struct label*
    184   1.6    kefren label_get(const union sockunion *sodest, const union sockunion *sopref)
    185   1.1    kefren {
    186  1.11    kefren 	struct label l;
    187  1.11    kefren 
    188  1.11    kefren 	memset(&l, 0, sizeof(l));
    189  1.11    kefren 	memcpy(&l.so_dest, sodest, sodest->sa.sa_len);
    190  1.11    kefren 	memcpy(&l.so_pref, sopref, sopref->sa.sa_len);
    191   1.1    kefren 
    192  1.11    kefren 	return rb_tree_find_node(&labels_tree, &l);
    193   1.1    kefren }
    194   1.1    kefren 
    195   1.1    kefren /*
    196   1.1    kefren  * Find all labels that points to a peer
    197   1.1    kefren  * and reattach them to IPv4
    198   1.1    kefren  */
    199   1.1    kefren void
    200   1.5    kefren label_reattach_all_peer_labels(const struct ldp_peer *p, int readd)
    201   1.1    kefren {
    202   1.1    kefren 	struct label   *l;
    203   1.1    kefren 
    204  1.11    kefren 	RB_TREE_FOREACH(l, &labels_tree)
    205   1.1    kefren 		if (l->p == p)
    206   1.1    kefren 			label_reattach_route(l, readd);
    207   1.1    kefren }
    208   1.1    kefren 
    209   1.1    kefren /*
    210   1.1    kefren  * Find all labels that points to a peer
    211   1.1    kefren  * and delete them
    212   1.1    kefren  */
    213   1.1    kefren void
    214   1.6    kefren del_all_peer_labels(const struct ldp_peer * p, int readd)
    215   1.1    kefren {
    216   1.3    kefren 	struct label   *l, *lnext;
    217   1.1    kefren 
    218  1.11    kefren 	RB_TREE_FOREACH(l, &labels_tree) {
    219  1.11    kefren back_delete:
    220   1.3    kefren 		if(l->p != p)
    221   1.3    kefren 			continue;
    222   1.3    kefren 		label_reattach_route(l, readd);
    223  1.11    kefren 		lnext = rb_tree_iterate(&labels_tree, l, RB_DIR_RIGHT);
    224   1.3    kefren 		label_del(l);
    225  1.11    kefren 		if (lnext == NULL)
    226  1.11    kefren 			break;
    227  1.11    kefren 		l = lnext;
    228  1.11    kefren 		goto back_delete;
    229   1.3    kefren 	}
    230   1.1    kefren }
    231   1.1    kefren 
    232   1.1    kefren /*
    233   1.1    kefren  * Finds a label by its binding and deletes it
    234   1.1    kefren  */
    235   1.1    kefren void
    236   1.1    kefren label_del_by_binding(uint32_t binding, int readd)
    237   1.1    kefren {
    238   1.1    kefren 	struct label   *l;
    239   1.1    kefren 
    240  1.11    kefren 	RB_TREE_FOREACH(l, &labels_tree)
    241   1.1    kefren 		if ((uint32_t)l->binding == binding) {
    242   1.1    kefren 			label_reattach_route(l, readd);
    243   1.1    kefren 			label_del(l);
    244   1.1    kefren 			break;
    245   1.1    kefren 		}
    246   1.1    kefren }
    247   1.1    kefren 
    248   1.1    kefren /*
    249   1.1    kefren  * For Compatibility with old bindinds code
    250   1.1    kefren  */
    251   1.1    kefren struct label*
    252   1.4    kefren label_get_by_prefix(const struct sockaddr *a, int prefixlen)
    253   1.1    kefren {
    254   1.8    kefren 	const union sockunion *so_dest;
    255   1.8    kefren 	union sockunion *so_pref;
    256   1.1    kefren 	struct label *l;
    257   1.1    kefren 
    258   1.8    kefren 	so_dest = (const union sockunion *)a;
    259   1.1    kefren 	so_pref = from_cidr_to_union(prefixlen);
    260   1.1    kefren 
    261   1.1    kefren 	l = label_get(so_dest, so_pref);
    262   1.1    kefren 
    263   1.1    kefren 	free(so_pref);
    264   1.1    kefren 
    265   1.1    kefren 	return l;
    266   1.1    kefren }
    267   1.1    kefren 
    268   1.1    kefren /*
    269   1.1    kefren  * Get a free binding
    270   1.1    kefren  */
    271   1.1    kefren uint32_t
    272   1.1    kefren get_free_local_label()
    273   1.1    kefren {
    274   1.1    kefren 	struct label *l;
    275   1.3    kefren 	int lbl;
    276   1.1    kefren 
    277   1.3    kefren 	for (lbl = min_label; lbl <= max_label; lbl++) {
    278  1.11    kefren 		RB_TREE_FOREACH(l, &labels_tree)
    279   1.3    kefren 			if (l->binding == lbl)
    280   1.1    kefren 				break;
    281   1.1    kefren 		if (l == NULL)
    282   1.1    kefren 			return lbl;
    283   1.1    kefren 	}
    284   1.1    kefren 	return 0;
    285   1.1    kefren }
    286   1.1    kefren 
    287   1.1    kefren /*
    288   1.9    kefren  * Announce peers that a label has changed its binding
    289   1.9    kefren  * by withdrawing it and reannouncing it
    290   1.1    kefren  */
    291   1.1    kefren void
    292   1.9    kefren announce_label_change(struct label *l)
    293   1.1    kefren {
    294   1.4    kefren 	send_withdraw_tlv_to_all(&(l->so_dest.sa),
    295   1.1    kefren 		from_union_to_cidr(&(l->so_pref)));
    296   1.4    kefren 	send_label_tlv_to_all(&(l->so_dest.sa),
    297   1.1    kefren 		from_union_to_cidr(&(l->so_pref)),
    298   1.1    kefren 		l->binding);
    299   1.1    kefren }
    300   1.8    kefren 
    301   1.8    kefren void
    302   1.8    kefren label_check_assoc(struct ldp_peer *p)
    303   1.8    kefren {
    304   1.8    kefren 	struct label *l;
    305   1.8    kefren 	struct ldp_peer_address *wp;
    306   1.8    kefren 
    307  1.11    kefren 	RB_TREE_FOREACH(l, &labels_tree)
    308   1.8    kefren 		if (l->p == NULL && l->so_gate.sa.sa_family != 0)
    309   1.8    kefren 			SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses)
    310   1.8    kefren 				if (sockaddr_cmp(&l->so_gate.sa,
    311  1.11    kefren 				    &wp->address.sa) == 0) {
    312   1.8    kefren 					l->p = p;
    313   1.8    kefren 					l->label = MPLS_LABEL_IMPLNULL;
    314   1.8    kefren 					break;
    315   1.8    kefren 				}
    316   1.8    kefren }
    317  1.11    kefren 
    318  1.11    kefren struct label *
    319  1.11    kefren label_get_right(struct label *l)
    320  1.11    kefren {
    321  1.11    kefren 	if (l == NULL)
    322  1.11    kefren 		return RB_TREE_MIN(&labels_tree);
    323  1.11    kefren 	else
    324  1.11    kefren 		return rb_tree_iterate(&labels_tree, l, RB_DIR_RIGHT);
    325  1.11    kefren }
    326