1 /* $OpenBSD: bfd.c,v 1.77 2019/06/02 13:22:36 deraadt 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 /* make sure we don't already have this setup */ 187 if (bfd_lookup(rt) != NULL) 188 return (EADDRINUSE); 189 190 /* Do our necessary memory allocations upfront */ 191 bfd = pool_get(&bfd_pool, PR_WAITOK | PR_ZERO); 192 bfd->bc_neighbor = pool_get(&bfd_pool_neigh, PR_WAITOK | PR_ZERO); 193 bfd->bc_time = pool_get(&bfd_pool_time, PR_WAITOK | PR_ZERO); 194 195 bfd->bc_rt = rt; 196 rtref(bfd->bc_rt); /* we depend on this route not going away */ 197 198 getmicrotime(bfd->bc_time); 199 bfd_reset(bfd); 200 bfd->bc_neighbor->bn_ldiscr = arc4random(); 201 202 if (!timeout_initialized(&bfd->bc_timo_rx)) 203 timeout_set(&bfd->bc_timo_rx, bfd_timeout_rx, bfd); 204 if (!timeout_initialized(&bfd->bc_timo_tx)) 205 timeout_set(&bfd->bc_timo_tx, bfd_timeout_tx, bfd); 206 207 task_set(&bfd->bc_bfd_task, bfd_start_task, bfd); 208 task_set(&bfd->bc_clear_task, bfd_clear_task, bfd); 209 210 task_add(bfdtq, &bfd->bc_bfd_task); 211 212 TAILQ_INSERT_TAIL(&bfd_queue, bfd, bc_entry); 213 bfd_set_state(bfd, BFD_STATE_DOWN); 214 215 return (0); 216 } 217 218 /* 219 * remove and free a bfd session 220 */ 221 void 222 bfdclear(struct rtentry *rt) 223 { 224 struct bfd_config *bfd; 225 226 if ((bfd = bfd_lookup(rt)) == NULL) 227 return; 228 229 task_add(bfdtq, &bfd->bc_clear_task); 230 } 231 232 void 233 bfd_clear_task(void *arg) 234 { 235 struct bfd_config *bfd = (struct bfd_config *)arg; 236 struct rtentry *rt = bfd->bc_rt; 237 238 timeout_del(&bfd->bc_timo_rx); 239 timeout_del(&bfd->bc_timo_tx); 240 task_del(bfdtq, &bfd->bc_upcall_task); 241 task_del(bfdtq, &bfd->bc_bfd_send_task); 242 243 TAILQ_REMOVE(&bfd_queue, bfd, bc_entry); 244 245 /* inform our neighbor */ 246 bfd_senddown(bfd); 247 248 rt->rt_flags &= ~RTF_BFD; 249 if (bfd->bc_so) { 250 /* remove upcall before calling soclose or it will be called */ 251 bfd->bc_so->so_upcall = NULL; 252 soclose(bfd->bc_so, MSG_DONTWAIT); 253 } 254 if (bfd->bc_soecho) { 255 bfd->bc_soecho->so_upcall = NULL; 256 soclose(bfd->bc_soecho, MSG_DONTWAIT); 257 } 258 if (bfd->bc_sosend) 259 soclose(bfd->bc_sosend, MSG_DONTWAIT); 260 261 rtfree(bfd->bc_rt); 262 bfd->bc_rt = NULL; 263 264 pool_put(&bfd_pool_time, bfd->bc_time); 265 pool_put(&bfd_pool_neigh, bfd->bc_neighbor); 266 pool_put(&bfd_pool, bfd); 267 } 268 269 /* 270 * Create and initialize the global bfd framework 271 */ 272 void 273 bfdinit(void) 274 { 275 pool_init(&bfd_pool, sizeof(struct bfd_config), 0, 276 IPL_SOFTNET, 0, "bfd_config", NULL); 277 pool_init(&bfd_pool_neigh, sizeof(struct bfd_neighbor), 0, 278 IPL_SOFTNET, 0, "bfd_config_peer", NULL); 279 pool_init(&bfd_pool_time, sizeof(struct timeval), 0, 280 IPL_SOFTNET, 0, "bfd_config_time", NULL); 281 282 bfdtq = taskq_create("bfd", 1, IPL_SOFTNET, 0); 283 if (bfdtq == NULL) 284 panic("unable to create BFD taskq"); 285 286 TAILQ_INIT(&bfd_queue); 287 } 288 289 /* 290 * Destroy all bfd sessions and remove the tasks 291 * 292 */ 293 void 294 bfddestroy(void) 295 { 296 struct bfd_config *bfd; 297 298 /* inform our neighbor we are rebooting */ 299 while ((bfd = TAILQ_FIRST(&bfd_queue))) { 300 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_FIB_RESET; 301 bfdclear(bfd->bc_rt); 302 } 303 304 taskq_barrier(bfdtq); 305 taskq_destroy(bfdtq); 306 pool_destroy(&bfd_pool_time); 307 pool_destroy(&bfd_pool_neigh); 308 pool_destroy(&bfd_pool); 309 } 310 311 /* 312 * Return the matching bfd 313 */ 314 struct bfd_config * 315 bfd_lookup(struct rtentry *rt) 316 { 317 struct bfd_config *bfd; 318 319 TAILQ_FOREACH(bfd, &bfd_queue, bc_entry) { 320 if (bfd->bc_rt == rt) 321 return (bfd); 322 } 323 return (NULL); 324 } 325 326 struct sockaddr * 327 bfd2sa(struct rtentry *rt, struct sockaddr_bfd *sa_bfd) 328 { 329 struct bfd_config *bfd; 330 331 bfd = bfd_lookup(rt); 332 333 if (bfd == NULL) 334 return (NULL); 335 336 memset(sa_bfd, 0, sizeof(*sa_bfd)); 337 sa_bfd->bs_len = sizeof(*sa_bfd); 338 sa_bfd->bs_family = bfd->bc_rt->rt_dest->sa_family; 339 340 sa_bfd->bs_mode = bfd->bc_mode; 341 sa_bfd->bs_mintx = bfd->bc_mintx; 342 sa_bfd->bs_minrx = bfd->bc_minrx; 343 sa_bfd->bs_minecho = bfd->bc_minecho; 344 sa_bfd->bs_multiplier = bfd->bc_multiplier; 345 346 sa_bfd->bs_uptime = bfd->bc_time->tv_sec; 347 sa_bfd->bs_lastuptime = bfd->bc_lastuptime; 348 sa_bfd->bs_state = bfd->bc_state; 349 sa_bfd->bs_remotestate = bfd->bc_neighbor->bn_rstate; 350 sa_bfd->bs_laststate = bfd->bc_laststate; 351 sa_bfd->bs_error = bfd->bc_error; 352 353 sa_bfd->bs_localdiscr = bfd->bc_neighbor->bn_ldiscr; 354 sa_bfd->bs_localdiag = bfd->bc_neighbor->bn_ldiag; 355 sa_bfd->bs_remotediscr = bfd->bc_neighbor->bn_rdiscr; 356 sa_bfd->bs_remotediag = bfd->bc_neighbor->bn_rdiag; 357 358 return ((struct sockaddr *)sa_bfd); 359 } 360 361 /* 362 * End of public interfaces. 363 * 364 * Everything below this line should not be used outside of this file. 365 */ 366 367 /* 368 * Task to listen and kick off the bfd process 369 */ 370 void 371 bfd_start_task(void *arg) 372 { 373 struct bfd_config *bfd = (struct bfd_config *)arg; 374 375 /* start listeners */ 376 bfd->bc_so = bfd_listener(bfd, BFD_UDP_PORT_CONTROL); 377 if (!bfd->bc_so) 378 printf("bfd_listener(%d) failed\n", 379 BFD_UDP_PORT_CONTROL); 380 bfd->bc_soecho = bfd_listener(bfd, BFD_UDP_PORT_ECHO); 381 if (!bfd->bc_soecho) 382 printf("bfd_listener(%d) failed\n", 383 BFD_UDP_PORT_ECHO); 384 385 /* start sending */ 386 bfd->bc_sosend = bfd_sender(bfd, BFD_UDP_PORT_CONTROL); 387 if (bfd->bc_sosend) { 388 task_set(&bfd->bc_bfd_send_task, bfd_send_task, bfd); 389 task_add(bfdtq, &bfd->bc_bfd_send_task); 390 } 391 392 task_set(&bfd->bc_upcall_task, bfd_upcall_task, bfd); 393 394 return; 395 } 396 397 void 398 bfd_send_task(void *arg) 399 { 400 struct bfd_config *bfd = (struct bfd_config *)arg; 401 struct rtentry *rt = bfd->bc_rt; 402 403 if (ISSET(rt->rt_flags, RTF_UP)) { 404 bfd_send_control(bfd); 405 } else { 406 if (bfd->bc_neighbor->bn_lstate > BFD_STATE_DOWN) { 407 bfd->bc_error++; 408 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_PATH_DOWN; 409 bfd_reset(bfd); 410 bfd_set_state(bfd, BFD_STATE_DOWN); 411 } 412 } 413 //rtm_bfd(bfd); 414 415 /* re-add 70%-90% jitter to our transmits, rfc 5880 6.8.7 */ 416 timeout_add_usec(&bfd->bc_timo_tx, 417 bfd->bc_mintx * (arc4random_uniform(20) + 70) / 100); 418 } 419 420 /* 421 * Setup a bfd listener socket 422 */ 423 struct socket * 424 bfd_listener(struct bfd_config *bfd, unsigned int port) 425 { 426 struct proc *p = curproc; 427 struct rtentry *rt = bfd->bc_rt; 428 struct sockaddr *src = rt->rt_ifa->ifa_addr; 429 struct sockaddr *dst = rt_key(rt); 430 struct sockaddr *sa; 431 struct sockaddr_in *sin; 432 struct sockaddr_in6 *sin6; 433 struct socket *so; 434 struct mbuf *m = NULL, *mopt = NULL; 435 int *ip, error; 436 int s; 437 438 /* sa_family and sa_len must be equal */ 439 if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len) 440 return (NULL); 441 442 error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0); 443 if (error) { 444 printf("%s: socreate error %d\n", 445 __func__, error); 446 return (NULL); 447 } 448 449 MGET(mopt, M_WAIT, MT_SOOPTS); 450 mopt->m_len = sizeof(int); 451 ip = mtod(mopt, int *); 452 *ip = MAXTTL; 453 s = solock(so); 454 error = sosetopt(so, IPPROTO_IP, IP_MINTTL, mopt); 455 sounlock(so, s); 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 s = solock(so); 481 error = sobind(so, m, p); 482 sounlock(so, s); 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 int s; 519 520 /* sa_family and sa_len must be equal */ 521 if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len) 522 return (NULL); 523 524 error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0); 525 526 if (error) 527 return (NULL); 528 529 MGET(mopt, M_WAIT, MT_SOOPTS); 530 mopt->m_len = sizeof(int); 531 ip = mtod(mopt, int *); 532 *ip = IP_PORTRANGE_HIGH; 533 s = solock(so); 534 error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt); 535 sounlock(so, s); 536 m_freem(mopt); 537 if (error) { 538 printf("%s: sosetopt error %d\n", 539 __func__, error); 540 goto close; 541 } 542 543 MGET(mopt, M_WAIT, MT_SOOPTS); 544 mopt->m_len = sizeof(int); 545 ip = mtod(mopt, int *); 546 *ip = MAXTTL; 547 s = solock(so); 548 error = sosetopt(so, IPPROTO_IP, IP_TTL, mopt); 549 sounlock(so, s); 550 m_freem(mopt); 551 if (error) { 552 printf("%s: sosetopt error %d\n", 553 __func__, error); 554 goto close; 555 } 556 557 MGET(mopt, M_WAIT, MT_SOOPTS); 558 mopt->m_len = sizeof(int); 559 ip = mtod(mopt, int *); 560 *ip = IPTOS_PREC_INTERNETCONTROL; 561 s = solock(so); 562 error = sosetopt(so, IPPROTO_IP, IP_TOS, mopt); 563 sounlock(so, s); 564 m_freem(mopt); 565 if (error) { 566 printf("%s: sosetopt error %d\n", 567 __func__, error); 568 goto close; 569 } 570 571 MGET(m, M_WAIT, MT_SONAME); 572 m->m_len = src->sa_len; 573 sa = mtod(m, struct sockaddr *); 574 memcpy(sa, src, src->sa_len); 575 switch(sa->sa_family) { 576 case AF_INET: 577 sin = (struct sockaddr_in *)sa; 578 sin->sin_port = 0; 579 break; 580 case AF_INET6: 581 sin6 = (struct sockaddr_in6 *)sa; 582 sin6->sin6_port = 0; 583 break; 584 default: 585 break; 586 } 587 588 s = solock(so); 589 error = sobind(so, m, p); 590 sounlock(so, s); 591 if (error) { 592 printf("%s: sobind error %d\n", 593 __func__, error); 594 goto close; 595 } 596 597 memcpy(sa, dst, dst->sa_len); 598 switch(sa->sa_family) { 599 case AF_INET: 600 sin = (struct sockaddr_in *)sa; 601 sin->sin_port = ntohs(port); 602 break; 603 case AF_INET6: 604 sin6 = (struct sockaddr_in6 *)sa; 605 sin6->sin6_port = ntohs(port); 606 break; 607 default: 608 break; 609 } 610 611 s = solock(so); 612 error = soconnect(so, m); 613 sounlock(so, s); 614 if (error && error != ECONNREFUSED) { 615 printf("%s: soconnect error %d\n", 616 __func__, error); 617 goto close; 618 } 619 620 m_free(m); 621 622 return (so); 623 624 close: 625 m_free(m); 626 soclose(so, MSG_DONTWAIT); 627 628 return (NULL); 629 } 630 631 /* 632 * Will be called per-received packet 633 */ 634 void 635 bfd_upcall(struct socket *so, caddr_t arg, int waitflag) 636 { 637 struct bfd_config *bfd = (struct bfd_config *)arg; 638 639 bfd->bc_upcallso = so; 640 task_add(bfdtq, &bfd->bc_upcall_task); 641 } 642 643 void 644 bfd_upcall_task(void *arg) 645 { 646 struct bfd_config *bfd = (struct bfd_config *)arg; 647 struct socket *so = bfd->bc_upcallso; 648 struct mbuf *m; 649 struct uio uio; 650 int flags, error; 651 652 uio.uio_procp = NULL; 653 do { 654 uio.uio_resid = so->so_rcv.sb_cc; 655 flags = MSG_DONTWAIT; 656 error = soreceive(so, NULL, &uio, &m, NULL, &flags, 0); 657 if (error && error != EAGAIN) { 658 bfd_error(bfd); 659 return; 660 } 661 if (m != NULL) 662 bfd_input(bfd, m); 663 } while (so->so_rcv.sb_cc); 664 665 bfd->bc_upcallso = NULL; 666 667 return; 668 } 669 670 void 671 bfd_error(struct bfd_config *bfd) 672 { 673 if (bfd->bc_state <= BFD_STATE_DOWN) 674 return; 675 676 if (++bfd->bc_error >= bfd->bc_neighbor->bn_mult) { 677 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_EXPIRED; 678 bfd_reset(bfd); 679 if (bfd->bc_state > BFD_STATE_DOWN) 680 bfd_set_state(bfd, BFD_STATE_DOWN); 681 } 682 } 683 684 void 685 bfd_timeout_tx(void *v) 686 { 687 struct bfd_config *bfd = v; 688 task_add(bfdtq, &bfd->bc_bfd_send_task); 689 } 690 691 /* 692 * Triggers when we do not receive a valid packet in time 693 */ 694 void 695 bfd_timeout_rx(void *v) 696 { 697 struct bfd_config *bfd = v; 698 699 if (bfd->bc_state > BFD_STATE_DOWN) { 700 bfd_error(bfd); 701 rtm_bfd(bfd); 702 } 703 704 timeout_add_usec(&bfd->bc_timo_rx, bfd->bc_minrx); 705 } 706 707 /* 708 * Tell our neighbor that we are going down 709 */ 710 void 711 bfd_senddown(struct bfd_config *bfd) 712 { 713 /* If we are down, return early */ 714 if (bfd->bc_state < BFD_STATE_INIT) 715 return; 716 717 if (bfd->bc_neighbor->bn_ldiag == 0) 718 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_ADMIN_DOWN; 719 720 bfd_set_state(bfd, BFD_STATE_ADMINDOWN); 721 bfd_send_control(bfd); 722 723 return; 724 } 725 726 /* 727 * Clean a BFD peer to defaults 728 */ 729 void 730 bfd_reset(struct bfd_config *bfd) 731 { 732 /* Clean */ 733 bfd->bc_neighbor->bn_rdiscr = 0; 734 bfd->bc_neighbor->bn_demand = 0; 735 bfd->bc_neighbor->bn_rdemand = 0; 736 bfd->bc_neighbor->bn_authtype = 0; 737 bfd->bc_neighbor->bn_rauthseq = 0; 738 bfd->bc_neighbor->bn_lauthseq = 0; 739 bfd->bc_neighbor->bn_authseqknown = 0; 740 bfd->bc_neighbor->bn_ldiag = 0; 741 742 bfd->bc_mode = BFD_MODE_ASYNC; 743 bfd->bc_state = BFD_STATE_DOWN; 744 745 /* rfc5880 6.8.18 */ 746 bfd->bc_neighbor->bn_lstate = BFD_STATE_DOWN; 747 bfd->bc_neighbor->bn_rstate = BFD_STATE_DOWN; 748 bfd->bc_neighbor->bn_mintx = BFD_SECOND; 749 bfd->bc_neighbor->bn_req_minrx = BFD_SECOND; 750 bfd->bc_neighbor->bn_rminrx = 1; 751 bfd->bc_neighbor->bn_mult = 3; 752 753 bfd->bc_mintx = bfd->bc_neighbor->bn_mintx; 754 bfd->bc_minrx = bfd->bc_neighbor->bn_req_minrx; 755 bfd->bc_multiplier = bfd->bc_neighbor->bn_mult; 756 bfd->bc_minecho = 0; //XXX - BFD_SECOND; 757 758 bfd_set_uptime(bfd); 759 760 return; 761 } 762 763 void 764 bfd_input(struct bfd_config *bfd, struct mbuf *m) 765 { 766 struct bfd_header *peer; 767 struct bfd_auth_header *auth; 768 struct mbuf *mp, *mp0; 769 unsigned int ver, diag = BFD_DIAG_NONE, state, flags; 770 int offp; 771 772 mp = m_pulldown(m, 0, sizeof(*peer), &offp); 773 774 if (mp == NULL) 775 return; 776 peer = (struct bfd_header *)(mp->m_data + offp); 777 778 /* We only support BFD Version 1 */ 779 if (( ver = BFD_VER(peer->bfd_ver_diag)) != 1) 780 goto discard; 781 782 diag = BFD_DIAG(peer->bfd_ver_diag); 783 state = BFD_STATE(peer->bfd_sta_flags); 784 flags = BFD_FLAGS(peer->bfd_sta_flags); 785 786 if (peer->bfd_length + offp > mp->m_len) { 787 printf("%s: bad len %d != %d\n", __func__, 788 peer->bfd_length + offp, mp->m_len); 789 goto discard; 790 } 791 792 if (peer->bfd_detect_multi == 0) 793 goto discard; 794 if (flags & BFD_FLAG_M) 795 goto discard; 796 if (ntohl(peer->bfd_my_discriminator) == 0) 797 goto discard; 798 if (ntohl(peer->bfd_your_discriminator) == 0 && 799 BFD_STATE(peer->bfd_sta_flags) > BFD_STATE_DOWN) 800 goto discard; 801 if ((ntohl(peer->bfd_your_discriminator) != 0) && 802 (ntohl(peer->bfd_your_discriminator) != 803 bfd->bc_neighbor->bn_ldiscr)) { 804 bfd_error(bfd); 805 goto discard; 806 } 807 808 if ((flags & BFD_FLAG_A) && bfd->bc_neighbor->bn_authtype == 0) 809 goto discard; 810 if (!(flags & BFD_FLAG_A) && bfd->bc_neighbor->bn_authtype != 0) 811 goto discard; 812 if (flags & BFD_FLAG_A) { 813 mp0 = m_pulldown(mp, 0, sizeof(*auth), &offp); 814 if (mp0 == NULL) 815 goto discard; 816 auth = (struct bfd_auth_header *)(mp0->m_data + offp); 817 #if 0 818 if (bfd_process_auth(bfd, auth) != 0) { 819 m_free(mp0); 820 goto discard; 821 } 822 #endif 823 } 824 825 bfd->bc_neighbor->bn_rdiscr = ntohl(peer->bfd_my_discriminator); 826 bfd->bc_neighbor->bn_rstate = state; 827 bfd->bc_neighbor->bn_rdemand = (flags & BFD_FLAG_D); 828 bfd->bc_poll = (flags & BFD_FLAG_F); 829 830 /* Local change to the algorithm, we don't accept below 50ms */ 831 if (ntohl(peer->bfd_required_min_rx_interval) < BFD_MINIMUM) 832 goto discard; 833 /* 834 * Local change to the algorithm, we can't use larger than signed 835 * 32bits for a timeout. 836 * That is Too Long(tm) anyways. 837 */ 838 if (ntohl(peer->bfd_required_min_rx_interval) > INT32_MAX) 839 goto discard; 840 bfd->bc_neighbor->bn_rminrx = 841 ntohl(peer->bfd_required_min_rx_interval); 842 bfd->bc_minrx = bfd->bc_neighbor->bn_req_minrx; 843 844 bfd->bc_neighbor->bn_mintx = 845 htonl(peer->bfd_desired_min_tx_interval); 846 if (bfd->bc_neighbor->bn_lstate != BFD_STATE_UP) 847 bfd->bc_neighbor->bn_mintx = BFD_SECOND; 848 849 bfd->bc_neighbor->bn_req_minrx = 850 ntohl(peer->bfd_required_min_rx_interval); 851 852 /* rfc5880 6.8.7 */ 853 bfd->bc_mintx = max(bfd->bc_neighbor->bn_rminrx, 854 bfd->bc_neighbor->bn_mintx); 855 856 /* According the to pseudo-code RFC 5880 page 34 */ 857 if (bfd->bc_state == BFD_STATE_ADMINDOWN) 858 goto discard; 859 if (bfd->bc_neighbor->bn_rstate == BFD_STATE_ADMINDOWN) { 860 if (bfd->bc_neighbor->bn_lstate != BFD_STATE_DOWN) { 861 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_NEIGHBOR_SIGDOWN; 862 bfd_set_state(bfd, BFD_STATE_DOWN); 863 } 864 } else if (bfd->bc_neighbor->bn_lstate == BFD_STATE_DOWN) { 865 if (bfd->bc_neighbor->bn_rstate == BFD_STATE_DOWN) 866 bfd_set_state(bfd, BFD_STATE_INIT); 867 else if (bfd->bc_neighbor->bn_rstate == BFD_STATE_INIT) { 868 bfd->bc_neighbor->bn_ldiag = 0; 869 bfd_set_state(bfd, BFD_STATE_UP); 870 } 871 } else if (bfd->bc_neighbor->bn_lstate == BFD_STATE_INIT) { 872 if (bfd->bc_neighbor->bn_rstate >= BFD_STATE_INIT) { 873 bfd->bc_neighbor->bn_ldiag = 0; 874 bfd_set_state(bfd, BFD_STATE_UP); 875 } else { 876 goto discard; 877 } 878 } else { 879 if (bfd->bc_neighbor->bn_rstate == BFD_STATE_DOWN) { 880 bfd->bc_neighbor->bn_ldiag = BFD_DIAG_NEIGHBOR_SIGDOWN; 881 bfd_set_state(bfd, BFD_STATE_DOWN); 882 goto discard; 883 } 884 } 885 886 if (bfd->bc_neighbor->bn_lstate == BFD_STATE_UP) { 887 bfd->bc_neighbor->bn_ldiag = 0; 888 bfd->bc_neighbor->bn_demand = 1; 889 bfd->bc_neighbor->bn_rdemand = (flags & BFD_FLAG_D); 890 } 891 892 bfd->bc_error = 0; 893 894 discard: 895 bfd->bc_neighbor->bn_rdiag = diag; 896 m_free(m); 897 898 timeout_add_usec(&bfd->bc_timo_rx, bfd->bc_minrx); 899 900 return; 901 } 902 903 void 904 bfd_set_state(struct bfd_config *bfd, unsigned int state) 905 { 906 struct ifnet *ifp; 907 struct rtentry *rt = bfd->bc_rt; 908 909 ifp = if_get(rt->rt_ifidx); 910 if (ifp == NULL) { 911 printf("%s: cannot find interface index %u\n", 912 __func__, rt->rt_ifidx); 913 bfd->bc_error++; 914 bfd_reset(bfd); 915 return; 916 } 917 918 bfd->bc_neighbor->bn_lstate = state; 919 if (state > BFD_STATE_ADMINDOWN) 920 bfd->bc_neighbor->bn_ldiag = 0; 921 922 if (!rtisvalid(rt)) 923 bfd->bc_neighbor->bn_lstate = BFD_STATE_DOWN; 924 925 switch (state) { 926 case BFD_STATE_ADMINDOWN: 927 bfd->bc_laststate = bfd->bc_state; 928 /* FALLTHROUGH */ 929 case BFD_STATE_DOWN: 930 if (bfd->bc_state == BFD_STATE_UP) { 931 bfd->bc_laststate = bfd->bc_state; 932 bfd_set_uptime(bfd); 933 } 934 break; 935 case BFD_STATE_INIT: 936 bfd->bc_laststate = bfd->bc_state; 937 break; 938 case BFD_STATE_UP: 939 bfd->bc_laststate = 940 bfd->bc_state == BFD_STATE_INIT ? 941 bfd->bc_laststate : bfd->bc_state; 942 bfd_set_uptime(bfd); 943 break; 944 } 945 946 bfd->bc_state = state; 947 rtm_bfd(bfd); 948 if_put(ifp); 949 950 return; 951 } 952 953 void 954 bfd_set_uptime(struct bfd_config *bfd) 955 { 956 struct timeval tv; 957 958 getmicrotime(&tv); 959 bfd->bc_lastuptime = tv.tv_sec - bfd->bc_time->tv_sec; 960 memcpy(bfd->bc_time, &tv, sizeof(tv)); 961 } 962 963 void 964 bfd_send_control(void *x) 965 { 966 struct bfd_config *bfd = x; 967 struct mbuf *m; 968 struct bfd_header *h; 969 int error, len; 970 971 MGETHDR(m, M_WAIT, MT_DATA); 972 MCLGET(m, M_WAIT); 973 974 len = BFD_HDRLEN; 975 m->m_len = m->m_pkthdr.len = len; 976 h = mtod(m, struct bfd_header *); 977 978 memset(h, 0xff, sizeof(*h)); /* canary */ 979 980 h->bfd_ver_diag = ((BFD_VERSION << 5) | (bfd->bc_neighbor->bn_ldiag)); 981 h->bfd_sta_flags = (bfd->bc_state << 6); 982 h->bfd_detect_multi = bfd->bc_neighbor->bn_mult; 983 h->bfd_length = BFD_HDRLEN; 984 h->bfd_my_discriminator = htonl(bfd->bc_neighbor->bn_ldiscr); 985 h->bfd_your_discriminator = htonl(bfd->bc_neighbor->bn_rdiscr); 986 987 h->bfd_desired_min_tx_interval = 988 htonl(bfd->bc_neighbor->bn_mintx); 989 h->bfd_required_min_rx_interval = 990 htonl(bfd->bc_neighbor->bn_req_minrx); 991 h->bfd_required_min_echo_interval = htonl(bfd->bc_minecho); 992 993 error = bfd_send(bfd, m); 994 995 if (error) { 996 bfd_error(bfd); 997 if (!(error == EHOSTDOWN || error == ECONNREFUSED)) { 998 printf("%s: %u\n", __func__, error); 999 } 1000 } 1001 } 1002 1003 int 1004 bfd_send(struct bfd_config *bfd, struct mbuf *m) 1005 { 1006 return(sosend(bfd->bc_sosend, NULL, NULL, m, NULL, MSG_DONTWAIT)); 1007 } 1008 1009 /* 1010 * Print debug information about this bfd instance 1011 */ 1012 void 1013 bfd_debug(struct bfd_config *bfd) 1014 { 1015 struct rtentry *rt = bfd->bc_rt; 1016 struct timeval tv; 1017 char buf[64]; 1018 1019 printf("dest: %s ", sockaddr_ntop(rt_key(rt), buf, sizeof(buf))); 1020 printf("src: %s ", sockaddr_ntop(rt->rt_ifa->ifa_addr, buf, 1021 sizeof(buf))); 1022 printf("\n"); 1023 printf("\t"); 1024 printf("session state: %u ", bfd->bc_state); 1025 printf("mode: %u ", bfd->bc_mode); 1026 printf("error: %u ", bfd->bc_error); 1027 printf("minrx: %u ", bfd->bc_minrx); 1028 printf("mintx: %u ", bfd->bc_mintx); 1029 printf("multiplier: %u ", bfd->bc_multiplier); 1030 printf("\n"); 1031 printf("\t"); 1032 printf("local session state: %u ", bfd->bc_neighbor->bn_lstate); 1033 printf("local diag: %u ", bfd->bc_neighbor->bn_ldiag); 1034 printf("\n"); 1035 printf("\t"); 1036 printf("remote discriminator: %u ", bfd->bc_neighbor->bn_rdiscr); 1037 printf("local discriminator: %u ", bfd->bc_neighbor->bn_ldiscr); 1038 printf("\n"); 1039 printf("\t"); 1040 printf("remote session state: %u ", bfd->bc_neighbor->bn_rstate); 1041 printf("remote diag: %u ", bfd->bc_neighbor->bn_rdiag); 1042 printf("remote min rx: %u ", bfd->bc_neighbor->bn_rminrx); 1043 printf("\n"); 1044 printf("\t"); 1045 printf("last state: %u ", bfd->bc_laststate); 1046 getmicrotime(&tv); 1047 printf("uptime %llds ", tv.tv_sec - bfd->bc_time->tv_sec); 1048 printf("time started %lld.%06ld ", bfd->bc_time->tv_sec, 1049 bfd->bc_time->tv_usec); 1050 printf("last uptime %llds ", bfd->bc_lastuptime); 1051 printf("\n"); 1052 } 1053