Home | History | Annotate | Line # | Download | only in net
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