xref: /freebsd/sys/net/if_llatbl.c (revision 2c2b37ad251d25fb81d6254e29130684fed774ab)
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>
60*2c2b37adSJustin Hibbits #include <net/if_private.h>
6182f39c91SKip Macy #include <net/route.h>
62da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h>
6363f7f392SAlexander V. Chernikov #include <net/route/route_debug.h>
64530c0060SRobert Watson #include <net/vnet.h>
6582f39c91SKip Macy #include <netinet/if_ether.h>
6682f39c91SKip Macy #include <netinet6/in6_var.h>
6782f39c91SKip Macy #include <netinet6/nd6.h>
6882f39c91SKip Macy 
6982f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
7082f39c91SKip Macy 
715f901c92SAndrew Turner VNET_DEFINE_STATIC(SLIST_HEAD(, lltable), lltables) =
7276d68eccSBjoern A. Zeeb     SLIST_HEAD_INITIALIZER(lltables);
73989e0411SMarko Zec #define	V_lltables	VNET(lltables)
7482f39c91SKip Macy 
75199511bcSAndrey V. Elsukov static struct rwlock lltable_list_lock;
76199511bcSAndrey V. Elsukov RW_SYSINIT(lltable_list_lock, &lltable_list_lock, "lltable_list_lock");
77199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_RLOCK()		rw_rlock(&lltable_list_lock)
78199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_RUNLOCK()		rw_runlock(&lltable_list_lock)
79199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_WLOCK()		rw_wlock(&lltable_list_lock)
80199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_WUNLOCK()		rw_wunlock(&lltable_list_lock)
81199511bcSAndrey V. Elsukov #define	LLTABLE_LIST_LOCK_ASSERT()	rw_assert(&lltable_list_lock, RA_LOCKED)
82dc56e98fSRobert Watson 
83721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt);
8411cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head);
8511cdad98SAlexander V. Chernikov 
8611cdad98SAlexander V. Chernikov /*
8711cdad98SAlexander V. Chernikov  * Dump lle state for a specific address family.
8811cdad98SAlexander V. Chernikov  */
8911cdad98SAlexander V. Chernikov static int
9011cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
9111cdad98SAlexander V. Chernikov {
92a68cc388SGleb Smirnoff 	struct epoch_tracker et;
9311cdad98SAlexander V. Chernikov 	int error;
9411cdad98SAlexander V. Chernikov 
95199511bcSAndrey V. Elsukov 	LLTABLE_LIST_LOCK_ASSERT();
9611cdad98SAlexander V. Chernikov 
9711cdad98SAlexander V. Chernikov 	if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
9811cdad98SAlexander V. Chernikov 		return (0);
9911cdad98SAlexander V. Chernikov 	error = 0;
10011cdad98SAlexander V. Chernikov 
101a68cc388SGleb Smirnoff 	NET_EPOCH_ENTER(et);
10211cdad98SAlexander V. Chernikov 	error = lltable_foreach_lle(llt,
10311cdad98SAlexander V. Chernikov 	    (llt_foreach_cb_t *)llt->llt_dump_entry, wr);
104a68cc388SGleb Smirnoff 	NET_EPOCH_EXIT(et);
10511cdad98SAlexander V. Chernikov 
10611cdad98SAlexander V. Chernikov 	return (error);
10711cdad98SAlexander V. Chernikov }
10811cdad98SAlexander V. Chernikov 
10982f39c91SKip Macy /*
11082f39c91SKip Macy  * Dump arp state for a specific address family.
11182f39c91SKip Macy  */
11282f39c91SKip Macy int
11382f39c91SKip Macy lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
11482f39c91SKip Macy {
11582f39c91SKip Macy 	struct lltable *llt;
11682f39c91SKip Macy 	int error = 0;
11782f39c91SKip Macy 
118199511bcSAndrey V. Elsukov 	LLTABLE_LIST_RLOCK();
119989e0411SMarko Zec 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
12082f39c91SKip Macy 		if (llt->llt_af == af) {
12111cdad98SAlexander V. Chernikov 			error = lltable_dump_af(llt, wr);
12282f39c91SKip Macy 			if (error != 0)
12382f39c91SKip Macy 				goto done;
12482f39c91SKip Macy 		}
12582f39c91SKip Macy 	}
12682f39c91SKip Macy done:
127199511bcSAndrey V. Elsukov 	LLTABLE_LIST_RUNLOCK();
12882f39c91SKip Macy 	return (error);
12982f39c91SKip Macy }
13082f39c91SKip Macy 
13182f39c91SKip Macy /*
132d18b4becSArseny Smalyuk  * Adds a mbuf to hold queue. Drops old packets if the queue is full.
133d18b4becSArseny Smalyuk  *
134d18b4becSArseny Smalyuk  * Returns the number of held packets that were dropped.
135d18b4becSArseny Smalyuk  */
136d18b4becSArseny Smalyuk size_t
137d18b4becSArseny Smalyuk lltable_append_entry_queue(struct llentry *lle, struct mbuf *m,
138d18b4becSArseny Smalyuk     size_t maxheld)
139d18b4becSArseny Smalyuk {
140d18b4becSArseny Smalyuk 	size_t pkts_dropped = 0;
141d18b4becSArseny Smalyuk 
142d18b4becSArseny Smalyuk 	LLE_WLOCK_ASSERT(lle);
143d18b4becSArseny Smalyuk 
144d18b4becSArseny Smalyuk 	while (lle->la_numheld >= maxheld && lle->la_hold != NULL) {
145d18b4becSArseny Smalyuk 		struct mbuf *next = lle->la_hold->m_nextpkt;
146d18b4becSArseny Smalyuk 		m_freem(lle->la_hold);
147d18b4becSArseny Smalyuk 		lle->la_hold = next;
148d18b4becSArseny Smalyuk 		lle->la_numheld--;
149d18b4becSArseny Smalyuk 		pkts_dropped++;
150d18b4becSArseny Smalyuk 	}
151d18b4becSArseny Smalyuk 
152d18b4becSArseny Smalyuk 	if (lle->la_hold != NULL) {
153d18b4becSArseny Smalyuk 		struct mbuf *curr = lle->la_hold;
154d18b4becSArseny Smalyuk 		while (curr->m_nextpkt != NULL)
155d18b4becSArseny Smalyuk 			curr = curr->m_nextpkt;
156d18b4becSArseny Smalyuk 		curr->m_nextpkt = m;
157d18b4becSArseny Smalyuk 	} else
158d18b4becSArseny Smalyuk 		lle->la_hold = m;
159d18b4becSArseny Smalyuk 
160d18b4becSArseny Smalyuk 	lle->la_numheld++;
161d18b4becSArseny Smalyuk 
162d18b4becSArseny Smalyuk 	return pkts_dropped;
163d18b4becSArseny Smalyuk }
164d18b4becSArseny Smalyuk 
165d18b4becSArseny Smalyuk 
166d18b4becSArseny Smalyuk /*
16711cdad98SAlexander V. Chernikov  * Common function helpers for chained hash table.
16811cdad98SAlexander V. Chernikov  */
16911cdad98SAlexander V. Chernikov 
17011cdad98SAlexander V. Chernikov /*
17111cdad98SAlexander V. Chernikov  * Runs specified callback for each entry in @llt.
17211cdad98SAlexander V. Chernikov  * Caller does the locking.
17311cdad98SAlexander V. Chernikov  *
17411cdad98SAlexander V. Chernikov  */
17511cdad98SAlexander V. Chernikov static int
17611cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
17711cdad98SAlexander V. Chernikov {
17811cdad98SAlexander V. Chernikov 	struct llentry *lle, *next;
17911cdad98SAlexander V. Chernikov 	int i, error;
18011cdad98SAlexander V. Chernikov 
18111cdad98SAlexander V. Chernikov 	error = 0;
18211cdad98SAlexander V. Chernikov 
18341cb42a6SAlexander V. Chernikov 	for (i = 0; i < llt->llt_hsize; i++) {
1844f6c66ccSMatt Macy 		CK_LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
18511cdad98SAlexander V. Chernikov 			error = f(llt, lle, farg);
18611cdad98SAlexander V. Chernikov 			if (error != 0)
18711cdad98SAlexander V. Chernikov 				break;
18811cdad98SAlexander V. Chernikov 		}
18911cdad98SAlexander V. Chernikov 	}
19011cdad98SAlexander V. Chernikov 
19111cdad98SAlexander V. Chernikov 	return (error);
19211cdad98SAlexander V. Chernikov }
19311cdad98SAlexander V. Chernikov 
1943818c25aSBjoern A. Zeeb /*
1953818c25aSBjoern A. Zeeb  * The htable_[un]link_entry() functions return:
1963818c25aSBjoern A. Zeeb  * 0 if the entry was (un)linked already and nothing changed,
1973818c25aSBjoern A. Zeeb  * 1 if the entry was added/removed to/from the table, and
1983818c25aSBjoern A. Zeeb  * -1 on error (e.g., not being able to add the entry due to limits reached).
1993818c25aSBjoern A. Zeeb  * While the "unlink" operation should never error, callers of
2003818c25aSBjoern A. Zeeb  * lltable_link_entry() need to check for errors and handle them.
2013818c25aSBjoern A. Zeeb  */
2023818c25aSBjoern A. Zeeb static int
20311cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle)
20411cdad98SAlexander V. Chernikov {
20511cdad98SAlexander V. Chernikov 	struct llentries *lleh;
20611cdad98SAlexander V. Chernikov 	uint32_t hashidx;
20711cdad98SAlexander V. Chernikov 
20811cdad98SAlexander V. Chernikov 	if ((lle->la_flags & LLE_LINKED) != 0)
2093818c25aSBjoern A. Zeeb 		return (0);
21011cdad98SAlexander V. Chernikov 
21111cdad98SAlexander V. Chernikov 	IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
21211cdad98SAlexander V. Chernikov 
2133818c25aSBjoern A. Zeeb 	if (llt->llt_maxentries > 0 &&
2143818c25aSBjoern A. Zeeb 	    llt->llt_entries >= llt->llt_maxentries)
2153818c25aSBjoern A. Zeeb 		return (-1);
2163818c25aSBjoern A. Zeeb 
2173a749863SAlexander V. Chernikov 	hashidx = llt->llt_hash(lle, llt->llt_hsize);
21811cdad98SAlexander V. Chernikov 	lleh = &llt->lle_head[hashidx];
21911cdad98SAlexander V. Chernikov 
22011cdad98SAlexander V. Chernikov 	lle->lle_tbl  = llt;
22111cdad98SAlexander V. Chernikov 	lle->lle_head = lleh;
22211cdad98SAlexander V. Chernikov 	lle->la_flags |= LLE_LINKED;
2234f6c66ccSMatt Macy 	CK_LIST_INSERT_HEAD(lleh, lle, lle_next);
2243818c25aSBjoern A. Zeeb 	llt->llt_entries++;
2253818c25aSBjoern A. Zeeb 
2263818c25aSBjoern A. Zeeb 	return (1);
22711cdad98SAlexander V. Chernikov }
22811cdad98SAlexander V. Chernikov 
2293818c25aSBjoern A. Zeeb static int
23011cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle)
23111cdad98SAlexander V. Chernikov {
2323818c25aSBjoern A. Zeeb 	struct lltable *llt;
23311cdad98SAlexander V. Chernikov 
234d9a61c96SBjoern A. Zeeb 	if ((lle->la_flags & LLE_LINKED) == 0)
2353818c25aSBjoern A. Zeeb 		return (0);
236d9a61c96SBjoern A. Zeeb 
2373818c25aSBjoern A. Zeeb 	llt = lle->lle_tbl;
2383818c25aSBjoern A. Zeeb 	IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
2393818c25aSBjoern A. Zeeb 	KASSERT(llt->llt_entries > 0, ("%s: lltable %p (%s) entries %d <= 0",
2403818c25aSBjoern A. Zeeb 	    __func__, llt, if_name(llt->llt_ifp), llt->llt_entries));
2413818c25aSBjoern A. Zeeb 
2424f6c66ccSMatt Macy 	CK_LIST_REMOVE(lle, lle_next);
24311cdad98SAlexander V. Chernikov 	lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
24411cdad98SAlexander V. Chernikov #if 0
24511cdad98SAlexander V. Chernikov 	lle->lle_tbl = NULL;
24611cdad98SAlexander V. Chernikov 	lle->lle_head = NULL;
24711cdad98SAlexander V. Chernikov #endif
2483818c25aSBjoern A. Zeeb 	llt->llt_entries--;
2493818c25aSBjoern A. Zeeb 
2503818c25aSBjoern A. Zeeb 	return (1);
25111cdad98SAlexander V. Chernikov }
25211cdad98SAlexander V. Chernikov 
25311cdad98SAlexander V. Chernikov struct prefix_match_data {
2543e7a2321SAlexander V. Chernikov 	const struct sockaddr *addr;
25511cdad98SAlexander V. Chernikov 	const struct sockaddr *mask;
25611cdad98SAlexander V. Chernikov 	struct llentries dchain;
25711cdad98SAlexander V. Chernikov 	u_int flags;
25811cdad98SAlexander V. Chernikov };
25911cdad98SAlexander V. Chernikov 
26011cdad98SAlexander V. Chernikov static int
26111cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
26211cdad98SAlexander V. Chernikov {
26311cdad98SAlexander V. Chernikov 	struct prefix_match_data *pmd;
26411cdad98SAlexander V. Chernikov 
26511cdad98SAlexander V. Chernikov 	pmd = (struct prefix_match_data *)farg;
26611cdad98SAlexander V. Chernikov 
2673e7a2321SAlexander V. Chernikov 	if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
26811cdad98SAlexander V. Chernikov 		LLE_WLOCK(lle);
2690f8d79d9SMatt Macy 		CK_LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
27011cdad98SAlexander V. Chernikov 	}
27111cdad98SAlexander V. Chernikov 
27211cdad98SAlexander V. Chernikov 	return (0);
27311cdad98SAlexander V. Chernikov }
27411cdad98SAlexander V. Chernikov 
27511cdad98SAlexander V. Chernikov static void
2763e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
27711cdad98SAlexander V. Chernikov     const struct sockaddr *mask, u_int flags)
27811cdad98SAlexander V. Chernikov {
27911cdad98SAlexander V. Chernikov 	struct llentry *lle, *next;
28011cdad98SAlexander V. Chernikov 	struct prefix_match_data pmd;
28111cdad98SAlexander V. Chernikov 
28211cdad98SAlexander V. Chernikov 	bzero(&pmd, sizeof(pmd));
2833e7a2321SAlexander V. Chernikov 	pmd.addr = addr;
28411cdad98SAlexander V. Chernikov 	pmd.mask = mask;
28511cdad98SAlexander V. Chernikov 	pmd.flags = flags;
2864f6c66ccSMatt Macy 	CK_LIST_INIT(&pmd.dchain);
28711cdad98SAlexander V. Chernikov 
28811cdad98SAlexander V. Chernikov 	IF_AFDATA_WLOCK(llt->llt_ifp);
28911cdad98SAlexander V. Chernikov 	/* Push matching lles to chain */
29011cdad98SAlexander V. Chernikov 	lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
29111cdad98SAlexander V. Chernikov 
29211cdad98SAlexander V. Chernikov 	llentries_unlink(llt, &pmd.dchain);
29311cdad98SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
29411cdad98SAlexander V. Chernikov 
2950f8d79d9SMatt Macy 	CK_LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
2965a255516SAlexander V. Chernikov 		lltable_free_entry(llt, lle);
29711cdad98SAlexander V. Chernikov }
29811cdad98SAlexander V. Chernikov 
29911cdad98SAlexander V. Chernikov static void
30041cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt)
30141cb42a6SAlexander V. Chernikov {
30241cb42a6SAlexander V. Chernikov 
30341cb42a6SAlexander V. Chernikov 	free(llt->lle_head, M_LLTABLE);
30441cb42a6SAlexander V. Chernikov 	free(llt, M_LLTABLE);
30541cb42a6SAlexander V. Chernikov }
30641cb42a6SAlexander V. Chernikov 
307721cd2e0SAlexander V. Chernikov static void
30811cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head)
30911cdad98SAlexander V. Chernikov {
31011cdad98SAlexander V. Chernikov 	struct llentry *lle, *next;
31111cdad98SAlexander V. Chernikov 
3120f8d79d9SMatt Macy 	CK_LIST_FOREACH_SAFE(lle, head, lle_chain, next)
31311cdad98SAlexander V. Chernikov 		llt->llt_unlink_entry(lle);
31411cdad98SAlexander V. Chernikov }
31511cdad98SAlexander V. Chernikov 
31611cdad98SAlexander V. Chernikov /*
31711cdad98SAlexander V. Chernikov  * Helper function used to drop all mbufs in hold queue.
318e162ea60SGeorge V. Neville-Neil  *
319e162ea60SGeorge V. Neville-Neil  * Returns the number of held packets, if any, that were dropped.
32082f39c91SKip Macy  */
321e162ea60SGeorge V. Neville-Neil size_t
32211cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle)
32382f39c91SKip Macy {
324d18b4becSArseny Smalyuk 	size_t pkts_dropped = 0;
32582f39c91SKip Macy 
32682f39c91SKip Macy 	LLE_WLOCK_ASSERT(lle);
32782f39c91SKip Macy 
328d18b4becSArseny Smalyuk 	while (lle->la_hold != NULL) {
329d18b4becSArseny Smalyuk 		struct mbuf *next = lle->la_hold->m_nextpkt;
33082f39c91SKip Macy 		m_freem(lle->la_hold);
331e162ea60SGeorge V. Neville-Neil 		lle->la_hold = next;
332e162ea60SGeorge V. Neville-Neil 		lle->la_numheld--;
333e162ea60SGeorge V. Neville-Neil 		pkts_dropped++;
334e162ea60SGeorge V. Neville-Neil 	}
335e162ea60SGeorge V. Neville-Neil 
336e162ea60SGeorge V. Neville-Neil 	KASSERT(lle->la_numheld == 0,
3374f493559SGordon Bergling 		("%s: la_numheld %d > 0, pkts_dropped %zd", __func__,
338e162ea60SGeorge V. Neville-Neil 		 lle->la_numheld, pkts_dropped));
33982f39c91SKip Macy 
34011cdad98SAlexander V. Chernikov 	return (pkts_dropped);
34111cdad98SAlexander V. Chernikov }
34211cdad98SAlexander V. Chernikov 
343ddd208f7SAlexander V. Chernikov void
344ddd208f7SAlexander V. Chernikov lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
3454fb3a820SAlexander V. Chernikov     const char *linkhdr, size_t linkhdrsize, int lladdr_off)
346ddd208f7SAlexander V. Chernikov {
347ddd208f7SAlexander V. Chernikov 
3484fb3a820SAlexander V. Chernikov 	memcpy(lle->r_linkdata, linkhdr, linkhdrsize);
3494fb3a820SAlexander V. Chernikov 	lle->r_hdrlen = linkhdrsize;
3504fb3a820SAlexander V. Chernikov 	lle->ll_addr = &lle->r_linkdata[lladdr_off];
351ddd208f7SAlexander V. Chernikov 	lle->la_flags |= LLE_VALID;
352f8aee88fSAlexander V. Chernikov 	lle->r_flags |= RLLE_VALID;
353ddd208f7SAlexander V. Chernikov }
354ddd208f7SAlexander V. Chernikov 
35511cdad98SAlexander V. Chernikov /*
3560b79b007SAlexander V. Chernikov  * Acquires lltable write lock.
3570b79b007SAlexander V. Chernikov  *
3580b79b007SAlexander V. Chernikov  * Returns true on success, with both lltable and lle lock held.
3590b79b007SAlexander V. Chernikov  * On failure, false is returned and lle wlock is still held.
3600b79b007SAlexander V. Chernikov  */
3610b79b007SAlexander V. Chernikov bool
3620b79b007SAlexander V. Chernikov lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle)
3630b79b007SAlexander V. Chernikov {
3640b79b007SAlexander V. Chernikov 	NET_EPOCH_ASSERT();
3650b79b007SAlexander V. Chernikov 
3660b79b007SAlexander V. Chernikov 	/* Perform real LLE update */
3670b79b007SAlexander V. Chernikov 	/* use afdata WLOCK to update fields */
3680b79b007SAlexander V. Chernikov 	LLE_WUNLOCK(lle);
3690b79b007SAlexander V. Chernikov 	IF_AFDATA_WLOCK(ifp);
3700b79b007SAlexander V. Chernikov 	LLE_WLOCK(lle);
3710b79b007SAlexander V. Chernikov 
3720b79b007SAlexander V. Chernikov 	/*
3730b79b007SAlexander V. Chernikov 	 * Since we droppped LLE lock, other thread might have deleted
3740b79b007SAlexander V. Chernikov 	 * this lle. Check and return
3750b79b007SAlexander V. Chernikov 	 */
3760b79b007SAlexander V. Chernikov 	if ((lle->la_flags & LLE_DELETED) != 0) {
3770b79b007SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
3780b79b007SAlexander V. Chernikov 		return (false);
3790b79b007SAlexander V. Chernikov 	}
3800b79b007SAlexander V. Chernikov 
3810b79b007SAlexander V. Chernikov 	return (true);
3820b79b007SAlexander V. Chernikov }
3830b79b007SAlexander V. Chernikov 
3840b79b007SAlexander V. Chernikov /*
38512cb7521SAlexander V. Chernikov  * Tries to update @lle link-level address.
38612cb7521SAlexander V. Chernikov  * Since update requires AFDATA WLOCK, function
38712cb7521SAlexander V. Chernikov  * drops @lle lock, acquires AFDATA lock and then acquires
38812cb7521SAlexander V. Chernikov  * @lle lock to maintain lock order.
38912cb7521SAlexander V. Chernikov  *
39012cb7521SAlexander V. Chernikov  * Returns 1 on success.
39112cb7521SAlexander V. Chernikov  */
39212cb7521SAlexander V. Chernikov int
39312cb7521SAlexander V. Chernikov lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
3944fb3a820SAlexander V. Chernikov     const char *linkhdr, size_t linkhdrsize, int lladdr_off)
39512cb7521SAlexander V. Chernikov {
39612cb7521SAlexander V. Chernikov 
3970b79b007SAlexander V. Chernikov 	if (!lltable_acquire_wlock(ifp, lle))
39812cb7521SAlexander V. Chernikov 		return (0);
39912cb7521SAlexander V. Chernikov 
40012cb7521SAlexander V. Chernikov 	/* Update data */
4014fb3a820SAlexander V. Chernikov 	lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off);
40212cb7521SAlexander V. Chernikov 
40312cb7521SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(ifp);
40412cb7521SAlexander V. Chernikov 
40512cb7521SAlexander V. Chernikov 	return (1);
40612cb7521SAlexander V. Chernikov }
40712cb7521SAlexander V. Chernikov 
40812cb7521SAlexander V. Chernikov  /*
4094fb3a820SAlexander V. Chernikov  * Helper function used to pre-compute full/partial link-layer
4104fb3a820SAlexander V. Chernikov  * header data suitable for feeding into if_output().
4114fb3a820SAlexander V. Chernikov  */
4124fb3a820SAlexander V. Chernikov int
4134fb3a820SAlexander V. Chernikov lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr,
4144fb3a820SAlexander V. Chernikov     char *buf, size_t *bufsize, int *lladdr_off)
4154fb3a820SAlexander V. Chernikov {
4164fb3a820SAlexander V. Chernikov 	struct if_encap_req ereq;
4174fb3a820SAlexander V. Chernikov 	int error;
4184fb3a820SAlexander V. Chernikov 
4194fb3a820SAlexander V. Chernikov 	bzero(buf, *bufsize);
4204fb3a820SAlexander V. Chernikov 	bzero(&ereq, sizeof(ereq));
4214fb3a820SAlexander V. Chernikov 	ereq.buf = buf;
4224fb3a820SAlexander V. Chernikov 	ereq.bufsize = *bufsize;
4234fb3a820SAlexander V. Chernikov 	ereq.rtype = IFENCAP_LL;
4244fb3a820SAlexander V. Chernikov 	ereq.family = family;
4254fb3a820SAlexander V. Chernikov 	ereq.lladdr = lladdr;
4264fb3a820SAlexander V. Chernikov 	ereq.lladdr_len = ifp->if_addrlen;
4274fb3a820SAlexander V. Chernikov 	error = ifp->if_requestencap(ifp, &ereq);
4284fb3a820SAlexander V. Chernikov 	if (error == 0) {
4294fb3a820SAlexander V. Chernikov 		*bufsize = ereq.bufsize;
4304fb3a820SAlexander V. Chernikov 		*lladdr_off = ereq.lladdr_off;
4314fb3a820SAlexander V. Chernikov 	}
4324fb3a820SAlexander V. Chernikov 
4334fb3a820SAlexander V. Chernikov 	return (error);
4344fb3a820SAlexander V. Chernikov }
4354fb3a820SAlexander V. Chernikov 
4364fb3a820SAlexander V. Chernikov /*
437c541bd36SAlexander V. Chernikov  * Searches for the child entry matching @family inside @lle.
438c541bd36SAlexander V. Chernikov  * Returns the entry or NULL.
439c541bd36SAlexander V. Chernikov  */
440c541bd36SAlexander V. Chernikov struct llentry *
441c541bd36SAlexander V. Chernikov llentry_lookup_family(struct llentry *lle, int family)
442c541bd36SAlexander V. Chernikov {
443c541bd36SAlexander V. Chernikov 	struct llentry *child_lle;
444c541bd36SAlexander V. Chernikov 
445c541bd36SAlexander V. Chernikov 	if (lle == NULL)
446c541bd36SAlexander V. Chernikov 		return (NULL);
447c541bd36SAlexander V. Chernikov 
448c541bd36SAlexander V. Chernikov 	CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) {
449c541bd36SAlexander V. Chernikov 		if (child_lle->r_family == family)
450c541bd36SAlexander V. Chernikov 			return (child_lle);
451c541bd36SAlexander V. Chernikov 	}
452c541bd36SAlexander V. Chernikov 
453c541bd36SAlexander V. Chernikov 	return (NULL);
454c541bd36SAlexander V. Chernikov }
455c541bd36SAlexander V. Chernikov 
456c541bd36SAlexander V. Chernikov /*
45763f7f392SAlexander V. Chernikov  * Retrieves upper protocol family for the llentry.
45863f7f392SAlexander V. Chernikov  * By default, all "normal" (e.g. upper_family == transport_family)
45963f7f392SAlexander V. Chernikov  * llentries have r_family set to 0.
46063f7f392SAlexander V. Chernikov  * Thus, use @default_family in that regard, otherwise use r_family.
46163f7f392SAlexander V. Chernikov  *
46263f7f392SAlexander V. Chernikov  * Returns upper protocol family
46363f7f392SAlexander V. Chernikov  */
46463f7f392SAlexander V. Chernikov int
46563f7f392SAlexander V. Chernikov llentry_get_upper_family(const struct llentry *lle, int default_family)
46663f7f392SAlexander V. Chernikov {
46763f7f392SAlexander V. Chernikov 	return (lle->r_family == 0 ? default_family : lle->r_family);
46863f7f392SAlexander V. Chernikov }
46963f7f392SAlexander V. Chernikov 
47063f7f392SAlexander V. Chernikov /*
47163f7f392SAlexander V. Chernikov  * Prints llentry @lle data into provided buffer.
47263f7f392SAlexander V. Chernikov  * Example: lle/inet/valid/em0/1.2.3.4
47363f7f392SAlexander V. Chernikov  *
47463f7f392SAlexander V. Chernikov  * Returns @buf.
47563f7f392SAlexander V. Chernikov  */
47663f7f392SAlexander V. Chernikov char *
47763f7f392SAlexander V. Chernikov llentry_print_buf(const struct llentry *lle, struct ifnet *ifp, int family,
47863f7f392SAlexander V. Chernikov     char *buf, size_t bufsize)
47963f7f392SAlexander V. Chernikov {
480a6668e31SEd Maste #if defined(INET) || defined(INET6)
48163f7f392SAlexander V. Chernikov 	char abuf[INET6_ADDRSTRLEN];
482a6668e31SEd Maste #endif
48363f7f392SAlexander V. Chernikov 
48463f7f392SAlexander V. Chernikov 	const char *valid = (lle->r_flags & RLLE_VALID) ? "valid" : "no_l2";
48563f7f392SAlexander V. Chernikov 	const char *upper_str = rib_print_family(llentry_get_upper_family(lle, family));
48663f7f392SAlexander V. Chernikov 
48763f7f392SAlexander V. Chernikov 	switch (family) {
48863f7f392SAlexander V. Chernikov #ifdef INET
48963f7f392SAlexander V. Chernikov 	case AF_INET:
49063f7f392SAlexander V. Chernikov 		inet_ntop(AF_INET, &lle->r_l3addr.addr4, abuf, sizeof(abuf));
49163f7f392SAlexander V. Chernikov 		snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str,
49263f7f392SAlexander V. Chernikov 		    valid, if_name(ifp), abuf);
49363f7f392SAlexander V. Chernikov 		break;
49463f7f392SAlexander V. Chernikov #endif
49563f7f392SAlexander V. Chernikov #ifdef INET6
49663f7f392SAlexander V. Chernikov 	case AF_INET6:
49763f7f392SAlexander V. Chernikov 		inet_ntop(AF_INET6, &lle->r_l3addr.addr6, abuf, sizeof(abuf));
49863f7f392SAlexander V. Chernikov 		snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str,
49963f7f392SAlexander V. Chernikov 		    valid, if_name(ifp), abuf);
50063f7f392SAlexander V. Chernikov 		break;
50163f7f392SAlexander V. Chernikov #endif
50263f7f392SAlexander V. Chernikov 	default:
50363f7f392SAlexander V. Chernikov 		snprintf(buf, bufsize, "lle/%s/%s/%s/????", upper_str,
50463f7f392SAlexander V. Chernikov 		    valid, if_name(ifp));
50563f7f392SAlexander V. Chernikov 		break;
50663f7f392SAlexander V. Chernikov 	}
50763f7f392SAlexander V. Chernikov 
50863f7f392SAlexander V. Chernikov 	return (buf);
50963f7f392SAlexander V. Chernikov }
51063f7f392SAlexander V. Chernikov 
51163f7f392SAlexander V. Chernikov char *
51263f7f392SAlexander V. Chernikov llentry_print_buf_lltable(const struct llentry *lle, char *buf, size_t bufsize)
51363f7f392SAlexander V. Chernikov {
51463f7f392SAlexander V. Chernikov 	struct lltable *tbl = lle->lle_tbl;
51563f7f392SAlexander V. Chernikov 
51663f7f392SAlexander V. Chernikov 	return (llentry_print_buf(lle, lltable_get_ifp(tbl), lltable_get_af(tbl), buf, bufsize));
51763f7f392SAlexander V. Chernikov }
51863f7f392SAlexander V. Chernikov 
51963f7f392SAlexander V. Chernikov /*
520f3a3b061SAlexander V. Chernikov  * Requests feedback from the datapath.
521f3a3b061SAlexander V. Chernikov  * First packet using @lle should result in
522f3a3b061SAlexander V. Chernikov  * setting r_skip_req back to 0 and updating
523f3a3b061SAlexander V. Chernikov  * lle_hittime to the current time_uptime.
524f3a3b061SAlexander V. Chernikov  */
525f3a3b061SAlexander V. Chernikov void
526f3a3b061SAlexander V. Chernikov llentry_request_feedback(struct llentry *lle)
527f3a3b061SAlexander V. Chernikov {
528c541bd36SAlexander V. Chernikov 	struct llentry *child_lle;
529c541bd36SAlexander V. Chernikov 
530f3a3b061SAlexander V. Chernikov 	LLE_REQ_LOCK(lle);
531f3a3b061SAlexander V. Chernikov 	lle->r_skip_req = 1;
532f3a3b061SAlexander V. Chernikov 	LLE_REQ_UNLOCK(lle);
533c541bd36SAlexander V. Chernikov 
534c541bd36SAlexander V. Chernikov 	CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) {
535c541bd36SAlexander V. Chernikov 		LLE_REQ_LOCK(child_lle);
536c541bd36SAlexander V. Chernikov 		child_lle->r_skip_req = 1;
537c541bd36SAlexander V. Chernikov 		LLE_REQ_UNLOCK(child_lle);
538c541bd36SAlexander V. Chernikov 	}
539f3a3b061SAlexander V. Chernikov }
540f3a3b061SAlexander V. Chernikov 
541f3a3b061SAlexander V. Chernikov /*
542f3a3b061SAlexander V. Chernikov  * Updates the lle state to mark it has been used
543f3a3b061SAlexander V. Chernikov  * and record the time.
544f3a3b061SAlexander V. Chernikov  * Used by the llentry_provide_feedback() wrapper.
545f3a3b061SAlexander V. Chernikov  */
546f3a3b061SAlexander V. Chernikov void
547f3a3b061SAlexander V. Chernikov llentry_mark_used(struct llentry *lle)
548f3a3b061SAlexander V. Chernikov {
549f3a3b061SAlexander V. Chernikov 	LLE_REQ_LOCK(lle);
550f3a3b061SAlexander V. Chernikov 	lle->r_skip_req = 0;
551f3a3b061SAlexander V. Chernikov 	lle->lle_hittime = time_uptime;
552f3a3b061SAlexander V. Chernikov 	LLE_REQ_UNLOCK(lle);
553f3a3b061SAlexander V. Chernikov }
554f3a3b061SAlexander V. Chernikov 
555f3a3b061SAlexander V. Chernikov /*
556f3a3b061SAlexander V. Chernikov  * Fetches the time when lle was used.
557f3a3b061SAlexander V. Chernikov  * Return 0 if the entry was not used, relevant time_uptime
558f3a3b061SAlexander V. Chernikov  *  otherwise.
559f3a3b061SAlexander V. Chernikov  */
560c541bd36SAlexander V. Chernikov static time_t
561c541bd36SAlexander V. Chernikov llentry_get_hittime_raw(struct llentry *lle)
562f3a3b061SAlexander V. Chernikov {
563f3a3b061SAlexander V. Chernikov 	time_t lle_hittime = 0;
564f3a3b061SAlexander V. Chernikov 
565f3a3b061SAlexander V. Chernikov 	LLE_REQ_LOCK(lle);
566f3a3b061SAlexander V. Chernikov 	if ((lle->r_skip_req == 0) && (lle_hittime < lle->lle_hittime))
567f3a3b061SAlexander V. Chernikov 		lle_hittime = lle->lle_hittime;
568f3a3b061SAlexander V. Chernikov 	LLE_REQ_UNLOCK(lle);
569f3a3b061SAlexander V. Chernikov 
570f3a3b061SAlexander V. Chernikov 	return (lle_hittime);
571f3a3b061SAlexander V. Chernikov }
572f3a3b061SAlexander V. Chernikov 
573c541bd36SAlexander V. Chernikov time_t
574c541bd36SAlexander V. Chernikov llentry_get_hittime(struct llentry *lle)
575c541bd36SAlexander V. Chernikov {
576c541bd36SAlexander V. Chernikov 	time_t lle_hittime = 0;
577c541bd36SAlexander V. Chernikov 	struct llentry *child_lle;
578c541bd36SAlexander V. Chernikov 
579c541bd36SAlexander V. Chernikov 	lle_hittime = llentry_get_hittime_raw(lle);
580c541bd36SAlexander V. Chernikov 
581c541bd36SAlexander V. Chernikov 	CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) {
582c541bd36SAlexander V. Chernikov 		time_t hittime = llentry_get_hittime_raw(child_lle);
583c541bd36SAlexander V. Chernikov 		if (hittime > lle_hittime)
584c541bd36SAlexander V. Chernikov 			lle_hittime = hittime;
585c541bd36SAlexander V. Chernikov 	}
586c541bd36SAlexander V. Chernikov 
587c541bd36SAlexander V. Chernikov 	return (lle_hittime);
588c541bd36SAlexander V. Chernikov }
589c541bd36SAlexander V. Chernikov 
590f3a3b061SAlexander V. Chernikov /*
5914fb3a820SAlexander V. Chernikov  * Update link-layer header for given @lle after
5924fb3a820SAlexander V. Chernikov  * interface lladdr was changed.
5934fb3a820SAlexander V. Chernikov  */
5944fb3a820SAlexander V. Chernikov static int
5954fb3a820SAlexander V. Chernikov llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg)
5964fb3a820SAlexander V. Chernikov {
5974fb3a820SAlexander V. Chernikov 	struct ifnet *ifp;
5984fb3a820SAlexander V. Chernikov 	u_char linkhdr[LLE_MAX_LINKHDR];
5994fb3a820SAlexander V. Chernikov 	size_t linkhdrsize;
6004fb3a820SAlexander V. Chernikov 	u_char *lladdr;
6014fb3a820SAlexander V. Chernikov 	int lladdr_off;
6024fb3a820SAlexander V. Chernikov 
6034fb3a820SAlexander V. Chernikov 	ifp = (struct ifnet *)farg;
6044fb3a820SAlexander V. Chernikov 
6054fb3a820SAlexander V. Chernikov 	lladdr = lle->ll_addr;
6064fb3a820SAlexander V. Chernikov 
6074fb3a820SAlexander V. Chernikov 	LLE_WLOCK(lle);
6084fb3a820SAlexander V. Chernikov 	if ((lle->la_flags & LLE_VALID) == 0) {
6094fb3a820SAlexander V. Chernikov 		LLE_WUNLOCK(lle);
6104fb3a820SAlexander V. Chernikov 		return (0);
6114fb3a820SAlexander V. Chernikov 	}
6124fb3a820SAlexander V. Chernikov 
6134fb3a820SAlexander V. Chernikov 	if ((lle->la_flags & LLE_IFADDR) != 0)
6144fb3a820SAlexander V. Chernikov 		lladdr = IF_LLADDR(ifp);
6154fb3a820SAlexander V. Chernikov 
6164fb3a820SAlexander V. Chernikov 	linkhdrsize = sizeof(linkhdr);
6174fb3a820SAlexander V. Chernikov 	lltable_calc_llheader(ifp, llt->llt_af, lladdr, linkhdr, &linkhdrsize,
6184fb3a820SAlexander V. Chernikov 	    &lladdr_off);
6194fb3a820SAlexander V. Chernikov 	memcpy(lle->r_linkdata, linkhdr, linkhdrsize);
6204fb3a820SAlexander V. Chernikov 	LLE_WUNLOCK(lle);
6214fb3a820SAlexander V. Chernikov 
6224fb3a820SAlexander V. Chernikov 	return (0);
6234fb3a820SAlexander V. Chernikov }
6244fb3a820SAlexander V. Chernikov 
6254fb3a820SAlexander V. Chernikov /*
6264fb3a820SAlexander V. Chernikov  * Update all calculated headers for given @llt
6274fb3a820SAlexander V. Chernikov  */
6284fb3a820SAlexander V. Chernikov void
6294fb3a820SAlexander V. Chernikov lltable_update_ifaddr(struct lltable *llt)
6304fb3a820SAlexander V. Chernikov {
6314fb3a820SAlexander V. Chernikov 
6324fb3a820SAlexander V. Chernikov 	if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
6334fb3a820SAlexander V. Chernikov 		return;
6344fb3a820SAlexander V. Chernikov 
6354fb3a820SAlexander V. Chernikov 	IF_AFDATA_WLOCK(llt->llt_ifp);
6364fb3a820SAlexander V. Chernikov 	lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp);
6374fb3a820SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
6384fb3a820SAlexander V. Chernikov }
6394fb3a820SAlexander V. Chernikov 
6404fb3a820SAlexander V. Chernikov /*
6415a255516SAlexander V. Chernikov  *
642a4641f4eSPedro F. Giffuni  * Performs generic cleanup routines and frees lle.
6435a255516SAlexander V. Chernikov  *
6445a255516SAlexander V. Chernikov  * Called for non-linked entries, with callouts and
6455a255516SAlexander V. Chernikov  * other AF-specific cleanups performed.
6465a255516SAlexander V. Chernikov  *
6475a255516SAlexander V. Chernikov  * @lle must be passed WLOCK'ed
64811cdad98SAlexander V. Chernikov  *
64911cdad98SAlexander V. Chernikov  * Returns the number of held packets, if any, that were dropped.
65011cdad98SAlexander V. Chernikov  */
65111cdad98SAlexander V. Chernikov size_t
65211cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle)
65311cdad98SAlexander V. Chernikov {
65411cdad98SAlexander V. Chernikov 	size_t pkts_dropped;
65511cdad98SAlexander V. Chernikov 
65611cdad98SAlexander V. Chernikov 	LLE_WLOCK_ASSERT(lle);
65711cdad98SAlexander V. Chernikov 
658d3cdb716SAlexander V. Chernikov 	KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle"));
65911cdad98SAlexander V. Chernikov 
66011cdad98SAlexander V. Chernikov 	pkts_dropped = lltable_drop_entry_queue(lle);
66111cdad98SAlexander V. Chernikov 
662acf673edSAndrey V. Elsukov 	/* cancel timer */
663acf673edSAndrey V. Elsukov 	if (callout_stop(&lle->lle_timer) > 0)
664acf673edSAndrey V. Elsukov 		LLE_REMREF(lle);
66582f39c91SKip Macy 	LLE_FREE_LOCKED(lle);
666e162ea60SGeorge V. Neville-Neil 
667e162ea60SGeorge V. Neville-Neil 	return (pkts_dropped);
66882f39c91SKip Macy }
66982f39c91SKip Macy 
670adfc35ffSKip Macy /*
67182f39c91SKip Macy  * Free all entries from given table and free itself.
67282f39c91SKip Macy  */
67311cdad98SAlexander V. Chernikov 
67411cdad98SAlexander V. Chernikov static int
67511cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
67611cdad98SAlexander V. Chernikov {
67711cdad98SAlexander V. Chernikov 	struct llentries *dchain;
67811cdad98SAlexander V. Chernikov 
67911cdad98SAlexander V. Chernikov 	dchain = (struct llentries *)farg;
68011cdad98SAlexander V. Chernikov 
68111cdad98SAlexander V. Chernikov 	LLE_WLOCK(lle);
6820f8d79d9SMatt Macy 	CK_LIST_INSERT_HEAD(dchain, lle, lle_chain);
68311cdad98SAlexander V. Chernikov 
68411cdad98SAlexander V. Chernikov 	return (0);
68511cdad98SAlexander V. Chernikov }
68611cdad98SAlexander V. Chernikov 
68711cdad98SAlexander V. Chernikov /*
68811cdad98SAlexander V. Chernikov  * Free all entries from given table and free itself.
68911cdad98SAlexander V. Chernikov  */
69082f39c91SKip Macy void
69182f39c91SKip Macy lltable_free(struct lltable *llt)
69282f39c91SKip Macy {
69382f39c91SKip Macy 	struct llentry *lle, *next;
69411cdad98SAlexander V. Chernikov 	struct llentries dchain;
69582f39c91SKip Macy 
69682f39c91SKip Macy 	KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
69782f39c91SKip Macy 
698721cd2e0SAlexander V. Chernikov 	lltable_unlink(llt);
69982f39c91SKip Macy 
7004f6c66ccSMatt Macy 	CK_LIST_INIT(&dchain);
701ea537929SGleb Smirnoff 	IF_AFDATA_WLOCK(llt->llt_ifp);
70211cdad98SAlexander V. Chernikov 	/* Push all lles to @dchain */
70311cdad98SAlexander V. Chernikov 	lltable_foreach_lle(llt, lltable_free_cb, &dchain);
70411cdad98SAlexander V. Chernikov 	llentries_unlink(llt, &dchain);
70511cdad98SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
70611cdad98SAlexander V. Chernikov 
7070f8d79d9SMatt Macy 	CK_LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
70882f39c91SKip Macy 		llentry_free(lle);
70982f39c91SKip Macy 	}
71082f39c91SKip Macy 
7113818c25aSBjoern A. Zeeb 	KASSERT(llt->llt_entries == 0, ("%s: lltable %p (%s) entires not 0: %d",
7123818c25aSBjoern A. Zeeb 	    __func__, llt, llt->llt_ifp->if_xname, llt->llt_entries));
7133818c25aSBjoern A. Zeeb 
714721cd2e0SAlexander V. Chernikov 	llt->llt_free_tbl(llt);
71582f39c91SKip Macy }
71682f39c91SKip Macy 
7173e7a2321SAlexander V. Chernikov /*
7183e7a2321SAlexander V. Chernikov  * Deletes an address from given lltable.
7193e7a2321SAlexander V. Chernikov  * Used for userland interaction to remove
7203e7a2321SAlexander V. Chernikov  * individual entries. Skips entries added by OS.
7213e7a2321SAlexander V. Chernikov  */
7223e7a2321SAlexander V. Chernikov int
7233e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags,
7243e7a2321SAlexander V. Chernikov     const struct sockaddr *l3addr)
7253e7a2321SAlexander V. Chernikov {
7263e7a2321SAlexander V. Chernikov 	struct llentry *lle;
7273e7a2321SAlexander V. Chernikov 	struct ifnet *ifp;
7283e7a2321SAlexander V. Chernikov 
7293e7a2321SAlexander V. Chernikov 	ifp = llt->llt_ifp;
7303e7a2321SAlexander V. Chernikov 	IF_AFDATA_WLOCK(ifp);
731c541bd36SAlexander V. Chernikov 	lle = lla_lookup(llt, LLE_SF(l3addr->sa_family, LLE_EXCLUSIVE), l3addr);
7323e7a2321SAlexander V. Chernikov 
7333e7a2321SAlexander V. Chernikov 	if (lle == NULL) {
7343e7a2321SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
7353e7a2321SAlexander V. Chernikov 		return (ENOENT);
7363e7a2321SAlexander V. Chernikov 	}
7373e7a2321SAlexander V. Chernikov 	if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
7383e7a2321SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
7393e7a2321SAlexander V. Chernikov 		LLE_WUNLOCK(lle);
7403e7a2321SAlexander V. Chernikov 		return (EPERM);
7413e7a2321SAlexander V. Chernikov 	}
7423e7a2321SAlexander V. Chernikov 
7433e7a2321SAlexander V. Chernikov 	lltable_unlink_entry(llt, lle);
7443e7a2321SAlexander V. Chernikov 	IF_AFDATA_WUNLOCK(ifp);
7453e7a2321SAlexander V. Chernikov 
7463e7a2321SAlexander V. Chernikov 	llt->llt_delete_entry(llt, lle);
7473e7a2321SAlexander V. Chernikov 
7483e7a2321SAlexander V. Chernikov 	return (0);
7493e7a2321SAlexander V. Chernikov }
7503e7a2321SAlexander V. Chernikov 
751c9d763bfSQing Li void
7523e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
7535b84dc78SQing Li     u_int flags)
754c9d763bfSQing Li {
755c9d763bfSQing Li 	struct lltable *llt;
756c9d763bfSQing Li 
757199511bcSAndrey V. Elsukov 	LLTABLE_LIST_RLOCK();
758989e0411SMarko Zec 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
759c9d763bfSQing Li 		if (llt->llt_af != af)
760c9d763bfSQing Li 			continue;
761c9d763bfSQing Li 
7623e7a2321SAlexander V. Chernikov 		llt->llt_prefix_free(llt, addr, mask, flags);
763c9d763bfSQing Li 	}
764199511bcSAndrey V. Elsukov 	LLTABLE_LIST_RUNLOCK();
765c9d763bfSQing Li }
766c9d763bfSQing Li 
767d6cd20ccSKUROSAWA Takahiro /*
768d6cd20ccSKUROSAWA Takahiro  * Delete llentries that func() returns true.
769d6cd20ccSKUROSAWA Takahiro  */
770d6cd20ccSKUROSAWA Takahiro struct lle_match_data {
771d6cd20ccSKUROSAWA Takahiro 	struct llentries dchain;
772d6cd20ccSKUROSAWA Takahiro 	llt_match_cb_t *func;
773d6cd20ccSKUROSAWA Takahiro 	void *farg;
774d6cd20ccSKUROSAWA Takahiro };
775d6cd20ccSKUROSAWA Takahiro 
776d6cd20ccSKUROSAWA Takahiro static int
777d6cd20ccSKUROSAWA Takahiro lltable_delete_conditional_cb(struct lltable *llt, struct llentry *lle,
778d6cd20ccSKUROSAWA Takahiro     void *farg)
779d6cd20ccSKUROSAWA Takahiro {
780d6cd20ccSKUROSAWA Takahiro 	struct lle_match_data *lmd;
781d6cd20ccSKUROSAWA Takahiro 
782d6cd20ccSKUROSAWA Takahiro 	lmd = (struct lle_match_data *)farg;
783d6cd20ccSKUROSAWA Takahiro 	if (lmd->func(llt, lle, lmd->farg)) {
784d6cd20ccSKUROSAWA Takahiro 		LLE_WLOCK(lle);
785d6cd20ccSKUROSAWA Takahiro 		CK_LIST_INSERT_HEAD(&lmd->dchain, lle, lle_chain);
786d6cd20ccSKUROSAWA Takahiro 	}
787d6cd20ccSKUROSAWA Takahiro 
788d6cd20ccSKUROSAWA Takahiro 	return (0);
789d6cd20ccSKUROSAWA Takahiro }
790d6cd20ccSKUROSAWA Takahiro 
791d6cd20ccSKUROSAWA Takahiro void
792d6cd20ccSKUROSAWA Takahiro lltable_delete_conditional(struct lltable *llt, llt_match_cb_t *func,
793d6cd20ccSKUROSAWA Takahiro     void *farg)
794d6cd20ccSKUROSAWA Takahiro {
795d6cd20ccSKUROSAWA Takahiro 	struct llentry *lle, *next;
796d6cd20ccSKUROSAWA Takahiro 	struct lle_match_data lmd;
797d6cd20ccSKUROSAWA Takahiro 
798d6cd20ccSKUROSAWA Takahiro 	bzero(&lmd, sizeof(lmd));
799d6cd20ccSKUROSAWA Takahiro 	CK_LIST_INIT(&lmd.dchain);
800d6cd20ccSKUROSAWA Takahiro 	lmd.func = func;
801d6cd20ccSKUROSAWA Takahiro 	lmd.farg = farg;
802d6cd20ccSKUROSAWA Takahiro 
803d6cd20ccSKUROSAWA Takahiro 	IF_AFDATA_WLOCK(llt->llt_ifp);
804d6cd20ccSKUROSAWA Takahiro 	lltable_foreach_lle(llt, lltable_delete_conditional_cb, &lmd);
805d6cd20ccSKUROSAWA Takahiro 	llentries_unlink(llt, &lmd.dchain);
806d6cd20ccSKUROSAWA Takahiro 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
807d6cd20ccSKUROSAWA Takahiro 
808d6cd20ccSKUROSAWA Takahiro 	CK_LIST_FOREACH_SAFE(lle, &lmd.dchain, lle_chain, next)
809d6cd20ccSKUROSAWA Takahiro 		llt->llt_delete_entry(llt, lle);
810d6cd20ccSKUROSAWA Takahiro }
811d6cd20ccSKUROSAWA Takahiro 
81282f39c91SKip Macy struct lltable *
81341cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize)
81482f39c91SKip Macy {
81582f39c91SKip Macy 	struct lltable *llt;
81641cb42a6SAlexander V. Chernikov 	int i;
81782f39c91SKip Macy 
81841cb42a6SAlexander V. Chernikov 	llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
81941cb42a6SAlexander V. Chernikov 	llt->llt_hsize = hsize;
82041cb42a6SAlexander V. Chernikov 	llt->lle_head = malloc(sizeof(struct llentries) * hsize,
82141cb42a6SAlexander V. Chernikov 	    M_LLTABLE, M_WAITOK | M_ZERO);
82282f39c91SKip Macy 
82341cb42a6SAlexander V. Chernikov 	for (i = 0; i < llt->llt_hsize; i++)
8244f6c66ccSMatt Macy 		CK_LIST_INIT(&llt->lle_head[i]);
82582f39c91SKip Macy 
82611cdad98SAlexander V. Chernikov 	/* Set some default callbacks */
82711cdad98SAlexander V. Chernikov 	llt->llt_link_entry = htable_link_entry;
82811cdad98SAlexander V. Chernikov 	llt->llt_unlink_entry = htable_unlink_entry;
82911cdad98SAlexander V. Chernikov 	llt->llt_prefix_free = htable_prefix_free;
83011cdad98SAlexander V. Chernikov 	llt->llt_foreach_entry = htable_foreach_lle;
83141cb42a6SAlexander V. Chernikov 	llt->llt_free_tbl = htable_free_tbl;
83241cb42a6SAlexander V. Chernikov 
83341cb42a6SAlexander V. Chernikov 	return (llt);
83441cb42a6SAlexander V. Chernikov }
83541cb42a6SAlexander V. Chernikov 
83682f39c91SKip Macy /*
837721cd2e0SAlexander V. Chernikov  * Links lltable to global llt list.
83882f39c91SKip Macy  */
839721cd2e0SAlexander V. Chernikov void
840721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt)
84182f39c91SKip Macy {
84211cdad98SAlexander V. Chernikov 
843199511bcSAndrey V. Elsukov 	LLTABLE_LIST_WLOCK();
844989e0411SMarko Zec 	SLIST_INSERT_HEAD(&V_lltables, llt, llt_link);
845199511bcSAndrey V. Elsukov 	LLTABLE_LIST_WUNLOCK();
846721cd2e0SAlexander V. Chernikov }
84782f39c91SKip Macy 
848721cd2e0SAlexander V. Chernikov static void
849721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt)
850721cd2e0SAlexander V. Chernikov {
851721cd2e0SAlexander V. Chernikov 
852199511bcSAndrey V. Elsukov 	LLTABLE_LIST_WLOCK();
853721cd2e0SAlexander V. Chernikov 	SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
854199511bcSAndrey V. Elsukov 	LLTABLE_LIST_WUNLOCK();
855721cd2e0SAlexander V. Chernikov 
85682f39c91SKip Macy }
85782f39c91SKip Macy 
85882f39c91SKip Macy /*
859ff3a85d3SAlexander V. Chernikov  * Gets interface @ifp lltable for the specified @family
860ff3a85d3SAlexander V. Chernikov  */
861ff3a85d3SAlexander V. Chernikov struct lltable *
862ff3a85d3SAlexander V. Chernikov lltable_get(struct ifnet *ifp, int family)
863ff3a85d3SAlexander V. Chernikov {
864ff3a85d3SAlexander V. Chernikov 	switch (family) {
865818952c6SEd Maste #ifdef INET
866ff3a85d3SAlexander V. Chernikov 	case AF_INET:
867ff3a85d3SAlexander V. Chernikov 		return (in_lltable_get(ifp));
868818952c6SEd Maste #endif
869818952c6SEd Maste #ifdef INET6
870ff3a85d3SAlexander V. Chernikov 	case AF_INET6:
871ff3a85d3SAlexander V. Chernikov 		return (in6_lltable_get(ifp));
872818952c6SEd Maste #endif
873ff3a85d3SAlexander V. Chernikov 	}
874ff3a85d3SAlexander V. Chernikov 
875ff3a85d3SAlexander V. Chernikov 	return (NULL);
876ff3a85d3SAlexander V. Chernikov }
877ff3a85d3SAlexander V. Chernikov 
878ff3a85d3SAlexander V. Chernikov /*
87911cdad98SAlexander V. Chernikov  * External methods used by lltable consumers
88011cdad98SAlexander V. Chernikov  */
88111cdad98SAlexander V. Chernikov 
88211cdad98SAlexander V. Chernikov int
88311cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
88411cdad98SAlexander V. Chernikov {
88511cdad98SAlexander V. Chernikov 
88611cdad98SAlexander V. Chernikov 	return (llt->llt_foreach_entry(llt, f, farg));
88711cdad98SAlexander V. Chernikov }
88811cdad98SAlexander V. Chernikov 
8895a255516SAlexander V. Chernikov struct llentry *
8905a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags,
8915a255516SAlexander V. Chernikov     const struct sockaddr *l3addr)
8925a255516SAlexander V. Chernikov {
8935a255516SAlexander V. Chernikov 
8945a255516SAlexander V. Chernikov 	return (llt->llt_alloc_entry(llt, flags, l3addr));
8955a255516SAlexander V. Chernikov }
8965a255516SAlexander V. Chernikov 
8975a255516SAlexander V. Chernikov void
8985a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle)
8995a255516SAlexander V. Chernikov {
9005a255516SAlexander V. Chernikov 
9015a255516SAlexander V. Chernikov 	llt->llt_free_entry(llt, lle);
9025a255516SAlexander V. Chernikov }
9035a255516SAlexander V. Chernikov 
9043818c25aSBjoern A. Zeeb int
90511cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle)
90611cdad98SAlexander V. Chernikov {
90711cdad98SAlexander V. Chernikov 
9083818c25aSBjoern A. Zeeb 	return (llt->llt_link_entry(llt, lle));
90911cdad98SAlexander V. Chernikov }
91011cdad98SAlexander V. Chernikov 
911c541bd36SAlexander V. Chernikov void
912c541bd36SAlexander V. Chernikov lltable_link_child_entry(struct llentry *lle, struct llentry *child_lle)
913c541bd36SAlexander V. Chernikov {
914c541bd36SAlexander V. Chernikov 	child_lle->lle_parent = lle;
915c541bd36SAlexander V. Chernikov 	child_lle->lle_tbl = lle->lle_tbl;
916c541bd36SAlexander V. Chernikov 	child_lle->la_flags |= LLE_LINKED;
917c541bd36SAlexander V. Chernikov 	CK_SLIST_INSERT_HEAD(&lle->lle_children, child_lle, lle_child_next);
918c541bd36SAlexander V. Chernikov }
919c541bd36SAlexander V. Chernikov 
920c541bd36SAlexander V. Chernikov void
921c541bd36SAlexander V. Chernikov lltable_unlink_child_entry(struct llentry *child_lle)
922c541bd36SAlexander V. Chernikov {
923c541bd36SAlexander V. Chernikov 	struct llentry *lle = child_lle->lle_parent;
924c541bd36SAlexander V. Chernikov 
925c541bd36SAlexander V. Chernikov 	child_lle->la_flags &= ~LLE_LINKED;
926c541bd36SAlexander V. Chernikov 	child_lle->lle_parent = NULL;
927c541bd36SAlexander V. Chernikov 	CK_SLIST_REMOVE(&lle->lle_children, child_lle, llentry, lle_child_next);
928c541bd36SAlexander V. Chernikov }
929c541bd36SAlexander V. Chernikov 
9303818c25aSBjoern A. Zeeb int
93111cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
93211cdad98SAlexander V. Chernikov {
93311cdad98SAlexander V. Chernikov 
9343818c25aSBjoern A. Zeeb 	return (llt->llt_unlink_entry(lle));
93511cdad98SAlexander V. Chernikov }
93611cdad98SAlexander V. Chernikov 
93711cdad98SAlexander V. Chernikov void
93811cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
93911cdad98SAlexander V. Chernikov {
94011cdad98SAlexander V. Chernikov 	struct lltable *llt;
94111cdad98SAlexander V. Chernikov 
94211cdad98SAlexander V. Chernikov 	llt = lle->lle_tbl;
94311cdad98SAlexander V. Chernikov 	llt->llt_fill_sa_entry(lle, sa);
94411cdad98SAlexander V. Chernikov }
94511cdad98SAlexander V. Chernikov 
94611cdad98SAlexander V. Chernikov struct ifnet *
94711cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt)
94811cdad98SAlexander V. Chernikov {
94911cdad98SAlexander V. Chernikov 
95011cdad98SAlexander V. Chernikov 	return (llt->llt_ifp);
95111cdad98SAlexander V. Chernikov }
95211cdad98SAlexander V. Chernikov 
95311cdad98SAlexander V. Chernikov int
95411cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt)
95511cdad98SAlexander V. Chernikov {
95611cdad98SAlexander V. Chernikov 
95711cdad98SAlexander V. Chernikov 	return (llt->llt_af);
95811cdad98SAlexander V. Chernikov }
95911cdad98SAlexander V. Chernikov 
96011cdad98SAlexander V. Chernikov /*
961b4b1367aSAlexander V. Chernikov  * Called in route_output when rtm_flags contains RTF_LLDATA.
96282f39c91SKip Macy  */
96382f39c91SKip Macy int
96482f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
96582f39c91SKip Macy {
96682f39c91SKip Macy 	struct sockaddr_dl *dl =
96782f39c91SKip Macy 	    (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY];
96882f39c91SKip Macy 	struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
96982f39c91SKip Macy 	struct ifnet *ifp;
97082f39c91SKip Macy 	struct lltable *llt;
9715a255516SAlexander V. Chernikov 	struct llentry *lle, *lle_tmp;
9724fb3a820SAlexander V. Chernikov 	uint8_t linkhdr[LLE_MAX_LINKHDR];
9734fb3a820SAlexander V. Chernikov 	size_t linkhdrsize;
9744fb3a820SAlexander V. Chernikov 	int lladdr_off;
975b4b1367aSAlexander V. Chernikov 	u_int laflags = 0;
976b4b1367aSAlexander V. Chernikov 	int error;
97782f39c91SKip Macy 
978c83dda36SAlexander V. Chernikov 	if (dl == NULL || dl->sdl_family != AF_LINK)
979c83dda36SAlexander V. Chernikov 		return (EINVAL);
9801910bfcbSGleb Smirnoff 
981e5b394f2SAlexander V. Chernikov 	/* XXX: should be ntohs() */
98282f39c91SKip Macy 	ifp = ifnet_byindex(dl->sdl_index);
98382f39c91SKip Macy 	if (ifp == NULL) {
98482f39c91SKip Macy 		log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
98582f39c91SKip Macy 		    __func__, dl->sdl_index);
98682f39c91SKip Macy 		return EINVAL;
98782f39c91SKip Macy 	}
98882f39c91SKip Macy 
989ff3a85d3SAlexander V. Chernikov 	llt = lltable_get(ifp, dst->sa_family);
990ff3a85d3SAlexander V. Chernikov 
991c83dda36SAlexander V. Chernikov 	if (llt == NULL)
992c83dda36SAlexander V. Chernikov 		return (ESRCH);
99382f39c91SKip Macy 
994b4b1367aSAlexander V. Chernikov 	error = 0;
99582f39c91SKip Macy 
996b4b1367aSAlexander V. Chernikov 	switch (rtm->rtm_type) {
997b4b1367aSAlexander V. Chernikov 	case RTM_ADD:
998b4b1367aSAlexander V. Chernikov 		/* Add static LLE */
9993b0fd911SAlexander V. Chernikov 		laflags = 0;
10003b0fd911SAlexander V. Chernikov 		if (rtm->rtm_rmx.rmx_expire == 0)
10013b0fd911SAlexander V. Chernikov 			laflags = LLE_STATIC;
10023b0fd911SAlexander V. Chernikov 		lle = lltable_alloc_entry(llt, laflags, dst);
10035a255516SAlexander V. Chernikov 		if (lle == NULL)
1004b4b1367aSAlexander V. Chernikov 			return (ENOMEM);
1005b4b1367aSAlexander V. Chernikov 
10064fb3a820SAlexander V. Chernikov 		linkhdrsize = sizeof(linkhdr);
10074fb3a820SAlexander V. Chernikov 		if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl),
1008990a6d18SMark Johnston 		    linkhdr, &linkhdrsize, &lladdr_off) != 0) {
1009990a6d18SMark Johnston 			lltable_free_entry(llt, lle);
10104fb3a820SAlexander V. Chernikov 			return (EINVAL);
1011990a6d18SMark Johnston 		}
10124fb3a820SAlexander V. Chernikov 		lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize,
10134fb3a820SAlexander V. Chernikov 		    lladdr_off);
1014b4b1367aSAlexander V. Chernikov 		if ((rtm->rtm_flags & RTF_ANNOUNCE))
1015b4b1367aSAlexander V. Chernikov 			lle->la_flags |= LLE_PUB;
101682f39c91SKip Macy 		lle->la_expire = rtm->rtm_rmx.rmx_expire;
10173b0fd911SAlexander V. Chernikov 
101882f39c91SKip Macy 		laflags = lle->la_flags;
10195a255516SAlexander V. Chernikov 
10205a255516SAlexander V. Chernikov 		/* Try to link new entry */
10215a255516SAlexander V. Chernikov 		lle_tmp = NULL;
10225a255516SAlexander V. Chernikov 		IF_AFDATA_WLOCK(ifp);
10235a255516SAlexander V. Chernikov 		LLE_WLOCK(lle);
10245a255516SAlexander V. Chernikov 		lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst);
10255a255516SAlexander V. Chernikov 		if (lle_tmp != NULL) {
10265a255516SAlexander V. Chernikov 			/* Check if we are trying to replace immutable entry */
10275a255516SAlexander V. Chernikov 			if ((lle_tmp->la_flags & LLE_IFADDR) != 0) {
1028b4b1367aSAlexander V. Chernikov 				IF_AFDATA_WUNLOCK(ifp);
10295a255516SAlexander V. Chernikov 				LLE_WUNLOCK(lle_tmp);
10305a255516SAlexander V. Chernikov 				lltable_free_entry(llt, lle);
10315a255516SAlexander V. Chernikov 				return (EPERM);
10325a255516SAlexander V. Chernikov 			}
10335a255516SAlexander V. Chernikov 			/* Unlink existing entry from table */
10345a255516SAlexander V. Chernikov 			lltable_unlink_entry(llt, lle_tmp);
10355a255516SAlexander V. Chernikov 		}
10365a255516SAlexander V. Chernikov 		lltable_link_entry(llt, lle);
1037d6cd20ccSKUROSAWA Takahiro 		if ((lle->la_flags & LLE_PUB) != 0 &&
1038d6cd20ccSKUROSAWA Takahiro 		    (llt->llt_flags & LLT_ADDEDPROXY) == 0)
1039d6cd20ccSKUROSAWA Takahiro 			llt->llt_flags |= LLT_ADDEDPROXY;
10405a255516SAlexander V. Chernikov 		IF_AFDATA_WUNLOCK(ifp);
10415a255516SAlexander V. Chernikov 
10425a255516SAlexander V. Chernikov 		if (lle_tmp != NULL) {
10435a255516SAlexander V. Chernikov 			EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED);
10445a255516SAlexander V. Chernikov 			lltable_free_entry(llt, lle_tmp);
10455a255516SAlexander V. Chernikov 		}
10465a255516SAlexander V. Chernikov 
10475a255516SAlexander V. Chernikov 		/*
10485a255516SAlexander V. Chernikov 		 * By invoking LLE handler here we might get
10495a255516SAlexander V. Chernikov 		 * two events on static LLE entry insertion
10505a255516SAlexander V. Chernikov 		 * in routing socket. However, since we might have
10515a255516SAlexander V. Chernikov 		 * other subscribers we need to generate this event.
10525a255516SAlexander V. Chernikov 		 */
10535a255516SAlexander V. Chernikov 		EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED);
10545a255516SAlexander V. Chernikov 		LLE_WUNLOCK(lle);
105577001f9bSKUROSAWA Takahiro 		llt->llt_post_resolved(llt, lle);
1056b4b1367aSAlexander V. Chernikov 		break;
1057b4b1367aSAlexander V. Chernikov 
1058b4b1367aSAlexander V. Chernikov 	case RTM_DELETE:
10593e7a2321SAlexander V. Chernikov 		return (lltable_delete_addr(llt, 0, dst));
1060b4b1367aSAlexander V. Chernikov 
1061b4b1367aSAlexander V. Chernikov 	default:
1062b4b1367aSAlexander V. Chernikov 		error = EINVAL;
1063b4b1367aSAlexander V. Chernikov 	}
106482f39c91SKip Macy 
106582f39c91SKip Macy 	return (error);
106682f39c91SKip Macy }
1067989e0411SMarko Zec 
1068335b943fSBjoern A. Zeeb #ifdef DDB
1069335b943fSBjoern A. Zeeb struct llentry_sa {
1070335b943fSBjoern A. Zeeb 	struct llentry		base;
1071335b943fSBjoern A. Zeeb 	struct sockaddr		l3_addr;
1072335b943fSBjoern A. Zeeb };
1073335b943fSBjoern A. Zeeb 
1074335b943fSBjoern A. Zeeb static void
1075335b943fSBjoern A. Zeeb llatbl_lle_show(struct llentry_sa *la)
1076335b943fSBjoern A. Zeeb {
1077335b943fSBjoern A. Zeeb 	struct llentry *lle;
1078335b943fSBjoern A. Zeeb 	uint8_t octet[6];
1079335b943fSBjoern A. Zeeb 
1080335b943fSBjoern A. Zeeb 	lle = &la->base;
1081335b943fSBjoern A. Zeeb 	db_printf("lle=%p\n", lle);
10820f8d79d9SMatt Macy 	db_printf(" lle_next=%p\n", lle->lle_next.cle_next);
1083335b943fSBjoern A. Zeeb 	db_printf(" lle_lock=%p\n", &lle->lle_lock);
1084335b943fSBjoern A. Zeeb 	db_printf(" lle_tbl=%p\n", lle->lle_tbl);
1085335b943fSBjoern A. Zeeb 	db_printf(" lle_head=%p\n", lle->lle_head);
1086335b943fSBjoern A. Zeeb 	db_printf(" la_hold=%p\n", lle->la_hold);
1087e162ea60SGeorge V. Neville-Neil 	db_printf(" la_numheld=%d\n", lle->la_numheld);
1088335b943fSBjoern A. Zeeb 	db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
1089335b943fSBjoern A. Zeeb 	db_printf(" la_flags=0x%04x\n", lle->la_flags);
1090335b943fSBjoern A. Zeeb 	db_printf(" la_asked=%u\n", lle->la_asked);
1091335b943fSBjoern A. Zeeb 	db_printf(" la_preempt=%u\n", lle->la_preempt);
1092335b943fSBjoern A. Zeeb 	db_printf(" ln_state=%d\n", lle->ln_state);
1093335b943fSBjoern A. Zeeb 	db_printf(" ln_router=%u\n", lle->ln_router);
1094335b943fSBjoern A. Zeeb 	db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
1095335b943fSBjoern A. Zeeb 	db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
10964fb3a820SAlexander V. Chernikov 	bcopy(lle->ll_addr, octet, sizeof(octet));
1097335b943fSBjoern A. Zeeb 	db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
1098335b943fSBjoern A. Zeeb 	    octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
10990447c136SAlexander V. Chernikov 	db_printf(" lle_timer=%p\n", &lle->lle_timer);
1100335b943fSBjoern A. Zeeb 
1101335b943fSBjoern A. Zeeb 	switch (la->l3_addr.sa_family) {
1102335b943fSBjoern A. Zeeb #ifdef INET
1103335b943fSBjoern A. Zeeb 	case AF_INET:
1104335b943fSBjoern A. Zeeb 	{
1105335b943fSBjoern A. Zeeb 		struct sockaddr_in *sin;
1106335b943fSBjoern A. Zeeb 		char l3s[INET_ADDRSTRLEN];
1107335b943fSBjoern A. Zeeb 
1108335b943fSBjoern A. Zeeb 		sin = (struct sockaddr_in *)&la->l3_addr;
1109335b943fSBjoern A. Zeeb 		inet_ntoa_r(sin->sin_addr, l3s);
1110335b943fSBjoern A. Zeeb 		db_printf(" l3_addr=%s\n", l3s);
1111335b943fSBjoern A. Zeeb 		break;
1112335b943fSBjoern A. Zeeb 	}
1113335b943fSBjoern A. Zeeb #endif
1114335b943fSBjoern A. Zeeb #ifdef INET6
1115335b943fSBjoern A. Zeeb 	case AF_INET6:
1116335b943fSBjoern A. Zeeb 	{
1117335b943fSBjoern A. Zeeb 		struct sockaddr_in6 *sin6;
1118335b943fSBjoern A. Zeeb 		char l3s[INET6_ADDRSTRLEN];
1119335b943fSBjoern A. Zeeb 
1120335b943fSBjoern A. Zeeb 		sin6 = (struct sockaddr_in6 *)&la->l3_addr;
1121335b943fSBjoern A. Zeeb 		ip6_sprintf(l3s, &sin6->sin6_addr);
1122335b943fSBjoern A. Zeeb 		db_printf(" l3_addr=%s\n", l3s);
1123335b943fSBjoern A. Zeeb 		break;
1124335b943fSBjoern A. Zeeb 	}
1125335b943fSBjoern A. Zeeb #endif
1126335b943fSBjoern A. Zeeb 	default:
1127335b943fSBjoern A. Zeeb 		db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family);
1128335b943fSBjoern A. Zeeb 		break;
1129335b943fSBjoern A. Zeeb 	}
1130335b943fSBjoern A. Zeeb }
1131335b943fSBjoern A. Zeeb 
1132335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry)
1133335b943fSBjoern A. Zeeb {
1134335b943fSBjoern A. Zeeb 
1135335b943fSBjoern A. Zeeb 	if (!have_addr) {
1136335b943fSBjoern A. Zeeb 		db_printf("usage: show llentry <struct llentry *>\n");
1137335b943fSBjoern A. Zeeb 		return;
1138335b943fSBjoern A. Zeeb 	}
1139335b943fSBjoern A. Zeeb 
1140335b943fSBjoern A. Zeeb 	llatbl_lle_show((struct llentry_sa *)addr);
1141335b943fSBjoern A. Zeeb }
1142335b943fSBjoern A. Zeeb 
1143335b943fSBjoern A. Zeeb static void
1144335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt)
1145335b943fSBjoern A. Zeeb {
1146335b943fSBjoern A. Zeeb 	int i;
1147335b943fSBjoern A. Zeeb 	struct llentry *lle;
1148335b943fSBjoern A. Zeeb 
1149335b943fSBjoern A. Zeeb 	db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
1150335b943fSBjoern A. Zeeb 	    llt, llt->llt_af, llt->llt_ifp);
1151335b943fSBjoern A. Zeeb 
11523a749863SAlexander V. Chernikov 	for (i = 0; i < llt->llt_hsize; i++) {
11534f6c66ccSMatt Macy 		CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
1154335b943fSBjoern A. Zeeb 			llatbl_lle_show((struct llentry_sa *)lle);
1155335b943fSBjoern A. Zeeb 			if (db_pager_quit)
1156335b943fSBjoern A. Zeeb 				return;
1157335b943fSBjoern A. Zeeb 		}
1158335b943fSBjoern A. Zeeb 	}
1159335b943fSBjoern A. Zeeb }
1160335b943fSBjoern A. Zeeb 
1161335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable)
1162335b943fSBjoern A. Zeeb {
1163335b943fSBjoern A. Zeeb 
1164335b943fSBjoern A. Zeeb 	if (!have_addr) {
1165335b943fSBjoern A. Zeeb 		db_printf("usage: show lltable <struct lltable *>\n");
1166335b943fSBjoern A. Zeeb 		return;
1167335b943fSBjoern A. Zeeb 	}
1168335b943fSBjoern A. Zeeb 
1169335b943fSBjoern A. Zeeb 	llatbl_llt_show((struct lltable *)addr);
1170335b943fSBjoern A. Zeeb }
1171335b943fSBjoern A. Zeeb 
1172335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
1173335b943fSBjoern A. Zeeb {
1174335b943fSBjoern A. Zeeb 	VNET_ITERATOR_DECL(vnet_iter);
1175335b943fSBjoern A. Zeeb 	struct lltable *llt;
1176335b943fSBjoern A. Zeeb 
1177335b943fSBjoern A. Zeeb 	VNET_FOREACH(vnet_iter) {
1178335b943fSBjoern A. Zeeb 		CURVNET_SET_QUIET(vnet_iter);
1179335b943fSBjoern A. Zeeb #ifdef VIMAGE
1180335b943fSBjoern A. Zeeb 		db_printf("vnet=%p\n", curvnet);
1181335b943fSBjoern A. Zeeb #endif
1182335b943fSBjoern A. Zeeb 		SLIST_FOREACH(llt, &V_lltables, llt_link) {
1183335b943fSBjoern A. Zeeb 			db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
1184335b943fSBjoern A. Zeeb 			    llt, llt->llt_af, llt->llt_ifp,
1185335b943fSBjoern A. Zeeb 			    (llt->llt_ifp != NULL) ?
1186335b943fSBjoern A. Zeeb 				llt->llt_ifp->if_xname : "?");
1187335b943fSBjoern A. Zeeb 			if (have_addr && addr != 0) /* verbose */
1188335b943fSBjoern A. Zeeb 				llatbl_llt_show(llt);
1189335b943fSBjoern A. Zeeb 			if (db_pager_quit) {
1190335b943fSBjoern A. Zeeb 				CURVNET_RESTORE();
1191335b943fSBjoern A. Zeeb 				return;
1192335b943fSBjoern A. Zeeb 			}
1193335b943fSBjoern A. Zeeb 		}
1194335b943fSBjoern A. Zeeb 		CURVNET_RESTORE();
1195335b943fSBjoern A. Zeeb 	}
1196335b943fSBjoern A. Zeeb }
1197335b943fSBjoern A. Zeeb #endif
1198