l2vpn.c revision 1.1
1/*	$OpenBSD: l2vpn.c,v 1.1 2015/07/21 04:52:29 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		err(1, "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 = PW_TYPE_ETHERNET;
56
57	return (l2vpn);
58}
59
60struct l2vpn *
61l2vpn_find(struct ldpd_conf *xconf, char *name)
62{
63	struct l2vpn	*l2vpn;
64
65	LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry)
66		if (strcmp(l2vpn->name, name) == 0)
67			return (l2vpn);
68
69	return (NULL);
70}
71
72void
73l2vpn_del(struct l2vpn *l2vpn)
74{
75	struct l2vpn_if		*lif;
76	struct l2vpn_pw		*pw;
77
78	while ((lif = LIST_FIRST(&l2vpn->if_list)) != NULL) {
79		LIST_REMOVE(lif, entry);
80		l2vpn_if_del(lif);
81	}
82	while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) {
83		LIST_REMOVE(pw, entry);
84		l2vpn_pw_del(pw);
85	}
86
87	free(l2vpn);
88}
89
90void
91l2vpn_init(struct l2vpn *l2vpn)
92{
93	struct l2vpn_pw	*pw;
94
95	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
96		l2vpn_pw_init(pw);
97}
98
99struct l2vpn_if *
100l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)
101{
102	struct l2vpn_if	*lif;
103
104	if ((lif = calloc(1, sizeof(*lif))) == NULL)
105		err(1, "l2vpn_if_new: calloc");
106
107	lif->l2vpn = l2vpn;
108	strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname));
109	lif->ifindex = kif->ifindex;
110	lif->flags = kif->flags;
111	lif->link_state = kif->link_state;
112
113	return (lif);
114}
115
116struct l2vpn_if *
117l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex)
118{
119	struct l2vpn_if	*lif;
120
121	LIST_FOREACH(lif, &l2vpn->if_list, entry)
122		if (lif->ifindex == ifindex)
123			return (lif);
124
125	return (NULL);
126}
127
128void
129l2vpn_if_del(struct l2vpn_if *lif)
130{
131	free(lif);
132}
133
134struct l2vpn_pw *
135l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif)
136{
137	struct l2vpn_pw	*pw;
138
139	if ((pw = calloc(1, sizeof(*pw))) == NULL)
140		err(1, "l2vpn_pw_new: calloc");
141
142	pw->l2vpn = l2vpn;
143	strlcpy(pw->ifname, kif->ifname, sizeof(pw->ifname));
144	pw->ifindex = kif->ifindex;
145
146	return (pw);
147}
148
149struct l2vpn_pw *
150l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex)
151{
152	struct l2vpn_pw	*pw;
153
154	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
155		if (pw->ifindex == ifindex)
156			return (pw);
157
158	return (NULL);
159}
160
161void
162l2vpn_pw_del(struct l2vpn_pw *pw)
163{
164	struct fec	 fec;
165
166	if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY)
167		return;
168
169	l2vpn_pw_fec(pw, &fec);
170	lde_kernel_remove(&fec, pw->addr);
171	free(pw);
172}
173
174void
175l2vpn_pw_init(struct l2vpn_pw *pw)
176{
177	struct fec	 fec;
178
179	if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY)
180		return;
181
182	l2vpn_pw_fec(pw, &fec);
183	lde_kernel_insert(&fec, pw->addr, 0, (void *)pw);
184}
185
186void
187l2vpn_pw_fec(struct l2vpn_pw *pw, struct fec *fec)
188{
189	bzero(fec, sizeof(*fec));
190	fec->type = FEC_TYPE_PWID;
191	fec->u.pwid.type = pw->l2vpn->pw_type;
192	fec->u.pwid.pwid = pw->pwid;
193	fec->u.pwid.nexthop.s_addr = pw->addr.s_addr;
194}
195
196void
197l2vpn_pw_reset(struct l2vpn_pw *pw)
198{
199	pw->remote_group = 0;
200	pw->remote_mtu = 0;
201	if (!(pw->flags & F_PW_CONTROLWORD_CONF))
202		pw->flags &= ~F_PW_CONTROLWORD;
203	if (!(pw->flags & F_PW_STATUSTLV_CONF))
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	bzero(&fec, sizeof(fec));
228	fec.type = FEC_TYPE_IPV4;
229	fec.u.ipv4.prefix.s_addr = pw->addr.s_addr;
230	fec.u.ipv4.prefixlen = 32;
231	fn = (struct fec_node *)fec_find(&ft, &fec);
232	if (fn == NULL)
233		return (0);
234	LIST_FOREACH(fnh, &fn->nexthops, entry)
235		if (fnh->remote_label == NO_LABEL)
236			return (0);
237
238	return (1);
239}
240
241int
242l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
243{
244	struct fec_nh		*fnh;
245	struct l2vpn_pw		*pw;
246
247	/* NOTE: thanks martini & friends for all this mess */
248
249	fnh = fec_nh_find(fn, ln->id);
250	if (fnh == NULL)
251		/*
252		 * pseudowire not configured, return and record
253		 * the mapping later
254		 */
255		return (0);
256	pw = (struct l2vpn_pw *) fnh->data;
257
258	l2vpn_pw_reset(pw);
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_CONTROLWORD_CONF)) {
264			/* ignore the received label mapping */
265			return (1);
266		} else if (!(map->flags & F_MAP_PW_CWORD) &&
267		    (pw->flags & F_PW_CONTROLWORD_CONF)) {
268			/* TODO append a "Wrong C-bit" status code */
269			lde_send_labelwithdraw(ln, fn);
270
271			pw->flags &= ~F_PW_CONTROLWORD;
272			lde_send_labelmapping(ln, fn, 1);
273		}
274	} else if (map->flags & F_MAP_PW_CWORD) {
275		if (pw->flags & F_PW_CONTROLWORD_CONF)
276			pw->flags |= F_PW_CONTROLWORD;
277		else
278			/* act as if no label mapping had been received */
279			return (1);
280	} else
281		pw->flags &= ~F_PW_CONTROLWORD;
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(u_int32_t peerid, u_int32_t status, struct fec *fec)
293{
294	struct notify_msg	 nm;
295
296	bzero(&nm, 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	fnh = fec_nh_find(fn, ln->id);
328	if (fnh == NULL)
329		return;
330	pw = (struct l2vpn_pw *) fnh->data;
331
332	/* remote status didn't change */
333	if (pw->remote_status == nm->pw_status)
334		return;
335
336	pw->remote_status = nm->pw_status;
337
338	if (l2vpn_pw_ok(pw, fnh))
339		lde_send_change_klabel(fn, fnh);
340	else
341		lde_send_delete_klabel(fn, fnh);
342}
343
344void
345l2vpn_sync_pws(struct in_addr addr)
346{
347	struct l2vpn		*l2vpn;
348	struct l2vpn_pw		*pw;
349	struct fec		 fec;
350	struct fec_node		*fn;
351	struct fec_nh		*fnh;
352
353	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) {
354		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
355			if (pw->addr.s_addr == addr.s_addr) {
356				l2vpn_pw_fec(pw, &fec);
357				fn = (struct fec_node *)fec_find(&ft, &fec);
358				if (fn == NULL)
359					continue;
360				fnh = fec_nh_find(fn, pw->addr);
361				if (fnh == NULL)
362					continue;
363
364				if (l2vpn_pw_ok(pw, fnh))
365					lde_send_change_klabel(fn, fnh);
366				else
367					lde_send_delete_klabel(fn, fnh);
368			}
369		}
370	}
371}
372
373void
374l2vpn_pw_ctl(pid_t pid)
375{
376	struct l2vpn		*l2vpn;
377	struct l2vpn_pw		*pw;
378	static struct ctl_pw	 pwctl;
379
380	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
381		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
382			bzero(&pwctl, sizeof(pwctl));
383			strlcpy(pwctl.ifname, pw->ifname,
384			    sizeof(pwctl.ifname));
385			pwctl.pwid = pw->pwid;
386			pwctl.nexthop.s_addr = pw->addr.s_addr;
387			pwctl.status = pw->flags & F_PW_STATUS_UP;
388
389			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
390			    pid, &pwctl, sizeof(pwctl));
391		}
392}
393
394void
395l2vpn_binding_ctl(pid_t pid)
396{
397	struct fec		*f;
398	struct fec_node		*fn;
399	struct lde_map		*me;
400	struct fec_nh		*fnh;
401	struct l2vpn_pw		*pw;
402	static struct ctl_pw	 pwctl;
403
404	RB_FOREACH(f, fec_tree, &ft) {
405		if (f->type != FEC_TYPE_PWID)
406			continue;
407
408		fn = (struct fec_node *)f;
409		if (fn->local_label == NO_LABEL &&
410		    LIST_EMPTY(&fn->downstream))
411			continue;
412
413		fnh = fec_nh_find(fn, f->u.pwid.nexthop);
414		if (fnh != NULL)
415			pw = (struct l2vpn_pw *) fnh->data;
416		else
417			pw = NULL;
418
419		bzero(&pwctl, sizeof(pwctl));
420		pwctl.type = f->u.pwid.type;
421		pwctl.pwid = f->u.pwid.pwid;
422		pwctl.nexthop = f->u.pwid.nexthop;
423
424		if (pw) {
425			pwctl.local_label = fn->local_label;
426			pwctl.local_gid = 0;
427			pwctl.local_ifmtu = pw->l2vpn->mtu;
428		} else
429			pwctl.local_label = NO_LABEL;
430
431		LIST_FOREACH(me, &fn->downstream, entry)
432			if (f->u.pwid.nexthop.s_addr == me->nexthop->id.s_addr)
433				break;
434
435		if (me) {
436			pwctl.remote_label = me->map.label;
437			pwctl.remote_gid = me->map.fec.pwid.group_id;
438			if (me->map.flags & F_MAP_PW_IFMTU)
439				pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
440
441			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
442			    0, pid, &pwctl, sizeof(pwctl));
443		} else if (pw) {
444			pwctl.remote_label = NO_LABEL;
445
446			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
447			    0, pid, &pwctl, sizeof(pwctl));
448		}
449	}
450}
451
452/* ldpe */
453
454void
455ldpe_l2vpn_init(struct l2vpn *l2vpn)
456{
457	struct l2vpn_pw		*pw;
458
459	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
460		ldpe_l2vpn_pw_init(pw);
461}
462
463void
464ldpe_l2vpn_exit(struct l2vpn *l2vpn)
465{
466	struct l2vpn_pw		*pw;
467
468	LIST_FOREACH(pw, &l2vpn->pw_list, entry)
469		ldpe_l2vpn_pw_exit(pw);
470}
471
472void
473ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
474{
475	struct tnbr		*tnbr;
476
477	if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY)
478		return;
479
480	tnbr = tnbr_find(leconf, pw->addr);
481	if (tnbr->discovery_fd == 0)
482		tnbr_init(leconf, tnbr);
483}
484
485void
486ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
487{
488	struct tnbr		*tnbr;
489
490	if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY)
491		return;
492
493	tnbr = tnbr_find(leconf, pw->addr);
494	if (tnbr) {
495		tnbr->pw_count--;
496		tnbr_check(tnbr);
497	}
498}
499