Module Name:    src
Committed By:   ozaki-r
Date:           Mon Aug 31 08:05:20 UTC 2015

Modified Files:
        src/sys/net: if_arp.h if_ethersubr.c if_llatbl.c if_llatbl.h
            if_tokensubr.c
        src/sys/netinet: if_arp.c in.c in_proto.c in_var.h

Log Message:
Replace ARP cache (llinfo) with lltable/llentry

Highlights of the change are:
- Use llentry instead of llinfo to manage ARP caches
  - ARP specific data are stored in the hashed list
    of an interface instead of the global list (llinfo_arp)
- Fine-grain locking on llentry
- arptimer (callout) per ARP cache
  - the global timer callout with the big locks can be
    removed (though softnet_lock is still required for now)
- net.inet.arp.prune is now obsoleted
  - it was the interval of the global timer callout
- net.inet.arp.refresh is now obsoleted
  - it was a parameter that prevents expiration of active caches
  - Removed to simplify the timer logic, but we may be able to
    restore the feature if really needed

Proposed on tech-kern and tech-net.


To generate a diff of this commit:
cvs rdiff -u -r1.29 -r1.30 src/sys/net/if_arp.h
cvs rdiff -u -r1.212 -r1.213 src/sys/net/if_ethersubr.c
cvs rdiff -u -r1.1 -r1.2 src/sys/net/if_llatbl.c src/sys/net/if_llatbl.h
cvs rdiff -u -r1.70 -r1.71 src/sys/net/if_tokensubr.c
cvs rdiff -u -r1.173 -r1.174 src/sys/netinet/if_arp.c
cvs rdiff -u -r1.158 -r1.159 src/sys/netinet/in.c
cvs rdiff -u -r1.113 -r1.114 src/sys/netinet/in_proto.c
cvs rdiff -u -r1.73 -r1.74 src/sys/netinet/in_var.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if_arp.h
diff -u src/sys/net/if_arp.h:1.29 src/sys/net/if_arp.h:1.30
--- src/sys/net/if_arp.h:1.29	Tue Apr 15 15:17:54 2008
+++ src/sys/net/if_arp.h	Mon Aug 31 08:05:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_arp.h,v 1.29 2008/04/15 15:17:54 thorpej Exp $	*/
+/*	$NetBSD: if_arp.h,v 1.30 2015/08/31 08:05:20 ozaki-r Exp $	*/
 
 /*
  * Copyright (c) 1986, 1993
@@ -127,4 +127,6 @@ struct arpreq {
 
 #define	ARP_NSTATS		23
 
+void arp_stat_add(int, uint64_t);
+
 #endif /* !_NET_IF_ARP_H_ */

Index: src/sys/net/if_ethersubr.c
diff -u src/sys/net/if_ethersubr.c:1.212 src/sys/net/if_ethersubr.c:1.213
--- src/sys/net/if_ethersubr.c:1.212	Mon Aug 24 22:21:26 2015
+++ src/sys/net/if_ethersubr.c	Mon Aug 31 08:05:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ethersubr.c,v 1.212 2015/08/24 22:21:26 pooka Exp $	*/
+/*	$NetBSD: if_ethersubr.c,v 1.213 2015/08/31 08:05:20 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.212 2015/08/24 22:21:26 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.213 2015/08/31 08:05:20 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -243,7 +243,7 @@ ether_output(struct ifnet * const ifp0, 
 		else if (m->m_flags & M_MCAST)
 			ETHER_MAP_IP_MULTICAST(&satocsin(dst)->sin_addr, edst);
 		else if (!arpresolve(ifp, rt, m, dst, edst))
-			return (0);	/* if not yet resolved */
+			return 0;	/* if not yet resolved */
 		/* If broadcasting on a simplex interface, loopback a copy */
 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
 			mcopy = m_copy(m, 0, (int)M_COPYALL);

Index: src/sys/net/if_llatbl.c
diff -u src/sys/net/if_llatbl.c:1.1 src/sys/net/if_llatbl.c:1.2
--- src/sys/net/if_llatbl.c:1.1	Mon Aug 31 07:56:58 2015
+++ src/sys/net/if_llatbl.c	Mon Aug 31 08:05:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_llatbl.c,v 1.1 2015/08/31 07:56:58 ozaki-r Exp $	*/
+/*	$NetBSD: if_llatbl.c,v 1.2 2015/08/31 08:05:20 ozaki-r Exp $	*/
 /*
  * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
  * Copyright (c) 2004-2008 Qing Li. All rights reserved.
@@ -373,6 +373,11 @@ lltable_free(struct lltable *llt)
 	LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
 		if (callout_stop(&lle->la_timer))
 			LLE_REMREF(lle);
+#if __NetBSD__
+		/* XXX should have callback? */
+		if (lle->la_rt != NULL)
+			rtfree(lle->la_rt);
+#endif
 		llentry_free(lle);
 	}
 
