xref: /freebsd/sys/net/if_llatbl.c (revision d3cdb7165559c1b98bec9b6a0145c85ac327710f)
182f39c91SKip Macy /*
282f39c91SKip Macy  * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
382f39c91SKip Macy  * Copyright (c) 2004-2008 Qing Li. All rights reserved.
482f39c91SKip Macy  * Copyright (c) 2008 Kip Macy. All rights reserved.
582f39c91SKip Macy  *
682f39c91SKip Macy  * Redistribution and use in source and binary forms, with or without
782f39c91SKip Macy  * modification, are permitted provided that the following conditions
882f39c91SKip Macy  * are met:
982f39c91SKip Macy  * 1. Redistributions of source code must retain the above copyright
1082f39c91SKip Macy  *    notice, this list of conditions and the following disclaimer.
1182f39c91SKip Macy  * 2. Redistributions in binary form must reproduce the above copyright
1282f39c91SKip Macy  *    notice, this list of conditions and the following disclaimer in the
1382f39c91SKip Macy  *    documentation and/or other materials provided with the distribution.
1482f39c91SKip Macy  *
1582f39c91SKip Macy  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1682f39c91SKip Macy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1782f39c91SKip Macy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1882f39c91SKip Macy  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1982f39c91SKip Macy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2082f39c91SKip Macy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2182f39c91SKip Macy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2282f39c91SKip Macy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2382f39c91SKip Macy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2482f39c91SKip Macy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2582f39c91SKip Macy  * SUCH DAMAGE.
2682f39c91SKip Macy  */
2782f39c91SKip Macy #include <sys/cdefs.h>
2882f39c91SKip Macy __FBSDID("$FreeBSD$");
2982f39c91SKip Macy 
30335b943fSBjoern A. Zeeb #include "opt_ddb.h"
3182f39c91SKip Macy #include "opt_inet.h"
3282f39c91SKip Macy #include "opt_inet6.h"
3382f39c91SKip Macy 
3482f39c91SKip Macy #include <sys/param.h>
3582f39c91SKip Macy #include <sys/systm.h>
3682f39c91SKip Macy #include <sys/malloc.h>
3782f39c91SKip Macy #include <sys/mbuf.h>
3882f39c91SKip Macy #include <sys/syslog.h>
3982f39c91SKip Macy #include <sys/sysctl.h>
4082f39c91SKip Macy #include <sys/socket.h>
4182f39c91SKip Macy #include <sys/kernel.h>
4282f39c91SKip Macy #include <sys/lock.h>
4382f39c91SKip Macy #include <sys/mutex.h>
4482f39c91SKip Macy #include <sys/rwlock.h>
4582f39c91SKip Macy 
46335b943fSBjoern A. Zeeb #ifdef DDB
47335b943fSBjoern A. Zeeb #include <ddb/ddb.h>
48335b943fSBjoern A. Zeeb #endif
49335b943fSBjoern A. Zeeb 
5082f39c91SKip Macy #include <vm/uma.h>
5182f39c91SKip Macy 
5282f39c91SKip Macy #include <netinet/in.h>
5382f39c91SKip Macy #include <net/if_llatbl.h>
5482f39c91SKip Macy #include <net/if.h>
5582f39c91SKip Macy #include <net/if_dl.h>
5682f39c91SKip Macy #include <net/if_var.h>
5782f39c91SKip Macy #include <net/route.h>
58530c0060SRobert Watson #include <net/vnet.h>
5982f39c91SKip Macy #include <netinet/if_ether.h>
6082f39c91SKip Macy #include <netinet6/in6_var.h>
6182f39c91SKip Macy #include <netinet6/nd6.h>
6282f39c91SKip Macy 
6382f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
6482f39c91SKip Macy 
653e288e62SDimitry Andric static VNET_DEFINE(SLIST_HEAD(, lltable), lltables);
66989e0411SMarko Zec #define	V_lltables	VNET(lltables)
6782f39c91SKip Macy 
68989e0411SMarko Zec static void vnet_lltable_init(void);
69989e0411SMarko Zec 
70f89d4c3aSAndre Oppermann struct rwlock lltable_rwlock;
71dc56e98fSRobert Watson RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock");
72dc56e98fSRobert Watson 
73721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt);
7411cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head);
7511cdad98SAlexander V. Chernikov 
7611cdad98SAlexander V. Chernikov static void htable_unlink_entry(struct llentry *lle);
7711cdad98SAlexander V. Chernikov static void htable_link_entry(struct lltable *llt, struct llentry *lle);
7811cdad98SAlexander V. Chernikov static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
7911cdad98SAlexander V. Chernikov     void *farg);
8011cdad98SAlexander V. Chernikov 
8111cdad98SAlexander V. Chernikov /*
8211cdad98SAlexander V. Chernikov  * Dump lle state for a specific address family.
8311cdad98SAlexander V. Chernikov  */
8411cdad98SAlexander V. Chernikov static int
8511cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
8611cdad98SAlexander V. Chernikov {
8711cdad98SAlexander V. Chernikov 	int error;
8811cdad98SAlexander V. Chernikov 
8911cdad98SAlexander V. Chernikov 	LLTABLE_LOCK_ASSERT();
9011cdad98SAlexander V. Chernikov 
9111cdad98SAlexander V. Chernikov 	if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
9211cdad98SAlexander V. Chernikov 		return (0);
9311cdad98SAlexander V. Chernikov 	error = 0;
9411cdad98SAlexander V. Chernikov 
9511cdad98SAlexander V. Chernikov 	IF_AFDATA_RLOCK(llt->llt_ifp);
9611cdad98SAlexander V. Chernikov 	error = lltable_foreach_lle(llt,
9711cdad98SAlexander V. Chernikov 	    (llt_foreach_cb_t *)llt->llt_dump_entry, wr);
9811cdad98SAlexander V. Chernikov 	IF_AFDATA_RUNLOCK(llt->llt_ifp);
9911cdad98SAlexander V. Chernikov 
10011cdad98SAlexander V. Chernikov 	return (error);
10111cdad98SAlexander V. Chernikov }
10211cdad98SAlexander V. Chernikov 
10382f39c91SKip Macy /*
10482f39c91SKip Macy  * Dump arp state for a specific address family.
10582f39c91SKip Macy  */
10682f39c91SKip Macy int
10782f39c91SKip Macy lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
10882f39c91SKip Macy {
10982f39c91SKip Macy 	struct lltable *llt;
11082f39c91SKip Macy 	int error = 0;
11182f39c91SKip Macy 
112dc56e98fSRobert Watson 	LLTABLE_RLOCK();
113989e0411SMarko Zec 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
11482f39c91SKip Macy 		if (llt->llt_af == af) {
11511cdad98SAlexander V. Chernikov 			error = lltable_dump_af(llt, wr);
11682f39c91SKip Macy 			if (error != 0)
11782f39c91SKip Macy 				goto done;
11882f39c91SKip Macy 		}
11982f39c91SKip Macy 	}
12082f39c91SKip Macy done:
121dc56e98fSRobert Watson 	LLTABLE_RUNLOCK();
12282f39c91SKip Macy 	return (error);
12382f39c91SKip Macy }
12482f39c91SKip Macy 
12582f39c91SKip Macy /*
12611cdad98SAlexander V. Chernikov  * Common function helpers for chained hash table.
12711cdad98SAlexander V. Chernikov  */
12811cdad98SAlexander V. Chernikov 
12911cdad98SAlexander V. Chernikov /*
13011cdad98SAlexander V. Chernikov  * Runs specified callback for each entry in @llt.
13111cdad98SAlexander V. Chernikov  * Caller does the locking.
13211cdad98SAlexander V. Chernikov  *
13311cdad98SAlexander V. Chernikov  */
13411cdad98SAlexander V. Chernikov static int
13511cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
13611cdad98SAlexander V. Chernikov {
13711cdad98SAlexander V. Chernikov 	struct llentry *lle, *next;
13811cdad98SAlexander V. Chernikov 	int i, error;
13911cdad98SAlexander V. Chernikov 
14011cdad98SAlexander V. Chernikov 	error = 0;
14111cdad98SAlexander V. Chernikov 
14241cb42a6SAlexander V. Chernikov 	for (i = 0; i < llt->llt_hsize; i++) {
14311cdad98SAlexander V. Chernikov 		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
14411cdad98SAlexander V. Chernikov 			error = f(llt, lle, farg);
14511cdad98SAlexander V. Chernikov 			if (error != 0)
14611cdad98SAlexander V. Chernikov 				break;
14711cdad98SAlexander V. Chernikov 		}
14811cdad98SAlexander V. Chernikov 	}
14911cdad98SAlexander V. Chernikov 
15011cdad98SAlexander V. Chernikov 	return (error);
15111cdad98SAlexander V. Chernikov }
15211cdad98SAlexander V. Chernikov 
15311cdad98SAlexander V. Chernikov static void
15411cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle)
15511cdad98SAlexander V. Chernikov {
15611cdad98SAlexander V. Chernikov 	struct llentries *lleh;
15711cdad98SAlexander V. Chernikov 	uint32_t hashidx;
15811cdad98SAlexander V. Chernikov 
15911cdad98SAlexander V. Chernikov 	if ((lle->la_flags & LLE_LINKED) != 0)
16011cdad98SAlexander V. Chernikov 		return;
16111cdad98SAlexander V. Chernikov 
16211cdad98SAlexander V. Chernikov 	IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
16311cdad98SAlexander V. Chernikov 
1643a749863SAlexander V. Chernikov 	hashidx = llt->llt_hash(lle, llt->llt_hsize);
16511cdad98SAlexander V. Chernikov 	lleh = &llt->lle_head[hashidx];
16611cdad98SAlexander V. Chernikov 
16711cdad98SAlexander V. Chernikov 	lle->lle_tbl  = llt;
16811cdad98SAlexander V. Chernikov 	lle->lle_head = lleh;
16911cdad98SAlexander V. Chernikov 	lle->la_flags |= LLE_LINKED;
17011cdad98SAlexander V. Chernikov 	LIST_INSERT_HEAD(lleh, lle, lle_next);
17111cdad98SAlexander V. Chernikov }
17211cdad98SAlexander V. Chernikov 
17311cdad98SAlexander V. Chernikov static void
17411cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle)
17511cdad98SAlexander V. Chernikov {
17611cdad98SAlexander V. Chernikov 
17711cdad98SAlexander V. Chernikov 	if ((lle->la_flags & LLE_LINKED) != 0) {
17811cdad98SAlexander V. Chernikov 		IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
17911cdad98SAlexander V. Chernikov 		LIST_REMOVE(lle, lle_next);
18011cdad98SAlexander V. Chernikov 		lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
18111cdad98SAlexander V. Chernikov #if 0
18211cdad98SAlexander V. Chernikov 		lle->lle_tbl = NULL;
18311cdad98SAlexander V. Chernikov 		lle->lle_head = NULL;
18411cdad98SAlexander V. Chernikov #endif
18511cdad98SAlexander V. Chernikov 	}
18611cdad98SAlexander V. Chernikov }
18711cdad98SAlexander V. Chernikov 
18811cdad98SAlexander V. Chernikov struct prefix_match_data {
1893e7a2321SAlexander V. Chernikov 	const struct sockaddr *addr;
19011cdad98SAlexander V. Chernikov 	const struct sockaddr *mask;
19111cdad98SAlexander V. Chernikov 	struct llentries dchain;
19211cdad98SAlexander V. Chernikov 	u_int flags;
19311cdad98SAlexander V. Chernikov };
19411cdad98SAlexander V. Chernikov 
19511cdad98SAlexander V. Chernikov static int
19611cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
19711cdad98SAlexander V. Chernikov {
19811cdad98SAlexander V. Chernikov 	struct prefix_match_data *pmd;
19911cdad98SAlexander V. Chernikov 
20011cdad98SAlexander V. Chernikov 	pmd = (struct prefix_match_data *)farg;
20111cdad98SAlexander V. Chernikov 
2023e7a2321SAlexander V. Chernikov 	if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
20311cdad98SAlexander V. Chernikov 		LLE_WLOCK(lle);
20411cdad98SAlexander V. Chernikov 		LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
20511cdad98SAlexander V. Chernikov 	}
20611cdad98SAlexander V. Chernikov 
20711cdad98SAlexander V. Chernikov 	return (0);
20811cdad98SAlexander V. Chernikov }
20911cdad98SAlexander V. Chernikov 
21011cdad98SAlexander V. Chernikov static void
2113e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
21211cdad98SAlexander V. Chernikov     const struct sockaddr *mask, u_int flags)
21311cdad98SAlexander V. Chernikov {
21411cdad98SAlexander V. Chernikov 	struct llentry *lle, *next;
21511cdad98SAlexander V. Chernikov 	struct prefix_match_data pmd;
21611cdad98SAlexander V. Chernikov 
21711cdad98SAlexander V. Chernikov 	bzero(&pmd, sizeof(pmd));
2183e7a2321SAlexander V. Chernikov 	pmd.addr = addr;
21911cdad98SAlexander V. Chernikov 	pmd.mask = mask;
22011cdad98SAlexander V. Chernikov 	pmd.flags = flags;
22111cdad98SAlexander V. Chernikov 	LIST_INIT(&pmd.dchain);
22211cdad98SAlexander V. Chernikov 
22311cdad98SAlexander V. Chernikov 	IF_AFDATA_WLOCK(llt->llt_ifp);
22411cdad98SAlexander V. Chernikov 	/* Push matching lles to chain */
22511cdad98SAlexander V. Chernikov 	lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
22611cdad98SAlexander V. Chernikov 
22711cdad98SAlexander V. Chernikov 	llentries_unlink(llt, &pmd.dchain);
22811cdad98SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
22911cdad98SAlexander V. Chernikov 
23011cdad98SAlexander V. Chernikov 	LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
2315a255516SAlexander V. Chernikov 		lltable_free_entry(llt, lle);
23211cdad98SAlexander V. Chernikov }
23311cdad98SAlexander V. Chernikov 
23411cdad98SAlexander V. Chernikov static void
23541cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt)
23641cb42a6SAlexander V. Chernikov {
23741cb42a6SAlexander V. Chernikov 
23841cb42a6SAlexander V. Chernikov 	free(llt->lle_head, M_LLTABLE);
23941cb42a6SAlexander V. Chernikov 	free(llt, M_LLTABLE);
24041cb42a6SAlexander V. Chernikov }
24141cb42a6SAlexander V. Chernikov 
242721cd2e0SAlexander V. Chernikov static void
24311cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head)
24411cdad98SAlexander V. Chernikov {
24511cdad98SAlexander V. Chernikov 	struct llentry *lle, *next;
24611cdad98SAlexander V. Chernikov 
24711cdad98SAlexander V. Chernikov 	LIST_FOREACH_SAFE(lle, head, lle_chain, next)
24811cdad98SAlexander V. Chernikov 		llt->llt_unlink_entry(lle);
24911cdad98SAlexander V. Chernikov }
25011cdad98SAlexander V. Chernikov 
25111cdad98SAlexander V. Chernikov /*
25211cdad98SAlexander V. Chernikov  * Helper function used to drop all mbufs in hold queue.
253e162ea60SGeorge V. Neville-Neil  *
254e162ea60SGeorge V. Neville-Neil  * Returns the number of held packets, if any, that were dropped.
25582f39c91SKip Macy  */
256e162ea60SGeorge V. Neville-Neil size_t
25711cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle)
25882f39c91SKip Macy {
259e162ea60SGeorge V. Neville-Neil 	size_t pkts_dropped;
260e162ea60SGeorge V. Neville-Neil 	struct mbuf *next;
26182f39c91SKip Macy 
26282f39c91SKip Macy 	LLE_WLOCK_ASSERT(lle);
26382f39c91SKip Macy 
264ea537929SGleb Smirnoff 	pkts_dropped = 0;
265e162ea60SGeorge V. Neville-Neil 	while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
266e162ea60SGeorge V. Neville-Neil 		next = lle->la_hold->m_nextpkt;
26782f39c91SKip Macy 		m_freem(lle->la_hold);
268e162ea60SGeorge V. Neville-Neil 		lle->la_hold = next;
269e162ea60SGeorge V. Neville-Neil 		lle->la_numheld--;
270e162ea60SGeorge V. Neville-Neil 		pkts_dropped++;
271e162ea60SGeorge V. Neville-Neil 	}
272e162ea60SGeorge V. Neville-Neil 
273e162ea60SGeorge V. Neville-Neil 	KASSERT(lle->la_numheld == 0,
2747b3b099eSKonstantin Belousov 		("%s: la_numheld %d > 0, pkts_droped %zd", __func__,
275e162ea60SGeorge V. Neville-Neil 		 lle->la_numheld, pkts_dropped));
27682f39c91SKip Macy 
27711cdad98SAlexander V. Chernikov 	return (pkts_dropped);
27811cdad98SAlexander V. Chernikov }
27911cdad98SAlexander V. Chernikov 
28011cdad98SAlexander V. Chernikov /*
2815a255516SAlexander V. Chernikov  *
2825a255516SAlexander V. Chernikov  * Performes generic cleanup routines and frees lle.
2835a255516SAlexander V. Chernikov  *
2845a255516SAlexander V. Chernikov  * Called for non-linked entries, with callouts and
2855a255516SAlexander V. Chernikov  * other AF-specific cleanups performed.
2865a255516SAlexander V. Chernikov  *
2875a255516SAlexander V. Chernikov  * @lle must be passed WLOCK'ed
28811cdad98SAlexander V. Chernikov  *
28911cdad98SAlexander V. Chernikov  * Returns the number of held packets, if any, that were dropped.
29011cdad98SAlexander V. Chernikov  */
29111cdad98SAlexander V. Chernikov size_t
29211cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle)
29311cdad98SAlexander V. Chernikov {
29411cdad98SAlexander V. Chernikov 	size_t pkts_dropped;
29511cdad98SAlexander V. Chernikov 
29611cdad98SAlexander V. Chernikov 	LLE_WLOCK_ASSERT(lle);
29711cdad98SAlexander V. Chernikov 
298*d3cdb716SAlexander V. Chernikov 	KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle"));
29911cdad98SAlexander V. Chernikov 
30011cdad98SAlexander V. Chernikov 	pkts_dropped = lltable_drop_entry_queue(lle);
30111cdad98SAlexander V. Chernikov 
30282f39c91SKip Macy 	LLE_FREE_LOCKED(lle);
303e162ea60SGeorge V. Neville-Neil 
304e162ea60SGeorge V. Neville-Neil 	return (pkts_dropped);
30582f39c91SKip Macy }
30682f39c91SKip Macy 
307adfc35ffSKip Macy /*
308b1d86af7SGleb Smirnoff  * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
309e94ba2ceSKip Macy  *
310b1d86af7SGleb Smirnoff  * If found the llentry * is returned referenced and unlocked.
311adfc35ffSKip Macy  */
312b1d86af7SGleb Smirnoff struct llentry *
313b1d86af7SGleb Smirnoff llentry_alloc(struct ifnet *ifp, struct lltable *lt,
314b1d86af7SGleb Smirnoff     struct sockaddr_storage *dst)
315c8da95acSKip Macy {
3165a255516SAlexander V. Chernikov 	struct llentry *la, *la_tmp;
317c8da95acSKip Macy 
318c8da95acSKip Macy 	IF_AFDATA_RLOCK(ifp);
319b1d86af7SGleb Smirnoff 	la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst);
320c8da95acSKip Macy 	IF_AFDATA_RUNLOCK(ifp);
321b1d86af7SGleb Smirnoff 
322b1d86af7SGleb Smirnoff 	if (la != NULL) {
323c8da95acSKip Macy 		LLE_ADDREF(la);
324c8da95acSKip Macy 		LLE_WUNLOCK(la);
3255a255516SAlexander V. Chernikov 		return (la);
3265a255516SAlexander V. Chernikov 	}
3275a255516SAlexander V. Chernikov 
3285a255516SAlexander V. Chernikov 	if ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
3295a255516SAlexander V. Chernikov 		la = lltable_alloc_entry(lt, 0, (struct sockaddr *)dst);
3305a255516SAlexander V. Chernikov 		if (la == NULL)
3315a255516SAlexander V. Chernikov 			return (NULL);
3325a255516SAlexander V. Chernikov 		IF_AFDATA_WLOCK(ifp);
3335a255516SAlexander V. Chernikov 		LLE_WLOCK(la);
3345a255516SAlexander V. Chernikov 		/* Prefer any existing LLE over newly-created one */
3355a255516SAlexander V. Chernikov 		la_tmp = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst);
3365a255516SAlexander V. Chernikov 		if (la_tmp == NULL)
3375a255516SAlexander V. Chernikov 			lltable_link_entry(lt, la);
3385a255516SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
3395a255516SAlexander V. Chernikov 		if (la_tmp != NULL) {
3405a255516SAlexander V. Chernikov 			lltable_free_entry(lt, la);
3415a255516SAlexander V. Chernikov 			la = la_tmp;
3425a255516SAlexander V. Chernikov 		}
3435a255516SAlexander V. Chernikov 		LLE_ADDREF(la);
3445a255516SAlexander V. Chernikov 		LLE_WUNLOCK(la);
345b1d86af7SGleb Smirnoff 	}
346c8da95acSKip Macy 
347b1d86af7SGleb Smirnoff 	return (la);
348c8da95acSKip Macy }
349c8da95acSKip Macy 
35082f39c91SKip Macy /*
35182f39c91SKip Macy  * Free all entries from given table and free itself.
35282f39c91SKip Macy  */
35311cdad98SAlexander V. Chernikov 
35411cdad98SAlexander V. Chernikov static int
35511cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
35611cdad98SAlexander V. Chernikov {
35711cdad98SAlexander V. Chernikov 	struct llentries *dchain;
35811cdad98SAlexander V. Chernikov 
35911cdad98SAlexander V. Chernikov 	dchain = (struct llentries *)farg;
36011cdad98SAlexander V. Chernikov 
36111cdad98SAlexander V. Chernikov 	LLE_WLOCK(lle);
36211cdad98SAlexander V. Chernikov 	LIST_INSERT_HEAD(dchain, lle, lle_chain);
36311cdad98SAlexander V. Chernikov 
36411cdad98SAlexander V. Chernikov 	return (0);
36511cdad98SAlexander V. Chernikov }
36611cdad98SAlexander V. Chernikov 
36711cdad98SAlexander V. Chernikov /*
36811cdad98SAlexander V. Chernikov  * Free all entries from given table and free itself.
36911cdad98SAlexander V. Chernikov  */
37082f39c91SKip Macy void
37182f39c91SKip Macy lltable_free(struct lltable *llt)
37282f39c91SKip Macy {
37382f39c91SKip Macy 	struct llentry *lle, *next;
37411cdad98SAlexander V. Chernikov 	struct llentries dchain;
37582f39c91SKip Macy 
37682f39c91SKip Macy 	KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
37782f39c91SKip Macy 
378721cd2e0SAlexander V. Chernikov 	lltable_unlink(llt);
37982f39c91SKip Macy 
38011cdad98SAlexander V. Chernikov 	LIST_INIT(&dchain);
381ea537929SGleb Smirnoff 	IF_AFDATA_WLOCK(llt->llt_ifp);
38211cdad98SAlexander V. Chernikov 	/* Push all lles to @dchain */
38311cdad98SAlexander V. Chernikov 	lltable_foreach_lle(llt, lltable_free_cb, &dchain);
38411cdad98SAlexander V. Chernikov 	llentries_unlink(llt, &dchain);
38511cdad98SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
38611cdad98SAlexander V. Chernikov 
38711cdad98SAlexander V. Chernikov 	LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
3880447c136SAlexander V. Chernikov 		if (callout_stop(&lle->lle_timer))
389becba438SBjoern A. Zeeb 			LLE_REMREF(lle);
39082f39c91SKip Macy 		llentry_free(lle);
39182f39c91SKip Macy 	}
39282f39c91SKip Macy 
393721cd2e0SAlexander V. Chernikov 	llt->llt_free_tbl(llt);
39482f39c91SKip Macy }
39582f39c91SKip Macy 
396fc2bfb32SBjoern A. Zeeb #if 0
39782f39c91SKip Macy void
39882f39c91SKip Macy lltable_drain(int af)
39982f39c91SKip Macy {
40082f39c91SKip Macy 	struct lltable	*llt;
40182f39c91SKip Macy 	struct llentry	*lle;
40282f39c91SKip Macy 	register int i;
40382f39c91SKip Macy 
404dc56e98fSRobert Watson 	LLTABLE_RLOCK();
405989e0411SMarko Zec 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
40682f39c91SKip Macy 		if (llt->llt_af != af)
40782f39c91SKip Macy 			continue;
40882f39c91SKip Macy 
4093a749863SAlexander V. Chernikov 		for (i=0; i < llt->llt_hsize; i++) {
41082f39c91SKip Macy 			LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
411fc2bfb32SBjoern A. Zeeb 				LLE_WLOCK(lle);
41282f39c91SKip Macy 				if (lle->la_hold) {
41382f39c91SKip Macy 					m_freem(lle->la_hold);
41482f39c91SKip Macy 					lle->la_hold = NULL;
41582f39c91SKip Macy 				}
416fc2bfb32SBjoern A. Zeeb 				LLE_WUNLOCK(lle);
41782f39c91SKip Macy 			}
41882f39c91SKip Macy 		}
41982f39c91SKip Macy 	}
420dc56e98fSRobert Watson 	LLTABLE_RUNLOCK();
42182f39c91SKip Macy }
422fc2bfb32SBjoern A. Zeeb #endif
42382f39c91SKip Macy 
4243e7a2321SAlexander V. Chernikov /*
4253e7a2321SAlexander V. Chernikov  * Deletes an address from given lltable.
4263e7a2321SAlexander V. Chernikov  * Used for userland interaction to remove
4273e7a2321SAlexander V. Chernikov  * individual entries. Skips entries added by OS.
4283e7a2321SAlexander V. Chernikov  */
4293e7a2321SAlexander V. Chernikov int
4303e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags,
4313e7a2321SAlexander V. Chernikov     const struct sockaddr *l3addr)
4323e7a2321SAlexander V. Chernikov {
4333e7a2321SAlexander V. Chernikov 	struct llentry *lle;
4343e7a2321SAlexander V. Chernikov 	struct ifnet *ifp;
4353e7a2321SAlexander V. Chernikov 
4363e7a2321SAlexander V. Chernikov 	ifp = llt->llt_ifp;
4373e7a2321SAlexander V. Chernikov 	IF_AFDATA_WLOCK(ifp);
4383e7a2321SAlexander V. Chernikov 	lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr);
4393e7a2321SAlexander V. Chernikov 
4403e7a2321SAlexander V. Chernikov 	if (lle == NULL) {
4413e7a2321SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
4423e7a2321SAlexander V. Chernikov 		return (ENOENT);
4433e7a2321SAlexander V. Chernikov 	}
4443e7a2321SAlexander V. Chernikov 	if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
4453e7a2321SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
4463e7a2321SAlexander V. Chernikov 		LLE_WUNLOCK(lle);
4473e7a2321SAlexander V. Chernikov 		return (EPERM);
4483e7a2321SAlexander V. Chernikov 	}
4493e7a2321SAlexander V. Chernikov 
4503e7a2321SAlexander V. Chernikov 	lltable_unlink_entry(llt, lle);
4513e7a2321SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(ifp);
4523e7a2321SAlexander V. Chernikov 
4533e7a2321SAlexander V. Chernikov 	llt->llt_delete_entry(llt, lle);
4543e7a2321SAlexander V. Chernikov 
4553e7a2321SAlexander V. Chernikov 	return (0);
4563e7a2321SAlexander V. Chernikov }
4573e7a2321SAlexander V. Chernikov 
458c9d763bfSQing Li void
4593e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
4605b84dc78SQing Li     u_int flags)
461c9d763bfSQing Li {
462c9d763bfSQing Li 	struct lltable *llt;
463c9d763bfSQing Li 
464dc56e98fSRobert Watson 	LLTABLE_RLOCK();
465989e0411SMarko Zec 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
466c9d763bfSQing Li 		if (llt->llt_af != af)
467c9d763bfSQing Li 			continue;
468c9d763bfSQing Li 
4693e7a2321SAlexander V. Chernikov 		llt->llt_prefix_free(llt, addr, mask, flags);
470c9d763bfSQing Li 	}
471dc56e98fSRobert Watson 	LLTABLE_RUNLOCK();
472c9d763bfSQing Li }
473c9d763bfSQing Li 
47482f39c91SKip Macy struct lltable *
47541cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize)
47682f39c91SKip Macy {
47782f39c91SKip Macy 	struct lltable *llt;
47841cb42a6SAlexander V. Chernikov 	int i;
47982f39c91SKip Macy 
48041cb42a6SAlexander V. Chernikov 	llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
48141cb42a6SAlexander V. Chernikov 	llt->llt_hsize = hsize;
48241cb42a6SAlexander V. Chernikov 	llt->lle_head = malloc(sizeof(struct llentries) * hsize,
48341cb42a6SAlexander V. Chernikov 	    M_LLTABLE, M_WAITOK | M_ZERO);
48482f39c91SKip Macy 
48541cb42a6SAlexander V. Chernikov 	for (i = 0; i < llt->llt_hsize; i++)
48682f39c91SKip Macy 		LIST_INIT(&llt->lle_head[i]);
48782f39c91SKip Macy 
48811cdad98SAlexander V. Chernikov 	/* Set some default callbacks */
48911cdad98SAlexander V. Chernikov 	llt->llt_link_entry = htable_link_entry;
49011cdad98SAlexander V. Chernikov 	llt->llt_unlink_entry = htable_unlink_entry;
49111cdad98SAlexander V. Chernikov 	llt->llt_prefix_free = htable_prefix_free;
49211cdad98SAlexander V. Chernikov 	llt->llt_foreach_entry = htable_foreach_lle;
49341cb42a6SAlexander V. Chernikov 	llt->llt_free_tbl = htable_free_tbl;
49441cb42a6SAlexander V. Chernikov 
49541cb42a6SAlexander V. Chernikov 	return (llt);
49641cb42a6SAlexander V. Chernikov }
49741cb42a6SAlexander V. Chernikov 
49882f39c91SKip Macy /*
499721cd2e0SAlexander V. Chernikov  * Links lltable to global llt list.
50082f39c91SKip Macy  */
501721cd2e0SAlexander V. Chernikov void
502721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt)
50382f39c91SKip Macy {
50411cdad98SAlexander V. Chernikov 
505dc56e98fSRobert Watson 	LLTABLE_WLOCK();
506989e0411SMarko Zec 	SLIST_INSERT_HEAD(&V_lltables, llt, llt_link);
507dc56e98fSRobert Watson 	LLTABLE_WUNLOCK();
508721cd2e0SAlexander V. Chernikov }
50982f39c91SKip Macy 
510721cd2e0SAlexander V. Chernikov static void
511721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt)
512721cd2e0SAlexander V. Chernikov {
513721cd2e0SAlexander V. Chernikov 
514721cd2e0SAlexander V. Chernikov 	LLTABLE_WLOCK();
515721cd2e0SAlexander V. Chernikov 	SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
516721cd2e0SAlexander V. Chernikov 	LLTABLE_WUNLOCK();
517721cd2e0SAlexander V. Chernikov 
51882f39c91SKip Macy }
51982f39c91SKip Macy 
52082f39c91SKip Macy /*
52111cdad98SAlexander V. Chernikov  * External methods used by lltable consumers
52211cdad98SAlexander V. Chernikov  */
52311cdad98SAlexander V. Chernikov 
52411cdad98SAlexander V. Chernikov int
52511cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
52611cdad98SAlexander V. Chernikov {
52711cdad98SAlexander V. Chernikov 
52811cdad98SAlexander V. Chernikov 	return (llt->llt_foreach_entry(llt, f, farg));
52911cdad98SAlexander V. Chernikov }
53011cdad98SAlexander V. Chernikov 
5315a255516SAlexander V. Chernikov struct llentry *
5325a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags,
5335a255516SAlexander V. Chernikov     const struct sockaddr *l3addr)
5345a255516SAlexander V. Chernikov {
5355a255516SAlexander V. Chernikov 
5365a255516SAlexander V. Chernikov 	return (llt->llt_alloc_entry(llt, flags, l3addr));
5375a255516SAlexander V. Chernikov }
5385a255516SAlexander V. Chernikov 
5395a255516SAlexander V. Chernikov void
5405a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle)
5415a255516SAlexander V. Chernikov {
5425a255516SAlexander V. Chernikov 
5435a255516SAlexander V. Chernikov 	llt->llt_free_entry(llt, lle);
5445a255516SAlexander V. Chernikov }
5455a255516SAlexander V. Chernikov 
54611cdad98SAlexander V. Chernikov void
54711cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle)
54811cdad98SAlexander V. Chernikov {
54911cdad98SAlexander V. Chernikov 
55011cdad98SAlexander V. Chernikov 	llt->llt_link_entry(llt, lle);
55111cdad98SAlexander V. Chernikov }
55211cdad98SAlexander V. Chernikov 
55311cdad98SAlexander V. Chernikov void
55411cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
55511cdad98SAlexander V. Chernikov {
55611cdad98SAlexander V. Chernikov 
55711cdad98SAlexander V. Chernikov 	llt->llt_unlink_entry(lle);
55811cdad98SAlexander V. Chernikov }
55911cdad98SAlexander V. Chernikov 
56011cdad98SAlexander V. Chernikov void
56111cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
56211cdad98SAlexander V. Chernikov {
56311cdad98SAlexander V. Chernikov 	struct lltable *llt;
56411cdad98SAlexander V. Chernikov 
56511cdad98SAlexander V. Chernikov 	llt = lle->lle_tbl;
56611cdad98SAlexander V. Chernikov 	llt->llt_fill_sa_entry(lle, sa);
56711cdad98SAlexander V. Chernikov }
56811cdad98SAlexander V. Chernikov 
56911cdad98SAlexander V. Chernikov struct ifnet *
57011cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt)
57111cdad98SAlexander V. Chernikov {
57211cdad98SAlexander V. Chernikov 
57311cdad98SAlexander V. Chernikov 	return (llt->llt_ifp);
57411cdad98SAlexander V. Chernikov }
57511cdad98SAlexander V. Chernikov 
57611cdad98SAlexander V. Chernikov int
57711cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt)
57811cdad98SAlexander V. Chernikov {
57911cdad98SAlexander V. Chernikov 
58011cdad98SAlexander V. Chernikov 	return (llt->llt_af);
58111cdad98SAlexander V. Chernikov }
58211cdad98SAlexander V. Chernikov 
58311cdad98SAlexander V. Chernikov /*
584b4b1367aSAlexander V. Chernikov  * Called in route_output when rtm_flags contains RTF_LLDATA.
58582f39c91SKip Macy  */
58682f39c91SKip Macy int
58782f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
58882f39c91SKip Macy {
58982f39c91SKip Macy 	struct sockaddr_dl *dl =
59082f39c91SKip Macy 	    (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY];
59182f39c91SKip Macy 	struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
59282f39c91SKip Macy 	struct ifnet *ifp;
59382f39c91SKip Macy 	struct lltable *llt;
5945a255516SAlexander V. Chernikov 	struct llentry *lle, *lle_tmp;
595b4b1367aSAlexander V. Chernikov 	u_int laflags = 0;
596b4b1367aSAlexander V. Chernikov 	int error;
59782f39c91SKip Macy 
5981910bfcbSGleb Smirnoff 	KASSERT(dl != NULL && dl->sdl_family == AF_LINK,
5991910bfcbSGleb Smirnoff 	    ("%s: invalid dl\n", __func__));
6001910bfcbSGleb Smirnoff 
60182f39c91SKip Macy 	ifp = ifnet_byindex(dl->sdl_index);
60282f39c91SKip Macy 	if (ifp == NULL) {
60382f39c91SKip Macy 		log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
60482f39c91SKip Macy 		    __func__, dl->sdl_index);
60582f39c91SKip Macy 		return EINVAL;
60682f39c91SKip Macy 	}
60782f39c91SKip Macy 
60882f39c91SKip Macy 	/* XXX linked list may be too expensive */
609dc56e98fSRobert Watson 	LLTABLE_RLOCK();
610989e0411SMarko Zec 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
61182f39c91SKip Macy 		if (llt->llt_af == dst->sa_family &&
61282f39c91SKip Macy 		    llt->llt_ifp == ifp)
61382f39c91SKip Macy 			break;
61482f39c91SKip Macy 	}
615dc56e98fSRobert Watson 	LLTABLE_RUNLOCK();
61682f39c91SKip Macy 	KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n"));
61782f39c91SKip Macy 
618b4b1367aSAlexander V. Chernikov 	error = 0;
61982f39c91SKip Macy 
620b4b1367aSAlexander V. Chernikov 	switch (rtm->rtm_type) {
621b4b1367aSAlexander V. Chernikov 	case RTM_ADD:
622b4b1367aSAlexander V. Chernikov 		/* Add static LLE */
6233b0fd911SAlexander V. Chernikov 		laflags = 0;
6243b0fd911SAlexander V. Chernikov 		if (rtm->rtm_rmx.rmx_expire == 0)
6253b0fd911SAlexander V. Chernikov 			laflags = LLE_STATIC;
6263b0fd911SAlexander V. Chernikov 		lle = lltable_alloc_entry(llt, laflags, dst);
6275a255516SAlexander V. Chernikov 		if (lle == NULL)
628b4b1367aSAlexander V. Chernikov 			return (ENOMEM);
629b4b1367aSAlexander V. Chernikov 
63082f39c91SKip Macy 		bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen);
631b4b1367aSAlexander V. Chernikov 		if ((rtm->rtm_flags & RTF_ANNOUNCE))
632b4b1367aSAlexander V. Chernikov 			lle->la_flags |= LLE_PUB;
63382f39c91SKip Macy 		lle->la_flags |= LLE_VALID;
63482f39c91SKip Macy 		lle->la_expire = rtm->rtm_rmx.rmx_expire;
6353b0fd911SAlexander V. Chernikov 
63682f39c91SKip Macy 		laflags = lle->la_flags;
6375a255516SAlexander V. Chernikov 
6385a255516SAlexander V. Chernikov 		/* Try to link new entry */
6395a255516SAlexander V. Chernikov 		lle_tmp = NULL;
6405a255516SAlexander V. Chernikov 		IF_AFDATA_WLOCK(ifp);
6415a255516SAlexander V. Chernikov 		LLE_WLOCK(lle);
6425a255516SAlexander V. Chernikov 		lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst);
6435a255516SAlexander V. Chernikov 		if (lle_tmp != NULL) {
6445a255516SAlexander V. Chernikov 			/* Check if we are trying to replace immutable entry */
6455a255516SAlexander V. Chernikov 			if ((lle_tmp->la_flags & LLE_IFADDR) != 0) {
646b4b1367aSAlexander V. Chernikov 				IF_AFDATA_WUNLOCK(ifp);
6475a255516SAlexander V. Chernikov 				LLE_WUNLOCK(lle_tmp);
6485a255516SAlexander V. Chernikov 				lltable_free_entry(llt, lle);
6495a255516SAlexander V. Chernikov 				return (EPERM);
6505a255516SAlexander V. Chernikov 			}
6515a255516SAlexander V. Chernikov 			/* Unlink existing entry from table */
6525a255516SAlexander V. Chernikov 			lltable_unlink_entry(llt, lle_tmp);
6535a255516SAlexander V. Chernikov 		}
6545a255516SAlexander V. Chernikov 		lltable_link_entry(llt, lle);
6555a255516SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
6565a255516SAlexander V. Chernikov 
6575a255516SAlexander V. Chernikov 		if (lle_tmp != NULL) {
6585a255516SAlexander V. Chernikov 			EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED);
6595a255516SAlexander V. Chernikov 			lltable_free_entry(llt, lle_tmp);
6605a255516SAlexander V. Chernikov 		}
6615a255516SAlexander V. Chernikov 
6625a255516SAlexander V. Chernikov 		/*
6635a255516SAlexander V. Chernikov 		 * By invoking LLE handler here we might get
6645a255516SAlexander V. Chernikov 		 * two events on static LLE entry insertion
6655a255516SAlexander V. Chernikov 		 * in routing socket. However, since we might have
6665a255516SAlexander V. Chernikov 		 * other subscribers we need to generate this event.
6675a255516SAlexander V. Chernikov 		 */
6685a255516SAlexander V. Chernikov 		EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED);
6695a255516SAlexander V. Chernikov 		LLE_WUNLOCK(lle);
67082f39c91SKip Macy #ifdef INET
6717b4d716bSKip Macy 		/* gratuitous ARP */
6729711a168SGleb Smirnoff 		if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
67382f39c91SKip Macy 			arprequest(ifp,
67482f39c91SKip Macy 			    &((struct sockaddr_in *)dst)->sin_addr,
67582f39c91SKip Macy 			    &((struct sockaddr_in *)dst)->sin_addr,
6769711a168SGleb Smirnoff 			    (u_char *)LLADDR(dl));
67782f39c91SKip Macy #endif
67882f39c91SKip Macy 
679b4b1367aSAlexander V. Chernikov 		break;
680b4b1367aSAlexander V. Chernikov 
681b4b1367aSAlexander V. Chernikov 	case RTM_DELETE:
6823e7a2321SAlexander V. Chernikov 		return (lltable_delete_addr(llt, 0, dst));
683b4b1367aSAlexander V. Chernikov 
684b4b1367aSAlexander V. Chernikov 	default:
685b4b1367aSAlexander V. Chernikov 		error = EINVAL;
686b4b1367aSAlexander V. Chernikov 	}
68782f39c91SKip Macy 
68882f39c91SKip Macy 	return (error);
68982f39c91SKip Macy }
690989e0411SMarko Zec 
691989e0411SMarko Zec static void
692989e0411SMarko Zec vnet_lltable_init()
693989e0411SMarko Zec {
694989e0411SMarko Zec 
695989e0411SMarko Zec 	SLIST_INIT(&V_lltables);
696989e0411SMarko Zec }
69738d61195SMarko Zec VNET_SYSINIT(vnet_lltable_init, SI_SUB_PSEUDO, SI_ORDER_FIRST,
69838d61195SMarko Zec     vnet_lltable_init, NULL);
699989e0411SMarko Zec 
700335b943fSBjoern A. Zeeb #ifdef DDB
701335b943fSBjoern A. Zeeb struct llentry_sa {
702335b943fSBjoern A. Zeeb 	struct llentry		base;
703335b943fSBjoern A. Zeeb 	struct sockaddr		l3_addr;
704335b943fSBjoern A. Zeeb };
705335b943fSBjoern A. Zeeb 
706335b943fSBjoern A. Zeeb static void
707335b943fSBjoern A. Zeeb llatbl_lle_show(struct llentry_sa *la)
708335b943fSBjoern A. Zeeb {
709335b943fSBjoern A. Zeeb 	struct llentry *lle;
710335b943fSBjoern A. Zeeb 	uint8_t octet[6];
711335b943fSBjoern A. Zeeb 
712335b943fSBjoern A. Zeeb 	lle = &la->base;
713335b943fSBjoern A. Zeeb 	db_printf("lle=%p\n", lle);
714335b943fSBjoern A. Zeeb 	db_printf(" lle_next=%p\n", lle->lle_next.le_next);
715335b943fSBjoern A. Zeeb 	db_printf(" lle_lock=%p\n", &lle->lle_lock);
716335b943fSBjoern A. Zeeb 	db_printf(" lle_tbl=%p\n", lle->lle_tbl);
717335b943fSBjoern A. Zeeb 	db_printf(" lle_head=%p\n", lle->lle_head);
718335b943fSBjoern A. Zeeb 	db_printf(" la_hold=%p\n", lle->la_hold);
719e162ea60SGeorge V. Neville-Neil 	db_printf(" la_numheld=%d\n", lle->la_numheld);
720335b943fSBjoern A. Zeeb 	db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
721335b943fSBjoern A. Zeeb 	db_printf(" la_flags=0x%04x\n", lle->la_flags);
722335b943fSBjoern A. Zeeb 	db_printf(" la_asked=%u\n", lle->la_asked);
723335b943fSBjoern A. Zeeb 	db_printf(" la_preempt=%u\n", lle->la_preempt);
724335b943fSBjoern A. Zeeb 	db_printf(" ln_byhint=%u\n", lle->ln_byhint);
725335b943fSBjoern A. Zeeb 	db_printf(" ln_state=%d\n", lle->ln_state);
726335b943fSBjoern A. Zeeb 	db_printf(" ln_router=%u\n", lle->ln_router);
727335b943fSBjoern A. Zeeb 	db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
728335b943fSBjoern A. Zeeb 	db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
729335b943fSBjoern A. Zeeb 	bcopy(&lle->ll_addr.mac16, octet, sizeof(octet));
730335b943fSBjoern A. Zeeb 	db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
731335b943fSBjoern A. Zeeb 	    octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
7320447c136SAlexander V. Chernikov 	db_printf(" lle_timer=%p\n", &lle->lle_timer);
733335b943fSBjoern A. Zeeb 
734335b943fSBjoern A. Zeeb 	switch (la->l3_addr.sa_family) {
735335b943fSBjoern A. Zeeb #ifdef INET
736335b943fSBjoern A. Zeeb 	case AF_INET:
737335b943fSBjoern A. Zeeb 	{
738335b943fSBjoern A. Zeeb 		struct sockaddr_in *sin;
739335b943fSBjoern A. Zeeb 		char l3s[INET_ADDRSTRLEN];
740335b943fSBjoern A. Zeeb 
741335b943fSBjoern A. Zeeb 		sin = (struct sockaddr_in *)&la->l3_addr;
742335b943fSBjoern A. Zeeb 		inet_ntoa_r(sin->sin_addr, l3s);
743335b943fSBjoern A. Zeeb 		db_printf(" l3_addr=%s\n", l3s);
744335b943fSBjoern A. Zeeb 		break;
745335b943fSBjoern A. Zeeb 	}
746335b943fSBjoern A. Zeeb #endif
747335b943fSBjoern A. Zeeb #ifdef INET6
748335b943fSBjoern A. Zeeb 	case AF_INET6:
749335b943fSBjoern A. Zeeb 	{
750335b943fSBjoern A. Zeeb 		struct sockaddr_in6 *sin6;
751335b943fSBjoern A. Zeeb 		char l3s[INET6_ADDRSTRLEN];
752335b943fSBjoern A. Zeeb 
753335b943fSBjoern A. Zeeb 		sin6 = (struct sockaddr_in6 *)&la->l3_addr;
754335b943fSBjoern A. Zeeb 		ip6_sprintf(l3s, &sin6->sin6_addr);
755335b943fSBjoern A. Zeeb 		db_printf(" l3_addr=%s\n", l3s);
756335b943fSBjoern A. Zeeb 		break;
757335b943fSBjoern A. Zeeb 	}
758335b943fSBjoern A. Zeeb #endif
759335b943fSBjoern A. Zeeb 	default:
760335b943fSBjoern A. Zeeb 		db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family);
761335b943fSBjoern A. Zeeb 		break;
762335b943fSBjoern A. Zeeb 	}
763335b943fSBjoern A. Zeeb }
764335b943fSBjoern A. Zeeb 
765335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry)
766335b943fSBjoern A. Zeeb {
767335b943fSBjoern A. Zeeb 
768335b943fSBjoern A. Zeeb 	if (!have_addr) {
769335b943fSBjoern A. Zeeb 		db_printf("usage: show llentry <struct llentry *>\n");
770335b943fSBjoern A. Zeeb 		return;
771335b943fSBjoern A. Zeeb 	}
772335b943fSBjoern A. Zeeb 
773335b943fSBjoern A. Zeeb 	llatbl_lle_show((struct llentry_sa *)addr);
774335b943fSBjoern A. Zeeb }
775335b943fSBjoern A. Zeeb 
776335b943fSBjoern A. Zeeb static void
777335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt)
778335b943fSBjoern A. Zeeb {
779335b943fSBjoern A. Zeeb 	int i;
780335b943fSBjoern A. Zeeb 	struct llentry *lle;
781335b943fSBjoern A. Zeeb 
782335b943fSBjoern A. Zeeb 	db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
783335b943fSBjoern A. Zeeb 	    llt, llt->llt_af, llt->llt_ifp);
784335b943fSBjoern A. Zeeb 
7853a749863SAlexander V. Chernikov 	for (i = 0; i < llt->llt_hsize; i++) {
786335b943fSBjoern A. Zeeb 		LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
787335b943fSBjoern A. Zeeb 
788335b943fSBjoern A. Zeeb 			llatbl_lle_show((struct llentry_sa *)lle);
789335b943fSBjoern A. Zeeb 			if (db_pager_quit)
790335b943fSBjoern A. Zeeb 				return;
791335b943fSBjoern A. Zeeb 		}
792335b943fSBjoern A. Zeeb 	}
793335b943fSBjoern A. Zeeb }
794335b943fSBjoern A. Zeeb 
795335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable)
796335b943fSBjoern A. Zeeb {
797335b943fSBjoern A. Zeeb 
798335b943fSBjoern A. Zeeb 	if (!have_addr) {
799335b943fSBjoern A. Zeeb 		db_printf("usage: show lltable <struct lltable *>\n");
800335b943fSBjoern A. Zeeb 		return;
801335b943fSBjoern A. Zeeb 	}
802335b943fSBjoern A. Zeeb 
803335b943fSBjoern A. Zeeb 	llatbl_llt_show((struct lltable *)addr);
804335b943fSBjoern A. Zeeb }
805335b943fSBjoern A. Zeeb 
806335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
807335b943fSBjoern A. Zeeb {
808335b943fSBjoern A. Zeeb 	VNET_ITERATOR_DECL(vnet_iter);
809335b943fSBjoern A. Zeeb 	struct lltable *llt;
810335b943fSBjoern A. Zeeb 
811335b943fSBjoern A. Zeeb 	VNET_FOREACH(vnet_iter) {
812335b943fSBjoern A. Zeeb 		CURVNET_SET_QUIET(vnet_iter);
813335b943fSBjoern A. Zeeb #ifdef VIMAGE
814335b943fSBjoern A. Zeeb 		db_printf("vnet=%p\n", curvnet);
815335b943fSBjoern A. Zeeb #endif
816335b943fSBjoern A. Zeeb 		SLIST_FOREACH(llt, &V_lltables, llt_link) {
817335b943fSBjoern A. Zeeb 			db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
818335b943fSBjoern A. Zeeb 			    llt, llt->llt_af, llt->llt_ifp,
819335b943fSBjoern A. Zeeb 			    (llt->llt_ifp != NULL) ?
820335b943fSBjoern A. Zeeb 				llt->llt_ifp->if_xname : "?");
821335b943fSBjoern A. Zeeb 			if (have_addr && addr != 0) /* verbose */
822335b943fSBjoern A. Zeeb 				llatbl_llt_show(llt);
823335b943fSBjoern A. Zeeb 			if (db_pager_quit) {
824335b943fSBjoern A. Zeeb 				CURVNET_RESTORE();
825335b943fSBjoern A. Zeeb 				return;
826335b943fSBjoern A. Zeeb 			}
827335b943fSBjoern A. Zeeb 		}
828335b943fSBjoern A. Zeeb 		CURVNET_RESTORE();
829335b943fSBjoern A. Zeeb 	}
830335b943fSBjoern A. Zeeb }
831335b943fSBjoern A. Zeeb #endif
832