Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 8 Jan 2015 18:02:06 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r276844 - head/sys/netinet6
Message-ID:  <201501081802.t08I26nA010368@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Thu Jan  8 18:02:05 2015
New Revision: 276844
URL: https://svnweb.freebsd.org/changeset/base/276844

Log:
  * Use newly-created nd6_grab_holdchain() function to retrieve lle
    hold mbuf chain instead of calling full-blown nd6_output_lle()
    for each packet. This simplifies both callers and nd6_output_lle()
    implementation.
  * Make nd6_output_lle() static and remove now-unused lle and chain
    arguments.
  * Rename nd6_output_flush() -> nd6_flush_holdchain() to be consistent.
  * Move all pre-send transmit hooks to newly-created nd6_output_ifp().
    Now nd6_output(), nd6_output_lle() and nd6_flush_holdchain() are using
    it to send mbufs to if_output.
  * Remove SeND hook from nd6_na_input() because it was implemented
    incorrectly since the beginning (r211501):
    - it tagged initial input mbuf (m) instead of m_hold
    - tagging _all_ mbufs in holdchain seems to be wrong anyway.

Modified:
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6.h
  head/sys/netinet6/nd6_nbr.c

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Thu Jan  8 18:00:38 2015	(r276843)
+++ head/sys/netinet6/nd6.c	Thu Jan  8 18:02:05 2015	(r276844)
@@ -134,6 +134,8 @@ static struct llentry *nd6_free(struct l
 static void nd6_llinfo_timer(void *);
 static void clear_llinfo_pqueue(struct llentry *);
 static void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
+static int nd6_output_lle(struct ifnet *, struct ifnet *, struct mbuf *,
+	struct sockaddr_in6 *);
 
 static VNET_DEFINE(struct callout, nd6_slowtimo_ch);
 #define	V_nd6_slowtimo_ch		VNET(nd6_slowtimo_ch)
@@ -1646,42 +1648,8 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
 		ln->ln_state = newstate;
 
 		if (ln->ln_state == ND6_LLINFO_STALE) {
-			/*
-			 * XXX: since nd6_output() below will cause
-			 * state tansition to DELAY and reset the timer,
-			 * we must set the timer now, although it is actually
-			 * meaningless.
-			 */
-			nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz);
-
-			if (ln->la_hold) {
-				struct mbuf *m_hold, *m_hold_next;
-
-				/*
-				 * reset the la_hold in advance, to explicitly
-				 * prevent a la_hold lookup in nd6_output()
-				 * (wouldn't happen, though...)
-				 */
-				for (m_hold = ln->la_hold, ln->la_hold = NULL;
-				    m_hold; m_hold = m_hold_next) {
-					m_hold_next = m_hold->m_nextpkt;
-					m_hold->m_nextpkt = NULL;
-
-					/*
-					 * we assume ifp is not a p2p here, so
-					 * just set the 2nd argument as the
-					 * 1st one.
-					 */
-					nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln, &chain);
-				}
-				/*
-				 * If we have mbufs in the chain we need to do
-				 * deferred transmit. Copy the address from the
-				 * llentry before dropping the lock down below.
-				 */
-				if (chain != NULL)
-					memcpy(&sin6, L3_ADDR_SIN6(ln), sizeof(sin6));
-			}
+			if (ln->la_hold != NULL)
+				nd6_grab_holdchain(ln, &chain, &sin6);
 		} else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
 			/* probe right away */
 			nd6_llinfo_settimer_locked((void *)ln, 0);
@@ -1764,8 +1732,8 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
 		if (static_route)
 			ln = NULL;
 	}