Index: src/sys/net/if_llatbl.h
diff -u src/sys/net/if_llatbl.h:1.1 src/sys/net/if_llatbl.h:1.2
--- src/sys/net/if_llatbl.h:1.1	Mon Aug 31 07:56:58 2015
+++ src/sys/net/if_llatbl.h	Mon Aug 31 08:05:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_llatbl.h,v 1.1 2015/08/31 07:56:58 ozaki-r Exp $	*/
+/*	$NetBSD: if_llatbl.h,v 1.2 2015/08/31 08:05:20 ozaki-r Exp $	*/
 /*
  * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
  * Copyright (c) 2004-2008 Qing Li. All rights reserved.
@@ -94,10 +94,29 @@ struct llentry {
 #endif
 };
 
-#define	LLE_WLOCK(lle)		rw_enter(&(lle)->lle_lock, RW_WRITER)
-#define	LLE_RLOCK(lle)		rw_enter(&(lle)->lle_lock, RW_READER)
-#define	LLE_WUNLOCK(lle)	rw_exit(&(lle)->lle_lock)
-#define	LLE_RUNLOCK(lle)	rw_exit(&(lle)->lle_lock)
+
+#if 0
+#define LLE_LOCK_TRACE(n)	aprint_normal("%s: " #n " line %d\n", __func__, __LINE__)
+#else
+#define LLE_LOCK_TRACE(n)
+#endif
+
+#define	LLE_WLOCK(lle)		do { \
+					LLE_LOCK_TRACE(WL); \
+					rw_enter(&(lle)->lle_lock, RW_WRITER); \
+				} while (0)
+#define	LLE_RLOCK(lle)		do { \
+					LLE_LOCK_TRACE(RL); \
+					rw_enter(&(lle)->lle_lock, RW_READER); \
+				} while (0)
+#define	LLE_WUNLOCK(lle)	do { \
+					LLE_LOCK_TRACE(WU); \
+					rw_exit(&(lle)->lle_lock); \
+				} while (0)
+#define	LLE_RUNLOCK(lle)	do { \
+					LLE_LOCK_TRACE(RU); \
+					rw_exit(&(lle)->lle_lock); \
+				} while (0)
 #define	LLE_DOWNGRADE(lle)	rw_downgrade(&(lle)->lle_lock)
 #define	LLE_TRY_UPGRADE(lle)	rw_tryupgrade(&(lle)->lle_lock)
 #ifdef __FreeBSD__
@@ -106,7 +125,7 @@ struct llentry {
 #define	LLE_LOCK_INIT(lle)	rw_init(&(lle)->lle_lock)
 #endif
 #define	LLE_LOCK_DESTROY(lle)	rw_destroy(&(lle)->lle_lock)
-#define	LLE_WLOCK_ASSERT(lle)	KASSERT(rw_lock_held(&(lle)->lle_lock))
+#define	LLE_WLOCK_ASSERT(lle)	KASSERT(rw_write_held(&(lle)->lle_lock))
 
 #define LLE_IS_VALID(lle)	(((lle) != NULL) && ((lle) != (void *)-1))
 

Index: src/sys/net/if_tokensubr.c
diff -u src/sys/net/if_tokensubr.c:1.70 src/sys/net/if_tokensubr.c:1.71
--- src/sys/net/if_tokensubr.c:1.70	Mon Aug 24 22:21:26 2015
+++ src/sys/net/if_tokensubr.c	Mon Aug 31 08:05:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_tokensubr.c,v 1.70 2015/08/24 22:21:26 pooka Exp $	*/
+/*	$NetBSD: if_tokensubr.c,v 1.71 2015/08/31 08:05:20 ozaki-r Exp $	*/
 
 /*
  * Copyright (c) 1982, 1989, 1993
@@ -92,7 +92,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_tokensubr.c,v 1.70 2015/08/24 22:21:26 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_tokensubr.c,v 1.71 2015/08/31 08:05:20 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -114,11 +114,12 @@ __KERNEL_RCSID(0, "$NetBSD: if_tokensubr
 #include <sys/cpu.h>
 
 #include <net/if.h>
-#include <net/netisr.h>
-#include <net/route.h>
-#include <net/if_llc.h>
 #include <net/if_dl.h>
+#include <net/if_llatbl.h>
+#include <net/if_llc.h>
 #include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
 
 #include <net/bpf.h>
 
@@ -217,9 +218,13 @@ token_output(struct ifnet *ifp0, struct 
  * XXX m->m_flags & M_MCAST   IEEE802_MAP_IP_MULTICAST ??
  */
 		else {
+			struct llentry *la;
 			if (!arpresolve(ifp, rt, m, dst, edst))
 				return (0);	/* if not yet resolved */
-			rif = TOKEN_RIF((struct llinfo_arp *) rt->rt_llinfo);
+			la = rt->rt_llinfo;
+			KASSERT(la != NULL);
+			KASSERT(la->la_opaque != NULL);
+			rif = la->la_opaque;
 			riflen = (ntohs(rif->tr_rcf) & TOKEN_RCF_LEN_MASK) >> 8;
 		}
 		/* If broadcasting on a simplex interface, loopback a copy. */

Index: src/sys/netinet/if_arp.c
diff -u src/sys/netinet/if_arp.c:1.173 src/sys/netinet/if_arp.c:1.174
--- src/sys/netinet/if_arp.c:1.173	Mon Aug 24 22:21:26 2015
+++ src/sys/netinet/if_arp.c	Mon Aug 31 08:05:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_arp.c,v 1.173 2015/08/24 22:21:26 pooka Exp $	*/
+/*	$NetBSD: if_arp.c,v 1.174 2015/08/31 08:05:20 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.173 2015/08/24 22:21:26 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.174 2015/08/31 08:05:20 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -98,6 +98,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1
 #include <sys/socketvar.h>
 #include <sys/percpu.h>
 #include <sys/cprng.h>
+#include <sys/kmem.h>
 
 #include <net/ethertypes.h>
 #include <net/if.h>
@@ -105,6 +106,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1
 #include <net/if_token.h>
 #include <net/if_types.h>
 #include <net/if_ether.h>
+#include <net/if_llatbl.h>
 #include <net/net_osdep.h>
 #include <net/route.h>
 #include <net/net_stats.h>
@@ -143,6 +145,7 @@ static int	arpt_prune = (5*60*1);	/* wal
 static int	arpt_keep = (20*60);	/* once resolved, good for 20 more minutes */
 static int	arpt_down = 20;		/* once declared down, don't send for 20 secs */
 static int	arpt_refresh = (5*60);	/* time left before refreshing */
+static int	arp_maxhold = 1;	/* number of packets to hold per ARP entry */
 #define	rt_expire rt_rmx.rmx_expire
 #define	rt_pksent rt_rmx.rmx_pksent
 
@@ -158,12 +161,10 @@ static	void arp_init(void);
 
 static	struct sockaddr *arp_setgate(struct rtentry *, struct sockaddr *,
 	    const struct sockaddr *);
-static	void arptfree(struct llinfo_arp *);
+static	void arptfree(struct llentry *);
 static	void arptimer(void *);
