1 /* $OpenBSD: if_etherbridge.c,v 1.7 2021/07/05 04:17:41 dlg Exp $ */ 2 3 /* 4 * Copyright (c) 2018, 2021 David Gwynne <dlg@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 #include "bpfilter.h" 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/kernel.h> 24 #include <sys/mbuf.h> 25 #include <sys/socket.h> 26 #include <sys/ioctl.h> 27 #include <sys/timeout.h> 28 #include <sys/pool.h> 29 #include <sys/tree.h> 30 31 #include <net/if.h> 32 #include <net/if_var.h> 33 #include <net/if_dl.h> 34 #include <net/if_media.h> 35 #include <net/if_types.h> 36 #include <net/rtable.h> 37 #include <net/toeplitz.h> 38 39 #include <netinet/in.h> 40 #include <netinet/if_ether.h> 41 42 /* for bridge stuff */ 43 #include <net/if_bridge.h> 44 45 #include <net/if_etherbridge.h> 46 47 static inline void ebe_rele(struct eb_entry *); 48 static void ebe_free(void *); 49 50 static void etherbridge_age(void *); 51 52 RBT_PROTOTYPE(eb_tree, eb_entry, ebe_tentry, ebt_cmp); 53 54 static struct pool eb_entry_pool; 55 56 static inline int 57 eb_port_eq(struct etherbridge *eb, void *a, void *b) 58 { 59 return ((*eb->eb_ops->eb_op_port_eq)(eb->eb_cookie, a, b)); 60 } 61 62 static inline void * 63 eb_port_take(struct etherbridge *eb, void *port) 64 { 65 return ((*eb->eb_ops->eb_op_port_take)(eb->eb_cookie, port)); 66 } 67 68 static inline void 69 eb_port_rele(struct etherbridge *eb, void *port) 70 { 71 return ((*eb->eb_ops->eb_op_port_rele)(eb->eb_cookie, port)); 72 } 73 74 static inline size_t 75 eb_port_ifname(struct etherbridge *eb, char *dst, size_t len, void *port) 76 { 77 return ((*eb->eb_ops->eb_op_port_ifname)(eb->eb_cookie, dst, len, 78 port)); 79 } 80 81 static inline void 82 eb_port_sa(struct etherbridge *eb, struct sockaddr_storage *ss, void *port) 83 { 84 (*eb->eb_ops->eb_op_port_sa)(eb->eb_cookie, ss, port); 85 } 86 87 int 88 etherbridge_init(struct etherbridge *eb, const char *name, 89 const struct etherbridge_ops *ops, void *cookie) 90 { 91 size_t i; 92 93 if (eb_entry_pool.pr_size == 0) { 94 pool_init(&eb_entry_pool, sizeof(struct eb_entry), 95 0, IPL_SOFTNET, 0, "ebepl", NULL); 96 } 97 98 eb->eb_table = mallocarray(ETHERBRIDGE_TABLE_SIZE, 99 sizeof(*eb->eb_table), M_DEVBUF, M_WAITOK|M_CANFAIL); 100 if (eb->eb_table == NULL) 101 return (ENOMEM); 102 103 eb->eb_name = name; 104 eb->eb_ops = ops; 105 eb->eb_cookie = cookie; 106 107 mtx_init(&eb->eb_lock, IPL_SOFTNET); 108 RBT_INIT(eb_tree, &eb->eb_tree); 109 110 eb->eb_num = 0; 111 eb->eb_max = 100; 112 eb->eb_max_age = 240; 113 timeout_set(&eb->eb_tmo_age, etherbridge_age, eb); 114 115 for (i = 0; i < ETHERBRIDGE_TABLE_SIZE; i++) { 116 struct eb_list *ebl = &eb->eb_table[i]; 117 SMR_TAILQ_INIT(ebl); 118 } 119 120 return (0); 121 } 122 123 int 124 etherbridge_up(struct etherbridge *eb) 125 { 126 etherbridge_age(eb); 127 128 return (0); 129 } 130 131 int 132 etherbridge_down(struct etherbridge *eb) 133 { 134 smr_barrier(); 135 136 return (0); 137 } 138 139 void 140 etherbridge_destroy(struct etherbridge *eb) 141 { 142 struct eb_entry *ebe, *nebe; 143 144 /* XXX assume that nothing will calling etherbridge_map now */ 145 146 timeout_del_barrier(&eb->eb_tmo_age); 147 148 free(eb->eb_table, M_DEVBUF, 149 ETHERBRIDGE_TABLE_SIZE * sizeof(*eb->eb_table)); 150 151 RBT_FOREACH_SAFE(ebe, eb_tree, &eb->eb_tree, nebe) { 152 RBT_REMOVE(eb_tree, &eb->eb_tree, ebe); 153 ebe_free(ebe); 154 } 155 } 156 157 static struct eb_list * 158 etherbridge_list(struct etherbridge *eb, uint64_t eba) 159 { 160 uint16_t hash; 161 162 hash = stoeplitz_h64(eba) & ETHERBRIDGE_TABLE_MASK; 163 164 return (&eb->eb_table[hash]); 165 } 166 167 static struct eb_entry * 168 ebl_find(struct eb_list *ebl, uint64_t eba) 169 { 170 struct eb_entry *ebe; 171 172 SMR_TAILQ_FOREACH(ebe, ebl, ebe_lentry) { 173 if (ebe->ebe_addr == eba) 174 return (ebe); 175 } 176 177 return (NULL); 178 } 179 180 static inline void 181 ebl_insert(struct eb_list *ebl, struct eb_entry *ebe) 182 { 183 SMR_TAILQ_INSERT_TAIL_LOCKED(ebl, ebe, ebe_lentry); 184 } 185 186 static inline void 187 ebl_remove(struct eb_list *ebl, struct eb_entry *ebe) 188 { 189 SMR_TAILQ_REMOVE_LOCKED(ebl, ebe, ebe_lentry); 190 } 191 192 static inline int 193 ebt_cmp(const struct eb_entry *aebe, const struct eb_entry *bebe) 194 { 195 if (aebe->ebe_addr > bebe->ebe_addr) 196 return (1); 197 if (aebe->ebe_addr < bebe->ebe_addr) 198 return (-1); 199 return (0); 200 } 201 202 RBT_GENERATE(eb_tree, eb_entry, ebe_tentry, ebt_cmp); 203 204 static inline struct eb_entry * 205 ebt_insert(struct etherbridge *eb, struct eb_entry *ebe) 206 { 207 return (RBT_INSERT(eb_tree, &eb->eb_tree, ebe)); 208 } 209 210 static inline struct eb_entry * 211 ebt_find(struct etherbridge *eb, const struct eb_entry *ebe) 212 { 213 return (RBT_FIND(eb_tree, &eb->eb_tree, ebe)); 214 } 215 216 static inline void 217 ebt_replace(struct etherbridge *eb, struct eb_entry *oebe, 218 struct eb_entry *nebe) 219 { 220 struct eb_entry *rvebe; 221 222 RBT_REMOVE(eb_tree, &eb->eb_tree, oebe); 223 rvebe = RBT_INSERT(eb_tree, &eb->eb_tree, nebe); 224 KASSERTMSG(rvebe == NULL, "ebt_replace eb %p nebe %p rvebe %p", 225 eb, nebe, rvebe); 226 } 227 228 static inline void 229 ebt_remove(struct etherbridge *eb, struct eb_entry *ebe) 230 { 231 RBT_REMOVE(eb_tree, &eb->eb_tree, ebe); 232 } 233 234 static inline void 235 ebe_rele(struct eb_entry *ebe) 236 { 237 smr_call(&ebe->ebe_smr_entry, ebe_free, ebe); 238 } 239 240 static void 241 ebe_free(void *arg) 242 { 243 struct eb_entry *ebe = arg; 244 struct etherbridge *eb = ebe->ebe_etherbridge; 245 246 eb_port_rele(eb, ebe->ebe_port); 247 pool_put(&eb_entry_pool, ebe); 248 } 249 250 void * 251 etherbridge_resolve_ea(struct etherbridge *eb, 252 const struct ether_addr *ea) 253 { 254 return (etherbridge_resolve(eb, ether_addr_to_e64(ea))); 255 } 256 257 void * 258 etherbridge_resolve(struct etherbridge *eb, uint64_t eba) 259 { 260 struct eb_list *ebl = etherbridge_list(eb, eba); 261 struct eb_entry *ebe; 262 263 SMR_ASSERT_CRITICAL(); 264 265 ebe = ebl_find(ebl, eba); 266 if (ebe != NULL) { 267 if (ebe->ebe_type == EBE_DYNAMIC) { 268 int diff = getuptime() - ebe->ebe_age; 269 if (diff > eb->eb_max_age) 270 return (NULL); 271 } 272 273 return (ebe->ebe_port); 274 } 275 276 return (NULL); 277 } 278 279 void 280 etherbridge_map_ea(struct etherbridge *eb, void *port, 281 const struct ether_addr *ea) 282 { 283 etherbridge_map(eb, port, ether_addr_to_e64(ea)); 284 } 285 286 void 287 etherbridge_map(struct etherbridge *eb, void *port, uint64_t eba) 288 { 289 struct eb_list *ebl; 290 struct eb_entry *oebe, *nebe; 291 unsigned int num; 292 void *nport; 293 int new = 0; 294 time_t now; 295 296 if (ETH64_IS_MULTICAST(eba) || ETH64_IS_ANYADDR(eba)) 297 return; 298 299 now = getuptime(); 300 ebl = etherbridge_list(eb, eba); 301 302 smr_read_enter(); 303 oebe = ebl_find(ebl, eba); 304 if (oebe == NULL) { 305 /* 306 * peek at the space to see if it's worth trying 307 * to make a new entry. 308 */ 309 if (eb->eb_num < eb->eb_max) 310 new = 1; 311 } else { 312 if (oebe->ebe_age != now) 313 oebe->ebe_age = now; 314 315 /* does this entry need to be replaced? */ 316 if (oebe->ebe_type == EBE_DYNAMIC && 317 !eb_port_eq(eb, oebe->ebe_port, port)) 318 new = 1; 319 } 320 smr_read_leave(); 321 322 if (!new) 323 return; 324 325 nport = eb_port_take(eb, port); 326 if (nport == NULL) { 327 /* XXX should we remove the old one and flood? */ 328 return; 329 } 330 331 nebe = pool_get(&eb_entry_pool, PR_NOWAIT); 332 if (nebe == NULL) { 333 /* XXX should we remove the old one and flood? */ 334 eb_port_rele(eb, nport); 335 return; 336 } 337 338 smr_init(&nebe->ebe_smr_entry); 339 nebe->ebe_etherbridge = eb; 340 341 nebe->ebe_addr = eba; 342 nebe->ebe_port = nport; 343 nebe->ebe_type = EBE_DYNAMIC; 344 nebe->ebe_age = now; 345 346 mtx_enter(&eb->eb_lock); 347 oebe = ebt_find(eb, nebe); 348 if (oebe == NULL) { 349 num = eb->eb_num + 1; 350 if (num <= eb->eb_max) { 351 ebl_insert(ebl, nebe); 352 353 oebe = ebt_insert(eb, nebe); 354 if (oebe != NULL) { 355 panic("etherbridge %p changed while locked", 356 eb); 357 } 358 359 /* great success */ 360 eb->eb_num = num; 361 nebe = NULL; /* give ref to table */ 362 } 363 } else if (oebe->ebe_type == EBE_DYNAMIC) { 364 /* do the update */ 365 ebl_insert(ebl, nebe); 366 367 ebl_remove(ebl, oebe); 368 ebt_replace(eb, oebe, nebe); 369 370 nebe = NULL; /* give ref to table */ 371 } else { 372 /* 373 * oebe is not a dynamic entry, so don't replace it. 374 */ 375 oebe = NULL; 376 } 377 mtx_leave(&eb->eb_lock); 378 379 if (nebe != NULL) { 380 /* 381 * the new entry didn't make it into the 382 * table so it can be freed directly. 383 */ 384 ebe_free(nebe); 385 } 386 387 if (oebe != NULL) { 388 /* 389 * we replaced this entry, it needs to be released. 390 */ 391 ebe_rele(oebe); 392 } 393 } 394 395 int 396 etherbridge_add_addr(struct etherbridge *eb, void *port, 397 const struct ether_addr *ea, unsigned int type) 398 { 399 uint64_t eba = ether_addr_to_e64(ea); 400 struct eb_list *ebl; 401 struct eb_entry *nebe; 402 unsigned int num; 403 void *nport; 404 int error = 0; 405 406 if (ETH64_IS_MULTICAST(eba) || ETH64_IS_ANYADDR(eba)) 407 return (EADDRNOTAVAIL); 408 409 nport = eb_port_take(eb, port); 410 if (nport == NULL) 411 return (ENOMEM); 412 413 nebe = pool_get(&eb_entry_pool, PR_NOWAIT); 414 if (nebe == NULL) { 415 eb_port_rele(eb, nport); 416 return (ENOMEM); 417 } 418 419 smr_init(&nebe->ebe_smr_entry); 420 nebe->ebe_etherbridge = eb; 421 422 nebe->ebe_addr = eba; 423 nebe->ebe_port = nport; 424 nebe->ebe_type = type; 425 nebe->ebe_age = getuptime(); 426 427 ebl = etherbridge_list(eb, eba); 428 429 mtx_enter(&eb->eb_lock); 430 num = eb->eb_num + 1; 431 if (num >= eb->eb_max) 432 error = ENOSPC; 433 else if (ebt_insert(eb, nebe) != NULL) 434 error = EADDRINUSE; 435 else { 436 /* we win, do the insert */ 437 ebl_insert(ebl, nebe); /* give the ref to etherbridge */ 438 eb->eb_num = num; 439 } 440 mtx_leave(&eb->eb_lock); 441 442 if (error != 0) { 443 /* 444 * the new entry didn't make it into the 445 * table, so it can be freed directly. 446 */ 447 ebe_free(nebe); 448 } 449 450 return (error); 451 } 452 int 453 etherbridge_del_addr(struct etherbridge *eb, const struct ether_addr *ea) 454 { 455 uint64_t eba = ether_addr_to_e64(ea); 456 struct eb_list *ebl; 457 struct eb_entry *oebe; 458 const struct eb_entry key = { 459 .ebe_addr = eba, 460 }; 461 int error = 0; 462 463 ebl = etherbridge_list(eb, eba); 464 465 mtx_enter(&eb->eb_lock); 466 oebe = ebt_find(eb, &key); 467 if (oebe == NULL) 468 error = ESRCH; 469 else { 470 KASSERT(eb->eb_num > 0); 471 eb->eb_num--; 472 473 ebl_remove(ebl, oebe); /* it's our ref now */ 474 ebt_remove(eb, oebe); 475 } 476 mtx_leave(&eb->eb_lock); 477 478 if (oebe != NULL) 479 ebe_rele(oebe); 480 481 return (error); 482 } 483 484 static void 485 etherbridge_age(void *arg) 486 { 487 struct etherbridge *eb = arg; 488 struct eb_entry *ebe, *nebe; 489 struct eb_queue ebq = TAILQ_HEAD_INITIALIZER(ebq); 490 int diff; 491 unsigned int now = getuptime(); 492 size_t i; 493 494 timeout_add_sec(&eb->eb_tmo_age, 100); 495 496 for (i = 0; i < ETHERBRIDGE_TABLE_SIZE; i++) { 497 struct eb_list *ebl = &eb->eb_table[i]; 498 #if 0 499 if (SMR_TAILQ_EMPTY(ebl)); 500 continue; 501 #endif 502 503 mtx_enter(&eb->eb_lock); /* don't block map too much */ 504 SMR_TAILQ_FOREACH_SAFE_LOCKED(ebe, ebl, ebe_lentry, nebe) { 505 if (ebe->ebe_type != EBE_DYNAMIC) 506 continue; 507 508 diff = now - ebe->ebe_age; 509 if (diff < eb->eb_max_age) 510 continue; 511 512 ebl_remove(ebl, ebe); 513 ebt_remove(eb, ebe); 514 eb->eb_num--; 515 516 /* we own the tables ref now */ 517 518 TAILQ_INSERT_TAIL(&ebq, ebe, ebe_qentry); 519 } 520 mtx_leave(&eb->eb_lock); 521 } 522 523 TAILQ_FOREACH_SAFE(ebe, &ebq, ebe_qentry, nebe) { 524 TAILQ_REMOVE(&ebq, ebe, ebe_qentry); 525 ebe_rele(ebe); 526 } 527 } 528 529 void 530 etherbridge_detach_port(struct etherbridge *eb, void *port) 531 { 532 struct eb_entry *ebe, *nebe; 533 struct eb_queue ebq = TAILQ_HEAD_INITIALIZER(ebq); 534 size_t i; 535 536 for (i = 0; i < ETHERBRIDGE_TABLE_SIZE; i++) { 537 struct eb_list *ebl = &eb->eb_table[i]; 538 539 mtx_enter(&eb->eb_lock); /* don't block map too much */ 540 SMR_TAILQ_FOREACH_SAFE_LOCKED(ebe, ebl, ebe_lentry, nebe) { 541 if (!eb_port_eq(eb, ebe->ebe_port, port)) 542 continue; 543 544 ebl_remove(ebl, ebe); 545 ebt_remove(eb, ebe); 546 eb->eb_num--; 547 548 /* we own the tables ref now */ 549 550 TAILQ_INSERT_TAIL(&ebq, ebe, ebe_qentry); 551 } 552 mtx_leave(&eb->eb_lock); 553 } 554 555 if (TAILQ_EMPTY(&ebq)) 556 return; 557 558 /* 559 * do one smr barrier for all the entries rather than an 560 * smr_call each. 561 */ 562 smr_barrier(); 563 564 TAILQ_FOREACH_SAFE(ebe, &ebq, ebe_qentry, nebe) { 565 TAILQ_REMOVE(&ebq, ebe, ebe_qentry); 566 ebe_free(ebe); 567 } 568 } 569 570 void 571 etherbridge_flush(struct etherbridge *eb, uint32_t flags) 572 { 573 struct eb_entry *ebe, *nebe; 574 struct eb_queue ebq = TAILQ_HEAD_INITIALIZER(ebq); 575 size_t i; 576 577 for (i = 0; i < ETHERBRIDGE_TABLE_SIZE; i++) { 578 struct eb_list *ebl = &eb->eb_table[i]; 579 580 mtx_enter(&eb->eb_lock); /* don't block map too much */ 581 SMR_TAILQ_FOREACH_SAFE_LOCKED(ebe, ebl, ebe_lentry, nebe) { 582 if (flags == IFBF_FLUSHDYN && 583 ebe->ebe_type != EBE_DYNAMIC) 584 continue; 585 586 ebl_remove(ebl, ebe); 587 ebt_remove(eb, ebe); 588 eb->eb_num--; 589 590 /* we own the tables ref now */ 591 592 TAILQ_INSERT_TAIL(&ebq, ebe, ebe_qentry); 593 } 594 mtx_leave(&eb->eb_lock); 595 } 596 597 if (TAILQ_EMPTY(&ebq)) 598 return; 599 600 /* 601 * do one smr barrier for all the entries rather than an 602 * smr_call each. 603 */ 604 smr_barrier(); 605 606 TAILQ_FOREACH_SAFE(ebe, &ebq, ebe_qentry, nebe) { 607 TAILQ_REMOVE(&ebq, ebe, ebe_qentry); 608 ebe_free(ebe); 609 } 610 } 611 612 int 613 etherbridge_rtfind(struct etherbridge *eb, struct ifbaconf *baconf) 614 { 615 struct eb_entry *ebe; 616 struct ifbareq bareq; 617 caddr_t buf; 618 size_t len, nlen; 619 time_t age, now = getuptime(); 620 int error; 621 622 if (baconf->ifbac_len == 0) { 623 /* single read is atomic */ 624 baconf->ifbac_len = eb->eb_num * sizeof(bareq); 625 return (0); 626 } 627 628 buf = malloc(baconf->ifbac_len, M_TEMP, M_WAITOK|M_CANFAIL); 629 if (buf == NULL) 630 return (ENOMEM); 631 len = 0; 632 633 mtx_enter(&eb->eb_lock); 634 RBT_FOREACH(ebe, eb_tree, &eb->eb_tree) { 635 nlen = len + sizeof(bareq); 636 if (nlen > baconf->ifbac_len) 637 break; 638 639 strlcpy(bareq.ifba_name, eb->eb_name, 640 sizeof(bareq.ifba_name)); 641 eb_port_ifname(eb, 642 bareq.ifba_ifsname, sizeof(bareq.ifba_ifsname), 643 ebe->ebe_port); 644 ether_e64_to_addr(&bareq.ifba_dst, ebe->ebe_addr); 645 646 memset(&bareq.ifba_dstsa, 0, sizeof(bareq.ifba_dstsa)); 647 eb_port_sa(eb, &bareq.ifba_dstsa, ebe->ebe_port); 648 649 switch (ebe->ebe_type) { 650 case EBE_DYNAMIC: 651 age = now - ebe->ebe_age; 652 bareq.ifba_age = MIN(age, 0xff); 653 bareq.ifba_flags = IFBAF_DYNAMIC; 654 break; 655 case EBE_STATIC: 656 bareq.ifba_age = 0; 657 bareq.ifba_flags = IFBAF_STATIC; 658 break; 659 } 660 661 memcpy(buf + len, &bareq, sizeof(bareq)); 662 len = nlen; 663 } 664 nlen = baconf->ifbac_len; 665 baconf->ifbac_len = eb->eb_num * sizeof(bareq); 666 mtx_leave(&eb->eb_lock); 667 668 error = copyout(buf, baconf->ifbac_buf, len); 669 free(buf, M_TEMP, nlen); 670 671 return (error); 672 } 673 674 int 675 etherbridge_set_max(struct etherbridge *eb, struct ifbrparam *bparam) 676 { 677 if (bparam->ifbrp_csize < 1 || 678 bparam->ifbrp_csize > 4096) /* XXX */ 679 return (EINVAL); 680 681 /* commit */ 682 eb->eb_max = bparam->ifbrp_csize; 683 684 return (0); 685 } 686 687 int 688 etherbridge_get_max(struct etherbridge *eb, struct ifbrparam *bparam) 689 { 690 bparam->ifbrp_csize = eb->eb_max; 691 692 return (0); 693 } 694 695 int 696 etherbridge_set_tmo(struct etherbridge *eb, struct ifbrparam *bparam) 697 { 698 if (bparam->ifbrp_ctime < 8 || 699 bparam->ifbrp_ctime > 3600) 700 return (EINVAL); 701 702 /* commit */ 703 eb->eb_max_age = bparam->ifbrp_ctime; 704 705 return (0); 706 } 707 708 int 709 etherbridge_get_tmo(struct etherbridge *eb, struct ifbrparam *bparam) 710 { 711 bparam->ifbrp_ctime = eb->eb_max_age; 712 713 return (0); 714 } 715