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