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