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