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 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 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 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 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 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 * 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 * 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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