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