]>
Commit | Line | Data |
---|---|---|
8429abe0 RW |
1 | /* $OpenBSD$ */ |
2 | ||
3 | /* | |
4 | * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> | |
5 | * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> | |
6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | |
19 | ||
eac6e3f0 | 20 | #include <zebra.h> |
8429abe0 RW |
21 | |
22 | #include "ldpd.h" | |
23 | #include "lde.h" | |
24 | #include "log.h" | |
25 | ||
eac6e3f0 RW |
26 | #include "mpls.h" |
27 | ||
45926e58 | 28 | static __inline int fec_compare(const struct fec *, const struct fec *); |
8429abe0 RW |
29 | static int lde_nbr_is_nexthop(struct fec_node *, |
30 | struct lde_nbr *); | |
31 | static void fec_free(void *); | |
32 | static struct fec_node *fec_add(struct fec *fec); | |
33 | static struct fec_nh *fec_nh_add(struct fec_node *, int, union ldpd_addr *, | |
e132dea0 | 34 | ifindex_t, uint8_t, unsigned short); |
8429abe0 RW |
35 | static void fec_nh_del(struct fec_nh *); |
36 | ||
37 | RB_GENERATE(fec_tree, fec, entry, fec_compare) | |
38 | ||
39 | struct fec_tree ft = RB_INITIALIZER(&ft); | |
eac6e3f0 | 40 | struct thread *gc_timer; |
8429abe0 RW |
41 | |
42 | /* FEC tree functions */ | |
43 | void | |
44 | fec_init(struct fec_tree *fh) | |
45 | { | |
45926e58 | 46 | RB_INIT(fec_tree, fh); |
8429abe0 RW |
47 | } |
48 | ||
49 | static __inline int | |
45926e58 | 50 | fec_compare(const struct fec *a, const struct fec *b) |
8429abe0 RW |
51 | { |
52 | if (a->type < b->type) | |
53 | return (-1); | |
54 | if (a->type > b->type) | |
55 | return (1); | |
56 | ||
57 | switch (a->type) { | |
58 | case FEC_TYPE_IPV4: | |
59 | if (ntohl(a->u.ipv4.prefix.s_addr) < | |
60 | ntohl(b->u.ipv4.prefix.s_addr)) | |
61 | return (-1); | |
62 | if (ntohl(a->u.ipv4.prefix.s_addr) > | |
63 | ntohl(b->u.ipv4.prefix.s_addr)) | |
64 | return (1); | |
65 | if (a->u.ipv4.prefixlen < b->u.ipv4.prefixlen) | |
66 | return (-1); | |
67 | if (a->u.ipv4.prefixlen > b->u.ipv4.prefixlen) | |
68 | return (1); | |
69 | return (0); | |
70 | case FEC_TYPE_IPV6: | |
71 | if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix, | |
72 | sizeof(struct in6_addr)) < 0) | |
73 | return (-1); | |
74 | if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix, | |
75 | sizeof(struct in6_addr)) > 0) | |
76 | return (1); | |
77 | if (a->u.ipv6.prefixlen < b->u.ipv6.prefixlen) | |
78 | return (-1); | |
79 | if (a->u.ipv6.prefixlen > b->u.ipv6.prefixlen) | |
80 | return (1); | |
81 | return (0); | |
82 | case FEC_TYPE_PWID: | |
83 | if (a->u.pwid.type < b->u.pwid.type) | |
84 | return (-1); | |
85 | if (a->u.pwid.type > b->u.pwid.type) | |
86 | return (1); | |
87 | if (a->u.pwid.pwid < b->u.pwid.pwid) | |
88 | return (-1); | |
89 | if (a->u.pwid.pwid > b->u.pwid.pwid) | |
90 | return (1); | |
91 | if (ntohl(a->u.pwid.lsr_id.s_addr) < | |
92 | ntohl(b->u.pwid.lsr_id.s_addr)) | |
93 | return (-1); | |
94 | if (ntohl(a->u.pwid.lsr_id.s_addr) > | |
95 | ntohl(b->u.pwid.lsr_id.s_addr)) | |
96 | return (1); | |
97 | return (0); | |
98 | } | |
99 | ||
100 | return (-1); | |
101 | } | |
102 | ||
103 | struct fec * | |
104 | fec_find(struct fec_tree *fh, struct fec *f) | |
105 | { | |
106 | return (RB_FIND(fec_tree, fh, f)); | |
107 | } | |
108 | ||
109 | int | |
110 | fec_insert(struct fec_tree *fh, struct fec *f) | |
111 | { | |
112 | if (RB_INSERT(fec_tree, fh, f) != NULL) | |
113 | return (-1); | |
114 | return (0); | |
115 | } | |
116 | ||
117 | int | |
118 | fec_remove(struct fec_tree *fh, struct fec *f) | |
119 | { | |
120 | if (RB_REMOVE(fec_tree, fh, f) == NULL) { | |
121 | log_warnx("%s failed for %s", __func__, log_fec(f)); | |
122 | return (-1); | |
123 | } | |
124 | return (0); | |
125 | } | |
126 | ||
127 | void | |
128 | fec_clear(struct fec_tree *fh, void (*free_cb)(void *)) | |
129 | { | |
130 | struct fec *f; | |
131 | ||
55cd0f61 DS |
132 | while (!RB_EMPTY(fec_tree, fh)) { |
133 | f = RB_ROOT(fec_tree, fh); | |
134 | ||
8429abe0 RW |
135 | fec_remove(fh, f); |
136 | free_cb(f); | |
137 | } | |
138 | } | |
139 | ||
140 | /* routing table functions */ | |
141 | static int | |
142 | lde_nbr_is_nexthop(struct fec_node *fn, struct lde_nbr *ln) | |
143 | { | |
144 | struct fec_nh *fnh; | |
145 | ||
146 | LIST_FOREACH(fnh, &fn->nexthops, entry) | |
147 | if (lde_address_find(ln, fnh->af, &fnh->nexthop)) | |
148 | return (1); | |
149 | ||
150 | return (0); | |
151 | } | |
152 | ||
153 | void | |
154 | rt_dump(pid_t pid) | |
155 | { | |
156 | struct fec *f; | |
157 | struct fec_node *fn; | |
158 | struct lde_map *me; | |
159 | static struct ctl_rt rtctl; | |
160 | ||
161 | RB_FOREACH(f, fec_tree, &ft) { | |
162 | fn = (struct fec_node *)f; | |
163 | if (fn->local_label == NO_LABEL && | |
45926e58 | 164 | RB_EMPTY(lde_map_head, &fn->downstream)) |
8429abe0 RW |
165 | continue; |
166 | ||
0f7b5df9 | 167 | memset(&rtctl, 0, sizeof(rtctl)); |
8429abe0 RW |
168 | switch (fn->fec.type) { |
169 | case FEC_TYPE_IPV4: | |
170 | rtctl.af = AF_INET; | |
171 | rtctl.prefix.v4 = fn->fec.u.ipv4.prefix; | |
172 | rtctl.prefixlen = fn->fec.u.ipv4.prefixlen; | |
173 | break; | |
174 | case FEC_TYPE_IPV6: | |
175 | rtctl.af = AF_INET6; | |
176 | rtctl.prefix.v6 = fn->fec.u.ipv6.prefix; | |
177 | rtctl.prefixlen = fn->fec.u.ipv6.prefixlen; | |
178 | break; | |
179 | default: | |
180 | continue; | |
181 | } | |
182 | ||
183 | rtctl.local_label = fn->local_label; | |
45926e58 | 184 | if (RB_EMPTY(lde_map_head, &fn->downstream)) { |
8429abe0 RW |
185 | rtctl.in_use = 0; |
186 | rtctl.nexthop.s_addr = INADDR_ANY; | |
187 | rtctl.remote_label = NO_LABEL; | |
0f7b5df9 RW |
188 | rtctl.no_downstream = 1; |
189 | } | |
190 | lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB_BEGIN, 0, pid, &rtctl, | |
191 | sizeof(rtctl)); | |
8429abe0 | 192 | |
0f7b5df9 RW |
193 | RB_FOREACH(me, lde_map_head, &fn->upstream) { |
194 | rtctl.nexthop = me->nexthop->id; | |
195 | lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB_SENT, 0, pid, | |
196 | &rtctl, sizeof(rtctl)); | |
197 | } | |
198 | ||
199 | RB_FOREACH(me, lde_map_head, &fn->downstream) { | |
200 | rtctl.in_use = lde_nbr_is_nexthop(fn, me->nexthop); | |
201 | rtctl.nexthop = me->nexthop->id; | |
202 | rtctl.remote_label = me->map.label; | |
203 | lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB_RCVD, 0, pid, | |
8429abe0 RW |
204 | &rtctl, sizeof(rtctl)); |
205 | } | |
0f7b5df9 RW |
206 | lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB_END, 0, pid, &rtctl, |
207 | sizeof(rtctl)); | |
8429abe0 RW |
208 | } |
209 | } | |
210 | ||
211 | void | |
212 | fec_snap(struct lde_nbr *ln) | |
213 | { | |
214 | struct fec *f; | |
215 | struct fec_node *fn; | |
216 | ||
217 | RB_FOREACH(f, fec_tree, &ft) { | |
218 | fn = (struct fec_node *)f; | |
219 | if (fn->local_label == NO_LABEL) | |
220 | continue; | |
221 | ||
222 | lde_send_labelmapping(ln, fn, 0); | |
223 | } | |
224 | ||
225 | lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0); | |
226 | } | |
227 | ||
228 | static void | |
229 | fec_free(void *arg) | |
230 | { | |
231 | struct fec_node *fn = arg; | |
232 | struct fec_nh *fnh; | |
233 | ||
11bf8e13 | 234 | while ((fnh = LIST_FIRST(&fn->nexthops))) { |
8429abe0 | 235 | fec_nh_del(fnh); |
11bf8e13 RW |
236 | assert(fnh != LIST_FIRST(&fn->nexthops)); |
237 | } | |
45926e58 | 238 | if (!RB_EMPTY(lde_map_head, &fn->downstream)) |
8429abe0 RW |
239 | log_warnx("%s: fec %s downstream list not empty", __func__, |
240 | log_fec(&fn->fec)); | |
45926e58 | 241 | if (!RB_EMPTY(lde_map_head, &fn->upstream)) |
8429abe0 RW |
242 | log_warnx("%s: fec %s upstream list not empty", __func__, |
243 | log_fec(&fn->fec)); | |
244 | ||
245 | free(fn); | |
246 | } | |
247 | ||
248 | void | |
249 | fec_tree_clear(void) | |
250 | { | |
251 | fec_clear(&ft, fec_free); | |
252 | } | |
253 | ||
254 | static struct fec_node * | |
255 | fec_add(struct fec *fec) | |
256 | { | |
257 | struct fec_node *fn; | |
258 | ||
259 | fn = calloc(1, sizeof(*fn)); | |
260 | if (fn == NULL) | |
261 | fatal(__func__); | |
262 | ||
263 | fn->fec = *fec; | |
264 | fn->local_label = NO_LABEL; | |
45926e58 RZ |
265 | RB_INIT(lde_map_head, &fn->upstream); |
266 | RB_INIT(lde_map_head, &fn->downstream); | |
8429abe0 RW |
267 | LIST_INIT(&fn->nexthops); |
268 | ||
269 | if (fec_insert(&ft, &fn->fec)) | |
270 | log_warnx("failed to add %s to ft tree", | |
271 | log_fec(&fn->fec)); | |
272 | ||
273 | return (fn); | |
274 | } | |
275 | ||
276 | struct fec_nh * | |
277 | fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, | |
e132dea0 | 278 | ifindex_t ifindex, uint8_t route_type, unsigned short route_instance) |
8429abe0 RW |
279 | { |
280 | struct fec_nh *fnh; | |
281 | ||
282 | LIST_FOREACH(fnh, &fn->nexthops, entry) | |
283 | if (fnh->af == af && | |
284 | ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 && | |
88d88a9c | 285 | fnh->ifindex == ifindex && |
e132dea0 RW |
286 | fnh->route_type == route_type && |
287 | fnh->route_instance == route_instance) | |
8429abe0 RW |
288 | return (fnh); |
289 | ||
290 | return (NULL); | |
291 | } | |
292 | ||
293 | static struct fec_nh * | |
294 | fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop, | |
e132dea0 | 295 | ifindex_t ifindex, uint8_t route_type, unsigned short route_instance) |
8429abe0 RW |
296 | { |
297 | struct fec_nh *fnh; | |
298 | ||
299 | fnh = calloc(1, sizeof(*fnh)); | |
300 | if (fnh == NULL) | |
301 | fatal(__func__); | |
302 | ||
303 | fnh->af = af; | |
304 | fnh->nexthop = *nexthop; | |
88d88a9c | 305 | fnh->ifindex = ifindex; |
8429abe0 | 306 | fnh->remote_label = NO_LABEL; |
e132dea0 RW |
307 | fnh->route_type = route_type; |
308 | fnh->route_instance = route_instance; | |
8429abe0 RW |
309 | LIST_INSERT_HEAD(&fn->nexthops, fnh, entry); |
310 | ||
311 | return (fnh); | |
312 | } | |
313 | ||
314 | static void | |
315 | fec_nh_del(struct fec_nh *fnh) | |
316 | { | |
317 | LIST_REMOVE(fnh, entry); | |
318 | free(fnh); | |
319 | } | |
320 | ||
8429abe0 RW |
321 | void |
322 | lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, | |
e132dea0 RW |
323 | ifindex_t ifindex, uint8_t route_type, unsigned short route_instance, |
324 | int connected, void *data) | |
8429abe0 RW |
325 | { |
326 | struct fec_node *fn; | |
327 | struct fec_nh *fnh; | |
8429abe0 RW |
328 | |
329 | fn = (struct fec_node *)fec_find(&ft, fec); | |
330 | if (fn == NULL) | |
331 | fn = fec_add(fec); | |
8cb1fc45 | 332 | if (data) |
8429abe0 RW |
333 | fn->data = data; |
334 | ||
e132dea0 | 335 | fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance); |
8cb1fc45 | 336 | if (fnh == NULL) |
e132dea0 RW |
337 | fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type, |
338 | route_instance); | |
134970a2 | 339 | fnh->flags |= F_FEC_NH_NEW; |
8cb1fc45 RW |
340 | if (connected) |
341 | fnh->flags |= F_FEC_NH_CONNECTED; | |
8429abe0 RW |
342 | } |
343 | ||
344 | void | |
345 | lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop, | |
e132dea0 | 346 | ifindex_t ifindex, uint8_t route_type, unsigned short route_instance) |
8429abe0 RW |
347 | { |
348 | struct fec_node *fn; | |
349 | struct fec_nh *fnh; | |
350 | ||
351 | fn = (struct fec_node *)fec_find(&ft, fec); | |
352 | if (fn == NULL) | |
353 | /* route lost */ | |
354 | return; | |
e132dea0 | 355 | fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance); |
8429abe0 RW |
356 | if (fnh == NULL) |
357 | /* route lost */ | |
358 | return; | |
359 | ||
8429abe0 RW |
360 | lde_send_delete_klabel(fn, fnh); |
361 | fec_nh_del(fnh); | |
8429abe0 RW |
362 | } |
363 | ||
134970a2 RW |
364 | /* |
365 | * Whenever a route is changed, zebra advertises its new version without | |
366 | * withdrawing the old one. So, after processing a ZEBRA_REDISTRIBUTE_IPV[46]_ADD | |
367 | * message, we need to check for nexthops that were removed and, for each of | |
368 | * them (if any), withdraw the associated labels from zebra. | |
369 | */ | |
370 | void | |
8cb1fc45 | 371 | lde_kernel_update(struct fec *fec) |
134970a2 RW |
372 | { |
373 | struct fec_node *fn; | |
374 | struct fec_nh *fnh, *safe; | |
8cb1fc45 RW |
375 | struct lde_nbr *ln; |
376 | struct lde_map *me; | |
134970a2 RW |
377 | |
378 | fn = (struct fec_node *)fec_find(&ft, fec); | |
379 | if (fn == NULL) | |
380 | return; | |
381 | ||
382 | LIST_FOREACH_SAFE(fnh, &fn->nexthops, entry, safe) { | |
383 | if (fnh->flags & F_FEC_NH_NEW) | |
384 | fnh->flags &= ~F_FEC_NH_NEW; | |
8cb1fc45 RW |
385 | else { |
386 | lde_send_delete_klabel(fn, fnh); | |
387 | fec_nh_del(fnh); | |
388 | } | |
389 | } | |
390 | ||
391 | if (LIST_EMPTY(&fn->nexthops)) { | |
0bcc2916 RW |
392 | RB_FOREACH(ln, nbr_tree, &lde_nbrs) |
393 | lde_send_labelwithdraw(ln, fn, NULL, NULL); | |
8cb1fc45 | 394 | fn->data = NULL; |
8cb1fc45 | 395 | |
095f12f9 RW |
396 | /* |
397 | * Do not deallocate the local label now, do that only in the | |
398 | * LIB garbage collector. This will prevent ldpd from changing | |
399 | * the input label of some prefixes too often when running on | |
400 | * an unstable network. Also, restart the garbage collector | |
401 | * timer so that labels are deallocated only when the network | |
402 | * is stabilized. | |
403 | */ | |
404 | lde_gc_start_timer(); | |
405 | } else { | |
8cb1fc45 | 406 | fn->local_label = lde_update_label(fn); |
b4fcca6b | 407 | if (fn->local_label != NO_LABEL) |
8cb1fc45 RW |
408 | /* FEC.1: perform lsr label distribution procedure */ |
409 | RB_FOREACH(ln, nbr_tree, &lde_nbrs) | |
410 | lde_send_labelmapping(ln, fn, 1); | |
8cb1fc45 RW |
411 | } |
412 | ||
413 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
414 | lde_send_change_klabel(fn, fnh); | |
415 | ||
416 | switch (fn->fec.type) { | |
417 | case FEC_TYPE_IPV4: | |
418 | case FEC_TYPE_IPV6: | |
419 | ln = lde_nbr_find_by_addr(fnh->af, &fnh->nexthop); | |
420 | break; | |
421 | case FEC_TYPE_PWID: | |
422 | ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id); | |
423 | break; | |
424 | default: | |
425 | ln = NULL; | |
426 | break; | |
427 | } | |
428 | ||
429 | if (ln) { | |
430 | /* FEC.2 */ | |
431 | me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); | |
432 | if (me) | |
433 | /* FEC.5 */ | |
434 | lde_check_mapping(&me->map, ln); | |
435 | } | |
134970a2 RW |
436 | } |
437 | } | |
438 | ||
8429abe0 RW |
439 | void |
440 | lde_check_mapping(struct map *map, struct lde_nbr *ln) | |
441 | { | |
442 | struct fec fec; | |
443 | struct fec_node *fn; | |
444 | struct fec_nh *fnh; | |
445 | struct lde_req *lre; | |
446 | struct lde_map *me; | |
447 | struct l2vpn_pw *pw; | |
8429abe0 RW |
448 | |
449 | lde_map2fec(map, ln->id, &fec); | |
45a8eba9 RW |
450 | |
451 | switch (fec.type) { | |
452 | case FEC_TYPE_IPV4: | |
453 | if (lde_acl_check(ldeconf->ipv4.acl_label_accept_from, | |
454 | AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) | |
455 | return; | |
456 | if (lde_acl_check(ldeconf->ipv4.acl_label_accept_for, | |
457 | AF_INET, (union ldpd_addr *)&fec.u.ipv4.prefix, | |
458 | fec.u.ipv4.prefixlen) != FILTER_PERMIT) | |
459 | return; | |
460 | break; | |
461 | case FEC_TYPE_IPV6: | |
462 | if (lde_acl_check(ldeconf->ipv6.acl_label_accept_from, | |
463 | AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) | |
464 | return; | |
465 | if (lde_acl_check(ldeconf->ipv6.acl_label_accept_for, | |
466 | AF_INET6, (union ldpd_addr *)&fec.u.ipv6.prefix, | |
467 | fec.u.ipv6.prefixlen) != FILTER_PERMIT) | |
468 | return; | |
469 | break; | |
470 | default: | |
471 | break; | |
472 | } | |
473 | ||
8429abe0 RW |
474 | fn = (struct fec_node *)fec_find(&ft, &fec); |
475 | if (fn == NULL) | |
476 | fn = fec_add(&fec); | |
477 | ||
478 | /* LMp.1: first check if we have a pending request running */ | |
479 | lre = (struct lde_req *)fec_find(&ln->sent_req, &fn->fec); | |
480 | if (lre) | |
481 | /* LMp.2: delete record of outstanding label request */ | |
482 | lde_req_del(ln, lre, 1); | |
483 | ||
484 | /* RFC 4447 control word and status tlv negotiation */ | |
485 | if (map->type == MAP_TYPE_PWID && l2vpn_pw_negotiate(ln, fn, map)) | |
486 | return; | |
487 | ||
488 | /* | |
489 | * LMp.3 - LMp.8: loop detection - unnecessary for frame-mode | |
490 | * mpls networks. | |
491 | */ | |
492 | ||
493 | /* LMp.9 */ | |
494 | me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); | |
495 | if (me) { | |
496 | /* LMp.10 */ | |
497 | if (me->map.label != map->label && lre == NULL) { | |
498 | /* LMp.10a */ | |
0bcc2916 | 499 | lde_send_labelrelease(ln, fn, NULL, me->map.label); |
8429abe0 RW |
500 | |
501 | /* | |
502 | * Can not use lde_nbr_find_by_addr() because there's | |
503 | * the possibility of multipath. | |
504 | */ | |
505 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
506 | if (lde_address_find(ln, fnh->af, | |
507 | &fnh->nexthop) == NULL) | |
508 | continue; | |
509 | ||
510 | lde_send_delete_klabel(fn, fnh); | |
511 | fnh->remote_label = NO_LABEL; | |
512 | } | |
513 | } | |
514 | } | |
515 | ||
516 | /* | |
517 | * LMp.11 - 12: consider multiple nexthops in order to | |
518 | * support multipath | |
519 | */ | |
520 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
521 | /* LMp.15: install FEC in FIB */ | |
522 | switch (fec.type) { | |
523 | case FEC_TYPE_IPV4: | |
524 | case FEC_TYPE_IPV6: | |
525 | if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) | |
526 | continue; | |
527 | ||
528 | fnh->remote_label = map->label; | |
529 | lde_send_change_klabel(fn, fnh); | |
530 | break; | |
531 | case FEC_TYPE_PWID: | |
532 | pw = (struct l2vpn_pw *) fn->data; | |
533 | if (pw == NULL) | |
534 | continue; | |
535 | ||
536 | pw->remote_group = map->fec.pwid.group_id; | |
537 | if (map->flags & F_MAP_PW_IFMTU) | |
538 | pw->remote_mtu = map->fec.pwid.ifmtu; | |
539 | if (map->flags & F_MAP_PW_STATUS) | |
540 | pw->remote_status = map->pw_status; | |
87b5f1b7 RW |
541 | else |
542 | pw->remote_status = PW_FORWARDING; | |
8429abe0 RW |
543 | fnh->remote_label = map->label; |
544 | if (l2vpn_pw_ok(pw, fnh)) | |
545 | lde_send_change_klabel(fn, fnh); | |
546 | break; | |
547 | default: | |
548 | break; | |
549 | } | |
8429abe0 RW |
550 | } |
551 | /* LMp.13 & LMp.16: Record the mapping from this peer */ | |
552 | if (me == NULL) | |
553 | me = lde_map_add(ln, fn, 0); | |
554 | me->map = *map; | |
555 | ||
8429abe0 RW |
556 | /* |
557 | * LMp.17 - LMp.27 are unnecessary since we don't need to implement | |
558 | * loop detection. LMp.28 - LMp.30 are unnecessary because we are | |
559 | * merging capable. | |
560 | */ | |
561 | } | |
562 | ||
563 | void | |
564 | lde_check_request(struct map *map, struct lde_nbr *ln) | |
565 | { | |
566 | struct fec fec; | |
567 | struct lde_req *lre; | |
568 | struct fec_node *fn; | |
569 | struct fec_nh *fnh; | |
570 | ||
d4afb819 RW |
571 | /* wildcard label request */ |
572 | if (map->type == MAP_TYPE_TYPED_WCARD) { | |
573 | lde_check_request_wcard(map, ln); | |
574 | return; | |
575 | } | |
576 | ||
8429abe0 RW |
577 | /* LRq.1: skip loop detection (not necessary) */ |
578 | ||
579 | /* LRq.2: is there a next hop for fec? */ | |
580 | lde_map2fec(map, ln->id, &fec); | |
581 | fn = (struct fec_node *)fec_find(&ft, &fec); | |
582 | if (fn == NULL || LIST_EMPTY(&fn->nexthops)) { | |
583 | /* LRq.5: send No Route notification */ | |
05aac414 | 584 | lde_send_notification(ln, S_NO_ROUTE, map->msg_id, |
8429abe0 RW |
585 | htons(MSG_TYPE_LABELREQUEST)); |
586 | return; | |
587 | } | |
588 | ||
589 | /* LRq.3: is MsgSource the next hop? */ | |
590 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
591 | switch (fec.type) { | |
592 | case FEC_TYPE_IPV4: | |
593 | case FEC_TYPE_IPV6: | |
594 | if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) | |
595 | continue; | |
596 | ||
597 | /* LRq.4: send Loop Detected notification */ | |
05aac414 RW |
598 | lde_send_notification(ln, S_LOOP_DETECTED, map->msg_id, |
599 | htons(MSG_TYPE_LABELREQUEST)); | |
8429abe0 RW |
600 | return; |
601 | default: | |
602 | break; | |
603 | } | |
604 | } | |
605 | ||
606 | /* LRq.6: first check if we have a pending request running */ | |
607 | lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec); | |
608 | if (lre != NULL) | |
609 | /* LRq.7: duplicate request */ | |
610 | return; | |
611 | ||
612 | /* LRq.8: record label request */ | |
613 | lre = lde_req_add(ln, &fn->fec, 0); | |
614 | if (lre != NULL) | |
615 | lre->msg_id = ntohl(map->msg_id); | |
616 | ||
617 | /* LRq.9: perform LSR label distribution */ | |
618 | lde_send_labelmapping(ln, fn, 1); | |
619 | ||
620 | /* | |
621 | * LRq.10: do nothing (Request Never) since we use liberal | |
622 | * label retention. | |
623 | * LRq.11 - 12 are unnecessary since we are merging capable. | |
624 | */ | |
625 | } | |
626 | ||
d4afb819 RW |
627 | void |
628 | lde_check_request_wcard(struct map *map, struct lde_nbr *ln) | |
629 | { | |
630 | struct fec *f; | |
631 | struct fec_node *fn; | |
632 | struct lde_req *lre; | |
633 | ||
634 | RB_FOREACH(f, fec_tree, &ft) { | |
635 | fn = (struct fec_node *)f; | |
636 | ||
637 | /* only a typed wildcard is possible here */ | |
638 | if (lde_wildcard_apply(map, &fn->fec, NULL) == 0) | |
639 | continue; | |
640 | ||
641 | /* LRq.2: is there a next hop for fec? */ | |
642 | if (LIST_EMPTY(&fn->nexthops)) | |
643 | continue; | |
644 | ||
645 | /* LRq.6: first check if we have a pending request running */ | |
646 | lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec); | |
647 | if (lre != NULL) | |
648 | /* LRq.7: duplicate request */ | |
649 | continue; | |
650 | ||
651 | /* LRq.8: record label request */ | |
652 | lre = lde_req_add(ln, &fn->fec, 0); | |
653 | if (lre != NULL) | |
654 | lre->msg_id = ntohl(map->msg_id); | |
655 | ||
656 | /* LRq.9: perform LSR label distribution */ | |
657 | lde_send_labelmapping(ln, fn, 1); | |
658 | } | |
659 | } | |
660 | ||
8429abe0 RW |
661 | void |
662 | lde_check_release(struct map *map, struct lde_nbr *ln) | |
663 | { | |
664 | struct fec fec; | |
665 | struct fec_node *fn; | |
666 | struct lde_wdraw *lw; | |
667 | struct lde_map *me; | |
7c2abbd7 | 668 | struct fec *pending_map; |
8429abe0 | 669 | |
0bcc2916 RW |
670 | /* wildcard label release */ |
671 | if (map->type == MAP_TYPE_WILDCARD || | |
d4afb819 | 672 | map->type == MAP_TYPE_TYPED_WCARD || |
0bcc2916 RW |
673 | (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) { |
674 | lde_check_release_wcard(map, ln); | |
8429abe0 | 675 | return; |
0bcc2916 | 676 | } |
8429abe0 RW |
677 | |
678 | lde_map2fec(map, ln->id, &fec); | |
679 | fn = (struct fec_node *)fec_find(&ft, &fec); | |
680 | /* LRl.1: does FEC match a known FEC? */ | |
681 | if (fn == NULL) | |
682 | return; | |
683 | ||
7c2abbd7 RW |
684 | /* LRl.6: check sent map list and remove it if available */ |
685 | me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); | |
686 | if (me && (map->label == NO_LABEL || map->label == me->map.label)) | |
687 | lde_map_del(ln, me, 1); | |
688 | ||
8429abe0 RW |
689 | /* LRl.3: first check if we have a pending withdraw running */ |
690 | lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); | |
be8e0d31 | 691 | if (lw && (map->label == NO_LABEL || map->label == lw->label)) { |
8429abe0 RW |
692 | /* LRl.4: delete record of outstanding label withdraw */ |
693 | lde_wdraw_del(ln, lw); | |
8429abe0 | 694 | |
7c2abbd7 RW |
695 | /* send pending label mapping if any */ |
696 | pending_map = fec_find(&ln->sent_map_pending, &fn->fec); | |
697 | if (pending_map) { | |
698 | lde_send_labelmapping(ln, fn, 1); | |
699 | lde_map_pending_del(ln, pending_map); | |
700 | } | |
701 | } | |
8429abe0 RW |
702 | |
703 | /* | |
704 | * LRl.11 - 13 are unnecessary since we remove the label from | |
705 | * forwarding/switching as soon as the FEC is unreachable. | |
706 | */ | |
707 | } | |
708 | ||
709 | void | |
710 | lde_check_release_wcard(struct map *map, struct lde_nbr *ln) | |
711 | { | |
712 | struct fec *f; | |
713 | struct fec_node *fn; | |
714 | struct lde_wdraw *lw; | |
715 | struct lde_map *me; | |
7c2abbd7 | 716 | struct fec *pending_map; |
8429abe0 RW |
717 | |
718 | RB_FOREACH(f, fec_tree, &ft) { | |
719 | fn = (struct fec_node *)f; | |
0bcc2916 RW |
720 | me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); |
721 | ||
722 | /* LRl.1: does FEC match a known FEC? */ | |
723 | if (lde_wildcard_apply(map, &fn->fec, me) == 0) | |
724 | continue; | |
8429abe0 | 725 | |
7c2abbd7 RW |
726 | /* LRl.6: check sent map list and remove it if available */ |
727 | if (me && | |
728 | (map->label == NO_LABEL || map->label == me->map.label)) | |
729 | lde_map_del(ln, me, 1); | |
730 | ||
8429abe0 RW |
731 | /* LRl.3: first check if we have a pending withdraw running */ |
732 | lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); | |
be8e0d31 | 733 | if (lw && (map->label == NO_LABEL || map->label == lw->label)) { |
8429abe0 RW |
734 | /* LRl.4: delete record of outstanding lbl withdraw */ |
735 | lde_wdraw_del(ln, lw); | |
8429abe0 | 736 | |
7c2abbd7 RW |
737 | /* send pending label mapping if any */ |
738 | pending_map = fec_find(&ln->sent_map_pending, &fn->fec); | |
739 | if (pending_map) { | |
740 | lde_send_labelmapping(ln, fn, 1); | |
741 | lde_map_pending_del(ln, pending_map); | |
742 | } | |
743 | } | |
8429abe0 RW |
744 | |
745 | /* | |
746 | * LRl.11 - 13 are unnecessary since we remove the label from | |
747 | * forwarding/switching as soon as the FEC is unreachable. | |
748 | */ | |
749 | } | |
750 | } | |
751 | ||
752 | void | |
753 | lde_check_withdraw(struct map *map, struct lde_nbr *ln) | |
754 | { | |
755 | struct fec fec; | |
756 | struct fec_node *fn; | |
757 | struct fec_nh *fnh; | |
758 | struct lde_map *me; | |
759 | struct l2vpn_pw *pw; | |
760 | ||
0bcc2916 RW |
761 | /* wildcard label withdraw */ |
762 | if (map->type == MAP_TYPE_WILDCARD || | |
d4afb819 | 763 | map->type == MAP_TYPE_TYPED_WCARD || |
0bcc2916 RW |
764 | (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) { |
765 | lde_check_withdraw_wcard(map, ln); | |
8429abe0 | 766 | return; |
0bcc2916 | 767 | } |
8429abe0 RW |
768 | |
769 | lde_map2fec(map, ln->id, &fec); | |
770 | fn = (struct fec_node *)fec_find(&ft, &fec); | |
771 | if (fn == NULL) | |
772 | fn = fec_add(&fec); | |
773 | ||
774 | /* LWd.1: remove label from forwarding/switching use */ | |
775 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
776 | switch (fec.type) { | |
777 | case FEC_TYPE_IPV4: | |
778 | case FEC_TYPE_IPV6: | |
779 | if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) | |
780 | continue; | |
781 | break; | |
782 | case FEC_TYPE_PWID: | |
783 | pw = (struct l2vpn_pw *) fn->data; | |
784 | if (pw == NULL) | |
785 | continue; | |
87b5f1b7 | 786 | pw->remote_status = PW_NOT_FORWARDING; |
8429abe0 RW |
787 | break; |
788 | default: | |
789 | break; | |
790 | } | |
be8e0d31 RW |
791 | if (map->label != NO_LABEL && map->label != fnh->remote_label) |
792 | continue; | |
793 | ||
8429abe0 RW |
794 | lde_send_delete_klabel(fn, fnh); |
795 | fnh->remote_label = NO_LABEL; | |
796 | } | |
797 | ||
798 | /* LWd.2: send label release */ | |
0bcc2916 | 799 | lde_send_labelrelease(ln, fn, NULL, map->label); |
8429abe0 RW |
800 | |
801 | /* LWd.3: check previously received label mapping */ | |
802 | me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); | |
803 | if (me && (map->label == NO_LABEL || map->label == me->map.label)) | |
804 | /* LWd.4: remove record of previously received lbl mapping */ | |
805 | lde_map_del(ln, me, 0); | |
806 | } | |
807 | ||
808 | void | |
809 | lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) | |
810 | { | |
811 | struct fec *f; | |
812 | struct fec_node *fn; | |
813 | struct fec_nh *fnh; | |
814 | struct lde_map *me; | |
87b5f1b7 | 815 | struct l2vpn_pw *pw; |
8429abe0 RW |
816 | |
817 | /* LWd.2: send label release */ | |
0bcc2916 | 818 | lde_send_labelrelease(ln, NULL, map, map->label); |
8429abe0 RW |
819 | |
820 | RB_FOREACH(f, fec_tree, &ft) { | |
821 | fn = (struct fec_node *)f; | |
0bcc2916 RW |
822 | me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); |
823 | ||
824 | if (lde_wildcard_apply(map, &fn->fec, me) == 0) | |
825 | continue; | |
8429abe0 RW |
826 | |
827 | /* LWd.1: remove label from forwarding/switching use */ | |
828 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
829 | switch (f->type) { | |
830 | case FEC_TYPE_IPV4: | |
831 | case FEC_TYPE_IPV6: | |
832 | if (!lde_address_find(ln, fnh->af, | |
833 | &fnh->nexthop)) | |
834 | continue; | |
835 | break; | |
836 | case FEC_TYPE_PWID: | |
837 | if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr) | |
838 | continue; | |
87b5f1b7 RW |
839 | pw = (struct l2vpn_pw *) fn->data; |
840 | if (pw) | |
841 | pw->remote_status = PW_NOT_FORWARDING; | |
8429abe0 RW |
842 | break; |
843 | default: | |
844 | break; | |
845 | } | |
be8e0d31 RW |
846 | if (map->label != NO_LABEL && map->label != |
847 | fnh->remote_label) | |
848 | continue; | |
849 | ||
8429abe0 RW |
850 | lde_send_delete_klabel(fn, fnh); |
851 | fnh->remote_label = NO_LABEL; | |
852 | } | |
853 | ||
854 | /* LWd.3: check previously received label mapping */ | |
8429abe0 RW |
855 | if (me && (map->label == NO_LABEL || |
856 | map->label == me->map.label)) | |
857 | /* | |
858 | * LWd.4: remove record of previously received | |
859 | * label mapping | |
860 | */ | |
861 | lde_map_del(ln, me, 0); | |
862 | } | |
863 | } | |
864 | ||
0bcc2916 RW |
865 | int |
866 | lde_wildcard_apply(struct map *wcard, struct fec *fec, struct lde_map *me) | |
867 | { | |
868 | switch (wcard->type) { | |
869 | case MAP_TYPE_WILDCARD: | |
870 | /* full wildcard */ | |
871 | return (1); | |
d4afb819 RW |
872 | case MAP_TYPE_TYPED_WCARD: |
873 | switch (wcard->fec.twcard.type) { | |
874 | case MAP_TYPE_PREFIX: | |
875 | if (wcard->fec.twcard.u.prefix_af == AF_INET && | |
876 | fec->type != FEC_TYPE_IPV4) | |
877 | return (0); | |
878 | if (wcard->fec.twcard.u.prefix_af == AF_INET6 && | |
879 | fec->type != FEC_TYPE_IPV6) | |
880 | return (0); | |
881 | return (1); | |
aba50a83 RW |
882 | case MAP_TYPE_PWID: |
883 | if (fec->type != FEC_TYPE_PWID) | |
884 | return (0); | |
885 | if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD && | |
886 | wcard->fec.twcard.u.pw_type != fec->u.pwid.type) | |
887 | return (0); | |
888 | return (1); | |
d4afb819 RW |
889 | default: |
890 | fatalx("lde_wildcard_apply: unexpected fec type"); | |
891 | } | |
892 | break; | |
0bcc2916 RW |
893 | case MAP_TYPE_PWID: |
894 | /* RFC4447 pw-id group wildcard */ | |
895 | if (fec->type != FEC_TYPE_PWID) | |
896 | return (0); | |
897 | if (fec->u.pwid.type != wcard->fec.pwid.type) | |
898 | return (0); | |
899 | if (me == NULL || (me->map.fec.pwid.group_id != | |
900 | wcard->fec.pwid.group_id)) | |
901 | return (0); | |
902 | return (1); | |
903 | default: | |
904 | fatalx("lde_wildcard_apply: unexpected fec type"); | |
905 | } | |
906 | } | |
907 | ||
8429abe0 RW |
908 | /* gabage collector timer: timer to remove dead entries from the LIB */ |
909 | ||
910 | /* ARGSUSED */ | |
eac6e3f0 RW |
911 | int |
912 | lde_gc_timer(struct thread *thread) | |
8429abe0 RW |
913 | { |
914 | struct fec *fec, *safe; | |
915 | struct fec_node *fn; | |
916 | int count = 0; | |
917 | ||
918 | RB_FOREACH_SAFE(fec, fec_tree, &ft, safe) { | |
919 | fn = (struct fec_node *) fec; | |
920 | ||
921 | if (!LIST_EMPTY(&fn->nexthops) || | |
45926e58 RZ |
922 | !RB_EMPTY(lde_map_head, &fn->downstream) || |
923 | !RB_EMPTY(lde_map_head, &fn->upstream)) | |
8429abe0 RW |
924 | continue; |
925 | ||
f4ec681c BA |
926 | if (fn->local_label != NO_LABEL) |
927 | lde_free_label(fn->local_label); | |
928 | ||
8429abe0 RW |
929 | fec_remove(&ft, &fn->fec); |
930 | free(fn); | |
931 | count++; | |
932 | } | |
933 | ||
934 | if (count > 0) | |
935 | log_debug("%s: %u entries removed", __func__, count); | |
936 | ||
937 | lde_gc_start_timer(); | |
eac6e3f0 RW |
938 | |
939 | return (0); | |
8429abe0 RW |
940 | } |
941 | ||
942 | void | |
943 | lde_gc_start_timer(void) | |
944 | { | |
eac6e3f0 | 945 | THREAD_TIMER_OFF(gc_timer); |
66e78ae6 QY |
946 | gc_timer = NULL; |
947 | thread_add_timer(master, lde_gc_timer, NULL, LDE_GC_INTERVAL, | |
948 | &gc_timer); | |
8429abe0 RW |
949 | } |
950 | ||
951 | void | |
952 | lde_gc_stop_timer(void) | |
953 | { | |
eac6e3f0 | 954 | THREAD_TIMER_OFF(gc_timer); |
8429abe0 | 955 | } |