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