xref: /openbsd/usr.sbin/ldpd/l2vpn.c (revision 38e65088)
1 /*	$OpenBSD: l2vpn.c,v 1.24 2017/03/04 00:21:48 renato Exp $ */
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 <sys/types.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 
27 #include "ldpd.h"
28 #include "ldpe.h"
29 #include "lde.h"
30 #include "log.h"
31 
32 static void	 l2vpn_pw_fec(struct l2vpn_pw *, struct fec *);
33 
34 struct l2vpn *
l2vpn_new(const char * name)35 l2vpn_new(const char *name)
36 {
37 	struct l2vpn	*l2vpn;
38 
39 	if ((l2vpn = calloc(1, sizeof(*l2vpn))) == NULL)
40 		fatal("l2vpn_new: calloc");
41 
42 	strlcpy(l2vpn->name, name, sizeof(l2vpn->name));
43 
44 	/* set default values */
45 	l2vpn->mtu = DEFAULT_L2VPN_MTU;
46 	l2vpn->pw_type = DEFAULT_PW_TYPE;
47 
48 	LIST_INIT(&l2vpn->if_list);
49 	LIST_INIT(&l2vpn->pw_list);
50 
51 	return (l2vpn);
52 }
53 
54 struct l2vpn *
l2vpn_find(struct ldpd_conf * xconf,const char * name)55 l2vpn_find(struct ldpd_conf *xconf, const char *name)
56 {
57 	struct l2vpn	*l2vpn;
58 
59 	LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry)
60 		if (strcmp(l2vpn->name, name) == 0)
61 			return (l2vpn);
62 
63 	return (NULL);
64 }
65 
66 void
l2vpn_del(struct l2vpn * l2vpn)67 l2vpn_del(struct l2vpn *l2vpn)
68 {
69 	struct l2vpn_if		*lif;
70 	struct l2vpn_pw		*pw;
71 
72 	while ((lif = LIST_FIRST(&l2vpn->if_list)) != NULL) {
73 		LIST_REMOVE(lif, entry);
74 		free(lif);
75 	}
76 	while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) {
77 		LIST_REMOVE(pw, entry);
78 		free(pw);
79 	}
80 
81 	free(l2vpn);
82 }
83 
84 void
l2vpn_init(struct l2vpn * l2vpn)85 l2vpn_init(struct l2vpn *l2vpn)
86 {
87 	struct l2vpn_pw	*pw;
88 
89 	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
90 		l2vpn_pw_init(pw);
91 }
92 
93 void
l2vpn_exit(struct l2vpn * l2vpn)94 l2vpn_exit(struct l2vpn *l2vpn)
95 {
96 	struct l2vpn_pw		*pw;
97 
98 	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
99 		l2vpn_pw_exit(pw);
100 }
101 
102 struct l2vpn_if *
l2vpn_if_new(struct l2vpn * l2vpn,struct kif * kif)103 l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)
104 {
105 	struct l2vpn_if	*lif;
106 
107 	if ((lif = calloc(1, sizeof(*lif))) == NULL)
108 		fatal("l2vpn_if_new: calloc");
109 
110 	lif->l2vpn = l2vpn;
111 	strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname));
112 	lif->ifindex = kif->ifindex;
113 	lif->flags = kif->flags;
114 	lif->linkstate = kif->link_state;
115 
116 	return (lif);
117 }
118 
119 struct l2vpn_if *
l2vpn_if_find(struct l2vpn * l2vpn,unsigned int ifindex)120 l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex)
121 {
122 	struct l2vpn_if	*lif;
123 
124 	LIST_FOREACH(lif, &l2vpn->if_list, entry)
125 		if (lif->ifindex == ifindex)
126 			return (lif);
127 
128 	return (NULL);
129 }
130 
131 void
l2vpn_if_update(struct l2vpn_if * lif)132 l2vpn_if_update(struct l2vpn_if *lif)
133 {
134 	struct l2vpn	*l2vpn = lif->l2vpn;
135 	struct l2vpn_pw	*pw;
136 	struct map	 fec;
137 	struct nbr	*nbr;
138 
139 	if ((lif->flags & IFF_UP) && LINK_STATE_IS_UP(lif->linkstate))
140 		return;
141 
142 	LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
143 		nbr = nbr_find_ldpid(pw->lsr_id.s_addr);
144 		if (nbr == NULL)
145 			continue;
146 
147 		memset(&fec, 0, sizeof(fec));
148 		fec.type = MAP_TYPE_PWID;
149 		fec.fec.pwid.type = l2vpn->pw_type;
150 		fec.fec.pwid.group_id = 0;
151 		fec.flags |= F_MAP_PW_ID;
152 		fec.fec.pwid.pwid = pw->pwid;
153 
154 		send_mac_withdrawal(nbr, &fec, lif->mac);
155 	}
156 }
157 
158 struct l2vpn_pw *
l2vpn_pw_new(struct l2vpn * l2vpn,struct kif * kif)159 l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif)
160 {
161 	struct l2vpn_pw	*pw;
162 
163 	if ((pw = calloc(1, sizeof(*pw))) == NULL)
164 		fatal("l2vpn_pw_new: calloc");
165 
166 	pw->l2vpn = l2vpn;
167 	strlcpy(pw->ifname, kif->ifname, sizeof(pw->ifname));
168 	pw->ifindex = kif->ifindex;
169 
170 	return (pw);
171 }
172 
173 struct l2vpn_pw *
l2vpn_pw_find(struct l2vpn * l2vpn,unsigned int ifindex)174 l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex)
175 {
176 	struct l2vpn_pw	*pw;
177 
178 	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
179 		if (pw->ifindex == ifindex)
180 			return (pw);
181 
182 	return (NULL);
183 }
184 
185 void
l2vpn_pw_init(struct l2vpn_pw * pw)186 l2vpn_pw_init(struct l2vpn_pw *pw)
187 {
188 	struct fec	 fec;
189 
190 	l2vpn_pw_reset(pw);
191 
192 	l2vpn_pw_fec(pw, &fec);
193 	lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0,
194 	    0, (void *)pw);
195 }
196 
197 void
l2vpn_pw_exit(struct l2vpn_pw * pw)198 l2vpn_pw_exit(struct l2vpn_pw *pw)
199 {
200 	struct fec	 fec;
201 
202 	l2vpn_pw_fec(pw, &fec);
203 	lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0);
204 }
205 
206 static void
l2vpn_pw_fec(struct l2vpn_pw * pw,struct fec * fec)207 l2vpn_pw_fec(struct l2vpn_pw *pw, struct fec *fec)
208 {
209 	memset(fec, 0, sizeof(*fec));
210 	fec->type = FEC_TYPE_PWID;
211 	fec->u.pwid.type = pw->l2vpn->pw_type;
212 	fec->u.pwid.pwid = pw->pwid;
213 	fec->u.pwid.lsr_id = pw->lsr_id;
214 }
215 
216 void
l2vpn_pw_reset(struct l2vpn_pw * pw)217 l2vpn_pw_reset(struct l2vpn_pw *pw)
218 {
219 	pw->remote_group = 0;
220 	pw->remote_mtu = 0;
221 	pw->remote_status = 0;
222 
223 	if (pw->flags & F_PW_CWORD_CONF)
224 		pw->flags |= F_PW_CWORD;
225 	else
226 		pw->flags &= ~F_PW_CWORD;
227 
228 	if (pw->flags & F_PW_STATUSTLV_CONF)
229 		pw->flags |= F_PW_STATUSTLV;
230 	else
231 		pw->flags &= ~F_PW_STATUSTLV;
232 }
233 
234 int
l2vpn_pw_ok(struct l2vpn_pw * pw,struct fec_nh * fnh)235 l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
236 {
237 	struct fec		 fec;
238 	struct fec_node		*fn;
239 
240 	/* check for a remote label */
241 	if (fnh->remote_label == NO_LABEL)
242 		return (0);
243 
244 	/* MTUs must match */
245 	if (pw->l2vpn->mtu != pw->remote_mtu)
246 		return (0);
247 
248 	/* check pw status if applicable */
249 	if ((pw->flags & F_PW_STATUSTLV) &&
250 	    pw->remote_status != PW_FORWARDING)
251 		return (0);
252 
253 	/* check for a working lsp to the nexthop */
254 	memset(&fec, 0, sizeof(fec));
255 	switch (pw->af) {
256 	case AF_INET:
257 		fec.type = FEC_TYPE_IPV4;
258 		fec.u.ipv4.prefix = pw->addr.v4;
259 		fec.u.ipv4.prefixlen = 32;
260 		break;
261 	case AF_INET6:
262 		fec.type = FEC_TYPE_IPV6;
263 		fec.u.ipv6.prefix = pw->addr.v6;
264 		fec.u.ipv6.prefixlen = 128;
265 		break;
266 	default:
267 		fatalx("l2vpn_pw_ok: unknown af");
268 	}
269 
270 	fn = (struct fec_node *)fec_find(&ft, &fec);
271 	if (fn == NULL || fn->local_label == NO_LABEL)
272 		return (0);
273 	/*
274 	 * Need to ensure that there's a label binding for all nexthops.
275 	 * Otherwise, ECMP for this route could render the pseudowire unusable.
276 	 */
277 	LIST_FOREACH(fnh, &fn->nexthops, entry)
278 		if (fnh->remote_label == NO_LABEL)
279 			return (0);
280 
281 	return (1);
282 }
283 
284 int
l2vpn_pw_negotiate(struct lde_nbr * ln,struct fec_node * fn,struct map * map)285 l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
286 {
287 	struct l2vpn_pw		*pw;
288 	struct status_tlv	 st;
289 
290 	/* NOTE: thanks martini & friends for all this mess */
291 
292 	pw = (struct l2vpn_pw *) fn->data;
293 	if (pw == NULL)
294 		/*
295 		 * pseudowire not configured, return and record
296 		 * the mapping later
297 		 */
298 		return (0);
299 
300 	/* RFC4447 - Section 6.2: control word negotiation */
301 	if (fec_find(&ln->sent_map, &fn->fec)) {
302 		if ((map->flags & F_MAP_PW_CWORD) &&
303 		    !(pw->flags & F_PW_CWORD_CONF)) {
304 			/* ignore the received label mapping */
305 			return (1);
306 		} else if (!(map->flags & F_MAP_PW_CWORD) &&
307 		    (pw->flags & F_PW_CWORD_CONF)) {
308 			/* append a "Wrong C-bit" status code */
309 			st.status_code = S_WRONG_CBIT;
310 			st.msg_id = map->msg_id;
311 			st.msg_type = htons(MSG_TYPE_LABELMAPPING);
312 			lde_send_labelwithdraw(ln, fn, NULL, &st);
313 
314 			pw->flags &= ~F_PW_CWORD;
315 			lde_send_labelmapping(ln, fn, 1);
316 		}
317 	} else if (map->flags & F_MAP_PW_CWORD) {
318 		if (pw->flags & F_PW_CWORD_CONF)
319 			pw->flags |= F_PW_CWORD;
320 		else
321 			/* act as if no label mapping had been received */
322 			return (1);
323 	} else
324 		pw->flags &= ~F_PW_CWORD;
325 
326 	/* RFC4447 - Section 5.4.3: pseudowire status negotiation */
327 	if (fec_find(&ln->recv_map, &fn->fec) == NULL &&
328 	    !(map->flags & F_MAP_PW_STATUS))
329 		pw->flags &= ~F_PW_STATUSTLV;
330 
331 	return (0);
332 }
333 
334 void
l2vpn_send_pw_status(struct lde_nbr * ln,uint32_t status,struct fec * fec)335 l2vpn_send_pw_status(struct lde_nbr *ln, uint32_t status, struct fec *fec)
336 {
337 	struct notify_msg	 nm;
338 
339 	memset(&nm, 0, sizeof(nm));
340 	nm.status_code = S_PW_STATUS;
341 	nm.pw_status = status;
342 	nm.flags |= F_NOTIF_PW_STATUS;
343 	lde_fec2map(fec, &nm.fec);
344 	nm.flags |= F_NOTIF_FEC;
345 
346 	lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
347 	    sizeof(nm));
348 }
349 
350 void
l2vpn_send_pw_status_wcard(struct lde_nbr * ln,uint32_t status,uint16_t pw_type,uint32_t group_id)351 l2vpn_send_pw_status_wcard(struct lde_nbr *ln, uint32_t status,
352     uint16_t pw_type, uint32_t group_id)
353 {
354 	struct notify_msg	 nm;
355 
356 	memset(&nm, 0, sizeof(nm));
357 	nm.status_code = S_PW_STATUS;
358 	nm.pw_status = status;
359 	nm.flags |= F_NOTIF_PW_STATUS;
360 	nm.fec.type = MAP_TYPE_PWID;
361 	nm.fec.fec.pwid.type = pw_type;
362 	nm.fec.fec.pwid.group_id = group_id;
363 	nm.flags |= F_NOTIF_FEC;
364 
365 	lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
366 	    sizeof(nm));
367 }
368 
369 void
l2vpn_recv_pw_status(struct lde_nbr * ln,struct notify_msg * nm)370 l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
371 {
372 	struct fec		 fec;
373 	struct fec_node		*fn;
374 	struct fec_nh		*fnh;
375 	struct l2vpn_pw		*pw;
376 
377 	if (nm->fec.type == MAP_TYPE_TYPED_WCARD ||
378 	    !(nm->fec.flags & F_MAP_PW_ID)) {
379 		l2vpn_recv_pw_status_wcard(ln, nm);
380 		return;
381 	}
382 
383 	lde_map2fec(&nm->fec, ln->id, &fec);
384 	fn = (struct fec_node *)fec_find(&ft, &fec);
385 	if (fn == NULL)
386 		/* unknown fec */
387 		return;
388 
389 	pw = (struct l2vpn_pw *) fn->data;
390 	if (pw == NULL)
391 		return;
392 
393 	fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0);
394 	if (fnh == NULL)
395 		return;
396 
397 	/* remote status didn't change */
398 	if (pw->remote_status == nm->pw_status)
399 		return;
400 	pw->remote_status = nm->pw_status;
401 
402 	if (l2vpn_pw_ok(pw, fnh))
403 		lde_send_change_klabel(fn, fnh);
404 	else
405 		lde_send_delete_klabel(fn, fnh);
406 }
407 
408 /* RFC4447 PWid group wildcard */
409 void
l2vpn_recv_pw_status_wcard(struct lde_nbr * ln,struct notify_msg * nm)410 l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
411 {
412 	struct fec		*f;
413 	struct fec_node		*fn;
414 	struct fec_nh		*fnh;
415 	struct l2vpn_pw		*pw;
416 	struct map		*wcard = &nm->fec;
417 
418 	RB_FOREACH(f, fec_tree, &ft) {
419 		fn = (struct fec_node *)f;
420 		if (fn->fec.type != FEC_TYPE_PWID)
421 			continue;
422 
423 		pw = (struct l2vpn_pw *) fn->data;
424 		if (pw == NULL)
425 			continue;
426 
427 		switch (wcard->type) {
428 		case MAP_TYPE_TYPED_WCARD:
429 			if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
430 			    wcard->fec.twcard.u.pw_type != fn->fec.u.pwid.type)
431 				continue;
432 			break;
433 		case MAP_TYPE_PWID:
434 			if (wcard->fec.pwid.type != fn->fec.u.pwid.type)
435 				continue;
436 			if (wcard->fec.pwid.group_id != pw->remote_group)
437 				continue;
438 			break;
439 		}
440 
441 		fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0);
442 		if (fnh == NULL)
443 			continue;
444 
445 		/* remote status didn't change */
446 		if (pw->remote_status == nm->pw_status)
447 			continue;
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 
457 void
l2vpn_sync_pws(int af,union ldpd_addr * addr)458 l2vpn_sync_pws(int af, union ldpd_addr *addr)
459 {
460 	struct l2vpn		*l2vpn;
461 	struct l2vpn_pw		*pw;
462 	struct fec		 fec;
463 	struct fec_node		*fn;
464 	struct fec_nh		*fnh;
465 
466 	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) {
467 		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
468 			if (af != pw->af || ldp_addrcmp(af, &pw->addr, addr))
469 				continue;
470 
471 			l2vpn_pw_fec(pw, &fec);
472 			fn = (struct fec_node *)fec_find(&ft, &fec);
473 			if (fn == NULL)
474 				continue;
475 			fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)
476 			    &pw->lsr_id, 0);
477 			if (fnh == NULL)
478 				continue;
479 
480 			if (l2vpn_pw_ok(pw, fnh))
481 				lde_send_change_klabel(fn, fnh);
482 			else
483 				lde_send_delete_klabel(fn, fnh);
484 		}
485 	}
486 }
487 
488 void
l2vpn_pw_ctl(pid_t pid)489 l2vpn_pw_ctl(pid_t pid)
490 {
491 	struct l2vpn		*l2vpn;
492 	struct l2vpn_pw		*pw;
493 	static struct ctl_pw	 pwctl;
494 
495 	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
496 		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
497 			memset(&pwctl, 0, sizeof(pwctl));
498 			strlcpy(pwctl.ifname, pw->ifname,
499 			    sizeof(pwctl.ifname));
500 			pwctl.pwid = pw->pwid;
501 			pwctl.lsr_id = pw->lsr_id;
502 			pwctl.status = pw->flags & F_PW_STATUS_UP;
503 
504 			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
505 			    pid, &pwctl, sizeof(pwctl));
506 		}
507 }
508 
509 void
l2vpn_binding_ctl(pid_t pid)510 l2vpn_binding_ctl(pid_t pid)
511 {
512 	struct fec		*f;
513 	struct fec_node		*fn;
514 	struct lde_map		*me;
515 	struct l2vpn_pw		*pw;
516 	static struct ctl_pw	 pwctl;
517 
518 	RB_FOREACH(f, fec_tree, &ft) {
519 		if (f->type != FEC_TYPE_PWID)
520 			continue;
521 
522 		fn = (struct fec_node *)f;
523 		if (fn->local_label == NO_LABEL &&
524 		    LIST_EMPTY(&fn->downstream))
525 			continue;
526 
527 		memset(&pwctl, 0, sizeof(pwctl));
528 		pwctl.type = f->u.pwid.type;
529 		pwctl.pwid = f->u.pwid.pwid;
530 		pwctl.lsr_id = f->u.pwid.lsr_id;
531 
532 		pw = (struct l2vpn_pw *) fn->data;
533 		if (pw) {
534 			pwctl.local_label = fn->local_label;
535 			pwctl.local_gid = 0;
536 			pwctl.local_ifmtu = pw->l2vpn->mtu;
537 		} else
538 			pwctl.local_label = NO_LABEL;
539 
540 		LIST_FOREACH(me, &fn->downstream, entry)
541 			if (f->u.pwid.lsr_id.s_addr == me->nexthop->id.s_addr)
542 				break;
543 
544 		if (me) {
545 			pwctl.remote_label = me->map.label;
546 			pwctl.remote_gid = me->map.fec.pwid.group_id;
547 			if (me->map.flags & F_MAP_PW_IFMTU)
548 				pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
549 
550 			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
551 			    0, pid, &pwctl, sizeof(pwctl));
552 		} else if (pw) {
553 			pwctl.remote_label = NO_LABEL;
554 
555 			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
556 			    0, pid, &pwctl, sizeof(pwctl));
557 		}
558 	}
559 }
560 
561 /* ldpe */
562 
563 void
ldpe_l2vpn_init(struct l2vpn * l2vpn)564 ldpe_l2vpn_init(struct l2vpn *l2vpn)
565 {
566 	struct l2vpn_pw		*pw;
567 
568 	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
569 		ldpe_l2vpn_pw_init(pw);
570 }
571 
572 void
ldpe_l2vpn_exit(struct l2vpn * l2vpn)573 ldpe_l2vpn_exit(struct l2vpn *l2vpn)
574 {
575 	struct l2vpn_pw		*pw;
576 
577 	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
578 		ldpe_l2vpn_pw_exit(pw);
579 }
580 
581 void
ldpe_l2vpn_pw_init(struct l2vpn_pw * pw)582 ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
583 {
584 	struct tnbr		*tnbr;
585 
586 	tnbr = tnbr_find(leconf, pw->af, &pw->addr);
587 	if (tnbr == NULL) {
588 		tnbr = tnbr_new(leconf, pw->af, &pw->addr);
589 		tnbr_update(tnbr);
590 		LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
591 	}
592 
593 	tnbr->pw_count++;
594 }
595 
596 void
ldpe_l2vpn_pw_exit(struct l2vpn_pw * pw)597 ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
598 {
599 	struct tnbr		*tnbr;
600 
601 	tnbr = tnbr_find(leconf, pw->af, &pw->addr);
602 	if (tnbr) {
603 		tnbr->pw_count--;
604 		tnbr_check(tnbr);
605 	}
606 }
607