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