if_llatbl.c revision 1.4.2.2 1 /* $NetBSD: if_llatbl.c,v 1.4.2.2 2015/09/22 12:06:10 skrll 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 LIST_INIT(&dchain);
368 IF_AFDATA_WLOCK(llt->llt_ifp);
369 /* Push all lles to @dchain */
370 lltable_foreach_lle(llt, lltable_free_cb, &dchain);
371 llentries_unlink(llt, &dchain);
372 IF_AFDATA_WUNLOCK(llt->llt_ifp);
373
374 mutex_enter(softnet_lock);
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 rtfree(lle->la_rt);
382 #endif
383 llentry_free(lle);
384 }
385 mutex_exit(softnet_lock);
386
387 llt->llt_free_tbl(llt);
388 }
389
390 void
391 lltable_drain(int af)
392 {
393 struct lltable *llt;
394 struct llentry *lle;
395 register int i;
396
397 LLTABLE_RLOCK();
398 SLIST_FOREACH(llt, &lltables, llt_link) {
399 if (llt->llt_af != af)
400 continue;
401
402 for (i=0; i < llt->llt_hsize; i++) {
403 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
404 LLE_WLOCK(lle);
405 lltable_drop_entry_queue(lle);
406 LLE_WUNLOCK(lle);
407 }
408 }
409 }
410 LLTABLE_RUNLOCK();
411 }
412
413 void
414 lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
415 u_int flags)
416 {
417 struct lltable *llt;
418
419 LLTABLE_RLOCK();
420 SLIST_FOREACH(llt, &lltables, llt_link) {
421 if (llt->llt_af != af)
422 continue;
423
424 llt->llt_prefix_free(llt, prefix, mask, flags);
425 }
426 LLTABLE_RUNLOCK();
427 }
428
429 struct lltable *
430 lltable_allocate_htbl(uint32_t hsize)
431 {
432 struct lltable *llt;
433 int i;
434
435 llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
436 llt->llt_hsize = hsize;
437 llt->lle_head = malloc(sizeof(struct llentries) * hsize,
438 M_LLTABLE, M_WAITOK | M_ZERO);
439
440 for (i = 0; i < llt->llt_hsize; i++)
441 LIST_INIT(&llt->lle_head[i]);
442
443 /* Set some default callbacks */
444 llt->llt_link_entry = htable_link_entry;
445 llt->llt_unlink_entry = htable_unlink_entry;
446 llt->llt_prefix_free = htable_prefix_free;
447 llt->llt_foreach_entry = htable_foreach_lle;
448
449 llt->llt_free_tbl = htable_free_tbl;
450
451 return (llt);
452 }
453
454 /*
455 * Links lltable to global llt list.
456 */
457 void
458 lltable_link(struct lltable *llt)
459 {
460
461 LLTABLE_WLOCK();
462 SLIST_INSERT_HEAD(&lltables, llt, llt_link);
463 LLTABLE_WUNLOCK();
464 }
465
466 static void
467 lltable_unlink(struct lltable *llt)
468 {
469
470 LLTABLE_WLOCK();
471 SLIST_REMOVE(&lltables, llt, lltable, llt_link);
472 LLTABLE_WUNLOCK();
473
474 }
475
476 /*
477 * External methods used by lltable consumers
478 */
479
480 int
481 lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
482 {
483
484 return (llt->llt_foreach_entry(llt, f, farg));
485 }
486
487 void
488 lltable_link_entry(struct lltable *llt, struct llentry *lle)
489 {
490
491 llt->llt_link_entry(llt, lle);
492 }
493
494 void
495 lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
496 {
497
498 llt->llt_unlink_entry(lle);
499 }
500
501 void
502 lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
503 {
504 struct lltable *llt;
505
506 llt = lle->lle_tbl;
507 llt->llt_fill_sa_entry(lle, sa);
508 }
509
510 struct ifnet *
511 lltable_get_ifp(const struct lltable *llt)
512 {
513
514 return (llt->llt_ifp);
515 }
516
517 int
518 lltable_get_af(const struct lltable *llt)
519 {
520
521 return (llt->llt_af);
522 }
523
524 /*
525 * Called in route_output when rtm_flags contains RTF_LLDATA.
526 */
527 int
528 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
529 {
530 const struct sockaddr_dl *dl = satocsdl(info->rti_info[RTAX_GATEWAY]);
531 const struct sockaddr *dst = info->rti_info[RTAX_DST];
532 struct ifnet *ifp;
533 struct lltable *llt;
534 struct llentry *lle;
535 u_int laflags;
536 int error;
537
538 KASSERTMSG(dl != NULL && dl->sdl_family == AF_LINK, "invalid dl");
539
540 ifp = if_byindex(dl->sdl_index);
541 if (ifp == NULL) {
542 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
543 __func__, dl->sdl_index);
544 return EINVAL;
545 }
546
547 /* XXX linked list may be too expensive */
548 LLTABLE_RLOCK();
549 SLIST_FOREACH(llt, &lltables, llt_link) {
550 if (llt->llt_af == dst->sa_family &&
551 llt->llt_ifp == ifp)
552 break;
553 }
554 LLTABLE_RUNLOCK();
555 KASSERTMSG(llt != NULL, "Yep, ugly hacks are bad");
556
557 error = 0;
558
559 switch (rtm->rtm_type) {
560 case RTM_ADD:
561 /* Add static LLE */
562 IF_AFDATA_WLOCK(ifp);
563 lle = lla_create(llt, 0, dst);
564 if (lle == NULL) {
565 IF_AFDATA_WUNLOCK(ifp);
566 return (ENOMEM);
567 }
568
569
570 memcpy(&lle->ll_addr, CLLADDR(dl), ifp->if_addrlen);
571 if ((rtm->rtm_flags & RTF_ANNOUNCE))
572 lle->la_flags |= LLE_PUB;
573 lle->la_flags |= LLE_VALID;
574 #ifdef INET6
575 /*
576 * ND6
577 */
578 if (dst->sa_family == AF_INET6)
579 lle->ln_state = ND6_LLINFO_REACHABLE;
580 #endif
581 /*
582 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST)
583 */
584
585 if (rtm->rtm_rmx.rmx_expire == 0) {
586 lle->la_flags |= LLE_STATIC;
587 lle->la_expire = 0;
588 } else
589 lle->la_expire = rtm->rtm_rmx.rmx_expire;
590 laflags = lle->la_flags;
591 LLE_WUNLOCK(lle);
592 IF_AFDATA_WUNLOCK(ifp);
593 #ifdef INET
594 /* gratuitous ARP */
595 if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
596 arprequest(ifp,
597 &((const struct sockaddr_in *)dst)->sin_addr,
598 &((const struct sockaddr_in *)dst)->sin_addr,
599 CLLADDR(dl));
600 #endif
601
602 break;
603
604 case RTM_DELETE:
605 IF_AFDATA_WLOCK(ifp);
606 error = lla_delete(llt, 0, dst);
607 IF_AFDATA_WUNLOCK(ifp);
608 return (error == 0 ? 0 : ENOENT);
609
610 default:
611 error = EINVAL;
612 }
613
614 return (error);
615 }
616
617 void
618 lltableinit(void)
619 {
620
621 SLIST_INIT(&lltables);
622 rw_init(&lltable_rwlock);
623 }
624
625 #ifdef __FreeBSD__
626 #ifdef DDB
627 struct llentry_sa {
628 struct llentry base;
629 struct sockaddr l3_addr;
630 };
631
632 static void
633 llatbl_lle_show(struct llentry_sa *la)
634 {
635 struct llentry *lle;
636 uint8_t octet[6];
637
638 lle = &la->base;
639 db_printf("lle=%p\n", lle);
640 db_printf(" lle_next=%p\n", lle->lle_next.le_next);
641 db_printf(" lle_lock=%p\n", &lle->lle_lock);
642 db_printf(" lle_tbl=%p\n", lle->lle_tbl);
643 db_printf(" lle_head=%p\n", lle->lle_head);
644 db_printf(" la_hold=%p\n", lle->la_hold);
645 db_printf(" la_numheld=%d\n", lle->la_numheld);
646 db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
647 db_printf(" la_flags=0x%04x\n", lle->la_flags);
648 db_printf(" la_asked=%u\n", lle->la_asked);
649 db_printf(" la_preempt=%u\n", lle->la_preempt);
650 db_printf(" ln_byhint=%u\n", lle->ln_byhint);
651 db_printf(" ln_state=%d\n", lle->ln_state);
652 db_printf(" ln_router=%u\n", lle->ln_router);
653 db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
654 db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
655 memcopy(octet, &lle->ll_addr.mac16, sizeof(octet));
656 db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
657 octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
658 db_printf(" lle_timer=%p\n", &lle->lle_timer);
659
660 switch (la->l3_addr.sa_family) {
661 #ifdef INET
662 case AF_INET:
663 {
664 struct sockaddr_in *sin;
665 char l3s[INET_ADDRSTRLEN];
666
667 sin = (struct sockaddr_in *)&la->l3_addr;
668 inet_ntoa_r(sin->sin_addr, l3s);
669 db_printf(" l3_addr=%s\n", l3s);
670 break;
671 }
672 #endif
673 #ifdef INET6
674 case AF_INET6:
675 {
676 struct sockaddr_in6 *sin6;
677 char l3s[INET6_ADDRSTRLEN];
678
679 sin6 = (struct sockaddr_in6 *)&la->l3_addr;
680 ip6_sprintf(l3s, &sin6->sin6_addr);
681 db_printf(" l3_addr=%s\n", l3s);
682 break;
683 }
684 #endif
685 default:
686 db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family);
687 break;
688 }
689 }
690
691 DB_SHOW_COMMAND(llentry, db_show_llentry)
692 {
693
694 if (!have_addr) {
695 db_printf("usage: show llentry <struct llentry *>\n");
696 return;
697 }
698
699 llatbl_lle_show((struct llentry_sa *)addr);
700 }
701
702 static void
703 llatbl_llt_show(struct lltable *llt)
704 {
705 int i;
706 struct llentry *lle;
707
708 db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
709 llt, llt->llt_af, llt->llt_ifp);
710
711 for (i = 0; i < llt->llt_hsize; i++) {
712 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
713
714 llatbl_lle_show((struct llentry_sa *)lle);
715 if (db_pager_quit)
716 return;
717 }
718 }
719 }
720
721 DB_SHOW_COMMAND(lltable, db_show_lltable)
722 {
723
724 if (!have_addr) {
725 db_printf("usage: show lltable <struct lltable *>\n");
726 return;
727 }
728
729 llatbl_llt_show((struct lltable *)addr);
730 }
731
732 DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
733 {
734 VNET_ITERATOR_DECL(vnet_iter);
735 struct lltable *llt;
736
737 VNET_FOREACH(vnet_iter) {
738 CURVNET_SET_QUIET(vnet_iter);
739 #ifdef VIMAGE
740 db_printf("vnet=%p\n", curvnet);
741 #endif
742 SLIST_FOREACH(llt, &lltables, llt_link) {
743 db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
744 llt, llt->llt_af, llt->llt_ifp,
745 (llt->llt_ifp != NULL) ?
746 llt->llt_ifp->if_xname : "?");
747 if (have_addr && addr != 0) /* verbose */
748 llatbl_llt_show(llt);
749 if (db_pager_quit) {
750 CURVNET_RESTORE();
751 return;
752 }
753 }
754 CURVNET_RESTORE();
755 }
756 }
757 #endif /* DDB */
758 #endif /* __FreeBSD__ */
759