]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/lde.c
ldpd: adapt the code for Quagga
[mirror_frr.git] / ldpd / lde.c
CommitLineData
8429abe0
RW
1/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
eac6e3f0 22#include <zebra.h>
8429abe0
RW
23
24#include "ldp.h"
25#include "ldpd.h"
26#include "ldpe.h"
27#include "log.h"
28#include "lde.h"
eac6e3f0 29#include "ldp_debug.h"
8429abe0 30
eac6e3f0
RW
31#include <lib/log.h>
32#include "memory.h"
33#include "privs.h"
34#include "sigevent.h"
35#include "mpls.h"
36
37static void lde_shutdown(void);
38static int lde_dispatch_imsg(struct thread *);
39static int lde_dispatch_parent(struct thread *);
8429abe0
RW
40static __inline int lde_nbr_compare(struct lde_nbr *,
41 struct lde_nbr *);
42static struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *);
43static void lde_nbr_del(struct lde_nbr *);
44static struct lde_nbr *lde_nbr_find(uint32_t);
45static void lde_nbr_clear(void);
46static void lde_nbr_addr_update(struct lde_nbr *,
47 struct lde_addr *, int);
48static void lde_map_free(void *);
49static int lde_address_add(struct lde_nbr *, struct lde_addr *);
50static int lde_address_del(struct lde_nbr *, struct lde_addr *);
51static void lde_address_list_free(struct lde_nbr *);
52
53RB_GENERATE(nbr_tree, lde_nbr, entry, lde_nbr_compare)
54
55struct ldpd_conf *ldeconf;
56struct nbr_tree lde_nbrs = RB_INITIALIZER(&lde_nbrs);
57
58static struct imsgev *iev_ldpe;
59static struct imsgev *iev_main;
60
eac6e3f0
RW
61/* Master of threads. */
62struct thread_master *master;
63
64/* lde privileges */
65static zebra_capabilities_t _caps_p [] =
8429abe0 66{
eac6e3f0
RW
67 /* none */
68};
8429abe0 69
eac6e3f0
RW
70static struct zebra_privs_t lde_privs =
71{
72#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP)
73 .user = QUAGGA_USER,
74 .group = QUAGGA_GROUP,
75#endif
76#if defined(VTY_GROUP)
77 .vty_group = VTY_GROUP,
78#endif
79 .caps_p = _caps_p,
80 .cap_num_p = array_size(_caps_p),
81 .cap_num_i = 0
82};
83
84/* SIGINT / SIGTERM handler. */
85static void
86sigint(void)
87{
88 lde_shutdown();
8429abe0
RW
89}
90
eac6e3f0
RW
91static struct quagga_signal_t lde_signals[] =
92{
93 {
94 .signal = SIGINT,
95 .handler = &sigint,
96 },
97 {
98 .signal = SIGTERM,
99 .handler = &sigint,
100 },
101};
102
8429abe0
RW
103/* label decision engine */
104void
eac6e3f0 105lde(const char *user, const char *group)
8429abe0 106{
eac6e3f0 107 struct thread thread;
8429abe0 108 struct timeval now;
8429abe0
RW
109
110 ldeconf = config_new_empty();
111
eac6e3f0 112#ifdef HAVE_SETPROCTITLE
8429abe0 113 setproctitle("label decision engine");
eac6e3f0 114#endif
8429abe0
RW
115 ldpd_process = PROC_LDE_ENGINE;
116
eac6e3f0
RW
117 /* drop privileges */
118 if (user)
119 lde_privs.user = user;
120 if (group)
121 lde_privs.group = group;
122 zprivs_init(&lde_privs);
8429abe0 123
eac6e3f0 124#ifdef HAVE_PLEDGE
8429abe0
RW
125 if (pledge("stdio recvfd", NULL) == -1)
126 fatal("pledge");
eac6e3f0 127#endif
8429abe0 128
eac6e3f0 129 master = thread_master_create();
8429abe0
RW
130
131 /* setup signal handler */
eac6e3f0 132 signal_init(master, array_size(lde_signals), lde_signals);
8429abe0
RW
133
134 /* setup pipe and event handler to the parent process */
135 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
136 fatal(NULL);
137 imsg_init(&iev_main->ibuf, 3);
eac6e3f0
RW
138 iev_main->handler_read = lde_dispatch_parent;
139 iev_main->ev_read = thread_add_read(master, iev_main->handler_read,
140 iev_main, iev_main->ibuf.fd);
141 iev_main->handler_write = ldp_write_handler;
142 iev_main->ev_write = NULL;
143
144 /* start the LIB garbage collector */
8429abe0
RW
145 lde_gc_start_timer();
146
147 gettimeofday(&now, NULL);
148 global.uptime = now.tv_sec;
149
eac6e3f0
RW
150 /* Fetch next active thread. */
151 while (thread_fetch(master, &thread))
152 thread_call(&thread);
8429abe0
RW
153}
154
eac6e3f0 155static void
8429abe0
RW
156lde_shutdown(void)
157{
158 /* close pipes */
159 msgbuf_clear(&iev_ldpe->ibuf.w);
160 close(iev_ldpe->ibuf.fd);
161 msgbuf_clear(&iev_main->ibuf.w);
162 close(iev_main->ibuf.fd);
163
164 lde_gc_stop_timer();
165 lde_nbr_clear();
166 fec_tree_clear();
167
168 config_clear(ldeconf);
169
170 free(iev_ldpe);
171 free(iev_main);
172
173 log_info("label decision engine exiting");
174 exit(0);
175}
176
177/* imesg */
eac6e3f0 178int
8429abe0
RW
179lde_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
180{
181 return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
182}
183
184int
185lde_imsg_compose_ldpe(int type, uint32_t peerid, pid_t pid, void *data,
186 uint16_t datalen)
187{
188 return (imsg_compose_event(iev_ldpe, type, peerid, pid,
189 -1, data, datalen));
190}
191
192/* ARGSUSED */
eac6e3f0
RW
193static int
194lde_dispatch_imsg(struct thread *thread)
8429abe0 195{
eac6e3f0 196 struct imsgev *iev = THREAD_ARG(thread);
8429abe0
RW
197 struct imsgbuf *ibuf = &iev->ibuf;
198 struct imsg imsg;
199 struct lde_nbr *ln;
200 struct map map;
201 struct lde_addr lde_addr;
202 struct notify_msg nm;
203 ssize_t n;
eac6e3f0 204 int shut = 0;
8429abe0 205
eac6e3f0
RW
206 iev->ev_read = NULL;
207
208 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
209 fatal("imsg_read error");
210 if (n == 0) /* connection closed */
211 shut = 1;
8429abe0
RW
212
213 for (;;) {
214 if ((n = imsg_get(ibuf, &imsg)) == -1)
215 fatal("lde_dispatch_imsg: imsg_get error");
216 if (n == 0)
217 break;
218
219 switch (imsg.hdr.type) {
220 case IMSG_LABEL_MAPPING_FULL:
221 ln = lde_nbr_find(imsg.hdr.peerid);
222 if (ln == NULL) {
223 log_debug("%s: cannot find lde neighbor",
224 __func__);
225 break;
226 }
227
228 fec_snap(ln);
229 break;
230 case IMSG_LABEL_MAPPING:
231 case IMSG_LABEL_REQUEST:
232 case IMSG_LABEL_RELEASE:
233 case IMSG_LABEL_WITHDRAW:
234 case IMSG_LABEL_ABORT:
235 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map))
236 fatalx("lde_dispatch_imsg: wrong imsg len");
237 memcpy(&map, imsg.data, sizeof(map));
238
239 ln = lde_nbr_find(imsg.hdr.peerid);
240 if (ln == NULL) {
241 log_debug("%s: cannot find lde neighbor",
242 __func__);
243 break;
244 }
245
246 switch (imsg.hdr.type) {
247 case IMSG_LABEL_MAPPING:
248 lde_check_mapping(&map, ln);
249 break;
250 case IMSG_LABEL_REQUEST:
251 lde_check_request(&map, ln);
252 break;
253 case IMSG_LABEL_RELEASE:
254 if (map.type == MAP_TYPE_WILDCARD)
255 lde_check_release_wcard(&map, ln);
256 else
257 lde_check_release(&map, ln);
258 break;
259 case IMSG_LABEL_WITHDRAW:
260 if (map.type == MAP_TYPE_WILDCARD)
261 lde_check_withdraw_wcard(&map, ln);
262 else
263 lde_check_withdraw(&map, ln);
264 break;
265 case IMSG_LABEL_ABORT:
266 /* not necessary */
267 break;
268 }
269 break;
270 case IMSG_ADDRESS_ADD:
271 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
272 fatalx("lde_dispatch_imsg: wrong imsg len");
273 memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
274
275 ln = lde_nbr_find(imsg.hdr.peerid);
276 if (ln == NULL) {
277 log_debug("%s: cannot find lde neighbor",
278 __func__);
279 break;
280 }
281 if (lde_address_add(ln, &lde_addr) < 0) {
282 log_debug("%s: cannot add address %s, it "
283 "already exists", __func__,
284 log_addr(lde_addr.af, &lde_addr.addr));
285 }
286 break;
287 case IMSG_ADDRESS_DEL:
288 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
289 fatalx("lde_dispatch_imsg: wrong imsg len");
290 memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
291
292 ln = lde_nbr_find(imsg.hdr.peerid);
293 if (ln == NULL) {
294 log_debug("%s: cannot find lde neighbor",
295 __func__);
296 break;
297 }
298 if (lde_address_del(ln, &lde_addr) < 0) {
299 log_debug("%s: cannot delete address %s, it "
300 "does not exist", __func__,
301 log_addr(lde_addr.af, &lde_addr.addr));
302 }
303 break;
304 case IMSG_NOTIFICATION:
305 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
306 fatalx("lde_dispatch_imsg: wrong imsg len");
307 memcpy(&nm, imsg.data, sizeof(nm));
308
309 ln = lde_nbr_find(imsg.hdr.peerid);
310 if (ln == NULL) {
311 log_debug("%s: cannot find lde neighbor",
312 __func__);
313 break;
314 }
315
316 switch (nm.status_code) {
317 case S_PW_STATUS:
318 l2vpn_recv_pw_status(ln, &nm);
319 break;
320 default:
321 break;
322 }
323 break;
324 case IMSG_NEIGHBOR_UP:
325 if (imsg.hdr.len - IMSG_HEADER_SIZE !=
326 sizeof(struct lde_nbr))
327 fatalx("lde_dispatch_imsg: wrong imsg len");
328
329 if (lde_nbr_find(imsg.hdr.peerid))
330 fatalx("lde_dispatch_imsg: "
331 "neighbor already exists");
332 lde_nbr_new(imsg.hdr.peerid, imsg.data);
333 break;
334 case IMSG_NEIGHBOR_DOWN:
335 lde_nbr_del(lde_nbr_find(imsg.hdr.peerid));
336 break;
337 case IMSG_CTL_SHOW_LIB:
338 rt_dump(imsg.hdr.pid);
339
340 lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
341 imsg.hdr.pid, NULL, 0);
342 break;
343 case IMSG_CTL_SHOW_L2VPN_PW:
344 l2vpn_pw_ctl(imsg.hdr.pid);
345
346 lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
347 imsg.hdr.pid, NULL, 0);
348 break;
349 case IMSG_CTL_SHOW_L2VPN_BINDING:
350 l2vpn_binding_ctl(imsg.hdr.pid);
351
352 lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
353 imsg.hdr.pid, NULL, 0);
354 break;
8429abe0
RW
355 default:
356 log_debug("%s: unexpected imsg %d", __func__,
357 imsg.hdr.type);
358 break;
359 }
360 imsg_free(&imsg);
361 }
362 if (!shut)
363 imsg_event_add(iev);
364 else {
eac6e3f0
RW
365 /* this pipe is dead, so remove the event handlers and exit */
366 THREAD_READ_OFF(iev->ev_read);
367 THREAD_WRITE_OFF(iev->ev_write);
368 lde_shutdown();
8429abe0 369 }
eac6e3f0
RW
370
371 return (0);
8429abe0
RW
372}
373
374/* ARGSUSED */
eac6e3f0
RW
375static int
376lde_dispatch_parent(struct thread *thread)
8429abe0
RW
377{
378 static struct ldpd_conf *nconf;
379 struct iface *niface;
380 struct tnbr *ntnbr;
381 struct nbr_params *nnbrp;
382 static struct l2vpn *nl2vpn;
383 struct l2vpn_if *nlif;
384 struct l2vpn_pw *npw;
385 struct imsg imsg;
386 struct kroute kr;
eac6e3f0
RW
387 int fd = THREAD_FD(thread);
388 struct imsgev *iev = THREAD_ARG(thread);
8429abe0
RW
389 struct imsgbuf *ibuf = &iev->ibuf;
390 ssize_t n;
391 int shut = 0;
392 struct fec fec;
393
eac6e3f0
RW
394 iev->ev_read = NULL;
395
396 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
397 fatal("imsg_read error");
398 if (n == 0) /* connection closed */
399 shut = 1;
8429abe0
RW
400
401 for (;;) {
402 if ((n = imsg_get(ibuf, &imsg)) == -1)
403 fatal("lde_dispatch_parent: imsg_get error");
404 if (n == 0)
405 break;
406
407 switch (imsg.hdr.type) {
408 case IMSG_NETWORK_ADD:
409 case IMSG_NETWORK_DEL:
410 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
411 log_warnx("%s: wrong imsg len", __func__);
412 break;
413 }
414 memcpy(&kr, imsg.data, sizeof(kr));
415
416 switch (kr.af) {
417 case AF_INET:
418 fec.type = FEC_TYPE_IPV4;
419 fec.u.ipv4.prefix = kr.prefix.v4;
420 fec.u.ipv4.prefixlen = kr.prefixlen;
421 break;
422 case AF_INET6:
423 fec.type = FEC_TYPE_IPV6;
424 fec.u.ipv6.prefix = kr.prefix.v6;
425 fec.u.ipv6.prefixlen = kr.prefixlen;
426 break;
427 default:
428 fatalx("lde_dispatch_parent: unknown af");
429 }
430
431 switch (imsg.hdr.type) {
432 case IMSG_NETWORK_ADD:
433 lde_kernel_insert(&fec, kr.af, &kr.nexthop,
434 kr.priority, kr.flags & F_CONNECTED, NULL);
435 break;
436 case IMSG_NETWORK_DEL:
437 lde_kernel_remove(&fec, kr.af, &kr.nexthop,
438 kr.priority);
439 break;
440 }
441 break;
442 case IMSG_SOCKET_IPC:
443 if (iev_ldpe) {
444 log_warnx("%s: received unexpected imsg fd "
445 "to ldpe", __func__);
446 break;
447 }
448 if ((fd = imsg.fd) == -1) {
449 log_warnx("%s: expected to receive imsg fd to "
450 "ldpe but didn't receive any", __func__);
451 break;
452 }
453
454 if ((iev_ldpe = malloc(sizeof(struct imsgev))) == NULL)
455 fatal(NULL);
456 imsg_init(&iev_ldpe->ibuf, fd);
eac6e3f0
RW
457 iev_ldpe->handler_read = lde_dispatch_imsg;
458 iev_ldpe->ev_read = thread_add_read(master,
459 iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd);
460 iev_ldpe->handler_write = ldp_write_handler;
461 iev_ldpe->ev_write = NULL;
8429abe0
RW
462 break;
463 case IMSG_RECONF_CONF:
464 if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
465 NULL)
466 fatal(NULL);
467 memcpy(nconf, imsg.data, sizeof(struct ldpd_conf));
468
469 LIST_INIT(&nconf->iface_list);
470 LIST_INIT(&nconf->tnbr_list);
471 LIST_INIT(&nconf->nbrp_list);
472 LIST_INIT(&nconf->l2vpn_list);
473 break;
474 case IMSG_RECONF_IFACE:
475 if ((niface = malloc(sizeof(struct iface))) == NULL)
476 fatal(NULL);
477 memcpy(niface, imsg.data, sizeof(struct iface));
478
479 LIST_INIT(&niface->addr_list);
480 LIST_INIT(&niface->ipv4.adj_list);
481 LIST_INIT(&niface->ipv6.adj_list);
482 niface->ipv4.iface = niface;
483 niface->ipv6.iface = niface;
484
485 LIST_INSERT_HEAD(&nconf->iface_list, niface, entry);
486 break;
487 case IMSG_RECONF_TNBR:
488 if ((ntnbr = malloc(sizeof(struct tnbr))) == NULL)
489 fatal(NULL);
490 memcpy(ntnbr, imsg.data, sizeof(struct tnbr));
491
492 LIST_INSERT_HEAD(&nconf->tnbr_list, ntnbr, entry);
493 break;
494 case IMSG_RECONF_NBRP:
495 if ((nnbrp = malloc(sizeof(struct nbr_params))) == NULL)
496 fatal(NULL);
497 memcpy(nnbrp, imsg.data, sizeof(struct nbr_params));
498
499 LIST_INSERT_HEAD(&nconf->nbrp_list, nnbrp, entry);
500 break;
501 case IMSG_RECONF_L2VPN:
502 if ((nl2vpn = malloc(sizeof(struct l2vpn))) == NULL)
503 fatal(NULL);
504 memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
505
506 LIST_INIT(&nl2vpn->if_list);
507 LIST_INIT(&nl2vpn->pw_list);
eac6e3f0 508 LIST_INIT(&nl2vpn->pw_inactive_list);
8429abe0
RW
509
510 LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);
511 break;
512 case IMSG_RECONF_L2VPN_IF:
513 if ((nlif = malloc(sizeof(struct l2vpn_if))) == NULL)
514 fatal(NULL);
515 memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
516
517 nlif->l2vpn = nl2vpn;
518 LIST_INSERT_HEAD(&nl2vpn->if_list, nlif, entry);
519 break;
520 case IMSG_RECONF_L2VPN_PW:
521 if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
522 fatal(NULL);
523 memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
524
525 npw->l2vpn = nl2vpn;
526 LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry);
527 break;
eac6e3f0
RW
528 case IMSG_RECONF_L2VPN_IPW:
529 if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
530 fatal(NULL);
531 memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
532
533 npw->l2vpn = nl2vpn;
534 LIST_INSERT_HEAD(&nl2vpn->pw_inactive_list, npw, entry);
535 break;
8429abe0
RW
536 case IMSG_RECONF_END:
537 merge_config(ldeconf, nconf);
538 nconf = NULL;
539 break;
eac6e3f0
RW
540 case IMSG_DEBUG_UPDATE:
541 if (imsg.hdr.len != IMSG_HEADER_SIZE +
542 sizeof(ldp_debug)) {
543 log_warnx("%s: wrong imsg len", __func__);
544 break;
545 }
546 memcpy(&ldp_debug, imsg.data, sizeof(ldp_debug));
547 break;
8429abe0
RW
548 default:
549 log_debug("%s: unexpected imsg %d", __func__,
550 imsg.hdr.type);
551 break;
552 }
553 imsg_free(&imsg);
554 }
555 if (!shut)
556 imsg_event_add(iev);
557 else {
eac6e3f0
RW
558 /* this pipe is dead, so remove the event handlers and exit */
559 THREAD_READ_OFF(iev->ev_read);
560 THREAD_WRITE_OFF(iev->ev_write);
561 lde_shutdown();
8429abe0 562 }
eac6e3f0
RW
563
564 return (0);
8429abe0
RW
565}
566
567uint32_t
568lde_assign_label(void)
569{
570 static uint32_t label = MPLS_LABEL_RESERVED_MAX;
571
eac6e3f0
RW
572 /*
573 * TODO: request label to zebra or define a range of labels for ldpd.
574 */
575
8429abe0
RW
576 label++;
577 return (label);
578}
579
580void
581lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
582{
583 struct kroute kr;
584 struct kpw kpw;
585 struct l2vpn_pw *pw;
586
587 switch (fn->fec.type) {
588 case FEC_TYPE_IPV4:
589 memset(&kr, 0, sizeof(kr));
590 kr.af = AF_INET;
591 kr.prefix.v4 = fn->fec.u.ipv4.prefix;
592 kr.prefixlen = fn->fec.u.ipv4.prefixlen;
593 kr.nexthop.v4 = fnh->nexthop.v4;
594 kr.local_label = fn->local_label;
595 kr.remote_label = fnh->remote_label;
596 kr.priority = fnh->priority;
597
598 lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
599 sizeof(kr));
600
601 if (fn->fec.u.ipv4.prefixlen == 32)
602 l2vpn_sync_pws(AF_INET, (union ldpd_addr *)
603 &fn->fec.u.ipv4.prefix);
604 break;
605 case FEC_TYPE_IPV6:
606 memset(&kr, 0, sizeof(kr));
607 kr.af = AF_INET6;
608 kr.prefix.v6 = fn->fec.u.ipv6.prefix;
609 kr.prefixlen = fn->fec.u.ipv6.prefixlen;
610 kr.nexthop.v6 = fnh->nexthop.v6;
611 kr.local_label = fn->local_label;
612 kr.remote_label = fnh->remote_label;
613 kr.priority = fnh->priority;
614
615 lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
616 sizeof(kr));
617
618 if (fn->fec.u.ipv6.prefixlen == 128)
619 l2vpn_sync_pws(AF_INET6, (union ldpd_addr *)
620 &fn->fec.u.ipv6.prefix);
621 break;
622 case FEC_TYPE_PWID:
623 if (fn->local_label == NO_LABEL ||
624 fnh->remote_label == NO_LABEL)
625 return;
626
627 pw = (struct l2vpn_pw *) fn->data;
628 pw->flags |= F_PW_STATUS_UP;
629
630 memset(&kpw, 0, sizeof(kpw));
631 kpw.ifindex = pw->ifindex;
632 kpw.pw_type = fn->fec.u.pwid.type;
633 kpw.af = pw->af;
634 kpw.nexthop = pw->addr;
635 kpw.local_label = fn->local_label;
636 kpw.remote_label = fnh->remote_label;
637 kpw.flags = pw->flags;
638
639 lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw,
640 sizeof(kpw));
641 break;
642 }
643}
644
645void
646lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
647{
648 struct kroute kr;
649 struct kpw kpw;
650 struct l2vpn_pw *pw;
651
652 switch (fn->fec.type) {
653 case FEC_TYPE_IPV4:
654 memset(&kr, 0, sizeof(kr));
655 kr.af = AF_INET;
656 kr.prefix.v4 = fn->fec.u.ipv4.prefix;
657 kr.prefixlen = fn->fec.u.ipv4.prefixlen;
658 kr.nexthop.v4 = fnh->nexthop.v4;
659 kr.local_label = fn->local_label;
660 kr.remote_label = fnh->remote_label;
661 kr.priority = fnh->priority;
662
663 lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
664 sizeof(kr));
665
666 if (fn->fec.u.ipv4.prefixlen == 32)
667 l2vpn_sync_pws(AF_INET, (union ldpd_addr *)
668 &fn->fec.u.ipv4.prefix);
669 break;
670 case FEC_TYPE_IPV6:
671 memset(&kr, 0, sizeof(kr));
672 kr.af = AF_INET6;
673 kr.prefix.v6 = fn->fec.u.ipv6.prefix;
674 kr.prefixlen = fn->fec.u.ipv6.prefixlen;
675 kr.nexthop.v6 = fnh->nexthop.v6;
676 kr.local_label = fn->local_label;
677 kr.remote_label = fnh->remote_label;
678 kr.priority = fnh->priority;
679
680 lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
681 sizeof(kr));
682
683 if (fn->fec.u.ipv6.prefixlen == 128)
684 l2vpn_sync_pws(AF_INET6, (union ldpd_addr *)
685 &fn->fec.u.ipv6.prefix);
686 break;
687 case FEC_TYPE_PWID:
688 pw = (struct l2vpn_pw *) fn->data;
689 if (!(pw->flags & F_PW_STATUS_UP))
690 return;
691 pw->flags &= ~F_PW_STATUS_UP;
692
693 memset(&kpw, 0, sizeof(kpw));
694 kpw.ifindex = pw->ifindex;
695 kpw.pw_type = fn->fec.u.pwid.type;
696 kpw.af = pw->af;
697 kpw.nexthop = pw->addr;
698 kpw.local_label = fn->local_label;
699 kpw.remote_label = fnh->remote_label;
700 kpw.flags = pw->flags;
701
702 lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw,
703 sizeof(kpw));
704 break;
705 }
706}
707
708void
709lde_fec2map(struct fec *fec, struct map *map)
710{
711 memset(map, 0, sizeof(*map));
712
713 switch (fec->type) {
714 case FEC_TYPE_IPV4:
715 map->type = MAP_TYPE_PREFIX;
716 map->fec.prefix.af = AF_INET;
717 map->fec.prefix.prefix.v4 = fec->u.ipv4.prefix;
718 map->fec.prefix.prefixlen = fec->u.ipv4.prefixlen;
719 break;
720 case FEC_TYPE_IPV6:
721 map->type = MAP_TYPE_PREFIX;
722 map->fec.prefix.af = AF_INET6;
723 map->fec.prefix.prefix.v6 = fec->u.ipv6.prefix;
724 map->fec.prefix.prefixlen = fec->u.ipv6.prefixlen;
725 break;
726 case FEC_TYPE_PWID:
727 map->type = MAP_TYPE_PWID;
728 map->fec.pwid.type = fec->u.pwid.type;
729 map->fec.pwid.group_id = 0;
730 map->flags |= F_MAP_PW_ID;
731 map->fec.pwid.pwid = fec->u.pwid.pwid;
732 break;
733 }
734}
735
736void
737lde_map2fec(struct map *map, struct in_addr lsr_id, struct fec *fec)
738{
739 memset(fec, 0, sizeof(*fec));
740
741 switch (map->type) {
742 case MAP_TYPE_PREFIX:
743 switch (map->fec.prefix.af) {
744 case AF_INET:
745 fec->type = FEC_TYPE_IPV4;
746 fec->u.ipv4.prefix = map->fec.prefix.prefix.v4;
747 fec->u.ipv4.prefixlen = map->fec.prefix.prefixlen;
748 break;
749 case AF_INET6:
750 fec->type = FEC_TYPE_IPV6;
751 fec->u.ipv6.prefix = map->fec.prefix.prefix.v6;
752 fec->u.ipv6.prefixlen = map->fec.prefix.prefixlen;
753 break;
754 default:
755 fatalx("lde_map2fec: unknown af");
756 break;
757 }
758 break;
759 case MAP_TYPE_PWID:
760 fec->type = FEC_TYPE_PWID;
761 fec->u.pwid.type = map->fec.pwid.type;
762 fec->u.pwid.pwid = map->fec.pwid.pwid;
763 fec->u.pwid.lsr_id = lsr_id;
764 break;
765 }
766}
767
768void
769lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
770{
771 struct lde_req *lre;
772 struct lde_map *me;
773 struct map map;
774 struct l2vpn_pw *pw;
775
776 /*
777 * This function skips SL.1 - 3 and SL.9 - 14 because the label
778 * allocation is done way earlier (because of the merging nature of
779 * ldpd).
780 */
781
782 lde_fec2map(&fn->fec, &map);
783 switch (fn->fec.type) {
784 case FEC_TYPE_IPV4:
785 if (!ln->v4_enabled)
786 return;
787 break;
788 case FEC_TYPE_IPV6:
789 if (!ln->v6_enabled)
790 return;
791 break;
792 case FEC_TYPE_PWID:
793 pw = (struct l2vpn_pw *) fn->data;
794 if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr)
795 /* not the remote end of the pseudowire */
796 return;
797
798 map.flags |= F_MAP_PW_IFMTU;
799 map.fec.pwid.ifmtu = pw->l2vpn->mtu;
800 if (pw->flags & F_PW_CWORD)
801 map.flags |= F_MAP_PW_CWORD;
802 if (pw->flags & F_PW_STATUSTLV) {
803 map.flags |= F_MAP_PW_STATUS;
804 /* VPLS are always up */
805 map.pw_status = PW_FORWARDING;
806 }
807 break;
808 }
809 map.label = fn->local_label;
810
811 /* SL.6: is there a pending request for this mapping? */
812 lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
813 if (lre) {
814 /* set label request msg id in the mapping response. */
815 map.requestid = lre->msg_id;
816 map.flags = F_MAP_REQ_ID;
817
818 /* SL.7: delete record of pending request */
819 lde_req_del(ln, lre, 0);
820 }
821
822 /* SL.4: send label mapping */
823 lde_imsg_compose_ldpe(IMSG_MAPPING_ADD, ln->peerid, 0,
824 &map, sizeof(map));
825 if (single)
826 lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0,
827 NULL, 0);
828
829 /* SL.5: record sent label mapping */
830 me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
831 if (me == NULL)
832 me = lde_map_add(ln, fn, 1);
833 me->map = map;
834}
835
836void
837lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
838 struct status_tlv *st)
839{
840 struct lde_wdraw *lw;
841 struct map map;
842 struct fec *f;
843 struct l2vpn_pw *pw;
844
845 if (fn) {
846 lde_fec2map(&fn->fec, &map);
847 switch (fn->fec.type) {
848 case FEC_TYPE_IPV4:
849 if (!ln->v4_enabled)
850 return;
851 break;
852 case FEC_TYPE_IPV6:
853 if (!ln->v6_enabled)
854 return;
855 break;
856 case FEC_TYPE_PWID:
857 pw = (struct l2vpn_pw *) fn->data;
858 if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr)
859 /* not the remote end of the pseudowire */
860 return;
861
862 if (pw->flags & F_PW_CWORD)
863 map.flags |= F_MAP_PW_CWORD;
864 break;
865 }
866 map.label = fn->local_label;
867 } else {
868 memset(&map, 0, sizeof(map));
869 map.type = MAP_TYPE_WILDCARD;
870 map.label = label;
871 }
872
873 if (st) {
874 map.st.status_code = st->status_code;
875 map.st.msg_id = st->msg_id;
876 map.st.msg_type = st->msg_type;
877 map.flags |= F_MAP_STATUS;
878 }
879
880 /* SWd.1: send label withdraw. */
881 lde_imsg_compose_ldpe(IMSG_WITHDRAW_ADD, ln->peerid, 0,
882 &map, sizeof(map));
883 lde_imsg_compose_ldpe(IMSG_WITHDRAW_ADD_END, ln->peerid, 0, NULL, 0);
884
885 /* SWd.2: record label withdraw. */
886 if (fn) {
887 lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
888 if (lw == NULL)
889 lw = lde_wdraw_add(ln, fn);
890 lw->label = map.label;
891 } else {
892 RB_FOREACH(f, fec_tree, &ft) {
893 fn = (struct fec_node *)f;
894
895 lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw,
896 &fn->fec);
897 if (lw == NULL)
898 lw = lde_wdraw_add(ln, fn);
899 lw->label = map.label;
900 }
901 }
902}
903
904void
905lde_send_labelwithdraw_all(struct fec_node *fn, uint32_t label)
906{
907 struct lde_nbr *ln;
908
909 RB_FOREACH(ln, nbr_tree, &lde_nbrs)
910 lde_send_labelwithdraw(ln, fn, label, NULL);
911}
912
913void
914lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
915{
916 struct map map;
917 struct l2vpn_pw *pw;
918
919 if (fn) {
920 lde_fec2map(&fn->fec, &map);
921 switch (fn->fec.type) {
922 case FEC_TYPE_IPV4:
923 if (!ln->v4_enabled)
924 return;
925 break;
926 case FEC_TYPE_IPV6:
927 if (!ln->v6_enabled)
928 return;
929 break;
930 case FEC_TYPE_PWID:
931 pw = (struct l2vpn_pw *) fn->data;
932 if (pw == NULL || pw->lsr_id.s_addr != ln->id.s_addr)
933 /* not the remote end of the pseudowire */
934 return;
935
936 if (pw->flags & F_PW_CWORD)
937 map.flags |= F_MAP_PW_CWORD;
938 break;
939 }
940 } else {
941 memset(&map, 0, sizeof(map));
942 map.type = MAP_TYPE_WILDCARD;
943 }
944 map.label = label;
945
946 lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0,
947 &map, sizeof(map));
948 lde_imsg_compose_ldpe(IMSG_RELEASE_ADD_END, ln->peerid, 0, NULL, 0);
949}
950
951void
952lde_send_notification(uint32_t peerid, uint32_t status_code, uint32_t msg_id,
953 uint16_t msg_type)
954{
955 struct notify_msg nm;
956
957 memset(&nm, 0, sizeof(nm));
958 nm.status_code = status_code;
959 /* 'msg_id' and 'msg_type' should be in network byte order */
960 nm.msg_id = msg_id;
961 nm.msg_type = msg_type;
962
963 lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
964 &nm, sizeof(nm));
965}
966
967static __inline int
968lde_nbr_compare(struct lde_nbr *a, struct lde_nbr *b)
969{
970 return (a->peerid - b->peerid);
971}
972
973static struct lde_nbr *
974lde_nbr_new(uint32_t peerid, struct lde_nbr *new)
975{
976 struct lde_nbr *ln;
977
978 if ((ln = calloc(1, sizeof(*ln))) == NULL)
979 fatal(__func__);
980
981 ln->id = new->id;
982 ln->v4_enabled = new->v4_enabled;
983 ln->v6_enabled = new->v6_enabled;
984 ln->peerid = peerid;
985 fec_init(&ln->recv_map);
986 fec_init(&ln->sent_map);
987 fec_init(&ln->recv_req);
988 fec_init(&ln->sent_req);
989 fec_init(&ln->sent_wdraw);
990
991 TAILQ_INIT(&ln->addr_list);
992
993 if (RB_INSERT(nbr_tree, &lde_nbrs, ln) != NULL)
994 fatalx("lde_nbr_new: RB_INSERT failed");
995
996 return (ln);
997}
998
999static void
1000lde_nbr_del(struct lde_nbr *ln)
1001{
1002 struct fec *f;
1003 struct fec_node *fn;
1004 struct fec_nh *fnh;
1005 struct l2vpn_pw *pw;
1006
1007 if (ln == NULL)
1008 return;
1009
1010 /* uninstall received mappings */
1011 RB_FOREACH(f, fec_tree, &ft) {
1012 fn = (struct fec_node *)f;
1013
1014 LIST_FOREACH(fnh, &fn->nexthops, entry) {
1015 switch (f->type) {
1016 case FEC_TYPE_IPV4:
1017 case FEC_TYPE_IPV6:
1018 if (!lde_address_find(ln, fnh->af,
1019 &fnh->nexthop))
1020 continue;
1021 break;
1022 case FEC_TYPE_PWID:
1023 if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
1024 continue;
1025 pw = (struct l2vpn_pw *) fn->data;
1026 if (pw)
1027 l2vpn_pw_reset(pw);
1028 break;
1029 default:
1030 break;
1031 }
1032
1033 lde_send_delete_klabel(fn, fnh);
1034 fnh->remote_label = NO_LABEL;
1035 }
1036 }
1037
1038 lde_address_list_free(ln);
1039
1040 fec_clear(&ln->recv_map, lde_map_free);
1041 fec_clear(&ln->sent_map, lde_map_free);
1042 fec_clear(&ln->recv_req, free);
1043 fec_clear(&ln->sent_req, free);
1044 fec_clear(&ln->sent_wdraw, free);
1045
1046 RB_REMOVE(nbr_tree, &lde_nbrs, ln);
1047
1048 free(ln);
1049}
1050
1051static struct lde_nbr *
1052lde_nbr_find(uint32_t peerid)
1053{
1054 struct lde_nbr ln;
1055
1056 ln.peerid = peerid;
1057
1058 return (RB_FIND(nbr_tree, &lde_nbrs, &ln));
1059}
1060
1061struct lde_nbr *
1062lde_nbr_find_by_lsrid(struct in_addr addr)
1063{
1064 struct lde_nbr *ln;
1065
1066 RB_FOREACH(ln, nbr_tree, &lde_nbrs)
1067 if (ln->id.s_addr == addr.s_addr)
1068 return (ln);
1069
1070 return (NULL);
1071}
1072
1073struct lde_nbr *
1074lde_nbr_find_by_addr(int af, union ldpd_addr *addr)
1075{
1076 struct lde_nbr *ln;
1077
1078 RB_FOREACH(ln, nbr_tree, &lde_nbrs)
1079 if (lde_address_find(ln, af, addr) != NULL)
1080 return (ln);
1081
1082 return (NULL);
1083}
1084
1085static void
1086lde_nbr_clear(void)
1087{
1088 struct lde_nbr *ln;
1089
1090 while ((ln = RB_ROOT(&lde_nbrs)) != NULL)
1091 lde_nbr_del(ln);
1092}
1093
1094static void
1095lde_nbr_addr_update(struct lde_nbr *ln, struct lde_addr *lde_addr, int removed)
1096{
1097 struct fec *fec;
1098 struct fec_node *fn;
1099 struct fec_nh *fnh;
1100 struct lde_map *me;
1101
1102 RB_FOREACH(fec, fec_tree, &ln->recv_map) {
1103 fn = (struct fec_node *)fec_find(&ft, fec);
1104 switch (fec->type) {
1105 case FEC_TYPE_IPV4:
1106 if (lde_addr->af != AF_INET)
1107 continue;
1108 break;
1109 case FEC_TYPE_IPV6:
1110 if (lde_addr->af != AF_INET6)
1111 continue;
1112 break;
1113 default:
1114 continue;
1115 }
1116
1117 LIST_FOREACH(fnh, &fn->nexthops, entry) {
1118 if (ldp_addrcmp(fnh->af, &fnh->nexthop,
1119 &lde_addr->addr))
1120 continue;
1121
1122 if (removed) {
1123 lde_send_delete_klabel(fn, fnh);
1124 fnh->remote_label = NO_LABEL;
1125 } else {
1126 me = (struct lde_map *)fec;
1127 fnh->remote_label = me->map.label;
1128 lde_send_change_klabel(fn, fnh);
1129 }
1130 break;
1131 }
1132 }
1133}
1134
1135struct lde_map *
1136lde_map_add(struct lde_nbr *ln, struct fec_node *fn, int sent)
1137{
1138 struct lde_map *me;
1139
1140 me = calloc(1, sizeof(*me));
1141 if (me == NULL)
1142 fatal(__func__);
1143
1144 me->fec = fn->fec;
1145 me->nexthop = ln;
1146
1147 if (sent) {
1148 LIST_INSERT_HEAD(&fn->upstream, me, entry);
1149 if (fec_insert(&ln->sent_map, &me->fec))
1150 log_warnx("failed to add %s to sent map",
1151 log_fec(&me->fec));
1152 /* XXX on failure more cleanup is needed */
1153 } else {
1154 LIST_INSERT_HEAD(&fn->downstream, me, entry);
1155 if (fec_insert(&ln->recv_map, &me->fec))
1156 log_warnx("failed to add %s to recv map",
1157 log_fec(&me->fec));
1158 }
1159
1160 return (me);
1161}
1162
1163void
1164lde_map_del(struct lde_nbr *ln, struct lde_map *me, int sent)
1165{
1166 if (sent)
1167 fec_remove(&ln->sent_map, &me->fec);
1168 else
1169 fec_remove(&ln->recv_map, &me->fec);
1170
1171 lde_map_free(me);
1172}
1173
1174static void
1175lde_map_free(void *ptr)
1176{
1177 struct lde_map *map = ptr;
1178
1179 LIST_REMOVE(map, entry);
1180 free(map);
1181}
1182
1183struct lde_req *
1184lde_req_add(struct lde_nbr *ln, struct fec *fec, int sent)
1185{
1186 struct fec_tree *t;
1187 struct lde_req *lre;
1188
1189 t = sent ? &ln->sent_req : &ln->recv_req;
1190
1191 lre = calloc(1, sizeof(*lre));
1192 if (lre != NULL) {
1193 lre->fec = *fec;
1194
1195 if (fec_insert(t, &lre->fec)) {
1196 log_warnx("failed to add %s to %s req",
1197 log_fec(&lre->fec), sent ? "sent" : "recv");
1198 free(lre);
1199 return (NULL);
1200 }
1201 }
1202
1203 return (lre);
1204}
1205
1206void
1207lde_req_del(struct lde_nbr *ln, struct lde_req *lre, int sent)
1208{
1209 if (sent)
1210 fec_remove(&ln->sent_req, &lre->fec);
1211 else
1212 fec_remove(&ln->recv_req, &lre->fec);
1213
1214 free(lre);
1215}
1216
1217struct lde_wdraw *
1218lde_wdraw_add(struct lde_nbr *ln, struct fec_node *fn)
1219{
1220 struct lde_wdraw *lw;
1221
1222 lw = calloc(1, sizeof(*lw));
1223 if (lw == NULL)
1224 fatal(__func__);
1225
1226 lw->fec = fn->fec;
1227
1228 if (fec_insert(&ln->sent_wdraw, &lw->fec))
1229 log_warnx("failed to add %s to sent wdraw",
1230 log_fec(&lw->fec));
1231
1232 return (lw);
1233}
1234
1235void
1236lde_wdraw_del(struct lde_nbr *ln, struct lde_wdraw *lw)
1237{
1238 fec_remove(&ln->sent_wdraw, &lw->fec);
1239 free(lw);
1240}
1241
1242void
1243lde_change_egress_label(int af, int was_implicit)
1244{
1245 struct lde_nbr *ln;
1246 struct fec *f;
1247 struct fec_node *fn;
1248
1249 RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
1250 /* explicit withdraw */
1251 if (was_implicit)
1252 lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL,
1253 NULL);
1254 else {
1255 if (ln->v4_enabled)
1256 lde_send_labelwithdraw(ln, NULL,
1257 MPLS_LABEL_IPV4NULL, NULL);
1258 if (ln->v6_enabled)
1259 lde_send_labelwithdraw(ln, NULL,
1260 MPLS_LABEL_IPV6NULL, NULL);
1261 }
1262
1263 /* advertise new label of connected prefixes */
1264 RB_FOREACH(f, fec_tree, &ft) {
1265 fn = (struct fec_node *)f;
1266 if (fn->local_label > MPLS_LABEL_RESERVED_MAX)
1267 continue;
1268
1269 switch (af) {
1270 case AF_INET:
1271 if (fn->fec.type != FEC_TYPE_IPV4)
1272 continue;
1273 break;
1274 case AF_INET6:
1275 if (fn->fec.type != FEC_TYPE_IPV6)
1276 continue;
1277 break;
1278 default:
1279 fatalx("lde_change_egress_label: unknown af");
1280 }
1281
1282 fn->local_label = egress_label(fn->fec.type);
1283 lde_send_labelmapping(ln, fn, 0);
1284 }
1285
1286 lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0,
1287 NULL, 0);
1288 }
1289}
1290
1291static int
1292lde_address_add(struct lde_nbr *ln, struct lde_addr *lde_addr)
1293{
1294 struct lde_addr *new;
1295
1296 if (lde_address_find(ln, lde_addr->af, &lde_addr->addr) != NULL)
1297 return (-1);
1298
1299 if ((new = calloc(1, sizeof(*new))) == NULL)
1300 fatal(__func__);
1301
1302 new->af = lde_addr->af;
1303 new->addr = lde_addr->addr;
1304 TAILQ_INSERT_TAIL(&ln->addr_list, new, entry);
1305
1306 /* reevaluate the previously received mappings from this neighbor */
1307 lde_nbr_addr_update(ln, lde_addr, 0);
1308
1309 return (0);
1310}
1311
1312static int
1313lde_address_del(struct lde_nbr *ln, struct lde_addr *lde_addr)
1314{
1315 lde_addr = lde_address_find(ln, lde_addr->af, &lde_addr->addr);
1316 if (lde_addr == NULL)
1317 return (-1);
1318
1319 /* reevaluate the previously received mappings from this neighbor */
1320 lde_nbr_addr_update(ln, lde_addr, 1);
1321
1322 TAILQ_REMOVE(&ln->addr_list, lde_addr, entry);
1323 free(lde_addr);
1324
1325 return (0);
1326}
1327
1328struct lde_addr *
1329lde_address_find(struct lde_nbr *ln, int af, union ldpd_addr *addr)
1330{
1331 struct lde_addr *lde_addr;
1332
1333 TAILQ_FOREACH(lde_addr, &ln->addr_list, entry)
1334 if (lde_addr->af == af &&
1335 ldp_addrcmp(af, &lde_addr->addr, addr) == 0)
1336 return (lde_addr);
1337
1338 return (NULL);
1339}
1340
1341static void
1342lde_address_list_free(struct lde_nbr *ln)
1343{
1344 struct lde_addr *lde_addr;
1345
1346 while ((lde_addr = TAILQ_FIRST(&ln->addr_list)) != NULL) {
1347 TAILQ_REMOVE(&ln->addr_list, lde_addr, entry);
1348 free(lde_addr);
1349 }
1350}