if_llatbl.c revision 1.9 1 /* $NetBSD: if_llatbl.c,v 1.9 2015/11/26 01:41:20 ozaki-r 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 <netinet6/in6_var.h>
64 #include <netinet6/nd6.h>
65
66 static SLIST_HEAD(, lltable) lltables;
67 krwlock_t lltable_rwlock;
68
69 static void lltable_unlink(struct lltable *llt);
70 static void llentries_unlink(struct lltable *llt, struct llentries *head);
71
72 static void htable_unlink_entry(struct llentry *lle);
73 static void htable_link_entry(struct lltable *llt, struct llentry *lle);
74 static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
75 void *farg);
76
77 /*
78 * Dump lle state for a specific address family.
79 */
80 static int
81 lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
82 {
83 int error;
84
85 LLTABLE_LOCK_ASSERT();
86
87 if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
88 return (0);
89 error = 0;
90
91 IF_AFDATA_RLOCK(llt->llt_ifp);
92 error = lltable_foreach_lle(llt,
93 (llt_foreach_cb_t *)llt->llt_dump_entry, wr);
94 IF_AFDATA_RUNLOCK(llt->llt_ifp);
95
96 return (error);
97 }
98
99 /*
100 * Dump arp state for a specific address family.
101 */
102 int
103 lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
104 {
105 struct lltable *llt;
106 int error = 0;
107
108 LLTABLE_RLOCK();
109 SLIST_FOREACH(llt, &lltables, llt_link) {
110 if (llt->llt_af == af) {
111 error = lltable_dump_af(llt, wr);
112 if (error != 0)
113 goto done;
114 }
115 }
116 done:
117 LLTABLE_RUNLOCK();
118 return (error);
119 }
120
121 /*
122 * Common function helpers for chained hash table.
123 */
124
125 /*
126 * Runs specified callback for each entry in @llt.
127 * Caller does the locking.
128 *
129 */
130 static int
131 htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
132 {
133 struct llentry *lle, *next;
134 int i, error;
135
136 error = 0;
137
138 for (i = 0; i < llt->llt_hsize; i++) {
139 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
140 error = f(llt, lle, farg);
141 if (error != 0)
142 break;
143 }
144 }
145
146 return (error);
147 }
148
149 static void
150 htable_link_entry(struct lltable *llt, struct llentry *lle)
151 {
152 struct llentries *lleh;
153 uint32_t hashidx;
154
155 if ((lle->la_flags & LLE_LINKED) != 0)
156 return;
157
158 IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
159
160 hashidx = llt->llt_hash(lle, llt->llt_hsize);
161 lleh = &llt->lle_head[hashidx];
162
163 lle->lle_tbl = llt;
164 lle->lle_head = lleh;
165 lle->la_flags |= LLE_LINKED;
166 LIST_INSERT_HEAD(lleh, lle, lle_next);
167
168 llt->llt_lle_count++;
169 }
170
171 static void
172 htable_unlink_entry(struct llentry *lle)
173 {
174
175 if ((lle->la_flags & LLE_LINKED) != 0) {
176 IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
177 LIST_REMOVE(lle, lle_next);
178 lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
179 #if 0
180 lle->lle_tbl = NULL;
181 lle->lle_head = NULL;
182 #endif
183 KASSERT(lle->lle_tbl->llt_lle_count != 0);
184 lle->lle_tbl->llt_lle_count--;
185 }
186 }
187
188 struct prefix_match_data {
189 const struct sockaddr *prefix;
190 const struct sockaddr *mask;
191 struct llentries dchain;
192 u_int flags;
193 };
194
195 static int
196 htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
197 {
198 struct prefix_match_data *pmd;
199
200 pmd = (struct prefix_match_data *)farg;
201
202 if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) {
203 LLE_WLOCK(lle);
204 LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
205 }
206
207 return (0);
208 }
209
210 static void
211 htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
212 const struct sockaddr *mask, u_int flags)
213 {
214 struct llentry *lle, *next;
215 struct prefix_match_data pmd;
216
217 memset(&pmd, 0, sizeof(pmd));
218 pmd.prefix = prefix;
219 pmd.mask = mask;
220 pmd.flags = flags;
221 LIST_INIT(&pmd.dchain);
222
223 IF_AFDATA_WLOCK(llt->llt_ifp);
224 /* Push matching lles to chain */
225 lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
226
227 llentries_unlink(llt, &pmd.dchain);
228 IF_AFDATA_WUNLOCK(llt->llt_ifp);
229
230 LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
231 llt->llt_free_entry(llt, lle);
232 }
233
234 static void
235 htable_free_tbl(struct lltable *llt)
236 {
237
238 free(llt->lle_head, M_LLTABLE);
239 free(llt, M_LLTABLE);
240 }
241
242 static void
243 llentries_unlink(struct lltable *llt, struct llentries *head)
244 {
245 struct llentry *lle, *next;
246
247 LIST_FOREACH_SAFE(lle, head, lle_chain, next)
248 llt->llt_unlink_entry(lle);
249 }
250
251 /*
252 * Helper function used to drop all mbufs in hold queue.
253 *
254 * Returns the number of held packets, if any, that were dropped.
255 */
256 size_t
257 lltable_drop_entry_queue(struct llentry *lle)
258 {
259 size_t pkts_dropped;
260 struct mbuf *next;
261
262 LLE_WLOCK_ASSERT(lle);
263
264 pkts_dropped = 0;
265 while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
266 next = lle->la_hold->m_nextpkt;
267 m_freem(lle->la_hold);
268 lle->la_hold = next;
269 lle->la_numheld--;
270 pkts_dropped++;
271 }
272
273 KASSERTMSG(lle->la_numheld == 0,
274 "la_numheld %d > 0, pkts_droped %zd",
275 lle->la_numheld, pkts_dropped);
276
277 return (pkts_dropped);
278 }
279
280 /*
281 * Deletes an address from the address table.
282 * This function is called by the timer functions
283 * such as arptimer() and nd6_llinfo_timer(), and
284 * the caller does the locking.
285 *
286 * Returns the number of held packets, if any, that were dropped.
287 */
288 size_t
289 llentry_free(struct llentry *lle)
290 {
291 struct lltable *llt;
292 size_t pkts_dropped;
293
294 LLE_WLOCK_ASSERT(lle);
295
296 if ((lle->la_flags & LLE_LINKED) != 0) {
297 llt = lle->lle_tbl;
298
299 IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
300 llt->llt_unlink_entry(lle);
301 }
302
303 pkts_dropped = lltable_drop_entry_queue(lle);
304
305 LLE_FREE_LOCKED(lle);
306
307 return (pkts_dropped);
308 }
309
310 /*
311 * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
312 *
313 * If found the llentry * is returned referenced and unlocked.
314 */
315 struct llentry *
316 llentry_alloc(struct ifnet *ifp, struct lltable *lt,
317 struct sockaddr_storage *dst)
318 {
319 struct llentry *la;
320
321 IF_AFDATA_RLOCK(ifp);
322 la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst);
323 IF_AFDATA_RUNLOCK(ifp);
324 if ((la == NULL) &&
325 #ifdef __FreeBSD__
326 (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
327 #else /* XXX */
328 (ifp->if_flags & IFF_NOARP) == 0) {
329 #endif
330 IF_AFDATA_WLOCK(ifp);
331 la = lla_create(lt, 0, (struct sockaddr *)dst);
332 IF_AFDATA_WUNLOCK(ifp);
333 }
334
335 if (la != NULL) {
336 LLE_ADDREF(la);
337 LLE_WUNLOCK(la);
338 }
339
340 return (la);
341 }
342
343 /*
344 * Free all entries from given table and free itself.
345 */
346
347 static int
348 lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
349 {
350 struct llentries *dchain;
351
352 dchain = (struct llentries *)farg;
353
354 LLE_WLOCK(lle);
355 LIST_INSERT_HEAD(dchain, lle, lle_chain);
356
357 return (0);
358 }
359
360 /*
361 * Free all entries from given table.
362 */
363 void
364 lltable_purge_entries(struct lltable *llt)
365 {
366 struct llentry *lle, *next;
367 struct llentries dchain;
368
369 KASSERTMSG(llt != NULL, "llt is NULL");
370
371 LIST_INIT(&dchain);
372 IF_AFDATA_WLOCK(llt->llt_ifp);
373 /* Push all lles to @dchain */
374 lltable_foreach_lle(llt, lltable_free_cb, &dchain);
375 llentries_unlink(llt, &dchain);
376 IF_AFDATA_WUNLOCK(llt->llt_ifp);
377
378 LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
379 if (callout_halt(&lle->la_timer, &lle->lle_lock))
380 LLE_REMREF(lle);
381 #if defined(__NetBSD__)
382 /* XXX should have callback? */
383 if (lle->la_rt != NULL) {
384 struct rtentry *rt = lle->la_rt;
385 lle->la_rt = NULL;
386 #ifdef GATEWAY
387 /* XXX cannot call rtfree with holding mutex(IPL_NET) */
388 LLE_ADDREF(lle);
389 LLE_WUNLOCK(lle);
390 #endif
391 rtfree(rt);
392 #ifdef GATEWAY
393 LLE_WLOCK(lle);
394 LLE_REMREF(lle);
395 #endif
396 }
397 #endif
398 llentry_free(lle);
399 }
400
401 }
402
403 /*
404 * Free all entries from given table and free itself.
405 */
406 void
407 lltable_free(struct lltable *llt)
408 {
409
410 KASSERTMSG(llt != NULL, "llt is NULL");
411
412 lltable_unlink(llt);
413 lltable_purge_entries(llt);
414 llt->llt_free_tbl(llt);
415 }
416
417 void
418 lltable_drain(int af)
419 {
420 struct lltable *llt;
421 struct llentry *lle;
422 register int i;
423
424 LLTABLE_RLOCK();
425 SLIST_FOREACH(llt, &lltables, llt_link) {
426 if (llt->llt_af != af)
427 continue;
428
429 for (i=0; i < llt->llt_hsize; i++) {
430 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
431 LLE_WLOCK(lle);
432 lltable_drop_entry_queue(lle);
433 LLE_WUNLOCK(lle);
434 }
435 }
436 }
437 LLTABLE_RUNLOCK();
438 }
439
440 void
441 lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
442 u_int flags)
443 {
444 struct lltable *llt;
445
446 LLTABLE_RLOCK();
447 SLIST_FOREACH(llt, &lltables, llt_link) {
448 if (llt->llt_af != af)
449 continue;
450
451 llt->llt_prefix_free(llt, prefix, mask, flags);
452 }
453 LLTABLE_RUNLOCK();
454 }
455
456 struct lltable *
457 lltable_allocate_htbl(uint32_t hsize)
458 {
459 struct lltable *llt;
460 int i;
461
462 llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
463 llt->llt_hsize = hsize;
464 llt->lle_head = malloc(sizeof(struct llentries) * hsize,
465 M_LLTABLE, M_WAITOK | M_ZERO);
466
467 for (i = 0; i < llt->llt_hsize; i++)
468 LIST_INIT(&llt->lle_head[i]);
469
470 /* Set some default callbacks */
471 llt->llt_link_entry = htable_link_entry;
472 llt->llt_unlink_entry = htable_unlink_entry;
473 llt->llt_prefix_free = htable_prefix_free;
474 llt->llt_foreach_entry = htable_foreach_lle;
475
476 llt->llt_free_tbl = htable_free_tbl;
477
478 return (llt);
479 }
480
481 /*
482 * Links lltable to global llt list.
483 */
484 void
485 lltable_link(struct lltable *llt)
486 {
487
488 LLTABLE_WLOCK();
489 SLIST_INSERT_HEAD(&lltables, llt, llt_link);
490 LLTABLE_WUNLOCK();
491 }
492
493 static void
494 lltable_unlink(struct lltable *llt)
495 {
496
497 LLTABLE_WLOCK();
498 SLIST_REMOVE(&lltables, llt, lltable, llt_link);
499 LLTABLE_WUNLOCK();
500
501 }
502
503 /*
504 * External methods used by lltable consumers
505 */
506
507 int
508 lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
509 {
510
511 return (llt->llt_foreach_entry(llt, f, farg));
512 }
513
514 void
515 lltable_link_entry(struct lltable *llt, struct llentry *lle)
516 {
517
518 llt->llt_link_entry(llt, lle);
519 }
520
521 void
522 lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
523 {
524
525 llt->llt_unlink_entry(lle);
526 }
527
528 void
529 lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
530 {
531 struct lltable *llt;
532
533 llt = lle->lle_tbl;
534 llt->llt_fill_sa_entry(lle, sa);
535 }
536
537 struct ifnet *
538 lltable_get_ifp(const struct lltable *llt)
539 {
540
541 return (llt->llt_ifp);
542 }
543
544 int
545 lltable_get_af(const struct lltable *llt)
546 {
547
548 return (llt->llt_af);
549 }
550
551 /*
552 * Called in route_output when rtm_flags contains RTF_LLDATA.
553 */
554 int
555 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
556 {
557 const struct sockaddr_dl *dl = satocsdl(info->rti_info[RTAX_GATEWAY]);
558 const struct sockaddr *dst = info->rti_info[RTAX_DST];
559 struct ifnet *ifp;
560 struct lltable *llt;
561 struct llentry *lle;
562 u_int laflags;
563 int error;
564
565 KASSERTMSG(dl != NULL && dl->sdl_family == AF_LINK, "invalid dl");
566
567 ifp = if_byindex(dl->sdl_index);
568 if (ifp == NULL) {
569 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
570 __func__, dl->sdl_index);
571 return EINVAL;
572 }
573
574 /* XXX linked list may be too expensive */
575 LLTABLE_RLOCK();
576 SLIST_FOREACH(llt, &lltables, llt_link) {
577 if (llt->llt_af == dst->sa_family &&
578 llt->llt_ifp == ifp)
579 break;
580 }
581 LLTABLE_RUNLOCK();
582 KASSERTMSG(llt != NULL, "Yep, ugly hacks are bad");
583
584 error = 0;
585
586 switch (rtm->rtm_type) {
587 case RTM_ADD:
588 /* Add static LLE */
589 IF_AFDATA_WLOCK(ifp);
590 lle = lla_create(llt, 0, dst);
591 if (lle == NULL) {
592 IF_AFDATA_WUNLOCK(ifp);
593 return (ENOMEM);
594 }
595
596
597 memcpy(&lle->ll_addr, CLLADDR(dl), ifp->if_addrlen);
598 if ((rtm->rtm_flags & RTF_ANNOUNCE))
599 lle->la_flags |= LLE_PUB;
600 lle->la_flags |= LLE_VALID;
601 #ifdef INET6
602 /*
603 * ND6
604 */
605 if (dst->sa_family == AF_INET6)
606 lle->ln_state = ND6_LLINFO_REACHABLE;
607 #endif
608 /*
609 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST)
610 */
611
612 if (rtm->rtm_rmx.rmx_expire == 0) {
613 lle->la_flags |= LLE_STATIC;
614 lle->la_expire = 0;
615 } else
616 lle->la_expire = rtm->rtm_rmx.rmx_expire;
617 laflags = lle->la_flags;
618 LLE_WUNLOCK(lle);
619 IF_AFDATA_WUNLOCK(ifp);
620 #if defined(INET) && NARP > 0
621 /* gratuitous ARP */
622 if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
623 arprequest(ifp,
624 &((const struct sockaddr_in *)dst)->sin_addr,
625 &((const struct sockaddr_in *)dst)->sin_addr,
626 CLLADDR(dl));
627 #else
628 (void)laflags;
629 #endif
630
631 break;
632
633 case RTM_DELETE:
634 IF_AFDATA_WLOCK(ifp);
635 error = lla_delete(llt, 0, dst);
636 IF_AFDATA_WUNLOCK(ifp);
637 return (error == 0 ? 0 : ENOENT);
638
639 default:
640 error = EINVAL;
641 }
642
643 return (error);
644 }
645
646 void
647 lltableinit(void)
648 {
649
650 SLIST_INIT(&lltables);
651 rw_init(&lltable_rwlock);
652 }
653
654 #ifdef __FreeBSD__
655 #ifdef DDB
656 struct llentry_sa {
657 struct llentry base;
658 struct sockaddr l3_addr;
659 };
660
661 static void
662 llatbl_lle_show(struct llentry_sa *la)
663 {
664 struct llentry *lle;
665 uint8_t octet[6];
666
667 lle = &la->base;
668 db_printf("lle=%p\n", lle);
669 db_printf(" lle_next=%p\n", lle->lle_next.le_next);
670 db_printf(" lle_lock=%p\n", &lle->lle_lock);
671 db_printf(" lle_tbl=%p\n", lle->lle_tbl);
672 db_printf(" lle_head=%p\n", lle->lle_head);
673 db_printf(" la_hold=%p\n", lle->la_hold);
674 db_printf(" la_numheld=%d\n", lle->la_numheld);
675 db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
676 db_printf(" la_flags=0x%04x\n", lle->la_flags);
677 db_printf(" la_asked=%u\n", lle->la_asked);
678 db_printf(" la_preempt=%u\n", lle->la_preempt);
679 db_printf(" ln_byhint=%u\n", lle->ln_byhint);
680 db_printf(" ln_state=%d\n", lle->ln_state);
681 db_printf(" ln_router=%u\n", lle->ln_router);
682 db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
683 db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
684 memcopy(octet, &lle->ll_addr.mac16, sizeof(octet));
685 db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
686 octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
687 db_printf(" lle_timer=%p\n", &lle->lle_timer);
688
689 switch (la->l3_addr.sa_family) {
690 #ifdef INET
691 case AF_INET:
692 {
693 struct sockaddr_in *sin;
694 char l3s[INET_ADDRSTRLEN];
695
696 sin = (struct sockaddr_in *)&la->l3_addr;
697 inet_ntoa_r(sin->sin_addr, l3s);
698 db_printf(" l3_addr=%s\n", l3s);
699 break;
700 }
701 #endif
702 #ifdef INET6
703 case AF_INET6:
704 {
705 struct sockaddr_in6 *sin6;
706 char l3s[INET6_ADDRSTRLEN];
707
708 sin6 = (struct sockaddr_in6 *)&la->l3_addr;
709 ip6_sprintf(l3s, &sin6->sin6_addr);
710 db_printf(" l3_addr=%s\n", l3s);
711 break;
712 }
713 #endif
714 default:
715 db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family);
716 break;
717 }
718 }
719
720 DB_SHOW_COMMAND(llentry, db_show_llentry)
721 {
722
723 if (!have_addr) {
724 db_printf("usage: show llentry <struct llentry *>\n");
725 return;
726 }
727
728 llatbl_lle_show((struct llentry_sa *)addr);
729 }
730
731 static void
732 llatbl_llt_show(struct lltable *llt)
733 {
734 int i;
735 struct llentry *lle;
736
737 db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
738 llt, llt->llt_af, llt->llt_ifp);
739
740 for (i = 0; i < llt->llt_hsize; i++) {
741 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
742
743 llatbl_lle_show((struct llentry_sa *)lle);
744 if (db_pager_quit)
745 return;
746 }
747 }
748 }
749
750 DB_SHOW_COMMAND(lltable, db_show_lltable)
751 {
752
753 if (!have_addr) {
754 db_printf("usage: show lltable <struct lltable *>\n");
755 return;
756 }
757
758 llatbl_llt_show((struct lltable *)addr);
759 }
760
761 DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
762 {
763 VNET_ITERATOR_DECL(vnet_iter);
764 struct lltable *llt;
765
766 VNET_FOREACH(vnet_iter) {
767 CURVNET_SET_QUIET(vnet_iter);
768 #ifdef VIMAGE
769 db_printf("vnet=%p\n", curvnet);
770 #endif
771 SLIST_FOREACH(llt, &lltables, llt_link) {
772 db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
773 llt, llt->llt_af, llt->llt_ifp,
774 (llt->llt_ifp != NULL) ?
775 llt->llt_ifp->if_xname : "?");
776 if (have_addr && addr != 0) /* verbose */
777 llatbl_llt_show(llt);
778 if (db_pager_quit) {
779 CURVNET_RESTORE();
780 return;
781 }
782 }
783 CURVNET_RESTORE();
784 }
785 }
786 #endif /* DDB */
787 #endif /* __FreeBSD__ */
788