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