label.c revision 1.11 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