l2vpn.c revision 1.11
1/*	$OpenBSD: l2vpn.c,v 1.11 2016/05/23 18:33:56 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		LIST_REMOVE(pw, entry);
87		l2vpn_pw_del(pw);
88	}
89
90	free(l2vpn);
91}
92
93void
94l2vpn_init(struct l2vpn *l2vpn)
95{
96	struct l2vpn_pw	*pw;
97
98	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
99		l2vpn_pw_init(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, pw->lsr_id, 0, (void *)pw);
167}
168
169void
170l2vpn_pw_del(struct l2vpn_pw *pw)
171{
172	struct fec	 fec;
173
174	l2vpn_pw_fec(pw, &fec);
175	lde_kernel_remove(&fec, pw->lsr_id);
176	free(pw);
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				l2vpn_pw_fec(pw, &fec);
360				fn = (struct fec_node *)fec_find(&ft, &fec);
361				if (fn == NULL)
362					continue;
363				fnh = fec_nh_find(fn, pw->lsr_id);
364				if (fnh == NULL)
365					continue;
366
367				if (l2vpn_pw_ok(pw, fnh))
368					lde_send_change_klabel(fn, fnh);
369				else
370					lde_send_delete_klabel(fn, fnh);
371			}
372		}
373	}
374}
375
376void
377l2vpn_pw_ctl(pid_t pid)
378{
379	struct l2vpn		*l2vpn;
380	struct l2vpn_pw		*pw;
381	static struct ctl_pw	 pwctl;
382
383	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
384		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
385			memset(&pwctl, 0, sizeof(pwctl));
386			strlcpy(pwctl.ifname, pw->ifname,
387			    sizeof(pwctl.ifname));
388			pwctl.pwid = pw->pwid;
389			pwctl.lsr_id = pw->lsr_id;
390			pwctl.status = pw->flags & F_PW_STATUS_UP;
391
392			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
393			    pid, &pwctl, sizeof(pwctl));
394		}
395}
396
397void
398l2vpn_binding_ctl(pid_t pid)
399{
400	struct fec		*f;
401	struct fec_node		*fn;
402	struct lde_map		*me;
403	struct l2vpn_pw		*pw;
404	static struct ctl_pw	 pwctl;
405
406	RB_FOREACH(f, fec_tree, &ft) {
407		if (f->type != FEC_TYPE_PWID)
408			continue;
409
410		fn = (struct fec_node *)f;
411		if (fn->local_label == NO_LABEL &&
412		    LIST_EMPTY(&fn->downstream))
413			continue;
414
415		memset(&pwctl, 0, sizeof(pwctl));
416		pwctl.type = f->u.pwid.type;
417		pwctl.pwid = f->u.pwid.pwid;
418		pwctl.lsr_id = f->u.pwid.lsr_id;
419
420		pw = (struct l2vpn_pw *) fn->data;
421		if (pw) {
422			pwctl.local_label = fn->local_label;
423			pwctl.local_gid = 0;
424			pwctl.local_ifmtu = pw->l2vpn->mtu;
425		} else
426			pwctl.local_label = NO_LABEL;
427
428		LIST_FOREACH(me, &fn->downstream, entry)
429			if (f->u.pwid.lsr_id.s_addr == me->nexthop->id.s_addr)
430				break;
431
432		if (me) {
433			pwctl.remote_label = me->map.label;
434			pwctl.remote_gid = me->map.fec.pwid.group_id;
435			if (me->map.flags & F_MAP_PW_IFMTU)
436				pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
437
438			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
439			    0, pid, &pwctl, sizeof(pwctl));
440		} else if (pw) {
441			pwctl.remote_label = NO_LABEL;
442
443			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
444			    0, pid, &pwctl, sizeof(pwctl));
445		}
446	}
447}
448
449/* ldpe */
450
451void
452ldpe_l2vpn_init(struct l2vpn *l2vpn)
453{
454	struct l2vpn_pw		*pw;
455
456	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
457		ldpe_l2vpn_pw_init(pw);
458}
459
460void
461ldpe_l2vpn_exit(struct l2vpn *l2vpn)
462{
463	struct l2vpn_pw		*pw;
464
465	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
466		ldpe_l2vpn_pw_exit(pw);
467}
468
469void
470ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
471{
472	struct tnbr		*tnbr;
473
474	tnbr = tnbr_find(leconf, pw->lsr_id);
475	if (!event_initialized(&tnbr->hello_timer))
476		tnbr_update(tnbr);
477}
478
479void
480ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
481{
482	struct tnbr		*tnbr;
483
484	tnbr = tnbr_find(leconf, pw->lsr_id);
485	if (tnbr) {
486		tnbr->pw_count--;
487		tnbr_check(tnbr);
488	}
489}
490