xref: /openbsd-src/usr.sbin/ldpd/lde_lib.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: lde_lib.c,v 1.63 2016/07/01 23:36:38 renato Exp $ */
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 
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netmpls/mpls.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 
27 #include "ldpd.h"
28 #include "lde.h"
29 #include "log.h"
30 
31 static __inline int	 fec_compare(struct fec *, struct fec *);
32 static int		 lde_nbr_is_nexthop(struct fec_node *,
33 			    struct lde_nbr *);
34 static void		 fec_free(void *);
35 static struct fec_node	*fec_add(struct fec *fec);
36 static struct fec_nh	*fec_nh_add(struct fec_node *, int, union ldpd_addr *,
37 			    uint8_t priority);
38 static void		 fec_nh_del(struct fec_nh *);
39 
40 RB_GENERATE(fec_tree, fec, entry, fec_compare)
41 
42 struct fec_tree		 ft = RB_INITIALIZER(&ft);
43 struct event		 gc_timer;
44 
45 /* FEC tree functions */
46 void
47 fec_init(struct fec_tree *fh)
48 {
49 	RB_INIT(fh);
50 }
51 
52 static __inline int
53 fec_compare(struct fec *a, struct fec *b)
54 {
55 	if (a->type < b->type)
56 		return (-1);
57 	if (a->type > b->type)
58 		return (1);
59 
60 	switch (a->type) {
61 	case FEC_TYPE_IPV4:
62 		if (ntohl(a->u.ipv4.prefix.s_addr) <
63 		    ntohl(b->u.ipv4.prefix.s_addr))
64 			return (-1);
65 		if (ntohl(a->u.ipv4.prefix.s_addr) >
66 		    ntohl(b->u.ipv4.prefix.s_addr))
67 			return (1);
68 		if (a->u.ipv4.prefixlen < b->u.ipv4.prefixlen)
69 			return (-1);
70 		if (a->u.ipv4.prefixlen > b->u.ipv4.prefixlen)
71 			return (1);
72 		return (0);
73 	case FEC_TYPE_IPV6:
74 		if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix,
75 		    sizeof(struct in6_addr)) < 0)
76 			return (-1);
77 		if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix,
78 		    sizeof(struct in6_addr)) > 0)
79 			return (1);
80 		if (a->u.ipv6.prefixlen < b->u.ipv6.prefixlen)
81 			return (-1);
82 		if (a->u.ipv6.prefixlen > b->u.ipv6.prefixlen)
83 			return (1);
84 		return (0);
85 	case FEC_TYPE_PWID:
86 		if (a->u.pwid.type < b->u.pwid.type)
87 			return (-1);
88 		if (a->u.pwid.type > b->u.pwid.type)
89 			return (1);
90 		if (a->u.pwid.pwid < b->u.pwid.pwid)
91 			return (-1);
92 		if (a->u.pwid.pwid > b->u.pwid.pwid)
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 		if (ntohl(a->u.pwid.lsr_id.s_addr) >
98 		    ntohl(b->u.pwid.lsr_id.s_addr))
99 			return (1);
100 		return (0);
101 	}
102 
103 	return (-1);
104 }
105 
106 struct fec *
107 fec_find(struct fec_tree *fh, struct fec *f)
108 {
109 	return (RB_FIND(fec_tree, fh, f));
110 }
111 
112 int
113 fec_insert(struct fec_tree *fh, struct fec *f)
114 {
115 	if (RB_INSERT(fec_tree, fh, f) != NULL)
116 		return (-1);
117 	return (0);
118 }
119 
120 int
121 fec_remove(struct fec_tree *fh, struct fec *f)
122 {
123 	if (RB_REMOVE(fec_tree, fh, f) == NULL) {
124 		log_warnx("%s failed for %s", __func__, log_fec(f));
125 		return (-1);
126 	}
127 	return (0);
128 }
129 
130 void
131 fec_clear(struct fec_tree *fh, void (*free_cb)(void *))
132 {
133 	struct fec	*f;
134 
135 	while ((f = RB_ROOT(fh)) != NULL) {
136 		fec_remove(fh, f);
137 		free_cb(f);
138 	}
139 }
140 
141 /* routing table functions */
142 static int
143 lde_nbr_is_nexthop(struct fec_node *fn, struct lde_nbr *ln)
144 {
145 	struct fec_nh		*fnh;
146 
147 	LIST_FOREACH(fnh, &fn->nexthops, entry)
148 		if (lde_address_find(ln, fnh->af, &fnh->nexthop))
149 			return (1);
150 
151 	return (0);
152 }
153 
154 void
155 rt_dump(pid_t pid)
156 {
157 	struct fec		*f;
158 	struct fec_node		*fn;
159 	struct lde_map		*me;
160 	static struct ctl_rt	 rtctl;
161 
162 	RB_FOREACH(f, fec_tree, &ft) {
163 		fn = (struct fec_node *)f;
164 		if (fn->local_label == NO_LABEL &&
165 		    LIST_EMPTY(&fn->downstream))
166 			continue;
167 
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;
184 		LIST_FOREACH(me, &fn->downstream, entry) {
185 			rtctl.in_use = lde_nbr_is_nexthop(fn, me->nexthop);
186 			rtctl.nexthop = me->nexthop->id;
187 			rtctl.remote_label = me->map.label;
188 
189 			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid,
190 			    &rtctl, sizeof(rtctl));
191 		}
192 		if (LIST_EMPTY(&fn->downstream)) {
193 			rtctl.in_use = 0;
194 			rtctl.nexthop.s_addr = INADDR_ANY;
195 			rtctl.remote_label = NO_LABEL;
196 
197 			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid,
198 			    &rtctl, sizeof(rtctl));
199 		}
200 	}
201 }
202 
203 void
204 fec_snap(struct lde_nbr *ln)
205 {
206 	struct fec	*f;
207 	struct fec_node	*fn;
208 
209 	RB_FOREACH(f, fec_tree, &ft) {
210 		fn = (struct fec_node *)f;
211 		if (fn->local_label == NO_LABEL)
212 			continue;
213 
214 		lde_send_labelmapping(ln, fn, 0);
215 	}
216 
217 	lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0);
218 }
219 
220 static void
221 fec_free(void *arg)
222 {
223 	struct fec_node	*fn = arg;
224 	struct fec_nh	*fnh;
225 
226 	while ((fnh = LIST_FIRST(&fn->nexthops)))
227 		fec_nh_del(fnh);
228 	if (!LIST_EMPTY(&fn->downstream))
229 		log_warnx("%s: fec %s downstream list not empty", __func__,
230 		    log_fec(&fn->fec));
231 	if (!LIST_EMPTY(&fn->upstream))
232 		log_warnx("%s: fec %s upstream list not empty", __func__,
233 		    log_fec(&fn->fec));
234 
235 	free(fn);
236 }
237 
238 void
239 fec_tree_clear(void)
240 {
241 	fec_clear(&ft, fec_free);
242 }
243 
244 static struct fec_node *
245 fec_add(struct fec *fec)
246 {
247 	struct fec_node	*fn;
248 
249 	fn = calloc(1, sizeof(*fn));
250 	if (fn == NULL)
251 		fatal(__func__);
252 
253 	fn->fec = *fec;
254 	fn->local_label = NO_LABEL;
255 	LIST_INIT(&fn->upstream);
256 	LIST_INIT(&fn->downstream);
257 	LIST_INIT(&fn->nexthops);
258 
259 	if (fec_insert(&ft, &fn->fec))
260 		log_warnx("failed to add %s to ft tree",
261 		    log_fec(&fn->fec));
262 
263 	return (fn);
264 }
265 
266 struct fec_nh *
267 fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop,
268     uint8_t priority)
269 {
270 	struct fec_nh	*fnh;
271 
272 	LIST_FOREACH(fnh, &fn->nexthops, entry)
273 		if (fnh->af == af &&
274 		    ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 &&
275 		    fnh->priority == priority)
276 			return (fnh);
277 
278 	return (NULL);
279 }
280 
281 static struct fec_nh *
282 fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop,
283     uint8_t priority)
284 {
285 	struct fec_nh	*fnh;
286 
287 	fnh = calloc(1, sizeof(*fnh));
288 	if (fnh == NULL)
289 		fatal(__func__);
290 
291 	fnh->af = af;
292 	fnh->nexthop = *nexthop;
293 	fnh->remote_label = NO_LABEL;
294 	fnh->priority = priority;
295 	LIST_INSERT_HEAD(&fn->nexthops, fnh, entry);
296 
297 	return (fnh);
298 }
299 
300 static void
301 fec_nh_del(struct fec_nh *fnh)
302 {
303 	LIST_REMOVE(fnh, entry);
304 	free(fnh);
305 }
306 
307 uint32_t
308 egress_label(enum fec_type fec_type)
309 {
310 	switch (fec_type) {
311 	case FEC_TYPE_IPV4:
312 		if (ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL)
313 			return (MPLS_LABEL_IPV4NULL);
314 		break;
315 	case FEC_TYPE_IPV6:
316 		if (ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL)
317 			return (MPLS_LABEL_IPV6NULL);
318 		break;
319 	default:
320 		fatalx("egress_label: unexpected fec type");
321 	}
322 
323 	return (MPLS_LABEL_IMPLNULL);
324 }
325 
326 void
327 lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
328     uint8_t priority, int connected, void *data)
329 {
330 	struct fec_node		*fn;
331 	struct fec_nh		*fnh;
332 	struct lde_map		*me;
333 	struct lde_nbr		*ln;
334 
335 	fn = (struct fec_node *)fec_find(&ft, fec);
336 	if (fn == NULL)
337 		fn = fec_add(fec);
338 	if (fec_nh_find(fn, af, nexthop, priority) != NULL)
339 		return;
340 
341 	log_debug("lde add fec %s nexthop %s",
342 	    log_fec(&fn->fec), log_addr(af, nexthop));
343 
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);
359 	lde_send_change_klabel(fn, fnh);
360 
361 	switch (fn->fec.type) {
362 	case FEC_TYPE_IPV4:
363 	case FEC_TYPE_IPV6:
364 		ln = lde_nbr_find_by_addr(af, &fnh->nexthop);
365 		break;
366 	case FEC_TYPE_PWID:
367 		ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id);
368 		break;
369 	default:
370 		ln = NULL;
371 		break;
372 	}
373 
374 	if (ln) {
375 		/* FEC.2  */
376 		me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
377 		if (me)
378 			/* FEC.5 */
379 			lde_check_mapping(&me->map, ln);
380 	}
381 }
382 
383 void
384 lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
385     uint8_t priority)
386 {
387 	struct fec_node		*fn;
388 	struct fec_nh		*fnh;
389 
390 	fn = (struct fec_node *)fec_find(&ft, fec);
391 	if (fn == NULL)
392 		/* route lost */
393 		return;
394 	fnh = fec_nh_find(fn, af, nexthop, priority);
395 	if (fnh == NULL)
396 		/* route lost */
397 		return;
398 
399 	log_debug("lde remove fec %s nexthop %s",
400 	    log_fec(&fn->fec), log_addr(af, nexthop));
401 
402 	lde_send_delete_klabel(fn, fnh);
403 	fec_nh_del(fnh);
404 	if (LIST_EMPTY(&fn->nexthops)) {
405 		lde_send_labelwithdraw_all(fn, NO_LABEL);
406 		fn->local_label = NO_LABEL;
407 		if (fn->fec.type == FEC_TYPE_PWID)
408 			fn->data = NULL;
409 	}
410 }
411 
412 void
413 lde_check_mapping(struct map *map, struct lde_nbr *ln)
414 {
415 	struct fec		 fec;
416 	struct fec_node		*fn;
417 	struct fec_nh		*fnh;
418 	struct lde_req		*lre;
419 	struct lde_map		*me;
420 	struct l2vpn_pw		*pw;
421 	int			 msgsource = 0;
422 
423 	lde_map2fec(map, ln->id, &fec);
424 	fn = (struct fec_node *)fec_find(&ft, &fec);
425 	if (fn == NULL)
426 		fn = fec_add(&fec);
427 
428 	/* LMp.1: first check if we have a pending request running */
429 	lre = (struct lde_req *)fec_find(&ln->sent_req, &fn->fec);
430 	if (lre)
431 		/* LMp.2: delete record of outstanding label request */
432 		lde_req_del(ln, lre, 1);
433 
434 	/* RFC 4447 control word and status tlv negotiation */
435 	if (map->type == MAP_TYPE_PWID && l2vpn_pw_negotiate(ln, fn, map))
436 		return;
437 
438 	/*
439 	 * LMp.3 - LMp.8: loop detection - unnecessary for frame-mode
440 	 * mpls networks.
441 	 */
442 
443 	/* LMp.9 */
444 	me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
445 	if (me) {
446 		/* LMp.10 */
447 		if (me->map.label != map->label && lre == NULL) {
448 			/* LMp.10a */
449 			lde_send_labelrelease(ln, fn, me->map.label);
450 
451 			/*
452 			 * Can not use lde_nbr_find_by_addr() because there's
453 			 * the possibility of multipath.
454 			 */
455 			LIST_FOREACH(fnh, &fn->nexthops, entry) {
456 				if (lde_address_find(ln, fnh->af,
457 				    &fnh->nexthop) == NULL)
458 					continue;
459 
460 				lde_send_delete_klabel(fn, fnh);
461 				fnh->remote_label = NO_LABEL;
462 			}
463 		}
464 	}
465 
466 	/*
467 	 * LMp.11 - 12: consider multiple nexthops in order to
468 	 * support multipath
469 	 */
470 	LIST_FOREACH(fnh, &fn->nexthops, entry) {
471 		/* LMp.15: install FEC in FIB */
472 		switch (fec.type) {
473 		case FEC_TYPE_IPV4:
474 		case FEC_TYPE_IPV6:
475 			if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
476 				continue;
477 
478 			fnh->remote_label = map->label;
479 			lde_send_change_klabel(fn, fnh);
480 			break;
481 		case FEC_TYPE_PWID:
482 			pw = (struct l2vpn_pw *) fn->data;
483 			if (pw == NULL)
484 				continue;
485 
486 			pw->remote_group = map->fec.pwid.group_id;
487 			if (map->flags & F_MAP_PW_IFMTU)
488 				pw->remote_mtu = map->fec.pwid.ifmtu;
489 			if (map->flags & F_MAP_PW_STATUS)
490 				pw->remote_status = map->pw_status;
491 			fnh->remote_label = map->label;
492 			if (l2vpn_pw_ok(pw, fnh))
493 				lde_send_change_klabel(fn, fnh);
494 			break;
495 		default:
496 			break;
497 		}
498 
499 		msgsource = 1;
500 	}
501 	/* LMp.13 & LMp.16: Record the mapping from this peer */
502 	if (me == NULL)
503 		me = lde_map_add(ln, fn, 0);
504 	me->map = *map;
505 
506 	if (msgsource == 0)
507 		/* LMp.13: just return since we use liberal lbl retention */
508 		return;
509 
510 	/*
511 	 * LMp.17 - LMp.27 are unnecessary since we don't need to implement
512 	 * loop detection. LMp.28 - LMp.30 are unnecessary because we are
513 	 * merging capable.
514 	 */
515 }
516 
517 void
518 lde_check_request(struct map *map, struct lde_nbr *ln)
519 {
520 	struct fec	 fec;
521 	struct lde_req	*lre;
522 	struct fec_node	*fn;
523 	struct fec_nh	*fnh;
524 
525 	/* LRq.1: skip loop detection (not necessary) */
526 
527 	/* LRq.2: is there a next hop for fec? */
528 	lde_map2fec(map, ln->id, &fec);
529 	fn = (struct fec_node *)fec_find(&ft, &fec);
530 	if (fn == NULL || LIST_EMPTY(&fn->nexthops)) {
531 		/* LRq.5: send No Route notification */
532 		lde_send_notification(ln->peerid, S_NO_ROUTE, map->msg_id,
533 		    htons(MSG_TYPE_LABELREQUEST));
534 		return;
535 	}
536 
537 	/* LRq.3: is MsgSource the next hop? */
538 	LIST_FOREACH(fnh, &fn->nexthops, entry) {
539 		switch (fec.type) {
540 		case FEC_TYPE_IPV4:
541 		case FEC_TYPE_IPV6:
542 			if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
543 				continue;
544 
545 			/* LRq.4: send Loop Detected notification */
546 			lde_send_notification(ln->peerid, S_LOOP_DETECTED,
547 			    map->msg_id, htons(MSG_TYPE_LABELREQUEST));
548 			return;
549 		default:
550 			break;
551 		}
552 	}
553 
554 	/* LRq.6: first check if we have a pending request running */
555 	lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
556 	if (lre != NULL)
557 		/* LRq.7: duplicate request */
558 		return;
559 
560 	/* LRq.8: record label request */
561 	lre = lde_req_add(ln, &fn->fec, 0);
562 	if (lre != NULL)
563 		lre->msg_id = ntohl(map->msg_id);
564 
565 	/* LRq.9: perform LSR label distribution */
566 	lde_send_labelmapping(ln, fn, 1);
567 
568 	/*
569 	 * LRq.10: do nothing (Request Never) since we use liberal
570 	 * label retention.
571 	 * LRq.11 - 12 are unnecessary since we are merging capable.
572 	 */
573 }
574 
575 void
576 lde_check_release(struct map *map, struct lde_nbr *ln)
577 {
578 	struct fec		 fec;
579 	struct fec_node		*fn;
580 	struct lde_wdraw	*lw;
581 	struct lde_map		*me;
582 
583 	/* TODO group wildcard */
584 	if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))
585 		return;
586 
587 	lde_map2fec(map, ln->id, &fec);
588 	fn = (struct fec_node *)fec_find(&ft, &fec);
589 	/* LRl.1: does FEC match a known FEC? */
590 	if (fn == NULL)
591 		return;
592 
593 	/* LRl.3: first check if we have a pending withdraw running */
594 	lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
595 	if (lw && (map->label == NO_LABEL ||
596 	    (lw->label != NO_LABEL && map->label == lw->label))) {
597 		/* LRl.4: delete record of outstanding label withdraw */
598 		lde_wdraw_del(ln, lw);
599 	}
600 
601 	/* LRl.6: check sent map list and remove it if available */
602 	me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
603 	if (me && (map->label == NO_LABEL || map->label == me->map.label))
604 		lde_map_del(ln, me, 1);
605 
606 	/*
607 	 * LRl.11 - 13 are unnecessary since we remove the label from
608 	 * forwarding/switching as soon as the FEC is unreachable.
609 	 */
610 }
611 
612 void
613 lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
614 {
615 	struct fec		*f;
616 	struct fec_node		*fn;
617 	struct lde_wdraw	*lw;
618 	struct lde_map		*me;
619 
620 	RB_FOREACH(f, fec_tree, &ft) {
621 		fn = (struct fec_node *)f;
622 
623 		/* LRl.3: first check if we have a pending withdraw running */
624 		lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
625 		if (lw && (map->label == NO_LABEL ||
626 		    (lw->label != NO_LABEL && map->label == lw->label))) {
627 			/* LRl.4: delete record of outstanding lbl withdraw */
628 			lde_wdraw_del(ln, lw);
629 		}
630 
631 		/* LRl.6: check sent map list and remove it if available */
632 		me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
633 		if (me &&
634 		    (map->label == NO_LABEL || map->label == me->map.label))
635 			lde_map_del(ln, me, 1);
636 
637 		/*
638 		 * LRl.11 - 13 are unnecessary since we remove the label from
639 		 * forwarding/switching as soon as the FEC is unreachable.
640 		 */
641 	}
642 }
643 
644 void
645 lde_check_withdraw(struct map *map, struct lde_nbr *ln)
646 {
647 	struct fec		 fec;
648 	struct fec_node		*fn;
649 	struct fec_nh		*fnh;
650 	struct lde_map		*me;
651 	struct l2vpn_pw		*pw;
652 
653 	/* TODO group wildcard */
654 	if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))
655 		return;
656 
657 	lde_map2fec(map, ln->id, &fec);
658 	fn = (struct fec_node *)fec_find(&ft, &fec);
659 	if (fn == NULL)
660 		fn = fec_add(&fec);
661 
662 	/* LWd.1: remove label from forwarding/switching use */
663 	LIST_FOREACH(fnh, &fn->nexthops, entry) {
664 		switch (fec.type) {
665 		case FEC_TYPE_IPV4:
666 		case FEC_TYPE_IPV6:
667 			if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
668 				continue;
669 			break;
670 		case FEC_TYPE_PWID:
671 			pw = (struct l2vpn_pw *) fn->data;
672 			if (pw == NULL)
673 				continue;
674 			break;
675 		default:
676 			break;
677 		}
678 		lde_send_delete_klabel(fn, fnh);
679 		fnh->remote_label = NO_LABEL;
680 	}
681 
682 	/* LWd.2: send label release */
683 	lde_send_labelrelease(ln, fn, map->label);
684 
685 	/* LWd.3: check previously received label mapping */
686 	me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
687 	if (me && (map->label == NO_LABEL || map->label == me->map.label))
688 		/* LWd.4: remove record of previously received lbl mapping */
689 		lde_map_del(ln, me, 0);
690 }
691 
692 void
693 lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
694 {
695 	struct fec	*f;
696 	struct fec_node	*fn;
697 	struct fec_nh	*fnh;
698 	struct lde_map	*me;
699 
700 	/* LWd.2: send label release */
701 	lde_send_labelrelease(ln, NULL, map->label);
702 
703 	RB_FOREACH(f, fec_tree, &ft) {
704 		fn = (struct fec_node *)f;
705 
706 		/* LWd.1: remove label from forwarding/switching use */
707 		LIST_FOREACH(fnh, &fn->nexthops, entry) {
708 			switch (f->type) {
709 			case FEC_TYPE_IPV4:
710 			case FEC_TYPE_IPV6:
711 				if (!lde_address_find(ln, fnh->af,
712 				    &fnh->nexthop))
713 					continue;
714 				break;
715 			case FEC_TYPE_PWID:
716 				if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
717 					continue;
718 				break;
719 			default:
720 				break;
721 			}
722 			lde_send_delete_klabel(fn, fnh);
723 			fnh->remote_label = NO_LABEL;
724 		}
725 
726 		/* LWd.3: check previously received label mapping */
727 		me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
728 		if (me && (map->label == NO_LABEL ||
729 		    map->label == me->map.label))
730 			/*
731 			 * LWd.4: remove record of previously received
732 			 * label mapping
733 			 */
734 			lde_map_del(ln, me, 0);
735 	}
736 }
737 
738 /* gabage collector timer: timer to remove dead entries from the LIB */
739 
740 /* ARGSUSED */
741 void
742 lde_gc_timer(int fd, short event, void *arg)
743 {
744 	struct fec	*fec, *safe;
745 	struct fec_node	*fn;
746 	int		 count = 0;
747 
748 	RB_FOREACH_SAFE(fec, fec_tree, &ft, safe) {
749 		fn = (struct fec_node *) fec;
750 
751 		if (!LIST_EMPTY(&fn->nexthops) ||
752 		    !LIST_EMPTY(&fn->downstream) ||
753 		    !LIST_EMPTY(&fn->upstream))
754 			continue;
755 
756 		fec_remove(&ft, &fn->fec);
757 		free(fn);
758 		count++;
759 	}
760 
761 	if (count > 0)
762 		log_debug("%s: %u entries removed", __func__, count);
763 
764 	lde_gc_start_timer();
765 }
766 
767 void
768 lde_gc_start_timer(void)
769 {
770 	struct timeval	 tv;
771 
772 	timerclear(&tv);
773 	tv.tv_sec = LDE_GC_INTERVAL;
774 	if (evtimer_add(&gc_timer, &tv) == -1)
775 		fatal(__func__);
776 }
777 
778 void
779 lde_gc_stop_timer(void)
780 {
781 	if (evtimer_pending(&gc_timer, NULL) &&
782 	    evtimer_del(&gc_timer) == -1)
783 		fatal(__func__);
784 }
785