-	if (chain)
-		nd6_output_flush(ifp, ifp, chain, &sin6);
+	if (chain != NULL)
+		nd6_flush_holdchain(ifp, ifp, chain, &sin6);
 	
 	/*
 	 * When the link-layer address of a router changes, select the
@@ -1833,6 +1801,79 @@ nd6_slowtimo(void *arg)
 	CURVNET_RESTORE();
 }
 
+void
+nd6_grab_holdchain(struct llentry *ln, struct mbuf **chain,
+    struct sockaddr_in6 *sin6)
+{
+
+	LLE_WLOCK_ASSERT(ln);
+
+	*chain = ln->la_hold;
+	ln->la_hold = NULL;
+	memcpy(sin6, L3_ADDR_SIN6(ln), sizeof(*sin6));
+
+	if (ln->ln_state == ND6_LLINFO_STALE) {
+
+		/*
+		 * The first time we send a packet to a
+		 * neighbor whose entry is STALE, we have
+		 * to change the state to DELAY and a sets
+		 * a timer to expire in DELAY_FIRST_PROBE_TIME
+		 * seconds to ensure do neighbor unreachability
+		 * detection on expiration.
+		 * (RFC 2461 7.3.3)
+		 */
+		ln->la_asked = 0;
+		ln->ln_state = ND6_LLINFO_DELAY;
+		nd6_llinfo_settimer_locked(ln, (long)V_nd6_delay * hz);
+	}
+}
+
+static int
+nd6_output_ifp(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
+    struct sockaddr_in6 *dst)
+{
+	int error;
+	int ip6len;
+	struct ip6_hdr *ip6;
+	struct m_tag *mtag;
+
+#ifdef MAC
+	mac_netinet6_nd6_send(ifp, m);
+#endif
+
+	/*
+	 * If called from nd6_ns_output() (NS), nd6_na_output() (NA),
+	 * icmp6_redirect_output() (REDIRECT) or from rip6_output() (RS, RA
+	 * as handled by rtsol and rtadvd), mbufs will be tagged for SeND
+	 * to be diverted to user space.  When re-injected into the kernel,
+	 * send_output() will directly dispatch them to the outgoing interface.
+	 */
+	if (send_sendso_input_hook != NULL) {
+		mtag = m_tag_find(m, PACKET_TAG_ND_OUTGOING, NULL);
+		if (mtag != NULL) {
+			ip6 = mtod(m, struct ip6_hdr *);
+			ip6len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
+			/* Use the SEND socket */
+			error = send_sendso_input_hook(m, ifp, SND_OUT,
+			    ip6len);
+			/* -1 == no app on SEND socket */
+			if (error == 0 || error != -1)
+			    return (error);
+		}
+	}
+
+	m_clrprotoflags(m);	/* Avoid confusing lower layers. */
+	IP_PROBE(send, NULL, NULL, mtod(m, struct ip6_hdr *), ifp, NULL,
+	    mtod(m, struct ip6_hdr *));
+
+	if ((ifp->if_flags & IFF_LOOPBACK) == 0)
+		origifp = ifp;
+
+	error = (*ifp->if_output)(origifp, m, (struct sockaddr *)dst, NULL);
+	return (error);
+}
+
 /*
  * IPv6 packet output - light version.
  * Checks if destination LLE exists and is in proper state
@@ -1844,7 +1885,6 @@ nd6_output(struct ifnet *ifp, struct ifn
     struct sockaddr_in6 *dst, struct rtentry *rt0)
 {
 	struct llentry *ln = NULL;
-	int error = 0;
 
 	/* discard the packet if IPv6 operation is disabled on the interface */
 	if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) {
@@ -1875,50 +1915,14 @@ nd6_output(struct ifnet *ifp, struct ifn
 		/* Fall back to slow processing path */
 		if (ln != NULL)
 			LLE_RUNLOCK(ln);
-		return (nd6_output_lle(ifp, origifp, m, dst, rt0, NULL, NULL));
+		return (nd6_output_lle(ifp, origifp, m, dst));
 	}
 
 sendpkt:
 	if (ln != NULL)
 		LLE_RUNLOCK(ln);
 
-#ifdef MAC
-	mac_netinet6_nd6_send(ifp, m);
-#endif
-
-	/*
-	 * If called from nd6_ns_output() (NS), nd6_na_output() (NA),
-	 * icmp6_redirect_output() (REDIRECT) or from rip6_output() (RS, RA
-	 * as handled by rtsol and rtadvd), mbufs will be tagged for SeND
-	 * to be diverted to user space.  When re-injected into the kernel,
-	 * send_output() will directly dispatch them to the outgoing interface.
-	 */
-	if (send_sendso_input_hook != NULL) {
-		struct m_tag *mtag;
-		struct ip6_hdr *ip6;
-		int ip6len;
-		mtag = m_tag_find(m, PACKET_TAG_ND_OUTGOING, NULL);
-		if (mtag != NULL) {
-			ip6 = mtod(m, struct ip6_hdr *);
-			ip6len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
-			/* Use the SEND socket */
-			error = send_sendso_input_hook(m, ifp, SND_OUT,
-			    ip6len);
-			/* -1 == no app on SEND socket */
-			if (error == 0 || error != -1)
-			    return (error);
-		}
-	}
-
-	m_clrprotoflags(m);	/* Avoid confusing lower layers. */
-	IP_PROBE(send, NULL, NULL, mtod(m, struct ip6_hdr *), ifp, NULL,
-	    mtod(m, struct ip6_hdr *));
-
-	if ((ifp->if_flags & IFF_LOOPBACK) == 0)
-		origifp = ifp;
-	
-	error = (*ifp->if_output)(origifp, m, (struct sockaddr *)dst, NULL);
-	return (error);
+	return (nd6_output_ifp(ifp, origifp, m, dst));
 }
 
 
