xref: /freebsd/sys/net/if_llatbl.c (revision 990a6d18b0cb1eee9e18a4220150d549b9bee753)
1fe267a55SPedro F. Giffuni /*-
2fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3fe267a55SPedro F. Giffuni  *
482f39c91SKip Macy  * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
582f39c91SKip Macy  * Copyright (c) 2004-2008 Qing Li. All rights reserved.
682f39c91SKip Macy  * Copyright (c) 2008 Kip Macy. All rights reserved.
782f39c91SKip Macy  *
882f39c91SKip Macy  * Redistribution and use in source and binary forms, with or without
982f39c91SKip Macy  * modification, are permitted provided that the following conditions
1082f39c91SKip Macy  * are met:
1182f39c91SKip Macy  * 1. Redistributions of source code must retain the above copyright
1282f39c91SKip Macy  *    notice, this list of conditions and the following disclaimer.
1382f39c91SKip Macy  * 2. Redistributions in binary form must reproduce the above copyright
1482f39c91SKip Macy  *    notice, this list of conditions and the following disclaimer in the
1582f39c91SKip Macy  *    documentation and/or other materials provided with the distribution.
1682f39c91SKip Macy  *
1782f39c91SKip Macy  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1882f39c91SKip Macy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1982f39c91SKip Macy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2082f39c91SKip Macy  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
2182f39c91SKip Macy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2282f39c91SKip Macy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2382f39c91SKip Macy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2482f39c91SKip Macy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2582f39c91SKip Macy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2682f39c91SKip Macy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2782f39c91SKip Macy  * SUCH DAMAGE.
2882f39c91SKip Macy  */
2982f39c91SKip Macy #include <sys/cdefs.h>
3082f39c91SKip Macy __FBSDID("$FreeBSD$");
3182f39c91SKip Macy 
32335b943fSBjoern A. Zeeb #include "opt_ddb.h"
3382f39c91SKip Macy #include "opt_inet.h"
3482f39c91SKip Macy #include "opt_inet6.h"
3582f39c91SKip Macy 
3682f39c91SKip Macy #include <sys/param.h>
3782f39c91SKip Macy #include <sys/systm.h>
38e2e050c8SConrad Meyer #include <sys/eventhandler.h>
3982f39c91SKip Macy #include <sys/malloc.h>
4082f39c91SKip Macy #include <sys/mbuf.h>
4182f39c91SKip Macy #include <sys/syslog.h>
4282f39c91SKip Macy #include <sys/sysctl.h>
4382f39c91SKip Macy #include <sys/socket.h>
4482f39c91SKip Macy #include <sys/kernel.h>
4582f39c91SKip Macy #include <sys/lock.h>
4682f39c91SKip Macy #include <sys/mutex.h>
4782f39c91SKip Macy #include <sys/rwlock.h>
4882f39c91SKip Macy 
49335b943fSBjoern A. Zeeb #ifdef DDB
50335b943fSBjoern A. Zeeb #include <ddb/ddb.h>
51335b943fSBjoern A. Zeeb #endif
52335b943fSBjoern A. Zeeb 
5382f39c91SKip Macy #include <vm/uma.h>
5482f39c91SKip Macy 
5582f39c91SKip Macy #include <netinet/in.h>
5682f39c91SKip Macy #include <net/if_llatbl.h>
5782f39c91SKip Macy #include <net/if.h>
5882f39c91SKip Macy #include <net/if_dl.h>
5982f39c91SKip Macy #include <net/if_var.h>
6082f39c91SKip Macy #include <net/route.h>
61da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h>
6263f7f392SAlexander V. Chernikov #include <net/route/route_debug.h>
63530c0060SRobert Watson #include <net/vnet.h>
6482f39c91SKip Macy #include <netinet/if_ether.h>
6582f39c91SKip Macy #include <netinet6/in6_var.h>
6682f39c91SKip Macy #include <netinet6/nd6.h>
6782f39c91SKip Macy 
6882f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
6982f39c91SKip Macy 
705f901c92SAndrew Turner VNET_DEFINE_STATIC(SLIST_HEAD(, lltable), lltables) =
7176d68eccSBjoern A. Zeeb     SLIST_HEAD_INITIALIZER(lltables);
72989e0411SMarko Zec #define	V_lltables	VNET(lltables)
7382f39c91SKip Macy 
74199511bcSAndrey V. Elsukov static struct rwlock lltable_list_lock;
75199511bcSAndrey V. Elsukov RW_SYSINIT(lltable_list_lock, &lltable_list_lock, "lltable_list_lock");
76199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_RLOCK()		rw_rlock(&lltable_list_lock)
77199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_RUNLOCK()		rw_runlock(&lltable_list_lock)
78199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_WLOCK()		rw_wlock(&lltable_list_lock)
79199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_WUNLOCK()		rw_wunlock(&lltable_list_lock)
80199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_LOCK_ASSERT()	rw_assert(&lltable_list_lock, RA_LOCKED)
81dc56e98fSRobert Watson 
82721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt);
8311cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head);
8411cdad98SAlexander V. Chernikov 
8511cdad98SAlexander V. Chernikov /*
8611cdad98SAlexander V. Chernikov  * Dump lle state for a specific address family.
8711cdad98SAlexander V. Chernikov  */
8811cdad98SAlexander V. Chernikov static int
8911cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
9011cdad98SAlexander V. Chernikov {
91a68cc388SGleb Smirnoff 	struct epoch_tracker et;
9211cdad98SAlexander V. Chernikov 	int error;
9311cdad98SAlexander V. Chernikov 
94199511bcSAndrey V. Elsukov 	LLTABLE_LIST_LOCK_ASSERT();
9511cdad98SAlexander V. Chernikov 
9611cdad98SAlexander V. Chernikov 	if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
9711cdad98SAlexander V. Chernikov 		return (0);
9811cdad98SAlexander V. Chernikov 	error = 0;
9911cdad98SAlexander V. Chernikov 
100a68cc388SGleb Smirnoff 	NET_EPOCH_ENTER(et);
10111cdad98SAlexander V. Chernikov 	error = lltable_foreach_lle(llt,
10211cdad98SAlexander V. Chernikov 	    (llt_foreach_cb_t *)llt->llt_dump_entry, wr);
103a68cc388SGleb Smirnoff 	NET_EPOCH_EXIT(et);
10411cdad98SAlexander V. Chernikov 
10511cdad98SAlexander V. Chernikov 	return (error);
10611cdad98SAlexander V. Chernikov }
10711cdad98SAlexander V. Chernikov 
10882f39c91SKip Macy /*
10982f39c91SKip Macy  * Dump arp state for a specific address family.
11082f39c91SKip Macy  */
11182f39c91SKip Macy int
11282f39c91SKip Macy lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
11382f39c91SKip Macy {
11482f39c91SKip Macy 	struct lltable *llt;
11582f39c91SKip Macy 	int error = 0;
11682f39c91SKip Macy 
117199511bcSAndrey V. Elsukov 	LLTABLE_LIST_RLOCK();
118989e0411SMarko Zec 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
11982f39c91SKip Macy 		if (llt->llt_af == af) {
12011cdad98SAlexander V. Chernikov 			error = lltable_dump_af(llt, wr);
12182f39c91SKip Macy 			if (error != 0)
12282f39c91SKip Macy 				goto done;
12382f39c91SKip Macy 		}
12482f39c91SKip Macy 	}
12582f39c91SKip Macy done:
126199511bcSAndrey V. Elsukov 	LLTABLE_LIST_RUNLOCK();
12782f39c91SKip Macy 	return (error);
12882f39c91SKip Macy }
12982f39c91SKip Macy 
13082f39c91SKip Macy /*
13111cdad98SAlexander V. Chernikov  * Common function helpers for chained hash table.
13211cdad98SAlexander V. Chernikov  */
13311cdad98SAlexander V. Chernikov 
13411cdad98SAlexander V. Chernikov /*
13511cdad98SAlexander V. Chernikov  * Runs specified callback for each entry in @llt.
13611cdad98SAlexander V. Chernikov  * Caller does the locking.
13711cdad98SAlexander V. Chernikov  *
13811cdad98SAlexander V. Chernikov  */
13911cdad98SAlexander V. Chernikov static int
14011cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
14111cdad98SAlexander V. Chernikov {
14211cdad98SAlexander V. Chernikov 	struct llentry *lle, *next;
14311cdad98SAlexander V. Chernikov 	int i, error;
14411cdad98SAlexander V. Chernikov 
14511cdad98SAlexander V. Chernikov 	error = 0;
14611cdad98SAlexander V. Chernikov 
14741cb42a6SAlexander V. Chernikov 	for (i = 0; i < llt->llt_hsize; i++) {
1484f6c66ccSMatt Macy 		CK_LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
14911cdad98SAlexander V. Chernikov 			error = f(llt, lle, farg);
15011cdad98SAlexander V. Chernikov 			if (error != 0)
15111cdad98SAlexander V. Chernikov 				break;
15211cdad98SAlexander V. Chernikov 		}
15311cdad98SAlexander V. Chernikov 	}
15411cdad98SAlexander V. Chernikov 
15511cdad98SAlexander V. Chernikov 	return (error);
15611cdad98SAlexander V. Chernikov }
15711cdad98SAlexander V. Chernikov 
1583818c25aSBjoern A. Zeeb /*
1593818c25aSBjoern A. Zeeb  * The htable_[un]link_entry() functions return:
1603818c25aSBjoern A. Zeeb  * 0 if the entry was (un)linked already and nothing changed,
1613818c25aSBjoern A. Zeeb  * 1 if the entry was added/removed to/from the table, and
1623818c25aSBjoern A. Zeeb  * -1 on error (e.g., not being able to add the entry due to limits reached).
1633818c25aSBjoern A. Zeeb  * While the "unlink" operation should never error, callers of
1643818c25aSBjoern A. Zeeb  * lltable_link_entry() need to check for errors and handle them.
1653818c25aSBjoern A. Zeeb  */
1663818c25aSBjoern A. Zeeb static int
16711cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle)
16811cdad98SAlexander V. Chernikov {
16911cdad98SAlexander V. Chernikov 	struct llentries *lleh;
17011cdad98SAlexander V. Chernikov 	uint32_t hashidx;
17111cdad98SAlexander V. Chernikov 
17211cdad98SAlexander V. Chernikov 	if ((lle->la_flags & LLE_LINKED) != 0)
1733818c25aSBjoern A. Zeeb 		return (0);
17411cdad98SAlexander V. Chernikov 
17511cdad98SAlexander V. Chernikov 	IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
17611cdad98SAlexander V. Chernikov 
1773818c25aSBjoern A. Zeeb 	if (llt->llt_maxentries > 0 &&
1783818c25aSBjoern A. Zeeb 	    llt->llt_entries >= llt->llt_maxentries)
1793818c25aSBjoern A. Zeeb 		return (-1);
1803818c25aSBjoern A. Zeeb 
1813a749863SAlexander V. Chernikov 	hashidx = llt->llt_hash(lle, llt->llt_hsize);
18211cdad98SAlexander V. Chernikov 	lleh = &llt->lle_head[hashidx];
18311cdad98SAlexander V. Chernikov 
18411cdad98SAlexander V. Chernikov 	lle->lle_tbl  = llt;
18511cdad98SAlexander V. Chernikov 	lle->lle_head = lleh;
18611cdad98SAlexander V. Chernikov 	lle->la_flags |= LLE_LINKED;
1874f6c66ccSMatt Macy 	CK_LIST_INSERT_HEAD(lleh, lle, lle_next);
1883818c25aSBjoern A. Zeeb 	llt->llt_entries++;
1893818c25aSBjoern A. Zeeb 
1903818c25aSBjoern A. Zeeb 	return (1);
19111cdad98SAlexander V. Chernikov }
19211cdad98SAlexander V. Chernikov 
1933818c25aSBjoern A. Zeeb static int
19411cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle)
19511cdad98SAlexander V. Chernikov {
1963818c25aSBjoern A. Zeeb 	struct lltable *llt;
19711cdad98SAlexander V. Chernikov 
198d9a61c96SBjoern A. Zeeb 	if ((lle->la_flags & LLE_LINKED) == 0)
1993818c25aSBjoern A. Zeeb 		return (0);
200d9a61c96SBjoern A. Zeeb 
2013818c25aSBjoern A. Zeeb 	llt = lle->lle_tbl;
2023818c25aSBjoern A. Zeeb 	IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
2033818c25aSBjoern A. Zeeb 	KASSERT(llt->llt_entries > 0, ("%s: lltable %p (%s) entries %d <= 0",
2043818c25aSBjoern A. Zeeb 	    __func__, llt, if_name(llt->llt_ifp), llt->llt_entries));
2053818c25aSBjoern A. Zeeb 
2064f6c66ccSMatt Macy 	CK_LIST_REMOVE(lle, lle_next);
20711cdad98SAlexander V. Chernikov 	lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
20811cdad98SAlexander V. Chernikov #if 0
20911cdad98SAlexander V. Chernikov 	lle->lle_tbl = NULL;
21011cdad98SAlexander V. Chernikov 	lle->lle_head = NULL;
21111cdad98SAlexander V. Chernikov #endif
2123818c25aSBjoern A. Zeeb 	llt->llt_entries--;
2133818c25aSBjoern A. Zeeb 
2143818c25aSBjoern A. Zeeb 	return (1);
21511cdad98SAlexander V. Chernikov }
21611cdad98SAlexander V. Chernikov 
21711cdad98SAlexander V. Chernikov struct prefix_match_data {
2183e7a2321SAlexander V. Chernikov 	const struct sockaddr *addr;
21911cdad98SAlexander V. Chernikov 	const struct sockaddr *mask;
22011cdad98SAlexander V. Chernikov 	struct llentries dchain;
22111cdad98SAlexander V. Chernikov 	u_int flags;
22211cdad98SAlexander V. Chernikov };
22311cdad98SAlexander V. Chernikov 
22411cdad98SAlexander V. Chernikov static int
22511cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
22611cdad98SAlexander V. Chernikov {
22711cdad98SAlexander V. Chernikov 	struct prefix_match_data *pmd;
22811cdad98SAlexander V. Chernikov 
22911cdad98SAlexander V. Chernikov 	pmd = (struct prefix_match_data *)farg;
23011cdad98SAlexander V. Chernikov 
2313e7a2321SAlexander V. Chernikov 	if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
23211cdad98SAlexander V. Chernikov 		LLE_WLOCK(lle);
2330f8d79d9SMatt Macy 		CK_LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
23411cdad98SAlexander V. Chernikov 	}
23511cdad98SAlexander V. Chernikov 
23611cdad98SAlexander V. Chernikov 	return (0);
23711cdad98SAlexander V. Chernikov }
23811cdad98SAlexander V. Chernikov 
23911cdad98SAlexander V. Chernikov static void
2403e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
24111cdad98SAlexander V. Chernikov     const struct sockaddr *mask, u_int flags)
24211cdad98SAlexander V. Chernikov {
24311cdad98SAlexander V. Chernikov 	struct llentry *lle, *next;
24411cdad98SAlexander V. Chernikov 	struct prefix_match_data pmd;
24511cdad98SAlexander V. Chernikov 
24611cdad98SAlexander V. Chernikov 	bzero(&pmd, sizeof(pmd));
2473e7a2321SAlexander V. Chernikov 	pmd.addr = addr;
24811cdad98SAlexander V. Chernikov 	pmd.mask = mask;
24911cdad98SAlexander V. Chernikov 	pmd.flags = flags;
2504f6c66ccSMatt Macy 	CK_LIST_INIT(&pmd.dchain);
25111cdad98SAlexander V. Chernikov 
25211cdad98SAlexander V. Chernikov 	IF_AFDATA_WLOCK(llt->llt_ifp);
25311cdad98SAlexander V. Chernikov 	/* Push matching lles to chain */
25411cdad98SAlexander V. Chernikov 	lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
25511cdad98SAlexander V. Chernikov 
25611cdad98SAlexander V. Chernikov 	llentries_unlink(llt, &pmd.dchain);
25711cdad98SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
25811cdad98SAlexander V. Chernikov 
2590f8d79d9SMatt Macy 	CK_LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
2605a255516SAlexander V. Chernikov 		lltable_free_entry(llt, lle);
26111cdad98SAlexander V. Chernikov }
26211cdad98SAlexander V. Chernikov 
26311cdad98SAlexander V. Chernikov static void
26441cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt)
26541cb42a6SAlexander V. Chernikov {
26641cb42a6SAlexander V. Chernikov 
26741cb42a6SAlexander V. Chernikov 	free(llt->lle_head, M_LLTABLE);
26841cb42a6SAlexander V. Chernikov 	free(llt, M_LLTABLE);
26941cb42a6SAlexander V. Chernikov }
27041cb42a6SAlexander V. Chernikov 
271721cd2e0SAlexander V. Chernikov static void
27211cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head)
27311cdad98SAlexander V. Chernikov {
27411cdad98SAlexander V. Chernikov 	struct llentry *lle, *next;
27511cdad98SAlexander V. Chernikov 
2760f8d79d9SMatt Macy 	CK_LIST_FOREACH_SAFE(lle, head, lle_chain, next)
27711cdad98SAlexander V. Chernikov 		llt->llt_unlink_entry(lle);
27811cdad98SAlexander V. Chernikov }
27911cdad98SAlexander V. Chernikov 
28011cdad98SAlexander V. Chernikov /*
28111cdad98SAlexander V. Chernikov  * Helper function used to drop all mbufs in hold queue.
282e162ea60SGeorge V. Neville-Neil  *
283e162ea60SGeorge V. Neville-Neil  * Returns the number of held packets, if any, that were dropped.
28482f39c91SKip Macy  */
285e162ea60SGeorge V. Neville-Neil size_t
28611cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle)
28782f39c91SKip Macy {
288e162ea60SGeorge V. Neville-Neil 	size_t pkts_dropped;
289e162ea60SGeorge V. Neville-Neil 	struct mbuf *next;
29082f39c91SKip Macy 
29182f39c91SKip Macy 	LLE_WLOCK_ASSERT(lle);
29282f39c91SKip Macy 
293ea537929SGleb Smirnoff 	pkts_dropped = 0;
294e162ea60SGeorge V. Neville-Neil 	while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
295e162ea60SGeorge V. Neville-Neil 		next = lle->la_hold->m_nextpkt;
29682f39c91SKip Macy 		m_freem(lle->la_hold);
297e162ea60SGeorge V. Neville-Neil 		lle->la_hold = next;
298e162ea60SGeorge V. Neville-Neil 		lle->la_numheld--;
299e162ea60SGeorge V. Neville-Neil 		pkts_dropped++;
300e162ea60SGeorge V. Neville-Neil 	}
301e162ea60SGeorge V. Neville-Neil 
302e162ea60SGeorge V. Neville-Neil 	KASSERT(lle->la_numheld == 0,
3037b3b099eSKonstantin Belousov 		("%s: la_numheld %d > 0, pkts_droped %zd", __func__,
304e162ea60SGeorge V. Neville-Neil 		 lle->la_numheld, pkts_dropped));
30582f39c91SKip Macy 
30611cdad98SAlexander V. Chernikov 	return (pkts_dropped);
30711cdad98SAlexander V. Chernikov }
30811cdad98SAlexander V. Chernikov 
309ddd208f7SAlexander V. Chernikov void
310ddd208f7SAlexander V. Chernikov lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
3114fb3a820SAlexander V. Chernikov     const char *linkhdr, size_t linkhdrsize, int lladdr_off)
312ddd208f7SAlexander V. Chernikov {
313ddd208f7SAlexander V. Chernikov 
3144fb3a820SAlexander V. Chernikov 	memcpy(lle->r_linkdata, linkhdr, linkhdrsize);
3154fb3a820SAlexander V. Chernikov 	lle->r_hdrlen = linkhdrsize;
3164fb3a820SAlexander V. Chernikov 	lle->ll_addr = &lle->r_linkdata[lladdr_off];
317ddd208f7SAlexander V. Chernikov 	lle->la_flags |= LLE_VALID;
318f8aee88fSAlexander V. Chernikov 	lle->r_flags |= RLLE_VALID;
319ddd208f7SAlexander V. Chernikov }
320ddd208f7SAlexander V. Chernikov 
32111cdad98SAlexander V. Chernikov /*
3220b79b007SAlexander V. Chernikov  * Acquires lltable write lock.
3230b79b007SAlexander V. Chernikov  *
3240b79b007SAlexander V. Chernikov  * Returns true on success, with both lltable and lle lock held.
3250b79b007SAlexander V. Chernikov  * On failure, false is returned and lle wlock is still held.
3260b79b007SAlexander V. Chernikov  */
3270b79b007SAlexander V. Chernikov bool
3280b79b007SAlexander V. Chernikov lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle)
3290b79b007SAlexander V. Chernikov {
3300b79b007SAlexander V. Chernikov 	NET_EPOCH_ASSERT();
3310b79b007SAlexander V. Chernikov 
3320b79b007SAlexander V. Chernikov 	/* Perform real LLE update */
3330b79b007SAlexander V. Chernikov 	/* use afdata WLOCK to update fields */
3340b79b007SAlexander V. Chernikov 	LLE_WUNLOCK(lle);
3350b79b007SAlexander V. Chernikov 	IF_AFDATA_WLOCK(ifp);
3360b79b007SAlexander V. Chernikov 	LLE_WLOCK(lle);
3370b79b007SAlexander V. Chernikov 
3380b79b007SAlexander V. Chernikov 	/*
3390b79b007SAlexander V. Chernikov 	 * Since we droppped LLE lock, other thread might have deleted
3400b79b007SAlexander V. Chernikov 	 * this lle. Check and return
3410b79b007SAlexander V. Chernikov 	 */
3420b79b007SAlexander V. Chernikov 	if ((lle->la_flags & LLE_DELETED) != 0) {
3430b79b007SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
3440b79b007SAlexander V. Chernikov 		return (false);
3450b79b007SAlexander V. Chernikov 	}
3460b79b007SAlexander V. Chernikov 
3470b79b007SAlexander V. Chernikov 	return (true);
3480b79b007SAlexander V. Chernikov }
3490b79b007SAlexander V. Chernikov 
3500b79b007SAlexander V. Chernikov /*
35112cb7521SAlexander V. Chernikov  * Tries to update @lle link-level address.
35212cb7521SAlexander V. Chernikov  * Since update requires AFDATA WLOCK, function
35312cb7521SAlexander V. Chernikov  * drops @lle lock, acquires AFDATA lock and then acquires
35412cb7521SAlexander V. Chernikov  * @lle lock to maintain lock order.
35512cb7521SAlexander V. Chernikov  *
35612cb7521SAlexander V. Chernikov  * Returns 1 on success.
35712cb7521SAlexander V. Chernikov  */
35812cb7521SAlexander V. Chernikov int
35912cb7521SAlexander V. Chernikov lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
3604fb3a820SAlexander V. Chernikov     const char *linkhdr, size_t linkhdrsize, int lladdr_off)
36112cb7521SAlexander V. Chernikov {
36212cb7521SAlexander V. Chernikov 
3630b79b007SAlexander V. Chernikov 	if (!lltable_acquire_wlock(ifp, lle))
36412cb7521SAlexander V. Chernikov 		return (0);
36512cb7521SAlexander V. Chernikov 
36612cb7521SAlexander V. Chernikov 	/* Update data */
3674fb3a820SAlexander V. Chernikov 	lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off);
36812cb7521SAlexander V. Chernikov 
36912cb7521SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(ifp);
37012cb7521SAlexander V. Chernikov 
37112cb7521SAlexander V. Chernikov 	return (1);
37212cb7521SAlexander V. Chernikov }
37312cb7521SAlexander V. Chernikov 
37412cb7521SAlexander V. Chernikov  /*
3754fb3a820SAlexander V. Chernikov  * Helper function used to pre-compute full/partial link-layer
3764fb3a820SAlexander V. Chernikov  * header data suitable for feeding into if_output().
3774fb3a820SAlexander V. Chernikov  */
3784fb3a820SAlexander V. Chernikov int
3794fb3a820SAlexander V. Chernikov lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr,
3804fb3a820SAlexander V. Chernikov     char *buf, size_t *bufsize, int *lladdr_off)
3814fb3a820SAlexander V. Chernikov {
3824fb3a820SAlexander V. Chernikov 	struct if_encap_req ereq;
3834fb3a820SAlexander V. Chernikov 	int error;
3844fb3a820SAlexander V. Chernikov 
3854fb3a820SAlexander V. Chernikov 	bzero(buf, *bufsize);
3864fb3a820SAlexander V. Chernikov 	bzero(&ereq, sizeof(ereq));
3874fb3a820SAlexander V. Chernikov 	ereq.buf = buf;
3884fb3a820SAlexander V. Chernikov 	ereq.bufsize = *bufsize;
3894fb3a820SAlexander V. Chernikov 	ereq.rtype = IFENCAP_LL;
3904fb3a820SAlexander V. Chernikov 	ereq.family = family;
3914fb3a820SAlexander V. Chernikov 	ereq.lladdr = lladdr;
3924fb3a820SAlexander V. Chernikov 	ereq.lladdr_len = ifp->if_addrlen;
3934fb3a820SAlexander V. Chernikov 	error = ifp->if_requestencap(ifp, &ereq);
3944fb3a820SAlexander V. Chernikov 	if (error == 0) {
3954fb3a820SAlexander V. Chernikov 		*bufsize = ereq.bufsize;
3964fb3a820SAlexander V. Chernikov 		*lladdr_off = ereq.lladdr_off;
3974fb3a820SAlexander V. Chernikov 	}
3984fb3a820SAlexander V. Chernikov 
3994fb3a820SAlexander V. Chernikov 	return (error);
4004fb3a820SAlexander V. Chernikov }
4014fb3a820SAlexander V. Chernikov 
4024fb3a820SAlexander V. Chernikov /*
403c541bd36SAlexander V. Chernikov  * Searches for the child entry matching @family inside @lle.
404c541bd36SAlexander V. Chernikov  * Returns the entry or NULL.
405c541bd36SAlexander V. Chernikov  */
406c541bd36SAlexander V. Chernikov struct llentry *
407c541bd36SAlexander V. Chernikov llentry_lookup_family(struct llentry *lle, int family)
408c541bd36SAlexander V. Chernikov {
409c541bd36SAlexander V. Chernikov 	struct llentry *child_lle;
410c541bd36SAlexander V. Chernikov 
411c541bd36SAlexander V. Chernikov 	if (lle == NULL)
412c541bd36SAlexander V. Chernikov 		return (NULL);
413c541bd36SAlexander V. Chernikov 
414c541bd36SAlexander V. Chernikov 	CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) {
415c541bd36SAlexander V. Chernikov 		if (child_lle->r_family == family)
416c541bd36SAlexander V. Chernikov 			return (child_lle);
417c541bd36SAlexander V. Chernikov 	}
418c541bd36SAlexander V. Chernikov 
419c541bd36SAlexander V. Chernikov 	return (NULL);
420c541bd36SAlexander V. Chernikov }
421c541bd36SAlexander V. Chernikov 
422c541bd36SAlexander V. Chernikov /*
42363f7f392SAlexander V. Chernikov  * Retrieves upper protocol family for the llentry.
42463f7f392SAlexander V. Chernikov  * By default, all "normal" (e.g. upper_family == transport_family)
42563f7f392SAlexander V. Chernikov  * llentries have r_family set to 0.
42663f7f392SAlexander V. Chernikov  * Thus, use @default_family in that regard, otherwise use r_family.
42763f7f392SAlexander V. Chernikov  *
42863f7f392SAlexander V. Chernikov  * Returns upper protocol family
42963f7f392SAlexander V. Chernikov  */
43063f7f392SAlexander V. Chernikov int
43163f7f392SAlexander V. Chernikov llentry_get_upper_family(const struct llentry *lle, int default_family)
43263f7f392SAlexander V. Chernikov {
43363f7f392SAlexander V. Chernikov 	return (lle->r_family == 0 ? default_family : lle->r_family);
43463f7f392SAlexander V. Chernikov }
43563f7f392SAlexander V. Chernikov 
43663f7f392SAlexander V. Chernikov /*
43763f7f392SAlexander V. Chernikov  * Prints llentry @lle data into provided buffer.
43863f7f392SAlexander V. Chernikov  * Example: lle/inet/valid/em0/1.2.3.4
43963f7f392SAlexander V. Chernikov  *
44063f7f392SAlexander V. Chernikov  * Returns @buf.
44163f7f392SAlexander V. Chernikov  */
44263f7f392SAlexander V. Chernikov char *
44363f7f392SAlexander V. Chernikov llentry_print_buf(const struct llentry *lle, struct ifnet *ifp, int family,
44463f7f392SAlexander V. Chernikov     char *buf, size_t bufsize)
44563f7f392SAlexander V. Chernikov {
446a6668e31SEd Maste #if defined(INET) || defined(INET6)
44763f7f392SAlexander V. Chernikov 	char abuf[INET6_ADDRSTRLEN];
448a6668e31SEd Maste #endif
44963f7f392SAlexander V. Chernikov 
45063f7f392SAlexander V. Chernikov 	const char *valid = (lle->r_flags & RLLE_VALID) ? "valid" : "no_l2";
45163f7f392SAlexander V. Chernikov 	const char *upper_str = rib_print_family(llentry_get_upper_family(lle, family));
45263f7f392SAlexander V. Chernikov 
45363f7f392SAlexander V. Chernikov 	switch (family) {
45463f7f392SAlexander V. Chernikov #ifdef INET
45563f7f392SAlexander V. Chernikov 	case AF_INET:
45663f7f392SAlexander V. Chernikov 		inet_ntop(AF_INET, &lle->r_l3addr.addr4, abuf, sizeof(abuf));
45763f7f392SAlexander V. Chernikov 		snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str,
45863f7f392SAlexander V. Chernikov 		    valid, if_name(ifp), abuf);
45963f7f392SAlexander V. Chernikov 		break;
46063f7f392SAlexander V. Chernikov #endif
46163f7f392SAlexander V. Chernikov #ifdef INET6
46263f7f392SAlexander V. Chernikov 	case AF_INET6:
46363f7f392SAlexander V. Chernikov 		inet_ntop(AF_INET6, &lle->r_l3addr.addr6, abuf, sizeof(abuf));
46463f7f392SAlexander V. Chernikov 		snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str,
46563f7f392SAlexander V. Chernikov 		    valid, if_name(ifp), abuf);
46663f7f392SAlexander V. Chernikov 		break;
46763f7f392SAlexander V. Chernikov #endif
46863f7f392SAlexander V. Chernikov 	default:
46963f7f392SAlexander V. Chernikov 		snprintf(buf, bufsize, "lle/%s/%s/%s/????", upper_str,
47063f7f392SAlexander V. Chernikov 		    valid, if_name(ifp));
47163f7f392SAlexander V. Chernikov 		break;
47263f7f392SAlexander V. Chernikov 	}
47363f7f392SAlexander V. Chernikov 
47463f7f392SAlexander V. Chernikov 	return (buf);
47563f7f392SAlexander V. Chernikov }
47663f7f392SAlexander V. Chernikov 
47763f7f392SAlexander V. Chernikov char *
47863f7f392SAlexander V. Chernikov llentry_print_buf_lltable(const struct llentry *lle, char *buf, size_t bufsize)
47963f7f392SAlexander V. Chernikov {
48063f7f392SAlexander V. Chernikov 	struct lltable *tbl = lle->lle_tbl;
48163f7f392SAlexander V. Chernikov 
48263f7f392SAlexander V. Chernikov 	return (llentry_print_buf(lle, lltable_get_ifp(tbl), lltable_get_af(tbl), buf, bufsize));
48363f7f392SAlexander V. Chernikov }
48463f7f392SAlexander V. Chernikov 
48563f7f392SAlexander V. Chernikov /*
486f3a3b061SAlexander V. Chernikov  * Requests feedback from the datapath.
487f3a3b061SAlexander V. Chernikov  * First packet using @lle should result in
488f3a3b061SAlexander V. Chernikov  * setting r_skip_req back to 0 and updating
489f3a3b061SAlexander V. Chernikov  * lle_hittime to the current time_uptime.
490f3a3b061SAlexander V. Chernikov  */
491f3a3b061SAlexander V. Chernikov void
492f3a3b061SAlexander V. Chernikov llentry_request_feedback(struct llentry *lle)
493f3a3b061SAlexander V. Chernikov {
494c541bd36SAlexander V. Chernikov 	struct llentry *child_lle;
495c541bd36SAlexander V. Chernikov 
496f3a3b061SAlexander V. Chernikov 	LLE_REQ_LOCK(lle);
497f3a3b061SAlexander V. Chernikov 	lle->r_skip_req = 1;
498f3a3b061SAlexander V. Chernikov 	LLE_REQ_UNLOCK(lle);
499c541bd36SAlexander V. Chernikov 
500c541bd36SAlexander V. Chernikov 	CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) {
501c541bd36SAlexander V. Chernikov 		LLE_REQ_LOCK(child_lle);
502c541bd36SAlexander V. Chernikov 		child_lle->r_skip_req = 1;
503c541bd36SAlexander V. Chernikov 		LLE_REQ_UNLOCK(child_lle);
504c541bd36SAlexander V. Chernikov 	}
505f3a3b061SAlexander V. Chernikov }
506f3a3b061SAlexander V. Chernikov 
507f3a3b061SAlexander V. Chernikov /*
508f3a3b061SAlexander V. Chernikov  * Updates the lle state to mark it has been used
509f3a3b061SAlexander V. Chernikov  * and record the time.
510f3a3b061SAlexander V. Chernikov  * Used by the llentry_provide_feedback() wrapper.
511f3a3b061SAlexander V. Chernikov  */
512f3a3b061SAlexander V. Chernikov void
513f3a3b061SAlexander V. Chernikov llentry_mark_used(struct llentry *lle)
514f3a3b061SAlexander V. Chernikov {
515f3a3b061SAlexander V. Chernikov 	LLE_REQ_LOCK(lle);
516f3a3b061SAlexander V. Chernikov 	lle->r_skip_req = 0;
517f3a3b061SAlexander V. Chernikov 	lle->lle_hittime = time_uptime;
518f3a3b061SAlexander V. Chernikov 	LLE_REQ_UNLOCK(lle);
519f3a3b061SAlexander V. Chernikov }
520f3a3b061SAlexander V. Chernikov 
521f3a3b061SAlexander V. Chernikov /*
522f3a3b061SAlexander V. Chernikov  * Fetches the time when lle was used.
523f3a3b061SAlexander V. Chernikov  * Return 0 if the entry was not used, relevant time_uptime
524f3a3b061SAlexander V. Chernikov  *  otherwise.
525f3a3b061SAlexander V. Chernikov  */
526c541bd36SAlexander V. Chernikov static time_t
527c541bd36SAlexander V. Chernikov llentry_get_hittime_raw(struct llentry *lle)
528f3a3b061SAlexander V. Chernikov {
529f3a3b061SAlexander V. Chernikov 	time_t lle_hittime = 0;
530f3a3b061SAlexander V. Chernikov 
531f3a3b061SAlexander V. Chernikov 	LLE_REQ_LOCK(lle);
532f3a3b061SAlexander V. Chernikov 	if ((lle->r_skip_req == 0) && (lle_hittime < lle->lle_hittime))
533f3a3b061SAlexander V. Chernikov 		lle_hittime = lle->lle_hittime;
534f3a3b061SAlexander V. Chernikov 	LLE_REQ_UNLOCK(lle);
535f3a3b061SAlexander V. Chernikov 
536f3a3b061SAlexander V. Chernikov 	return (lle_hittime);
537f3a3b061SAlexander V. Chernikov }
538f3a3b061SAlexander V. Chernikov 
539c541bd36SAlexander V. Chernikov time_t
540c541bd36SAlexander V. Chernikov llentry_get_hittime(struct llentry *lle)
541c541bd36SAlexander V. Chernikov {
542c541bd36SAlexander V. Chernikov 	time_t lle_hittime = 0;
543c541bd36SAlexander V. Chernikov 	struct llentry *child_lle;
544c541bd36SAlexander V. Chernikov 
545c541bd36SAlexander V. Chernikov 	lle_hittime = llentry_get_hittime_raw(lle);
546c541bd36SAlexander V. Chernikov 
547c541bd36SAlexander V. Chernikov 	CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) {
548c541bd36SAlexander V. Chernikov 		time_t hittime = llentry_get_hittime_raw(child_lle);
549c541bd36SAlexander V. Chernikov 		if (hittime > lle_hittime)
550c541bd36SAlexander V. Chernikov 			lle_hittime = hittime;
551c541bd36SAlexander V. Chernikov 	}
552c541bd36SAlexander V. Chernikov 
553c541bd36SAlexander V. Chernikov 	return (lle_hittime);
554c541bd36SAlexander V. Chernikov }
555c541bd36SAlexander V. Chernikov 
556f3a3b061SAlexander V. Chernikov /*
5574fb3a820SAlexander V. Chernikov  * Update link-layer header for given @lle after
5584fb3a820SAlexander V. Chernikov  * interface lladdr was changed.
5594fb3a820SAlexander V. Chernikov  */
5604fb3a820SAlexander V. Chernikov static int
5614fb3a820SAlexander V. Chernikov llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg)
5624fb3a820SAlexander V. Chernikov {
5634fb3a820SAlexander V. Chernikov 	struct ifnet *ifp;
5644fb3a820SAlexander V. Chernikov 	u_char linkhdr[LLE_MAX_LINKHDR];
5654fb3a820SAlexander V. Chernikov 	size_t linkhdrsize;
5664fb3a820SAlexander V. Chernikov 	u_char *lladdr;
5674fb3a820SAlexander V. Chernikov 	int lladdr_off;
5684fb3a820SAlexander V. Chernikov 
5694fb3a820SAlexander V. Chernikov 	ifp = (struct ifnet *)farg;
5704fb3a820SAlexander V. Chernikov 
5714fb3a820SAlexander V. Chernikov 	lladdr = lle->ll_addr;
5724fb3a820SAlexander V. Chernikov 
5734fb3a820SAlexander V. Chernikov 	LLE_WLOCK(lle);
5744fb3a820SAlexander V. Chernikov 	if ((lle->la_flags & LLE_VALID) == 0) {
5754fb3a820SAlexander V. Chernikov 		LLE_WUNLOCK(lle);
5764fb3a820SAlexander V. Chernikov 		return (0);
5774fb3a820SAlexander V. Chernikov 	}
5784fb3a820SAlexander V. Chernikov 
5794fb3a820SAlexander V. Chernikov 	if ((lle->la_flags & LLE_IFADDR) != 0)
5804fb3a820SAlexander V. Chernikov 		lladdr = IF_LLADDR(ifp);
5814fb3a820SAlexander V. Chernikov 
5824fb3a820SAlexander V. Chernikov 	linkhdrsize = sizeof(linkhdr);
5834fb3a820SAlexander V. Chernikov 	lltable_calc_llheader(ifp, llt->llt_af, lladdr, linkhdr, &linkhdrsize,
5844fb3a820SAlexander V. Chernikov 	    &lladdr_off);
5854fb3a820SAlexander V. Chernikov 	memcpy(lle->r_linkdata, linkhdr, linkhdrsize);
5864fb3a820SAlexander V. Chernikov 	LLE_WUNLOCK(lle);
5874fb3a820SAlexander V. Chernikov 
5884fb3a820SAlexander V. Chernikov 	return (0);
5894fb3a820SAlexander V. Chernikov }
5904fb3a820SAlexander V. Chernikov 
5914fb3a820SAlexander V. Chernikov /*
5924fb3a820SAlexander V. Chernikov  * Update all calculated headers for given @llt
5934fb3a820SAlexander V. Chernikov  */
5944fb3a820SAlexander V. Chernikov void
5954fb3a820SAlexander V. Chernikov lltable_update_ifaddr(struct lltable *llt)
5964fb3a820SAlexander V. Chernikov {
5974fb3a820SAlexander V. Chernikov 
5984fb3a820SAlexander V. Chernikov 	if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
5994fb3a820SAlexander V. Chernikov 		return;
6004fb3a820SAlexander V. Chernikov 
6014fb3a820SAlexander V. Chernikov 	IF_AFDATA_WLOCK(llt->llt_ifp);
6024fb3a820SAlexander V. Chernikov 	lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp);
6034fb3a820SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
6044fb3a820SAlexander V. Chernikov }
6054fb3a820SAlexander V. Chernikov 
6064fb3a820SAlexander V. Chernikov /*
6075a255516SAlexander V. Chernikov  *
608a4641f4eSPedro F. Giffuni  * Performs generic cleanup routines and frees lle.
6095a255516SAlexander V. Chernikov  *
6105a255516SAlexander V. Chernikov  * Called for non-linked entries, with callouts and
6115a255516SAlexander V. Chernikov  * other AF-specific cleanups performed.
6125a255516SAlexander V. Chernikov  *
6135a255516SAlexander V. Chernikov  * @lle must be passed WLOCK'ed
61411cdad98SAlexander V. Chernikov  *
61511cdad98SAlexander V. Chernikov  * Returns the number of held packets, if any, that were dropped.
61611cdad98SAlexander V. Chernikov  */
61711cdad98SAlexander V. Chernikov size_t
61811cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle)
61911cdad98SAlexander V. Chernikov {
62011cdad98SAlexander V. Chernikov 	size_t pkts_dropped;
62111cdad98SAlexander V. Chernikov 
62211cdad98SAlexander V. Chernikov 	LLE_WLOCK_ASSERT(lle);
62311cdad98SAlexander V. Chernikov 
624d3cdb716SAlexander V. Chernikov 	KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle"));
62511cdad98SAlexander V. Chernikov 
62611cdad98SAlexander V. Chernikov 	pkts_dropped = lltable_drop_entry_queue(lle);
62711cdad98SAlexander V. Chernikov 
628acf673edSAndrey V. Elsukov 	/* cancel timer */
629acf673edSAndrey V. Elsukov 	if (callout_stop(&lle->lle_timer) > 0)
630acf673edSAndrey V. Elsukov 		LLE_REMREF(lle);
63182f39c91SKip Macy 	LLE_FREE_LOCKED(lle);
632e162ea60SGeorge V. Neville-Neil 
633e162ea60SGeorge V. Neville-Neil 	return (pkts_dropped);
63482f39c91SKip Macy }
63582f39c91SKip Macy 
636adfc35ffSKip Macy /*
63782f39c91SKip Macy  * Free all entries from given table and free itself.
63882f39c91SKip Macy  */
63911cdad98SAlexander V. Chernikov 
64011cdad98SAlexander V. Chernikov static int
64111cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
64211cdad98SAlexander V. Chernikov {
64311cdad98SAlexander V. Chernikov 	struct llentries *dchain;
64411cdad98SAlexander V. Chernikov 
64511cdad98SAlexander V. Chernikov 	dchain = (struct llentries *)farg;
64611cdad98SAlexander V. Chernikov 
64711cdad98SAlexander V. Chernikov 	LLE_WLOCK(lle);
6480f8d79d9SMatt Macy 	CK_LIST_INSERT_HEAD(dchain, lle, lle_chain);
64911cdad98SAlexander V. Chernikov 
65011cdad98SAlexander V. Chernikov 	return (0);
65111cdad98SAlexander V. Chernikov }
65211cdad98SAlexander V. Chernikov 
65311cdad98SAlexander V. Chernikov /*
65411cdad98SAlexander V. Chernikov  * Free all entries from given table and free itself.
65511cdad98SAlexander V. Chernikov  */
65682f39c91SKip Macy void
65782f39c91SKip Macy lltable_free(struct lltable *llt)
65882f39c91SKip Macy {
65982f39c91SKip Macy 	struct llentry *lle, *next;
66011cdad98SAlexander V. Chernikov 	struct llentries dchain;
66182f39c91SKip Macy 
66282f39c91SKip Macy 	KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
66382f39c91SKip Macy 
664721cd2e0SAlexander V. Chernikov 	lltable_unlink(llt);
66582f39c91SKip Macy 
6664f6c66ccSMatt Macy 	CK_LIST_INIT(&dchain);
667ea537929SGleb Smirnoff 	IF_AFDATA_WLOCK(llt->llt_ifp);
66811cdad98SAlexander V. Chernikov 	/* Push all lles to @dchain */
66911cdad98SAlexander V. Chernikov 	lltable_foreach_lle(llt, lltable_free_cb, &dchain);
67011cdad98SAlexander V. Chernikov 	llentries_unlink(llt, &dchain);
67111cdad98SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
67211cdad98SAlexander V. Chernikov 
6730f8d79d9SMatt Macy 	CK_LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
67482f39c91SKip Macy 		llentry_free(lle);
67582f39c91SKip Macy 	}
67682f39c91SKip Macy 
6773818c25aSBjoern A. Zeeb 	KASSERT(llt->llt_entries == 0, ("%s: lltable %p (%s) entires not 0: %d",
6783818c25aSBjoern A. Zeeb 	    __func__, llt, llt->llt_ifp->if_xname, llt->llt_entries));
6793818c25aSBjoern A. Zeeb 
680721cd2e0SAlexander V. Chernikov 	llt->llt_free_tbl(llt);
68182f39c91SKip Macy }
68282f39c91SKip Macy 
6833e7a2321SAlexander V. Chernikov /*
6843e7a2321SAlexander V. Chernikov  * Deletes an address from given lltable.
6853e7a2321SAlexander V. Chernikov  * Used for userland interaction to remove
6863e7a2321SAlexander V. Chernikov  * individual entries. Skips entries added by OS.
6873e7a2321SAlexander V. Chernikov  */
6883e7a2321SAlexander V. Chernikov int
6893e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags,
6903e7a2321SAlexander V. Chernikov     const struct sockaddr *l3addr)
6913e7a2321SAlexander V. Chernikov {
6923e7a2321SAlexander V. Chernikov 	struct llentry *lle;
6933e7a2321SAlexander V. Chernikov 	struct ifnet *ifp;
6943e7a2321SAlexander V. Chernikov 
6953e7a2321SAlexander V. Chernikov 	ifp = llt->llt_ifp;
6963e7a2321SAlexander V. Chernikov 	IF_AFDATA_WLOCK(ifp);
697c541bd36SAlexander V. Chernikov 	lle = lla_lookup(llt, LLE_SF(l3addr->sa_family, LLE_EXCLUSIVE), l3addr);
6983e7a2321SAlexander V. Chernikov 
6993e7a2321SAlexander V. Chernikov 	if (lle == NULL) {
7003e7a2321SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
7013e7a2321SAlexander V. Chernikov 		return (ENOENT);
7023e7a2321SAlexander V. Chernikov 	}
7033e7a2321SAlexander V. Chernikov 	if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
7043e7a2321SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
7053e7a2321SAlexander V. Chernikov 		LLE_WUNLOCK(lle);
7063e7a2321SAlexander V. Chernikov 		return (EPERM);
7073e7a2321SAlexander V. Chernikov 	}
7083e7a2321SAlexander V. Chernikov 
7093e7a2321SAlexander V. Chernikov 	lltable_unlink_entry(llt, lle);
7103e7a2321SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(ifp);
7113e7a2321SAlexander V. Chernikov 
7123e7a2321SAlexander V. Chernikov 	llt->llt_delete_entry(llt, lle);
7133e7a2321SAlexander V. Chernikov 
7143e7a2321SAlexander V. Chernikov 	return (0);
7153e7a2321SAlexander V. Chernikov }
7163e7a2321SAlexander V. Chernikov 
717c9d763bfSQing Li void
7183e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
7195b84dc78SQing Li     u_int flags)
720c9d763bfSQing Li {
721c9d763bfSQing Li 	struct lltable *llt;
722c9d763bfSQing Li 
723199511bcSAndrey V. Elsukov 	LLTABLE_LIST_RLOCK();
724989e0411SMarko Zec 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
725c9d763bfSQing Li 		if (llt->llt_af != af)
726c9d763bfSQing Li 			continue;
727c9d763bfSQing Li 
7283e7a2321SAlexander V. Chernikov 		llt->llt_prefix_free(llt, addr, mask, flags);
729c9d763bfSQing Li 	}
730199511bcSAndrey V. Elsukov 	LLTABLE_LIST_RUNLOCK();
731c9d763bfSQing Li }
732c9d763bfSQing Li 
73382f39c91SKip Macy struct lltable *
73441cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize)
73582f39c91SKip Macy {
73682f39c91SKip Macy 	struct lltable *llt;
73741cb42a6SAlexander V. Chernikov 	int i;
73882f39c91SKip Macy 
73941cb42a6SAlexander V. Chernikov 	llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
74041cb42a6SAlexander V. Chernikov 	llt->llt_hsize = hsize;
74141cb42a6SAlexander V. Chernikov 	llt->lle_head = malloc(sizeof(struct llentries) * hsize,
74241cb42a6SAlexander V. Chernikov 	    M_LLTABLE, M_WAITOK | M_ZERO);
74382f39c91SKip Macy 
74441cb42a6SAlexander V. Chernikov 	for (i = 0; i < llt->llt_hsize; i++)
7454f6c66ccSMatt Macy 		CK_LIST_INIT(&llt->lle_head[i]);
74682f39c91SKip Macy 
74711cdad98SAlexander V. Chernikov 	/* Set some default callbacks */
74811cdad98SAlexander V. Chernikov 	llt->llt_link_entry = htable_link_entry;
74911cdad98SAlexander V. Chernikov 	llt->llt_unlink_entry = htable_unlink_entry;
75011cdad98SAlexander V. Chernikov 	llt->llt_prefix_free = htable_prefix_free;
75111cdad98SAlexander V. Chernikov 	llt->llt_foreach_entry = htable_foreach_lle;
75241cb42a6SAlexander V. Chernikov 	llt->llt_free_tbl = htable_free_tbl;
75341cb42a6SAlexander V. Chernikov 
75441cb42a6SAlexander V. Chernikov 	return (llt);
75541cb42a6SAlexander V. Chernikov }
75641cb42a6SAlexander V. Chernikov 
75782f39c91SKip Macy /*
758721cd2e0SAlexander V. Chernikov  * Links lltable to global llt list.
75982f39c91SKip Macy  */
760721cd2e0SAlexander V. Chernikov void
761721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt)
76282f39c91SKip Macy {
76311cdad98SAlexander V. Chernikov 
764199511bcSAndrey V. Elsukov 	LLTABLE_LIST_WLOCK();
765989e0411SMarko Zec 	SLIST_INSERT_HEAD(&V_lltables, llt, llt_link);
766199511bcSAndrey V. Elsukov 	LLTABLE_LIST_WUNLOCK();
767721cd2e0SAlexander V. Chernikov }
76882f39c91SKip Macy 
769721cd2e0SAlexander V. Chernikov static void
770721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt)
771721cd2e0SAlexander V. Chernikov {
772721cd2e0SAlexander V. Chernikov 
773199511bcSAndrey V. Elsukov 	LLTABLE_LIST_WLOCK();
774721cd2e0SAlexander V. Chernikov 	SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
775199511bcSAndrey V. Elsukov 	LLTABLE_LIST_WUNLOCK();
776721cd2e0SAlexander V. Chernikov 
77782f39c91SKip Macy }
77882f39c91SKip Macy 
77982f39c91SKip Macy /*
780ff3a85d3SAlexander V. Chernikov  * Gets interface @ifp lltable for the specified @family
781ff3a85d3SAlexander V. Chernikov  */
782ff3a85d3SAlexander V. Chernikov struct lltable *
783ff3a85d3SAlexander V. Chernikov lltable_get(struct ifnet *ifp, int family)
784ff3a85d3SAlexander V. Chernikov {
785ff3a85d3SAlexander V. Chernikov 	switch (family) {
786818952c6SEd Maste #ifdef INET
787ff3a85d3SAlexander V. Chernikov 	case AF_INET:
788ff3a85d3SAlexander V. Chernikov 		return (in_lltable_get(ifp));
789818952c6SEd Maste #endif
790818952c6SEd Maste #ifdef INET6
791ff3a85d3SAlexander V. Chernikov 	case AF_INET6:
792ff3a85d3SAlexander V. Chernikov 		return (in6_lltable_get(ifp));
793818952c6SEd Maste #endif
794ff3a85d3SAlexander V. Chernikov 	}
795ff3a85d3SAlexander V. Chernikov 
796ff3a85d3SAlexander V. Chernikov 	return (NULL);
797ff3a85d3SAlexander V. Chernikov }
798ff3a85d3SAlexander V. Chernikov 
799ff3a85d3SAlexander V. Chernikov /*
80011cdad98SAlexander V. Chernikov  * External methods used by lltable consumers
80111cdad98SAlexander V. Chernikov  */
80211cdad98SAlexander V. Chernikov 
80311cdad98SAlexander V. Chernikov int
80411cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
80511cdad98SAlexander V. Chernikov {
80611cdad98SAlexander V. Chernikov 
80711cdad98SAlexander V. Chernikov 	return (llt->llt_foreach_entry(llt, f, farg));
80811cdad98SAlexander V. Chernikov }
80911cdad98SAlexander V. Chernikov 
8105a255516SAlexander V. Chernikov struct llentry *
8115a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags,
8125a255516SAlexander V. Chernikov     const struct sockaddr *l3addr)
8135a255516SAlexander V. Chernikov {
8145a255516SAlexander V. Chernikov 
8155a255516SAlexander V. Chernikov 	return (llt->llt_alloc_entry(llt, flags, l3addr));
8165a255516SAlexander V. Chernikov }
8175a255516SAlexander V. Chernikov 
8185a255516SAlexander V. Chernikov void
8195a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle)
8205a255516SAlexander V. Chernikov {
8215a255516SAlexander V. Chernikov 
8225a255516SAlexander V. Chernikov 	llt->llt_free_entry(llt, lle);
8235a255516SAlexander V. Chernikov }
8245a255516SAlexander V. Chernikov 
8253818c25aSBjoern A. Zeeb int
82611cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle)
82711cdad98SAlexander V. Chernikov {
82811cdad98SAlexander V. Chernikov 
8293818c25aSBjoern A. Zeeb 	return (llt->llt_link_entry(llt, lle));
83011cdad98SAlexander V. Chernikov }
83111cdad98SAlexander V. Chernikov 
832c541bd36SAlexander V. Chernikov void
833c541bd36SAlexander V. Chernikov lltable_link_child_entry(struct llentry *lle, struct llentry *child_lle)
834c541bd36SAlexander V. Chernikov {
835c541bd36SAlexander V. Chernikov 	child_lle->lle_parent = lle;
836c541bd36SAlexander V. Chernikov 	child_lle->lle_tbl = lle->lle_tbl;
837c541bd36SAlexander V. Chernikov 	child_lle->la_flags |= LLE_LINKED;
838c541bd36SAlexander V. Chernikov 	CK_SLIST_INSERT_HEAD(&lle->lle_children, child_lle, lle_child_next);
839c541bd36SAlexander V. Chernikov }
840c541bd36SAlexander V. Chernikov 
841c541bd36SAlexander V. Chernikov void
842c541bd36SAlexander V. Chernikov lltable_unlink_child_entry(struct llentry *child_lle)
843c541bd36SAlexander V. Chernikov {
844c541bd36SAlexander V. Chernikov 	struct llentry *lle = child_lle->lle_parent;
845c541bd36SAlexander V. Chernikov 
846c541bd36SAlexander V. Chernikov 	child_lle->la_flags &= ~LLE_LINKED;
847c541bd36SAlexander V. Chernikov 	child_lle->lle_parent = NULL;
848c541bd36SAlexander V. Chernikov 	CK_SLIST_REMOVE(&lle->lle_children, child_lle, llentry, lle_child_next);
849c541bd36SAlexander V. Chernikov }
850c541bd36SAlexander V. Chernikov 
8513818c25aSBjoern A. Zeeb int
85211cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
85311cdad98SAlexander V. Chernikov {
85411cdad98SAlexander V. Chernikov 
8553818c25aSBjoern A. Zeeb 	return (llt->llt_unlink_entry(lle));
85611cdad98SAlexander V. Chernikov }
85711cdad98SAlexander V. Chernikov 
85811cdad98SAlexander V. Chernikov void
85911cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
86011cdad98SAlexander V. Chernikov {
86111cdad98SAlexander V. Chernikov 	struct lltable *llt;
86211cdad98SAlexander V. Chernikov 
86311cdad98SAlexander V. Chernikov 	llt = lle->lle_tbl;
86411cdad98SAlexander V. Chernikov 	llt->llt_fill_sa_entry(lle, sa);
86511cdad98SAlexander V. Chernikov }
86611cdad98SAlexander V. Chernikov 
86711cdad98SAlexander V. Chernikov struct ifnet *
86811cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt)
86911cdad98SAlexander V. Chernikov {
87011cdad98SAlexander V. Chernikov 
87111cdad98SAlexander V. Chernikov 	return (llt->llt_ifp);
87211cdad98SAlexander V. Chernikov }
87311cdad98SAlexander V. Chernikov 
87411cdad98SAlexander V. Chernikov int
87511cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt)
87611cdad98SAlexander V. Chernikov {
87711cdad98SAlexander V. Chernikov 
87811cdad98SAlexander V. Chernikov 	return (llt->llt_af);
87911cdad98SAlexander V. Chernikov }
88011cdad98SAlexander V. Chernikov 
88111cdad98SAlexander V. Chernikov /*
882b4b1367aSAlexander V. Chernikov  * Called in route_output when rtm_flags contains RTF_LLDATA.
88382f39c91SKip Macy  */
88482f39c91SKip Macy int
88582f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
88682f39c91SKip Macy {
88782f39c91SKip Macy 	struct sockaddr_dl *dl =
88882f39c91SKip Macy 	    (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY];
88982f39c91SKip Macy 	struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
89082f39c91SKip Macy 	struct ifnet *ifp;
89182f39c91SKip Macy 	struct lltable *llt;
8925a255516SAlexander V. Chernikov 	struct llentry *lle, *lle_tmp;
8934fb3a820SAlexander V. Chernikov 	uint8_t linkhdr[LLE_MAX_LINKHDR];
8944fb3a820SAlexander V. Chernikov 	size_t linkhdrsize;
8954fb3a820SAlexander V. Chernikov 	int lladdr_off;
896b4b1367aSAlexander V. Chernikov 	u_int laflags = 0;
897b4b1367aSAlexander V. Chernikov 	int error;
89882f39c91SKip Macy 
899c83dda36SAlexander V. Chernikov 	if (dl == NULL || dl->sdl_family != AF_LINK)
900c83dda36SAlexander V. Chernikov 		return (EINVAL);
9011910bfcbSGleb Smirnoff 
902e5b394f2SAlexander V. Chernikov 	/* XXX: should be ntohs() */
90382f39c91SKip Macy 	ifp = ifnet_byindex(dl->sdl_index);
90482f39c91SKip Macy 	if (ifp == NULL) {
90582f39c91SKip Macy 		log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
90682f39c91SKip Macy 		    __func__, dl->sdl_index);
90782f39c91SKip Macy 		return EINVAL;
90882f39c91SKip Macy 	}
90982f39c91SKip Macy 
910ff3a85d3SAlexander V. Chernikov 	llt = lltable_get(ifp, dst->sa_family);
911ff3a85d3SAlexander V. Chernikov 
912c83dda36SAlexander V. Chernikov 	if (llt == NULL)
913c83dda36SAlexander V. Chernikov 		return (ESRCH);
91482f39c91SKip Macy 
915b4b1367aSAlexander V. Chernikov 	error = 0;
91682f39c91SKip Macy 
917b4b1367aSAlexander V. Chernikov 	switch (rtm->rtm_type) {
918b4b1367aSAlexander V. Chernikov 	case RTM_ADD:
919b4b1367aSAlexander V. Chernikov 		/* Add static LLE */
9203b0fd911SAlexander V. Chernikov 		laflags = 0;
9213b0fd911SAlexander V. Chernikov 		if (rtm->rtm_rmx.rmx_expire == 0)
9223b0fd911SAlexander V. Chernikov 			laflags = LLE_STATIC;
9233b0fd911SAlexander V. Chernikov 		lle = lltable_alloc_entry(llt, laflags, dst);
9245a255516SAlexander V. Chernikov 		if (lle == NULL)
925b4b1367aSAlexander V. Chernikov 			return (ENOMEM);
926b4b1367aSAlexander V. Chernikov 
9274fb3a820SAlexander V. Chernikov 		linkhdrsize = sizeof(linkhdr);
9284fb3a820SAlexander V. Chernikov 		if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl),
929*990a6d18SMark Johnston 		    linkhdr, &linkhdrsize, &lladdr_off) != 0) {
930*990a6d18SMark Johnston 			lltable_free_entry(llt, lle);
9314fb3a820SAlexander V. Chernikov 			return (EINVAL);
932*990a6d18SMark Johnston 		}
9334fb3a820SAlexander V. Chernikov 		lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize,
9344fb3a820SAlexander V. Chernikov 		    lladdr_off);
935b4b1367aSAlexander V. Chernikov 		if ((rtm->rtm_flags & RTF_ANNOUNCE))
936b4b1367aSAlexander V. Chernikov 			lle->la_flags |= LLE_PUB;
93782f39c91SKip Macy 		lle->la_expire = rtm->rtm_rmx.rmx_expire;
9383b0fd911SAlexander V. Chernikov 
93982f39c91SKip Macy 		laflags = lle->la_flags;
9405a255516SAlexander V. Chernikov 
9415a255516SAlexander V. Chernikov 		/* Try to link new entry */
9425a255516SAlexander V. Chernikov 		lle_tmp = NULL;
9435a255516SAlexander V. Chernikov 		IF_AFDATA_WLOCK(ifp);
9445a255516SAlexander V. Chernikov 		LLE_WLOCK(lle);
9455a255516SAlexander V. Chernikov 		lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst);
9465a255516SAlexander V. Chernikov 		if (lle_tmp != NULL) {
9475a255516SAlexander V. Chernikov 			/* Check if we are trying to replace immutable entry */
9485a255516SAlexander V. Chernikov 			if ((lle_tmp->la_flags & LLE_IFADDR) != 0) {
949b4b1367aSAlexander V. Chernikov 				IF_AFDATA_WUNLOCK(ifp);
9505a255516SAlexander V. Chernikov 				LLE_WUNLOCK(lle_tmp);
9515a255516SAlexander V. Chernikov 				lltable_free_entry(llt, lle);
9525a255516SAlexander V. Chernikov 				return (EPERM);
9535a255516SAlexander V. Chernikov 			}
9545a255516SAlexander V. Chernikov 			/* Unlink existing entry from table */
9555a255516SAlexander V. Chernikov 			lltable_unlink_entry(llt, lle_tmp);
9565a255516SAlexander V. Chernikov 		}
9575a255516SAlexander V. Chernikov 		lltable_link_entry(llt, lle);
9585a255516SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
9595a255516SAlexander V. Chernikov 
9605a255516SAlexander V. Chernikov 		if (lle_tmp != NULL) {
9615a255516SAlexander V. Chernikov 			EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED);
9625a255516SAlexander V. Chernikov 			lltable_free_entry(llt, lle_tmp);
9635a255516SAlexander V. Chernikov 		}
9645a255516SAlexander V. Chernikov 
9655a255516SAlexander V. Chernikov 		/*
9665a255516SAlexander V. Chernikov 		 * By invoking LLE handler here we might get
9675a255516SAlexander V. Chernikov 		 * two events on static LLE entry insertion
9685a255516SAlexander V. Chernikov 		 * in routing socket. However, since we might have
9695a255516SAlexander V. Chernikov 		 * other subscribers we need to generate this event.
9705a255516SAlexander V. Chernikov 		 */
9715a255516SAlexander V. Chernikov 		EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED);
9725a255516SAlexander V. Chernikov 		LLE_WUNLOCK(lle);
97382f39c91SKip Macy #ifdef INET
9747b4d716bSKip Macy 		/* gratuitous ARP */
9759711a168SGleb Smirnoff 		if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
97682f39c91SKip Macy 			arprequest(ifp,
97782f39c91SKip Macy 			    &((struct sockaddr_in *)dst)->sin_addr,
97882f39c91SKip Macy 			    &((struct sockaddr_in *)dst)->sin_addr,
9799711a168SGleb Smirnoff 			    (u_char *)LLADDR(dl));
98082f39c91SKip Macy #endif
98182f39c91SKip Macy 
982b4b1367aSAlexander V. Chernikov 		break;
983b4b1367aSAlexander V. Chernikov 
984b4b1367aSAlexander V. Chernikov 	case RTM_DELETE:
9853e7a2321SAlexander V. Chernikov 		return (lltable_delete_addr(llt, 0, dst));
986b4b1367aSAlexander V. Chernikov 
987b4b1367aSAlexander V. Chernikov 	default:
988b4b1367aSAlexander V. Chernikov 		error = EINVAL;
989b4b1367aSAlexander V. Chernikov 	}
99082f39c91SKip Macy 
99182f39c91SKip Macy 	return (error);
99282f39c91SKip Macy }
993989e0411SMarko Zec 
994335b943fSBjoern A. Zeeb #ifdef DDB
995335b943fSBjoern A. Zeeb struct llentry_sa {
996335b943fSBjoern A. Zeeb 	struct llentry		base;
997335b943fSBjoern A. Zeeb 	struct sockaddr		l3_addr;
998335b943fSBjoern A. Zeeb };
999335b943fSBjoern A. Zeeb 
1000335b943fSBjoern A. Zeeb static void
1001335b943fSBjoern A. Zeeb llatbl_lle_show(struct llentry_sa *la)
1002335b943fSBjoern A. Zeeb {
1003335b943fSBjoern A. Zeeb 	struct llentry *lle;
1004335b943fSBjoern A. Zeeb 	uint8_t octet[6];
1005335b943fSBjoern A. Zeeb 
1006335b943fSBjoern A. Zeeb 	lle = &la->base;
1007335b943fSBjoern A. Zeeb 	db_printf("lle=%p\n", lle);
10080f8d79d9SMatt Macy 	db_printf(" lle_next=%p\n", lle->lle_next.cle_next);
1009335b943fSBjoern A. Zeeb 	db_printf(" lle_lock=%p\n", &lle->lle_lock);
1010335b943fSBjoern A. Zeeb 	db_printf(" lle_tbl=%p\n", lle->lle_tbl);
1011335b943fSBjoern A. Zeeb 	db_printf(" lle_head=%p\n", lle->lle_head);
1012335b943fSBjoern A. Zeeb 	db_printf(" la_hold=%p\n", lle->la_hold);
1013e162ea60SGeorge V. Neville-Neil 	db_printf(" la_numheld=%d\n", lle->la_numheld);
1014335b943fSBjoern A. Zeeb 	db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
1015335b943fSBjoern A. Zeeb 	db_printf(" la_flags=0x%04x\n", lle->la_flags);
1016335b943fSBjoern A. Zeeb 	db_printf(" la_asked=%u\n", lle->la_asked);
1017335b943fSBjoern A. Zeeb 	db_printf(" la_preempt=%u\n", lle->la_preempt);
1018335b943fSBjoern A. Zeeb 	db_printf(" ln_state=%d\n", lle->ln_state);
1019335b943fSBjoern A. Zeeb 	db_printf(" ln_router=%u\n", lle->ln_router);
1020335b943fSBjoern A. Zeeb 	db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
1021335b943fSBjoern A. Zeeb 	db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
10224fb3a820SAlexander V. Chernikov 	bcopy(lle->ll_addr, octet, sizeof(octet));
1023335b943fSBjoern A. Zeeb 	db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
1024335b943fSBjoern A. Zeeb 	    octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
10250447c136SAlexander V. Chernikov 	db_printf(" lle_timer=%p\n", &lle->lle_timer);
1026335b943fSBjoern A. Zeeb 
1027335b943fSBjoern A. Zeeb 	switch (la->l3_addr.sa_family) {
1028335b943fSBjoern A. Zeeb #ifdef INET
1029335b943fSBjoern A. Zeeb 	case AF_INET:
1030335b943fSBjoern A. Zeeb 	{
1031335b943fSBjoern A. Zeeb 		struct sockaddr_in *sin;
1032335b943fSBjoern A. Zeeb 		char l3s[INET_ADDRSTRLEN];
1033335b943fSBjoern A. Zeeb 
1034335b943fSBjoern A. Zeeb 		sin = (struct sockaddr_in *)&la->l3_addr;
1035335b943fSBjoern A. Zeeb 		inet_ntoa_r(sin->sin_addr, l3s);
1036335b943fSBjoern A. Zeeb 		db_printf(" l3_addr=%s\n", l3s);
1037335b943fSBjoern A. Zeeb 		break;
1038335b943fSBjoern A. Zeeb 	}
1039335b943fSBjoern A. Zeeb #endif
1040335b943fSBjoern A. Zeeb #ifdef INET6
1041335b943fSBjoern A. Zeeb 	case AF_INET6:
1042335b943fSBjoern A. Zeeb 	{
1043335b943fSBjoern A. Zeeb 		struct sockaddr_in6 *sin6;
1044335b943fSBjoern A. Zeeb 		char l3s[INET6_ADDRSTRLEN];
1045335b943fSBjoern A. Zeeb 
1046335b943fSBjoern A. Zeeb 		sin6 = (struct sockaddr_in6 *)&la->l3_addr;
1047335b943fSBjoern A. Zeeb 		ip6_sprintf(l3s, &sin6->sin6_addr);
1048335b943fSBjoern A. Zeeb 		db_printf(" l3_addr=%s\n", l3s);
1049335b943fSBjoern A. Zeeb 		break;
1050335b943fSBjoern A. Zeeb 	}
1051335b943fSBjoern A. Zeeb #endif
1052335b943fSBjoern A. Zeeb 	default:
1053335b943fSBjoern A. Zeeb 		db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family);
1054335b943fSBjoern A. Zeeb 		break;
1055335b943fSBjoern A. Zeeb 	}
1056335b943fSBjoern A. Zeeb }
1057335b943fSBjoern A. Zeeb 
1058335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry)
1059335b943fSBjoern A. Zeeb {
1060335b943fSBjoern A. Zeeb 
1061335b943fSBjoern A. Zeeb 	if (!have_addr) {
1062335b943fSBjoern A. Zeeb 		db_printf("usage: show llentry <struct llentry *>\n");
1063335b943fSBjoern A. Zeeb 		return;
1064335b943fSBjoern A. Zeeb 	}
1065335b943fSBjoern A. Zeeb 
1066335b943fSBjoern A. Zeeb 	llatbl_lle_show((struct llentry_sa *)addr);
1067335b943fSBjoern A. Zeeb }
1068335b943fSBjoern A. Zeeb 
1069335b943fSBjoern A. Zeeb static void
1070335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt)
1071335b943fSBjoern A. Zeeb {
1072335b943fSBjoern A. Zeeb 	int i;
1073335b943fSBjoern A. Zeeb 	struct llentry *lle;
1074335b943fSBjoern A. Zeeb 
1075335b943fSBjoern A. Zeeb 	db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
1076335b943fSBjoern A. Zeeb 	    llt, llt->llt_af, llt->llt_ifp);
1077335b943fSBjoern A. Zeeb 
10783a749863SAlexander V. Chernikov 	for (i = 0; i < llt->llt_hsize; i++) {
10794f6c66ccSMatt Macy 		CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
1080335b943fSBjoern A. Zeeb 			llatbl_lle_show((struct llentry_sa *)lle);
1081335b943fSBjoern A. Zeeb 			if (db_pager_quit)
1082335b943fSBjoern A. Zeeb 				return;
1083335b943fSBjoern A. Zeeb 		}
1084335b943fSBjoern A. Zeeb 	}
1085335b943fSBjoern A. Zeeb }
1086335b943fSBjoern A. Zeeb 
1087335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable)
1088335b943fSBjoern A. Zeeb {
1089335b943fSBjoern A. Zeeb 
1090335b943fSBjoern A. Zeeb 	if (!have_addr) {
1091335b943fSBjoern A. Zeeb 		db_printf("usage: show lltable <struct lltable *>\n");
1092335b943fSBjoern A. Zeeb 		return;
1093335b943fSBjoern A. Zeeb 	}
1094335b943fSBjoern A. Zeeb 
1095335b943fSBjoern A. Zeeb 	llatbl_llt_show((struct lltable *)addr);
1096335b943fSBjoern A. Zeeb }
1097335b943fSBjoern A. Zeeb 
1098335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
1099335b943fSBjoern A. Zeeb {
1100335b943fSBjoern A. Zeeb 	VNET_ITERATOR_DECL(vnet_iter);
1101335b943fSBjoern A. Zeeb 	struct lltable *llt;
1102335b943fSBjoern A. Zeeb 
1103335b943fSBjoern A. Zeeb 	VNET_FOREACH(vnet_iter) {
1104335b943fSBjoern A. Zeeb 		CURVNET_SET_QUIET(vnet_iter);
1105335b943fSBjoern A. Zeeb #ifdef VIMAGE
1106335b943fSBjoern A. Zeeb 		db_printf("vnet=%p\n", curvnet);
1107335b943fSBjoern A. Zeeb #endif
1108335b943fSBjoern A. Zeeb 		SLIST_FOREACH(llt, &V_lltables, llt_link) {
1109335b943fSBjoern A. Zeeb 			db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
1110335b943fSBjoern A. Zeeb 			    llt, llt->llt_af, llt->llt_ifp,
1111335b943fSBjoern A. Zeeb 			    (llt->llt_ifp != NULL) ?
1112335b943fSBjoern A. Zeeb 				llt->llt_ifp->if_xname : "?");
1113335b943fSBjoern A. Zeeb 			if (have_addr && addr != 0) /* verbose */
1114335b943fSBjoern A. Zeeb 				llatbl_llt_show(llt);
1115335b943fSBjoern A. Zeeb 			if (db_pager_quit) {
1116335b943fSBjoern A. Zeeb 				CURVNET_RESTORE();
1117335b943fSBjoern A. Zeeb 				return;
1118335b943fSBjoern A. Zeeb 			}
1119335b943fSBjoern A. Zeeb 		}
1120335b943fSBjoern A. Zeeb 		CURVNET_RESTORE();
1121335b943fSBjoern A. Zeeb 	}
1122335b943fSBjoern A. Zeeb }
1123335b943fSBjoern A. Zeeb #endif
1124