xref: /openbsd/sys/net/bfd.c (revision ee078639)
1 /*	$OpenBSD: bfd.c,v 1.80 2023/08/03 09:49:08 mvs Exp $	*/
2 
3 /*
4  * Copyright (c) 2016-2018 Peter Hessler <phessler@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Support for Bi-directional Forwarding Detection (RFC 5880 / 5881)
21  */
22 
23 #include <sys/param.h>
24 #include <sys/errno.h>
25 
26 #include <sys/task.h>
27 #include <sys/pool.h>
28 #include <sys/socket.h>
29 #include <sys/socketvar.h>
30 #include <sys/stdint.h>
31 #include <sys/systm.h>
32 
33 #include <net/if.h>
34 #include <net/if_var.h>
35 #include <net/route.h>
36 #include <netinet/in.h>
37 #include <netinet/ip.h>
38 
39 #include <net/bfd.h>
40 
41 /*
42  * RFC 5880 Page 7
43  * The Mandatory Section of a BFD Control packet has the following
44  * format:
45  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46  * |Vers | Diag    |Sta|P|F|C|A|D|M|  Detect Mult  |    Length     |
47  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48  * |                      My Discriminator                         |
49  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50  * |                     Your Discriminator                        |
51  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52  * |                  Desired Min TX Interval                      |
53  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54  * |                 Required Min RX Interval                      |
55  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56  * |                Required Min Echo RX Interval                  |
57  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58  *
59  *
60  * An optional Authentication Section MAY be present:
61  *  0                   1                   2                   3
62  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
63  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64  * |   Auth Type   |   Auth Len    |     Authentication Data...    |
65  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66  *
67  */
68 
69 /* BFD on-wire format */
70 struct bfd_header {
71 	uint8_t	bfd_ver_diag;
72 	uint8_t	bfd_sta_flags;
73 
74 	uint8_t		bfd_detect_multi;	/* detection time multiplier */
75 	uint8_t		bfd_length;		/* in bytes */
76 	uint32_t	bfd_my_discriminator;		/* From this system */
77 	uint32_t	bfd_your_discriminator;		/* Received */
78 	uint32_t	bfd_desired_min_tx_interval;	/* in microseconds */
79 	uint32_t	bfd_required_min_rx_interval;	/* in microseconds */
80 	uint32_t	bfd_required_min_echo_interval;	/* in microseconds */
81 } __packed;
82 
83 /* optional authentication on-wire format */
84 struct bfd_auth_header {
85 	uint8_t	bfd_auth_type;
86 	uint8_t	bfd_auth_len;
87 	uint16_t	bfd_auth_data;
88 } __packed;
89 
90 #define BFD_VERSION		1	/* RFC 5880 Page 6 */
91 #define BFD_VER(x)		(((x) & 0xe0) >> 5)
92 #define BFD_DIAG(x)		((x) & 0x1f)
93 #define BFD_STATE(x)		(((x) & 0xc0) >> 6)
94 #define BFD_FLAGS(x)		((x) & 0x3f)
95 #define BFD_HDRLEN		24	/* RFC 5880 Page 37 */
96 #define BFD_AUTH_SIMPLE_LEN	16 + 3	/* RFC 5880 Page 10 */
97 #define BFD_AUTH_MD5_LEN	24	/* RFC 5880 Page 11 */
98 #define BFD_AUTH_SHA1_LEN	28	/* RFC 5880 Page 12 */
99 
100 /* Diagnostic Code (RFC 5880 Page 8) */
101 #define BFD_DIAG_NONE			0
102 #define BFD_DIAG_EXPIRED		1
103 #define BFD_DIAG_ECHO_FAILED		2
104 #define BFD_DIAG_NEIGHBOR_SIGDOWN	3
105 #define BFD_DIAG_FIB_RESET		4
106 #define BFD_DIAG_PATH_DOWN		5
107 #define BFD_DIAG_CONCAT_PATH_DOWN	6
108 #define BFD_DIAG_ADMIN_DOWN		7
109 #define BFD_DIAG_CONCAT_REVERSE_DOWN	8
110 
111 /* State (RFC 5880 Page 8) */
112 #define BFD_STATE_ADMINDOWN		0
113 #define BFD_STATE_DOWN			1
114 #define BFD_STATE_INIT			2
115 #define BFD_STATE_UP			3
116 
117 /* Flags (RFC 5880 Page 8) */
118 #define BFD_FLAG_P			0x20
119 #define BFD_FLAG_F			0x10
120 #define BFD_FLAG_C			0x08
121 #define BFD_FLAG_A			0x04
122 #define BFD_FLAG_D			0x02
123 #define BFD_FLAG_M			0x01
124 
125 
126 /* Auth Type (RFC 5880 Page 10) */
127 #define BFD_AUTH_TYPE_RESERVED		0
128 #define BFD_AUTH_TYPE_SIMPLE		1
129 #define BFD_AUTH_KEYED_MD5		2
130 #define BFD_AUTH_METICULOUS_MD5		3
131 #define BFD_AUTH_KEYED_SHA1		4
132 #define BFD_AUTH_METICULOUS_SHA1	5
133 
134 #define BFD_UDP_PORT_CONTROL		3784
135 #define BFD_UDP_PORT_ECHO		3785
136 
137 #define BFD_SECOND			1000000 /* 1,000,000 us == 1 second */
138 /* We currently tick every 10ms, so force a minimum that can be handled */
139 #define BFD_MINIMUM			50000	/* 50,000 us == 50 ms */
140 
141 
142 struct pool	 bfd_pool, bfd_pool_neigh, bfd_pool_time;
143 struct taskq	*bfdtq;
144 
145 
146 struct bfd_config *bfd_lookup(struct rtentry *);
147 void		 bfddestroy(void);
148 
149 struct socket	*bfd_listener(struct bfd_config *, unsigned int);
150 struct socket	*bfd_sender(struct bfd_config *, unsigned int);
151 void		 bfd_input(struct bfd_config *, struct mbuf *);
152 void		 bfd_set_state(struct bfd_config *, unsigned int);
153 
154 int	 bfd_send(struct bfd_config *, struct mbuf *);
155 void	 bfd_send_control(void *);
156 
157 void	 bfd_start_task(void *);
158 void	 bfd_send_task(void *);
159 void	 bfd_upcall_task(void *);
160 void	 bfd_clear_task(void *);
161 void	 bfd_error(struct bfd_config *);
162 void	 bfd_timeout_rx(void *);
163 void	 bfd_timeout_tx(void *);
164 
165 void	 bfd_upcall(struct socket *, caddr_t, int);
166 void	 bfd_senddown(struct bfd_config *);
167 void	 bfd_reset(struct bfd_config *);
168 void	 bfd_set_uptime(struct bfd_config *);
169 
170 void	 bfd_debug(struct bfd_config *);
171 
172 TAILQ_HEAD(bfd_queue, bfd_config)  bfd_queue;
173 
174 /*
175  * allocate a new bfd session
176  */
177 int
bfdset(struct rtentry * rt)178 bfdset(struct rtentry *rt)
179 {
180 	struct bfd_config	*bfd;
181 
182 	/* at the moment it is not allowed to run BFD on indirect routes */
183 	if (ISSET(rt->rt_flags, RTF_GATEWAY) || !ISSET(rt->rt_flags, RTF_HOST))
184 		return (EINVAL);
185 
186 	/* Do our necessary memory allocations upfront */
187 	bfd = pool_get(&bfd_pool, PR_WAITOK | PR_ZERO);
188 
189 	/* make sure we don't already have this setup */
190 	if (bfd_lookup(rt) != NULL) {
191 		pool_put(&bfd_pool, bfd);
192 		return (EADDRINUSE);
193 	}
194 
195 	bfd->bc_neighbor = pool_get(&bfd_pool_neigh, PR_WAITOK | PR_ZERO);
196 	bfd->bc_time = pool_get(&bfd_pool_time, PR_WAITOK | PR_ZERO);
197 
198 	bfd->bc_rt = rt;
199 	rtref(bfd->bc_rt);	/* we depend on this route not going away */
200 
201 	getmicrotime(bfd->bc_time);
202 	bfd_reset(bfd);
203 	bfd->bc_neighbor->bn_ldiscr = arc4random();
204 
205 	if (!timeout_initialized(&bfd->bc_timo_rx))
206 		timeout_set(&bfd->bc_timo_rx, bfd_timeout_rx, bfd);
207 	if (!timeout_initialized(&bfd->bc_timo_tx))
208 		timeout_set(&bfd->bc_timo_tx, bfd_timeout_tx, bfd);
209 
210 	task_set(&bfd->bc_bfd_task, bfd_start_task, bfd);
211 	task_set(&bfd->bc_clear_task, bfd_clear_task, bfd);
212 
213 	task_add(bfdtq, &bfd->bc_bfd_task);
214 
215 	TAILQ_INSERT_TAIL(&bfd_queue, bfd, bc_entry);
216 	bfd_set_state(bfd, BFD_STATE_DOWN);
217 
218 	return (0);
219 }
220 
221 /*
222  * remove and free a bfd session
223  */
224 void
bfdclear(struct rtentry * rt)225 bfdclear(struct rtentry *rt)
226 {
227 	struct bfd_config *bfd;
228 
229 	if ((bfd = bfd_lookup(rt)) == NULL)
230 		return;
231 
232 	task_add(bfdtq, &bfd->bc_clear_task);
233 }
234 
235 void
bfd_clear_task(void * arg)236 bfd_clear_task(void *arg)
237 {
238 	struct bfd_config	*bfd = (struct bfd_config *)arg;
239 	struct rtentry		*rt = bfd->bc_rt;
240 
241 	timeout_del(&bfd->bc_timo_rx);
242 	timeout_del(&bfd->bc_timo_tx);
243 	task_del(bfdtq, &bfd->bc_upcall_task);
244 	task_del(bfdtq, &bfd->bc_bfd_send_task);
245 
246 	TAILQ_REMOVE(&bfd_queue, bfd, bc_entry);
247 
248 	/* inform our neighbor */
249 	bfd_senddown(bfd);
250 
251 	rt->rt_flags &= ~RTF_BFD;
252 	if (bfd->bc_so) {
253 		/* remove upcall before calling soclose or it will be called */
254 		bfd->bc_so->so_upcall = NULL;
255 		soclose(bfd->bc_so, MSG_DONTWAIT);
256 	}
257 	if (bfd->bc_soecho) {
258 		bfd->bc_soecho->so_upcall = NULL;
259 		soclose(bfd->bc_soecho, MSG_DONTWAIT);
260 	}
261 	if (bfd->bc_sosend)
262 		soclose(bfd->bc_sosend, MSG_DONTWAIT);
263 
264 	rtfree(bfd->bc_rt);
265 	bfd->bc_rt = NULL;
266 
267 	pool_put(&bfd_pool_time, bfd->bc_time);
268 	pool_put(&bfd_pool_neigh, bfd->bc_neighbor);
269 	pool_put(&bfd_pool, bfd);
270 }
271 
272 /*
273  * Create and initialize the global bfd framework
274  */
275 void
bfdinit(void)276 bfdinit(void)
277 {
278 	pool_init(&bfd_pool, sizeof(struct bfd_config), 0,
279 	    IPL_SOFTNET, 0, "bfd_config", NULL);
280 	pool_init(&bfd_pool_neigh, sizeof(struct bfd_neighbor), 0,
281 	    IPL_SOFTNET, 0, "bfd_config_peer", NULL);
282 	pool_init(&bfd_pool_time, sizeof(struct timeval), 0,
283 	    IPL_SOFTNET, 0, "bfd_config_time", NULL);
284 
285 	bfdtq = taskq_create("bfd", 1, IPL_SOFTNET, 0);
286 	if (bfdtq == NULL)
287 		panic("unable to create BFD taskq");
288 
289 	TAILQ_INIT(&bfd_queue);
290 }
291 
292 /*
293  * Destroy all bfd sessions and remove the tasks
294  *
295  */
296 void
bfddestroy(void)297 bfddestroy(void)
298 {
299 	struct bfd_config	*bfd;
300 
301 	/* inform our neighbor we are rebooting */
302 	while ((bfd = TAILQ_FIRST(&bfd_queue))) {
303 		bfd->bc_neighbor->bn_ldiag = BFD_DIAG_FIB_RESET;
304 		bfdclear(bfd->bc_rt);
305 	}
306 
307 	taskq_barrier(bfdtq);
308 	taskq_destroy(bfdtq);
309 	pool_destroy(&bfd_pool_time);
310 	pool_destroy(&bfd_pool_neigh);
311 	pool_destroy(&bfd_pool);
312 }
313 
314 /*
315  * Return the matching bfd
316  */
317 struct bfd_config *
bfd_lookup(struct rtentry * rt)318 bfd_lookup(struct rtentry *rt)
319 {
320 	struct bfd_config *bfd;
321 
322 	TAILQ_FOREACH(bfd, &bfd_queue, bc_entry) {
323 		if (bfd->bc_rt == rt)
324 			return (bfd);
325 	}
326 	return (NULL);
327 }
328 
329 struct sockaddr *
bfd2sa(struct rtentry * rt,struct sockaddr_bfd * sa_bfd)330 bfd2sa(struct rtentry *rt, struct sockaddr_bfd *sa_bfd)
331 {
332 	struct bfd_config *bfd;
333 
334 	bfd = bfd_lookup(rt);
335 
336 	if (bfd == NULL)
337 		return (NULL);
338 
339 	memset(sa_bfd, 0, sizeof(*sa_bfd));
340 	sa_bfd->bs_len = sizeof(*sa_bfd);
341 	sa_bfd->bs_family = bfd->bc_rt->rt_dest->sa_family;
342 
343 	sa_bfd->bs_mode = bfd->bc_mode;
344 	sa_bfd->bs_mintx = bfd->bc_mintx;
345 	sa_bfd->bs_minrx = bfd->bc_minrx;
346 	sa_bfd->bs_minecho = bfd->bc_minecho;
347 	sa_bfd->bs_multiplier = bfd->bc_multiplier;
348 
349 	sa_bfd->bs_uptime = bfd->bc_time->tv_sec;
350 	sa_bfd->bs_lastuptime = bfd->bc_lastuptime;
351 	sa_bfd->bs_state = bfd->bc_state;
352 	sa_bfd->bs_remotestate = bfd->bc_neighbor->bn_rstate;
353 	sa_bfd->bs_laststate = bfd->bc_laststate;
354 	sa_bfd->bs_error = bfd->bc_error;
355 
356 	sa_bfd->bs_localdiscr = bfd->bc_neighbor->bn_ldiscr;
357 	sa_bfd->bs_localdiag = bfd->bc_neighbor->bn_ldiag;
358 	sa_bfd->bs_remotediscr = bfd->bc_neighbor->bn_rdiscr;
359 	sa_bfd->bs_remotediag = bfd->bc_neighbor->bn_rdiag;
360 
361 	return ((struct sockaddr *)sa_bfd);
362 }
363 
364 /*
365  * End of public interfaces.
366  *
367  * Everything below this line should not be used outside of this file.
368  */
369 
370 /*
371  * Task to listen and kick off the bfd process
372  */
373 void
bfd_start_task(void * arg)374 bfd_start_task(void *arg)
375 {
376 	struct bfd_config	*bfd = (struct bfd_config *)arg;
377 
378 	/* start listeners */
379 	bfd->bc_so = bfd_listener(bfd, BFD_UDP_PORT_CONTROL);
380 	if (!bfd->bc_so)
381 		printf("bfd_listener(%d) failed\n",
382 		    BFD_UDP_PORT_CONTROL);
383 	bfd->bc_soecho = bfd_listener(bfd, BFD_UDP_PORT_ECHO);
384 	if (!bfd->bc_soecho)
385 		printf("bfd_listener(%d) failed\n",
386 		    BFD_UDP_PORT_ECHO);
387 
388 	/* start sending */
389 	bfd->bc_sosend = bfd_sender(bfd, BFD_UDP_PORT_CONTROL);
390 	if (bfd->bc_sosend) {
391 		task_set(&bfd->bc_bfd_send_task, bfd_send_task, bfd);
392 		task_add(bfdtq, &bfd->bc_bfd_send_task);
393 	}
394 
395 	task_set(&bfd->bc_upcall_task, bfd_upcall_task, bfd);
396 
397 	return;
398 }
399 
400 void
bfd_send_task(void * arg)401 bfd_send_task(void *arg)
402 {
403 	struct bfd_config	*bfd = (struct bfd_config *)arg;
404 	struct rtentry		*rt = bfd->bc_rt;
405 
406 	if (ISSET(rt->rt_flags, RTF_UP)) {
407 		bfd_send_control(bfd);
408 	} else {
409 		if (bfd->bc_neighbor->bn_lstate > BFD_STATE_DOWN) {
410 			bfd->bc_error++;
411 			bfd->bc_neighbor->bn_ldiag = BFD_DIAG_PATH_DOWN;
412 			bfd_reset(bfd);
413 			bfd_set_state(bfd, BFD_STATE_DOWN);
414 		}
415 	}
416 //rtm_bfd(bfd);
417 
418 	/* re-add 70%-90% jitter to our transmits, rfc 5880 6.8.7 */
419 	timeout_add_usec(&bfd->bc_timo_tx,
420 	    bfd->bc_mintx * (arc4random_uniform(20) + 70) / 100);
421 }
422 
423 /*
424  * Setup a bfd listener socket
425  */
426 struct socket *
bfd_listener(struct bfd_config * bfd,unsigned int port)427 bfd_listener(struct bfd_config *bfd, unsigned int port)
428 {
429 	struct proc		*p = curproc;
430 	struct rtentry		*rt = bfd->bc_rt;
431 	struct sockaddr		*src = rt->rt_ifa->ifa_addr;
432 	struct sockaddr		*dst = rt_key(rt);
433 	struct sockaddr		*sa;
434 	struct sockaddr_in	*sin;
435 	struct sockaddr_in6	*sin6;
436 	struct socket		*so;
437 	struct mbuf		*m = NULL, *mopt = NULL;
438 	int			*ip, error;
439 
440 	/* sa_family and sa_len must be equal */
441 	if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len)
442 		return (NULL);
443 
444 	error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0);
445 	if (error) {
446 		printf("%s: socreate error %d\n",
447 		    __func__, error);
448 		return (NULL);
449 	}
450 
451 	MGET(mopt, M_WAIT, MT_SOOPTS);
452 	mopt->m_len = sizeof(int);
453 	ip = mtod(mopt, int *);
454 	*ip = MAXTTL;
455 	error = sosetopt(so, IPPROTO_IP, IP_MINTTL, mopt);
456 	m_freem(mopt);
457 	if (error) {
458 		printf("%s: sosetopt error %d\n",
459 		    __func__, error);
460 		goto close;
461 	}
462 
463 	MGET(m, M_WAIT, MT_SONAME);
464 	m->m_len = src->sa_len;
465 	sa = mtod(m, struct sockaddr *);
466 	memcpy(sa, src, src->sa_len);
467 	switch(sa->sa_family) {
468 	case AF_INET:
469 		sin = (struct sockaddr_in *)sa;
470 		sin->sin_port = htons(port);
471 		break;
472 	case AF_INET6:
473 		sin6 = (struct sockaddr_in6 *)sa;
474 		sin6->sin6_port = htons(port);
475 		break;
476 	default:
477 		break;
478 	}
479 
480 	solock(so);
481 	error = sobind(so, m, p);
482 	sounlock(so);
483 	if (error) {
484 		printf("%s: sobind error %d\n",
485 		    __func__, error);
486 		goto close;
487 	}
488 	so->so_upcallarg = (caddr_t)bfd;
489 	so->so_upcall = bfd_upcall;
490 
491 	m_free(m);
492 
493 	return (so);
494 
495  close:
496 	m_free(m);
497 	soclose(so, MSG_DONTWAIT);
498 
499 	return (NULL);
500 }
501 
502 /*
503  * Setup the bfd sending process
504  */
505 struct socket *
bfd_sender(struct bfd_config * bfd,unsigned int port)506 bfd_sender(struct bfd_config *bfd, unsigned int port)
507 {
508 	struct socket		*so;
509 	struct rtentry		*rt = bfd->bc_rt;
510 	struct proc		*p = curproc;
511 	struct mbuf		*m = NULL, *mopt = NULL;
512 	struct sockaddr		*src = rt->rt_ifa->ifa_addr;
513 	struct sockaddr		*dst = rt_key(rt);
514 	struct sockaddr		*sa;
515 	struct sockaddr_in6	*sin6;
516 	struct sockaddr_in	*sin;
517 	int		 error, *ip;
518 
519 	/* sa_family and sa_len must be equal */
520 	if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len)
521 		return (NULL);
522 
523 	error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0);
524 
525 	if (error)
526 		return (NULL);
527 
528 	MGET(mopt, M_WAIT, MT_SOOPTS);
529 	mopt->m_len = sizeof(int);
530 	ip = mtod(mopt, int *);
531 	*ip = IP_PORTRANGE_HIGH;
532 	error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
533 	m_freem(mopt);
534 	if (error) {
535 		printf("%s: sosetopt error %d\n",
536 		    __func__, error);
537 		goto close;
538 	}
539 
540 	MGET(mopt, M_WAIT, MT_SOOPTS);
541 	mopt->m_len = sizeof(int);
542 	ip = mtod(mopt, int *);
543 	*ip = MAXTTL;
544 	error = sosetopt(so, IPPROTO_IP, IP_TTL, mopt);
545 	m_freem(mopt);
546 	if (error) {
547 		printf("%s: sosetopt error %d\n",
548 		    __func__, error);
549 		goto close;
550 	}
551 
552 	MGET(mopt, M_WAIT, MT_SOOPTS);
553 	mopt->m_len = sizeof(int);
554 	ip = mtod(mopt, int *);
555 	*ip = IPTOS_PREC_INTERNETCONTROL;
556 	error = sosetopt(so, IPPROTO_IP, IP_TOS, mopt);
557 	m_freem(mopt);
558 	if (error) {
559 		printf("%s: sosetopt error %d\n",
560 		    __func__, error);
561 		goto close;
562 	}
563 
564 	MGET(m, M_WAIT, MT_SONAME);
565 	m->m_len = src->sa_len;
566 	sa = mtod(m, struct sockaddr *);
567 	memcpy(sa, src, src->sa_len);
568 	switch(sa->sa_family) {
569 	case AF_INET:
570 		sin = (struct sockaddr_in *)sa;
571 		sin->sin_port = 0;
572 		break;
573 	case AF_INET6:
574 		sin6 = (struct sockaddr_in6 *)sa;
575 		sin6->sin6_port = 0;
576 		break;
577 	default:
578 		break;
579 	}
580 
581 	solock(so);
582 	error = sobind(so, m, p);
583 	sounlock(so);
584 	if (error) {
585 		printf("%s: sobind error %d\n",
586 		    __func__, error);
587 		goto close;
588 	}
589 
590 	memcpy(sa, dst, dst->sa_len);
591 	switch(sa->sa_family) {
592 	case AF_INET:
593 		sin = (struct sockaddr_in *)sa;
594 		sin->sin_port = ntohs(port);
595 		break;
596 	case AF_INET6:
597 		sin6 = (struct sockaddr_in6 *)sa;
598 		sin6->sin6_port = ntohs(port);
599 		break;
600 	default:
601 		break;
602 	}
603 
604 	solock(so);
605 	error = soconnect(so, m);
606 	sounlock(so);
607 	if (error && error != ECONNREFUSED) {
608 		printf("%s: soconnect error %d\n",
609 		    __func__, error);
610 		goto close;
611 	}
612 
613 	m_free(m);
614 
615 	return (so);
616 
617  close:
618 	m_free(m);
619 	soclose(so, MSG_DONTWAIT);
620 
621 	return (NULL);
622 }
623 
624 /*
625  * Will be called per-received packet
626  */
627 void
bfd_upcall(struct socket * so,caddr_t arg,int waitflag)628 bfd_upcall(struct socket *so, caddr_t arg, int waitflag)
629 {
630 	struct bfd_config *bfd = (struct bfd_config *)arg;
631 
632 	bfd->bc_upcallso = so;
633 	task_add(bfdtq, &bfd->bc_upcall_task);
634 }
635 
636 void
bfd_upcall_task(void * arg)637 bfd_upcall_task(void *arg)
638 {
639 	struct bfd_config	*bfd = (struct bfd_config *)arg;
640 	struct socket		*so = bfd->bc_upcallso;
641 	struct mbuf		*m;
642 	struct uio		 uio;
643 	int			 flags, error;
644 
645 	uio.uio_procp = NULL;
646 	do {
647 		uio.uio_resid = so->so_rcv.sb_cc;
648 		flags = MSG_DONTWAIT;
649 		error = soreceive(so, NULL, &uio, &m, NULL, &flags, 0);
650 		if (error && error != EAGAIN) {
651 			bfd_error(bfd);
652 			return;
653 		}
654 		if (m != NULL)
655 			bfd_input(bfd, m);
656 	} while (so->so_rcv.sb_cc);
657 
658 	bfd->bc_upcallso = NULL;
659 
660 	return;
661 }
662 
663 void
bfd_error(struct bfd_config * bfd)664 bfd_error(struct bfd_config *bfd)
665 {
666 	if (bfd->bc_state <= BFD_STATE_DOWN)
667 		return;
668 
669 	if (++bfd->bc_error >= bfd->bc_neighbor->bn_mult) {
670 		bfd->bc_neighbor->bn_ldiag = BFD_DIAG_EXPIRED;
671 		bfd_reset(bfd);
672 		if (bfd->bc_state > BFD_STATE_DOWN)
673 			bfd_set_state(bfd, BFD_STATE_DOWN);
674 	}
675 }
676 
677 void
bfd_timeout_tx(void * v)678 bfd_timeout_tx(void *v)
679 {
680 	struct bfd_config *bfd = v;
681 	task_add(bfdtq, &bfd->bc_bfd_send_task);
682 }
683 
684 /*
685  * Triggers when we do not receive a valid packet in time
686  */
687 void
bfd_timeout_rx(void * v)688 bfd_timeout_rx(void *v)
689 {
690 	struct bfd_config *bfd = v;
691 
692 	if (bfd->bc_state > BFD_STATE_DOWN) {
693 		bfd_error(bfd);
694 		rtm_bfd(bfd);
695 	}
696 
697 	timeout_add_usec(&bfd->bc_timo_rx, bfd->bc_minrx);
698 }
699 
700 /*
701  * Tell our neighbor that we are going down
702  */
703 void
bfd_senddown(struct bfd_config * bfd)704 bfd_senddown(struct bfd_config *bfd)
705 {
706 	/* If we are down, return early */
707 	if (bfd->bc_state < BFD_STATE_INIT)
708 		return;
709 
710 	if (bfd->bc_neighbor->bn_ldiag == 0)
711 		bfd->bc_neighbor->bn_ldiag = BFD_DIAG_ADMIN_DOWN;
712 
713 	bfd_set_state(bfd, BFD_STATE_ADMINDOWN);
714 	bfd_send_control(bfd);
715 
716 	return;
717 }
718 
719 /*
720  * Clean a BFD peer to defaults
721  */
722 void
bfd_reset(struct bfd_config * bfd)723 bfd_reset(struct bfd_config *bfd)
724 {
725 	/* Clean */
726 	bfd->bc_neighbor->bn_rdiscr = 0;
727 	bfd->bc_neighbor->bn_demand = 0;
728 	bfd->bc_neighbor->bn_rdemand = 0;
729 	bfd->bc_neighbor->bn_authtype = 0;
730 	bfd->bc_neighbor->bn_rauthseq = 0;
731 	bfd->bc_neighbor->bn_lauthseq = 0;
732 	bfd->bc_neighbor->bn_authseqknown = 0;
733 	bfd->bc_neighbor->bn_ldiag = 0;
734 
735 	bfd->bc_mode = BFD_MODE_ASYNC;
736 	bfd->bc_state = BFD_STATE_DOWN;
737 
738 	/* rfc5880 6.8.18 */
739 	bfd->bc_neighbor->bn_lstate = BFD_STATE_DOWN;
740 	bfd->bc_neighbor->bn_rstate = BFD_STATE_DOWN;
741 	bfd->bc_neighbor->bn_mintx = BFD_SECOND;
742 	bfd->bc_neighbor->bn_req_minrx = BFD_SECOND;
743 	bfd->bc_neighbor->bn_rminrx = 1;
744 	bfd->bc_neighbor->bn_mult = 3;
745 
746 	bfd->bc_mintx = bfd->bc_neighbor->bn_mintx;
747 	bfd->bc_minrx = bfd->bc_neighbor->bn_req_minrx;
748 	bfd->bc_multiplier = bfd->bc_neighbor->bn_mult;
749 	bfd->bc_minecho = 0;	//XXX - BFD_SECOND;
750 
751 	bfd_set_uptime(bfd);
752 
753 	return;
754 }
755 
756 void
bfd_input(struct bfd_config * bfd,struct mbuf * m)757 bfd_input(struct bfd_config *bfd, struct mbuf *m)
758 {
759 	struct bfd_header	*peer;
760 	struct bfd_auth_header	*auth;
761 	struct mbuf		*mp, *mp0;
762 	unsigned int		 ver, diag = BFD_DIAG_NONE, state, flags;
763 	int			 offp;
764 
765 	mp = m_pulldown(m, 0, sizeof(*peer), &offp);
766 
767 	if (mp == NULL)
768 		return;
769 	peer = (struct bfd_header *)(mp->m_data + offp);
770 
771 	/* We only support BFD Version 1 */
772 	if (( ver = BFD_VER(peer->bfd_ver_diag)) != 1)
773 		goto discard;
774 
775 	diag = BFD_DIAG(peer->bfd_ver_diag);
776 	state = BFD_STATE(peer->bfd_sta_flags);
777 	flags = BFD_FLAGS(peer->bfd_sta_flags);
778 
779 	if (peer->bfd_length + offp > mp->m_len) {
780 		printf("%s: bad len %d != %d\n", __func__,
781 		    peer->bfd_length + offp, mp->m_len);
782 		goto discard;
783 	}
784 
785 	if (peer->bfd_detect_multi == 0)
786 		goto discard;
787 	if (flags & BFD_FLAG_M)
788 		goto discard;
789 	if (ntohl(peer->bfd_my_discriminator) == 0)
790 		goto discard;
791 	if (ntohl(peer->bfd_your_discriminator) == 0 &&
792 	    BFD_STATE(peer->bfd_sta_flags) > BFD_STATE_DOWN)
793 		goto discard;
794 	if ((ntohl(peer->bfd_your_discriminator) != 0) &&
795 	    (ntohl(peer->bfd_your_discriminator) !=
796 	    bfd->bc_neighbor->bn_ldiscr)) {
797 		bfd_error(bfd);
798 		goto discard;
799 	}
800 
801 	if ((flags & BFD_FLAG_A) && bfd->bc_neighbor->bn_authtype == 0)
802 		goto discard;
803 	if (!(flags & BFD_FLAG_A) && bfd->bc_neighbor->bn_authtype != 0)
804 		goto discard;
805 	if (flags & BFD_FLAG_A) {
806 		mp0 = m_pulldown(mp, 0, sizeof(*auth), &offp);
807 		if (mp0 == NULL)
808 			goto discard;
809 		auth = (struct bfd_auth_header *)(mp0->m_data + offp);
810 #if 0
811 		if (bfd_process_auth(bfd, auth) != 0) {
812 			m_free(mp0);
813 			goto discard;
814 		}
815 #endif
816 	}
817 
818 	bfd->bc_neighbor->bn_rdiscr = ntohl(peer->bfd_my_discriminator);
819 	bfd->bc_neighbor->bn_rstate = state;
820 	bfd->bc_neighbor->bn_rdemand = (flags & BFD_FLAG_D);
821 	bfd->bc_poll = (flags & BFD_FLAG_F);
822 
823 	/* Local change to the algorithm, we don't accept below 50ms */
824 	if (ntohl(peer->bfd_required_min_rx_interval) < BFD_MINIMUM)
825 		goto discard;
826 	/*
827 	 * Local change to the algorithm, we can't use larger than signed
828 	 * 32bits for a timeout.
829 	 * That is Too Long(tm) anyways.
830 	 */
831 	if (ntohl(peer->bfd_required_min_rx_interval) > INT32_MAX)
832 		goto discard;
833 	bfd->bc_neighbor->bn_rminrx =
834 	    ntohl(peer->bfd_required_min_rx_interval);
835 	bfd->bc_minrx = bfd->bc_neighbor->bn_req_minrx;
836 
837 	bfd->bc_neighbor->bn_mintx =
838 	    htonl(peer->bfd_desired_min_tx_interval);
839 	if (bfd->bc_neighbor->bn_lstate != BFD_STATE_UP)
840 		bfd->bc_neighbor->bn_mintx = BFD_SECOND;
841 
842 	bfd->bc_neighbor->bn_req_minrx =
843 	    ntohl(peer->bfd_required_min_rx_interval);
844 
845 	/* rfc5880 6.8.7 */
846 	bfd->bc_mintx = max(bfd->bc_neighbor->bn_rminrx,
847 	    bfd->bc_neighbor->bn_mintx);
848 
849 	/* According the to pseudo-code RFC 5880 page 34 */
850 	if (bfd->bc_state == BFD_STATE_ADMINDOWN)
851 		goto discard;
852 	if (bfd->bc_neighbor->bn_rstate == BFD_STATE_ADMINDOWN) {
853 		if (bfd->bc_neighbor->bn_lstate != BFD_STATE_DOWN) {
854 			bfd->bc_neighbor->bn_ldiag = BFD_DIAG_NEIGHBOR_SIGDOWN;
855 			bfd_set_state(bfd, BFD_STATE_DOWN);
856 		}
857 	} else if (bfd->bc_neighbor->bn_lstate == BFD_STATE_DOWN) {
858 		if (bfd->bc_neighbor->bn_rstate == BFD_STATE_DOWN)
859 			bfd_set_state(bfd, BFD_STATE_INIT);
860 		else if (bfd->bc_neighbor->bn_rstate == BFD_STATE_INIT) {
861 			bfd->bc_neighbor->bn_ldiag = 0;
862 			bfd_set_state(bfd, BFD_STATE_UP);
863 		}
864 	} else if (bfd->bc_neighbor->bn_lstate == BFD_STATE_INIT) {
865 		if (bfd->bc_neighbor->bn_rstate >= BFD_STATE_INIT) {
866 			bfd->bc_neighbor->bn_ldiag = 0;
867 			bfd_set_state(bfd, BFD_STATE_UP);
868 		} else {
869 			goto discard;
870 		}
871 	} else {
872 		if (bfd->bc_neighbor->bn_rstate == BFD_STATE_DOWN) {
873 			bfd->bc_neighbor->bn_ldiag = BFD_DIAG_NEIGHBOR_SIGDOWN;
874 			bfd_set_state(bfd, BFD_STATE_DOWN);
875 			goto discard;
876 		}
877 	}
878 
879 	if (bfd->bc_neighbor->bn_lstate == BFD_STATE_UP) {
880 		bfd->bc_neighbor->bn_ldiag = 0;
881 		bfd->bc_neighbor->bn_demand = 1;
882 		bfd->bc_neighbor->bn_rdemand = (flags & BFD_FLAG_D);
883 	}
884 
885 	bfd->bc_error = 0;
886 
887  discard:
888 	bfd->bc_neighbor->bn_rdiag = diag;
889 	m_free(m);
890 
891 	timeout_add_usec(&bfd->bc_timo_rx, bfd->bc_minrx);
892 
893 	return;
894 }
895 
896 void
bfd_set_state(struct bfd_config * bfd,unsigned int state)897 bfd_set_state(struct bfd_config *bfd, unsigned int state)
898 {
899 	struct ifnet	*ifp;
900 	struct rtentry	*rt = bfd->bc_rt;
901 
902 	ifp = if_get(rt->rt_ifidx);
903 	if (ifp == NULL) {
904 		printf("%s: cannot find interface index %u\n",
905 		    __func__, rt->rt_ifidx);
906 		bfd->bc_error++;
907 		bfd_reset(bfd);
908 		return;
909 	}
910 
911 	bfd->bc_neighbor->bn_lstate = state;
912 	if (state > BFD_STATE_ADMINDOWN)
913 		bfd->bc_neighbor->bn_ldiag = 0;
914 
915 	if (!rtisvalid(rt))
916 		bfd->bc_neighbor->bn_lstate = BFD_STATE_DOWN;
917 
918 	switch (state) {
919 	case BFD_STATE_ADMINDOWN:
920 		bfd->bc_laststate = bfd->bc_state;
921 	/* FALLTHROUGH */
922 	case BFD_STATE_DOWN:
923 		if (bfd->bc_state == BFD_STATE_UP) {
924 			bfd->bc_laststate = bfd->bc_state;
925 			bfd_set_uptime(bfd);
926 		}
927 		break;
928 	case BFD_STATE_INIT:
929 		bfd->bc_laststate = bfd->bc_state;
930 		break;
931 	case BFD_STATE_UP:
932 		bfd->bc_laststate =
933 		    bfd->bc_state == BFD_STATE_INIT ?
934 		    bfd->bc_laststate : bfd->bc_state;
935 		bfd_set_uptime(bfd);
936 		break;
937 	}
938 
939 	bfd->bc_state = state;
940 	rtm_bfd(bfd);
941 	if_put(ifp);
942 
943 	return;
944 }
945 
946 void
bfd_set_uptime(struct bfd_config * bfd)947 bfd_set_uptime(struct bfd_config *bfd)
948 {
949 	struct timeval tv;
950 
951 	getmicrotime(&tv);
952 	bfd->bc_lastuptime = tv.tv_sec - bfd->bc_time->tv_sec;
953 	memcpy(bfd->bc_time, &tv, sizeof(tv));
954 }
955 
956 void
bfd_send_control(void * x)957 bfd_send_control(void *x)
958 {
959 	struct bfd_config	*bfd = x;
960 	struct mbuf		*m;
961 	struct bfd_header	*h;
962 	int error, len;
963 
964 	MGETHDR(m, M_WAIT, MT_DATA);
965 	MCLGET(m, M_WAIT);
966 
967 	len = BFD_HDRLEN;
968 	m->m_len = m->m_pkthdr.len = len;
969 	h = mtod(m, struct bfd_header *);
970 
971 	memset(h, 0xff, sizeof(*h));	/* canary */
972 
973 	h->bfd_ver_diag = ((BFD_VERSION << 5) | (bfd->bc_neighbor->bn_ldiag));
974 	h->bfd_sta_flags = (bfd->bc_state << 6);
975 	h->bfd_detect_multi = bfd->bc_neighbor->bn_mult;
976 	h->bfd_length = BFD_HDRLEN;
977 	h->bfd_my_discriminator = htonl(bfd->bc_neighbor->bn_ldiscr);
978 	h->bfd_your_discriminator = htonl(bfd->bc_neighbor->bn_rdiscr);
979 
980 	h->bfd_desired_min_tx_interval =
981 	    htonl(bfd->bc_neighbor->bn_mintx);
982 	h->bfd_required_min_rx_interval =
983 	    htonl(bfd->bc_neighbor->bn_req_minrx);
984 	h->bfd_required_min_echo_interval = htonl(bfd->bc_minecho);
985 
986 	error = bfd_send(bfd, m);
987 
988 	if (error) {
989 		bfd_error(bfd);
990 		if (!(error == EHOSTDOWN || error == ECONNREFUSED)) {
991 			printf("%s: %u\n", __func__, error);
992 		}
993 	}
994 }
995 
996 int
bfd_send(struct bfd_config * bfd,struct mbuf * m)997 bfd_send(struct bfd_config *bfd, struct mbuf *m)
998 {
999 	return(sosend(bfd->bc_sosend, NULL, NULL, m, NULL, MSG_DONTWAIT));
1000 }
1001 
1002 /*
1003  * Print debug information about this bfd instance
1004  */
1005 void
bfd_debug(struct bfd_config * bfd)1006 bfd_debug(struct bfd_config *bfd)
1007 {
1008 	struct rtentry	*rt = bfd->bc_rt;
1009 	struct timeval	 tv;
1010 	char buf[64];
1011 
1012 	printf("dest: %s ", sockaddr_ntop(rt_key(rt), buf, sizeof(buf)));
1013 	printf("src: %s ", sockaddr_ntop(rt->rt_ifa->ifa_addr, buf,
1014 	    sizeof(buf)));
1015 	printf("\n");
1016 	printf("\t");
1017 	printf("session state: %u ", bfd->bc_state);
1018 	printf("mode: %u ", bfd->bc_mode);
1019 	printf("error: %u ", bfd->bc_error);
1020 	printf("minrx: %u ", bfd->bc_minrx);
1021 	printf("mintx: %u ", bfd->bc_mintx);
1022 	printf("multiplier: %u ", bfd->bc_multiplier);
1023 	printf("\n");
1024 	printf("\t");
1025 	printf("local session state: %u ", bfd->bc_neighbor->bn_lstate);
1026 	printf("local diag: %u ", bfd->bc_neighbor->bn_ldiag);
1027 	printf("\n");
1028 	printf("\t");
1029 	printf("remote discriminator: %u ", bfd->bc_neighbor->bn_rdiscr);
1030 	printf("local discriminator: %u ", bfd->bc_neighbor->bn_ldiscr);
1031 	printf("\n");
1032 	printf("\t");
1033 	printf("remote session state: %u ", bfd->bc_neighbor->bn_rstate);
1034 	printf("remote diag: %u ", bfd->bc_neighbor->bn_rdiag);
1035 	printf("remote min rx: %u ", bfd->bc_neighbor->bn_rminrx);
1036 	printf("\n");
1037 	printf("\t");
1038 	printf("last state: %u ", bfd->bc_laststate);
1039 	getmicrotime(&tv);
1040 	printf("uptime %llds ", tv.tv_sec - bfd->bc_time->tv_sec);
1041 	printf("time started %lld.%06ld ", bfd->bc_time->tv_sec,
1042 	    bfd->bc_time->tv_usec);
1043 	printf("last uptime %llds ", bfd->bc_lastuptime);
1044 	printf("\n");
1045 }
1046