]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/l2vpn.c
ldpd: copy original sources from OpenBSD (14/09/2016)
[mirror_frr.git] / ldpd / l2vpn.c
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
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->link_state = 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 struct l2vpn_pw *
132 l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif)
133 {
134 struct l2vpn_pw *pw;
135
136 if ((pw = calloc(1, sizeof(*pw))) == NULL)
137 fatal("l2vpn_pw_new: calloc");
138
139 pw->l2vpn = l2vpn;
140 strlcpy(pw->ifname, kif->ifname, sizeof(pw->ifname));
141 pw->ifindex = kif->ifindex;
142
143 return (pw);
144 }
145
146 struct l2vpn_pw *
147 l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex)
148 {
149 struct l2vpn_pw *pw;
150
151 LIST_FOREACH(pw, &l2vpn->pw_list, entry)
152 if (pw->ifindex == ifindex)
153 return (pw);
154
155 return (NULL);
156 }
157
158 void
159 l2vpn_pw_init(struct l2vpn_pw *pw)
160 {
161 struct fec fec;
162
163 l2vpn_pw_reset(pw);
164
165 l2vpn_pw_fec(pw, &fec);
166 lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0,
167 0, (void *)pw);
168 }
169
170 void
171 l2vpn_pw_exit(struct l2vpn_pw *pw)
172 {
173 struct fec fec;
174
175 l2vpn_pw_fec(pw, &fec);
176 lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0);
177 }
178
179 static void
180 l2vpn_pw_fec(struct l2vpn_pw *pw, struct fec *fec)
181 {
182 memset(fec, 0, sizeof(*fec));
183 fec->type = FEC_TYPE_PWID;
184 fec->u.pwid.type = pw->l2vpn->pw_type;
185 fec->u.pwid.pwid = pw->pwid;
186 fec->u.pwid.lsr_id = pw->lsr_id;
187 }
188
189 void
190 l2vpn_pw_reset(struct l2vpn_pw *pw)
191 {
192 pw->remote_group = 0;
193 pw->remote_mtu = 0;
194 pw->remote_status = 0;
195
196 if (pw->flags & F_PW_CWORD_CONF)
197 pw->flags |= F_PW_CWORD;
198 else
199 pw->flags &= ~F_PW_CWORD;
200
201 if (pw->flags & F_PW_STATUSTLV_CONF)
202 pw->flags |= F_PW_STATUSTLV;
203 else
204 pw->flags &= ~F_PW_STATUSTLV;
205 }
206
207 int
208 l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
209 {
210 struct fec fec;
211 struct fec_node *fn;
212
213 /* check for a remote label */
214 if (fnh->remote_label == NO_LABEL)
215 return (0);
216
217 /* MTUs must match */
218 if (pw->l2vpn->mtu != pw->remote_mtu)
219 return (0);
220
221 /* check pw status if applicable */
222 if ((pw->flags & F_PW_STATUSTLV) &&
223 pw->remote_status != PW_FORWARDING)
224 return (0);
225
226 /* check for a working lsp to the nexthop */
227 memset(&fec, 0, sizeof(fec));
228 switch (pw->af) {
229 case AF_INET:
230 fec.type = FEC_TYPE_IPV4;
231 fec.u.ipv4.prefix = pw->addr.v4;
232 fec.u.ipv4.prefixlen = 32;
233 break;
234 case AF_INET6:
235 fec.type = FEC_TYPE_IPV6;
236 fec.u.ipv6.prefix = pw->addr.v6;
237 fec.u.ipv6.prefixlen = 128;
238 break;
239 default:
240 fatalx("l2vpn_pw_ok: unknown af");
241 }
242
243 fn = (struct fec_node *)fec_find(&ft, &fec);
244 if (fn == NULL || fn->local_label == NO_LABEL)
245 return (0);
246 /*
247 * Need to ensure that there's a label binding for all nexthops.
248 * Otherwise, ECMP for this route could render the pseudowire unusable.
249 */
250 LIST_FOREACH(fnh, &fn->nexthops, entry)
251 if (fnh->remote_label == NO_LABEL)
252 return (0);
253
254 return (1);
255 }
256
257 int
258 l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
259 {
260 struct l2vpn_pw *pw;
261 struct status_tlv st;
262
263 /* NOTE: thanks martini & friends for all this mess */
264
265 pw = (struct l2vpn_pw *) fn->data;
266 if (pw == NULL)
267 /*
268 * pseudowire not configured, return and record
269 * the mapping later
270 */
271 return (0);
272
273 /* RFC4447 - Section 6.2: control word negotiation */
274 if (fec_find(&ln->sent_map, &fn->fec)) {
275 if ((map->flags & F_MAP_PW_CWORD) &&
276 !(pw->flags & F_PW_CWORD_CONF)) {
277 /* ignore the received label mapping */
278 return (1);
279 } else if (!(map->flags & F_MAP_PW_CWORD) &&
280 (pw->flags & F_PW_CWORD_CONF)) {
281 /* append a "Wrong C-bit" status code */
282 st.status_code = S_WRONG_CBIT;
283 st.msg_id = map->msg_id;
284 st.msg_type = htons(MSG_TYPE_LABELMAPPING);
285 lde_send_labelwithdraw(ln, fn, NO_LABEL, &st);
286
287 pw->flags &= ~F_PW_CWORD;
288 lde_send_labelmapping(ln, fn, 1);
289 }
290 } else if (map->flags & F_MAP_PW_CWORD) {
291 if (pw->flags & F_PW_CWORD_CONF)
292 pw->flags |= F_PW_CWORD;
293 else
294 /* act as if no label mapping had been received */
295 return (1);
296 } else
297 pw->flags &= ~F_PW_CWORD;
298
299 /* RFC4447 - Section 5.4.3: pseudowire status negotiation */
300 if (fec_find(&ln->recv_map, &fn->fec) == NULL &&
301 !(map->flags & F_MAP_PW_STATUS))
302 pw->flags &= ~F_PW_STATUSTLV;
303
304 return (0);
305 }
306
307 void
308 l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec)
309 {
310 struct notify_msg nm;
311
312 memset(&nm, 0, sizeof(nm));
313 nm.status_code = S_PW_STATUS;
314 nm.pw_status = status;
315 nm.flags |= F_NOTIF_PW_STATUS;
316 lde_fec2map(fec, &nm.fec);
317 nm.flags |= F_NOTIF_FEC;
318
319 lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
320 &nm, sizeof(nm));
321 }
322
323 void
324 l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
325 {
326 struct fec fec;
327 struct fec_node *fn;
328 struct fec_nh *fnh;
329 struct l2vpn_pw *pw;
330
331 /* TODO group wildcard */
332 if (!(nm->fec.flags & F_MAP_PW_ID))
333 return;
334
335 lde_map2fec(&nm->fec, ln->id, &fec);
336 fn = (struct fec_node *)fec_find(&ft, &fec);
337 if (fn == NULL)
338 /* unknown fec */
339 return;
340
341 pw = (struct l2vpn_pw *) fn->data;
342 if (pw == NULL)
343 return;
344
345 fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0);
346 if (fnh == NULL)
347 return;
348
349 /* remote status didn't change */
350 if (pw->remote_status == nm->pw_status)
351 return;
352
353 pw->remote_status = nm->pw_status;
354
355 if (l2vpn_pw_ok(pw, fnh))
356 lde_send_change_klabel(fn, fnh);
357 else
358 lde_send_delete_klabel(fn, fnh);
359 }
360
361 void
362 l2vpn_sync_pws(int af, union ldpd_addr *addr)
363 {
364 struct l2vpn *l2vpn;
365 struct l2vpn_pw *pw;
366 struct fec fec;
367 struct fec_node *fn;
368 struct fec_nh *fnh;
369
370 LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) {
371 LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
372 if (af != pw->af || ldp_addrcmp(af, &pw->addr, addr))
373 continue;
374
375 l2vpn_pw_fec(pw, &fec);
376 fn = (struct fec_node *)fec_find(&ft, &fec);
377 if (fn == NULL)
378 continue;
379 fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)
380 &pw->lsr_id, 0);
381 if (fnh == NULL)
382 continue;
383
384 if (l2vpn_pw_ok(pw, fnh))
385 lde_send_change_klabel(fn, fnh);
386 else
387 lde_send_delete_klabel(fn, fnh);
388 }
389 }
390 }
391
392 void
393 l2vpn_pw_ctl(pid_t pid)
394 {
395 struct l2vpn *l2vpn;
396 struct l2vpn_pw *pw;
397 static struct ctl_pw pwctl;
398
399 LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
400 LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
401 memset(&pwctl, 0, sizeof(pwctl));
402 strlcpy(pwctl.ifname, pw->ifname,
403 sizeof(pwctl.ifname));
404 pwctl.pwid = pw->pwid;
405 pwctl.lsr_id = pw->lsr_id;
406 pwctl.status = pw->flags & F_PW_STATUS_UP;
407
408 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
409 pid, &pwctl, sizeof(pwctl));
410 }
411 }
412
413 void
414 l2vpn_binding_ctl(pid_t pid)
415 {
416 struct fec *f;
417 struct fec_node *fn;
418 struct lde_map *me;
419 struct l2vpn_pw *pw;
420 static struct ctl_pw pwctl;
421
422 RB_FOREACH(f, fec_tree, &ft) {
423 if (f->type != FEC_TYPE_PWID)
424 continue;
425
426 fn = (struct fec_node *)f;
427 if (fn->local_label == NO_LABEL &&
428 LIST_EMPTY(&fn->downstream))
429 continue;
430
431 memset(&pwctl, 0, sizeof(pwctl));
432 pwctl.type = f->u.pwid.type;
433 pwctl.pwid = f->u.pwid.pwid;
434 pwctl.lsr_id = f->u.pwid.lsr_id;
435
436 pw = (struct l2vpn_pw *) fn->data;
437 if (pw) {
438 pwctl.local_label = fn->local_label;
439 pwctl.local_gid = 0;
440 pwctl.local_ifmtu = pw->l2vpn->mtu;
441 } else
442 pwctl.local_label = NO_LABEL;
443
444 LIST_FOREACH(me, &fn->downstream, entry)
445 if (f->u.pwid.lsr_id.s_addr == me->nexthop->id.s_addr)
446 break;
447
448 if (me) {
449 pwctl.remote_label = me->map.label;
450 pwctl.remote_gid = me->map.fec.pwid.group_id;
451 if (me->map.flags & F_MAP_PW_IFMTU)
452 pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
453
454 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
455 0, pid, &pwctl, sizeof(pwctl));
456 } else if (pw) {
457 pwctl.remote_label = NO_LABEL;
458
459 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
460 0, pid, &pwctl, sizeof(pwctl));
461 }
462 }
463 }
464
465 /* ldpe */
466
467 void
468 ldpe_l2vpn_init(struct l2vpn *l2vpn)
469 {
470 struct l2vpn_pw *pw;
471
472 LIST_FOREACH(pw, &l2vpn->pw_list, entry)
473 ldpe_l2vpn_pw_init(pw);
474 }
475
476 void
477 ldpe_l2vpn_exit(struct l2vpn *l2vpn)
478 {
479 struct l2vpn_pw *pw;
480
481 LIST_FOREACH(pw, &l2vpn->pw_list, entry)
482 ldpe_l2vpn_pw_exit(pw);
483 }
484
485 void
486 ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
487 {
488 struct tnbr *tnbr;
489
490 tnbr = tnbr_find(leconf, pw->af, &pw->addr);
491 if (tnbr == NULL) {
492 tnbr = tnbr_new(leconf, pw->af, &pw->addr);
493 tnbr_update(tnbr);
494 LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
495 }
496
497 tnbr->pw_count++;
498 }
499
500 void
501 ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
502 {
503 struct tnbr *tnbr;
504
505 tnbr = tnbr_find(leconf, pw->af, &pw->addr);
506 if (tnbr) {
507 tnbr->pw_count--;
508 tnbr_check(tnbr);
509 }
510 }