]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/l2vpn.c
Merge pull request #6377 from ton31337/fix/bgpd_statistics
[mirror_frr.git] / ldpd / l2vpn.c
1 /* $OpenBSD$ */
2
3 /*
4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
7 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@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
22 #include <zebra.h>
23
24 #include "ldpd.h"
25 #include "ldpe.h"
26 #include "lde.h"
27 #include "log.h"
28
29 static void l2vpn_pw_fec(struct l2vpn_pw *, struct fec *);
30 static __inline int l2vpn_compare(const struct l2vpn *, const struct l2vpn *);
31 static __inline int l2vpn_if_compare(const struct l2vpn_if *, const struct l2vpn_if *);
32 static __inline int l2vpn_pw_compare(const struct l2vpn_pw *, const struct l2vpn_pw *);
33
34 RB_GENERATE(l2vpn_head, l2vpn, entry, l2vpn_compare)
35 RB_GENERATE(l2vpn_if_head, l2vpn_if, entry, l2vpn_if_compare)
36 RB_GENERATE(l2vpn_pw_head, l2vpn_pw, entry, l2vpn_pw_compare)
37
38 static __inline int
39 l2vpn_compare(const struct l2vpn *a, const struct l2vpn *b)
40 {
41 return (strcmp(a->name, b->name));
42 }
43
44 struct l2vpn *
45 l2vpn_new(const char *name)
46 {
47 struct l2vpn *l2vpn;
48
49 if ((l2vpn = calloc(1, sizeof(*l2vpn))) == NULL)
50 fatal("l2vpn_new: calloc");
51
52 strlcpy(l2vpn->name, name, sizeof(l2vpn->name));
53
54 /* set default values */
55 l2vpn->mtu = DEFAULT_L2VPN_MTU;
56 l2vpn->pw_type = DEFAULT_PW_TYPE;
57
58 RB_INIT(l2vpn_if_head, &l2vpn->if_tree);
59 RB_INIT(l2vpn_pw_head, &l2vpn->pw_tree);
60 RB_INIT(l2vpn_pw_head, &l2vpn->pw_inactive_tree);
61
62 return (l2vpn);
63 }
64
65 struct l2vpn *
66 l2vpn_find(struct ldpd_conf *xconf, const char *name)
67 {
68 struct l2vpn l2vpn;
69 strlcpy(l2vpn.name, name, sizeof(l2vpn.name));
70 return (RB_FIND(l2vpn_head, &xconf->l2vpn_tree, &l2vpn));
71 }
72
73 void
74 l2vpn_del(struct l2vpn *l2vpn)
75 {
76 struct l2vpn_if *lif;
77 struct l2vpn_pw *pw;
78
79 while (!RB_EMPTY(l2vpn_if_head, &l2vpn->if_tree)) {
80 lif = RB_ROOT(l2vpn_if_head, &l2vpn->if_tree);
81
82 RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
83 free(lif);
84 }
85 while (!RB_EMPTY(l2vpn_pw_head, &l2vpn->pw_tree)) {
86 pw = RB_ROOT(l2vpn_pw_head, &l2vpn->pw_tree);
87
88 RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
89 free(pw);
90 }
91 while (!RB_EMPTY(l2vpn_pw_head, &l2vpn->pw_inactive_tree)) {
92 pw = RB_ROOT(l2vpn_pw_head, &l2vpn->pw_inactive_tree);
93
94 RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
95 free(pw);
96 }
97
98 free(l2vpn);
99 }
100
101 void
102 l2vpn_init(struct l2vpn *l2vpn)
103 {
104 struct l2vpn_pw *pw;
105
106 RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
107 l2vpn_pw_init(pw);
108 }
109
110 void
111 l2vpn_exit(struct l2vpn *l2vpn)
112 {
113 struct l2vpn_pw *pw;
114
115 RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
116 l2vpn_pw_exit(pw);
117 }
118
119 static __inline int
120 l2vpn_if_compare(const struct l2vpn_if *a, const struct l2vpn_if *b)
121 {
122 return if_cmp_name_func(a->ifname, b->ifname);
123 }
124
125 struct l2vpn_if *
126 l2vpn_if_new(struct l2vpn *l2vpn, const char *ifname)
127 {
128 struct l2vpn_if *lif;
129
130 if ((lif = calloc(1, sizeof(*lif))) == NULL)
131 fatal("l2vpn_if_new: calloc");
132
133 lif->l2vpn = l2vpn;
134 strlcpy(lif->ifname, ifname, sizeof(lif->ifname));
135
136 return (lif);
137 }
138
139 struct l2vpn_if *
140 l2vpn_if_find(struct l2vpn *l2vpn, const char *ifname)
141 {
142 struct l2vpn_if lif;
143 strlcpy(lif.ifname, ifname, sizeof(lif.ifname));
144 return (RB_FIND(l2vpn_if_head, &l2vpn->if_tree, &lif));
145 }
146
147 void
148 l2vpn_if_update_info(struct l2vpn_if *lif, struct kif *kif)
149 {
150 lif->ifindex = kif->ifindex;
151 lif->operative = kif->operative;
152 memcpy(lif->mac, kif->mac, sizeof(lif->mac));
153 }
154
155 void
156 l2vpn_if_update(struct l2vpn_if *lif)
157 {
158 struct l2vpn *l2vpn = lif->l2vpn;
159 struct l2vpn_pw *pw;
160 struct map fec;
161 struct nbr *nbr;
162
163 if (lif->operative)
164 return;
165
166 RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
167 nbr = nbr_find_ldpid(pw->lsr_id.s_addr);
168 if (nbr == NULL)
169 continue;
170
171 memset(&fec, 0, sizeof(fec));
172 fec.type = MAP_TYPE_PWID;
173 fec.fec.pwid.type = l2vpn->pw_type;
174 fec.fec.pwid.group_id = 0;
175 fec.flags |= F_MAP_PW_ID;
176 fec.fec.pwid.pwid = pw->pwid;
177
178 send_mac_withdrawal(nbr, &fec, lif->mac);
179 }
180 }
181
182 static __inline int
183 l2vpn_pw_compare(const struct l2vpn_pw *a, const struct l2vpn_pw *b)
184 {
185 return if_cmp_name_func(a->ifname, b->ifname);
186 }
187
188 struct l2vpn_pw *
189 l2vpn_pw_new(struct l2vpn *l2vpn, const char *ifname)
190 {
191 struct l2vpn_pw *pw;
192
193 if ((pw = calloc(1, sizeof(*pw))) == NULL)
194 fatal("l2vpn_pw_new: calloc");
195
196 pw->l2vpn = l2vpn;
197 strlcpy(pw->ifname, ifname, sizeof(pw->ifname));
198
199 return (pw);
200 }
201
202 struct l2vpn_pw *
203 l2vpn_pw_find(struct l2vpn *l2vpn, const char *ifname)
204 {
205 struct l2vpn_pw *pw;
206 struct l2vpn_pw s;
207
208 strlcpy(s.ifname, ifname, sizeof(s.ifname));
209 pw = RB_FIND(l2vpn_pw_head, &l2vpn->pw_tree, &s);
210 if (pw)
211 return (pw);
212 return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_inactive_tree, &s));
213 }
214
215 struct l2vpn_pw *
216 l2vpn_pw_find_active(struct l2vpn *l2vpn, const char *ifname)
217 {
218 struct l2vpn_pw s;
219
220 strlcpy(s.ifname, ifname, sizeof(s.ifname));
221 return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_tree, &s));
222 }
223
224 struct l2vpn_pw *
225 l2vpn_pw_find_inactive(struct l2vpn *l2vpn, const char *ifname)
226 {
227 struct l2vpn_pw s;
228
229 strlcpy(s.ifname, ifname, sizeof(s.ifname));
230 return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_inactive_tree, &s));
231 }
232
233 void
234 l2vpn_pw_update_info(struct l2vpn_pw *pw, struct kif *kif)
235 {
236 pw->ifindex = kif->ifindex;
237 }
238
239 void
240 l2vpn_pw_init(struct l2vpn_pw *pw)
241 {
242 struct fec fec;
243 struct zapi_pw zpw;
244
245 l2vpn_pw_reset(pw);
246
247 pw2zpw(pw, &zpw);
248 lde_imsg_compose_parent(IMSG_KPW_ADD, 0, &zpw, sizeof(zpw));
249
250 l2vpn_pw_fec(pw, &fec);
251 lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0,
252 0, 0, (void *)pw);
253 lde_kernel_update(&fec);
254 }
255
256 void
257 l2vpn_pw_exit(struct l2vpn_pw *pw)
258 {
259 struct fec fec;
260 struct zapi_pw zpw;
261
262 l2vpn_pw_fec(pw, &fec);
263 lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, 0);
264 lde_kernel_update(&fec);
265
266 pw2zpw(pw, &zpw);
267 lde_imsg_compose_parent(IMSG_KPW_DELETE, 0, &zpw, sizeof(zpw));
268 }
269
270 static void
271 l2vpn_pw_fec(struct l2vpn_pw *pw, struct fec *fec)
272 {
273 memset(fec, 0, sizeof(*fec));
274 fec->type = FEC_TYPE_PWID;
275 fec->u.pwid.type = pw->l2vpn->pw_type;
276 fec->u.pwid.pwid = pw->pwid;
277 fec->u.pwid.lsr_id = pw->lsr_id;
278 }
279
280 void
281 l2vpn_pw_reset(struct l2vpn_pw *pw)
282 {
283 pw->remote_group = 0;
284 pw->remote_mtu = 0;
285 pw->local_status = PW_FORWARDING;
286 pw->remote_status = PW_NOT_FORWARDING;
287
288 if (pw->flags & F_PW_CWORD_CONF)
289 pw->flags |= F_PW_CWORD;
290 else
291 pw->flags &= ~F_PW_CWORD;
292
293 if (pw->flags & F_PW_STATUSTLV_CONF)
294 pw->flags |= F_PW_STATUSTLV;
295 else
296 pw->flags &= ~F_PW_STATUSTLV;
297 }
298
299 int
300 l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
301 {
302 /* check for a remote label */
303 if (fnh->remote_label == NO_LABEL) {
304 log_warnx("%s: pseudowire %s: no remote label", __func__,
305 pw->ifname);
306 pw->reason = F_PW_NO_REMOTE_LABEL;
307 return (0);
308 }
309
310 /* MTUs must match */
311 if (pw->l2vpn->mtu != pw->remote_mtu) {
312 log_warnx("%s: pseudowire %s: MTU mismatch detected", __func__,
313 pw->ifname);
314 pw->reason = F_PW_MTU_MISMATCH;
315 return (0);
316 }
317
318 /* check pw status if applicable */
319 if ((pw->flags & F_PW_STATUSTLV) &&
320 pw->remote_status != PW_FORWARDING) {
321 log_warnx("%s: pseudowire %s: remote end is down", __func__,
322 pw->ifname);
323 pw->reason = F_PW_REMOTE_NOT_FWD;
324 return (0);
325 }
326
327 pw->reason = F_PW_NO_ERR;
328 return (1);
329 }
330
331 int
332 l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
333 {
334 struct l2vpn_pw *pw;
335 struct status_tlv st;
336
337 /* NOTE: thanks martini & friends for all this mess */
338
339 pw = (struct l2vpn_pw *) fn->data;
340 if (pw == NULL)
341 /*
342 * pseudowire not configured, return and record
343 * the mapping later
344 */
345 return (0);
346
347 /* RFC4447 - Section 6.2: control word negotiation */
348 if (fec_find(&ln->sent_map, &fn->fec)) {
349 if ((map->flags & F_MAP_PW_CWORD) &&
350 !(pw->flags & F_PW_CWORD_CONF)) {
351 /* ignore the received label mapping */
352 return (1);
353 } else if (!(map->flags & F_MAP_PW_CWORD) &&
354 (pw->flags & F_PW_CWORD_CONF)) {
355 /* append a "Wrong C-bit" status code */
356 st.status_code = S_WRONG_CBIT;
357 st.msg_id = map->msg_id;
358 st.msg_type = htons(MSG_TYPE_LABELMAPPING);
359 lde_send_labelwithdraw(ln, fn, NULL, &st);
360
361 pw->flags &= ~F_PW_CWORD;
362 lde_send_labelmapping(ln, fn, 1);
363 }
364 } else if (map->flags & F_MAP_PW_CWORD) {
365 if (pw->flags & F_PW_CWORD_CONF)
366 pw->flags |= F_PW_CWORD;
367 else
368 /* act as if no label mapping had been received */
369 return (1);
370 } else
371 pw->flags &= ~F_PW_CWORD;
372
373 /* RFC4447 - Section 5.4.3: pseudowire status negotiation */
374 if (fec_find(&ln->recv_map, &fn->fec) == NULL &&
375 !(map->flags & F_MAP_PW_STATUS))
376 pw->flags &= ~F_PW_STATUSTLV;
377
378 return (0);
379 }
380
381 void
382 l2vpn_send_pw_status(struct lde_nbr *ln, uint32_t status, struct fec *fec)
383 {
384 struct notify_msg nm;
385
386 memset(&nm, 0, sizeof(nm));
387 nm.status_code = S_PW_STATUS;
388 nm.pw_status = status;
389 nm.flags |= F_NOTIF_PW_STATUS;
390 lde_fec2map(fec, &nm.fec);
391 nm.flags |= F_NOTIF_FEC;
392
393 lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
394 sizeof(nm));
395 }
396
397 void
398 l2vpn_send_pw_status_wcard(struct lde_nbr *ln, uint32_t status,
399 uint16_t pw_type, uint32_t group_id)
400 {
401 struct notify_msg nm;
402
403 memset(&nm, 0, sizeof(nm));
404 nm.status_code = S_PW_STATUS;
405 nm.pw_status = status;
406 nm.flags |= F_NOTIF_PW_STATUS;
407 nm.fec.type = MAP_TYPE_PWID;
408 nm.fec.fec.pwid.type = pw_type;
409 nm.fec.fec.pwid.group_id = group_id;
410 nm.flags |= F_NOTIF_FEC;
411
412 lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
413 sizeof(nm));
414 }
415
416 void
417 l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
418 {
419 struct fec fec;
420 struct fec_node *fn;
421 struct fec_nh *fnh;
422 struct l2vpn_pw *pw;
423
424 if (nm->fec.type == MAP_TYPE_TYPED_WCARD ||
425 !(nm->fec.flags & F_MAP_PW_ID)) {
426 l2vpn_recv_pw_status_wcard(ln, nm);
427 return;
428 }
429
430 lde_map2fec(&nm->fec, ln->id, &fec);
431 fn = (struct fec_node *)fec_find(&ft, &fec);
432 if (fn == NULL)
433 /* unknown fec */
434 return;
435
436 pw = (struct l2vpn_pw *) fn->data;
437 if (pw == NULL)
438 return;
439
440 fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0, 0);
441 if (fnh == NULL)
442 return;
443
444 /* remote status didn't change */
445 if (pw->remote_status == nm->pw_status)
446 return;
447 pw->remote_status = nm->pw_status;
448
449 if (l2vpn_pw_ok(pw, fnh))
450 lde_send_change_klabel(fn, fnh);
451 else
452 lde_send_delete_klabel(fn, fnh);
453 }
454
455 /* RFC4447 PWid group wildcard */
456 void
457 l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
458 {
459 struct fec *f;
460 struct fec_node *fn;
461 struct fec_nh *fnh;
462 struct l2vpn_pw *pw;
463 struct map *wcard = &nm->fec;
464
465 RB_FOREACH(f, fec_tree, &ft) {
466 fn = (struct fec_node *)f;
467 if (fn->fec.type != FEC_TYPE_PWID)
468 continue;
469
470 pw = (struct l2vpn_pw *) fn->data;
471 if (pw == NULL)
472 continue;
473
474 switch (wcard->type) {
475 case MAP_TYPE_TYPED_WCARD:
476 if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
477 wcard->fec.twcard.u.pw_type != fn->fec.u.pwid.type)
478 continue;
479 break;
480 case MAP_TYPE_PWID:
481 if (wcard->fec.pwid.type != fn->fec.u.pwid.type)
482 continue;
483 if (wcard->fec.pwid.group_id != pw->remote_group)
484 continue;
485 break;
486 }
487
488 fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id,
489 0, 0, 0);
490 if (fnh == NULL)
491 continue;
492
493 /* remote status didn't change */
494 if (pw->remote_status == nm->pw_status)
495 continue;
496 pw->remote_status = nm->pw_status;
497
498 if (l2vpn_pw_ok(pw, fnh))
499 lde_send_change_klabel(fn, fnh);
500 else
501 lde_send_delete_klabel(fn, fnh);
502 }
503 }
504
505 int
506 l2vpn_pw_status_update(struct zapi_pw_status *zpw)
507 {
508 struct l2vpn *l2vpn;
509 struct l2vpn_pw *pw = NULL;
510 struct lde_nbr *ln;
511 struct fec fec;
512 uint32_t local_status;
513
514 RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) {
515 pw = l2vpn_pw_find(l2vpn, zpw->ifname);
516 if (pw)
517 break;
518 }
519 if (!pw) {
520 log_warnx("%s: pseudowire %s not found", __func__, zpw->ifname);
521 return (1);
522 }
523
524 if (zpw->status == PW_STATUS_UP) {
525 local_status = PW_FORWARDING;
526 pw->reason = F_PW_NO_ERR;
527 } else {
528 local_status = PW_NOT_FORWARDING;
529 pw->reason = F_PW_LOCAL_NOT_FWD;
530 }
531
532 /* local status didn't change */
533 if (pw->local_status == local_status)
534 return (0);
535 pw->local_status = local_status;
536
537 /* notify remote peer about the status update */
538 ln = lde_nbr_find_by_lsrid(pw->lsr_id);
539 if (ln == NULL)
540 return (0);
541 l2vpn_pw_fec(pw, &fec);
542 if (pw->flags & F_PW_STATUSTLV)
543 l2vpn_send_pw_status(ln, local_status, &fec);
544 else {
545 struct fec_node *fn;
546 fn = (struct fec_node *)fec_find(&ft, &fec);
547 if (fn) {
548 if (pw->local_status == PW_FORWARDING)
549 lde_send_labelmapping(ln, fn, 1);
550 else
551 lde_send_labelwithdraw(ln, fn, NULL, NULL);
552 }
553 }
554
555 return (0);
556 }
557
558 void
559 l2vpn_pw_ctl(pid_t pid)
560 {
561 struct l2vpn *l2vpn;
562 struct l2vpn_pw *pw;
563 static struct ctl_pw pwctl;
564
565 RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree)
566 RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
567 memset(&pwctl, 0, sizeof(pwctl));
568 strlcpy(pwctl.l2vpn_name, pw->l2vpn->name,
569 sizeof(pwctl.l2vpn_name));
570 strlcpy(pwctl.ifname, pw->ifname,
571 sizeof(pwctl.ifname));
572 pwctl.pwid = pw->pwid;
573 pwctl.lsr_id = pw->lsr_id;
574 if (pw->enabled &&
575 pw->local_status == PW_FORWARDING &&
576 pw->remote_status == PW_FORWARDING)
577 pwctl.status = 1;
578
579 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
580 pid, &pwctl, sizeof(pwctl));
581 }
582 }
583
584 void
585 l2vpn_binding_ctl(pid_t pid)
586 {
587 struct fec *f;
588 struct fec_node *fn;
589 struct lde_map *me;
590 struct l2vpn_pw *pw;
591 static struct ctl_pw pwctl;
592
593 RB_FOREACH(f, fec_tree, &ft) {
594 if (f->type != FEC_TYPE_PWID)
595 continue;
596
597 fn = (struct fec_node *)f;
598 if (fn->local_label == NO_LABEL &&
599 RB_EMPTY(lde_map_head, &fn->downstream))
600 continue;
601
602 memset(&pwctl, 0, sizeof(pwctl));
603 pwctl.type = f->u.pwid.type;
604 pwctl.pwid = f->u.pwid.pwid;
605 pwctl.lsr_id = f->u.pwid.lsr_id;
606
607 pw = (struct l2vpn_pw *) fn->data;
608 if (pw) {
609 pwctl.local_label = fn->local_label;
610 pwctl.local_gid = 0;
611 pwctl.local_ifmtu = pw->l2vpn->mtu;
612 pwctl.local_cword = (pw->flags & F_PW_CWORD_CONF) ?
613 1 : 0;
614 pwctl.reason = pw->reason;
615 } else
616 pwctl.local_label = NO_LABEL;
617
618 RB_FOREACH(me, lde_map_head, &fn->downstream)
619 if (f->u.pwid.lsr_id.s_addr == me->nexthop->id.s_addr)
620 break;
621
622 if (me) {
623 pwctl.remote_label = me->map.label;
624 pwctl.remote_gid = me->map.fec.pwid.group_id;
625 if (me->map.flags & F_MAP_PW_IFMTU)
626 pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
627 if (pw)
628 pwctl.remote_cword = (pw->flags & F_PW_CWORD) ?
629 1 : 0;
630
631 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
632 0, pid, &pwctl, sizeof(pwctl));
633 } else if (pw) {
634 pwctl.remote_label = NO_LABEL;
635
636 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
637 0, pid, &pwctl, sizeof(pwctl));
638 }
639 }
640 }
641
642 /* ldpe */
643
644 void
645 ldpe_l2vpn_init(struct l2vpn *l2vpn)
646 {
647 struct l2vpn_pw *pw;
648
649 RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
650 ldpe_l2vpn_pw_init(pw);
651 }
652
653 void
654 ldpe_l2vpn_exit(struct l2vpn *l2vpn)
655 {
656 struct l2vpn_pw *pw;
657
658 RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
659 ldpe_l2vpn_pw_exit(pw);
660 }
661
662 void
663 ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
664 {
665 struct tnbr *tnbr;
666
667 tnbr = tnbr_find(leconf, pw->af, &pw->addr);
668 if (tnbr == NULL) {
669 tnbr = tnbr_new(pw->af, &pw->addr);
670 tnbr_update(tnbr);
671 RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
672 }
673
674 tnbr->pw_count++;
675 }
676
677 void
678 ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
679 {
680 struct tnbr *tnbr;
681
682 tnbr = tnbr_find(leconf, pw->af, &pw->addr);
683 if (tnbr) {
684 tnbr->pw_count--;
685 tnbr_check(leconf, tnbr);
686 }
687 }