-static	struct llinfo_arp *arplookup1(struct mbuf *, const struct in_addr *,
-				      int, int, struct rtentry *);
-static	struct llinfo_arp *arplookup(struct mbuf *, const struct in_addr *,
-					  int, int);
+static	struct llentry *arplookup(struct ifnet *, struct mbuf *,
+	    const struct in_addr *, int, int, int, struct rtentry *);
 static	void in_arpinput(struct mbuf *);
 static	void in_revarpinput(struct mbuf *);
 static	void revarprequest(struct ifnet *);
@@ -175,7 +176,6 @@ static void arp_dad_start(struct ifaddr 
 static void arp_dad_stop(struct ifaddr *);
 static void arp_dad_duplicated(struct ifaddr *);
 
-LIST_HEAD(llinfo_arpq, llinfo_arp) llinfo_arp;
 struct	ifqueue arpintrq = {
 	.ifq_head = NULL,
 	.ifq_tail = NULL,
@@ -186,7 +186,6 @@ struct	ifqueue arpintrq = {
 static int	arp_inuse, arp_allocated;
 static int	arp_maxtries = 5;
 static int	useloopback = 1;	/* use loopback interface for local traffic */
-static int	arpinit_done = 0;
 
 static percpu_t *arpstat_percpu;
 
@@ -196,8 +195,6 @@ static percpu_t *arpstat_percpu;
 #define	ARP_STATINC(x)		_NET_STATINC(arpstat_percpu, x)
 #define	ARP_STATADD(x, v)	_NET_STATADD(arpstat_percpu, x, v)
 
-struct	callout arptimer_ch;
-
 /* revarp state */
 static struct	in_addr myip, srv_ip;
 static int	myip_initialized = 0;
@@ -287,75 +284,6 @@ struct domain arpdomain = {
 	.dom_protoswNPROTOSW = &arpsw[__arraycount(arpsw)],
 };
 
-/*
- * ARP table locking.
- *
- * to prevent lossage vs. the arp_drain routine (which may be called at
- * any time, including in a device driver context), we do two things:
- *
- * 1) manipulation of la->la_hold is done at splnet() (for all of
- * about two instructions).
- *
- * 2) manipulation of the arp table's linked list is done under the
- * protection of the ARP_LOCK; if arp_drain() or arptimer is called
- * while the arp table is locked, we punt and try again later.
- */
-
-static int	arp_locked;
-static inline int arp_lock_try(int);
-static inline void arp_unlock(void);
-
-static inline int
-arp_lock_try(int recurse)
-{
-	int s;
-
-	/*
-	 * Use splvm() -- we're blocking things that would cause
-	 * mbuf allocation.
-	 */
-	s = splvm();
-	if (!recurse && arp_locked) {
-		splx(s);
-		return 0;
-	}
-	arp_locked++;
-	splx(s);
-	return 1;
-}
-
-static inline void
-arp_unlock(void)
-{
-	int s;
-
-	s = splvm();
-	arp_locked--;
-	splx(s);
-}
-
-#ifdef DIAGNOSTIC
-#define	ARP_LOCK(recurse)						\
-do {									\
-	if (arp_lock_try(recurse) == 0) {				\
-		printf("%s:%d: arp already locked\n", __FILE__, __LINE__); \
-		panic("arp_lock");					\
-	}								\
-} while (/*CONSTCOND*/ 0)
-#define	ARP_LOCK_CHECK()						\
-do {									\
-	if (arp_locked == 0) {						\
-		printf("%s:%d: arp lock not held\n", __FILE__, __LINE__); \
-		panic("arp lock check");				\
-	}								\
-} while (/*CONSTCOND*/ 0)
-#else
-#define	ARP_LOCK(x)		(void) arp_lock_try(x)
-#define	ARP_LOCK_CHECK()	/* nothing */
-#endif
-
-#define	ARP_UNLOCK()		arp_unlock()
-
 static void sysctl_net_inet_arp_setup(struct sysctllog **);
 
 void
@@ -380,74 +308,71 @@ arp_drainstub(void)
 void
 arp_drain(void)
 {
-	struct llinfo_arp *la;
-	int count = 0;
-	struct mbuf *mold;
-
-	KERNEL_LOCK(1, NULL);
-
-	if (arp_lock_try(0) == 0) {
-		KERNEL_UNLOCK_ONE(NULL);
-		return;
-	}
-
-	LIST_FOREACH(la, &llinfo_arp, la_list) {
-		mold = la->la_hold;
-		la->la_hold = NULL;
 
-		if (mold) {
-			m_freem(mold);
-			count++;
-		}
-	}
-	ARP_UNLOCK();
-	ARP_STATADD(ARP_STAT_DFRDROPPED, count);
-	KERNEL_UNLOCK_ONE(NULL);
+	lltable_drain(AF_INET);
 }
 
-
-/*
- * Timeout routine.  Age arp_tab entries periodically.
- */
-/* ARGSUSED */
 static void
 arptimer(void *arg)
 {
-	struct llinfo_arp *la, *nla;
+	struct llentry *lle = arg;
+	struct ifnet *ifp;
 
 	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
 
-	if (arp_lock_try(0) == 0) {
-		/* get it later.. */
-		KERNEL_UNLOCK_ONE(NULL);
-		mutex_exit(softnet_lock);
-		return;
+	if (lle == NULL)
+		goto out;
+
+	if (lle->la_flags & LLE_STATIC)
+		goto out;
+
+	LLE_WLOCK(lle);
+	if (callout_pending(&lle->la_timer)) {
+		/*
+		 * Here we are a bit odd here in the treatment of
+		 * active/pending. If the pending bit is set, it got
+		 * rescheduled before I ran. The active
+		 * bit we ignore, since if it was stopped
+		 * in ll_tablefree() and was currently running
+		 * it would have return 0 so the code would
+		 * not have deleted it since the callout could
+		 * not be stopped so we want to go through
+		 * with the delete here now. If the callout
+		 * was restarted, the pending bit will be back on and
+		 * we just want to bail since the callout_reset would
+		 * return 1 and our reference would have been removed
+		 * by arpresolve() below.
+		 */
+		LLE_WUNLOCK(lle);
+		goto out;
 	}
+	ifp = lle->lle_tbl->llt_ifp;
 
-	callout_reset(&arptimer_ch, arpt_prune * hz, arptimer, NULL);
-	LIST_FOREACH_SAFE(la, &llinfo_arp, la_list, nla) {
-		struct rtentry *rt = la->la_rt;
-
-		if (rt->rt_expire == 0)
-			continue;
-		if ((rt->rt_expire - time_uptime) < arpt_refresh &&
-		    rt->rt_pksent > (time_uptime - arpt_keep)) {
-			/*
-			 * If the entry has been used during since last
-			 * refresh, try to renew it before deleting.
-			 */
-			arprequest(rt->rt_ifp,
-			    &satocsin(rt->rt_ifa->ifa_addr)->sin_addr,
-			    &satocsin(rt_getkey(rt))->sin_addr,
-			    CLLADDR(rt->rt_ifp->if_sadl));
-		} else if (rt->rt_expire <= time_uptime)
-			arptfree(la); /* timer has expired; clear */
+	callout_stop(&lle->la_timer);
+
+	/* XXX: LOR avoidance. We still have ref on lle. */
+	LLE_WUNLOCK(lle);
+
+	/* We have to call this w/o lock */
+	arptfree(lle);
+
+	IF_AFDATA_LOCK(ifp);
+	LLE_WLOCK(lle);
+
+	/* Guard against race with other llentry_free(). */
+	if (lle->la_flags & LLE_LINKED) {
+		size_t pkts_dropped;
+
+		LLE_REMREF(lle);
+		pkts_dropped = llentry_free(lle);
+		ARP_STATADD(ARP_STAT_DFRDROPPED, pkts_dropped);
+	} else {
+		LLE_FREE_LOCKED(lle);
 	}
 
-	ARP_UNLOCK();
+	IF_AFDATA_UNLOCK(ifp);
 
-	KERNEL_UNLOCK_ONE(NULL);
+out:
 	mutex_exit(softnet_lock);
 }
 
@@ -498,19 +423,11 @@ void
 arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
 {
 	struct sockaddr *gate = rt->rt_gateway;
-	struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
-	size_t allocsize;
-	struct mbuf *mold;
-	int s;
+	struct llentry *la = NULL;
 	struct in_ifaddr *ia;
 	struct ifaddr *ifa;
 	struct ifnet *ifp = rt->rt_ifp;
-
-	if (!arpinit_done) {
-		arpinit_done = 1;
-		callout_init(&arptimer_ch, CALLOUT_MPSAFE);
-		callout_reset(&arptimer_ch, hz, arptimer, NULL);
-	}
+	int flags = 0;
 
 	if (req == RTM_LLINFO_UPD) {
 		struct in_addr *in;
@@ -565,7 +482,9 @@ arp_rtrequest(int req, struct rtentry *r
 		return;
 	}
 
-	ARP_LOCK(1);		/* we may already be locked here. */
+	IF_AFDATA_RLOCK(ifp);
+	la = lla_lookup(LLTABLE(ifp), flags, rt_getkey(rt));
+	IF_AFDATA_RUNLOCK(ifp);
 
 	switch (req) {
 	case RTM_SETGATE:
@@ -660,26 +579,38 @@ arp_rtrequest(int req, struct rtentry *r
 		 * Case 2:  This route may come from cloning, or a manual route
 		 * add with a LL address.
 		 */
+		flags = LLE_EXCLUSIVE;
+		if ((rt->rt_flags & RTF_CLONED) == 0)
+			flags |= LLE_IFADDR;
+
+		IF_AFDATA_WLOCK(ifp);
+		la = lla_create(LLTABLE(ifp), flags, rt_getkey(rt));
+		IF_AFDATA_WUNLOCK(ifp);
+
+		if (la == NULL) {
+			log(LOG_DEBUG, "%s: lla_create failed\n",
+			    __func__);
+			rt->rt_llinfo = NULL;
+			break;
+		}
+		rt->rt_llinfo = la;
 		switch (ifp->if_type) {
 #if NTOKEN > 0
 		case IFT_ISO88025:
-			allocsize = sizeof(*la) + sizeof(struct token_rif);
+			la->la_opaque = kmem_alloc(sizeof(struct token_rif),
+			    KM_SLEEP);
 			break;
 #endif /* NTOKEN > 0 */
 		default:
-			allocsize = sizeof(*la);
-		}
-		R_Malloc(la, struct llinfo_arp *, allocsize);
-		rt->rt_llinfo = (void *)la;
-		if (la == NULL) {
-			log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");
 			break;
 		}
-		arp_inuse++, arp_allocated++;
-		memset(la, 0, allocsize);
 		la->la_rt = rt;
+		rt->rt_refcnt++;
 		rt->rt_flags |= RTF_LLINFO;
-		LIST_INSERT_HEAD(&llinfo_arp, la, la_list);
+		arp_inuse++, arp_allocated++;
+
+		LLE_WUNLOCK(la);
+		la = NULL;
 
 		INADDR_TO_IA(satocsin(rt_getkey(rt))->sin_addr, ia);
 		while (ia && ia->ia_ifp != ifp)
@@ -726,21 +657,54 @@ arp_rtrequest(int req, struct rtentry *r
 		if (la == NULL)
 			break;
 		arp_inuse--;
-		LIST_REMOVE(la, la_list);
 		rt->rt_llinfo = NULL;
 		rt->rt_flags &= ~RTF_LLINFO;
 
-		s = splnet();
-		mold = la->la_hold;
-		la->la_hold = NULL;
-		splx(s);
+		LLE_RUNLOCK(la);
 
-		if (mold)
-			m_freem(mold);
+		flags |= LLE_EXCLUSIVE;
+		IF_AFDATA_WLOCK(ifp);
+
+		la = lla_lookup(LLTABLE(ifp), flags, rt_getkey(rt));
+		/* This shouldn't happen */
+		if (la == NULL) {
+			IF_AFDATA_WUNLOCK(ifp);
+			break;
+		}
 
-		Free((void *)la);
+		if (la->la_opaque != NULL) {
+			switch (ifp->if_type) {
+#if NTOKEN > 0
+			case IFT_ISO88025:
+				kmem_free(la->la_opaque,
+				    sizeof(struct token_rif));
+				break;
+#endif /* NTOKEN > 0 */
+			default:
+				break;
+			}
+		}
+
+		if (la->la_rt != NULL) {
+			/*
+			 * Don't rtfree (may actually free objects) here.
+			 * Leave it to rtrequest1.
+			 */
+			la->la_rt->rt_refcnt--;
+			la->la_rt = NULL;
+		}
+		llentry_free(la);
+
+		IF_AFDATA_WUNLOCK(ifp);
+		la = NULL;
+	}
+
+	if (la != NULL) {
+		if (flags & LLE_EXCLUSIVE)
+			LLE_WUNLOCK(la);
+		else
+			LLE_RUNLOCK(la);
 	}
-	ARP_UNLOCK();
 }
 
 /*
@@ -759,6 +723,10 @@ arprequest(struct ifnet *ifp,
 	struct sockaddr sa;
 	uint64_t *arps;
 
+	KASSERT(sip != NULL);
+	KASSERT(tip != NULL);
+	KASSERT(enaddr != NULL);
+
 	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
 		return;
 	MCLAIM(m, &arpdomain.dom_mowner);
@@ -816,12 +784,15 @@ int
 arpresolve(struct ifnet *ifp, struct rtentry *rt, struct mbuf *m,
     const struct sockaddr *dst, u_char *desten)
 {
-	struct llinfo_arp *la;
+	struct llentry *la;
 	const struct sockaddr_dl *sdl;
-	struct mbuf *mold;
-	int s;
+	int renew;
+	int flags = 0;
+	int error;
+	bool create;
 
-	if ((la = arplookup1(m, &satocsin(dst)->sin_addr, 1, 0, rt)) != NULL)
+	la = arplookup(ifp, m, &satocsin(dst)->sin_addr, 1, 0, 0, rt);
+	if (la != NULL)
 		rt = la->la_rt;
 
 	if (la == NULL || rt == NULL) {
@@ -830,6 +801,8 @@ arpresolve(struct ifnet *ifp, struct rte
 		    "arpresolve: can't allocate llinfo on %s for %s\n",
 		    ifp->if_xname, in_fmtaddr(satocsin(dst)->sin_addr));
 		m_freem(m);
+		if (la != NULL)
+			LLE_RUNLOCK(la);
 		return 0;
 	}
 	sdl = satocsdl(rt->rt_gateway);
@@ -842,24 +815,9 @@ arpresolve(struct ifnet *ifp, struct rte
 		memcpy(desten, CLLADDR(sdl),
 		    min(sdl->sdl_alen, ifp->if_addrlen));
 		rt->rt_pksent = time_uptime; /* Time for last pkt sent */
+		LLE_RUNLOCK(la);
 		return 1;
 	}
-	/*
-	 * There is an arptab entry, but no ethernet address
-	 * response yet.  Replace the held mbuf with this
-	 * latest one.
-	 */
-
-	ARP_STATINC(ARP_STAT_DFRTOTAL);
-	s = splnet();
-	mold = la->la_hold;
-	la->la_hold = m;
-	splx(s);
-
-	if (mold) {
-		ARP_STATINC(ARP_STAT_DFRDROPPED);
-		m_freem(mold);
-	}
 
 	/*
 	 * Re-send the ARP request when appropriate.
@@ -872,27 +830,158 @@ arpresolve(struct ifnet *ifp, struct rte
 		rt->rt_expire = time_uptime;
 	}
 #endif
-	if (rt->rt_expire) {
-		rt->rt_flags &= ~RTF_REJECT;
-		if (la->la_asked == 0 || rt->rt_expire != time_uptime) {
-			rt->rt_expire = time_uptime;
-			if (la->la_asked++ < arp_maxtries) {
-				arprequest(ifp,
-				    &satocsin(rt->rt_ifa->ifa_addr)->sin_addr,
-				    &satocsin(dst)->sin_addr,
+
+retry:
+	create = false;
+	if (la == NULL) {
+		IF_AFDATA_RLOCK(ifp);
+		la = lla_lookup(LLTABLE(ifp), flags, dst);
+		IF_AFDATA_RUNLOCK(ifp);
+	}
+
+	if ((la == NULL) && ((flags & LLE_EXCLUSIVE) == 0)
+#ifdef __FreeBSD__
+	    && ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0)) {
+#else
+	    && ((ifp->if_flags & IFF_NOARP) == 0)) {
+#endif
+		create = true;
+		flags |= LLE_EXCLUSIVE;
+		IF_AFDATA_WLOCK(ifp);
+		la = lla_create(LLTABLE(ifp), flags, dst);
+		IF_AFDATA_WUNLOCK(ifp);
+	}
+
+	if (la == NULL) {
+		if (create) {
+			log(LOG_DEBUG,
+			    "%s: failed to create llentry for %s on %s\n",
+			    __func__, inet_ntoa(satocsin(dst)->sin_addr),
+			    ifp->if_xname);
+		}
+		m_freem(m);
+		return 0;
+	}
+
+	if ((la->la_flags & LLE_VALID) &&
+	    ((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime)) {
+		memcpy(desten, CLLADDR(sdl),
+		    min(sdl->sdl_alen, ifp->if_addrlen));
+		renew = 0;
+		/*
+		 * If entry has an expiry time and it is approaching,
+		 * see if we need to send an ARP request within this
+		 * arpt_down interval.
+		 */
+		if (!(la->la_flags & LLE_STATIC) &&
+		    time_uptime + la->la_preempt > la->la_expire) {
+			renew = 1;
+			la->la_preempt--;
+		}
+
+		if (flags & LLE_EXCLUSIVE)
+			LLE_WUNLOCK(la);
+		else
+			LLE_RUNLOCK(la);
+
+		if (renew == 1) {
+			const u_int8_t *enaddr =
 #if NCARP > 0
-				    (rt->rt_ifp->if_type == IFT_CARP) ?
-				    CLLADDR(rt->rt_ifp->if_sadl):
+			    (rt->rt_ifp->if_type == IFT_CARP) ?
+			    CLLADDR(rt->rt_ifp->if_sadl):
 #endif
-				    CLLADDR(ifp->if_sadl));
-			} else {
-				rt->rt_flags |= RTF_REJECT;
-				rt->rt_expire += arpt_down;
-				la->la_asked = 0;
+			    CLLADDR(ifp->if_sadl);
+			arprequest(ifp, &satocsin(rt->rt_ifa->ifa_addr)->sin_addr,
+			    &satocsin(dst)->sin_addr, enaddr);
+		}
+
+		return 1;
+	}
+
+	if (la->la_flags & LLE_STATIC) {   /* should not happen! */
+		log(LOG_DEBUG, "arpresolve: ouch, empty static llinfo for %s\n",
+		    inet_ntoa(satocsin(dst)->sin_addr));
+		m_freem(m);
+		error = EINVAL;
+		goto done;
+	}
+
+	renew = (la->la_asked == 0 || la->la_expire != time_uptime);
+	if ((renew || m != NULL) && (flags & LLE_EXCLUSIVE) == 0) {
+		flags |= LLE_EXCLUSIVE;
+		LLE_RUNLOCK(la);
+		la = NULL;
+		goto retry;
+	}
+	/*
+	 * There is an arptab entry, but no ethernet address
+	 * response yet.  Add the mbuf to the list, dropping
+	 * the oldest packet if we have exceeded the system
+	 * setting.
+	 */
+	if (m != NULL) {
+		LLE_WLOCK_ASSERT(la);
+		if (la->la_numheld >= arp_maxhold) {
+			if (la->la_hold != NULL) {
+				struct mbuf *next = la->la_hold->m_nextpkt;
+				m_freem(la->la_hold);
+				la->la_hold = next;
+				la->la_numheld--;
+				ARP_STATINC(ARP_STAT_DFRDROPPED);
 			}
 		}
+		if (la->la_hold != NULL) {
+			struct mbuf *curr = la->la_hold;
+			while (curr->m_nextpkt != NULL)
+				curr = curr->m_nextpkt;
+			curr->m_nextpkt = m;
+		} else
+			la->la_hold = m;
+		la->la_numheld++;
+		if (renew == 0 && (flags & LLE_EXCLUSIVE)) {
+			flags &= ~LLE_EXCLUSIVE;
+			LLE_DOWNGRADE(la);
+		}
+
 	}
-	return 0;
+	/*
+	 * Return EWOULDBLOCK if we have tried less than arp_maxtries. It
+	 * will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH
+	 * if we have already sent arp_maxtries ARP requests. Retransmit the
+	 * ARP request, but not faster than one request per second.
+	 */
+	if (la->la_asked < arp_maxtries)
+		error = EWOULDBLOCK;	/* First request. */
+	else
+		error = (rt->rt_flags & RTF_GATEWAY) ?
+		    EHOSTUNREACH : EHOSTDOWN;
+
+	if (renew) {
+		const u_int8_t *enaddr =
+#if NCARP > 0
+		    (rt->rt_ifp->if_type == IFT_CARP) ?
+		    CLLADDR(rt->rt_ifp->if_sadl):
+#endif
+		    CLLADDR(ifp->if_sadl);
+		LLE_ADDREF(la);
+		la->la_expire = time_uptime;
+		callout_reset(&la->la_timer, hz * arpt_down,
+		    arptimer, la);
+		la->la_asked++;
+		if (flags & LLE_EXCLUSIVE)
+			LLE_WUNLOCK(la);
+		else
+			LLE_RUNLOCK(la);
+		arprequest(ifp, &satocsin(rt->rt_ifa->ifa_addr)->sin_addr,
+		    &satocsin(dst)->sin_addr, enaddr);
+		return error == 0;
+	}
+done:
+	if (flags & LLE_EXCLUSIVE)
+		LLE_WUNLOCK(la);
+	else
+		LLE_RUNLOCK(la);
+	return error == 0;
 }
 
 /*
@@ -976,8 +1065,8 @@ in_arpinput(struct mbuf *m)
 {
 	struct arphdr *ah;
 	struct ifnet *ifp = m->m_pkthdr.rcvif;
-	struct llinfo_arp *la = NULL;
-	struct rtentry  *rt;
+	struct llentry *la = NULL;
+	struct rtentry  *rt = NULL;
 	struct in_ifaddr *ia;
 #if NBRIDGE > 0
 	struct in_ifaddr *bridge_ia = NULL;
@@ -985,13 +1074,11 @@ in_arpinput(struct mbuf *m)
 #if NCARP > 0
 	u_int32_t count = 0, index = 0;
 #endif
-	struct sockaddr_dl *sdl;
+	struct sockaddr_dl *sdl = NULL;
 	struct sockaddr sa;
 	struct in_addr isaddr, itaddr, myaddr;
 	int op;
-	struct mbuf *mold;
 	void *tha;
-	int s;
 	uint64_t *arps;
 
 	if (__predict_false(m_makewritable(&m, 0, m->m_pkthdr.len, M_DONTWAIT)))
@@ -1142,8 +1229,14 @@ in_arpinput(struct mbuf *m)
 		itaddr = myaddr;
 		goto reply;
 	}
-	la = arplookup(m, &isaddr, in_hosteq(itaddr, myaddr), 0);
-	if (la != NULL && (rt = la->la_rt) && (sdl = satosdl(rt->rt_gateway))) {
+
+	la = arplookup(ifp, m, &isaddr, in_hosteq(itaddr, myaddr), 0, 1, NULL);
+	if (la != NULL) {
+		rt = la->la_rt;
+		if (rt != NULL)
+			sdl = satosdl(rt->rt_gateway);
+	}
+	if (sdl != NULL) {
 		if (sdl->sdl_alen &&
 		    memcmp(ar_sha(ah), CLLADDR(sdl), sdl->sdl_alen)) {
 			if (rt->rt_flags & RTF_STATIC) {
@@ -1226,22 +1319,43 @@ in_arpinput(struct mbuf *m)
 #endif /* NTOKEN > 0 */
 		(void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, ar_sha(ah),
 		    ah->ar_hln);
-		if (rt->rt_expire)
+		if (rt->rt_expire) {
 			rt->rt_expire = time_uptime + arpt_keep;
+
+			KASSERT((la->la_flags & LLE_STATIC) == 0);
+			LLE_ADDREF(la);
+			callout_reset(&la->la_timer, hz * arpt_keep, arptimer, la);
+		}
 		rt->rt_flags &= ~RTF_REJECT;
 		la->la_asked = 0;
 
-		s = splnet();
-		mold = la->la_hold;
-		la->la_hold = NULL;
-		splx(s);
-
-		if (mold) {
-			ARP_STATINC(ARP_STAT_DFRSENT);
-			(*ifp->if_output)(ifp, mold, rt_getkey(rt), rt);
-		}
+		if (la->la_hold != NULL) {
+			int n = la->la_numheld;
+			struct mbuf *m_hold, *m_hold_next;
+
+			m_hold = la->la_hold;
+			la->la_hold = NULL;
+			la->la_numheld = 0;
+			/*
+			 * We have to unlock here because if_output would call
+			 * arpresolve
+			 */
+			LLE_WUNLOCK(la);
+			ARP_STATADD(ARP_STAT_DFRSENT, n);
+			for (; m_hold != NULL; m_hold = m_hold_next) {
+				m_hold_next = m_hold->m_nextpkt;
+				m_hold->m_nextpkt = NULL;
+				(*ifp->if_output)(ifp, m_hold, rt_getkey(rt), rt);
+			}
+		} else
+			LLE_WUNLOCK(la);
+		la = NULL;
 	}
 reply:
+	if (la != NULL) {
+		LLE_WUNLOCK(la);
+		la = NULL;
+	}
 	if (op != ARPOP_REQUEST) {
 		if (op == ARPOP_REPLY)
 			ARP_STATINC(ARP_STAT_RCVREPLY);
@@ -1258,10 +1372,12 @@ reply:
 			memcpy(tha, ar_sha(ah), ah->ar_hln);
 		memcpy(ar_sha(ah), CLLADDR(ifp->if_sadl), ah->ar_hln);
 	} else {
-		la = arplookup(m, &itaddr, 0, SIN_PROXY);
+		la = arplookup(ifp, m, &itaddr, 0, SIN_PROXY, 0, NULL);
 		if (la == NULL)
 			goto out;
 		rt = la->la_rt;
+		LLE_RUNLOCK(la);
+		la = NULL;
 		if (rt->rt_ifp->if_type == IFT_CARP &&
 		    m->m_pkthdr.rcvif->if_type != IFT_CARP)
 			goto out;
@@ -1300,47 +1416,38 @@ reply:
 	ARP_STAT_PUTREF();
 	(*ifp->if_output)(ifp, m, &sa, NULL);
 	return;
+
 out:
+	if (la != NULL)
+		LLE_WUNLOCK(la);
 	m_freem(m);
 }
 
 /*
  * Free an arp entry.
  */
-static void arptfree(struct llinfo_arp *la)
+static void arptfree(struct llentry *la)
 {
 	struct rtentry *rt = la->la_rt;
-	struct sockaddr_dl *sdl;
 
-	ARP_LOCK_CHECK();
+	KASSERT(rt != NULL);
 
-	if (rt == NULL)
-		panic("arptfree");
-	if (rt->rt_refcnt > 0 && (sdl = satosdl(rt->rt_gateway)) &&
-	    sdl->sdl_family == AF_LINK) {
-		sdl->sdl_alen = 0;
-		la->la_asked = 0;
-		rt->rt_flags &= ~RTF_REJECT;
-		return;
+	if (la->la_rt != NULL) {
+		rtfree(la->la_rt);
+		la->la_rt = NULL;
 	}
-	rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL);
-}
 
-static struct llinfo_arp *
-arplookup(struct mbuf *m, const struct in_addr *addr, int create, int proxy)
-{
-	return arplookup1(m, addr, create, proxy, NULL);
+	rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL);
 }
 
 /*
  * Lookup or enter a new address in arptab.
  */
-static struct llinfo_arp *
-arplookup1(struct mbuf *m, const struct in_addr *addr, int create, int proxy,
-    struct rtentry *rt0)
+static struct llentry *
+arplookup(struct ifnet *ifp, struct mbuf *m, const struct in_addr *addr,
+    int create, int proxy, int wlock, struct rtentry *rt0)
 {
 	struct arphdr *ah;
-	struct ifnet *ifp = m->m_pkthdr.rcvif;
 	struct rtentry *rt;
 	struct sockaddr_inarp sin;
 	const char *why = NULL;
@@ -1364,8 +1471,22 @@ arplookup1(struct mbuf *m, const struct 
 	 (__rt)->rt_gateway->sa_family == AF_LINK)
 
 
-	if (IS_LLINFO(rt))
-		return (struct llinfo_arp *)rt->rt_llinfo;
+	if (IS_LLINFO(rt)) {
+		struct llentry *la;
+		int flags = wlock ? LLE_EXCLUSIVE : 0;
+
+		if (create) {
+			IF_AFDATA_WLOCK(ifp);
+			la = lla_create(LLTABLE(ifp), flags, rt_getkey(rt));
+			IF_AFDATA_WUNLOCK(ifp);
+		} else {
+			IF_AFDATA_RLOCK(ifp);
+			la = lla_lookup(LLTABLE(ifp), flags, rt_getkey(rt));
+			IF_AFDATA_RUNLOCK(ifp);
+		}
+
+		return la;
+	}
 
 	if (create) {
 		if (rt->rt_flags & RTF_GATEWAY) {
@@ -1382,7 +1503,7 @@ arplookup1(struct mbuf *m, const struct 
 			    lla_snprintf(ar_sha(ah), ah->ar_hln),
 			    (ifp) ? ifp->if_xname : "null", why);
 		}
-		if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_CLONED) != 0) {
+		if ((rt->rt_flags & RTF_CLONED) != 0) {
 			rtrequest(RTM_DELETE, rt_getkey(rt),
 		    	    rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL);
 		}
@@ -1997,6 +2118,12 @@ db_show_arptab(db_expr_t addr, bool have
 }
 #endif
 
+void
+arp_stat_add(int type, uint64_t count)
+{
+	ARP_STATADD(type, count);
+}
+
 static int
 sysctl_net_inet_arp_stats(SYSCTLFN_ARGS)
 {

Index: src/sys/netinet/in.c
diff -u src/sys/netinet/in.c:1.158 src/sys/netinet/in.c:1.159
--- src/sys/netinet/in.c:1.158	Mon Aug 31 08:02:44 2015
+++ src/sys/netinet/in.c	Mon Aug 31 08:05:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: in.c,v 1.158 2015/08/31 08:02:44 ozaki-r Exp $	*/
+/*	$NetBSD: in.c,v 1.159 2015/08/31 08:05:20 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.158 2015/08/31 08:02:44 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.159 2015/08/31 08:05:20 ozaki-r Exp $");
 
 #include "arp.h"
 
@@ -121,6 +121,7 @@ __KERNEL_RCSID(0, "$NetBSD: in.c,v 1.158
 #include <net/route.h>
 #include <net/pfil.h>
 
+#include <net/if_arp.h>
 #include <net/if_ether.h>
 #include <net/if_types.h>
 #include <net/if_llatbl.h>
@@ -1574,7 +1575,7 @@ in_lltable_new(struct in_addr addr4, u_i
 	lle->base.lle_refcnt = 1;
 	lle->base.lle_free = in_lltable_destroy_lle;
 	LLE_LOCK_INIT(&lle->base);
-	callout_init(&lle->base.la_timer, 1);
+	callout_init(&lle->base.la_timer, CALLOUT_MPSAFE);
 
 	return (&lle->base);
 }
@@ -1622,11 +1623,7 @@ in_lltable_free_entry(struct lltable *ll
 
 	/* Drop hold queue */
 	pkts_dropped = llentry_free(lle);
-#ifdef __FreeBSD__
-	ARPSTAT_ADD(dropped, pkts_dropped);
-#else
-	(void) pkts_dropped; /* FIXME */
-#endif
+	arp_stat_add(ARP_STAT_DFRDROPPED, (uint64_t)pkts_dropped);
 }
 
 static int
@@ -1653,7 +1650,7 @@ in_lltable_rtcheck(struct ifnet *ifp, u_
 		    rt->rt_ifp->if_type != IFT_ETHER ||
 #ifdef __FreeBSD__
 		    (rt->rt_ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0 ||
-#else /* XXX */
+#else
 		    (rt->rt_ifp->if_flags & IFF_NOARP) != 0 ||
 #endif
 		    memcmp(rt->rt_gateway->sa_data, l3addr->sa_data,
@@ -1699,9 +1696,6 @@ in_lltable_rtcheck(struct ifnet *ifp, u_
 
 	error = 0;
 error:
-#ifdef __FreeBSD__
-	RTFREE_LOCKED(rt);
-#endif
 	return error;
 }
 
@@ -1773,9 +1767,6 @@ in_lltable_delete(struct lltable *llt, u
 	if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
 		LLE_WLOCK(lle);
 		lle->la_flags |= LLE_DELETED;
-#ifdef __FreeBSD__
-		EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
-#endif
 #ifdef DIAGNOSTIC
 		log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
 #endif

Index: src/sys/netinet/in_proto.c
diff -u src/sys/netinet/in_proto.c:1.113 src/sys/netinet/in_proto.c:1.114
--- src/sys/netinet/in_proto.c:1.113	Mon Aug 24 22:21:26 2015
+++ src/sys/netinet/in_proto.c	Mon Aug 31 08:05:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_proto.c,v 1.113 2015/08/24 22:21:26 pooka Exp $	*/
+/*	$NetBSD: in_proto.c,v 1.114 2015/08/31 08:05:20 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.113 2015/08/24 22:21:26 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.114 2015/08/31 08:05:20 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mrouting.h"
@@ -388,13 +388,8 @@ struct domain inetdomain = {
 	.dom_maxrtkey = sizeof(struct ip_pack4),
 	.dom_if_up = in_if_up,
 	.dom_if_down = in_if_down,
-#ifdef IPSELSRC
 	.dom_ifattach = in_domifattach,
 	.dom_ifdetach = in_domifdetach,
-#else
-	.dom_ifattach = NULL,
-	.dom_ifdetach = NULL,
-#endif
 	.dom_if_link_state_change = in_if_link_state_change,
 	.dom_ifqueues = { NULL, NULL },
 	.dom_link = { NULL },

Index: src/sys/netinet/in_var.h
diff -u src/sys/netinet/in_var.h:1.73 src/sys/netinet/in_var.h:1.74
--- src/sys/netinet/in_var.h:1.73	Mon Aug 31 08:02:44 2015
+++ src/sys/netinet/in_var.h	Mon Aug 31 08:05:20 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_var.h,v 1.73 2015/08/31 08:02:44 ozaki-r Exp $	*/
+/*	$NetBSD: in_var.h,v 1.74 2015/08/31 08:05:20 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -323,6 +323,9 @@ ip_newid(const struct in_ifaddr *ia)
 int	sysctl_inpcblist(SYSCTLFN_PROTO);
 #endif
 
+#define LLTABLE(ifp)	\
+	((struct in_ifinfo *)(ifp)->if_afdata[AF_INET])->ii_llt
+
 #endif	/* !_KERNEL */
 
 /* INET6 stuff */

Reply via email to