l2vpn.c revision 1.13
1/*	$OpenBSD: l2vpn.c,v 1.13 2016/05/23 18:55:21 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 <sys/socket.h>
24#include <arpa/inet.h>
25
26#include <err.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "ldpd.h"
32#include "lde.h"
33#include "ldpe.h"
34#include "control.h"
35#include "log.h"
36
37RB_PROTOTYPE(fec_tree, fec, entry, fec_compare)
38extern struct fec_tree		 ft;
39
40extern struct ldpd_conf		*ldeconf;
41extern struct ldpd_conf		*leconf;
42
43struct l2vpn *
44l2vpn_new(const char *name)
45{
46	struct l2vpn	*l2vpn;
47
48	if ((l2vpn = calloc(1, sizeof(*l2vpn))) == NULL)
49		fatal("l2vpn_new: calloc");
50
51	strlcpy(l2vpn->name, name, sizeof(l2vpn->name));
52
53	/* set default values */
54	l2vpn->mtu = DEFAULT_L2VPN_MTU;
55	l2vpn->pw_type = DEFAULT_PW_TYPE;
56
57	LIST_INIT(&l2vpn->if_list);
58	LIST_INIT(&l2vpn->pw_list);
59
60	return (l2vpn);
61}
62
63struct l2vpn *
64l2vpn_find(struct ldpd_conf *xconf, const char *name)
65{
66	struct l2vpn	*l2vpn;
67
68	LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry)
69		if (strcmp(l2vpn->name, name) == 0)
70			return (l2vpn);
71
72	return (NULL);
73}
74
75void
76l2vpn_del(struct l2vpn *l2vpn)
77{
78	struct l2vpn_if		*lif;
79	struct l2vpn_pw		*pw;
80
81	while ((lif = LIST_FIRST(&l2vpn->if_list)) != NULL) {
82		LIST_REMOVE(lif, entry);
83		free(lif);
84	}
85	while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) {
86		l2vpn_pw_exit(pw);
87		LIST_REMOVE(pw, entry);
88		free(pw);
89	}
90
91	free(l2vpn);
92}
93
94void
95l2vpn_init(struct l2vpn *l2vpn)
96{
97	struct l2vpn_pw	*pw;
98
99	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
100		l2vpn_pw_init(pw);
101}
102
103struct l2vpn_if *
104l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)
105{
106	struct l2vpn_if	*lif;
107
108	if ((lif = calloc(1, sizeof(*lif))) == NULL)
109		fatal("l2vpn_if_new: calloc");
110
111	lif->l2vpn = l2vpn;
112	strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname));
113	lif->ifindex = kif->ifindex;
114	lif->flags = kif->flags;
115	lif->link_state = kif->link_state;
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
132struct l2vpn_pw *
133l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif)
134{
135	struct l2vpn_pw	*pw;
136
137	if ((pw = calloc(1, sizeof(*pw))) == NULL)
138		fatal("l2vpn_pw_new: calloc");
139
140	pw->l2vpn = l2vpn;
141	strlcpy(pw->ifname, kif->ifname, sizeof(pw->ifname));
142	pw->ifindex = kif->ifindex;
143
144	return (pw);
145}
146
147struct l2vpn_pw *
148l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex)
149{
150	struct l2vpn_pw	*pw;
151
152	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
153		if (pw->ifindex == ifindex)
154			return (pw);
155
156	return (NULL);
157}
158
159void
160l2vpn_pw_init(struct l2vpn_pw *pw)
161{
162	struct fec	 fec;
163
164	l2vpn_pw_reset(pw);
165
166	l2vpn_pw_fec(pw, &fec);
167	lde_kernel_insert(&fec, pw->lsr_id, 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, pw->lsr_id);
177}
178
179void
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	fec.type = FEC_TYPE_IPV4;
229	fec.u.ipv4.prefix = pw->lsr_id;
230	fec.u.ipv4.prefixlen = 32;
231	fn = (struct fec_node *)fec_find(&ft, &fec);
232	if (fn == NULL || fn->local_label == NO_LABEL)
233		return (0);
234	/*
235	 * Need to ensure that there's a label binding for all nexthops.
236	 * Otherwise, ECMP for this route could render the pseudowire unusable.
237	 */
238	LIST_FOREACH(fnh, &fn->nexthops, entry)
239		if (fnh->remote_label == NO_LABEL)
240			return (0);
241
242	return (1);
243}
244
245int
246l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
247{
248	struct l2vpn_pw		*pw;
249
250	/* NOTE: thanks martini & friends for all this mess */
251
252	pw = (struct l2vpn_pw *) fn->data;
253	if (pw == NULL)
254		/*
255		 * pseudowire not configured, return and record
256		 * the mapping later
257		 */
258		return (0);
259
260	/* RFC4447 - Section 6.2: control word negotiation */
261	if (fec_find(&ln->sent_map, &fn->fec)) {
262		if ((map->flags & F_MAP_PW_CWORD) &&
263		    !(pw->flags & F_PW_CWORD_CONF)) {
264			/* ignore the received label mapping */
265			return (1);
266		} else if (!(map->flags & F_MAP_PW_CWORD) &&
267		    (pw->flags & F_PW_CWORD_CONF)) {
268			/* TODO append a "Wrong C-bit" status code */
269			lde_send_labelwithdraw(ln, fn, NO_LABEL);
270
271			pw->flags &= ~F_PW_CWORD;
272			lde_send_labelmapping(ln, fn, 1);
273		}
274	} else if (map->flags & F_MAP_PW_CWORD) {
275		if (pw->flags & F_PW_CWORD_CONF)
276			pw->flags |= F_PW_CWORD;
277		else
278			/* act as if no label mapping had been received */
279			return (1);
280	} else
281		pw->flags &= ~F_PW_CWORD;
282
283	/* RFC4447 - Section 5.4.3: pseudowire status negotiation */
284	if (fec_find(&ln->recv_map, &fn->fec) == NULL &&
285	    !(map->flags & F_MAP_PW_STATUS))
286		pw->flags &= ~F_PW_STATUSTLV;
287
288	return (0);
289}
290
291void
292l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec)
293{
294	struct notify_msg	 nm;
295
296	memset(&nm, 0, sizeof(nm));
297	nm.status = S_PW_STATUS;
298
299	nm.pw_status = status;
300	nm.flags |= F_NOTIF_PW_STATUS;
301
302	lde_fec2map(fec, &nm.fec);
303	nm.flags |= F_NOTIF_FEC;
304
305	lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
306	    &nm, sizeof(nm));
307}
308
309void
310l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
311{
312	struct fec		 fec;
313	struct fec_node		*fn;
314	struct fec_nh		*fnh;
315	struct l2vpn_pw		*pw;
316
317	/* TODO group wildcard */
318	if (!(nm->fec.flags & F_MAP_PW_ID))
319		return;
320
321	lde_map2fec(&nm->fec, ln->id, &fec);
322	fn = (struct fec_node *)fec_find(&ft, &fec);
323	if (fn == NULL)
324		/* unknown fec */
325		return;
326
327	pw = (struct l2vpn_pw *) fn->data;
328	if (pw == NULL)
329		return;
330
331	fnh = fec_nh_find(fn, ln->id);
332	if (fnh == NULL)
333		return;
334
335	/* remote status didn't change */
336	if (pw->remote_status == nm->pw_status)
337		return;
338
339	pw->remote_status = nm->pw_status;
340
341	if (l2vpn_pw_ok(pw, fnh))
342		lde_send_change_klabel(fn, fnh);
343	else
344		lde_send_delete_klabel(fn, fnh);
345}
346
347void
348l2vpn_sync_pws(struct in_addr addr)
349{
350	struct l2vpn		*l2vpn;
351	struct l2vpn_pw		*pw;
352	struct fec		 fec;
353	struct fec_node		*fn;
354	struct fec_nh		*fnh;
355
356	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) {
357		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
358			if (pw->lsr_id.s_addr != addr.s_addr)
359				continue;
360
361			l2vpn_pw_fec(pw, &fec);
362			fn = (struct fec_node *)fec_find(&ft, &fec);
363			if (fn == NULL)
364				continue;
365			fnh = fec_nh_find(fn, pw->lsr_id);
366			if (fnh == NULL)
367				continue;
368
369			if (l2vpn_pw_ok(pw, fnh))
370				lde_send_change_klabel(fn, fnh);
371			else
372				lde_send_delete_klabel(fn, fnh);
373		}
374	}
375}
376
377void
378l2vpn_pw_ctl(pid_t pid)
379{
380	struct l2vpn		*l2vpn;
381	struct l2vpn_pw		*pw;
382	static struct ctl_pw	 pwctl;
383
384	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
385		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
386			memset(&pwctl, 0, sizeof(pwctl));
387			strlcpy(pwctl.ifname, pw->ifname,
388			    sizeof(pwctl.ifname));
389			pwctl.pwid = pw->pwid;
390			pwctl.lsr_id = pw->lsr_id;
391			pwctl.status = pw->flags & F_PW_STATUS_UP;
392
393			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
394			    pid, &pwctl, sizeof(pwctl));
395		}
396}
397
398void
399l2vpn_binding_ctl(pid_t pid)
400{
401	struct fec		*f;
402	struct fec_node		*fn;
403	struct lde_map		*me;
404	struct l2vpn_pw		*pw;
405	static struct ctl_pw	 pwctl;
406
407	RB_FOREACH(f, fec_tree, &ft) {
408		if (f->type != FEC_TYPE_PWID)
409			continue;
410
411		fn = (struct fec_node *)f;
412		if (fn->local_label == NO_LABEL &&
413		    LIST_EMPTY(&fn->downstream))
414			continue;
415
416		memset(&pwctl, 0, sizeof(pwctl));
417		pwctl.type = f->u.pwid.type;
418		pwctl.pwid = f->u.pwid.pwid;
419		pwctl.lsr_id = f->u.pwid.lsr_id;
420
421		pw = (struct l2vpn_pw *) fn->data;
422		if (pw) {
423			pwctl.local_label = fn->local_label;
424			pwctl.local_gid = 0;
425			pwctl.local_ifmtu = pw->l2vpn->mtu;
426		} else
427			pwctl.local_label = NO_LABEL;
428
429		LIST_FOREACH(me, &fn->downstream, entry)
430			if (f->u.pwid.lsr_id.s_addr == me->nexthop->id.s_addr)
431				break;
432
433		if (me) {
434			pwctl.remote_label = me->map.label;
435			pwctl.remote_gid = me->map.fec.pwid.group_id;
436			if (me->map.flags & F_MAP_PW_IFMTU)
437				pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
438
439			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
440			    0, pid, &pwctl, sizeof(pwctl));
441		} else if (pw) {
442			pwctl.remote_label = NO_LABEL;
443
444			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
445			    0, pid, &pwctl, sizeof(pwctl));
446		}
447	}
448}
449
450/* ldpe */
451
452void
453ldpe_l2vpn_init(struct l2vpn *l2vpn)
454{
455	struct l2vpn_pw		*pw;
456
457	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
458		ldpe_l2vpn_pw_init(pw);
459}
460
461void
462ldpe_l2vpn_exit(struct l2vpn *l2vpn)
463{
464	struct l2vpn_pw		*pw;
465
466	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
467		ldpe_l2vpn_pw_exit(pw);
468}
469
470void
471ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
472{
473	struct tnbr		*tnbr;
474
475	tnbr = tnbr_find(leconf, pw->lsr_id);
476	if (tnbr == NULL) {
477		tnbr = tnbr_new(leconf, pw->lsr_id);
478		tnbr_update(tnbr);
479		LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
480	}
481
482	tnbr->pw_count++;
483}
484
485void
486ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
487{
488	struct tnbr		*tnbr;
489
490	tnbr = tnbr_find(leconf, pw->lsr_id);
491	if (tnbr) {
492		tnbr->pw_count--;
493		tnbr_check(tnbr);
494	}
495}
496