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