xref: /openbsd-src/usr.sbin/ldpd/lde.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1*f1b790a5Sclaudio /*	$OpenBSD: lde.c,v 1.84 2024/11/21 13:38:14 claudio Exp $ */
2ab0c2486Smichele 
3ab0c2486Smichele /*
45dc9330aSrenato  * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5ab0c2486Smichele  * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
6ab0c2486Smichele  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7ab0c2486Smichele  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8ab0c2486Smichele  *
9ab0c2486Smichele  * Permission to use, copy, modify, and distribute this software for any
10ab0c2486Smichele  * purpose with or without fee is hereby granted, provided that the above
11ab0c2486Smichele  * copyright notice and this permission notice appear in all copies.
12ab0c2486Smichele  *
13ab0c2486Smichele  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14ab0c2486Smichele  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15ab0c2486Smichele  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16ab0c2486Smichele  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17ab0c2486Smichele  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18ab0c2486Smichele  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19ab0c2486Smichele  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20ab0c2486Smichele  */
21ab0c2486Smichele 
22ab0c2486Smichele #include <sys/types.h>
235411bbb6Srenato #include <sys/time.h>
24ab0c2486Smichele #include <sys/socket.h>
25ab0c2486Smichele #include <netinet/in.h>
26e3948831Sclaudio #include <netmpls/mpls.h>
27ab0c2486Smichele #include <arpa/inet.h>
28ab0c2486Smichele #include <errno.h>
29ab0c2486Smichele #include <stdlib.h>
30ab0c2486Smichele #include <signal.h>
31ab0c2486Smichele #include <string.h>
32ab0c2486Smichele #include <pwd.h>
33ab0c2486Smichele #include <unistd.h>
345411bbb6Srenato #include <limits.h>
35ab0c2486Smichele 
36ab0c2486Smichele #include "ldp.h"
37ab0c2486Smichele #include "ldpd.h"
38ab0c2486Smichele #include "ldpe.h"
39ab0c2486Smichele #include "log.h"
40ab0c2486Smichele #include "lde.h"
41ab0c2486Smichele 
42c28a25a1Srenato static void		 lde_sig_handler(int sig, short, void *);
43d5e026a8Srenato static __dead void	 lde_shutdown(void);
44c28a25a1Srenato static int		 lde_imsg_compose_parent(int, pid_t, void *, uint16_t);
45c28a25a1Srenato static void		 lde_dispatch_imsg(int, short, void *);
46c28a25a1Srenato static void		 lde_dispatch_parent(int, short, void *);
47c28a25a1Srenato static __inline	int	 lde_nbr_compare(struct lde_nbr *,
48c28a25a1Srenato 			    struct lde_nbr *);
49c28a25a1Srenato static struct lde_nbr	*lde_nbr_new(uint32_t, struct lde_nbr *);
50c28a25a1Srenato static void		 lde_nbr_del(struct lde_nbr *);
51c28a25a1Srenato static struct lde_nbr	*lde_nbr_find(uint32_t);
52c28a25a1Srenato static void		 lde_nbr_clear(void);
53ed90b960Srenato static void		 lde_nbr_addr_update(struct lde_nbr *,
54ed90b960Srenato 			    struct lde_addr *, int);
55c28a25a1Srenato static void		 lde_map_free(void *);
56c28a25a1Srenato static int		 lde_address_add(struct lde_nbr *, struct lde_addr *);
57c28a25a1Srenato static int		 lde_address_del(struct lde_nbr *, struct lde_addr *);
58c28a25a1Srenato static void		 lde_address_list_free(struct lde_nbr *);
59ab0c2486Smichele 
603de94509Srenato RB_GENERATE(nbr_tree, lde_nbr, entry, lde_nbr_compare)
613de94509Srenato 
62c28a25a1Srenato struct ldpd_conf	*ldeconf;
633de94509Srenato struct nbr_tree		 lde_nbrs = RB_INITIALIZER(&lde_nbrs);
643de94509Srenato 
65c28a25a1Srenato static struct imsgev	*iev_ldpe;
66c28a25a1Srenato static struct imsgev	*iev_main;
67c28a25a1Srenato 
68c28a25a1Srenato static void
69ab0c2486Smichele lde_sig_handler(int sig, short event, void *arg)
70ab0c2486Smichele {
71ab0c2486Smichele 	/*
72ab0c2486Smichele 	 * signal handler rules don't apply, libevent decouples for us
73ab0c2486Smichele 	 */
74ab0c2486Smichele 
75ab0c2486Smichele 	switch (sig) {
76ab0c2486Smichele 	case SIGINT:
77ab0c2486Smichele 	case SIGTERM:
78ab0c2486Smichele 		lde_shutdown();
79ab0c2486Smichele 		/* NOTREACHED */
80ab0c2486Smichele 	default:
81ab0c2486Smichele 		fatalx("unexpected signal");
82ab0c2486Smichele 	}
83ab0c2486Smichele }
84ab0c2486Smichele 
85ab0c2486Smichele /* label decision engine */
86e21b401eSrenato void
8716040b47Srenato lde(int debug, int verbose)
88ab0c2486Smichele {
89ab0c2486Smichele 	struct event		 ev_sigint, ev_sigterm;
90ab0c2486Smichele 	struct timeval		 now;
91ab0c2486Smichele 	struct passwd		*pw;
92ab0c2486Smichele 
9316040b47Srenato 	ldeconf = config_new_empty();
94ab0c2486Smichele 
9516040b47Srenato 	log_init(debug);
9616040b47Srenato 	log_verbose(verbose);
97ab0c2486Smichele 
981b8ec09cSclaudio 	setproctitle("label decision engine");
991b8ec09cSclaudio 	ldpd_process = PROC_LDE_ENGINE;
1002b80d179Sclaudio 	log_procname = "lde";
1011b8ec09cSclaudio 
102ab0c2486Smichele 	if ((pw = getpwnam(LDPD_USER)) == NULL)
103ab0c2486Smichele 		fatal("getpwnam");
104ab0c2486Smichele 
105ab0c2486Smichele 	if (chroot(pw->pw_dir) == -1)
106ab0c2486Smichele 		fatal("chroot");
107ab0c2486Smichele 	if (chdir("/") == -1)
108ab0c2486Smichele 		fatal("chdir(\"/\")");
109ab0c2486Smichele 
110ab0c2486Smichele 	if (setgroups(1, &pw->pw_gid) ||
111ab0c2486Smichele 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
112ab0c2486Smichele 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
113ab0c2486Smichele 		fatal("can't drop privileges");
114ab0c2486Smichele 
11516040b47Srenato 	if (pledge("stdio recvfd", NULL) == -1)
11678497d21Srenato 		fatal("pledge");
11778497d21Srenato 
118ab0c2486Smichele 	event_init();
119ab0c2486Smichele 
120ab0c2486Smichele 	/* setup signal handler */
121ab0c2486Smichele 	signal_set(&ev_sigint, SIGINT, lde_sig_handler, NULL);
122ab0c2486Smichele 	signal_set(&ev_sigterm, SIGTERM, lde_sig_handler, NULL);
123ab0c2486Smichele 	signal_add(&ev_sigint, NULL);
124ab0c2486Smichele 	signal_add(&ev_sigterm, NULL);
125ab0c2486Smichele 	signal(SIGPIPE, SIG_IGN);
126ab0c2486Smichele 	signal(SIGHUP, SIG_IGN);
127ab0c2486Smichele 
12816040b47Srenato 	/* setup pipe and event handler to the parent process */
12916040b47Srenato 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
130ab0c2486Smichele 		fatal(NULL);
131*f1b790a5Sclaudio 	if (imsgbuf_init(&iev_main->ibuf, 3) == -1)
132*f1b790a5Sclaudio 		fatal(NULL);
133*f1b790a5Sclaudio 	imsgbuf_allow_fdpass(&iev_main->ibuf);
134cb77742aSpyr 	iev_main->handler = lde_dispatch_parent;
135cb77742aSpyr 	iev_main->events = EV_READ;
136cb77742aSpyr 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
137cb77742aSpyr 	    iev_main->handler, iev_main);
138cb77742aSpyr 	event_add(&iev_main->ev, NULL);
139ab0c2486Smichele 
140b79e02a8Srenato 	/* setup and start the LIB garbage collector */
141b79e02a8Srenato 	evtimer_set(&gc_timer, lde_gc_timer, NULL);
142b79e02a8Srenato 	lde_gc_start_timer();
143b79e02a8Srenato 
144ab0c2486Smichele 	gettimeofday(&now, NULL);
1453de94509Srenato 	global.uptime = now.tv_sec;
146ab0c2486Smichele 
147ab0c2486Smichele 	event_dispatch();
148ab0c2486Smichele 
149ab0c2486Smichele 	lde_shutdown();
150ab0c2486Smichele }
151ab0c2486Smichele 
152d5e026a8Srenato static __dead void
153ab0c2486Smichele lde_shutdown(void)
154ab0c2486Smichele {
155d5e026a8Srenato 	/* close pipes */
1569cbf9e90Sclaudio 	imsgbuf_clear(&iev_ldpe->ibuf);
157d5e026a8Srenato 	close(iev_ldpe->ibuf.fd);
1589cbf9e90Sclaudio 	imsgbuf_clear(&iev_main->ibuf);
159d5e026a8Srenato 	close(iev_main->ibuf.fd);
160d5e026a8Srenato 
161b79e02a8Srenato 	lde_gc_stop_timer();
162e3948831Sclaudio 	lde_nbr_clear();
1636106bae4Srenato 	fec_tree_clear();
164ab0c2486Smichele 
16517cc0810Srenato 	config_clear(ldeconf);
16617cc0810Srenato 
167cb77742aSpyr 	free(iev_ldpe);
168cb77742aSpyr 	free(iev_main);
169ab0c2486Smichele 
170ab0c2486Smichele 	log_info("label decision engine exiting");
171220e0715Srenato 	exit(0);
172ab0c2486Smichele }
173ab0c2486Smichele 
174eab950efSrenato /* imesg */
175c28a25a1Srenato static int
1763de94509Srenato lde_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
177eab950efSrenato {
178eab950efSrenato 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
179eab950efSrenato }
180eab950efSrenato 
181ab0c2486Smichele int
1823de94509Srenato lde_imsg_compose_ldpe(int type, uint32_t peerid, pid_t pid, void *data,
1833de94509Srenato     uint16_t datalen)
184ab0c2486Smichele {
185cb77742aSpyr 	return (imsg_compose_event(iev_ldpe, type, peerid, pid,
186cb77742aSpyr 	     -1, data, datalen));
187ab0c2486Smichele }
188ab0c2486Smichele 
189c28a25a1Srenato static void
190ab0c2486Smichele lde_dispatch_imsg(int fd, short event, void *bula)
191ab0c2486Smichele {
192cb77742aSpyr 	struct imsgev		*iev = bula;
193cb77742aSpyr 	struct imsgbuf		*ibuf = &iev->ibuf;
194ab0c2486Smichele 	struct imsg		 imsg;
1952d825b92Srenato 	struct lde_nbr		*ln;
196ab0c2486Smichele 	struct map		 map;
197a8c39dc0Srenato 	struct lde_addr		 lde_addr;
1986399cec1Srenato 	struct notify_msg	 nm;
199ab0c2486Smichele 	ssize_t			 n;
200d5d77daaSclaudio 	int			 shut = 0, verbose;
201ab0c2486Smichele 
202ab0c2486Smichele 	if (event & EV_READ) {
203668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
204dd7efffeSclaudio 			fatal("imsgbuf_read error");
205ab0c2486Smichele 		if (n == 0)	/* connection closed */
206ab0c2486Smichele 			shut = 1;
207ab0c2486Smichele 	}
208ab0c2486Smichele 	if (event & EV_WRITE) {
209dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
210c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
2111203692fSkrw 				shut = 1;
212c1aa9554Sclaudio 			else
213dd7efffeSclaudio 				fatal("imsgbuf_write");
214c1aa9554Sclaudio 		}
215ab0c2486Smichele 	}
216ab0c2486Smichele 
217ab0c2486Smichele 	for (;;) {
218ab0c2486Smichele 		if ((n = imsg_get(ibuf, &imsg)) == -1)
219ae7f1740Sclaudio 			fatal("lde_dispatch_imsg: imsg_get error");
220ab0c2486Smichele 		if (n == 0)
221ab0c2486Smichele 			break;
222ab0c2486Smichele 
223ab0c2486Smichele 		switch (imsg.hdr.type) {
224ab0c2486Smichele 		case IMSG_LABEL_MAPPING_FULL:
2253de94509Srenato 			ln = lde_nbr_find(imsg.hdr.peerid);
2263de94509Srenato 			if (ln == NULL) {
227b7b4db73Srenato 				log_debug("%s: cannot find lde neighbor",
228b7b4db73Srenato 				    __func__);
2293de94509Srenato 				break;
230510d51a3Sclaudio 			}
231ab0c2486Smichele 
2323de94509Srenato 			fec_snap(ln);
233ab0c2486Smichele 			break;
2344d839438Sclaudio 		case IMSG_LABEL_MAPPING:
235ab0c2486Smichele 		case IMSG_LABEL_REQUEST:
2364d839438Sclaudio 		case IMSG_LABEL_RELEASE:
2374d839438Sclaudio 		case IMSG_LABEL_WITHDRAW:
2384d839438Sclaudio 		case IMSG_LABEL_ABORT:
239ab0c2486Smichele 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map))
240d99a8fc3Srenato 				fatalx("lde_dispatch_imsg: wrong imsg len");
241ab0c2486Smichele 			memcpy(&map, imsg.data, sizeof(map));
242ab0c2486Smichele 
2432d825b92Srenato 			ln = lde_nbr_find(imsg.hdr.peerid);
2442d825b92Srenato 			if (ln == NULL) {
245b7b4db73Srenato 				log_debug("%s: cannot find lde neighbor",
246b7b4db73Srenato 				    __func__);
2473de94509Srenato 				break;
248ab0c2486Smichele 			}
249ab0c2486Smichele 
2504d839438Sclaudio 			switch (imsg.hdr.type) {
2514d839438Sclaudio 			case IMSG_LABEL_MAPPING:
2522d825b92Srenato 				lde_check_mapping(&map, ln);
2534d839438Sclaudio 				break;
2544d839438Sclaudio 			case IMSG_LABEL_REQUEST:
2552d825b92Srenato 				lde_check_request(&map, ln);
256ab0c2486Smichele 				break;
2574d839438Sclaudio 			case IMSG_LABEL_RELEASE:
2582d825b92Srenato 				lde_check_release(&map, ln);
2594d839438Sclaudio 				break;
260510d51a3Sclaudio 			case IMSG_LABEL_WITHDRAW:
2612d825b92Srenato 				lde_check_withdraw(&map, ln);
262510d51a3Sclaudio 				break;
263cf483f25Srenato 			case IMSG_LABEL_ABORT:
264cf483f25Srenato 				/* not necessary */
265cf483f25Srenato 				break;
2664d839438Sclaudio 			}
2674d839438Sclaudio 			break;
268ab0c2486Smichele 		case IMSG_ADDRESS_ADD:
269a8c39dc0Srenato 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
270d99a8fc3Srenato 				fatalx("lde_dispatch_imsg: wrong imsg len");
271a8c39dc0Srenato 			memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
272ab0c2486Smichele 
2733de94509Srenato 			ln = lde_nbr_find(imsg.hdr.peerid);
2743de94509Srenato 			if (ln == NULL) {
275b7b4db73Srenato 				log_debug("%s: cannot find lde neighbor",
276b7b4db73Srenato 				    __func__);
2773de94509Srenato 				break;
278ab0c2486Smichele 			}
279a8c39dc0Srenato 			if (lde_address_add(ln, &lde_addr) < 0) {
280b7b4db73Srenato 				log_debug("%s: cannot add address %s, it "
281b7b4db73Srenato 				    "already exists", __func__,
282a8c39dc0Srenato 				    log_addr(lde_addr.af, &lde_addr.addr));
283ab0c2486Smichele 			}
284ab0c2486Smichele 			break;
285ab0c2486Smichele 		case IMSG_ADDRESS_DEL:
286a8c39dc0Srenato 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
287d99a8fc3Srenato 				fatalx("lde_dispatch_imsg: wrong imsg len");
288a8c39dc0Srenato 			memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
289ab0c2486Smichele 
2903de94509Srenato 			ln = lde_nbr_find(imsg.hdr.peerid);
2913de94509Srenato 			if (ln == NULL) {
292b7b4db73Srenato 				log_debug("%s: cannot find lde neighbor",
293b7b4db73Srenato 				    __func__);
2943de94509Srenato 				break;
295ab0c2486Smichele 			}
296a8c39dc0Srenato 			if (lde_address_del(ln, &lde_addr) < 0) {
297b7b4db73Srenato 				log_debug("%s: cannot delete address %s, it "
298d99a8fc3Srenato 				    "does not exist", __func__,
299a8c39dc0Srenato 				    log_addr(lde_addr.af, &lde_addr.addr));
300ab0c2486Smichele 			}
301ab0c2486Smichele 			break;
3026399cec1Srenato 		case IMSG_NOTIFICATION:
3036399cec1Srenato 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
304d99a8fc3Srenato 				fatalx("lde_dispatch_imsg: wrong imsg len");
3056399cec1Srenato 			memcpy(&nm, imsg.data, sizeof(nm));
3066399cec1Srenato 
3072d825b92Srenato 			ln = lde_nbr_find(imsg.hdr.peerid);
3082d825b92Srenato 			if (ln == NULL) {
309b7b4db73Srenato 				log_debug("%s: cannot find lde neighbor",
310b7b4db73Srenato 				    __func__);
3113de94509Srenato 				break;
3126399cec1Srenato 			}
3136399cec1Srenato 
31460e1e0e7Srenato 			switch (nm.status_code) {
3156399cec1Srenato 			case S_PW_STATUS:
3162d825b92Srenato 				l2vpn_recv_pw_status(ln, &nm);
3176399cec1Srenato 				break;
3189246985aSrenato 			case S_ENDOFLIB:
3199246985aSrenato 				/*
3209246985aSrenato 				 * Do nothing for now. Should be useful in
3219246985aSrenato 				 * the future when we implement LDP-IGP
3229246985aSrenato 				 * Synchronization (RFC 5443) and Graceful
3239246985aSrenato 				 * Restart (RFC 3478).
3249246985aSrenato 				 */
3256399cec1Srenato 			default:
3266399cec1Srenato 				break;
3276399cec1Srenato 			}
3286399cec1Srenato 			break;
329ab0c2486Smichele 		case IMSG_NEIGHBOR_UP:
330a8c39dc0Srenato 			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
331a8c39dc0Srenato 			    sizeof(struct lde_nbr))
332d99a8fc3Srenato 				fatalx("lde_dispatch_imsg: wrong imsg len");
333ab0c2486Smichele 
334ab0c2486Smichele 			if (lde_nbr_find(imsg.hdr.peerid))
335ab0c2486Smichele 				fatalx("lde_dispatch_imsg: "
336ab0c2486Smichele 				    "neighbor already exists");
33719fce358Srenato 			lde_nbr_new(imsg.hdr.peerid, imsg.data);
338ab0c2486Smichele 			break;
339ab0c2486Smichele 		case IMSG_NEIGHBOR_DOWN:
340ab0c2486Smichele 			lde_nbr_del(lde_nbr_find(imsg.hdr.peerid));
341ab0c2486Smichele 			break;
342ab0c2486Smichele 		case IMSG_CTL_SHOW_LIB:
343ab0c2486Smichele 			rt_dump(imsg.hdr.pid);
344ab0c2486Smichele 
345eab950efSrenato 			lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
346eab950efSrenato 			    imsg.hdr.pid, NULL, 0);
347ab0c2486Smichele 			break;
3486399cec1Srenato 		case IMSG_CTL_SHOW_L2VPN_PW:
3496399cec1Srenato 			l2vpn_pw_ctl(imsg.hdr.pid);
3506399cec1Srenato 
3516399cec1Srenato 			lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
3526399cec1Srenato 			    imsg.hdr.pid, NULL, 0);
3536399cec1Srenato 			break;
3546399cec1Srenato 		case IMSG_CTL_SHOW_L2VPN_BINDING:
3556399cec1Srenato 			l2vpn_binding_ctl(imsg.hdr.pid);
3566399cec1Srenato 
3576399cec1Srenato 			lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
3586399cec1Srenato 			    imsg.hdr.pid, NULL, 0);
3596399cec1Srenato 			break;
3607dc5fe12Sclaudio 		case IMSG_CTL_LOG_VERBOSE:
3617dc5fe12Sclaudio 			/* already checked by ldpe */
3627dc5fe12Sclaudio 			memcpy(&verbose, imsg.data, sizeof(verbose));
3637dc5fe12Sclaudio 			log_verbose(verbose);
3647dc5fe12Sclaudio 			break;
365ab0c2486Smichele 		default:
366b7b4db73Srenato 			log_debug("%s: unexpected imsg %d", __func__,
367ab0c2486Smichele 			    imsg.hdr.type);
368ab0c2486Smichele 			break;
369ab0c2486Smichele 		}
370ab0c2486Smichele 		imsg_free(&imsg);
371ab0c2486Smichele 	}
372ab0c2486Smichele 	if (!shut)
373cb77742aSpyr 		imsg_event_add(iev);
374ab0c2486Smichele 	else {
375ab0c2486Smichele 		/* this pipe is dead, so remove the event handler */
376cb77742aSpyr 		event_del(&iev->ev);
377ab0c2486Smichele 		event_loopexit(NULL);
378ab0c2486Smichele 	}
379ab0c2486Smichele }
380ab0c2486Smichele 
381c28a25a1Srenato static void
382ab0c2486Smichele lde_dispatch_parent(int fd, short event, void *bula)
383ab0c2486Smichele {
384c28a25a1Srenato 	static struct ldpd_conf	*nconf;
385be87e4d3Srenato 	struct iface		*niface;
386be87e4d3Srenato 	struct tnbr		*ntnbr;
387be87e4d3Srenato 	struct nbr_params	*nnbrp;
3886399cec1Srenato 	static struct l2vpn	*nl2vpn;
3896399cec1Srenato 	struct l2vpn_if		*nlif;
3906399cec1Srenato 	struct l2vpn_pw		*npw;
391ab0c2486Smichele 	struct imsg		 imsg;
392ab0c2486Smichele 	struct kroute		 kr;
393cb77742aSpyr 	struct imsgev		*iev = bula;
394cb77742aSpyr 	struct imsgbuf		*ibuf = &iev->ibuf;
395ab0c2486Smichele 	ssize_t			 n;
396ab0c2486Smichele 	int			 shut = 0;
3976399cec1Srenato 	struct fec		 fec;
398ab0c2486Smichele 
399ab0c2486Smichele 	if (event & EV_READ) {
400668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
401dd7efffeSclaudio 			fatal("imsgbuf_read error");
402ab0c2486Smichele 		if (n == 0)	/* connection closed */
403ab0c2486Smichele 			shut = 1;
404ab0c2486Smichele 	}
405ab0c2486Smichele 	if (event & EV_WRITE) {
406dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
407c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
4081203692fSkrw 				shut = 1;
409c1aa9554Sclaudio 			else
410dd7efffeSclaudio 				fatal("imsgbuf_write");
411c1aa9554Sclaudio 		}
412ab0c2486Smichele 	}
413ab0c2486Smichele 
414ab0c2486Smichele 	for (;;) {
415ab0c2486Smichele 		if ((n = imsg_get(ibuf, &imsg)) == -1)
416ae7f1740Sclaudio 			fatal("lde_dispatch_parent: imsg_get error");
417ab0c2486Smichele 		if (n == 0)
418ab0c2486Smichele 			break;
419ab0c2486Smichele 
420ab0c2486Smichele 		switch (imsg.hdr.type) {
421ab0c2486Smichele 		case IMSG_NETWORK_ADD:
422ab0c2486Smichele 		case IMSG_NETWORK_DEL:
423ab0c2486Smichele 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
424b7b4db73Srenato 				log_warnx("%s: wrong imsg len", __func__);
425ab0c2486Smichele 				break;
426ab0c2486Smichele 			}
427ab0c2486Smichele 			memcpy(&kr, imsg.data, sizeof(kr));
428ab0c2486Smichele 
429a8c39dc0Srenato 			switch (kr.af) {
430a8c39dc0Srenato 			case AF_INET:
4316399cec1Srenato 				fec.type = FEC_TYPE_IPV4;
432a8c39dc0Srenato 				fec.u.ipv4.prefix = kr.prefix.v4;
4336399cec1Srenato 				fec.u.ipv4.prefixlen = kr.prefixlen;
434a8c39dc0Srenato 				break;
435a8c39dc0Srenato 			case AF_INET6:
436a8c39dc0Srenato 				fec.type = FEC_TYPE_IPV6;
437a8c39dc0Srenato 				fec.u.ipv6.prefix = kr.prefix.v6;
438a8c39dc0Srenato 				fec.u.ipv6.prefixlen = kr.prefixlen;
439a8c39dc0Srenato 				break;
440a8c39dc0Srenato 			default:
441a8c39dc0Srenato 				fatalx("lde_dispatch_parent: unknown af");
442a8c39dc0Srenato 			}
443a8c39dc0Srenato 
444a8c39dc0Srenato 			switch (imsg.hdr.type) {
445a8c39dc0Srenato 			case IMSG_NETWORK_ADD:
446a8c39dc0Srenato 				lde_kernel_insert(&fec, kr.af, &kr.nexthop,
4470c0343b7Srenato 				    kr.priority, kr.flags & F_CONNECTED, NULL);
448a8c39dc0Srenato 				break;
449a8c39dc0Srenato 			case IMSG_NETWORK_DEL:
4500c0343b7Srenato 				lde_kernel_remove(&fec, kr.af, &kr.nexthop,
4510c0343b7Srenato 				    kr.priority);
452a8c39dc0Srenato 				break;
453a8c39dc0Srenato 			}
454ab0c2486Smichele 			break;
45516040b47Srenato 		case IMSG_SOCKET_IPC:
45616040b47Srenato 			if (iev_ldpe) {
45716040b47Srenato 				log_warnx("%s: received unexpected imsg fd "
45816040b47Srenato 				    "to ldpe", __func__);
45916040b47Srenato 				break;
46016040b47Srenato 			}
4614bba3f27Sclaudio 			if ((fd = imsg_get_fd(&imsg)) == -1) {
46216040b47Srenato 				log_warnx("%s: expected to receive imsg fd to "
46316040b47Srenato 				    "ldpe but didn't receive any", __func__);
46416040b47Srenato 				break;
46516040b47Srenato 			}
46616040b47Srenato 
46716040b47Srenato 			if ((iev_ldpe = malloc(sizeof(struct imsgev))) == NULL)
46816040b47Srenato 				fatal(NULL);
469*f1b790a5Sclaudio 			if (imsgbuf_init(&iev_ldpe->ibuf, fd) == -1)
470*f1b790a5Sclaudio 				fatal(NULL);
47116040b47Srenato 			iev_ldpe->handler = lde_dispatch_imsg;
47216040b47Srenato 			iev_ldpe->events = EV_READ;
47316040b47Srenato 			event_set(&iev_ldpe->ev, iev_ldpe->ibuf.fd,
47416040b47Srenato 			    iev_ldpe->events, iev_ldpe->handler, iev_ldpe);
47516040b47Srenato 			event_add(&iev_ldpe->ev, NULL);
47616040b47Srenato 			break;
477ab0c2486Smichele 		case IMSG_RECONF_CONF:
478ab0c2486Smichele 			if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
479ab0c2486Smichele 			    NULL)
480ab0c2486Smichele 				fatal(NULL);
481ab0c2486Smichele 			memcpy(nconf, imsg.data, sizeof(struct ldpd_conf));
482ab0c2486Smichele 
483be87e4d3Srenato 			LIST_INIT(&nconf->iface_list);
484be87e4d3Srenato 			LIST_INIT(&nconf->tnbr_list);
485be87e4d3Srenato 			LIST_INIT(&nconf->nbrp_list);
4866399cec1Srenato 			LIST_INIT(&nconf->l2vpn_list);
4877ee91690Sdlg 			LIST_INIT(&nconf->auth_list);
488ab0c2486Smichele 			break;
489ab0c2486Smichele 		case IMSG_RECONF_IFACE:
490be87e4d3Srenato 			if ((niface = malloc(sizeof(struct iface))) == NULL)
491be87e4d3Srenato 				fatal(NULL);
492be87e4d3Srenato 			memcpy(niface, imsg.data, sizeof(struct iface));
493be87e4d3Srenato 
494be87e4d3Srenato 			LIST_INIT(&niface->addr_list);
495a8c39dc0Srenato 			LIST_INIT(&niface->ipv4.adj_list);
496a8c39dc0Srenato 			LIST_INIT(&niface->ipv6.adj_list);
497a8c39dc0Srenato 			niface->ipv4.iface = niface;
498a8c39dc0Srenato 			niface->ipv6.iface = niface;
499be87e4d3Srenato 
500be87e4d3Srenato 			LIST_INSERT_HEAD(&nconf->iface_list, niface, entry);
501be87e4d3Srenato 			break;
502be87e4d3Srenato 		case IMSG_RECONF_TNBR:
503be87e4d3Srenato 			if ((ntnbr = malloc(sizeof(struct tnbr))) == NULL)
504be87e4d3Srenato 				fatal(NULL);
505be87e4d3Srenato 			memcpy(ntnbr, imsg.data, sizeof(struct tnbr));
506be87e4d3Srenato 
507be87e4d3Srenato 			LIST_INSERT_HEAD(&nconf->tnbr_list, ntnbr, entry);
508be87e4d3Srenato 			break;
509be87e4d3Srenato 		case IMSG_RECONF_NBRP:
510be87e4d3Srenato 			if ((nnbrp = malloc(sizeof(struct nbr_params))) == NULL)
511be87e4d3Srenato 				fatal(NULL);
512be87e4d3Srenato 			memcpy(nnbrp, imsg.data, sizeof(struct nbr_params));
513be87e4d3Srenato 
514be87e4d3Srenato 			LIST_INSERT_HEAD(&nconf->nbrp_list, nnbrp, entry);
515ab0c2486Smichele 			break;
5166399cec1Srenato 		case IMSG_RECONF_L2VPN:
5176399cec1Srenato 			if ((nl2vpn = malloc(sizeof(struct l2vpn))) == NULL)
5186399cec1Srenato 				fatal(NULL);
5196399cec1Srenato 			memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
5206399cec1Srenato 
5216399cec1Srenato 			LIST_INIT(&nl2vpn->if_list);
5226399cec1Srenato 			LIST_INIT(&nl2vpn->pw_list);
5236399cec1Srenato 
5246399cec1Srenato 			LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);
5256399cec1Srenato 			break;
5266399cec1Srenato 		case IMSG_RECONF_L2VPN_IF:
5276399cec1Srenato 			if ((nlif = malloc(sizeof(struct l2vpn_if))) == NULL)
5286399cec1Srenato 				fatal(NULL);
5296399cec1Srenato 			memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
5306399cec1Srenato 
5316399cec1Srenato 			nlif->l2vpn = nl2vpn;
5326399cec1Srenato 			LIST_INSERT_HEAD(&nl2vpn->if_list, nlif, entry);
5336399cec1Srenato 			break;
5346399cec1Srenato 		case IMSG_RECONF_L2VPN_PW:
5356399cec1Srenato 			if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
5366399cec1Srenato 				fatal(NULL);
5376399cec1Srenato 			memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
5386399cec1Srenato 
5396399cec1Srenato 			npw->l2vpn = nl2vpn;
5406399cec1Srenato 			LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry);
5416399cec1Srenato 			break;
5427ee91690Sdlg 		case IMSG_RECONF_CONF_AUTH: {
5437ee91690Sdlg 			struct ldp_auth *auth;
5447ee91690Sdlg 
5457ee91690Sdlg 			auth = malloc(sizeof(*auth));
5467ee91690Sdlg 			if (auth == NULL)
5477ee91690Sdlg 				fatal(NULL);
5487ee91690Sdlg 
5497ee91690Sdlg 			memcpy(auth, imsg.data, sizeof(*auth));
5507ee91690Sdlg 
5517ee91690Sdlg 			LIST_INSERT_HEAD(&nconf->auth_list, auth, entry);
5527ee91690Sdlg 			break;
5537ee91690Sdlg 		}
554ab0c2486Smichele 		case IMSG_RECONF_END:
555be87e4d3Srenato 			merge_config(ldeconf, nconf);
556be87e4d3Srenato 			nconf = NULL;
557ab0c2486Smichele 			break;
558ab0c2486Smichele 		default:
559b7b4db73Srenato 			log_debug("%s: unexpected imsg %d", __func__,
560ab0c2486Smichele 			    imsg.hdr.type);
561ab0c2486Smichele 			break;
562ab0c2486Smichele 		}
563ab0c2486Smichele 		imsg_free(&imsg);
564ab0c2486Smichele 	}
565ab0c2486Smichele 	if (!shut)
566cb77742aSpyr 		imsg_event_add(iev);
567ab0c2486Smichele 	else {
568ab0c2486Smichele 		/* this pipe is dead, so remove the event handler */
569cb77742aSpyr 		event_del(&iev->ev);
570ab0c2486Smichele 		event_loopexit(NULL);
571ab0c2486Smichele 	}
572ab0c2486Smichele }
573ab0c2486Smichele 
5743de94509Srenato uint32_t
575e3948831Sclaudio lde_assign_label(void)
576ab0c2486Smichele {
5773de94509Srenato 	static uint32_t label = MPLS_LABEL_RESERVED_MAX;
578e3948831Sclaudio 
579e3948831Sclaudio 	/* XXX some checks needed */
580e3948831Sclaudio 	label++;
58119fce358Srenato 	return (label);
582ab0c2486Smichele }
583ab0c2486Smichele 
584ab0c2486Smichele void
5856106bae4Srenato lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
586ab0c2486Smichele {
587ab0c2486Smichele 	struct kroute	kr;
5886399cec1Srenato 	struct kpw	kpw;
5896399cec1Srenato 	struct l2vpn_pw	*pw;
590ab0c2486Smichele 
5916399cec1Srenato 	switch (fn->fec.type) {
5926399cec1Srenato 	case FEC_TYPE_IPV4:
5933de94509Srenato 		memset(&kr, 0, sizeof(kr));
594a8c39dc0Srenato 		kr.af = AF_INET;
595a8c39dc0Srenato 		kr.prefix.v4 = fn->fec.u.ipv4.prefix;
5966399cec1Srenato 		kr.prefixlen = fn->fec.u.ipv4.prefixlen;
597a8c39dc0Srenato 		kr.nexthop.v4 = fnh->nexthop.v4;
5986106bae4Srenato 		kr.local_label = fn->local_label;
5996106bae4Srenato 		kr.remote_label = fnh->remote_label;
6000c0343b7Srenato 		kr.priority = fnh->priority;
601ab0c2486Smichele 
6026399cec1Srenato 		lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
6036399cec1Srenato 		    sizeof(kr));
6046399cec1Srenato 
605a8c39dc0Srenato 		if (fn->fec.u.ipv4.prefixlen == 32)
606a8c39dc0Srenato 			l2vpn_sync_pws(AF_INET, (union ldpd_addr *)
607a8c39dc0Srenato 			    &fn->fec.u.ipv4.prefix);
608a8c39dc0Srenato 		break;
609a8c39dc0Srenato 	case FEC_TYPE_IPV6:
610a8c39dc0Srenato 		memset(&kr, 0, sizeof(kr));
611a8c39dc0Srenato 		kr.af = AF_INET6;
612a8c39dc0Srenato 		kr.prefix.v6 = fn->fec.u.ipv6.prefix;
613a8c39dc0Srenato 		kr.prefixlen = fn->fec.u.ipv6.prefixlen;
614a8c39dc0Srenato 		kr.nexthop.v6 = fnh->nexthop.v6;
615a8c39dc0Srenato 		kr.local_label = fn->local_label;
616a8c39dc0Srenato 		kr.remote_label = fnh->remote_label;
6170c0343b7Srenato 		kr.priority = fnh->priority;
618a8c39dc0Srenato 
619a8c39dc0Srenato 		lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
620a8c39dc0Srenato 		    sizeof(kr));
621a8c39dc0Srenato 
622a8c39dc0Srenato 		if (fn->fec.u.ipv6.prefixlen == 128)
623a8c39dc0Srenato 			l2vpn_sync_pws(AF_INET6, (union ldpd_addr *)
624a8c39dc0Srenato 			    &fn->fec.u.ipv6.prefix);
6256399cec1Srenato 		break;
6266399cec1Srenato 	case FEC_TYPE_PWID:
6276399cec1Srenato 		if (fn->local_label == NO_LABEL ||
6286399cec1Srenato 		    fnh->remote_label == NO_LABEL)
6296399cec1Srenato 			return;
6306399cec1Srenato 
63172bfe95eSrenato 		pw = (struct l2vpn_pw *) fn->data;
6326399cec1Srenato 		pw->flags |= F_PW_STATUS_UP;
6336399cec1Srenato 
6343de94509Srenato 		memset(&kpw, 0, sizeof(kpw));
6356399cec1Srenato 		kpw.ifindex = pw->ifindex;
6366399cec1Srenato 		kpw.pw_type = fn->fec.u.pwid.type;
637a8c39dc0Srenato 		kpw.af = pw->af;
638a8c39dc0Srenato 		kpw.nexthop = pw->addr;
6396399cec1Srenato 		kpw.local_label = fn->local_label;
6406399cec1Srenato 		kpw.remote_label = fnh->remote_label;
6416399cec1Srenato 		kpw.flags = pw->flags;
6426399cec1Srenato 
6436399cec1Srenato 		lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw,
6446399cec1Srenato 		    sizeof(kpw));
6456399cec1Srenato 		break;
6466399cec1Srenato 	}
647ab0c2486Smichele }
648ab0c2486Smichele 
649ab0c2486Smichele void
6506106bae4Srenato lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
651ab0c2486Smichele {
652ab0c2486Smichele 	struct kroute	 kr;
6536399cec1Srenato 	struct kpw	 kpw;
6546399cec1Srenato 	struct l2vpn_pw	*pw;
655ab0c2486Smichele 
6566399cec1Srenato 	switch (fn->fec.type) {
6576399cec1Srenato 	case FEC_TYPE_IPV4:
6583de94509Srenato 		memset(&kr, 0, sizeof(kr));
659a8c39dc0Srenato 		kr.af = AF_INET;
660a8c39dc0Srenato 		kr.prefix.v4 = fn->fec.u.ipv4.prefix;
6616399cec1Srenato 		kr.prefixlen = fn->fec.u.ipv4.prefixlen;
662a8c39dc0Srenato 		kr.nexthop.v4 = fnh->nexthop.v4;
6636106bae4Srenato 		kr.local_label = fn->local_label;
6646106bae4Srenato 		kr.remote_label = fnh->remote_label;
6650c0343b7Srenato 		kr.priority = fnh->priority;
666ab0c2486Smichele 
6676399cec1Srenato 		lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
6686399cec1Srenato 		    sizeof(kr));
6696399cec1Srenato 
6706399cec1Srenato 		if (fn->fec.u.ipv4.prefixlen == 32)
671a8c39dc0Srenato 			l2vpn_sync_pws(AF_INET, (union ldpd_addr *)
672a8c39dc0Srenato 			    &fn->fec.u.ipv4.prefix);
673a8c39dc0Srenato 		break;
674a8c39dc0Srenato 	case FEC_TYPE_IPV6:
675a8c39dc0Srenato 		memset(&kr, 0, sizeof(kr));
676a8c39dc0Srenato 		kr.af = AF_INET6;
677a8c39dc0Srenato 		kr.prefix.v6 = fn->fec.u.ipv6.prefix;
678a8c39dc0Srenato 		kr.prefixlen = fn->fec.u.ipv6.prefixlen;
679a8c39dc0Srenato 		kr.nexthop.v6 = fnh->nexthop.v6;
680a8c39dc0Srenato 		kr.local_label = fn->local_label;
681a8c39dc0Srenato 		kr.remote_label = fnh->remote_label;
6820c0343b7Srenato 		kr.priority = fnh->priority;
683a8c39dc0Srenato 
684a8c39dc0Srenato 		lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
685a8c39dc0Srenato 		    sizeof(kr));
686a8c39dc0Srenato 
687a8c39dc0Srenato 		if (fn->fec.u.ipv6.prefixlen == 128)
688a8c39dc0Srenato 			l2vpn_sync_pws(AF_INET6, (union ldpd_addr *)
689a8c39dc0Srenato 			    &fn->fec.u.ipv6.prefix);
6906399cec1Srenato 		break;
6916399cec1Srenato 	case FEC_TYPE_PWID:
69272bfe95eSrenato 		pw = (struct l2vpn_pw *) fn->data;
6936399cec1Srenato 		if (!(pw->flags & F_PW_STATUS_UP))
6946399cec1Srenato 			return;
6956399cec1Srenato 		pw->flags &= ~F_PW_STATUS_UP;
6966399cec1Srenato 
6973de94509Srenato 		memset(&kpw, 0, sizeof(kpw));
6986399cec1Srenato 		kpw.ifindex = pw->ifindex;
6996399cec1Srenato 		kpw.pw_type = fn->fec.u.pwid.type;
700a8c39dc0Srenato 		kpw.af = pw->af;
701a8c39dc0Srenato 		kpw.nexthop = pw->addr;
7026399cec1Srenato 		kpw.local_label = fn->local_label;
7036399cec1Srenato 		kpw.remote_label = fnh->remote_label;
7046399cec1Srenato 		kpw.flags = pw->flags;
7056399cec1Srenato 
7066399cec1Srenato 		lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw,
7076399cec1Srenato 		    sizeof(kpw));
7086399cec1Srenato 		break;
7096399cec1Srenato 	}
710ab0c2486Smichele }
711ab0c2486Smichele 
712ab0c2486Smichele void
7136399cec1Srenato lde_fec2map(struct fec *fec, struct map *map)
7146399cec1Srenato {
7153de94509Srenato 	memset(map, 0, sizeof(*map));
7166399cec1Srenato 
7176399cec1Srenato 	switch (fec->type) {
7186399cec1Srenato 	case FEC_TYPE_IPV4:
719cf09440fSrenato 		map->type = MAP_TYPE_PREFIX;
72000f5e67fSrenato 		map->fec.prefix.af = AF_INET;
721a8c39dc0Srenato 		map->fec.prefix.prefix.v4 = fec->u.ipv4.prefix;
722a8c39dc0Srenato 		map->fec.prefix.prefixlen = fec->u.ipv4.prefixlen;
723a8c39dc0Srenato 		break;
724a8c39dc0Srenato 	case FEC_TYPE_IPV6:
725a8c39dc0Srenato 		map->type = MAP_TYPE_PREFIX;
72600f5e67fSrenato 		map->fec.prefix.af = AF_INET6;
727a8c39dc0Srenato 		map->fec.prefix.prefix.v6 = fec->u.ipv6.prefix;
728a8c39dc0Srenato 		map->fec.prefix.prefixlen = fec->u.ipv6.prefixlen;
7296399cec1Srenato 		break;
7306399cec1Srenato 	case FEC_TYPE_PWID:
731cf09440fSrenato 		map->type = MAP_TYPE_PWID;
7326399cec1Srenato 		map->fec.pwid.type = fec->u.pwid.type;
7336399cec1Srenato 		map->fec.pwid.group_id = 0;
7346399cec1Srenato 		map->flags |= F_MAP_PW_ID;
7356399cec1Srenato 		map->fec.pwid.pwid = fec->u.pwid.pwid;
7366399cec1Srenato 		break;
7376399cec1Srenato 	}
7386399cec1Srenato }
7396399cec1Srenato 
7406399cec1Srenato void
74172bfe95eSrenato lde_map2fec(struct map *map, struct in_addr lsr_id, struct fec *fec)
7426399cec1Srenato {
7433de94509Srenato 	memset(fec, 0, sizeof(*fec));
7446399cec1Srenato 
7456399cec1Srenato 	switch (map->type) {
746cf09440fSrenato 	case MAP_TYPE_PREFIX:
747a8c39dc0Srenato 		switch (map->fec.prefix.af) {
74800f5e67fSrenato 		case AF_INET:
7496399cec1Srenato 			fec->type = FEC_TYPE_IPV4;
750a8c39dc0Srenato 			fec->u.ipv4.prefix = map->fec.prefix.prefix.v4;
751a8c39dc0Srenato 			fec->u.ipv4.prefixlen = map->fec.prefix.prefixlen;
752a8c39dc0Srenato 			break;
75300f5e67fSrenato 		case AF_INET6:
754a8c39dc0Srenato 			fec->type = FEC_TYPE_IPV6;
755a8c39dc0Srenato 			fec->u.ipv6.prefix = map->fec.prefix.prefix.v6;
756a8c39dc0Srenato 			fec->u.ipv6.prefixlen = map->fec.prefix.prefixlen;
757a8c39dc0Srenato 			break;
758a8c39dc0Srenato 		default:
759a8c39dc0Srenato 			fatalx("lde_map2fec: unknown af");
760a8c39dc0Srenato 			break;
761a8c39dc0Srenato 		}
7626399cec1Srenato 		break;
763cf09440fSrenato 	case MAP_TYPE_PWID:
7646399cec1Srenato 		fec->type = FEC_TYPE_PWID;
7656399cec1Srenato 		fec->u.pwid.type = map->fec.pwid.type;
7666399cec1Srenato 		fec->u.pwid.pwid = map->fec.pwid.pwid;
76772bfe95eSrenato 		fec->u.pwid.lsr_id = lsr_id;
7686399cec1Srenato 		break;
7696399cec1Srenato 	}
7706399cec1Srenato }
7716399cec1Srenato 
7726399cec1Srenato void
7736399cec1Srenato lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
774ab0c2486Smichele {
775fb298019Sclaudio 	struct lde_req	*lre;
776fb298019Sclaudio 	struct lde_map	*me;
777fb298019Sclaudio 	struct map	 map;
7786399cec1Srenato 	struct l2vpn_pw	*pw;
779fb298019Sclaudio 
780fb298019Sclaudio 	/*
781cf483f25Srenato 	 * This function skips SL.1 - 3 and SL.9 - 14 because the label
782fb298019Sclaudio 	 * allocation is done way earlier (because of the merging nature of
783fb298019Sclaudio 	 * ldpd).
784fb298019Sclaudio 	 */
785fb298019Sclaudio 
7866399cec1Srenato 	lde_fec2map(&fn->fec, &map);
787a8c39dc0Srenato 	switch (fn->fec.type) {
788a8c39dc0Srenato 	case FEC_TYPE_IPV4:
789a8c39dc0Srenato 		if (!ln->v4_enabled)
790a8c39dc0Srenato 			return;
791a8c39dc0Srenato 		break;
792a8c39dc0Srenato 	case FEC_TYPE_IPV6:
793a8c39dc0Srenato 		if (!ln->v6_enabled)
794a8c39dc0Srenato 			return;
795a8c39dc0Srenato 		break;
796a8c39dc0Srenato 	case FEC_TYPE_PWID:
79772bfe95eSrenato 		pw = (struct l2vpn_pw *) fn->data;
79872bfe95eSrenato 		if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr)
79972bfe95eSrenato 			/* not the remote end of the pseudowire */
8006399cec1Srenato 			return;
8016399cec1Srenato 
8026399cec1Srenato 		map.flags |= F_MAP_PW_IFMTU;
8036399cec1Srenato 		map.fec.pwid.ifmtu = pw->l2vpn->mtu;
8042d825b92Srenato 		if (pw->flags & F_PW_CWORD)
8056399cec1Srenato 			map.flags |= F_MAP_PW_CWORD;
8066399cec1Srenato 		if (pw->flags & F_PW_STATUSTLV) {
8076399cec1Srenato 			map.flags |= F_MAP_PW_STATUS;
8086399cec1Srenato 			/* VPLS are always up */
8096399cec1Srenato 			map.pw_status = PW_FORWARDING;
8106399cec1Srenato 		}
811a8c39dc0Srenato 		break;
8126399cec1Srenato 	}
8136106bae4Srenato 	map.label = fn->local_label;
814fb298019Sclaudio 
815cf483f25Srenato 	/* SL.6: is there a pending request for this mapping? */
8166106bae4Srenato 	lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
817fb298019Sclaudio 	if (lre) {
818fb298019Sclaudio 		/* set label request msg id in the mapping response. */
81960e1e0e7Srenato 		map.requestid = lre->msg_id;
820fb298019Sclaudio 		map.flags = F_MAP_REQ_ID;
821cf483f25Srenato 
822cf483f25Srenato 		/* SL.7: delete record of pending request */
823fb298019Sclaudio 		lde_req_del(ln, lre, 0);
824fb298019Sclaudio 	}
825fb298019Sclaudio 
826cf483f25Srenato 	/* SL.4: send label mapping */
827cf483f25Srenato 	lde_imsg_compose_ldpe(IMSG_MAPPING_ADD, ln->peerid, 0,
828cf483f25Srenato 	    &map, sizeof(map));
8296399cec1Srenato 	if (single)
8306399cec1Srenato 		lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0,
8316399cec1Srenato 		    NULL, 0);
832cf483f25Srenato 
833cf483f25Srenato 	/* SL.5: record sent label mapping */
8346106bae4Srenato 	me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
835fb298019Sclaudio 	if (me == NULL)
8366106bae4Srenato 		me = lde_map_add(ln, fn, 1);
8377aa09c5dSrenato 	me->map = map;
838cf483f25Srenato }
839fb298019Sclaudio 
840cf483f25Srenato void
8412c06fdf4Srenato lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn,
8422c06fdf4Srenato     struct map *wcard, struct status_tlv *st)
843cf483f25Srenato {
844cf483f25Srenato 	struct lde_wdraw	*lw;
845cf483f25Srenato 	struct map		 map;
846cf483f25Srenato 	struct fec		*f;
8476399cec1Srenato 	struct l2vpn_pw		*pw;
8486399cec1Srenato 
8496106bae4Srenato 	if (fn) {
8506399cec1Srenato 		lde_fec2map(&fn->fec, &map);
851a8c39dc0Srenato 		switch (fn->fec.type) {
852a8c39dc0Srenato 		case FEC_TYPE_IPV4:
853a8c39dc0Srenato 			if (!ln->v4_enabled)
854a8c39dc0Srenato 				return;
855a8c39dc0Srenato 			break;
856a8c39dc0Srenato 		case FEC_TYPE_IPV6:
857a8c39dc0Srenato 			if (!ln->v6_enabled)
858a8c39dc0Srenato 				return;
859a8c39dc0Srenato 			break;
860a8c39dc0Srenato 		case FEC_TYPE_PWID:
8613de94509Srenato 			pw = (struct l2vpn_pw *) fn->data;
8623de94509Srenato 			if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr)
8633de94509Srenato 				/* not the remote end of the pseudowire */
8643de94509Srenato 				return;
8653de94509Srenato 
8662d825b92Srenato 			if (pw->flags & F_PW_CWORD)
8676399cec1Srenato 				map.flags |= F_MAP_PW_CWORD;
868a8c39dc0Srenato 			break;
8696399cec1Srenato 		}
870a8c39dc0Srenato 		map.label = fn->local_label;
8712c06fdf4Srenato 	} else
8722c06fdf4Srenato 		memcpy(&map, wcard, sizeof(map));
873cf483f25Srenato 
87460e1e0e7Srenato 	if (st) {
87560e1e0e7Srenato 		map.st.status_code = st->status_code;
87660e1e0e7Srenato 		map.st.msg_id = st->msg_id;
87760e1e0e7Srenato 		map.st.msg_type = st->msg_type;
8785ba85977Srenato 		map.flags |= F_MAP_STATUS;
8795ba85977Srenato 	}
8805ba85977Srenato 
881cf483f25Srenato 	/* SWd.1: send label withdraw. */
882cf483f25Srenato 	lde_imsg_compose_ldpe(IMSG_WITHDRAW_ADD, ln->peerid, 0,
883eab950efSrenato  	    &map, sizeof(map));
884cf483f25Srenato 	lde_imsg_compose_ldpe(IMSG_WITHDRAW_ADD_END, ln->peerid, 0, NULL, 0);
885cf483f25Srenato 
886cf483f25Srenato 	/* SWd.2: record label withdraw. */
8876106bae4Srenato 	if (fn) {
8886106bae4Srenato 		lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
889cf483f25Srenato 		if (lw == NULL)
8906106bae4Srenato 			lw = lde_wdraw_add(ln, fn);
891cf483f25Srenato 		lw->label = map.label;
892cf483f25Srenato 	} else {
8932c06fdf4Srenato 		struct lde_map *me;
8942c06fdf4Srenato 
8956106bae4Srenato 		RB_FOREACH(f, fec_tree, &ft) {
8966106bae4Srenato 			fn = (struct fec_node *)f;
8972c06fdf4Srenato 			me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
8982c06fdf4Srenato 			if (lde_wildcard_apply(wcard, &fn->fec, me) == 0)
8992c06fdf4Srenato 				continue;
900cf483f25Srenato 
901cf483f25Srenato 			lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw,
9026106bae4Srenato 			    &fn->fec);
903cf483f25Srenato 			if (lw == NULL)
9046106bae4Srenato 				lw = lde_wdraw_add(ln, fn);
905cf483f25Srenato 			lw->label = map.label;
906cf483f25Srenato 		}
907cf483f25Srenato 	}
908ab0c2486Smichele }
909ab0c2486Smichele 
910ab0c2486Smichele void
9112c06fdf4Srenato lde_send_labelwithdraw_wcard(struct lde_nbr *ln, uint32_t label)
912ab0c2486Smichele {
9132c06fdf4Srenato 	struct map	 wcard;
9146399cec1Srenato 
9152c06fdf4Srenato 	memset(&wcard, 0, sizeof(wcard));
9162c06fdf4Srenato 	wcard.type = MAP_TYPE_WILDCARD;
9172c06fdf4Srenato 	wcard.label = label;
9182c06fdf4Srenato 	lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
9196399cec1Srenato }
920fb298019Sclaudio 
9213de94509Srenato void
922c7c5a728Srenato lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *ln, uint16_t af,
923c7c5a728Srenato     uint32_t label)
924c7c5a728Srenato {
925c7c5a728Srenato 	struct map	 wcard;
926c7c5a728Srenato 
927c7c5a728Srenato 	memset(&wcard, 0, sizeof(wcard));
928c7c5a728Srenato 	wcard.type = MAP_TYPE_TYPED_WCARD;
929c7c5a728Srenato 	wcard.fec.twcard.type = MAP_TYPE_PREFIX;
930c7c5a728Srenato 	wcard.fec.twcard.u.prefix_af = af;
931c7c5a728Srenato 	wcard.label = label;
932c7c5a728Srenato 	lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
933c7c5a728Srenato }
934c7c5a728Srenato 
935c7c5a728Srenato void
9366702dd25Srenato lde_send_labelwithdraw_twcard_pwid(struct lde_nbr *ln, uint16_t pw_type,
9376702dd25Srenato     uint32_t label)
9386702dd25Srenato {
9396702dd25Srenato 	struct map	 wcard;
9406702dd25Srenato 
9416702dd25Srenato 	memset(&wcard, 0, sizeof(wcard));
9426702dd25Srenato 	wcard.type = MAP_TYPE_TYPED_WCARD;
9436702dd25Srenato 	wcard.fec.twcard.type = MAP_TYPE_PWID;
9446702dd25Srenato 	wcard.fec.twcard.u.pw_type = pw_type;
9456702dd25Srenato 	wcard.label = label;
9466702dd25Srenato 	lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
9476702dd25Srenato }
9486702dd25Srenato 
9496702dd25Srenato void
9502c06fdf4Srenato lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *ln, uint16_t pw_type,
9512c06fdf4Srenato     uint32_t group_id)
9522c06fdf4Srenato {
9532c06fdf4Srenato 	struct map	 wcard;
9542c06fdf4Srenato 
9552c06fdf4Srenato 	memset(&wcard, 0, sizeof(wcard));
9562c06fdf4Srenato 	wcard.type = MAP_TYPE_PWID;
9572c06fdf4Srenato 	wcard.fec.pwid.type = pw_type;
9582c06fdf4Srenato 	wcard.fec.pwid.group_id = group_id;
9592c06fdf4Srenato 	/* we can not append a Label TLV when using PWid group wildcards. */
9602c06fdf4Srenato 	wcard.label = NO_LABEL;
9612c06fdf4Srenato 	lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
9622c06fdf4Srenato }
9632c06fdf4Srenato 
9642c06fdf4Srenato void
9652c06fdf4Srenato lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn,
9662c06fdf4Srenato     struct map *wcard, uint32_t label)
9673de94509Srenato {
9683de94509Srenato 	struct map		 map;
9693de94509Srenato 	struct l2vpn_pw		*pw;
9703de94509Srenato 
9716106bae4Srenato 	if (fn) {
9726399cec1Srenato 		lde_fec2map(&fn->fec, &map);
973a8c39dc0Srenato 		switch (fn->fec.type) {
974a8c39dc0Srenato 		case FEC_TYPE_IPV4:
975a8c39dc0Srenato 			if (!ln->v4_enabled)
976a8c39dc0Srenato 				return;
977a8c39dc0Srenato 			break;
978a8c39dc0Srenato 		case FEC_TYPE_IPV6:
979a8c39dc0Srenato 			if (!ln->v6_enabled)
980a8c39dc0Srenato 				return;
981a8c39dc0Srenato 			break;
982a8c39dc0Srenato 		case FEC_TYPE_PWID:
9833de94509Srenato 			pw = (struct l2vpn_pw *) fn->data;
9843de94509Srenato 			if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr)
9853de94509Srenato 				/* not the remote end of the pseudowire */
9863de94509Srenato 				return;
9873de94509Srenato 
9882d825b92Srenato 			if (pw->flags & F_PW_CWORD)
9896399cec1Srenato 				map.flags |= F_MAP_PW_CWORD;
990a8c39dc0Srenato 			break;
9916399cec1Srenato 		}
9922c06fdf4Srenato 	} else
9932c06fdf4Srenato 		memcpy(&map, wcard, sizeof(map));
994fb298019Sclaudio 	map.label = label;
995fb298019Sclaudio 
996eab950efSrenato 	lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0,
997eab950efSrenato 	    &map, sizeof(map));
998cf483f25Srenato 	lde_imsg_compose_ldpe(IMSG_RELEASE_ADD_END, ln->peerid, 0, NULL, 0);
999ab0c2486Smichele }
1000ab0c2486Smichele 
1001ab0c2486Smichele void
100202a212eeSrenato lde_send_notification(struct lde_nbr *ln, uint32_t status_code, uint32_t msg_id,
100360e1e0e7Srenato     uint16_t msg_type)
1004ab0c2486Smichele {
10057d508fe8Smichele 	struct notify_msg nm;
10067d508fe8Smichele 
10073de94509Srenato 	memset(&nm, 0, sizeof(nm));
100860e1e0e7Srenato 	nm.status_code = status_code;
100960e1e0e7Srenato 	/* 'msg_id' and 'msg_type' should be in network byte order */
101060e1e0e7Srenato 	nm.msg_id = msg_id;
101160e1e0e7Srenato 	nm.msg_type = msg_type;
10127d508fe8Smichele 
101302a212eeSrenato 	lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
1014eab950efSrenato 	    &nm, sizeof(nm));
1015ab0c2486Smichele }
1016ab0c2486Smichele 
10179246985aSrenato void
10189246985aSrenato lde_send_notification_eol_prefix(struct lde_nbr *ln, int af)
10199246985aSrenato {
10209246985aSrenato 	struct notify_msg nm;
10219246985aSrenato 
10229246985aSrenato 	memset(&nm, 0, sizeof(nm));
10239246985aSrenato 	nm.status_code = S_ENDOFLIB;
10249246985aSrenato 	nm.fec.type = MAP_TYPE_TYPED_WCARD;
10259246985aSrenato 	nm.fec.fec.twcard.type = MAP_TYPE_PREFIX;
10269246985aSrenato 	nm.fec.fec.twcard.u.prefix_af = af;
10279246985aSrenato 	nm.flags |= F_NOTIF_FEC;
10289246985aSrenato 
10299246985aSrenato 	lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
10309246985aSrenato 	    &nm, sizeof(nm));
10319246985aSrenato }
10329246985aSrenato 
10339246985aSrenato void
10349246985aSrenato lde_send_notification_eol_pwid(struct lde_nbr *ln, uint16_t pw_type)
10359246985aSrenato {
10369246985aSrenato 	struct notify_msg nm;
10379246985aSrenato 
10389246985aSrenato 	memset(&nm, 0, sizeof(nm));
10399246985aSrenato 	nm.status_code = S_ENDOFLIB;
10409246985aSrenato 	nm.fec.type = MAP_TYPE_TYPED_WCARD;
10419246985aSrenato 	nm.fec.fec.twcard.type = MAP_TYPE_PWID;
10429246985aSrenato 	nm.fec.fec.twcard.u.pw_type = pw_type;
10439246985aSrenato 	nm.flags |= F_NOTIF_FEC;
10449246985aSrenato 
10459246985aSrenato 	lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
10469246985aSrenato 	    &nm, sizeof(nm));
10479246985aSrenato }
10489246985aSrenato 
1049e3948831Sclaudio static __inline int
1050e3948831Sclaudio lde_nbr_compare(struct lde_nbr *a, struct lde_nbr *b)
1051ab0c2486Smichele {
1052e3948831Sclaudio 	return (a->peerid - b->peerid);
1053ab0c2486Smichele }
1054ab0c2486Smichele 
1055c28a25a1Srenato static struct lde_nbr *
1056a8c39dc0Srenato lde_nbr_new(uint32_t peerid, struct lde_nbr *new)
1057ab0c2486Smichele {
10582d825b92Srenato 	struct lde_nbr	*ln;
1059ab0c2486Smichele 
10602d825b92Srenato 	if ((ln = calloc(1, sizeof(*ln))) == NULL)
1061b7b4db73Srenato 		fatal(__func__);
1062ab0c2486Smichele 
1063a8c39dc0Srenato 	ln->id = new->id;
1064a8c39dc0Srenato 	ln->v4_enabled = new->v4_enabled;
1065a8c39dc0Srenato 	ln->v6_enabled = new->v6_enabled;
10669246985aSrenato 	ln->flags = new->flags;
10672d825b92Srenato 	ln->peerid = peerid;
10682d825b92Srenato 	fec_init(&ln->recv_map);
10692d825b92Srenato 	fec_init(&ln->sent_map);
10702d825b92Srenato 	fec_init(&ln->recv_req);
10712d825b92Srenato 	fec_init(&ln->sent_req);
10722d825b92Srenato 	fec_init(&ln->sent_wdraw);
1073ab0c2486Smichele 
10742d825b92Srenato 	TAILQ_INIT(&ln->addr_list);
1075ab0c2486Smichele 
10762d825b92Srenato 	if (RB_INSERT(nbr_tree, &lde_nbrs, ln) != NULL)
1077e3948831Sclaudio 		fatalx("lde_nbr_new: RB_INSERT failed");
1078ab0c2486Smichele 
10792d825b92Srenato 	return (ln);
1080ab0c2486Smichele }
1081ab0c2486Smichele 
1082c28a25a1Srenato static void
10832d825b92Srenato lde_nbr_del(struct lde_nbr *ln)
1084d5e40e07Sclaudio {
10855b52d092Srenato 	struct fec		*f;
10866106bae4Srenato 	struct fec_node		*fn;
10876106bae4Srenato 	struct fec_nh		*fnh;
1088a2da3f43Srenato 	struct l2vpn_pw		*pw;
10895b52d092Srenato 
10902d825b92Srenato 	if (ln == NULL)
1091d5e40e07Sclaudio 		return;
1092d5e40e07Sclaudio 
10935b52d092Srenato 	/* uninstall received mappings */
10946106bae4Srenato 	RB_FOREACH(f, fec_tree, &ft) {
10956106bae4Srenato 		fn = (struct fec_node *)f;
10965b52d092Srenato 
10976106bae4Srenato 		LIST_FOREACH(fnh, &fn->nexthops, entry) {
109872bfe95eSrenato 			switch (f->type) {
109972bfe95eSrenato 			case FEC_TYPE_IPV4:
1100a8c39dc0Srenato 			case FEC_TYPE_IPV6:
1101a8c39dc0Srenato 				if (!lde_address_find(ln, fnh->af,
1102a8c39dc0Srenato 				    &fnh->nexthop))
110372bfe95eSrenato 					continue;
110472bfe95eSrenato 				break;
110572bfe95eSrenato 			case FEC_TYPE_PWID:
110672bfe95eSrenato 				if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
110772bfe95eSrenato 					continue;
1108a2da3f43Srenato 				pw = (struct l2vpn_pw *) fn->data;
1109a2da3f43Srenato 				if (pw)
1110a2da3f43Srenato 					l2vpn_pw_reset(pw);
111172bfe95eSrenato 				break;
111272bfe95eSrenato 			default:
111372bfe95eSrenato 				break;
111472bfe95eSrenato 			}
111572bfe95eSrenato 
11166106bae4Srenato 			lde_send_delete_klabel(fn, fnh);
11176106bae4Srenato 			fnh->remote_label = NO_LABEL;
11185b52d092Srenato 		}
11195b52d092Srenato 	}
11205b52d092Srenato 
11212d825b92Srenato 	lde_address_list_free(ln);
1122d5e40e07Sclaudio 
11232d825b92Srenato 	fec_clear(&ln->recv_map, lde_map_free);
11242d825b92Srenato 	fec_clear(&ln->sent_map, lde_map_free);
11252d825b92Srenato 	fec_clear(&ln->recv_req, free);
11262d825b92Srenato 	fec_clear(&ln->sent_req, free);
11272d825b92Srenato 	fec_clear(&ln->sent_wdraw, free);
1128e3948831Sclaudio 
11292d825b92Srenato 	RB_REMOVE(nbr_tree, &lde_nbrs, ln);
1130d5e40e07Sclaudio 
11312d825b92Srenato 	free(ln);
1132d5e40e07Sclaudio }
1133d5e40e07Sclaudio 
1134c28a25a1Srenato static struct lde_nbr *
113533f6ccfeSrenato lde_nbr_find(uint32_t peerid)
113633f6ccfeSrenato {
11372d825b92Srenato 	struct lde_nbr		 ln;
113833f6ccfeSrenato 
11392d825b92Srenato 	ln.peerid = peerid;
114033f6ccfeSrenato 
11412d825b92Srenato 	return (RB_FIND(nbr_tree, &lde_nbrs, &ln));
114233f6ccfeSrenato }
114333f6ccfeSrenato 
114472bfe95eSrenato struct lde_nbr *
114572bfe95eSrenato lde_nbr_find_by_lsrid(struct in_addr addr)
114672bfe95eSrenato {
114772bfe95eSrenato 	struct lde_nbr		*ln;
114872bfe95eSrenato 
114972bfe95eSrenato 	RB_FOREACH(ln, nbr_tree, &lde_nbrs)
115072bfe95eSrenato 		if (ln->id.s_addr == addr.s_addr)
115172bfe95eSrenato 			return (ln);
115272bfe95eSrenato 
115372bfe95eSrenato 	return (NULL);
115472bfe95eSrenato }
115572bfe95eSrenato 
115672bfe95eSrenato struct lde_nbr *
1157a8c39dc0Srenato lde_nbr_find_by_addr(int af, union ldpd_addr *addr)
115872bfe95eSrenato {
115972bfe95eSrenato 	struct lde_nbr		*ln;
116072bfe95eSrenato 
116172bfe95eSrenato 	RB_FOREACH(ln, nbr_tree, &lde_nbrs)
1162a8c39dc0Srenato 		if (lde_address_find(ln, af, addr) != NULL)
116372bfe95eSrenato 			return (ln);
116472bfe95eSrenato 
116572bfe95eSrenato 	return (NULL);
116672bfe95eSrenato }
116772bfe95eSrenato 
1168c28a25a1Srenato static void
1169e3948831Sclaudio lde_nbr_clear(void)
1170e3948831Sclaudio {
11712d825b92Srenato 	struct lde_nbr	*ln;
1172e3948831Sclaudio 
11732d825b92Srenato 	while ((ln = RB_ROOT(&lde_nbrs)) != NULL)
11742d825b92Srenato 		lde_nbr_del(ln);
1175e3948831Sclaudio }
1176e3948831Sclaudio 
1177ed90b960Srenato static void
1178ed90b960Srenato lde_nbr_addr_update(struct lde_nbr *ln, struct lde_addr *lde_addr, int removed)
1179ed90b960Srenato {
1180ed90b960Srenato 	struct fec		*fec;
1181ed90b960Srenato 	struct fec_node		*fn;
1182ed90b960Srenato 	struct fec_nh		*fnh;
1183ed90b960Srenato 	struct lde_map		*me;
1184ed90b960Srenato 
1185ed90b960Srenato 	RB_FOREACH(fec, fec_tree, &ln->recv_map) {
1186ed90b960Srenato 		fn = (struct fec_node *)fec_find(&ft, fec);
1187ed90b960Srenato 		switch (fec->type) {
1188ed90b960Srenato 		case FEC_TYPE_IPV4:
1189ed90b960Srenato 			if (lde_addr->af != AF_INET)
1190ed90b960Srenato 				continue;
1191ed90b960Srenato 			break;
1192ed90b960Srenato 		case FEC_TYPE_IPV6:
1193ed90b960Srenato 			if (lde_addr->af != AF_INET6)
1194ed90b960Srenato 				continue;
1195ed90b960Srenato 			break;
1196ed90b960Srenato 		default:
1197ed90b960Srenato 			continue;
1198ed90b960Srenato 		}
1199ed90b960Srenato 
1200ed90b960Srenato 		LIST_FOREACH(fnh, &fn->nexthops, entry) {
1201ed90b960Srenato 			if (ldp_addrcmp(fnh->af, &fnh->nexthop,
1202ed90b960Srenato 			    &lde_addr->addr))
1203ed90b960Srenato 				continue;
1204ed90b960Srenato 
1205ed90b960Srenato 			if (removed) {
1206ed90b960Srenato 				lde_send_delete_klabel(fn, fnh);
1207ed90b960Srenato 				fnh->remote_label = NO_LABEL;
1208ed90b960Srenato 			} else {
1209ed90b960Srenato 				me = (struct lde_map *)fec;
1210ed90b960Srenato 				fnh->remote_label = me->map.label;
1211ed90b960Srenato 				lde_send_change_klabel(fn, fnh);
1212ed90b960Srenato 			}
1213ed90b960Srenato 			break;
1214ed90b960Srenato 		}
1215ed90b960Srenato 	}
1216ed90b960Srenato }
1217ed90b960Srenato 
1218a094a533Sclaudio struct lde_map *
12196106bae4Srenato lde_map_add(struct lde_nbr *ln, struct fec_node *fn, int sent)
1220a094a533Sclaudio {
1221a094a533Sclaudio 	struct lde_map  *me;
1222a094a533Sclaudio 
1223a094a533Sclaudio 	me = calloc(1, sizeof(*me));
1224a094a533Sclaudio 	if (me == NULL)
1225b7b4db73Srenato 		fatal(__func__);
1226a094a533Sclaudio 
12276106bae4Srenato 	me->fec = fn->fec;
1228a094a533Sclaudio 	me->nexthop = ln;
1229a094a533Sclaudio 
1230a094a533Sclaudio 	if (sent) {
12316106bae4Srenato 		LIST_INSERT_HEAD(&fn->upstream, me, entry);
1232a094a533Sclaudio 		if (fec_insert(&ln->sent_map, &me->fec))
12336399cec1Srenato 			log_warnx("failed to add %s to sent map",
12346399cec1Srenato 			    log_fec(&me->fec));
1235fb298019Sclaudio 			/* XXX on failure more cleanup is needed */
1236a094a533Sclaudio 	} else {
12376106bae4Srenato 		LIST_INSERT_HEAD(&fn->downstream, me, entry);
1238a094a533Sclaudio 		if (fec_insert(&ln->recv_map, &me->fec))
12396399cec1Srenato 			log_warnx("failed to add %s to recv map",
12406399cec1Srenato 			    log_fec(&me->fec));
1241a094a533Sclaudio 	}
1242a094a533Sclaudio 
1243a094a533Sclaudio 	return (me);
1244a094a533Sclaudio }
1245a094a533Sclaudio 
1246e3948831Sclaudio void
1247510d51a3Sclaudio lde_map_del(struct lde_nbr *ln, struct lde_map *me, int sent)
1248510d51a3Sclaudio {
1249510d51a3Sclaudio 	if (sent)
1250510d51a3Sclaudio 		fec_remove(&ln->sent_map, &me->fec);
1251510d51a3Sclaudio 	else
1252510d51a3Sclaudio 		fec_remove(&ln->recv_map, &me->fec);
1253510d51a3Sclaudio 
1254510d51a3Sclaudio 	lde_map_free(me);
1255510d51a3Sclaudio }
1256510d51a3Sclaudio 
1257c28a25a1Srenato static void
1258e3948831Sclaudio lde_map_free(void *ptr)
1259e3948831Sclaudio {
1260e3948831Sclaudio 	struct lde_map	*map = ptr;
1261e3948831Sclaudio 
1262e3948831Sclaudio 	LIST_REMOVE(map, entry);
1263e3948831Sclaudio 	free(map);
1264e3948831Sclaudio }
1265e3948831Sclaudio 
1266fb298019Sclaudio struct lde_req *
1267fb298019Sclaudio lde_req_add(struct lde_nbr *ln, struct fec *fec, int sent)
1268fb298019Sclaudio {
12696106bae4Srenato 	struct fec_tree	*t;
1270fb298019Sclaudio 	struct lde_req	*lre;
1271fb298019Sclaudio 
12726106bae4Srenato 	t = sent ? &ln->sent_req : &ln->recv_req;
1273fb298019Sclaudio 
1274fb298019Sclaudio 	lre = calloc(1, sizeof(*lre));
1275fb298019Sclaudio 	if (lre != NULL) {
1276fb298019Sclaudio 		lre->fec = *fec;
1277fb298019Sclaudio 
12786106bae4Srenato 		if (fec_insert(t, &lre->fec)) {
1279a8e25944Sbenno 			log_warnx("failed to add %s to %s req",
12806399cec1Srenato 			    log_fec(&lre->fec), sent ? "sent" : "recv");
1281fb298019Sclaudio 			free(lre);
1282fb298019Sclaudio 			return (NULL);
1283fb298019Sclaudio 		}
1284fb298019Sclaudio 	}
1285fb298019Sclaudio 
1286fb298019Sclaudio 	return (lre);
1287fb298019Sclaudio }
1288fb298019Sclaudio 
1289fb298019Sclaudio void
1290fb298019Sclaudio lde_req_del(struct lde_nbr *ln, struct lde_req *lre, int sent)
1291fb298019Sclaudio {
1292fb298019Sclaudio 	if (sent)
1293fb298019Sclaudio 		fec_remove(&ln->sent_req, &lre->fec);
1294fb298019Sclaudio 	else
1295fb298019Sclaudio 		fec_remove(&ln->recv_req, &lre->fec);
1296fb298019Sclaudio 
1297fb298019Sclaudio 	free(lre);
1298fb298019Sclaudio }
1299fb298019Sclaudio 
1300cf483f25Srenato struct lde_wdraw *
13016106bae4Srenato lde_wdraw_add(struct lde_nbr *ln, struct fec_node *fn)
1302cf483f25Srenato {
1303cf483f25Srenato 	struct lde_wdraw  *lw;
1304cf483f25Srenato 
1305cf483f25Srenato 	lw = calloc(1, sizeof(*lw));
1306cf483f25Srenato 	if (lw == NULL)
1307b7b4db73Srenato 		fatal(__func__);
1308cf483f25Srenato 
13096106bae4Srenato 	lw->fec = fn->fec;
1310cf483f25Srenato 
1311cf483f25Srenato 	if (fec_insert(&ln->sent_wdraw, &lw->fec))
13126399cec1Srenato 		log_warnx("failed to add %s to sent wdraw",
13136399cec1Srenato 		    log_fec(&lw->fec));
1314cf483f25Srenato 
1315cf483f25Srenato 	return (lw);
1316cf483f25Srenato }
1317cf483f25Srenato 
1318cf483f25Srenato void
1319cf483f25Srenato lde_wdraw_del(struct lde_nbr *ln, struct lde_wdraw *lw)
1320cf483f25Srenato {
1321cf483f25Srenato 	fec_remove(&ln->sent_wdraw, &lw->fec);
1322cf483f25Srenato 	free(lw);
1323cf483f25Srenato }
1324cf483f25Srenato 
132533f6ccfeSrenato void
1326a8c39dc0Srenato lde_change_egress_label(int af, int was_implicit)
132733f6ccfeSrenato {
132833f6ccfeSrenato 	struct lde_nbr	*ln;
132933f6ccfeSrenato 	struct fec	*f;
133033f6ccfeSrenato 	struct fec_node	*fn;
133133f6ccfeSrenato 
1332a8c39dc0Srenato 	RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
133333f6ccfeSrenato 		/* explicit withdraw */
133433f6ccfeSrenato 		if (was_implicit)
13352c06fdf4Srenato 			lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLNULL);
1336a8c39dc0Srenato 		else {
1337a8c39dc0Srenato 			if (ln->v4_enabled)
13382c06fdf4Srenato 				lde_send_labelwithdraw_wcard(ln,
13392c06fdf4Srenato 				    MPLS_LABEL_IPV4NULL);
1340a8c39dc0Srenato 			if (ln->v6_enabled)
13412c06fdf4Srenato 				lde_send_labelwithdraw_wcard(ln,
13422c06fdf4Srenato 				    MPLS_LABEL_IPV6NULL);
1343a8c39dc0Srenato 		}
134433f6ccfeSrenato 
1345a8c39dc0Srenato 		/* advertise new label of connected prefixes */
134633f6ccfeSrenato 		RB_FOREACH(f, fec_tree, &ft) {
134733f6ccfeSrenato 			fn = (struct fec_node *)f;
134833f6ccfeSrenato 			if (fn->local_label > MPLS_LABEL_RESERVED_MAX)
134933f6ccfeSrenato 				continue;
135033f6ccfeSrenato 
1351a8c39dc0Srenato 			switch (af) {
1352a8c39dc0Srenato 			case AF_INET:
1353a8c39dc0Srenato 				if (fn->fec.type != FEC_TYPE_IPV4)
1354a8c39dc0Srenato 					continue;
1355a8c39dc0Srenato 				break;
1356a8c39dc0Srenato 			case AF_INET6:
1357a8c39dc0Srenato 				if (fn->fec.type != FEC_TYPE_IPV6)
1358a8c39dc0Srenato 					continue;
1359a8c39dc0Srenato 				break;
1360a8c39dc0Srenato 			default:
1361a8c39dc0Srenato 				fatalx("lde_change_egress_label: unknown af");
1362a8c39dc0Srenato 			}
1363a8c39dc0Srenato 
136433f6ccfeSrenato 			fn->local_label = egress_label(fn->fec.type);
136533f6ccfeSrenato 			lde_send_labelmapping(ln, fn, 0);
136633f6ccfeSrenato 		}
136734f55a3fSrenato 
136834f55a3fSrenato 		lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0,
136934f55a3fSrenato 		    NULL, 0);
137033f6ccfeSrenato 	}
137133f6ccfeSrenato }
137233f6ccfeSrenato 
1373c28a25a1Srenato static int
1374a8c39dc0Srenato lde_address_add(struct lde_nbr *ln, struct lde_addr *lde_addr)
1375ab0c2486Smichele {
137619fce358Srenato 	struct lde_addr		*new;
1377ab0c2486Smichele 
1378a8c39dc0Srenato 	if (lde_address_find(ln, lde_addr->af, &lde_addr->addr) != NULL)
1379ab0c2486Smichele 		return (-1);
1380ab0c2486Smichele 
138119fce358Srenato 	if ((new = calloc(1, sizeof(*new))) == NULL)
1382b7b4db73Srenato 		fatal(__func__);
1383ab0c2486Smichele 
1384a8c39dc0Srenato 	new->af = lde_addr->af;
1385a8c39dc0Srenato 	new->addr = lde_addr->addr;
138619fce358Srenato 	TAILQ_INSERT_TAIL(&ln->addr_list, new, entry);
1387ab0c2486Smichele 
1388ed90b960Srenato 	/* reevaluate the previously received mappings from this neighbor */
1389ed90b960Srenato 	lde_nbr_addr_update(ln, lde_addr, 0);
1390ed90b960Srenato 
1391ab0c2486Smichele 	return (0);
1392ab0c2486Smichele }
1393ab0c2486Smichele 
1394c28a25a1Srenato static int
1395a8c39dc0Srenato lde_address_del(struct lde_nbr *ln, struct lde_addr *lde_addr)
1396ab0c2486Smichele {
1397a8c39dc0Srenato 	lde_addr = lde_address_find(ln, lde_addr->af, &lde_addr->addr);
139819fce358Srenato 	if (lde_addr == NULL)
1399ab0c2486Smichele 		return (-1);
1400ab0c2486Smichele 
1401ed90b960Srenato 	/* reevaluate the previously received mappings from this neighbor */
1402ed90b960Srenato 	lde_nbr_addr_update(ln, lde_addr, 1);
1403ed90b960Srenato 
140419fce358Srenato 	TAILQ_REMOVE(&ln->addr_list, lde_addr, entry);
140519fce358Srenato 	free(lde_addr);
1406ab0c2486Smichele 
1407ab0c2486Smichele 	return (0);
1408ab0c2486Smichele }
1409ab0c2486Smichele 
14102d825b92Srenato struct lde_addr *
1411a8c39dc0Srenato lde_address_find(struct lde_nbr *ln, int af, union ldpd_addr *addr)
141233f6ccfeSrenato {
141319fce358Srenato 	struct lde_addr		*lde_addr;
141433f6ccfeSrenato 
141519fce358Srenato 	TAILQ_FOREACH(lde_addr, &ln->addr_list, entry)
1416a8c39dc0Srenato 		if (lde_addr->af == af &&
1417a8c39dc0Srenato 		    ldp_addrcmp(af, &lde_addr->addr, addr) == 0)
141819fce358Srenato 			return (lde_addr);
141933f6ccfeSrenato 
142033f6ccfeSrenato 	return (NULL);
142133f6ccfeSrenato }
142233f6ccfeSrenato 
1423c28a25a1Srenato static void
14242d825b92Srenato lde_address_list_free(struct lde_nbr *ln)
1425ab0c2486Smichele {
142619fce358Srenato 	struct lde_addr		*lde_addr;
1427ab0c2486Smichele 
142819fce358Srenato 	while ((lde_addr = TAILQ_FIRST(&ln->addr_list)) != NULL) {
142919fce358Srenato 		TAILQ_REMOVE(&ln->addr_list, lde_addr, entry);
143019fce358Srenato 		free(lde_addr);
1431ab0c2486Smichele 	}
1432ab0c2486Smichele }
1433