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