]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/l2vpn.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[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 SET_FLAG(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 (CHECK_FLAG(pw->flags, F_PW_CWORD_CONF))
278 SET_FLAG(pw->flags, F_PW_CWORD);
279 else
280 UNSET_FLAG(pw->flags, F_PW_CWORD);
281
282 if (CHECK_FLAG(pw->flags, F_PW_STATUSTLV_CONF))
283 SET_FLAG(pw->flags, F_PW_STATUSTLV);
284 else
285 UNSET_FLAG(pw->flags, F_PW_STATUSTLV);
286
287 if (CHECK_FLAG(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__, pw->ifname);
304 pw->reason = F_PW_NO_REMOTE_LABEL;
305 return (0);
306 }
307
308 /* MTUs must match */
309 if (pw->l2vpn->mtu != pw->remote_mtu) {
310 log_warnx("%s: pseudowire %s: MTU mismatch detected", __func__,
311 pw->ifname);
312 pw->reason = F_PW_MTU_MISMATCH;
313 return (0);
314 }
315
316 /* check pw status if applicable */
317 if (CHECK_FLAG(pw->flags, F_PW_STATUSTLV) &&
318 pw->remote_status != PW_FORWARDING) {
319 log_warnx("%s: pseudowire %s: remote end is down", __func__, pw->ifname);
320 pw->reason = F_PW_REMOTE_NOT_FWD;
321 return (0);
322 }
323
324 pw->reason = F_PW_NO_ERR;
325 return (1);
326 }
327
328 int
329 l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
330 {
331 struct l2vpn_pw *pw;
332 struct status_tlv st;
333
334 /* NOTE: thanks martini & friends for all this mess */
335
336 pw = (struct l2vpn_pw *) fn->data;
337 if (pw == NULL)
338 /*
339 * pseudowire not configured, return and record
340 * the mapping later
341 */
342 return (0);
343
344 /* RFC4447 - Section 6.2: control word negotiation */
345 if (fec_find(&ln->sent_map, &fn->fec)) {
346 if (CHECK_FLAG(map->flags, F_MAP_PW_CWORD) &&
347 !CHECK_FLAG(pw->flags, F_PW_CWORD_CONF)) {
348 /* ignore the received label mapping */
349 return (1);
350 } else if (!CHECK_FLAG(map->flags, F_MAP_PW_CWORD) &&
351 CHECK_FLAG(pw->flags, F_PW_CWORD_CONF)) {
352 /* append a "Wrong C-bit" status code */
353 st.status_code = S_WRONG_CBIT;
354 st.msg_id = map->msg_id;
355 st.msg_type = htons(MSG_TYPE_LABELMAPPING);
356 lde_send_labelwithdraw(ln, fn, NULL, &st);
357
358 UNSET_FLAG(pw->flags, F_PW_CWORD);
359 lde_send_labelmapping(ln, fn, 1);
360 }
361 } else if (CHECK_FLAG(map->flags, F_MAP_PW_CWORD)) {
362 if (CHECK_FLAG(pw->flags, F_PW_CWORD_CONF))
363 SET_FLAG(pw->flags, F_PW_CWORD);
364 else
365 /* act as if no label mapping had been received */
366 return (1);
367 } else
368 UNSET_FLAG(pw->flags, F_PW_CWORD);
369
370 /* RFC4447 - Section 5.4.3: pseudowire status negotiation */
371 if (fec_find(&ln->recv_map, &fn->fec) == NULL &&
372 !CHECK_FLAG(map->flags, F_MAP_PW_STATUS))
373 UNSET_FLAG(pw->flags, F_PW_STATUSTLV);
374
375 return (0);
376 }
377
378 void
379 l2vpn_send_pw_status(struct lde_nbr *ln, uint32_t status, struct fec *fec)
380 {
381 struct notify_msg nm;
382
383 memset(&nm, 0, sizeof(nm));
384 nm.status_code = S_PW_STATUS;
385 nm.pw_status = status;
386 SET_FLAG(nm.flags, F_NOTIF_PW_STATUS);
387 lde_fec2map(fec, &nm.fec);
388 SET_FLAG(nm.flags, F_NOTIF_FEC);
389
390 lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, sizeof(nm));
391 }
392
393 void
394 l2vpn_send_pw_status_wcard(struct lde_nbr *ln, uint32_t status,
395 uint16_t pw_type, uint32_t group_id)
396 {
397 struct notify_msg nm;
398
399 memset(&nm, 0, sizeof(nm));
400 nm.status_code = S_PW_STATUS;
401 nm.pw_status = status;
402 SET_FLAG(nm.flags, F_NOTIF_PW_STATUS);
403 nm.fec.type = MAP_TYPE_PWID;
404 nm.fec.fec.pwid.type = pw_type;
405 nm.fec.fec.pwid.group_id = group_id;
406 SET_FLAG(nm.flags, F_NOTIF_FEC);
407
408 lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, sizeof(nm));
409 }
410
411 void
412 l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
413 {
414 struct fec fec;
415 struct fec_node *fn;
416 struct fec_nh *fnh;
417 struct l2vpn_pw *pw;
418
419 if (nm->fec.type == MAP_TYPE_TYPED_WCARD ||
420 !CHECK_FLAG(nm->fec.flags, F_MAP_PW_ID)) {
421 l2vpn_recv_pw_status_wcard(ln, nm);
422 return;
423 }
424
425 lde_map2fec(&nm->fec, ln->id, &fec);
426 fn = (struct fec_node *)fec_find(&ft, &fec);
427 if (fn == NULL)
428 /* unknown fec */
429 return;
430
431 fn->pw_remote_status = nm->pw_status;
432
433 pw = (struct l2vpn_pw *) fn->data;
434 if (pw == NULL)
435 return;
436
437 fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0, 0);
438 if (fnh == NULL)
439 return;
440
441 /* remote status didn't change */
442 if (pw->remote_status == nm->pw_status)
443 return;
444 pw->remote_status = nm->pw_status;
445
446 if (l2vpn_pw_ok(pw, fnh))
447 lde_send_change_klabel(fn, fnh);
448 else
449 lde_send_delete_klabel(fn, fnh);
450 }
451
452 /* RFC4447 PWid group wildcard */
453 void
454 l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
455 {
456 struct fec *f;
457 struct fec_node *fn;
458 struct fec_nh *fnh;
459 struct l2vpn_pw *pw;
460 struct map *wcard = &nm->fec;
461
462 RB_FOREACH(f, fec_tree, &ft) {
463 fn = (struct fec_node *)f;
464 if (fn->fec.type != FEC_TYPE_PWID)
465 continue;
466
467 pw = (struct l2vpn_pw *) fn->data;
468 if (pw == NULL)
469 continue;
470
471 switch (wcard->type) {
472 case MAP_TYPE_TYPED_WCARD:
473 if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
474 wcard->fec.twcard.u.pw_type != fn->fec.u.pwid.type)
475 continue;
476 break;
477 case MAP_TYPE_PWID:
478 if (wcard->fec.pwid.type != fn->fec.u.pwid.type)
479 continue;
480 if (wcard->fec.pwid.group_id != pw->remote_group)
481 continue;
482 break;
483 }
484
485 fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id,
486 0, 0, 0);
487 if (fnh == NULL)
488 continue;
489
490 /* remote status didn't change */
491 if (pw->remote_status == nm->pw_status)
492 continue;
493 pw->remote_status = nm->pw_status;
494
495 if (l2vpn_pw_ok(pw, fnh))
496 lde_send_change_klabel(fn, fnh);
497 else
498 lde_send_delete_klabel(fn, fnh);
499 }
500 }
501
502 int
503 l2vpn_pw_status_update(struct zapi_pw_status *zpw)
504 {
505 struct l2vpn *l2vpn;
506 struct l2vpn_pw *pw = NULL;
507 struct lde_nbr *ln;
508 struct fec fec;
509 uint32_t local_status;
510
511 RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) {
512 pw = l2vpn_pw_find(l2vpn, zpw->ifname);
513 if (pw)
514 break;
515 }
516 if (!pw) {
517 log_warnx("%s: pseudowire %s not found", __func__, zpw->ifname);
518 return (1);
519 }
520
521 if (zpw->status == PW_FORWARDING) {
522 local_status = PW_FORWARDING;
523 pw->reason = F_PW_NO_ERR;
524 } else {
525 local_status = zpw->status;
526 pw->reason = F_PW_LOCAL_NOT_FWD;
527 }
528
529 /* local status didn't change */
530 if (pw->local_status == local_status)
531 return (0);
532 pw->local_status = local_status;
533
534 /* notify remote peer about the status update */
535 ln = lde_nbr_find_by_lsrid(pw->lsr_id);
536 if (ln == NULL)
537 return (0);
538 l2vpn_pw_fec(pw, &fec);
539 if (CHECK_FLAG(pw->flags, F_PW_STATUSTLV))
540 l2vpn_send_pw_status(ln, local_status, &fec);
541 else {
542 struct fec_node *fn;
543 fn = (struct fec_node *)fec_find(&ft, &fec);
544 if (fn) {
545 if (pw->local_status == PW_FORWARDING)
546 lde_send_labelmapping(ln, fn, 1);
547 else
548 lde_send_labelwithdraw(ln, fn, NULL, NULL);
549 }
550 }
551
552 return (0);
553 }
554
555 void
556 l2vpn_pw_ctl(pid_t pid)
557 {
558 struct l2vpn *l2vpn;
559 struct l2vpn_pw *pw;
560 static struct ctl_pw pwctl;
561
562 RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree)
563 RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
564 memset(&pwctl, 0, sizeof(pwctl));
565 strlcpy(pwctl.l2vpn_name, pw->l2vpn->name,
566 sizeof(pwctl.l2vpn_name));
567 strlcpy(pwctl.ifname, pw->ifname,
568 sizeof(pwctl.ifname));
569 pwctl.pwid = pw->pwid;
570 pwctl.lsr_id = pw->lsr_id;
571 pwctl.status = PW_NOT_FORWARDING;
572 if (pw->enabled &&
573 pw->local_status == PW_FORWARDING &&
574 pw->remote_status == PW_FORWARDING)
575 pwctl.status = PW_FORWARDING;
576
577 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
578 pid, &pwctl, sizeof(pwctl));
579 }
580 }
581
582 void
583 l2vpn_binding_ctl(pid_t pid)
584 {
585 struct fec *f;
586 struct fec_node *fn;
587 struct lde_map *me;
588 struct l2vpn_pw *pw;
589 static struct ctl_pw pwctl;
590
591 RB_FOREACH(f, fec_tree, &ft) {
592 if (f->type != FEC_TYPE_PWID)
593 continue;
594
595 fn = (struct fec_node *)f;
596 if (fn->local_label == NO_LABEL &&
597 RB_EMPTY(lde_map_head, &fn->downstream))
598 continue;
599
600 memset(&pwctl, 0, sizeof(pwctl));
601 pwctl.type = f->u.pwid.type;
602 pwctl.pwid = f->u.pwid.pwid;
603 pwctl.lsr_id = f->u.pwid.lsr_id;
604
605 pw = (struct l2vpn_pw *) fn->data;
606 if (pw) {
607 pwctl.local_label = fn->local_label;
608 pwctl.local_gid = 0;
609 pwctl.local_ifmtu = pw->l2vpn->mtu;
610 pwctl.local_cword = CHECK_FLAG(pw->flags, F_PW_CWORD_CONF) ? 1 : 0;
611 pwctl.reason = pw->reason;
612 } else
613 pwctl.local_label = NO_LABEL;
614
615 RB_FOREACH(me, lde_map_head, &fn->downstream)
616 if (f->u.pwid.lsr_id.s_addr == me->nexthop->id.s_addr)
617 break;
618
619 if (me) {
620 pwctl.remote_label = me->map.label;
621 pwctl.remote_gid = me->map.fec.pwid.group_id;
622 if (CHECK_FLAG(me->map.flags, F_MAP_PW_IFMTU))
623 pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
624 if (pw)
625 pwctl.remote_cword = CHECK_FLAG(pw->flags, F_PW_CWORD) ? 1 : 0;
626
627 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
628 0, pid, &pwctl, sizeof(pwctl));
629 } else if (pw) {
630 pwctl.remote_label = NO_LABEL;
631
632 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
633 0, pid, &pwctl, sizeof(pwctl));
634 }
635 }
636 }
637
638 /* ldpe */
639
640 void
641 ldpe_l2vpn_init(struct l2vpn *l2vpn)
642 {
643 struct l2vpn_pw *pw;
644
645 RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
646 ldpe_l2vpn_pw_init(pw);
647 }
648
649 void
650 ldpe_l2vpn_exit(struct l2vpn *l2vpn)
651 {
652 struct l2vpn_pw *pw;
653
654 RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
655 ldpe_l2vpn_pw_exit(pw);
656 }
657
658 void
659 ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
660 {
661 struct tnbr *tnbr;
662
663 tnbr = tnbr_find(leconf, pw->af, &pw->addr);
664 if (tnbr == NULL) {
665 tnbr = tnbr_new(pw->af, &pw->addr);
666 tnbr_update(tnbr);
667 RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
668 }
669
670 tnbr->pw_count++;
671 }
672
673 void
674 ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
675 {
676 struct tnbr *tnbr;
677
678 tnbr = tnbr_find(leconf, pw->af, &pw->addr);
679 if (tnbr) {
680 tnbr->pw_count--;
681 tnbr_check(leconf, tnbr);
682 }
683 }