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