xref: /openbsd-src/usr.sbin/ldpd/lde_lib.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: lde_lib.c,v 1.71 2023/03/08 04:43:13 guenther Exp $ */
2ab0c2486Smichele 
3ab0c2486Smichele /*
45dc9330aSrenato  * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5ab0c2486Smichele  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6ab0c2486Smichele  *
7ab0c2486Smichele  * Permission to use, copy, modify, and distribute this software for any
8ab0c2486Smichele  * purpose with or without fee is hereby granted, provided that the above
9ab0c2486Smichele  * copyright notice and this permission notice appear in all copies.
10ab0c2486Smichele  *
11ab0c2486Smichele  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12ab0c2486Smichele  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13ab0c2486Smichele  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14ab0c2486Smichele  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15ab0c2486Smichele  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16ab0c2486Smichele  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17ab0c2486Smichele  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18ab0c2486Smichele  */
19ab0c2486Smichele 
20ab0c2486Smichele #include <sys/types.h>
21ab0c2486Smichele #include <sys/socket.h>
22ab0c2486Smichele #include <netmpls/mpls.h>
23ab0c2486Smichele #include <stdlib.h>
24ab0c2486Smichele #include <string.h>
255411bbb6Srenato #include <limits.h>
26ab0c2486Smichele 
27ab0c2486Smichele #include "ldpd.h"
28ab0c2486Smichele #include "lde.h"
299246985aSrenato #include "ldpe.h"
305411bbb6Srenato #include "log.h"
31ab0c2486Smichele 
32c28a25a1Srenato static __inline int	 fec_compare(struct fec *, struct fec *);
33c28a25a1Srenato static int		 lde_nbr_is_nexthop(struct fec_node *,
34c28a25a1Srenato 			    struct lde_nbr *);
35c28a25a1Srenato static void		 fec_free(void *);
36c28a25a1Srenato static struct fec_node	*fec_add(struct fec *fec);
370c0343b7Srenato static struct fec_nh	*fec_nh_add(struct fec_node *, int, union ldpd_addr *,
380c0343b7Srenato 			    uint8_t priority);
39c28a25a1Srenato static void		 fec_nh_del(struct fec_nh *);
40a094a533Sclaudio 
41e3948831Sclaudio RB_GENERATE(fec_tree, fec, entry, fec_compare)
42e3948831Sclaudio 
436106bae4Srenato struct fec_tree		 ft = RB_INITIALIZER(&ft);
44b79e02a8Srenato struct event		 gc_timer;
45ab0c2486Smichele 
468fc45048Smiod /* FEC tree functions */
47ab0c2486Smichele void
fec_init(struct fec_tree * fh)48e3948831Sclaudio fec_init(struct fec_tree *fh)
49ab0c2486Smichele {
50e3948831Sclaudio 	RB_INIT(fh);
51ab0c2486Smichele }
52ab0c2486Smichele 
53c28a25a1Srenato static __inline int
fec_compare(struct fec * a,struct fec * b)54e3948831Sclaudio fec_compare(struct fec *a, struct fec *b)
55ab0c2486Smichele {
566399cec1Srenato 	if (a->type < b->type)
57ab0c2486Smichele 		return (-1);
586399cec1Srenato 	if (a->type > b->type)
59ab0c2486Smichele 		return (1);
60ab0c2486Smichele 
616399cec1Srenato 	switch (a->type) {
626399cec1Srenato 	case FEC_TYPE_IPV4:
636399cec1Srenato 		if (ntohl(a->u.ipv4.prefix.s_addr) <
646399cec1Srenato 		    ntohl(b->u.ipv4.prefix.s_addr))
656399cec1Srenato 			return (-1);
666399cec1Srenato 		if (ntohl(a->u.ipv4.prefix.s_addr) >
676399cec1Srenato 		    ntohl(b->u.ipv4.prefix.s_addr))
686399cec1Srenato 			return (1);
696399cec1Srenato 		if (a->u.ipv4.prefixlen < b->u.ipv4.prefixlen)
706399cec1Srenato 			return (-1);
716399cec1Srenato 		if (a->u.ipv4.prefixlen > b->u.ipv4.prefixlen)
726399cec1Srenato 			return (1);
73ab0c2486Smichele 		return (0);
74a8c39dc0Srenato 	case FEC_TYPE_IPV6:
75a8c39dc0Srenato 		if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix,
76a8c39dc0Srenato 		    sizeof(struct in6_addr)) < 0)
77a8c39dc0Srenato 			return (-1);
78a8c39dc0Srenato 		if (memcmp(&a->u.ipv6.prefix, &b->u.ipv6.prefix,
79a8c39dc0Srenato 		    sizeof(struct in6_addr)) > 0)
80a8c39dc0Srenato 			return (1);
81a8c39dc0Srenato 		if (a->u.ipv6.prefixlen < b->u.ipv6.prefixlen)
82a8c39dc0Srenato 			return (-1);
83a8c39dc0Srenato 		if (a->u.ipv6.prefixlen > b->u.ipv6.prefixlen)
84a8c39dc0Srenato 			return (1);
85a8c39dc0Srenato 		return (0);
866399cec1Srenato 	case FEC_TYPE_PWID:
876399cec1Srenato 		if (a->u.pwid.type < b->u.pwid.type)
886399cec1Srenato 			return (-1);
896399cec1Srenato 		if (a->u.pwid.type > b->u.pwid.type)
906399cec1Srenato 			return (1);
916399cec1Srenato 		if (a->u.pwid.pwid < b->u.pwid.pwid)
926399cec1Srenato 			return (-1);
936399cec1Srenato 		if (a->u.pwid.pwid > b->u.pwid.pwid)
946399cec1Srenato 			return (1);
9572bfe95eSrenato 		if (ntohl(a->u.pwid.lsr_id.s_addr) <
9672bfe95eSrenato 		    ntohl(b->u.pwid.lsr_id.s_addr))
976399cec1Srenato 			return (-1);
9872bfe95eSrenato 		if (ntohl(a->u.pwid.lsr_id.s_addr) >
9972bfe95eSrenato 		    ntohl(b->u.pwid.lsr_id.s_addr))
1006399cec1Srenato 			return (1);
1016399cec1Srenato 		return (0);
102ab0c2486Smichele 	}
103ab0c2486Smichele 
1046399cec1Srenato 	return (-1);
105ab0c2486Smichele }
106ab0c2486Smichele 
107e3948831Sclaudio struct fec *
fec_find(struct fec_tree * fh,struct fec * f)108e3948831Sclaudio fec_find(struct fec_tree *fh, struct fec *f)
109e3948831Sclaudio {
110e3948831Sclaudio 	return (RB_FIND(fec_tree, fh, f));
111e3948831Sclaudio }
112e3948831Sclaudio 
113ab0c2486Smichele int
fec_insert(struct fec_tree * fh,struct fec * f)114e3948831Sclaudio fec_insert(struct fec_tree *fh, struct fec *f)
115ab0c2486Smichele {
116e3948831Sclaudio 	if (RB_INSERT(fec_tree, fh, f) != NULL)
117ab0c2486Smichele 		return (-1);
118ab0c2486Smichele 	return (0);
119ab0c2486Smichele }
120ab0c2486Smichele 
121ab0c2486Smichele int
fec_remove(struct fec_tree * fh,struct fec * f)122e3948831Sclaudio fec_remove(struct fec_tree *fh, struct fec *f)
123ab0c2486Smichele {
124e3948831Sclaudio 	if (RB_REMOVE(fec_tree, fh, f) == NULL) {
125b7b4db73Srenato 		log_warnx("%s failed for %s", __func__, log_fec(f));
126ab0c2486Smichele 		return (-1);
127ab0c2486Smichele 	}
128ab0c2486Smichele 	return (0);
129ab0c2486Smichele }
130ab0c2486Smichele 
131ab0c2486Smichele void
fec_clear(struct fec_tree * fh,void (* free_cb)(void *))132e3948831Sclaudio fec_clear(struct fec_tree *fh, void (*free_cb)(void *))
133e3948831Sclaudio {
134e3948831Sclaudio 	struct fec	*f;
135e3948831Sclaudio 
136e3948831Sclaudio 	while ((f = RB_ROOT(fh)) != NULL) {
137e3948831Sclaudio 		fec_remove(fh, f);
138e3948831Sclaudio 		free_cb(f);
139e3948831Sclaudio 	}
140e3948831Sclaudio }
141e3948831Sclaudio 
142a094a533Sclaudio /* routing table functions */
143c28a25a1Srenato static int
lde_nbr_is_nexthop(struct fec_node * fn,struct lde_nbr * ln)1446106bae4Srenato lde_nbr_is_nexthop(struct fec_node *fn, struct lde_nbr *ln)
145b3d43398Srenato {
1466106bae4Srenato 	struct fec_nh		*fnh;
147b3d43398Srenato 
1486106bae4Srenato 	LIST_FOREACH(fnh, &fn->nexthops, entry)
149a8c39dc0Srenato 		if (lde_address_find(ln, fnh->af, &fnh->nexthop))
150b3d43398Srenato 			return (1);
151b3d43398Srenato 
152b3d43398Srenato 	return (0);
153b3d43398Srenato }
154b3d43398Srenato 
155e3948831Sclaudio void
rt_dump(pid_t pid)156ab0c2486Smichele rt_dump(pid_t pid)
157ab0c2486Smichele {
158e3948831Sclaudio 	struct fec		*f;
1596106bae4Srenato 	struct fec_node		*fn;
160a094a533Sclaudio 	struct lde_map		*me;
161ab0c2486Smichele 	static struct ctl_rt	 rtctl;
162ab0c2486Smichele 
1636106bae4Srenato 	RB_FOREACH(f, fec_tree, &ft) {
1646106bae4Srenato 		fn = (struct fec_node *)f;
1656106bae4Srenato 		if (fn->local_label == NO_LABEL &&
1666106bae4Srenato 		    LIST_EMPTY(&fn->downstream))
167cf483f25Srenato 			continue;
168cf483f25Srenato 
169a8c39dc0Srenato 		switch (fn->fec.type) {
170a8c39dc0Srenato 		case FEC_TYPE_IPV4:
171a8c39dc0Srenato 			rtctl.af = AF_INET;
172a8c39dc0Srenato 			rtctl.prefix.v4 = fn->fec.u.ipv4.prefix;
1736399cec1Srenato 			rtctl.prefixlen = fn->fec.u.ipv4.prefixlen;
174a8c39dc0Srenato 			break;
175a8c39dc0Srenato 		case FEC_TYPE_IPV6:
176a8c39dc0Srenato 			rtctl.af = AF_INET6;
177a8c39dc0Srenato 			rtctl.prefix.v6 = fn->fec.u.ipv6.prefix;
178a8c39dc0Srenato 			rtctl.prefixlen = fn->fec.u.ipv6.prefixlen;
179a8c39dc0Srenato 			break;
180a8c39dc0Srenato 		default:
181a8c39dc0Srenato 			continue;
182a8c39dc0Srenato 		}
183ab0c2486Smichele 
184a8c39dc0Srenato 		rtctl.local_label = fn->local_label;
1856106bae4Srenato 		LIST_FOREACH(me, &fn->downstream, entry) {
1866106bae4Srenato 			rtctl.in_use = lde_nbr_is_nexthop(fn, me->nexthop);
187a094a533Sclaudio 			rtctl.nexthop = me->nexthop->id;
18829d4fbdbSrenato 			rtctl.remote_label = me->map.label;
189a094a533Sclaudio 
190a094a533Sclaudio 			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid,
191a094a533Sclaudio 			    &rtctl, sizeof(rtctl));
192a094a533Sclaudio 		}
1936106bae4Srenato 		if (LIST_EMPTY(&fn->downstream)) {
194b3d43398Srenato 			rtctl.in_use = 0;
195b3d43398Srenato 			rtctl.nexthop.s_addr = INADDR_ANY;
196b3d43398Srenato 			rtctl.remote_label = NO_LABEL;
197b3d43398Srenato 
198b3d43398Srenato 			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid,
199b3d43398Srenato 			    &rtctl, sizeof(rtctl));
200a094a533Sclaudio 		}
201ab0c2486Smichele 	}
202ab0c2486Smichele }
203ab0c2486Smichele 
204ab0c2486Smichele void
fec_snap(struct lde_nbr * ln)2056106bae4Srenato fec_snap(struct lde_nbr *ln)
206ab0c2486Smichele {
207e3948831Sclaudio 	struct fec	*f;
2086106bae4Srenato 	struct fec_node	*fn;
209ab0c2486Smichele 
2106106bae4Srenato 	RB_FOREACH(f, fec_tree, &ft) {
2116106bae4Srenato 		fn = (struct fec_node *)f;
2126106bae4Srenato 		if (fn->local_label == NO_LABEL)
213cf483f25Srenato 			continue;
214ab0c2486Smichele 
2156399cec1Srenato 		lde_send_labelmapping(ln, fn, 0);
216ab0c2486Smichele 	}
21734f55a3fSrenato 
21834f55a3fSrenato 	lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0);
2199246985aSrenato 
2209246985aSrenato 	/*
2219246985aSrenato 	 * RFC 5919 - Section 4:
2229246985aSrenato 	 * "An LDP speaker that conforms to this specification SHOULD signal
2239246985aSrenato 	 * completion of its label advertisements to a peer by means of a
2249246985aSrenato 	 * Notification message, if its peer has advertised the Unrecognized
2259246985aSrenato 	 * Notification capability during session establishment.  The LDP
2269246985aSrenato 	 * speaker SHOULD send the Notification message (per Forwarding
2279246985aSrenato 	 * Equivalence Class (FEC) Type) to a peer even if the LDP speaker has
2289246985aSrenato 	 * zero Label bindings to advertise to that peer".
2299246985aSrenato 	 */
2309246985aSrenato 	if (ln->flags & F_NBR_CAP_UNOTIF) {
2319246985aSrenato 		lde_send_notification_eol_prefix(ln, AF_INET);
2329246985aSrenato 		lde_send_notification_eol_prefix(ln, AF_INET6);
2339246985aSrenato 		lde_send_notification_eol_pwid(ln, PW_TYPE_WILDCARD);
2349246985aSrenato 	}
235ab0c2486Smichele }
236ab0c2486Smichele 
237c28a25a1Srenato static void
fec_free(void * arg)2386106bae4Srenato fec_free(void *arg)
239a094a533Sclaudio {
2406106bae4Srenato 	struct fec_node	*fn = arg;
2416106bae4Srenato 	struct fec_nh	*fnh;
242a094a533Sclaudio 
2436106bae4Srenato 	while ((fnh = LIST_FIRST(&fn->nexthops)))
2446106bae4Srenato 		fec_nh_del(fnh);
2456106bae4Srenato 	if (!LIST_EMPTY(&fn->downstream))
246b7b4db73Srenato 		log_warnx("%s: fec %s downstream list not empty", __func__,
2476399cec1Srenato 		    log_fec(&fn->fec));
2486106bae4Srenato 	if (!LIST_EMPTY(&fn->upstream))
249b7b4db73Srenato 		log_warnx("%s: fec %s upstream list not empty", __func__,
2506399cec1Srenato 		    log_fec(&fn->fec));
251a094a533Sclaudio 
2526106bae4Srenato 	free(fn);
253a094a533Sclaudio }
254a094a533Sclaudio 
255a094a533Sclaudio void
fec_tree_clear(void)2566106bae4Srenato fec_tree_clear(void)
257ab0c2486Smichele {
2586106bae4Srenato 	fec_clear(&ft, fec_free);
259a094a533Sclaudio }
260a094a533Sclaudio 
261c28a25a1Srenato static struct fec_node *
fec_add(struct fec * fec)2626399cec1Srenato fec_add(struct fec *fec)
263a094a533Sclaudio {
2646106bae4Srenato 	struct fec_node	*fn;
265a094a533Sclaudio 
2666106bae4Srenato 	fn = calloc(1, sizeof(*fn));
2676106bae4Srenato 	if (fn == NULL)
268b7b4db73Srenato 		fatal(__func__);
269a094a533Sclaudio 
2707aa09c5dSrenato 	fn->fec = *fec;
2716106bae4Srenato 	fn->local_label = NO_LABEL;
2726106bae4Srenato 	LIST_INIT(&fn->upstream);
2736106bae4Srenato 	LIST_INIT(&fn->downstream);
2746106bae4Srenato 	LIST_INIT(&fn->nexthops);
275a094a533Sclaudio 
2766106bae4Srenato 	if (fec_insert(&ft, &fn->fec))
2776399cec1Srenato 		log_warnx("failed to add %s to ft tree",
2786399cec1Srenato 		    log_fec(&fn->fec));
279a094a533Sclaudio 
2806106bae4Srenato 	return (fn);
281a094a533Sclaudio }
282a094a533Sclaudio 
2836106bae4Srenato struct fec_nh *
fec_nh_find(struct fec_node * fn,int af,union ldpd_addr * nexthop,uint8_t priority)2840c0343b7Srenato fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop,
2850c0343b7Srenato     uint8_t priority)
286a094a533Sclaudio {
2876106bae4Srenato 	struct fec_nh	*fnh;
288a094a533Sclaudio 
2896106bae4Srenato 	LIST_FOREACH(fnh, &fn->nexthops, entry)
290a8c39dc0Srenato 		if (fnh->af == af &&
2910c0343b7Srenato 		    ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 &&
2920c0343b7Srenato 		    fnh->priority == priority)
2936106bae4Srenato 			return (fnh);
29419fce358Srenato 
295a094a533Sclaudio 	return (NULL);
296a094a533Sclaudio }
297a094a533Sclaudio 
298c28a25a1Srenato static struct fec_nh *
fec_nh_add(struct fec_node * fn,int af,union ldpd_addr * nexthop,uint8_t priority)2990c0343b7Srenato fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop,
3000c0343b7Srenato     uint8_t priority)
301a094a533Sclaudio {
3026106bae4Srenato 	struct fec_nh	*fnh;
303a094a533Sclaudio 
3046106bae4Srenato 	fnh = calloc(1, sizeof(*fnh));
3056106bae4Srenato 	if (fnh == NULL)
306b7b4db73Srenato 		fatal(__func__);
307a094a533Sclaudio 
308a8c39dc0Srenato 	fnh->af = af;
309a8c39dc0Srenato 	fnh->nexthop = *nexthop;
3106106bae4Srenato 	fnh->remote_label = NO_LABEL;
3110c0343b7Srenato 	fnh->priority = priority;
3126106bae4Srenato 	LIST_INSERT_HEAD(&fn->nexthops, fnh, entry);
31310c7a445Srenato 
3146106bae4Srenato 	return (fnh);
315a094a533Sclaudio }
316a094a533Sclaudio 
317c28a25a1Srenato static void
fec_nh_del(struct fec_nh * fnh)3186106bae4Srenato fec_nh_del(struct fec_nh *fnh)
319a094a533Sclaudio {
3206106bae4Srenato 	LIST_REMOVE(fnh, entry);
3216106bae4Srenato 	free(fnh);
322ab0c2486Smichele }
323ab0c2486Smichele 
3243de94509Srenato uint32_t
egress_label(enum fec_type fec_type)3253de94509Srenato egress_label(enum fec_type fec_type)
3263de94509Srenato {
3273de94509Srenato 	switch (fec_type) {
3283de94509Srenato 	case FEC_TYPE_IPV4:
329d3e006a4Srenato 		if (ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL)
3303de94509Srenato 			return (MPLS_LABEL_IPV4NULL);
331d3e006a4Srenato 		break;
332a8c39dc0Srenato 	case FEC_TYPE_IPV6:
333d3e006a4Srenato 		if (ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL)
334a8c39dc0Srenato 			return (MPLS_LABEL_IPV6NULL);
335d3e006a4Srenato 		break;
3363de94509Srenato 	default:
337d3e006a4Srenato 		fatalx("egress_label: unexpected fec type");
3383de94509Srenato 	}
3393de94509Srenato 
340d3e006a4Srenato 	return (MPLS_LABEL_IMPLNULL);
3413de94509Srenato }
3423de94509Srenato 
343ab0c2486Smichele void
lde_kernel_insert(struct fec * fec,int af,union ldpd_addr * nexthop,uint8_t priority,int connected,void * data)344a8c39dc0Srenato lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
3450c0343b7Srenato     uint8_t priority, int connected, void *data)
346ab0c2486Smichele {
3476106bae4Srenato 	struct fec_node		*fn;
3486106bae4Srenato 	struct fec_nh		*fnh;
349cf483f25Srenato 	struct lde_map		*me;
350cf483f25Srenato 	struct lde_nbr		*ln;
351ab0c2486Smichele 
3526399cec1Srenato 	fn = (struct fec_node *)fec_find(&ft, fec);
3536106bae4Srenato 	if (fn == NULL)
3546399cec1Srenato 		fn = fec_add(fec);
3550c0343b7Srenato 	if (fec_nh_find(fn, af, nexthop, priority) != NULL)
356a7c87e05Smichele 		return;
357a7c87e05Smichele 
35819fce358Srenato 	log_debug("lde add fec %s nexthop %s",
359a8c39dc0Srenato 	    log_fec(&fn->fec), log_addr(af, nexthop));
36019fce358Srenato 
36172bfe95eSrenato 	if (fn->fec.type == FEC_TYPE_PWID)
36272bfe95eSrenato 		fn->data = data;
36372bfe95eSrenato 
3646106bae4Srenato 	if (fn->local_label == NO_LABEL) {
3656399cec1Srenato 		if (connected)
3663de94509Srenato 			fn->local_label = egress_label(fn->fec.type);
367a094a533Sclaudio 		else
3686106bae4Srenato 			fn->local_label = lde_assign_label();
369d7d0957bSmichele 
370cf483f25Srenato 		/* FEC.1: perform lsr label distribution procedure */
3716399cec1Srenato 		RB_FOREACH(ln, nbr_tree, &lde_nbrs)
3726399cec1Srenato 			lde_send_labelmapping(ln, fn, 1);
373cf483f25Srenato 	}
374cf483f25Srenato 
3750c0343b7Srenato 	fnh = fec_nh_add(fn, af, nexthop, priority);
3766106bae4Srenato 	lde_send_change_klabel(fn, fnh);
37772bfe95eSrenato 
37872bfe95eSrenato 	switch (fn->fec.type) {
37972bfe95eSrenato 	case FEC_TYPE_IPV4:
380a8c39dc0Srenato 	case FEC_TYPE_IPV6:
381a8c39dc0Srenato 		ln = lde_nbr_find_by_addr(af, &fnh->nexthop);
38272bfe95eSrenato 		break;
38372bfe95eSrenato 	case FEC_TYPE_PWID:
38472bfe95eSrenato 		ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id);
38572bfe95eSrenato 		break;
38672bfe95eSrenato 	default:
38772bfe95eSrenato 		ln = NULL;
38872bfe95eSrenato 		break;
38972bfe95eSrenato 	}
39072bfe95eSrenato 
391cf483f25Srenato 	if (ln) {
392cf483f25Srenato 		/* FEC.2  */
3936106bae4Srenato 		me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
39429d4fbdbSrenato 		if (me)
395cf483f25Srenato 			/* FEC.5 */
39629d4fbdbSrenato 			lde_check_mapping(&me->map, ln);
397cf483f25Srenato 	}
398ab0c2486Smichele }
399ab0c2486Smichele 
400ab0c2486Smichele void
lde_kernel_remove(struct fec * fec,int af,union ldpd_addr * nexthop,uint8_t priority)4010c0343b7Srenato lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
4020c0343b7Srenato     uint8_t priority)
4039c6090f2Smichele {
4046106bae4Srenato 	struct fec_node		*fn;
4056106bae4Srenato 	struct fec_nh		*fnh;
4062c06fdf4Srenato 	struct lde_nbr		*ln;
4079c6090f2Smichele 
4086399cec1Srenato 	fn = (struct fec_node *)fec_find(&ft, fec);
4096106bae4Srenato 	if (fn == NULL)
410a094a533Sclaudio 		/* route lost */
4119c6090f2Smichele 		return;
4120c0343b7Srenato 	fnh = fec_nh_find(fn, af, nexthop, priority);
4136106bae4Srenato 	if (fnh == NULL)
414cf483f25Srenato 		/* route lost */
415cf483f25Srenato 		return;
416cf483f25Srenato 
41719fce358Srenato 	log_debug("lde remove fec %s nexthop %s",
418a8c39dc0Srenato 	    log_fec(&fn->fec), log_addr(af, nexthop));
41919fce358Srenato 
4206399cec1Srenato 	lde_send_delete_klabel(fn, fnh);
4216106bae4Srenato 	fec_nh_del(fnh);
4223de94509Srenato 	if (LIST_EMPTY(&fn->nexthops)) {
4232c06fdf4Srenato 		RB_FOREACH(ln, nbr_tree, &lde_nbrs)
4242c06fdf4Srenato 			lde_send_labelwithdraw(ln, fn, NULL, NULL);
425e5099c8bSrenato 		fn->local_label = NO_LABEL;
4263de94509Srenato 		if (fn->fec.type == FEC_TYPE_PWID)
4273de94509Srenato 			fn->data = NULL;
4283de94509Srenato 	}
4299c6090f2Smichele }
4309c6090f2Smichele 
4319c6090f2Smichele void
lde_check_mapping(struct map * map,struct lde_nbr * ln)432ab0c2486Smichele lde_check_mapping(struct map *map, struct lde_nbr *ln)
433ab0c2486Smichele {
4346399cec1Srenato 	struct fec		 fec;
4356106bae4Srenato 	struct fec_node		*fn;
4366106bae4Srenato 	struct fec_nh		*fnh;
437510d51a3Sclaudio 	struct lde_req		*lre;
438e3948831Sclaudio 	struct lde_map		*me;
4396399cec1Srenato 	struct l2vpn_pw		*pw;
440cf483f25Srenato 	int			 msgsource = 0;
4410211d6d6Sclaudio 
4426399cec1Srenato 	lde_map2fec(map, ln->id, &fec);
4436399cec1Srenato 	fn = (struct fec_node *)fec_find(&ft, &fec);
4446106bae4Srenato 	if (fn == NULL)
4456399cec1Srenato 		fn = fec_add(&fec);
446a7c87e05Smichele 
447cf483f25Srenato 	/* LMp.1: first check if we have a pending request running */
4486106bae4Srenato 	lre = (struct lde_req *)fec_find(&ln->sent_req, &fn->fec);
449fb298019Sclaudio 	if (lre)
450cf483f25Srenato 		/* LMp.2: delete record of outstanding label request */
451fb298019Sclaudio 		lde_req_del(ln, lre, 1);
452510d51a3Sclaudio 
4536399cec1Srenato 	/* RFC 4447 control word and status tlv negotiation */
454cf09440fSrenato 	if (map->type == MAP_TYPE_PWID && l2vpn_pw_negotiate(ln, fn, map))
4556399cec1Srenato 		return;
4566399cec1Srenato 
457fb298019Sclaudio 	/*
458d0b141dbSrenato 	 * LMp.3 - LMp.8: loop detection - unnecessary for frame-mode
459d0b141dbSrenato 	 * mpls networks.
460e3948831Sclaudio 	 */
461cf483f25Srenato 
462cf483f25Srenato 	/* LMp.9 */
4636106bae4Srenato 	me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
464cf483f25Srenato 	if (me) {
465cf483f25Srenato 		/* LMp.10 */
46629d4fbdbSrenato 		if (me->map.label != map->label && lre == NULL) {
467cf483f25Srenato 			/* LMp.10a */
4682c06fdf4Srenato 			lde_send_labelrelease(ln, fn, NULL, me->map.label);
469cf483f25Srenato 
4706dfcbc27Srenato 			/*
4716dfcbc27Srenato 			 * Can not use lde_nbr_find_by_addr() because there's
4726dfcbc27Srenato 			 * the possibility of multipath.
4736dfcbc27Srenato 			 */
4746dfcbc27Srenato 			LIST_FOREACH(fnh, &fn->nexthops, entry) {
475a8c39dc0Srenato 				if (lde_address_find(ln, fnh->af,
476a8c39dc0Srenato 				    &fnh->nexthop) == NULL)
4776dfcbc27Srenato 					continue;
4786dfcbc27Srenato 
4796106bae4Srenato 				lde_send_delete_klabel(fn, fnh);
4806106bae4Srenato 				fnh->remote_label = NO_LABEL;
481ab0c2486Smichele 			}
482cf483f25Srenato 		}
483ab0c2486Smichele 	}
484ab0c2486Smichele 
485cf483f25Srenato 	/*
486cf483f25Srenato 	 * LMp.11 - 12: consider multiple nexthops in order to
487cf483f25Srenato 	 * support multipath
488cf483f25Srenato 	 */
4896106bae4Srenato 	LIST_FOREACH(fnh, &fn->nexthops, entry) {
49072bfe95eSrenato 		/* LMp.15: install FEC in FIB */
49172bfe95eSrenato 		switch (fec.type) {
49272bfe95eSrenato 		case FEC_TYPE_IPV4:
493a8c39dc0Srenato 		case FEC_TYPE_IPV6:
494a8c39dc0Srenato 			if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
4956399cec1Srenato 				continue;
4966399cec1Srenato 
4976106bae4Srenato 			fnh->remote_label = map->label;
4986106bae4Srenato 			lde_send_change_klabel(fn, fnh);
4996399cec1Srenato 			break;
50072bfe95eSrenato 		case FEC_TYPE_PWID:
50172bfe95eSrenato 			pw = (struct l2vpn_pw *) fn->data;
50272bfe95eSrenato 			if (pw == NULL)
50372bfe95eSrenato 				continue;
50472bfe95eSrenato 
5056399cec1Srenato 			pw->remote_group = map->fec.pwid.group_id;
5066399cec1Srenato 			if (map->flags & F_MAP_PW_IFMTU)
5076399cec1Srenato 				pw->remote_mtu = map->fec.pwid.ifmtu;
5086399cec1Srenato 			if (map->flags & F_MAP_PW_STATUS)
5096399cec1Srenato 				pw->remote_status = map->pw_status;
51072bfe95eSrenato 			fnh->remote_label = map->label;
5116399cec1Srenato 			if (l2vpn_pw_ok(pw, fnh))
5126399cec1Srenato 				lde_send_change_klabel(fn, fnh);
5136399cec1Srenato 			break;
51472bfe95eSrenato 		default:
51572bfe95eSrenato 			break;
516a094a533Sclaudio 		}
51772bfe95eSrenato 
51872bfe95eSrenato 		msgsource = 1;
519cf483f25Srenato 	}
5206399cec1Srenato 	/* LMp.13 & LMp.16: Record the mapping from this peer */
521e3948831Sclaudio 	if (me == NULL)
5226106bae4Srenato 		me = lde_map_add(ln, fn, 0);
5237aa09c5dSrenato 	me->map = *map;
524ab0c2486Smichele 
5256399cec1Srenato 	if (msgsource == 0)
5266399cec1Srenato 		/* LMp.13: just return since we use liberal lbl retention */
5276399cec1Srenato 		return;
528ab0c2486Smichele 
529cf483f25Srenato 	/*
530cf483f25Srenato 	 * LMp.17 - LMp.27 are unnecessary since we don't need to implement
531cf483f25Srenato 	 * loop detection. LMp.28 - LMp.30 are unnecessary because we are
532cf483f25Srenato 	 * merging capable.
533cf483f25Srenato 	 */
534ab0c2486Smichele }
535ab0c2486Smichele 
536ab0c2486Smichele void
lde_check_request(struct map * map,struct lde_nbr * ln)537ab0c2486Smichele lde_check_request(struct map *map, struct lde_nbr *ln)
538ab0c2486Smichele {
5396399cec1Srenato 	struct fec	 fec;
540e3948831Sclaudio 	struct lde_req	*lre;
5416106bae4Srenato 	struct fec_node	*fn;
5426106bae4Srenato 	struct fec_nh	*fnh;
543ab0c2486Smichele 
544c7c5a728Srenato 	/* wildcard label request */
545c7c5a728Srenato 	if (map->type == MAP_TYPE_TYPED_WCARD) {
546c7c5a728Srenato 		lde_check_request_wcard(map, ln);
547c7c5a728Srenato 		return;
548c7c5a728Srenato 	}
549c7c5a728Srenato 
550d0b141dbSrenato 	/* LRq.1: skip loop detection (not necessary) */
5510211d6d6Sclaudio 
552cf483f25Srenato 	/* LRq.2: is there a next hop for fec? */
5536399cec1Srenato 	lde_map2fec(map, ln->id, &fec);
5546399cec1Srenato 	fn = (struct fec_node *)fec_find(&ft, &fec);
5556106bae4Srenato 	if (fn == NULL || LIST_EMPTY(&fn->nexthops)) {
556d0b141dbSrenato 		/* LRq.5: send No Route notification */
55702a212eeSrenato 		lde_send_notification(ln, S_NO_ROUTE, map->msg_id,
558e4ecb75dSrenato 		    htons(MSG_TYPE_LABELREQUEST));
559ab0c2486Smichele 		return;
560ab0c2486Smichele 	}
561ab0c2486Smichele 
562cf483f25Srenato 	/* LRq.3: is MsgSource the next hop? */
5636106bae4Srenato 	LIST_FOREACH(fnh, &fn->nexthops, entry) {
56472bfe95eSrenato 		switch (fec.type) {
56572bfe95eSrenato 		case FEC_TYPE_IPV4:
566a8c39dc0Srenato 		case FEC_TYPE_IPV6:
567a8c39dc0Srenato 			if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
56872bfe95eSrenato 				continue;
56972bfe95eSrenato 
570d0b141dbSrenato 			/* LRq.4: send Loop Detected notification */
57102a212eeSrenato 			lde_send_notification(ln, S_LOOP_DETECTED, map->msg_id,
57202a212eeSrenato 			    htons(MSG_TYPE_LABELREQUEST));
573ab0c2486Smichele 			return;
57472bfe95eSrenato 		default:
57572bfe95eSrenato 			break;
576ab0c2486Smichele 		}
577a094a533Sclaudio 	}
578ab0c2486Smichele 
579cf483f25Srenato 	/* LRq.6: first check if we have a pending request running */
5806106bae4Srenato 	lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
581510d51a3Sclaudio 	if (lre != NULL)
582cf483f25Srenato 		/* LRq.7: duplicate request */
583510d51a3Sclaudio 		return;
584cf483f25Srenato 
585cf483f25Srenato 	/* LRq.8: record label request */
5866106bae4Srenato 	lre = lde_req_add(ln, &fn->fec, 0);
587fb298019Sclaudio 	if (lre != NULL)
58860e1e0e7Srenato 		lre->msg_id = ntohl(map->msg_id);
589510d51a3Sclaudio 
590cf483f25Srenato 	/* LRq.9: perform LSR label distribution */
5916399cec1Srenato 	lde_send_labelmapping(ln, fn, 1);
592a094a533Sclaudio 
593cf483f25Srenato 	/*
594cf483f25Srenato 	 * LRq.10: do nothing (Request Never) since we use liberal
595cf483f25Srenato 	 * label retention.
596cf483f25Srenato 	 * LRq.11 - 12 are unnecessary since we are merging capable.
597cf483f25Srenato 	 */
598ab0c2486Smichele }
599d5e40e07Sclaudio 
600d5e40e07Sclaudio void
lde_check_request_wcard(struct map * map,struct lde_nbr * ln)601c7c5a728Srenato lde_check_request_wcard(struct map *map, struct lde_nbr *ln)
602c7c5a728Srenato {
603c7c5a728Srenato 	struct fec	*f;
604c7c5a728Srenato 	struct fec_node	*fn;
605c7c5a728Srenato 	struct lde_req	*lre;
606c7c5a728Srenato 
607c7c5a728Srenato 	RB_FOREACH(f, fec_tree, &ft) {
608c7c5a728Srenato 		fn = (struct fec_node *)f;
609c7c5a728Srenato 
610c7c5a728Srenato 		/* only a typed wildcard is possible here */
611c7c5a728Srenato 		if (lde_wildcard_apply(map, &fn->fec, NULL) == 0)
612c7c5a728Srenato 			continue;
613c7c5a728Srenato 
614c7c5a728Srenato 		/* LRq.2: is there a next hop for fec? */
615c7c5a728Srenato 		if (LIST_EMPTY(&fn->nexthops))
616c7c5a728Srenato 			continue;
617c7c5a728Srenato 
618c7c5a728Srenato 		/* LRq.6: first check if we have a pending request running */
619c7c5a728Srenato 		lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
620c7c5a728Srenato 		if (lre != NULL)
621c7c5a728Srenato 			/* LRq.7: duplicate request */
622c7c5a728Srenato 			continue;
623c7c5a728Srenato 
624c7c5a728Srenato 		/* LRq.8: record label request */
625c7c5a728Srenato 		lre = lde_req_add(ln, &fn->fec, 0);
626c7c5a728Srenato 		if (lre != NULL)
627c7c5a728Srenato 			lre->msg_id = ntohl(map->msg_id);
628c7c5a728Srenato 
629c7c5a728Srenato 		/* LRq.9: perform LSR label distribution */
630c7c5a728Srenato 		lde_send_labelmapping(ln, fn, 1);
631c7c5a728Srenato 	}
6329246985aSrenato 
6339246985aSrenato 	/*
6349246985aSrenato 	 * RFC 5919 - Section 5.3:
6359246985aSrenato 	 * "When an LDP speaker receives a Label Request message for a Typed
6369246985aSrenato 	 * Wildcard FEC (e.g., a particular FEC Element Type) from a peer, the
6379246985aSrenato 	 * LDP speaker determines the set of bindings (as per any local
6389246985aSrenato 	 * filtering policy) to advertise to the peer for the FEC type specified
6399246985aSrenato 	 * by the request.  Assuming the peer had advertised the Unrecognized
6409246985aSrenato 	 * Notification capability at session initialization time, the speaker
6419246985aSrenato 	 * should send the peer an End-of-LIB Notification for the FEC type when
6429246985aSrenato 	 * it completes advertisement of the permitted bindings".
6439246985aSrenato 	 */
6449246985aSrenato 	if (ln->flags & F_NBR_CAP_UNOTIF) {
6459246985aSrenato 		switch (map->fec.twcard.type) {
6469246985aSrenato 		case MAP_TYPE_PREFIX:
6479246985aSrenato 			lde_send_notification_eol_prefix(ln,
6489246985aSrenato 			    map->fec.twcard.u.prefix_af);
6499246985aSrenato 			break;
6509246985aSrenato 		case MAP_TYPE_PWID:
6519246985aSrenato 			lde_send_notification_eol_pwid(ln,
6529246985aSrenato 			    map->fec.twcard.u.pw_type);
6539246985aSrenato 			break;
6549246985aSrenato 		default:
6559246985aSrenato 			break;
6569246985aSrenato 		}
6579246985aSrenato 	}
658c7c5a728Srenato }
659c7c5a728Srenato 
660c7c5a728Srenato void
lde_check_release(struct map * map,struct lde_nbr * ln)661f1b8b674Sclaudio lde_check_release(struct map *map, struct lde_nbr *ln)
662f1b8b674Sclaudio {
6636399cec1Srenato 	struct fec		 fec;
6646106bae4Srenato 	struct fec_node		*fn;
665cf483f25Srenato 	struct lde_wdraw	*lw;
666510d51a3Sclaudio 	struct lde_map		*me;
667510d51a3Sclaudio 
6682c06fdf4Srenato 	/* wildcard label release */
6692c06fdf4Srenato 	if (map->type == MAP_TYPE_WILDCARD ||
670c7c5a728Srenato 	    map->type == MAP_TYPE_TYPED_WCARD ||
6712c06fdf4Srenato 	    (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) {
6722c06fdf4Srenato 		lde_check_release_wcard(map, ln);
6736399cec1Srenato 		return;
6742c06fdf4Srenato 	}
6756399cec1Srenato 
6766399cec1Srenato 	lde_map2fec(map, ln->id, &fec);
6776399cec1Srenato 	fn = (struct fec_node *)fec_find(&ft, &fec);
678cf483f25Srenato 	/* LRl.1: does FEC match a known FEC? */
6796106bae4Srenato 	if (fn == NULL)
680510d51a3Sclaudio 		return;
681510d51a3Sclaudio 
682cf483f25Srenato 	/* LRl.3: first check if we have a pending withdraw running */
6836106bae4Srenato 	lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
684438d9009Srenato 	if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
685cf483f25Srenato 		/* LRl.4: delete record of outstanding label withdraw */
686cf483f25Srenato 		lde_wdraw_del(ln, lw);
687510d51a3Sclaudio 	}
688510d51a3Sclaudio 
689cf483f25Srenato 	/* LRl.6: check sent map list and remove it if available */
6906106bae4Srenato 	me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
69129d4fbdbSrenato 	if (me && (map->label == NO_LABEL || map->label == me->map.label))
692510d51a3Sclaudio 		lde_map_del(ln, me, 1);
693510d51a3Sclaudio 
694cf483f25Srenato 	/*
695cf483f25Srenato 	 * LRl.11 - 13 are unnecessary since we remove the label from
696cf483f25Srenato 	 * forwarding/switching as soon as the FEC is unreachable.
697cf483f25Srenato 	 */
698cf483f25Srenato }
699510d51a3Sclaudio 
700cf483f25Srenato void
lde_check_release_wcard(struct map * map,struct lde_nbr * ln)701cf483f25Srenato lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
702cf483f25Srenato {
703cf483f25Srenato 	struct fec		*f;
7046106bae4Srenato 	struct fec_node		*fn;
705cf483f25Srenato 	struct lde_wdraw	*lw;
706cf483f25Srenato 	struct lde_map		*me;
707cf483f25Srenato 
7086106bae4Srenato 	RB_FOREACH(f, fec_tree, &ft) {
7096106bae4Srenato 		fn = (struct fec_node *)f;
7102c06fdf4Srenato 		me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
7112c06fdf4Srenato 
7122c06fdf4Srenato 		/* LRl.1: does FEC match a known FEC? */
7132c06fdf4Srenato 		if (lde_wildcard_apply(map, &fn->fec, me) == 0)
7142c06fdf4Srenato 			continue;
715cf483f25Srenato 
716cf483f25Srenato 		/* LRl.3: first check if we have a pending withdraw running */
7176106bae4Srenato 		lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
718438d9009Srenato 		if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
719cf483f25Srenato 			/* LRl.4: delete record of outstanding lbl withdraw */
720cf483f25Srenato 			lde_wdraw_del(ln, lw);
721cf483f25Srenato 		}
722cf483f25Srenato 
723cf483f25Srenato 		/* LRl.6: check sent map list and remove it if available */
724cf483f25Srenato 		if (me &&
72519fce358Srenato 		    (map->label == NO_LABEL || map->label == me->map.label))
726cf483f25Srenato 			lde_map_del(ln, me, 1);
727cf483f25Srenato 
728cf483f25Srenato 		/*
729cf483f25Srenato 		 * LRl.11 - 13 are unnecessary since we remove the label from
730cf483f25Srenato 		 * forwarding/switching as soon as the FEC is unreachable.
731cf483f25Srenato 		 */
732cf483f25Srenato 	}
733510d51a3Sclaudio }
734510d51a3Sclaudio 
735510d51a3Sclaudio void
lde_check_withdraw(struct map * map,struct lde_nbr * ln)736510d51a3Sclaudio lde_check_withdraw(struct map *map, struct lde_nbr *ln)
737510d51a3Sclaudio {
7386399cec1Srenato 	struct fec		 fec;
7396106bae4Srenato 	struct fec_node		*fn;
7406106bae4Srenato 	struct fec_nh		*fnh;
741510d51a3Sclaudio 	struct lde_map		*me;
74272bfe95eSrenato 	struct l2vpn_pw		*pw;
743510d51a3Sclaudio 
7442c06fdf4Srenato 	/* wildcard label withdraw */
7452c06fdf4Srenato 	if (map->type == MAP_TYPE_WILDCARD ||
746c7c5a728Srenato 	    map->type == MAP_TYPE_TYPED_WCARD ||
7472c06fdf4Srenato 	    (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) {
7482c06fdf4Srenato 		lde_check_withdraw_wcard(map, ln);
7496399cec1Srenato 		return;
7502c06fdf4Srenato 	}
7516399cec1Srenato 
7526399cec1Srenato 	lde_map2fec(map, ln->id, &fec);
7536399cec1Srenato 	fn = (struct fec_node *)fec_find(&ft, &fec);
7546106bae4Srenato 	if (fn == NULL)
7556399cec1Srenato 		fn = fec_add(&fec);
756510d51a3Sclaudio 
757cf483f25Srenato 	/* LWd.1: remove label from forwarding/switching use */
7586106bae4Srenato 	LIST_FOREACH(fnh, &fn->nexthops, entry) {
75972bfe95eSrenato 		switch (fec.type) {
76072bfe95eSrenato 		case FEC_TYPE_IPV4:
761a8c39dc0Srenato 		case FEC_TYPE_IPV6:
762a8c39dc0Srenato 			if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
76372bfe95eSrenato 				continue;
76472bfe95eSrenato 			break;
76572bfe95eSrenato 		case FEC_TYPE_PWID:
76672bfe95eSrenato 			pw = (struct l2vpn_pw *) fn->data;
76772bfe95eSrenato 			if (pw == NULL)
76872bfe95eSrenato 				continue;
76972bfe95eSrenato 			break;
77072bfe95eSrenato 		default:
77172bfe95eSrenato 			break;
77272bfe95eSrenato 		}
773438d9009Srenato 		if (map->label != NO_LABEL && map->label != fnh->remote_label)
774438d9009Srenato 			continue;
775438d9009Srenato 
7766106bae4Srenato 		lde_send_delete_klabel(fn, fnh);
7776106bae4Srenato 		fnh->remote_label = NO_LABEL;
778cf483f25Srenato 	}
779cf483f25Srenato 
780cf483f25Srenato 	/* LWd.2: send label release */
7812c06fdf4Srenato 	lde_send_labelrelease(ln, fn, NULL, map->label);
782510d51a3Sclaudio 
783cf483f25Srenato 	/* LWd.3: check previously received label mapping */
7846106bae4Srenato 	me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
78529d4fbdbSrenato 	if (me && (map->label == NO_LABEL || map->label == me->map.label))
786cf483f25Srenato 		/* LWd.4: remove record of previously received lbl mapping */
787510d51a3Sclaudio 		lde_map_del(ln, me, 0);
788cf483f25Srenato }
789510d51a3Sclaudio 
790cf483f25Srenato void
lde_check_withdraw_wcard(struct map * map,struct lde_nbr * ln)791cf483f25Srenato lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
792cf483f25Srenato {
793cf483f25Srenato 	struct fec	*f;
7946106bae4Srenato 	struct fec_node	*fn;
7956106bae4Srenato 	struct fec_nh	*fnh;
796cf483f25Srenato 	struct lde_map	*me;
797510d51a3Sclaudio 
798cf483f25Srenato 	/* LWd.2: send label release */
7992c06fdf4Srenato 	lde_send_labelrelease(ln, NULL, map, map->label);
800cf483f25Srenato 
8016106bae4Srenato 	RB_FOREACH(f, fec_tree, &ft) {
8026106bae4Srenato 		fn = (struct fec_node *)f;
8032c06fdf4Srenato 		me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
8042c06fdf4Srenato 
8052c06fdf4Srenato 		if (lde_wildcard_apply(map, &fn->fec, me) == 0)
8062c06fdf4Srenato 			continue;
807cf483f25Srenato 
808cf483f25Srenato 		/* LWd.1: remove label from forwarding/switching use */
8096106bae4Srenato 		LIST_FOREACH(fnh, &fn->nexthops, entry) {
81072bfe95eSrenato 			switch (f->type) {
81172bfe95eSrenato 			case FEC_TYPE_IPV4:
812a8c39dc0Srenato 			case FEC_TYPE_IPV6:
813a8c39dc0Srenato 				if (!lde_address_find(ln, fnh->af,
814a8c39dc0Srenato 				    &fnh->nexthop))
81572bfe95eSrenato 					continue;
81672bfe95eSrenato 				break;
81772bfe95eSrenato 			case FEC_TYPE_PWID:
81872bfe95eSrenato 				if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
81972bfe95eSrenato 					continue;
82072bfe95eSrenato 				break;
82172bfe95eSrenato 			default:
82272bfe95eSrenato 				break;
82372bfe95eSrenato 			}
824438d9009Srenato 			if (map->label != NO_LABEL && map->label !=
825438d9009Srenato 			    fnh->remote_label)
826438d9009Srenato 				continue;
827438d9009Srenato 
8286106bae4Srenato 			lde_send_delete_klabel(fn, fnh);
8296106bae4Srenato 			fnh->remote_label = NO_LABEL;
830cf483f25Srenato 		}
831cf483f25Srenato 
832cf483f25Srenato 		/* LWd.3: check previously received label mapping */
83329d4fbdbSrenato 		if (me && (map->label == NO_LABEL ||
83429d4fbdbSrenato 		    map->label == me->map.label))
835cf483f25Srenato 			/*
836cf483f25Srenato 			 * LWd.4: remove record of previously received
837cf483f25Srenato 			 * label mapping
838cf483f25Srenato 			 */
839cf483f25Srenato 			lde_map_del(ln, me, 0);
840cf483f25Srenato 	}
841f1b8b674Sclaudio }
842b79e02a8Srenato 
8432c06fdf4Srenato int
lde_wildcard_apply(struct map * wcard,struct fec * fec,struct lde_map * me)8442c06fdf4Srenato lde_wildcard_apply(struct map *wcard, struct fec *fec, struct lde_map *me)
8452c06fdf4Srenato {
8462c06fdf4Srenato 	switch (wcard->type) {
8472c06fdf4Srenato 	case MAP_TYPE_WILDCARD:
8482c06fdf4Srenato 		/* full wildcard */
8492c06fdf4Srenato 		return (1);
850c7c5a728Srenato 	case MAP_TYPE_TYPED_WCARD:
851c7c5a728Srenato 		switch (wcard->fec.twcard.type) {
852c7c5a728Srenato 		case MAP_TYPE_PREFIX:
853c7c5a728Srenato 			if (wcard->fec.twcard.u.prefix_af == AF_INET &&
854c7c5a728Srenato 			    fec->type != FEC_TYPE_IPV4)
855c7c5a728Srenato 				return (0);
856c7c5a728Srenato 			if (wcard->fec.twcard.u.prefix_af == AF_INET6 &&
857c7c5a728Srenato 			    fec->type != FEC_TYPE_IPV6)
858c7c5a728Srenato 				return (0);
859c7c5a728Srenato 			return (1);
8606702dd25Srenato 		case MAP_TYPE_PWID:
8616702dd25Srenato 			if (fec->type != FEC_TYPE_PWID)
8626702dd25Srenato 				return (0);
8636702dd25Srenato 			if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
8646702dd25Srenato 			    wcard->fec.twcard.u.pw_type != fec->u.pwid.type)
8656702dd25Srenato 				return (0);
8666702dd25Srenato 			return (1);
867c7c5a728Srenato 		default:
868c7c5a728Srenato 			fatalx("lde_wildcard_apply: unexpected fec type");
869c7c5a728Srenato 		}
870c7c5a728Srenato 		break;
8712c06fdf4Srenato 	case MAP_TYPE_PWID:
8722c06fdf4Srenato 		/* RFC4447 pw-id group wildcard */
8732c06fdf4Srenato 		if (fec->type != FEC_TYPE_PWID)
8742c06fdf4Srenato 			return (0);
8752c06fdf4Srenato 		if (fec->u.pwid.type != wcard->fec.pwid.type)
8762c06fdf4Srenato 			return (0);
8772c06fdf4Srenato 		if (me == NULL || (me->map.fec.pwid.group_id !=
8782c06fdf4Srenato 		    wcard->fec.pwid.group_id))
8792c06fdf4Srenato 			return (0);
8802c06fdf4Srenato 		return (1);
8812c06fdf4Srenato 	default:
8822c06fdf4Srenato 		fatalx("lde_wildcard_apply: unexpected fec type");
8832c06fdf4Srenato 	}
8842c06fdf4Srenato }
8852c06fdf4Srenato 
8863a50f0a9Sjmc /* garbage collector timer: timer to remove dead entries from the LIB */
887b79e02a8Srenato 
888b79e02a8Srenato void
lde_gc_timer(int fd,short event,void * arg)889b79e02a8Srenato lde_gc_timer(int fd, short event, void *arg)
890b79e02a8Srenato {
891b79e02a8Srenato 	struct fec	*fec, *safe;
892b79e02a8Srenato 	struct fec_node	*fn;
893b79e02a8Srenato 	int		 count = 0;
894b79e02a8Srenato 
895b79e02a8Srenato 	RB_FOREACH_SAFE(fec, fec_tree, &ft, safe) {
896b79e02a8Srenato 		fn = (struct fec_node *) fec;
897b79e02a8Srenato 
898b79e02a8Srenato 		if (!LIST_EMPTY(&fn->nexthops) ||
899b79e02a8Srenato 		    !LIST_EMPTY(&fn->downstream) ||
900b79e02a8Srenato 		    !LIST_EMPTY(&fn->upstream))
901b79e02a8Srenato 			continue;
902b79e02a8Srenato 
903b79e02a8Srenato 		fec_remove(&ft, &fn->fec);
904b79e02a8Srenato 		free(fn);
905b79e02a8Srenato 		count++;
906b79e02a8Srenato 	}
907b79e02a8Srenato 
908b79e02a8Srenato 	if (count > 0)
909b79e02a8Srenato 		log_debug("%s: %u entries removed", __func__, count);
910b79e02a8Srenato 
911b79e02a8Srenato 	lde_gc_start_timer();
912b79e02a8Srenato }
913b79e02a8Srenato 
914b79e02a8Srenato void
lde_gc_start_timer(void)915b79e02a8Srenato lde_gc_start_timer(void)
916b79e02a8Srenato {
917b79e02a8Srenato 	struct timeval	 tv;
918b79e02a8Srenato 
919b79e02a8Srenato 	timerclear(&tv);
920b79e02a8Srenato 	tv.tv_sec = LDE_GC_INTERVAL;
921b79e02a8Srenato 	if (evtimer_add(&gc_timer, &tv) == -1)
922b79e02a8Srenato 		fatal(__func__);
923b79e02a8Srenato }
924b79e02a8Srenato 
925b79e02a8Srenato void
lde_gc_stop_timer(void)926b79e02a8Srenato lde_gc_stop_timer(void)
927b79e02a8Srenato {
928b79e02a8Srenato 	if (evtimer_pending(&gc_timer, NULL) &&
929b79e02a8Srenato 	    evtimer_del(&gc_timer) == -1)
930b79e02a8Srenato 		fatal(__func__);
931b79e02a8Srenato }
932