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