xref: /openbsd/usr.sbin/ldpd/l2vpn.c (revision 19fce358)
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 
37 RB_PROTOTYPE(fec_tree, fec, entry, fec_compare)
38 extern struct fec_tree		 ft;
39 
40 extern struct ldpd_conf		*ldeconf;
41 extern struct ldpd_conf		*leconf;
42 
43 struct l2vpn *
44 l2vpn_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 
63 struct l2vpn *
64 l2vpn_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 
75 void
76 l2vpn_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 
94 void
95 l2vpn_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 
103 struct l2vpn_if *
104 l2vpn_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 
120 struct l2vpn_if *
121 l2vpn_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 
132 struct l2vpn_pw *
133 l2vpn_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 
147 struct l2vpn_pw *
148 l2vpn_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 
159 void
160 l2vpn_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 
170 void
171 l2vpn_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 
179 void
180 l2vpn_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 
189 void
190 l2vpn_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 
207 int
208 l2vpn_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 
245 int
246 l2vpn_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 
291 void
292 l2vpn_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 
309 void
310 l2vpn_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 
347 void
348 l2vpn_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 
377 void
378 l2vpn_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 
398 void
399 l2vpn_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 
452 void
453 ldpe_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 
461 void
462 ldpe_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 
470 void
471 ldpe_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 
485 void
486 ldpe_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