l2vpn.c revision 1.20
1/*	$OpenBSD: l2vpn.c,v 1.20 2016/07/01 23:33:46 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
32static void	 l2vpn_pw_fec(struct l2vpn_pw *, struct fec *);
33
34struct l2vpn *
35l2vpn_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
54struct l2vpn *
55l2vpn_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
66void
67l2vpn_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
84void
85l2vpn_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
93void
94l2vpn_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
102struct l2vpn_if *
103l2vpn_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
119struct l2vpn_if *
120l2vpn_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
131struct l2vpn_pw *
132l2vpn_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
146struct l2vpn_pw *
147l2vpn_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
158void
159l2vpn_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
170void
171l2vpn_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
179static void
180l2vpn_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
189void
190l2vpn_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
207int
208l2vpn_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
257int
258l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
259{
260	struct l2vpn_pw		*pw;
261	struct status_tlv	 status;
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			status.status_code = S_WRONG_CBIT;
283			status.msg_id = map->messageid;
284			status.msg_type = htons(MSG_TYPE_LABELMAPPING);
285			lde_send_labelwithdraw(ln, fn, NO_LABEL, &status);
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
307void
308l2vpn_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 = S_PW_STATUS;
314
315	nm.pw_status = status;
316	nm.flags |= F_NOTIF_PW_STATUS;
317
318	lde_fec2map(fec, &nm.fec);
319	nm.flags |= F_NOTIF_FEC;
320
321	lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
322	    &nm, sizeof(nm));
323}
324
325void
326l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
327{
328	struct fec		 fec;
329	struct fec_node		*fn;
330	struct fec_nh		*fnh;
331	struct l2vpn_pw		*pw;
332
333	/* TODO group wildcard */
334	if (!(nm->fec.flags & F_MAP_PW_ID))
335		return;
336
337	lde_map2fec(&nm->fec, ln->id, &fec);
338	fn = (struct fec_node *)fec_find(&ft, &fec);
339	if (fn == NULL)
340		/* unknown fec */
341		return;
342
343	pw = (struct l2vpn_pw *) fn->data;
344	if (pw == NULL)
345		return;
346
347	fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0);
348	if (fnh == NULL)
349		return;
350
351	/* remote status didn't change */
352	if (pw->remote_status == nm->pw_status)
353		return;
354
355	pw->remote_status = nm->pw_status;
356
357	if (l2vpn_pw_ok(pw, fnh))
358		lde_send_change_klabel(fn, fnh);
359	else
360		lde_send_delete_klabel(fn, fnh);
361}
362
363void
364l2vpn_sync_pws(int af, union ldpd_addr *addr)
365{
366	struct l2vpn		*l2vpn;
367	struct l2vpn_pw		*pw;
368	struct fec		 fec;
369	struct fec_node		*fn;
370	struct fec_nh		*fnh;
371
372	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) {
373		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
374			if (af != pw->af || ldp_addrcmp(af, &pw->addr, addr))
375				continue;
376
377			l2vpn_pw_fec(pw, &fec);
378			fn = (struct fec_node *)fec_find(&ft, &fec);
379			if (fn == NULL)
380				continue;
381			fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)
382			    &pw->lsr_id, 0);
383			if (fnh == NULL)
384				continue;
385
386			if (l2vpn_pw_ok(pw, fnh))
387				lde_send_change_klabel(fn, fnh);
388			else
389				lde_send_delete_klabel(fn, fnh);
390		}
391	}
392}
393
394void
395l2vpn_pw_ctl(pid_t pid)
396{
397	struct l2vpn		*l2vpn;
398	struct l2vpn_pw		*pw;
399	static struct ctl_pw	 pwctl;
400
401	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
402		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
403			memset(&pwctl, 0, sizeof(pwctl));
404			strlcpy(pwctl.ifname, pw->ifname,
405			    sizeof(pwctl.ifname));
406			pwctl.pwid = pw->pwid;
407			pwctl.lsr_id = pw->lsr_id;
408			pwctl.status = pw->flags & F_PW_STATUS_UP;
409
410			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
411			    pid, &pwctl, sizeof(pwctl));
412		}
413}
414
415void
416l2vpn_binding_ctl(pid_t pid)
417{
418	struct fec		*f;
419	struct fec_node		*fn;
420	struct lde_map		*me;
421	struct l2vpn_pw		*pw;
422	static struct ctl_pw	 pwctl;
423
424	RB_FOREACH(f, fec_tree, &ft) {
425		if (f->type != FEC_TYPE_PWID)
426			continue;
427
428		fn = (struct fec_node *)f;
429		if (fn->local_label == NO_LABEL &&
430		    LIST_EMPTY(&fn->downstream))
431			continue;
432
433		memset(&pwctl, 0, sizeof(pwctl));
434		pwctl.type = f->u.pwid.type;
435		pwctl.pwid = f->u.pwid.pwid;
436		pwctl.lsr_id = f->u.pwid.lsr_id;
437
438		pw = (struct l2vpn_pw *) fn->data;
439		if (pw) {
440			pwctl.local_label = fn->local_label;
441			pwctl.local_gid = 0;
442			pwctl.local_ifmtu = pw->l2vpn->mtu;
443		} else
444			pwctl.local_label = NO_LABEL;
445
446		LIST_FOREACH(me, &fn->downstream, entry)
447			if (f->u.pwid.lsr_id.s_addr == me->nexthop->id.s_addr)
448				break;
449
450		if (me) {
451			pwctl.remote_label = me->map.label;
452			pwctl.remote_gid = me->map.fec.pwid.group_id;
453			if (me->map.flags & F_MAP_PW_IFMTU)
454				pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
455
456			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
457			    0, pid, &pwctl, sizeof(pwctl));
458		} else if (pw) {
459			pwctl.remote_label = NO_LABEL;
460
461			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
462			    0, pid, &pwctl, sizeof(pwctl));
463		}
464	}
465}
466
467/* ldpe */
468
469void
470ldpe_l2vpn_init(struct l2vpn *l2vpn)
471{
472	struct l2vpn_pw		*pw;
473
474	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
475		ldpe_l2vpn_pw_init(pw);
476}
477
478void
479ldpe_l2vpn_exit(struct l2vpn *l2vpn)
480{
481	struct l2vpn_pw		*pw;
482
483	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
484		ldpe_l2vpn_pw_exit(pw);
485}
486
487void
488ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
489{
490	struct tnbr		*tnbr;
491
492	tnbr = tnbr_find(leconf, pw->af, &pw->addr);
493	if (tnbr == NULL) {
494		tnbr = tnbr_new(leconf, pw->af, &pw->addr);
495		tnbr_update(tnbr);
496		LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
497	}
498
499	tnbr->pw_count++;
500}
501
502void
503ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
504{
505	struct tnbr		*tnbr;
506
507	tnbr = tnbr_find(leconf, pw->af, &pw->addr);
508	if (tnbr) {
509		tnbr->pw_count--;
510		tnbr_check(tnbr);
511	}
512}
513