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