@@ -1931,26 +1935,13 @@ sendpkt:
  *   in that case packets are queued in &chain.
  *
  */
-int
+static int
 nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
-    struct sockaddr_in6 *dst, struct rtentry *rt0, struct llentry *lle,
-	struct mbuf **chain)
+    struct sockaddr_in6 *dst)
 {
-	struct m_tag *mtag;
-	struct ip6_hdr *ip6;
-	int error = 0;
+	struct llentry *lle = NULL;
 	int flags = 0;
-	int has_lle = 0;
-	int ip6len;
-
-#ifdef INVARIANTS
-	if (lle != NULL) {
-		
-		LLE_WLOCK_ASSERT(lle);
 
-		KASSERT(chain != NULL, (" lle locked but no mbuf chain pointer passed"));
-	}
-#endif
 	KASSERT(m != NULL, ("NULL mbuf, nothing to send"));
 	/* discard the packet if IPv6 operation is disabled on the interface */
 	if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) {
@@ -1958,9 +1949,6 @@ nd6_output_lle(struct ifnet *ifp, struct
 		return (ENETDOWN); /* better error? */
 	}
 
-	if (lle != NULL)
-		has_lle = 1;
-
 	if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
 		goto sendpkt;
 
@@ -2076,88 +2064,23 @@ nd6_output_lle(struct ifnet *ifp, struct
 		    (long)ND_IFINFO(ifp)->retrans * hz / 1000);
 		LLE_WUNLOCK(lle);
 		nd6_ns_output(ifp, NULL, &dst->sin6_addr, lle, 0);
-		if (has_lle != 0)
-			LLE_WLOCK(lle);
-	} else if (has_lle == 0) {
-		/*
-		 * We did the lookup (no lle arg) so we
-		 * need to do the unlock here.
-		 */
+	} else {
+		/* We did the lookup so we need to do the unlock here. */
 		LLE_WUNLOCK(lle);
 	}
 
 	return (0);
 
   sendpkt:
-	/*
-	 * ln is valid and the caller did not pass in 
-	 * an llentry
-	 */
-	if (lle != NULL && has_lle == 0)
+	if (lle != NULL)
 		LLE_WUNLOCK(lle);
 
-#ifdef MAC
-	mac_netinet6_nd6_send(ifp, m);
-#endif
-
-	/*
-	 * If called from nd6_ns_output() (NS), nd6_na_output() (NA),
-	 * icmp6_redirect_output() (REDIRECT) or from rip6_output() (RS, RA
-	 * as handled by rtsol and rtadvd), mbufs will be tagged for SeND
-	 * to be diverted to user space.  When re-injected into the kernel,
-	 * send_output() will directly dispatch them to the outgoing interface.
-	 */
-	if (send_sendso_input_hook != NULL) {
-		mtag = m_tag_find(m, PACKET_TAG_ND_OUTGOING, NULL);
-		if (mtag != NULL) {
-			ip6 = mtod(m, struct ip6_hdr *);
-			ip6len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
-			/* Use the SEND socket */
-			error = send_sendso_input_hook(m, ifp, SND_OUT,
-			    ip6len);
-			/* -1 == no app on SEND socket */
-			if (error == 0 || error != -1)
-			    return (error);
-		}
-	}
-
-	/*
-	 * We were passed in a pointer to an lle with the lock held 
-	 * this means that we can't call if_output as we will
-	 * recurse on the lle lock - so what we do is we create
-	 * a list of mbufs to send and transmit them in the caller
-	 * after the lock is dropped
-	 */
-	if (has_lle != 0) {
-		if (*chain == NULL)
-			*chain = m;
-		else {
-			struct mbuf *mb;
-
-			/*
-			 * append mbuf to end of deferred chain
-			 */
-			mb = *chain;
-			while (mb->m_nextpkt != NULL)
-				mb = mb->m_nextpkt;
-			mb->m_nextpkt = m;
-		}
-		return (error);
-	}
-	m_clrprotoflags(m);	/* Avoid confusing lower layers. */
-	IP_PROBE(send, NULL, NULL, mtod(m, struct ip6_hdr *), ifp, NULL,
-	    mtod(m, struct ip6_hdr *));
-
-	if ((ifp->if_flags & IFF_LOOPBACK) == 0)
-		origifp = ifp;
-
-	error = (*ifp->if_output)(origifp, m, (struct sockaddr *)dst, NULL);
-	return (error);
+	return (nd6_output_ifp(ifp, origifp, m, dst));
 }
 
 
 int
