1 /* $NetBSD: if_llatbl.c,v 1.17 2017/01/16 15:44:46 christos Exp $ */ 2 /* 3 * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. 4 * Copyright (c) 2004-2008 Qing Li. All rights reserved. 5 * Copyright (c) 2008 Kip Macy. All rights reserved. 6 * Copyright (c) 2015 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 #include <sys/cdefs.h> 31 32 #ifdef _KERNEL_OPT 33 #include "opt_ddb.h" 34 #include "opt_inet.h" 35 #include "opt_inet6.h" 36 #endif 37 38 #include "arp.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/malloc.h> 43 #include <sys/mbuf.h> 44 #include <sys/syslog.h> 45 #include <sys/sysctl.h> 46 #include <sys/socket.h> 47 #include <sys/socketvar.h> 48 #include <sys/kernel.h> 49 #include <sys/lock.h> 50 #include <sys/mutex.h> 51 #include <sys/rwlock.h> 52 53 #ifdef DDB 54 #include <ddb/ddb.h> 55 #endif 56 57 #include <netinet/in.h> 58 #include <net/if_llatbl.h> 59 #include <net/if.h> 60 #include <net/if_dl.h> 61 #include <net/route.h> 62 #include <netinet/if_inarp.h> 63 #include <netinet/in_var.h> 64 #include <netinet6/in6_var.h> 65 #include <netinet6/nd6.h> 66 67 static SLIST_HEAD(, lltable) lltables; 68 krwlock_t lltable_rwlock; 69 70 static void lltable_unlink(struct lltable *llt); 71 static void llentries_unlink(struct lltable *llt, struct llentries *head); 72 73 static void htable_unlink_entry(struct llentry *lle); 74 static void htable_link_entry(struct lltable *llt, struct llentry *lle); 75 static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, 76 void *farg); 77 78 int 79 lltable_dump_entry(struct lltable *llt, struct llentry *lle, 80 struct rt_walkarg *w, struct sockaddr *sa) 81 { 82 struct ifnet *ifp = llt->llt_ifp; 83 int error; 84 void *a; 85 struct sockaddr_dl sdl; 86 int size; 87 struct rt_addrinfo info; 88 89 memset(&info, 0, sizeof(info)); 90 info.rti_info[RTAX_DST] = sa; 91 92 a = (lle->la_flags & LLE_VALID) == LLE_VALID ? &lle->ll_addr : NULL; 93 if (sockaddr_dl_init(&sdl, sizeof(sdl), ifp->if_index, ifp->if_type, 94 NULL, 0, a, ifp->if_addrlen) == NULL) 95 return EINVAL; 96 97 info.rti_info[RTAX_GATEWAY] = sstocsa(&sdl); 98 if (sa->sa_family == AF_INET && lle->la_flags & LLE_PUB) { 99 struct sockaddr_inarp *sin; 100 sin = (struct sockaddr_inarp *)sa; 101 sin->sin_other = SIN_PROXY; 102 } 103 if ((error = rt_msg3(RTM_GET, &info, 0, w, &size))) 104 return error; 105 if (w->w_where && w->w_tmem && w->w_needed <= 0) { 106 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 107 108 /* Need to copy by myself */ 109 rtm->rtm_rmx.rmx_expire = 110 (lle->la_flags & LLE_STATIC) ? 0 : lle->la_expire; 111 rtm->rtm_flags |= RTF_HOST; /* For ndp */ 112 rtm->rtm_flags |= (lle->la_flags & LLE_STATIC) ? RTF_STATIC : 0; 113 if (lle->la_flags & LLE_PUB) 114 rtm->rtm_flags |= RTF_ANNOUNCE; 115 rtm->rtm_addrs = info.rti_addrs; 116 if ((error = copyout(rtm, w->w_where, size)) != 0) 117 w->w_where = NULL; 118 else 119 w->w_where = (char *)w->w_where + size; 120 } 121 122 return error; 123 } 124 125 /* 126 * Dump lle state for a specific address family. 127 */ 128 static int 129 lltable_dump_af(struct lltable *llt, struct rt_walkarg *w) 130 { 131 int error; 132 133 LLTABLE_LOCK_ASSERT(); 134 135 if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 136 return (0); 137 error = 0; 138 139 IF_AFDATA_RLOCK(llt->llt_ifp); 140 error = lltable_foreach_lle(llt, 141 (llt_foreach_cb_t *)llt->llt_dump_entry, w); 142 IF_AFDATA_RUNLOCK(llt->llt_ifp); 143 144 return (error); 145 } 146 147 /* 148 * Dump arp state for a specific address family. 149 */ 150 int 151 lltable_sysctl_dumparp(int af, struct rt_walkarg *w) 152 { 153 struct lltable *llt; 154 int error = 0; 155 156 LLTABLE_RLOCK(); 157 SLIST_FOREACH(llt, &lltables, llt_link) { 158 if (llt->llt_af == af) { 159 error = lltable_dump_af(llt, w); 160 if (error != 0) 161 goto done; 162 } 163 } 164 done: 165 LLTABLE_RUNLOCK(); 166 return (error); 167 } 168 169 /* 170 * Common function helpers for chained hash table. 171 */ 172 173 /* 174 * Runs specified callback for each entry in @llt. 175 * Caller does the locking. 176 * 177 */ 178 static int 179 htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 180 { 181 struct llentry *lle, *next; 182 int i, error; 183 184 error = 0; 185 186 for (i = 0; i < llt->llt_hsize; i++) { 187 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 188 error = f(llt, lle, farg); 189 if (error != 0) 190 break; 191 } 192 } 193 194 return (error); 195 } 196 197 static void 198 htable_link_entry(struct lltable *llt, struct llentry *lle) 199 { 200 struct llentries *lleh; 201 uint32_t hashidx; 202 203 if ((lle->la_flags & LLE_LINKED) != 0) 204 return; 205 206 IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 207 208 hashidx = llt->llt_hash(lle, llt->llt_hsize); 209 lleh = &llt->lle_head[hashidx]; 210 211 lle->lle_tbl = llt; 212 lle->lle_head = lleh; 213 lle->la_flags |= LLE_LINKED; 214 LIST_INSERT_HEAD(lleh, lle, lle_next); 215 216 llt->llt_lle_count++; 217 } 218 219 static void 220 htable_unlink_entry(struct llentry *lle) 221 { 222 223 if ((lle->la_flags & LLE_LINKED) != 0) { 224 IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp); 225 LIST_REMOVE(lle, lle_next); 226 lle->la_flags &= ~(LLE_VALID | LLE_LINKED); 227 #if 0 228 lle->lle_tbl = NULL; 229 lle->lle_head = NULL; 230 #endif 231 KASSERT(lle->lle_tbl->llt_lle_count != 0); 232 lle->lle_tbl->llt_lle_count--; 233 } 234 } 235 236 struct prefix_match_data { 237 const struct sockaddr *prefix; 238 const struct sockaddr *mask; 239 struct llentries dchain; 240 u_int flags; 241 }; 242 243 static int 244 htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 245 { 246 struct prefix_match_data *pmd; 247 248 pmd = (struct prefix_match_data *)farg; 249 250 if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) { 251 LLE_WLOCK(lle); 252 LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); 253 } 254 255 return (0); 256 } 257 258 static void 259 htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix, 260 const struct sockaddr *mask, u_int flags) 261 { 262 struct llentry *lle, *next; 263 struct prefix_match_data pmd; 264 265 memset(&pmd, 0, sizeof(pmd)); 266 pmd.prefix = prefix; 267 pmd.mask = mask; 268 pmd.flags = flags; 269 LIST_INIT(&pmd.dchain); 270 271 IF_AFDATA_WLOCK(llt->llt_ifp); 272 /* Push matching lles to chain */ 273 lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd); 274 275 llentries_unlink(llt, &pmd.dchain); 276 IF_AFDATA_WUNLOCK(llt->llt_ifp); 277 278 LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) 279 llt->llt_free_entry(llt, lle); 280 } 281 282 static void 283 htable_free_tbl(struct lltable *llt) 284 { 285 286 free(llt->lle_head, M_LLTABLE); 287 free(llt, M_LLTABLE); 288 } 289 290 static void 291 llentries_unlink(struct lltable *llt, struct llentries *head) 292 { 293 struct llentry *lle, *next; 294 295 LIST_FOREACH_SAFE(lle, head, lle_chain, next) 296 llt->llt_unlink_entry(lle); 297 } 298 299 /* 300 * Helper function used to drop all mbufs in hold queue. 301 * 302 * Returns the number of held packets, if any, that were dropped. 303 */ 304 size_t 305 lltable_drop_entry_queue(struct llentry *lle) 306 { 307 size_t pkts_dropped; 308 struct mbuf *next; 309 310 LLE_WLOCK_ASSERT(lle); 311 312 pkts_dropped = 0; 313 while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) { 314 next = lle->la_hold->m_nextpkt; 315 m_freem(lle->la_hold); 316 lle->la_hold = next; 317 lle->la_numheld--; 318 pkts_dropped++; 319 } 320 321 KASSERTMSG(lle->la_numheld == 0, 322 "la_numheld %d > 0, pkts_droped %zd", 323 lle->la_numheld, pkts_dropped); 324 325 return (pkts_dropped); 326 } 327 328 /* 329 * Deletes an address from the address table. 330 * This function is called by the timer functions 331 * such as arptimer() and nd6_llinfo_timer(), and 332 * the caller does the locking. 333 * 334 * Returns the number of held packets, if any, that were dropped. 335 */ 336 size_t 337 llentry_free(struct llentry *lle) 338 { 339 struct lltable *llt; 340 size_t pkts_dropped; 341 342 LLE_WLOCK_ASSERT(lle); 343 344 if ((lle->la_flags & LLE_LINKED) != 0) { 345 llt = lle->lle_tbl; 346 347 IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 348 llt->llt_unlink_entry(lle); 349 } 350 351 pkts_dropped = lltable_drop_entry_queue(lle); 352 353 LLE_FREE_LOCKED(lle); 354 355 return (pkts_dropped); 356 } 357 358 /* 359 * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp). 360 * 361 * If found the llentry * is returned referenced and unlocked. 362 */ 363 struct llentry * 364 llentry_alloc(struct ifnet *ifp, struct lltable *lt, 365 struct sockaddr_storage *dst) 366 { 367 struct llentry *la; 368 369 IF_AFDATA_RLOCK(ifp); 370 la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); 371 IF_AFDATA_RUNLOCK(ifp); 372 if ((la == NULL) && 373 #ifdef __FreeBSD__ 374 (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { 375 #else /* XXX */ 376 (ifp->if_flags & IFF_NOARP) == 0) { 377 #endif 378 IF_AFDATA_WLOCK(ifp); 379 la = lla_create(lt, 0, (struct sockaddr *)dst); 380 IF_AFDATA_WUNLOCK(ifp); 381 } 382 383 if (la != NULL) { 384 LLE_ADDREF(la); 385 LLE_WUNLOCK(la); 386 } 387 388 return (la); 389 } 390 391 /* 392 * Free all entries from given table and free itself. 393 */ 394 395 static int 396 lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 397 { 398 struct llentries *dchain; 399 400 dchain = (struct llentries *)farg; 401 402 LLE_WLOCK(lle); 403 LIST_INSERT_HEAD(dchain, lle, lle_chain); 404 405 return (0); 406 } 407 408 /* 409 * Free all entries from given table. 410 */ 411 void 412 lltable_purge_entries(struct lltable *llt) 413 { 414 struct llentry *lle, *next; 415 struct llentries dchain; 416 417 KASSERTMSG(llt != NULL, "llt is NULL"); 418 419 LIST_INIT(&dchain); 420 IF_AFDATA_WLOCK(llt->llt_ifp); 421 /* Push all lles to @dchain */ 422 lltable_foreach_lle(llt, lltable_free_cb, &dchain); 423 llentries_unlink(llt, &dchain); 424 IF_AFDATA_WUNLOCK(llt->llt_ifp); 425 426 LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { 427 /* 428 * We need to release the lock here to lle_timer proceeds; 429 * lle_timer should stop immediately if LLE_LINKED isn't set. 430 * Note that we cannot pass lle->lle_lock to callout_halt 431 * because it's a rwlock. 432 */ 433 LLE_ADDREF(lle); 434 LLE_WUNLOCK(lle); 435 #ifdef NET_MPSAFE 436 callout_halt(&lle->la_timer, NULL); 437 #else 438 if (mutex_owned(softnet_lock)) 439 callout_halt(&lle->la_timer, softnet_lock); 440 else 441 callout_halt(&lle->la_timer, NULL); 442 #endif 443 LLE_WLOCK(lle); 444 LLE_REMREF(lle); 445 llentry_free(lle); 446 } 447 448 } 449 450 /* 451 * Free all entries from given table and free itself. 452 */ 453 void 454 lltable_free(struct lltable *llt) 455 { 456 457 KASSERTMSG(llt != NULL, "llt is NULL"); 458 459 lltable_unlink(llt); 460 lltable_purge_entries(llt); 461 llt->llt_free_tbl(llt); 462 } 463 464 void 465 lltable_drain(int af) 466 { 467 struct lltable *llt; 468 struct llentry *lle; 469 register int i; 470 471 LLTABLE_RLOCK(); 472 SLIST_FOREACH(llt, &lltables, llt_link) { 473 if (llt->llt_af != af) 474 continue; 475 476 for (i=0; i < llt->llt_hsize; i++) { 477 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 478 LLE_WLOCK(lle); 479 lltable_drop_entry_queue(lle); 480 LLE_WUNLOCK(lle); 481 } 482 } 483 } 484 LLTABLE_RUNLOCK(); 485 } 486 487 void 488 lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask, 489 u_int flags) 490 { 491 struct lltable *llt; 492 493 LLTABLE_RLOCK(); 494 SLIST_FOREACH(llt, &lltables, llt_link) { 495 if (llt->llt_af != af) 496 continue; 497 498 llt->llt_prefix_free(llt, prefix, mask, flags); 499 } 500 LLTABLE_RUNLOCK(); 501 } 502 503 struct lltable * 504 lltable_allocate_htbl(uint32_t hsize) 505 { 506 struct lltable *llt; 507 int i; 508 509 llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO); 510 llt->llt_hsize = hsize; 511 llt->lle_head = malloc(sizeof(struct llentries) * hsize, 512 M_LLTABLE, M_WAITOK | M_ZERO); 513 514 for (i = 0; i < llt->llt_hsize; i++) 515 LIST_INIT(&llt->lle_head[i]); 516 517 /* Set some default callbacks */ 518 llt->llt_link_entry = htable_link_entry; 519 llt->llt_unlink_entry = htable_unlink_entry; 520 llt->llt_prefix_free = htable_prefix_free; 521 llt->llt_foreach_entry = htable_foreach_lle; 522 523 llt->llt_free_tbl = htable_free_tbl; 524 525 return (llt); 526 } 527 528 /* 529 * Links lltable to global llt list. 530 */ 531 void 532 lltable_link(struct lltable *llt) 533 { 534 535 LLTABLE_WLOCK(); 536 SLIST_INSERT_HEAD(&lltables, llt, llt_link); 537 LLTABLE_WUNLOCK(); 538 } 539 540 static void 541 lltable_unlink(struct lltable *llt) 542 { 543 544 LLTABLE_WLOCK(); 545 SLIST_REMOVE(&lltables, llt, lltable, llt_link); 546 LLTABLE_WUNLOCK(); 547 548 } 549 550 /* 551 * External methods used by lltable consumers 552 */ 553 554 int 555 lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 556 { 557 558 return (llt->llt_foreach_entry(llt, f, farg)); 559 } 560 561 void 562 lltable_link_entry(struct lltable *llt, struct llentry *lle) 563 { 564 565 llt->llt_link_entry(llt, lle); 566 } 567 568 void 569 lltable_unlink_entry(struct lltable *llt, struct llentry *lle) 570 { 571 572 llt->llt_unlink_entry(lle); 573 } 574 575 void 576 lltable_free_entry(struct lltable *llt, struct llentry *lle) 577 { 578 579 llt->llt_free_entry(llt, lle); 580 } 581 582 void 583 lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) 584 { 585 struct lltable *llt; 586 587 llt = lle->lle_tbl; 588 llt->llt_fill_sa_entry(lle, sa); 589 } 590 591 struct ifnet * 592 lltable_get_ifp(const struct lltable *llt) 593 { 594 595 return (llt->llt_ifp); 596 } 597 598 int 599 lltable_get_af(const struct lltable *llt) 600 { 601 602 return (llt->llt_af); 603 } 604 605 /* 606 * Called in route_output when rtm_flags contains RTF_LLDATA. 607 */ 608 int 609 lla_rt_output(const u_char rtm_type, const int rtm_flags, const time_t rtm_expire, 610 struct rt_addrinfo *info, int sdl_index) 611 { 612 const struct sockaddr_dl *dl = satocsdl(info->rti_info[RTAX_GATEWAY]); 613 const struct sockaddr *dst = info->rti_info[RTAX_DST]; 614 struct ifnet *ifp; 615 struct lltable *llt; 616 struct llentry *lle; 617 u_int laflags; 618 int error; 619 struct psref psref; 620 int bound; 621 622 KASSERTMSG(dl != NULL && dl->sdl_family == AF_LINK, "invalid dl"); 623 624 bound = curlwp_bind(); 625 if (sdl_index != 0) 626 ifp = if_get_byindex(sdl_index, &psref); 627 else 628 ifp = if_get_byindex(dl->sdl_index, &psref); 629 if (ifp == NULL) { 630 curlwp_bindx(bound); 631 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 632 __func__, sdl_index != 0 ? sdl_index : dl->sdl_index); 633 return EINVAL; 634 } 635 636 /* XXX linked list may be too expensive */ 637 LLTABLE_RLOCK(); 638 SLIST_FOREACH(llt, &lltables, llt_link) { 639 if (llt->llt_af == dst->sa_family && 640 llt->llt_ifp == ifp) 641 break; 642 } 643 LLTABLE_RUNLOCK(); 644 KASSERTMSG(llt != NULL, "Yep, ugly hacks are bad"); 645 646 error = 0; 647 648 switch (rtm_type) { 649 case RTM_ADD: 650 /* Add static LLE */ 651 IF_AFDATA_WLOCK(ifp); 652 lle = lla_lookup(llt, 0, dst); 653 654 /* Cannot overwrite an existing static entry */ 655 if (lle != NULL && 656 (lle->la_flags & LLE_STATIC || lle->la_expire == 0)) { 657 LLE_RUNLOCK(lle); 658 IF_AFDATA_WUNLOCK(ifp); 659 error = EEXIST; 660 goto out; 661 } 662 if (lle != NULL) 663 LLE_RUNLOCK(lle); 664 665 lle = lla_create(llt, 0, dst); 666 if (lle == NULL) { 667 IF_AFDATA_WUNLOCK(ifp); 668 error = ENOMEM; 669 goto out; 670 } 671 672 KASSERT(ifp->if_addrlen <= sizeof(lle->ll_addr)); 673 memcpy(&lle->ll_addr, CLLADDR(dl), ifp->if_addrlen); 674 if ((rtm_flags & RTF_ANNOUNCE)) 675 lle->la_flags |= LLE_PUB; 676 lle->la_flags |= LLE_VALID; 677 #ifdef INET6 678 /* 679 * ND6 680 */ 681 if (dst->sa_family == AF_INET6) 682 lle->ln_state = ND6_LLINFO_REACHABLE; 683 #endif 684 /* 685 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) 686 */ 687 688 if (rtm_expire == 0) { 689 lle->la_flags |= LLE_STATIC; 690 lle->la_expire = 0; 691 } else 692 lle->la_expire = rtm_expire; 693 laflags = lle->la_flags; 694 LLE_WUNLOCK(lle); 695 IF_AFDATA_WUNLOCK(ifp); 696 #if defined(INET) && NARP > 0 697 /* gratuitous ARP */ 698 if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) { 699 const struct sockaddr_in *sin; 700 struct in_ifaddr *ia; 701 struct psref _psref; 702 703 sin = satocsin(dst); 704 ia = in_get_ia_on_iface_psref(sin->sin_addr, 705 ifp, &_psref); 706 if (ia != NULL) { 707 arpannounce(ifp, &ia->ia_ifa, CLLADDR(dl)); 708 ia4_release(ia, &_psref); 709 } 710 } 711 #else 712 (void)laflags; 713 #endif 714 715 break; 716 717 case RTM_DELETE: 718 IF_AFDATA_WLOCK(ifp); 719 error = lla_delete(llt, 0, dst); 720 IF_AFDATA_WUNLOCK(ifp); 721 error = (error == 0 ? 0 : ENOENT); 722 break; 723 724 default: 725 error = EINVAL; 726 } 727 728 out: 729 if_put(ifp, &psref); 730 curlwp_bindx(bound); 731 return (error); 732 } 733 734 void 735 lltableinit(void) 736 { 737 738 SLIST_INIT(&lltables); 739 rw_init(&lltable_rwlock); 740 } 741 742 #ifdef __FreeBSD__ 743 #ifdef DDB 744 struct llentry_sa { 745 struct llentry base; 746 struct sockaddr l3_addr; 747 }; 748 749 static void 750 llatbl_lle_show(struct llentry_sa *la) 751 { 752 struct llentry *lle; 753 uint8_t octet[6]; 754 755 lle = &la->base; 756 db_printf("lle=%p\n", lle); 757 db_printf(" lle_next=%p\n", lle->lle_next.le_next); 758 db_printf(" lle_lock=%p\n", &lle->lle_lock); 759 db_printf(" lle_tbl=%p\n", lle->lle_tbl); 760 db_printf(" lle_head=%p\n", lle->lle_head); 761 db_printf(" la_hold=%p\n", lle->la_hold); 762 db_printf(" la_numheld=%d\n", lle->la_numheld); 763 db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 764 db_printf(" la_flags=0x%04x\n", lle->la_flags); 765 db_printf(" la_asked=%u\n", lle->la_asked); 766 db_printf(" la_preempt=%u\n", lle->la_preempt); 767 db_printf(" ln_byhint=%u\n", lle->ln_byhint); 768 db_printf(" ln_state=%d\n", lle->ln_state); 769 db_printf(" ln_router=%u\n", lle->ln_router); 770 db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 771 db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 772 memcopy(octet, &lle->ll_addr.mac16, sizeof(octet)); 773 db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 774 octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 775 db_printf(" lle_timer=%p\n", &lle->lle_timer); 776 777 switch (la->l3_addr.sa_family) { 778 #ifdef INET 779 case AF_INET: 780 { 781 struct sockaddr_in *sin; 782 char l3s[INET_ADDRSTRLEN]; 783 784 sin = (struct sockaddr_in *)&la->l3_addr; 785 inet_ntoa_r(sin->sin_addr, l3s); 786 db_printf(" l3_addr=%s\n", l3s); 787 break; 788 } 789 #endif 790 #ifdef INET6 791 case AF_INET6: 792 { 793 struct sockaddr_in6 *sin6; 794 char l3s[INET6_ADDRSTRLEN]; 795 796 sin6 = (struct sockaddr_in6 *)&la->l3_addr; 797 IN6_PRINT(l3s, &sin6->sin6_addr); 798 db_printf(" l3_addr=%s\n", l3s); 799 break; 800 } 801 #endif 802 default: 803 db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 804 break; 805 } 806 } 807 808 DB_SHOW_COMMAND(llentry, db_show_llentry) 809 { 810 811 if (!have_addr) { 812 db_printf("usage: show llentry <struct llentry *>\n"); 813 return; 814 } 815 816 llatbl_lle_show((struct llentry_sa *)addr); 817 } 818 819 static void 820 llatbl_llt_show(struct lltable *llt) 821 { 822 int i; 823 struct llentry *lle; 824 825 db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 826 llt, llt->llt_af, llt->llt_ifp); 827 828 for (i = 0; i < llt->llt_hsize; i++) { 829 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 830 831 llatbl_lle_show((struct llentry_sa *)lle); 832 if (db_pager_quit) 833 return; 834 } 835 } 836 } 837 838 DB_SHOW_COMMAND(lltable, db_show_lltable) 839 { 840 841 if (!have_addr) { 842 db_printf("usage: show lltable <struct lltable *>\n"); 843 return; 844 } 845 846 llatbl_llt_show((struct lltable *)addr); 847 } 848 849 DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 850 { 851 VNET_ITERATOR_DECL(vnet_iter); 852 struct lltable *llt; 853 854 VNET_FOREACH(vnet_iter) { 855 CURVNET_SET_QUIET(vnet_iter); 856 #ifdef VIMAGE 857 db_printf("vnet=%p\n", curvnet); 858 #endif 859 SLIST_FOREACH(llt, &lltables, llt_link) { 860 db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 861 llt, llt->llt_af, llt->llt_ifp, 862 (llt->llt_ifp != NULL) ? 863 llt->llt_ifp->if_xname : "?"); 864 if (have_addr && addr != 0) /* verbose */ 865 llatbl_llt_show(llt); 866 if (db_pager_quit) { 867 CURVNET_RESTORE(); 868 return; 869 } 870 } 871 CURVNET_RESTORE(); 872 } 873 } 874 #endif /* DDB */ 875 #endif /* __FreeBSD__ */ 876