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