-nd6_output_flush(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *chain,
+nd6_flush_holdchain(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *chain,
     struct sockaddr_in6 *dst)
 {
 	struct mbuf *m, *m_head;
@@ -2173,7 +2096,7 @@ nd6_output_flush(struct ifnet *ifp, stru
 	while (m_head) {
 		m = m_head;
 		m_head = m_head->m_nextpkt;
-		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, NULL);
+		error = nd6_output_ifp(ifp, origifp, m, dst);
 	}
 
 	/*

Modified: head/sys/netinet6/nd6.h
==============================================================================
--- head/sys/netinet6/nd6.h	Thu Jan  8 18:00:38 2015	(r276843)
+++ head/sys/netinet6/nd6.h	Thu Jan  8 18:02:05 2015	(r276844)
@@ -409,11 +409,10 @@ struct llentry *nd6_cache_lladdr(struct 
 	char *, int, int, int);
 int nd6_output(struct ifnet *, struct ifnet *, struct mbuf *,
 	struct sockaddr_in6 *, struct rtentry *);
-int nd6_output_lle(struct ifnet *, struct ifnet *, struct mbuf *,
-	struct sockaddr_in6 *, struct rtentry *, struct llentry *,
-	struct mbuf **);
-int nd6_output_flush(struct ifnet *, struct ifnet *, struct mbuf *,
-	struct sockaddr_in6 *);
+void nd6_grab_holdchain(struct llentry *, struct mbuf **,
+    struct sockaddr_in6 *);
+int nd6_flush_holdchain(struct ifnet *, struct ifnet *, struct mbuf *,
+    struct sockaddr_in6 *);
 int nd6_need_cache(struct ifnet *);
 int nd6_add_ifa_lle(struct in6_ifaddr *);
 void nd6_rem_ifa_lle(struct in6_ifaddr *);

Modified: head/sys/netinet6/nd6_nbr.c
==============================================================================
--- head/sys/netinet6/nd6_nbr.c	Thu Jan  8 18:00:38 2015	(r276843)
+++ head/sys/netinet6/nd6_nbr.c	Thu Jan  8 18:02:05 2015	(r276844)
@@ -626,7 +626,6 @@ nd6_na_input(struct mbuf *m, int off, in
 	struct llentry *ln = NULL;
 	union nd_opts ndopts;
 	struct mbuf *chain = NULL;
-	struct m_tag *mtag;
 	struct sockaddr_in6 sin6;
 	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
 
@@ -653,6 +652,7 @@ nd6_na_input(struct mbuf *m, int off, in
 	is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
 	is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
 	is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
+	memset(&sin6, 0, sizeof(sin6));
 
 	taddr6 = nd_na->nd_na_target;
 	if (in6_setscope(&taddr6, ifp, NULL))
@@ -891,43 +891,15 @@ nd6_na_input(struct mbuf *m, int off, in
 	 *  rt->rt_flags &= ~RTF_REJECT;
 	 */
 	ln->la_asked = 0;
-	if (ln->la_hold) {
-		struct mbuf *m_hold, *m_hold_next;
-
-		/*
-		 * reset the la_hold in advance, to explicitly
-		 * prevent a la_hold lookup in nd6_output()
-		 * (wouldn't happen, though...)
-		 */
-		for (m_hold = ln->la_hold, ln->la_hold = NULL;
-		    m_hold; m_hold = m_hold_next) {
-			m_hold_next = m_hold->m_nextpkt;
-			m_hold->m_nextpkt = NULL;
-			/*
-			 * we assume ifp is not a loopback here, so just set
-			 * the 2nd argument as the 1st one.
-			 */
-
-			if (send_sendso_input_hook != NULL) {
-				mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
-				    sizeof(unsigned short), M_NOWAIT);
-				if (mtag == NULL)
-					goto bad;
-				m_tag_prepend(m, mtag);
-			}
-
-			nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln, &chain);
-		}
-	}
+	if (ln->la_hold != NULL)
+		nd6_grab_holdchain(ln, &chain, &sin6);
  freeit:
-	if (ln != NULL) {
-		if (chain)
-			memcpy(&sin6, L3_ADDR_SIN6(ln), sizeof(sin6));
+	if (ln != NULL)
 		LLE_WUNLOCK(ln);
 
-		if (chain)
-			nd6_output_flush(ifp, ifp, chain, &sin6);
-	}
+	if (chain != NULL)
+		nd6_flush_holdchain(ifp, ifp, chain, &sin6);
+
 	if (checklink)
 		pfxlist_onlink_check();
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201501081802.t08I26nA010368>