]>
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 | ||
8429abe0 RW |
28 | static __inline int fec_compare(struct fec *, struct fec *); |
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 *, | |
34 | uint8_t priority); | |
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 | { | |
46 | RB_INIT(fh); | |
47 | } | |
48 | ||
49 | static __inline int | |
50 | fec_compare(struct fec *a, struct fec *b) | |
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 | ||
132 | while ((f = RB_ROOT(fh)) != NULL) { | |
133 | fec_remove(fh, f); | |
134 | free_cb(f); | |
135 | } | |
136 | } | |
137 | ||
138 | /* routing table functions */ | |
139 | static int | |
140 | lde_nbr_is_nexthop(struct fec_node *fn, struct lde_nbr *ln) | |
141 | { | |
142 | struct fec_nh *fnh; | |
143 | ||
144 | LIST_FOREACH(fnh, &fn->nexthops, entry) | |
145 | if (lde_address_find(ln, fnh->af, &fnh->nexthop)) | |
146 | return (1); | |
147 | ||
148 | return (0); | |
149 | } | |
150 | ||
151 | void | |
152 | rt_dump(pid_t pid) | |
153 | { | |
154 | struct fec *f; | |
155 | struct fec_node *fn; | |
156 | struct lde_map *me; | |
157 | static struct ctl_rt rtctl; | |
158 | ||
159 | RB_FOREACH(f, fec_tree, &ft) { | |
160 | fn = (struct fec_node *)f; | |
161 | if (fn->local_label == NO_LABEL && | |
162 | LIST_EMPTY(&fn->downstream)) | |
163 | continue; | |
164 | ||
eac6e3f0 | 165 | rtctl.first = 1; |
8429abe0 RW |
166 | switch (fn->fec.type) { |
167 | case FEC_TYPE_IPV4: | |
168 | rtctl.af = AF_INET; | |
169 | rtctl.prefix.v4 = fn->fec.u.ipv4.prefix; | |
170 | rtctl.prefixlen = fn->fec.u.ipv4.prefixlen; | |
171 | break; | |
172 | case FEC_TYPE_IPV6: | |
173 | rtctl.af = AF_INET6; | |
174 | rtctl.prefix.v6 = fn->fec.u.ipv6.prefix; | |
175 | rtctl.prefixlen = fn->fec.u.ipv6.prefixlen; | |
176 | break; | |
177 | default: | |
178 | continue; | |
179 | } | |
180 | ||
181 | rtctl.local_label = fn->local_label; | |
182 | LIST_FOREACH(me, &fn->downstream, entry) { | |
183 | rtctl.in_use = lde_nbr_is_nexthop(fn, me->nexthop); | |
184 | rtctl.nexthop = me->nexthop->id; | |
185 | rtctl.remote_label = me->map.label; | |
186 | ||
187 | lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid, | |
188 | &rtctl, sizeof(rtctl)); | |
eac6e3f0 | 189 | rtctl.first = 0; |
8429abe0 RW |
190 | } |
191 | if (LIST_EMPTY(&fn->downstream)) { | |
192 | rtctl.in_use = 0; | |
193 | rtctl.nexthop.s_addr = INADDR_ANY; | |
194 | rtctl.remote_label = NO_LABEL; | |
195 | ||
196 | lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid, | |
197 | &rtctl, sizeof(rtctl)); | |
198 | } | |
199 | } | |
200 | } | |
201 | ||
202 | void | |
203 | fec_snap(struct lde_nbr *ln) | |
204 | { | |
205 | struct fec *f; | |
206 | struct fec_node *fn; | |
207 | ||
208 | RB_FOREACH(f, fec_tree, &ft) { | |
209 | fn = (struct fec_node *)f; | |
210 | if (fn->local_label == NO_LABEL) | |
211 | continue; | |
212 | ||
213 | lde_send_labelmapping(ln, fn, 0); | |
214 | } | |
215 | ||
216 | lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0); | |
217 | } | |
218 | ||
219 | static void | |
220 | fec_free(void *arg) | |
221 | { | |
222 | struct fec_node *fn = arg; | |
223 | struct fec_nh *fnh; | |
224 | ||
225 | while ((fnh = LIST_FIRST(&fn->nexthops))) | |
226 | fec_nh_del(fnh); | |
227 | if (!LIST_EMPTY(&fn->downstream)) | |
228 | log_warnx("%s: fec %s downstream list not empty", __func__, | |
229 | log_fec(&fn->fec)); | |
230 | if (!LIST_EMPTY(&fn->upstream)) | |
231 | log_warnx("%s: fec %s upstream list not empty", __func__, | |
232 | log_fec(&fn->fec)); | |
233 | ||
234 | free(fn); | |
235 | } | |
236 | ||
237 | void | |
238 | fec_tree_clear(void) | |
239 | { | |
240 | fec_clear(&ft, fec_free); | |
241 | } | |
242 | ||
243 | static struct fec_node * | |
244 | fec_add(struct fec *fec) | |
245 | { | |
246 | struct fec_node *fn; | |
247 | ||
248 | fn = calloc(1, sizeof(*fn)); | |
249 | if (fn == NULL) | |
250 | fatal(__func__); | |
251 | ||
252 | fn->fec = *fec; | |
253 | fn->local_label = NO_LABEL; | |
254 | LIST_INIT(&fn->upstream); | |
255 | LIST_INIT(&fn->downstream); | |
256 | LIST_INIT(&fn->nexthops); | |
257 | ||
258 | if (fec_insert(&ft, &fn->fec)) | |
259 | log_warnx("failed to add %s to ft tree", | |
260 | log_fec(&fn->fec)); | |
261 | ||
262 | return (fn); | |
263 | } | |
264 | ||
265 | struct fec_nh * | |
266 | fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, | |
267 | uint8_t priority) | |
268 | { | |
269 | struct fec_nh *fnh; | |
270 | ||
271 | LIST_FOREACH(fnh, &fn->nexthops, entry) | |
272 | if (fnh->af == af && | |
273 | ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 && | |
274 | fnh->priority == priority) | |
275 | return (fnh); | |
276 | ||
277 | return (NULL); | |
278 | } | |
279 | ||
280 | static struct fec_nh * | |
281 | fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop, | |
282 | uint8_t priority) | |
283 | { | |
284 | struct fec_nh *fnh; | |
285 | ||
286 | fnh = calloc(1, sizeof(*fnh)); | |
287 | if (fnh == NULL) | |
288 | fatal(__func__); | |
289 | ||
290 | fnh->af = af; | |
291 | fnh->nexthop = *nexthop; | |
292 | fnh->remote_label = NO_LABEL; | |
293 | fnh->priority = priority; | |
294 | LIST_INSERT_HEAD(&fn->nexthops, fnh, entry); | |
295 | ||
296 | return (fnh); | |
297 | } | |
298 | ||
299 | static void | |
300 | fec_nh_del(struct fec_nh *fnh) | |
301 | { | |
302 | LIST_REMOVE(fnh, entry); | |
303 | free(fnh); | |
304 | } | |
305 | ||
306 | uint32_t | |
307 | egress_label(enum fec_type fec_type) | |
308 | { | |
309 | switch (fec_type) { | |
310 | case FEC_TYPE_IPV4: | |
311 | if (ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL) | |
312 | return (MPLS_LABEL_IPV4NULL); | |
313 | break; | |
314 | case FEC_TYPE_IPV6: | |
315 | if (ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL) | |
316 | return (MPLS_LABEL_IPV6NULL); | |
317 | break; | |
318 | default: | |
319 | fatalx("egress_label: unexpected fec type"); | |
320 | } | |
321 | ||
322 | return (MPLS_LABEL_IMPLNULL); | |
323 | } | |
324 | ||
325 | void | |
326 | lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, | |
327 | uint8_t priority, int connected, void *data) | |
328 | { | |
329 | struct fec_node *fn; | |
330 | struct fec_nh *fnh; | |
331 | struct lde_map *me; | |
332 | struct lde_nbr *ln; | |
333 | ||
334 | fn = (struct fec_node *)fec_find(&ft, fec); | |
335 | if (fn == NULL) | |
336 | fn = fec_add(fec); | |
134970a2 RW |
337 | fnh = fec_nh_find(fn, af, nexthop, priority); |
338 | if (fnh != NULL) { | |
daca38ae | 339 | lde_send_change_klabel(fn, fnh); |
134970a2 | 340 | fnh->flags |= F_FEC_NH_NEW; |
8429abe0 | 341 | return; |
134970a2 | 342 | } |
8429abe0 | 343 | |
8429abe0 RW |
344 | if (fn->fec.type == FEC_TYPE_PWID) |
345 | fn->data = data; | |
346 | ||
347 | if (fn->local_label == NO_LABEL) { | |
348 | if (connected) | |
349 | fn->local_label = egress_label(fn->fec.type); | |
350 | else | |
351 | fn->local_label = lde_assign_label(); | |
352 | ||
353 | /* FEC.1: perform lsr label distribution procedure */ | |
354 | RB_FOREACH(ln, nbr_tree, &lde_nbrs) | |
355 | lde_send_labelmapping(ln, fn, 1); | |
356 | } | |
357 | ||
358 | fnh = fec_nh_add(fn, af, nexthop, priority); | |
134970a2 | 359 | fnh->flags |= F_FEC_NH_NEW; |
8429abe0 RW |
360 | lde_send_change_klabel(fn, fnh); |
361 | ||
362 | switch (fn->fec.type) { | |
363 | case FEC_TYPE_IPV4: | |
364 | case FEC_TYPE_IPV6: | |
365 | ln = lde_nbr_find_by_addr(af, &fnh->nexthop); | |
366 | break; | |
367 | case FEC_TYPE_PWID: | |
368 | ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id); | |
369 | break; | |
370 | default: | |
371 | ln = NULL; | |
372 | break; | |
373 | } | |
374 | ||
375 | if (ln) { | |
376 | /* FEC.2 */ | |
377 | me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); | |
378 | if (me) | |
379 | /* FEC.5 */ | |
380 | lde_check_mapping(&me->map, ln); | |
381 | } | |
382 | } | |
383 | ||
384 | void | |
385 | lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop, | |
386 | uint8_t priority) | |
387 | { | |
388 | struct fec_node *fn; | |
389 | struct fec_nh *fnh; | |
390 | ||
391 | fn = (struct fec_node *)fec_find(&ft, fec); | |
392 | if (fn == NULL) | |
393 | /* route lost */ | |
394 | return; | |
395 | fnh = fec_nh_find(fn, af, nexthop, priority); | |
396 | if (fnh == NULL) | |
397 | /* route lost */ | |
398 | return; | |
399 | ||
8429abe0 RW |
400 | lde_send_delete_klabel(fn, fnh); |
401 | fec_nh_del(fnh); | |
402 | if (LIST_EMPTY(&fn->nexthops)) { | |
403 | lde_send_labelwithdraw_all(fn, NO_LABEL); | |
404 | fn->local_label = NO_LABEL; | |
405 | if (fn->fec.type == FEC_TYPE_PWID) | |
406 | fn->data = NULL; | |
407 | } | |
408 | } | |
409 | ||
134970a2 RW |
410 | /* |
411 | * Whenever a route is changed, zebra advertises its new version without | |
412 | * withdrawing the old one. So, after processing a ZEBRA_REDISTRIBUTE_IPV[46]_ADD | |
413 | * message, we need to check for nexthops that were removed and, for each of | |
414 | * them (if any), withdraw the associated labels from zebra. | |
415 | */ | |
416 | void | |
417 | lde_kernel_reevaluate(struct fec *fec) | |
418 | { | |
419 | struct fec_node *fn; | |
420 | struct fec_nh *fnh, *safe; | |
421 | ||
422 | fn = (struct fec_node *)fec_find(&ft, fec); | |
423 | if (fn == NULL) | |
424 | return; | |
425 | ||
426 | LIST_FOREACH_SAFE(fnh, &fn->nexthops, entry, safe) { | |
427 | if (fnh->flags & F_FEC_NH_NEW) | |
428 | fnh->flags &= ~F_FEC_NH_NEW; | |
429 | else | |
430 | lde_kernel_remove(fec, fnh->af, &fnh->nexthop, | |
431 | fnh->priority); | |
432 | } | |
433 | } | |
434 | ||
8429abe0 RW |
435 | void |
436 | lde_check_mapping(struct map *map, struct lde_nbr *ln) | |
437 | { | |
438 | struct fec fec; | |
439 | struct fec_node *fn; | |
440 | struct fec_nh *fnh; | |
441 | struct lde_req *lre; | |
442 | struct lde_map *me; | |
443 | struct l2vpn_pw *pw; | |
444 | int msgsource = 0; | |
445 | ||
446 | lde_map2fec(map, ln->id, &fec); | |
447 | fn = (struct fec_node *)fec_find(&ft, &fec); | |
448 | if (fn == NULL) | |
449 | fn = fec_add(&fec); | |
450 | ||
451 | /* LMp.1: first check if we have a pending request running */ | |
452 | lre = (struct lde_req *)fec_find(&ln->sent_req, &fn->fec); | |
453 | if (lre) | |
454 | /* LMp.2: delete record of outstanding label request */ | |
455 | lde_req_del(ln, lre, 1); | |
456 | ||
457 | /* RFC 4447 control word and status tlv negotiation */ | |
458 | if (map->type == MAP_TYPE_PWID && l2vpn_pw_negotiate(ln, fn, map)) | |
459 | return; | |
460 | ||
461 | /* | |
462 | * LMp.3 - LMp.8: loop detection - unnecessary for frame-mode | |
463 | * mpls networks. | |
464 | */ | |
465 | ||
466 | /* LMp.9 */ | |
467 | me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); | |
468 | if (me) { | |
469 | /* LMp.10 */ | |
470 | if (me->map.label != map->label && lre == NULL) { | |
471 | /* LMp.10a */ | |
472 | lde_send_labelrelease(ln, fn, me->map.label); | |
473 | ||
474 | /* | |
475 | * Can not use lde_nbr_find_by_addr() because there's | |
476 | * the possibility of multipath. | |
477 | */ | |
478 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
479 | if (lde_address_find(ln, fnh->af, | |
480 | &fnh->nexthop) == NULL) | |
481 | continue; | |
482 | ||
483 | lde_send_delete_klabel(fn, fnh); | |
484 | fnh->remote_label = NO_LABEL; | |
485 | } | |
486 | } | |
487 | } | |
488 | ||
489 | /* | |
490 | * LMp.11 - 12: consider multiple nexthops in order to | |
491 | * support multipath | |
492 | */ | |
493 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
494 | /* LMp.15: install FEC in FIB */ | |
495 | switch (fec.type) { | |
496 | case FEC_TYPE_IPV4: | |
497 | case FEC_TYPE_IPV6: | |
498 | if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) | |
499 | continue; | |
500 | ||
501 | fnh->remote_label = map->label; | |
502 | lde_send_change_klabel(fn, fnh); | |
503 | break; | |
504 | case FEC_TYPE_PWID: | |
505 | pw = (struct l2vpn_pw *) fn->data; | |
506 | if (pw == NULL) | |
507 | continue; | |
508 | ||
509 | pw->remote_group = map->fec.pwid.group_id; | |
510 | if (map->flags & F_MAP_PW_IFMTU) | |
511 | pw->remote_mtu = map->fec.pwid.ifmtu; | |
512 | if (map->flags & F_MAP_PW_STATUS) | |
513 | pw->remote_status = map->pw_status; | |
514 | fnh->remote_label = map->label; | |
515 | if (l2vpn_pw_ok(pw, fnh)) | |
516 | lde_send_change_klabel(fn, fnh); | |
517 | break; | |
518 | default: | |
519 | break; | |
520 | } | |
521 | ||
522 | msgsource = 1; | |
523 | } | |
524 | /* LMp.13 & LMp.16: Record the mapping from this peer */ | |
525 | if (me == NULL) | |
526 | me = lde_map_add(ln, fn, 0); | |
527 | me->map = *map; | |
528 | ||
529 | if (msgsource == 0) | |
530 | /* LMp.13: just return since we use liberal lbl retention */ | |
531 | return; | |
532 | ||
533 | /* | |
534 | * LMp.17 - LMp.27 are unnecessary since we don't need to implement | |
535 | * loop detection. LMp.28 - LMp.30 are unnecessary because we are | |
536 | * merging capable. | |
537 | */ | |
538 | } | |
539 | ||
540 | void | |
541 | lde_check_request(struct map *map, struct lde_nbr *ln) | |
542 | { | |
543 | struct fec fec; | |
544 | struct lde_req *lre; | |
545 | struct fec_node *fn; | |
546 | struct fec_nh *fnh; | |
547 | ||
548 | /* LRq.1: skip loop detection (not necessary) */ | |
549 | ||
550 | /* LRq.2: is there a next hop for fec? */ | |
551 | lde_map2fec(map, ln->id, &fec); | |
552 | fn = (struct fec_node *)fec_find(&ft, &fec); | |
553 | if (fn == NULL || LIST_EMPTY(&fn->nexthops)) { | |
554 | /* LRq.5: send No Route notification */ | |
555 | lde_send_notification(ln->peerid, S_NO_ROUTE, map->msg_id, | |
556 | htons(MSG_TYPE_LABELREQUEST)); | |
557 | return; | |
558 | } | |
559 | ||
560 | /* LRq.3: is MsgSource the next hop? */ | |
561 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
562 | switch (fec.type) { | |
563 | case FEC_TYPE_IPV4: | |
564 | case FEC_TYPE_IPV6: | |
565 | if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) | |
566 | continue; | |
567 | ||
568 | /* LRq.4: send Loop Detected notification */ | |
569 | lde_send_notification(ln->peerid, S_LOOP_DETECTED, | |
570 | map->msg_id, htons(MSG_TYPE_LABELREQUEST)); | |
571 | return; | |
572 | default: | |
573 | break; | |
574 | } | |
575 | } | |
576 | ||
577 | /* LRq.6: first check if we have a pending request running */ | |
578 | lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec); | |
579 | if (lre != NULL) | |
580 | /* LRq.7: duplicate request */ | |
581 | return; | |
582 | ||
583 | /* LRq.8: record label request */ | |
584 | lre = lde_req_add(ln, &fn->fec, 0); | |
585 | if (lre != NULL) | |
586 | lre->msg_id = ntohl(map->msg_id); | |
587 | ||
588 | /* LRq.9: perform LSR label distribution */ | |
589 | lde_send_labelmapping(ln, fn, 1); | |
590 | ||
591 | /* | |
592 | * LRq.10: do nothing (Request Never) since we use liberal | |
593 | * label retention. | |
594 | * LRq.11 - 12 are unnecessary since we are merging capable. | |
595 | */ | |
596 | } | |
597 | ||
598 | void | |
599 | lde_check_release(struct map *map, struct lde_nbr *ln) | |
600 | { | |
601 | struct fec fec; | |
602 | struct fec_node *fn; | |
603 | struct lde_wdraw *lw; | |
604 | struct lde_map *me; | |
605 | ||
606 | /* TODO group wildcard */ | |
607 | if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID)) | |
608 | return; | |
609 | ||
610 | lde_map2fec(map, ln->id, &fec); | |
611 | fn = (struct fec_node *)fec_find(&ft, &fec); | |
612 | /* LRl.1: does FEC match a known FEC? */ | |
613 | if (fn == NULL) | |
614 | return; | |
615 | ||
616 | /* LRl.3: first check if we have a pending withdraw running */ | |
617 | lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); | |
618 | if (lw && (map->label == NO_LABEL || | |
619 | (lw->label != NO_LABEL && map->label == lw->label))) { | |
620 | /* LRl.4: delete record of outstanding label withdraw */ | |
621 | lde_wdraw_del(ln, lw); | |
622 | } | |
623 | ||
624 | /* LRl.6: check sent map list and remove it if available */ | |
625 | me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); | |
626 | if (me && (map->label == NO_LABEL || map->label == me->map.label)) | |
627 | lde_map_del(ln, me, 1); | |
628 | ||
629 | /* | |
630 | * LRl.11 - 13 are unnecessary since we remove the label from | |
631 | * forwarding/switching as soon as the FEC is unreachable. | |
632 | */ | |
633 | } | |
634 | ||
635 | void | |
636 | lde_check_release_wcard(struct map *map, struct lde_nbr *ln) | |
637 | { | |
638 | struct fec *f; | |
639 | struct fec_node *fn; | |
640 | struct lde_wdraw *lw; | |
641 | struct lde_map *me; | |
642 | ||
643 | RB_FOREACH(f, fec_tree, &ft) { | |
644 | fn = (struct fec_node *)f; | |
645 | ||
646 | /* LRl.3: first check if we have a pending withdraw running */ | |
647 | lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); | |
648 | if (lw && (map->label == NO_LABEL || | |
649 | (lw->label != NO_LABEL && map->label == lw->label))) { | |
650 | /* LRl.4: delete record of outstanding lbl withdraw */ | |
651 | lde_wdraw_del(ln, lw); | |
652 | } | |
653 | ||
654 | /* LRl.6: check sent map list and remove it if available */ | |
655 | me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); | |
656 | if (me && | |
657 | (map->label == NO_LABEL || map->label == me->map.label)) | |
658 | lde_map_del(ln, me, 1); | |
659 | ||
660 | /* | |
661 | * LRl.11 - 13 are unnecessary since we remove the label from | |
662 | * forwarding/switching as soon as the FEC is unreachable. | |
663 | */ | |
664 | } | |
665 | } | |
666 | ||
667 | void | |
668 | lde_check_withdraw(struct map *map, struct lde_nbr *ln) | |
669 | { | |
670 | struct fec fec; | |
671 | struct fec_node *fn; | |
672 | struct fec_nh *fnh; | |
673 | struct lde_map *me; | |
674 | struct l2vpn_pw *pw; | |
675 | ||
676 | /* TODO group wildcard */ | |
677 | if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID)) | |
678 | return; | |
679 | ||
680 | lde_map2fec(map, ln->id, &fec); | |
681 | fn = (struct fec_node *)fec_find(&ft, &fec); | |
682 | if (fn == NULL) | |
683 | fn = fec_add(&fec); | |
684 | ||
685 | /* LWd.1: remove label from forwarding/switching use */ | |
686 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
687 | switch (fec.type) { | |
688 | case FEC_TYPE_IPV4: | |
689 | case FEC_TYPE_IPV6: | |
690 | if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) | |
691 | continue; | |
692 | break; | |
693 | case FEC_TYPE_PWID: | |
694 | pw = (struct l2vpn_pw *) fn->data; | |
695 | if (pw == NULL) | |
696 | continue; | |
697 | break; | |
698 | default: | |
699 | break; | |
700 | } | |
701 | lde_send_delete_klabel(fn, fnh); | |
702 | fnh->remote_label = NO_LABEL; | |
703 | } | |
704 | ||
705 | /* LWd.2: send label release */ | |
706 | lde_send_labelrelease(ln, fn, map->label); | |
707 | ||
708 | /* LWd.3: check previously received label mapping */ | |
709 | me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); | |
710 | if (me && (map->label == NO_LABEL || map->label == me->map.label)) | |
711 | /* LWd.4: remove record of previously received lbl mapping */ | |
712 | lde_map_del(ln, me, 0); | |
713 | } | |
714 | ||
715 | void | |
716 | lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) | |
717 | { | |
718 | struct fec *f; | |
719 | struct fec_node *fn; | |
720 | struct fec_nh *fnh; | |
721 | struct lde_map *me; | |
722 | ||
723 | /* LWd.2: send label release */ | |
724 | lde_send_labelrelease(ln, NULL, map->label); | |
725 | ||
726 | RB_FOREACH(f, fec_tree, &ft) { | |
727 | fn = (struct fec_node *)f; | |
728 | ||
729 | /* LWd.1: remove label from forwarding/switching use */ | |
730 | LIST_FOREACH(fnh, &fn->nexthops, entry) { | |
731 | switch (f->type) { | |
732 | case FEC_TYPE_IPV4: | |
733 | case FEC_TYPE_IPV6: | |
734 | if (!lde_address_find(ln, fnh->af, | |
735 | &fnh->nexthop)) | |
736 | continue; | |
737 | break; | |
738 | case FEC_TYPE_PWID: | |
739 | if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr) | |
740 | continue; | |
741 | break; | |
742 | default: | |
743 | break; | |
744 | } | |
745 | lde_send_delete_klabel(fn, fnh); | |
746 | fnh->remote_label = NO_LABEL; | |
747 | } | |
748 | ||
749 | /* LWd.3: check previously received label mapping */ | |
750 | me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); | |
751 | if (me && (map->label == NO_LABEL || | |
752 | map->label == me->map.label)) | |
753 | /* | |
754 | * LWd.4: remove record of previously received | |
755 | * label mapping | |
756 | */ | |
757 | lde_map_del(ln, me, 0); | |
758 | } | |
759 | } | |
760 | ||
761 | /* gabage collector timer: timer to remove dead entries from the LIB */ | |
762 | ||
763 | /* ARGSUSED */ | |
eac6e3f0 RW |
764 | int |
765 | lde_gc_timer(struct thread *thread) | |
8429abe0 RW |
766 | { |
767 | struct fec *fec, *safe; | |
768 | struct fec_node *fn; | |
769 | int count = 0; | |
770 | ||
771 | RB_FOREACH_SAFE(fec, fec_tree, &ft, safe) { | |
772 | fn = (struct fec_node *) fec; | |
773 | ||
774 | if (!LIST_EMPTY(&fn->nexthops) || | |
775 | !LIST_EMPTY(&fn->downstream) || | |
776 | !LIST_EMPTY(&fn->upstream)) | |
777 | continue; | |
778 | ||
779 | fec_remove(&ft, &fn->fec); | |
780 | free(fn); | |
781 | count++; | |
782 | } | |
783 | ||
784 | if (count > 0) | |
785 | log_debug("%s: %u entries removed", __func__, count); | |
786 | ||
787 | lde_gc_start_timer(); | |
eac6e3f0 RW |
788 | |
789 | return (0); | |
8429abe0 RW |
790 | } |
791 | ||
792 | void | |
793 | lde_gc_start_timer(void) | |
794 | { | |
eac6e3f0 RW |
795 | THREAD_TIMER_OFF(gc_timer); |
796 | gc_timer = thread_add_timer(master, lde_gc_timer, NULL, | |
797 | LDE_GC_INTERVAL); | |
8429abe0 RW |
798 | } |
799 | ||
800 | void | |
801 | lde_gc_stop_timer(void) | |
802 | { | |
eac6e3f0 | 803 | THREAD_TIMER_OFF(gc_timer); |
8429abe0 | 804 | } |