]>
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 | 119 | struct l2vpn_if * |
52b530fc | 120 | l2vpn_if_new(struct l2vpn *l2vpn, const char *ifname) |
8429abe0 RW |
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; | |
52b530fc | 128 | strlcpy(lif->ifname, ifname, sizeof(lif->ifname)); |
8429abe0 RW |
129 | |
130 | return (lif); | |
131 | } | |
132 | ||
133 | struct l2vpn_if * | |
52bd4c23 | 134 | l2vpn_if_find(struct l2vpn *l2vpn, const char *ifname) |
eac6e3f0 | 135 | { |
029c1958 RW |
136 | struct l2vpn_if lif; |
137 | strlcpy(lif.ifname, ifname, sizeof(lif.ifname)); | |
138 | return (RB_FIND(l2vpn_if_head, &l2vpn->if_tree, &lif)); | |
eac6e3f0 RW |
139 | } |
140 | ||
52b530fc RW |
141 | void |
142 | l2vpn_if_update_info(struct l2vpn_if *lif, struct kif *kif) | |
143 | { | |
144 | lif->ifindex = kif->ifindex; | |
988ded8d | 145 | lif->operative = kif->operative; |
52b530fc RW |
146 | memcpy(lif->mac, kif->mac, sizeof(lif->mac)); |
147 | } | |
148 | ||
26519d8c RW |
149 | void |
150 | l2vpn_if_update(struct l2vpn_if *lif) | |
151 | { | |
152 | struct l2vpn *l2vpn = lif->l2vpn; | |
153 | struct l2vpn_pw *pw; | |
154 | struct map fec; | |
155 | struct nbr *nbr; | |
156 | ||
988ded8d | 157 | if (lif->operative) |
26519d8c RW |
158 | return; |
159 | ||
160 | RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) { | |
161 | nbr = nbr_find_ldpid(pw->lsr_id.s_addr); | |
162 | if (nbr == NULL) | |
163 | continue; | |
164 | ||
165 | memset(&fec, 0, sizeof(fec)); | |
166 | fec.type = MAP_TYPE_PWID; | |
167 | fec.fec.pwid.type = l2vpn->pw_type; | |
168 | fec.fec.pwid.group_id = 0; | |
169 | fec.flags |= F_MAP_PW_ID; | |
170 | fec.fec.pwid.pwid = pw->pwid; | |
171 | ||
172 | send_mac_withdrawal(nbr, &fec, lif->mac); | |
173 | } | |
174 | } | |
175 | ||
20bacaeb RW |
176 | static __inline int |
177 | l2vpn_pw_compare(struct l2vpn_pw *a, struct l2vpn_pw *b) | |
178 | { | |
179 | return (strcmp(a->ifname, b->ifname)); | |
180 | } | |
eac6e3f0 | 181 | |
8429abe0 | 182 | struct l2vpn_pw * |
52b530fc | 183 | l2vpn_pw_new(struct l2vpn *l2vpn, const char *ifname) |
8429abe0 RW |
184 | { |
185 | struct l2vpn_pw *pw; | |
186 | ||
187 | if ((pw = calloc(1, sizeof(*pw))) == NULL) | |
188 | fatal("l2vpn_pw_new: calloc"); | |
189 | ||
190 | pw->l2vpn = l2vpn; | |
52b530fc | 191 | strlcpy(pw->ifname, ifname, sizeof(pw->ifname)); |
8429abe0 RW |
192 | |
193 | return (pw); | |
194 | } | |
195 | ||
196 | struct l2vpn_pw * | |
52bd4c23 | 197 | l2vpn_pw_find(struct l2vpn *l2vpn, const char *ifname) |
eac6e3f0 RW |
198 | { |
199 | struct l2vpn_pw *pw; | |
20bacaeb | 200 | struct l2vpn_pw s; |
eac6e3f0 | 201 | |
20bacaeb RW |
202 | strlcpy(s.ifname, ifname, sizeof(s.ifname)); |
203 | pw = RB_FIND(l2vpn_pw_head, &l2vpn->pw_tree, &s); | |
204 | if (pw) | |
205 | return (pw); | |
206 | return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_inactive_tree, &s)); | |
8429abe0 RW |
207 | } |
208 | ||
5c3f00af RW |
209 | struct l2vpn_pw * |
210 | l2vpn_pw_find_active(struct l2vpn *l2vpn, const char *ifname) | |
211 | { | |
212 | struct l2vpn_pw s; | |
213 | ||
214 | strlcpy(s.ifname, ifname, sizeof(s.ifname)); | |
215 | return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_tree, &s)); | |
216 | } | |
217 | ||
218 | struct l2vpn_pw * | |
219 | l2vpn_pw_find_inactive(struct l2vpn *l2vpn, const char *ifname) | |
220 | { | |
221 | struct l2vpn_pw s; | |
222 | ||
223 | strlcpy(s.ifname, ifname, sizeof(s.ifname)); | |
224 | return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_inactive_tree, &s)); | |
225 | } | |
226 | ||
52b530fc RW |
227 | void |
228 | l2vpn_pw_update_info(struct l2vpn_pw *pw, struct kif *kif) | |
229 | { | |
230 | pw->ifindex = kif->ifindex; | |
231 | } | |
232 | ||
8429abe0 RW |
233 | void |
234 | l2vpn_pw_init(struct l2vpn_pw *pw) | |
235 | { | |
236 | struct fec fec; | |
237 | ||
238 | l2vpn_pw_reset(pw); | |
239 | ||
240 | l2vpn_pw_fec(pw, &fec); | |
88d88a9c | 241 | lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, |
8429abe0 | 242 | 0, (void *)pw); |
8cb1fc45 | 243 | lde_kernel_update(&fec); |
8429abe0 RW |
244 | } |
245 | ||
246 | void | |
247 | l2vpn_pw_exit(struct l2vpn_pw *pw) | |
248 | { | |
249 | struct fec fec; | |
250 | ||
251 | l2vpn_pw_fec(pw, &fec); | |
88d88a9c | 252 | lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0); |
8cb1fc45 | 253 | lde_kernel_update(&fec); |
8429abe0 RW |
254 | } |
255 | ||
256 | static void | |
257 | l2vpn_pw_fec(struct l2vpn_pw *pw, struct fec *fec) | |
258 | { | |
259 | memset(fec, 0, sizeof(*fec)); | |
260 | fec->type = FEC_TYPE_PWID; | |
261 | fec->u.pwid.type = pw->l2vpn->pw_type; | |
262 | fec->u.pwid.pwid = pw->pwid; | |
263 | fec->u.pwid.lsr_id = pw->lsr_id; | |
264 | } | |
265 | ||
266 | void | |
267 | l2vpn_pw_reset(struct l2vpn_pw *pw) | |
268 | { | |
269 | pw->remote_group = 0; | |
270 | pw->remote_mtu = 0; | |
271 | pw->remote_status = 0; | |
272 | ||
273 | if (pw->flags & F_PW_CWORD_CONF) | |
274 | pw->flags |= F_PW_CWORD; | |
275 | else | |
276 | pw->flags &= ~F_PW_CWORD; | |
277 | ||
278 | if (pw->flags & F_PW_STATUSTLV_CONF) | |
279 | pw->flags |= F_PW_STATUSTLV; | |
280 | else | |
281 | pw->flags &= ~F_PW_STATUSTLV; | |
282 | } | |
283 | ||
284 | int | |
285 | l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh) | |
286 | { | |
8429abe0 RW |
287 | /* check for a remote label */ |
288 | if (fnh->remote_label == NO_LABEL) | |
289 | return (0); | |
290 | ||
291 | /* MTUs must match */ | |
292 | if (pw->l2vpn->mtu != pw->remote_mtu) | |
293 | return (0); | |
294 | ||
295 | /* check pw status if applicable */ | |
296 | if ((pw->flags & F_PW_STATUSTLV) && | |
297 | pw->remote_status != PW_FORWARDING) | |
298 | return (0); | |
299 | ||
8429abe0 RW |
300 | return (1); |
301 | } | |
302 | ||
303 | int | |
304 | l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map) | |
305 | { | |
306 | struct l2vpn_pw *pw; | |
307 | struct status_tlv st; | |
308 | ||
309 | /* NOTE: thanks martini & friends for all this mess */ | |
310 | ||
311 | pw = (struct l2vpn_pw *) fn->data; | |
312 | if (pw == NULL) | |
313 | /* | |
314 | * pseudowire not configured, return and record | |
315 | * the mapping later | |
316 | */ | |
317 | return (0); | |
318 | ||
319 | /* RFC4447 - Section 6.2: control word negotiation */ | |
320 | if (fec_find(&ln->sent_map, &fn->fec)) { | |
321 | if ((map->flags & F_MAP_PW_CWORD) && | |
322 | !(pw->flags & F_PW_CWORD_CONF)) { | |
323 | /* ignore the received label mapping */ | |
324 | return (1); | |
325 | } else if (!(map->flags & F_MAP_PW_CWORD) && | |
326 | (pw->flags & F_PW_CWORD_CONF)) { | |
327 | /* append a "Wrong C-bit" status code */ | |
328 | st.status_code = S_WRONG_CBIT; | |
329 | st.msg_id = map->msg_id; | |
330 | st.msg_type = htons(MSG_TYPE_LABELMAPPING); | |
0bcc2916 | 331 | lde_send_labelwithdraw(ln, fn, NULL, &st); |
8429abe0 RW |
332 | |
333 | pw->flags &= ~F_PW_CWORD; | |
334 | lde_send_labelmapping(ln, fn, 1); | |
335 | } | |
336 | } else if (map->flags & F_MAP_PW_CWORD) { | |
337 | if (pw->flags & F_PW_CWORD_CONF) | |
338 | pw->flags |= F_PW_CWORD; | |
339 | else | |
340 | /* act as if no label mapping had been received */ | |
341 | return (1); | |
342 | } else | |
343 | pw->flags &= ~F_PW_CWORD; | |
344 | ||
345 | /* RFC4447 - Section 5.4.3: pseudowire status negotiation */ | |
346 | if (fec_find(&ln->recv_map, &fn->fec) == NULL && | |
347 | !(map->flags & F_MAP_PW_STATUS)) | |
348 | pw->flags &= ~F_PW_STATUSTLV; | |
349 | ||
350 | return (0); | |
351 | } | |
352 | ||
353 | void | |
0bcc2916 | 354 | l2vpn_send_pw_status(struct lde_nbr *ln, uint32_t status, struct fec *fec) |
8429abe0 RW |
355 | { |
356 | struct notify_msg nm; | |
357 | ||
358 | memset(&nm, 0, sizeof(nm)); | |
359 | nm.status_code = S_PW_STATUS; | |
360 | nm.pw_status = status; | |
361 | nm.flags |= F_NOTIF_PW_STATUS; | |
362 | lde_fec2map(fec, &nm.fec); | |
363 | nm.flags |= F_NOTIF_FEC; | |
364 | ||
0bcc2916 RW |
365 | lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, |
366 | sizeof(nm)); | |
367 | } | |
368 | ||
369 | void | |
370 | l2vpn_send_pw_status_wcard(struct lde_nbr *ln, uint32_t status, | |
371 | uint16_t pw_type, uint32_t group_id) | |
372 | { | |
373 | struct notify_msg nm; | |
374 | ||
375 | memset(&nm, 0, sizeof(nm)); | |
376 | nm.status_code = S_PW_STATUS; | |
377 | nm.pw_status = status; | |
378 | nm.flags |= F_NOTIF_PW_STATUS; | |
379 | nm.fec.type = MAP_TYPE_PWID; | |
380 | nm.fec.fec.pwid.type = pw_type; | |
381 | nm.fec.fec.pwid.group_id = group_id; | |
382 | nm.flags |= F_NOTIF_FEC; | |
383 | ||
384 | lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, | |
385 | sizeof(nm)); | |
8429abe0 RW |
386 | } |
387 | ||
388 | void | |
389 | l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) | |
390 | { | |
391 | struct fec fec; | |
392 | struct fec_node *fn; | |
393 | struct fec_nh *fnh; | |
394 | struct l2vpn_pw *pw; | |
395 | ||
aba50a83 RW |
396 | if (nm->fec.type == MAP_TYPE_TYPED_WCARD || |
397 | !(nm->fec.flags & F_MAP_PW_ID)) { | |
0bcc2916 | 398 | l2vpn_recv_pw_status_wcard(ln, nm); |
8429abe0 | 399 | return; |
0bcc2916 | 400 | } |
8429abe0 RW |
401 | |
402 | lde_map2fec(&nm->fec, ln->id, &fec); | |
403 | fn = (struct fec_node *)fec_find(&ft, &fec); | |
404 | if (fn == NULL) | |
405 | /* unknown fec */ | |
406 | return; | |
407 | ||
408 | pw = (struct l2vpn_pw *) fn->data; | |
409 | if (pw == NULL) | |
410 | return; | |
411 | ||
88d88a9c | 412 | fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0); |
8429abe0 RW |
413 | if (fnh == NULL) |
414 | return; | |
415 | ||
416 | /* remote status didn't change */ | |
417 | if (pw->remote_status == nm->pw_status) | |
418 | return; | |
8429abe0 RW |
419 | pw->remote_status = nm->pw_status; |
420 | ||
421 | if (l2vpn_pw_ok(pw, fnh)) | |
422 | lde_send_change_klabel(fn, fnh); | |
423 | else | |
424 | lde_send_delete_klabel(fn, fnh); | |
425 | } | |
426 | ||
0bcc2916 RW |
427 | /* RFC4447 PWid group wildcard */ |
428 | void | |
429 | l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) | |
430 | { | |
431 | struct fec *f; | |
432 | struct fec_node *fn; | |
433 | struct fec_nh *fnh; | |
434 | struct l2vpn_pw *pw; | |
aba50a83 | 435 | struct map *wcard = &nm->fec; |
0bcc2916 RW |
436 | |
437 | RB_FOREACH(f, fec_tree, &ft) { | |
438 | fn = (struct fec_node *)f; | |
439 | if (fn->fec.type != FEC_TYPE_PWID) | |
440 | continue; | |
0bcc2916 RW |
441 | |
442 | pw = (struct l2vpn_pw *) fn->data; | |
443 | if (pw == NULL) | |
444 | continue; | |
aba50a83 RW |
445 | |
446 | switch (wcard->type) { | |
447 | case MAP_TYPE_TYPED_WCARD: | |
448 | if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD && | |
449 | wcard->fec.twcard.u.pw_type != fn->fec.u.pwid.type) | |
450 | continue; | |
451 | break; | |
452 | case MAP_TYPE_PWID: | |
453 | if (wcard->fec.pwid.type != fn->fec.u.pwid.type) | |
454 | continue; | |
455 | if (wcard->fec.pwid.group_id != pw->remote_group) | |
456 | continue; | |
457 | break; | |
458 | } | |
0bcc2916 RW |
459 | |
460 | fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, | |
461 | 0, 0); | |
462 | if (fnh == NULL) | |
463 | continue; | |
464 | ||
465 | /* remote status didn't change */ | |
466 | if (pw->remote_status == nm->pw_status) | |
467 | continue; | |
468 | pw->remote_status = nm->pw_status; | |
469 | ||
470 | if (l2vpn_pw_ok(pw, fnh)) | |
471 | lde_send_change_klabel(fn, fnh); | |
472 | else | |
473 | lde_send_delete_klabel(fn, fnh); | |
474 | } | |
475 | } | |
476 | ||
8429abe0 RW |
477 | void |
478 | l2vpn_pw_ctl(pid_t pid) | |
479 | { | |
480 | struct l2vpn *l2vpn; | |
481 | struct l2vpn_pw *pw; | |
482 | static struct ctl_pw pwctl; | |
483 | ||
90d7e7bd | 484 | RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) |
20bacaeb | 485 | RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) { |
8429abe0 | 486 | memset(&pwctl, 0, sizeof(pwctl)); |
eac6e3f0 RW |
487 | strlcpy(pwctl.l2vpn_name, pw->l2vpn->name, |
488 | sizeof(pwctl.l2vpn_name)); | |
8429abe0 RW |
489 | strlcpy(pwctl.ifname, pw->ifname, |
490 | sizeof(pwctl.ifname)); | |
491 | pwctl.pwid = pw->pwid; | |
492 | pwctl.lsr_id = pw->lsr_id; | |
493 | pwctl.status = pw->flags & F_PW_STATUS_UP; | |
494 | ||
495 | lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0, | |
496 | pid, &pwctl, sizeof(pwctl)); | |
497 | } | |
498 | } | |
499 | ||
500 | void | |
501 | l2vpn_binding_ctl(pid_t pid) | |
502 | { | |
503 | struct fec *f; | |
504 | struct fec_node *fn; | |
505 | struct lde_map *me; | |
506 | struct l2vpn_pw *pw; | |
507 | static struct ctl_pw pwctl; | |
508 | ||
509 | RB_FOREACH(f, fec_tree, &ft) { | |
510 | if (f->type != FEC_TYPE_PWID) | |
511 | continue; | |
512 | ||
513 | fn = (struct fec_node *)f; | |
514 | if (fn->local_label == NO_LABEL && | |
d3e1887a | 515 | RB_EMPTY(&fn->downstream)) |
8429abe0 RW |
516 | continue; |
517 | ||
518 | memset(&pwctl, 0, sizeof(pwctl)); | |
519 | pwctl.type = f->u.pwid.type; | |
520 | pwctl.pwid = f->u.pwid.pwid; | |
521 | pwctl.lsr_id = f->u.pwid.lsr_id; | |
522 | ||
523 | pw = (struct l2vpn_pw *) fn->data; | |
524 | if (pw) { | |
525 | pwctl.local_label = fn->local_label; | |
526 | pwctl.local_gid = 0; | |
527 | pwctl.local_ifmtu = pw->l2vpn->mtu; | |
eac6e3f0 RW |
528 | pwctl.local_cword = (pw->flags & F_PW_CWORD_CONF) ? |
529 | 1 : 0; | |
8429abe0 RW |
530 | } else |
531 | pwctl.local_label = NO_LABEL; | |
532 | ||
d3e1887a | 533 | RB_FOREACH(me, lde_map_head, &fn->downstream) |
8429abe0 RW |
534 | if (f->u.pwid.lsr_id.s_addr == me->nexthop->id.s_addr) |
535 | break; | |
536 | ||
537 | if (me) { | |
538 | pwctl.remote_label = me->map.label; | |
539 | pwctl.remote_gid = me->map.fec.pwid.group_id; | |
540 | if (me->map.flags & F_MAP_PW_IFMTU) | |
541 | pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu; | |
eac6e3f0 RW |
542 | if (pw) |
543 | pwctl.remote_cword = (pw->flags & F_PW_CWORD) ? | |
544 | 1 : 0; | |
8429abe0 RW |
545 | |
546 | lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING, | |
547 | 0, pid, &pwctl, sizeof(pwctl)); | |
548 | } else if (pw) { | |
549 | pwctl.remote_label = NO_LABEL; | |
550 | ||
551 | lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING, | |
552 | 0, pid, &pwctl, sizeof(pwctl)); | |
553 | } | |
554 | } | |
555 | } | |
556 | ||
557 | /* ldpe */ | |
558 | ||
559 | void | |
560 | ldpe_l2vpn_init(struct l2vpn *l2vpn) | |
561 | { | |
562 | struct l2vpn_pw *pw; | |
563 | ||
20bacaeb | 564 | RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) |
8429abe0 RW |
565 | ldpe_l2vpn_pw_init(pw); |
566 | } | |
567 | ||
568 | void | |
569 | ldpe_l2vpn_exit(struct l2vpn *l2vpn) | |
570 | { | |
571 | struct l2vpn_pw *pw; | |
572 | ||
20bacaeb | 573 | RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) |
8429abe0 RW |
574 | ldpe_l2vpn_pw_exit(pw); |
575 | } | |
576 | ||
577 | void | |
578 | ldpe_l2vpn_pw_init(struct l2vpn_pw *pw) | |
579 | { | |
580 | struct tnbr *tnbr; | |
581 | ||
582 | tnbr = tnbr_find(leconf, pw->af, &pw->addr); | |
583 | if (tnbr == NULL) { | |
eac6e3f0 | 584 | tnbr = tnbr_new(pw->af, &pw->addr); |
8429abe0 | 585 | tnbr_update(tnbr); |
7989cdba | 586 | RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr); |
8429abe0 RW |
587 | } |
588 | ||
589 | tnbr->pw_count++; | |
590 | } | |
591 | ||
592 | void | |
593 | ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw) | |
594 | { | |
595 | struct tnbr *tnbr; | |
596 | ||
597 | tnbr = tnbr_find(leconf, pw->af, &pw->addr); | |
598 | if (tnbr) { | |
599 | tnbr->pw_count--; | |
7989cdba | 600 | tnbr_check(leconf, tnbr); |
8429abe0 RW |
601 | } |
602 | } |