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