1 /* $OpenBSD: bfd.c,v 1.78 2021/09/14 09:15:55 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 int s; 440 441 /* sa_family and sa_len must be equal */ 442 if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len) 443 return (NULL); 444 445 error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0); 446 if (error) { 447 printf("%s: socreate error %d\n", 448 __func__, error); 449 return (NULL); 450 } 451 452 MGET(mopt, M_WAIT, MT_SOOPTS); 453 mopt->m_len = sizeof(int); 454 ip = mtod(mopt, int *); 455 *ip = MAXTTL; 456 s = solock(so); 457 error = sosetopt(so, IPPROTO_IP, IP_MINTTL, mopt); 458 sounlock(so, s); 459 m_freem(mopt); 460 if (error) { 461 printf("%s: sosetopt error %d\n", 462 __func__, error); 463 goto close; 464 } 465 466 MGET(m, M_WAIT, MT_SONAME); 467 m->m_len = src->sa_len; 468 sa = mtod(m, struct sockaddr *); 469 memcpy(sa, src, src->sa_len); 470 switch(sa->sa_family) { 471 case AF_INET: 472 sin = (struct sockaddr_in *)sa; 473 sin->sin_port = htons(port); 474 break; 475 case AF_INET6: 476 sin6 = (struct sockaddr_in6 *)sa; 477 sin6->sin6_port = htons(port); 478 break; 479 default: 480 break; 481 } 482 483 s = solock(so); 484 error = sobind(so, m, p); 485 sounlock(so, s); 486 if (error) { 487 printf("%s: sobind error %d\n", 488 __func__, error); 489 goto close; 490 } 491 so->so_upcallarg = (caddr_t)bfd; 492 so->so_upcall = bfd_upcall; 493 494 m_free(m); 495 496 return (so); 497 498 close: 499 m_free(m); 500 soclose(so, MSG_DONTWAIT); 501 502 return (NULL); 503 } 504 505 /* 506 * Setup the bfd sending process 507 */ 508 struct socket * 509 bfd_sender(struct bfd_config *bfd, unsigned int port) 510 { 511 struct socket *so; 512 struct rtentry *rt = bfd->bc_rt; 513 struct proc *p = curproc; 514 struct mbuf *m = NULL, *mopt = NULL; 515 struct sockaddr *src = rt->rt_ifa->ifa_addr; 516 struct sockaddr *dst = rt_key(rt); 517 struct sockaddr *sa; 518 struct sockaddr_in6 *sin6; 519 struct sockaddr_in *sin; 520 int error, *ip; 521 int s; 522 523 /* sa_family and sa_len must be equal */ 524 if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len) 525 return (NULL); 526 527 error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0); 528 529 if (error) 530 return (NULL); 531 532 MGET(mopt, M_WAIT, MT_SOOPTS); 533 mopt->m_len = sizeof(int); 534 ip = mtod(mopt, int *); 535 *ip = IP_PORTRANGE_HIGH; 536 s = solock(so); 537 error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt); 538 sounlock(so, s); 539 m_freem(mopt); 540 if (error) { 541 printf("%s: sosetopt error %d\n", 542 __func__, error); 543 goto close; 544 } 545 546 MGET(mopt, M_WAIT, MT_SOOPTS); 547 mopt->m_len = sizeof(int); 548 ip = mtod(mopt, int *); 549 *ip = MAXTTL; 550 s = solock(so); 551 error = sosetopt(so, IPPROTO_IP, IP_TTL, mopt); 552 sounlock(so, s); 553 m_freem(mopt); 554 if (error) { 555 printf("%s: sosetopt error %d\n", 556 __func__, error); 557 goto close; 558 } 559 560 MGET(mopt, M_WAIT, MT_SOOPTS); 561 mopt->m_len = sizeof(int); 562 ip = mtod(mopt, int *); 563 *ip = IPTOS_PREC_INTERNETCONTROL; 564 s = solock(so); 565 error = sosetopt(so, IPPROTO_IP, IP_TOS, mopt); 566 sounlock(so, s); 567 m_freem(mopt); 568 if (error) { 569 printf("%s: sosetopt error %d\n", 570 __func__, error); 571 goto close; 572 } 573 574 MGET(m, M_WAIT, MT_SONAME); 575 m->m_len = src->sa_len; 576 sa = mtod(m, struct sockaddr *); 577 memcpy(sa, src, src->sa_len); 578 switch(sa->sa_family) { 579 case AF_INET: 580 sin = (struct sockaddr_in *)sa; 581 sin->sin_port = 0; 582 break; 583 case AF_INET6: 584 sin6 = (struct sockaddr_in6 *)sa; 585 sin6->sin6_port = 0; 586 break; 587 default: 588 break; 589 } 590 591 s = solock(so); 592 error = sobind(so, m, p); 593 sounlock(so, s); 594 if (error) { 595 printf("%s: sobind error %d\n", 596 __func__, error); 597 goto close; 598 } 599 600 memcpy(sa, dst, dst->sa_len); 601 switch(sa->sa_family) { 602 case AF_INET: 603 sin = (struct sockaddr_in *)sa; 604 sin->sin_port = ntohs(port); 605 break; 606 case AF_INET6: 607 sin6 = (struct sockaddr_in6 *)sa; 608 sin6->sin6_port = ntohs(port); 609 break; 610 default: 611 break; 612 } 613 614 s = solock(so); 615 error = soconnect(so, m); 616 sounlock(so, s); 617 if (error && error != ECONNREFUSED) { 618 printf("%s: soconnect error %d\n", 619 __func__, error); 620 goto close; 621 } 622 623 m_free(m); 624 625 return (so); 626 627 close: 628 m_free(m); 629 soclose(so, MSG_DONTWAIT); 630 631 return (NULL); 632 } 633 634 /* 635 * Will be called per-received packet 636 */ 637 void 638 bfd_upcall(struct socket *so, caddr_t arg, int waitflag) 639 { 640 struct bfd_config *bfd = (struct bfd_config *)arg; 641 642 bfd->bc_upcallso = so; 643 task_add(bfdtq, &bfd->bc_upcall_task); 644 } 645 646 void 647 bfd_upcall_task(void *arg) 648 { 649 struct bfd_config *bfd = (struct bfd_config *)arg; 650 struct socket *so = bfd->bc_upcallso; 651 struct mbuf *m; 652 struct uio uio; 653 int flags, error; 654 655 uio.uio_procp = NULL; 656 do { 657 uio.uio_resid = so->so_rcv.sb_cc; 658 flags = MSG_DONTWAIT; 659 error = soreceive(so, NULL, &uio, &m, NULL, &flags, 0); 660 if (error && error != EAGAIN) { 661 bfd_error(bfd); 662 return; 663 } 664 if (m != NULL) 665 bfd_input(bfd, m); 666 } while (so->so_rcv.sb_cc); 667 668 bfd->bc_upcallso = NULL; 669 670 return; 671 } 672 673 void 674 bfd_error(struct bfd_config *bfd) 675 { 676 if (bfd->bc_state <= BFD_STATE_DOWN) 677 return; 678 679 if (++bfd->bc_error >= bfd->bc_neighbor->bn_mult) { 680 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_EXPIRED; 681 bfd_reset(bfd); 682 if (bfd->bc_state > BFD_STATE_DOWN) 683 bfd_set_state(bfd, BFD_STATE_DOWN); 684 } 685 } 686 687 void 688 bfd_timeout_tx(void *v) 689 { 690 struct bfd_config *bfd = v; 691 task_add(bfdtq, &bfd->bc_bfd_send_task); 692 } 693 694 /* 695 * Triggers when we do not receive a valid packet in time 696 */ 697 void 698 bfd_timeout_rx(void *v) 699 { 700 struct bfd_config *bfd = v; 701 702 if (bfd->bc_state > BFD_STATE_DOWN) { 703 bfd_error(bfd); 704 rtm_bfd(bfd); 705 } 706 707 timeout_add_usec(&bfd->bc_timo_rx, bfd->bc_minrx); 708 } 709 710 /* 711 * Tell our neighbor that we are going down 712 */ 713 void 714 bfd_senddown(struct bfd_config *bfd) 715 { 716 /* If we are down, return early */ 717 if (bfd->bc_state < BFD_STATE_INIT) 718 return; 719 720 if (bfd->bc_neighbor->bn_ldiag == 0) 721 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_ADMIN_DOWN; 722 723 bfd_set_state(bfd, BFD_STATE_ADMINDOWN); 724 bfd_send_control(bfd); 725 726 return; 727 } 728 729 /* 730 * Clean a BFD peer to defaults 731 */ 732 void 733 bfd_reset(struct bfd_config *bfd) 734 { 735 /* Clean */ 736 bfd->bc_neighbor->bn_rdiscr = 0; 737 bfd->bc_neighbor->bn_demand = 0; 738 bfd->bc_neighbor->bn_rdemand = 0; 739 bfd->bc_neighbor->bn_authtype = 0; 740 bfd->bc_neighbor->bn_rauthseq = 0; 741 bfd->bc_neighbor->bn_lauthseq = 0; 742 bfd->bc_neighbor->bn_authseqknown = 0; 743 bfd->bc_neighbor->bn_ldiag = 0; 744 745 bfd->bc_mode = BFD_MODE_ASYNC; 746 bfd->bc_state = BFD_STATE_DOWN; 747 748 /* rfc5880 6.8.18 */ 749 bfd->bc_neighbor->bn_lstate = BFD_STATE_DOWN; 750 bfd->bc_neighbor->bn_rstate = BFD_STATE_DOWN; 751 bfd->bc_neighbor->bn_mintx = BFD_SECOND; 752 bfd->bc_neighbor->bn_req_minrx = BFD_SECOND; 753 bfd->bc_neighbor->bn_rminrx = 1; 754 bfd->bc_neighbor->bn_mult = 3; 755 756 bfd->bc_mintx = bfd->bc_neighbor->bn_mintx; 757 bfd->bc_minrx = bfd->bc_neighbor->bn_req_minrx; 758 bfd->bc_multiplier = bfd->bc_neighbor->bn_mult; 759 bfd->bc_minecho = 0; //XXX - BFD_SECOND; 760 761 bfd_set_uptime(bfd); 762 763 return; 764 } 765 766 void 767 bfd_input(struct bfd_config *bfd, struct mbuf *m) 768 { 769 struct bfd_header *peer; 770 struct bfd_auth_header *auth; 771 struct mbuf *mp, *mp0; 772 unsigned int ver, diag = BFD_DIAG_NONE, state, flags; 773 int offp; 774 775 mp = m_pulldown(m, 0, sizeof(*peer), &offp); 776 777 if (mp == NULL) 778 return; 779 peer = (struct bfd_header *)(mp->m_data + offp); 780 781 /* We only support BFD Version 1 */ 782 if (( ver = BFD_VER(peer->bfd_ver_diag)) != 1) 783 goto discard; 784 785 diag = BFD_DIAG(peer->bfd_ver_diag); 786 state = BFD_STATE(peer->bfd_sta_flags); 787 flags = BFD_FLAGS(peer->bfd_sta_flags); 788 789 if (peer->bfd_length + offp > mp->m_len) { 790 printf("%s: bad len %d != %d\n", __func__, 791 peer->bfd_length + offp, mp->m_len); 792 goto discard; 793 } 794 795 if (peer->bfd_detect_multi == 0) 796 goto discard; 797 if (flags & BFD_FLAG_M) 798 goto discard; 799 if (ntohl(peer->bfd_my_discriminator) == 0) 800 goto discard; 801 if (ntohl(peer->bfd_your_discriminator) == 0 && 802 BFD_STATE(peer->bfd_sta_flags) > BFD_STATE_DOWN) 803 goto discard; 804 if ((ntohl(peer->bfd_your_discriminator) != 0) && 805 (ntohl(peer->bfd_your_discriminator) != 806 bfd->bc_neighbor->bn_ldiscr)) { 807 bfd_error(bfd); 808 goto discard; 809 } 810 811 if ((flags & BFD_FLAG_A) && bfd->bc_neighbor->bn_authtype == 0) 812 goto discard; 813 if (!(flags & BFD_FLAG_A) && bfd->bc_neighbor->bn_authtype != 0) 814 goto discard; 815 if (flags & BFD_FLAG_A) { 816 mp0 = m_pulldown(mp, 0, sizeof(*auth), &offp); 817 if (mp0 == NULL) 818 goto discard; 819 auth = (struct bfd_auth_header *)(mp0->m_data + offp); 820 #if 0 821 if (bfd_process_auth(bfd, auth) != 0) { 822 m_free(mp0); 823 goto discard; 824 } 825 #endif 826 } 827 828 bfd->bc_neighbor->bn_rdiscr = ntohl(peer->bfd_my_discriminator); 829 bfd->bc_neighbor->bn_rstate = state; 830 bfd->bc_neighbor->bn_rdemand = (flags & BFD_FLAG_D); 831 bfd->bc_poll = (flags & BFD_FLAG_F); 832 833 /* Local change to the algorithm, we don't accept below 50ms */ 834 if (ntohl(peer->bfd_required_min_rx_interval) < BFD_MINIMUM) 835 goto discard; 836 /* 837 * Local change to the algorithm, we can't use larger than signed 838 * 32bits for a timeout. 839 * That is Too Long(tm) anyways. 840 */ 841 if (ntohl(peer->bfd_required_min_rx_interval) > INT32_MAX) 842 goto discard; 843 bfd->bc_neighbor->bn_rminrx = 844 ntohl(peer->bfd_required_min_rx_interval); 845 bfd->bc_minrx = bfd->bc_neighbor->bn_req_minrx; 846 847 bfd->bc_neighbor->bn_mintx = 848 htonl(peer->bfd_desired_min_tx_interval); 849 if (bfd->bc_neighbor->bn_lstate != BFD_STATE_UP) 850 bfd->bc_neighbor->bn_mintx = BFD_SECOND; 851 852 bfd->bc_neighbor->bn_req_minrx = 853 ntohl(peer->bfd_required_min_rx_interval); 854 855 /* rfc5880 6.8.7 */ 856 bfd->bc_mintx = max(bfd->bc_neighbor->bn_rminrx, 857 bfd->bc_neighbor->bn_mintx); 858 859 /* According the to pseudo-code RFC 5880 page 34 */ 860 if (bfd->bc_state == BFD_STATE_ADMINDOWN) 861 goto discard; 862 if (bfd->bc_neighbor->bn_rstate == BFD_STATE_ADMINDOWN) { 863 if (bfd->bc_neighbor->bn_lstate != BFD_STATE_DOWN) { 864 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_NEIGHBOR_SIGDOWN; 865 bfd_set_state(bfd, BFD_STATE_DOWN); 866 } 867 } else if (bfd->bc_neighbor->bn_lstate == BFD_STATE_DOWN) { 868 if (bfd->bc_neighbor->bn_rstate == BFD_STATE_DOWN) 869 bfd_set_state(bfd, BFD_STATE_INIT); 870 else if (bfd->bc_neighbor->bn_rstate == BFD_STATE_INIT) { 871 bfd->bc_neighbor->bn_ldiag = 0; 872 bfd_set_state(bfd, BFD_STATE_UP); 873 } 874 } else if (bfd->bc_neighbor->bn_lstate == BFD_STATE_INIT) { 875 if (bfd->bc_neighbor->bn_rstate >= BFD_STATE_INIT) { 876 bfd->bc_neighbor->bn_ldiag = 0; 877 bfd_set_state(bfd, BFD_STATE_UP); 878 } else { 879 goto discard; 880 } 881 } else { 882 if (bfd->bc_neighbor->bn_rstate == BFD_STATE_DOWN) { 883 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_NEIGHBOR_SIGDOWN; 884 bfd_set_state(bfd, BFD_STATE_DOWN); 885 goto discard; 886 } 887 } 888 889 if (bfd->bc_neighbor->bn_lstate == BFD_STATE_UP) { 890 bfd->bc_neighbor->bn_ldiag = 0; 891 bfd->bc_neighbor->bn_demand = 1; 892 bfd->bc_neighbor->bn_rdemand = (flags & BFD_FLAG_D); 893 } 894 895 bfd->bc_error = 0; 896 897 discard: 898 bfd->bc_neighbor->bn_rdiag = diag; 899 m_free(m); 900 901 timeout_add_usec(&bfd->bc_timo_rx, bfd->bc_minrx); 902 903 return; 904 } 905 906 void 907 bfd_set_state(struct bfd_config *bfd, unsigned int state) 908 { 909 struct ifnet *ifp; 910 struct rtentry *rt = bfd->bc_rt; 911 912 ifp = if_get(rt->rt_ifidx); 913 if (ifp == NULL) { 914 printf("%s: cannot find interface index %u\n", 915 __func__, rt->rt_ifidx); 916 bfd->bc_error++; 917 bfd_reset(bfd); 918 return; 919 } 920 921 bfd->bc_neighbor->bn_lstate = state; 922 if (state > BFD_STATE_ADMINDOWN) 923 bfd->bc_neighbor->bn_ldiag = 0; 924 925 if (!rtisvalid(rt)) 926 bfd->bc_neighbor->bn_lstate = BFD_STATE_DOWN; 927 928 switch (state) { 929 case BFD_STATE_ADMINDOWN: 930 bfd->bc_laststate = bfd->bc_state; 931 /* FALLTHROUGH */ 932 case BFD_STATE_DOWN: 933 if (bfd->bc_state == BFD_STATE_UP) { 934 bfd->bc_laststate = bfd->bc_state; 935 bfd_set_uptime(bfd); 936 } 937 break; 938 case BFD_STATE_INIT: 939 bfd->bc_laststate = bfd->bc_state; 940 break; 941 case BFD_STATE_UP: 942 bfd->bc_laststate = 943 bfd->bc_state == BFD_STATE_INIT ? 944 bfd->bc_laststate : bfd->bc_state; 945 bfd_set_uptime(bfd); 946 break; 947 } 948 949 bfd->bc_state = state; 950 rtm_bfd(bfd); 951 if_put(ifp); 952 953 return; 954 } 955 956 void 957 bfd_set_uptime(struct bfd_config *bfd) 958 { 959 struct timeval tv; 960 961 getmicrotime(&tv); 962 bfd->bc_lastuptime = tv.tv_sec - bfd->bc_time->tv_sec; 963 memcpy(bfd->bc_time, &tv, sizeof(tv)); 964 } 965 966 void 967 bfd_send_control(void *x) 968 { 969 struct bfd_config *bfd = x; 970 struct mbuf *m; 971 struct bfd_header *h; 972 int error, len; 973 974 MGETHDR(m, M_WAIT, MT_DATA); 975 MCLGET(m, M_WAIT); 976 977 len = BFD_HDRLEN; 978 m->m_len = m->m_pkthdr.len = len; 979 h = mtod(m, struct bfd_header *); 980 981 memset(h, 0xff, sizeof(*h)); /* canary */ 982 983 h->bfd_ver_diag = ((BFD_VERSION << 5) | (bfd->bc_neighbor->bn_ldiag)); 984 h->bfd_sta_flags = (bfd->bc_state << 6); 985 h->bfd_detect_multi = bfd->bc_neighbor->bn_mult; 986 h->bfd_length = BFD_HDRLEN; 987 h->bfd_my_discriminator = htonl(bfd->bc_neighbor->bn_ldiscr); 988 h->bfd_your_discriminator = htonl(bfd->bc_neighbor->bn_rdiscr); 989 990 h->bfd_desired_min_tx_interval = 991 htonl(bfd->bc_neighbor->bn_mintx); 992 h->bfd_required_min_rx_interval = 993 htonl(bfd->bc_neighbor->bn_req_minrx); 994 h->bfd_required_min_echo_interval = htonl(bfd->bc_minecho); 995 996 error = bfd_send(bfd, m); 997 998 if (error) { 999 bfd_error(bfd); 1000 if (!(error == EHOSTDOWN || error == ECONNREFUSED)) { 1001 printf("%s: %u\n", __func__, error); 1002 } 1003 } 1004 } 1005 1006 int 1007 bfd_send(struct bfd_config *bfd, struct mbuf *m) 1008 { 1009 return(sosend(bfd->bc_sosend, NULL, NULL, m, NULL, MSG_DONTWAIT)); 1010 } 1011 1012 /* 1013 * Print debug information about this bfd instance 1014 */ 1015 void 1016 bfd_debug(struct bfd_config *bfd) 1017 { 1018 struct rtentry *rt = bfd->bc_rt; 1019 struct timeval tv; 1020 char buf[64]; 1021 1022 printf("dest: %s ", sockaddr_ntop(rt_key(rt), buf, sizeof(buf))); 1023 printf("src: %s ", sockaddr_ntop(rt->rt_ifa->ifa_addr, buf, 1024 sizeof(buf))); 1025 printf("\n"); 1026 printf("\t"); 1027 printf("session state: %u ", bfd->bc_state); 1028 printf("mode: %u ", bfd->bc_mode); 1029 printf("error: %u ", bfd->bc_error); 1030 printf("minrx: %u ", bfd->bc_minrx); 1031 printf("mintx: %u ", bfd->bc_mintx); 1032 printf("multiplier: %u ", bfd->bc_multiplier); 1033 printf("\n"); 1034 printf("\t"); 1035 printf("local session state: %u ", bfd->bc_neighbor->bn_lstate); 1036 printf("local diag: %u ", bfd->bc_neighbor->bn_ldiag); 1037 printf("\n"); 1038 printf("\t"); 1039 printf("remote discriminator: %u ", bfd->bc_neighbor->bn_rdiscr); 1040 printf("local discriminator: %u ", bfd->bc_neighbor->bn_ldiscr); 1041 printf("\n"); 1042 printf("\t"); 1043 printf("remote session state: %u ", bfd->bc_neighbor->bn_rstate); 1044 printf("remote diag: %u ", bfd->bc_neighbor->bn_rdiag); 1045 printf("remote min rx: %u ", bfd->bc_neighbor->bn_rminrx); 1046 printf("\n"); 1047 printf("\t"); 1048 printf("last state: %u ", bfd->bc_laststate); 1049 getmicrotime(&tv); 1050 printf("uptime %llds ", tv.tv_sec - bfd->bc_time->tv_sec); 1051 printf("time started %lld.%06ld ", bfd->bc_time->tv_sec, 1052 bfd->bc_time->tv_usec); 1053 printf("last uptime %llds ", bfd->bc_lastuptime); 1054 printf("\n"); 1055 } 1056