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