Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 4 Mar 2009 03:45:35 +0000 (UTC)
From:      Bruce M Simpson <bms@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r189359 - head/sys/netinet
Message-ID:  <200903040345.n243jZsQ031038@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bms
Date: Wed Mar  4 03:45:34 2009
New Revision: 189359
URL: http://svn.freebsd.org/changeset/base/189359

Log:
  In ip_output(), do not acquire the IN_MULTI_LOCK(),
  and do not attempt to perform a group lookup.
  This is a socket layer lock, and the bottom half of IP
  really has no business taking it.
  
  Use the value of the in_mcast_loop sysctl to determine
  if we should loop back by default, in the absence of
  any multicast socket options. Because the check on
  group membership is now deferred to the input path,
  an m_copym() is now required.
  
  This should increase multicast send performance where the
  source has not requested loopback, although this has not been
  benchmarked or measured.
  
  It is also a necessary change for IN_MULTI_LOCK to become
  non-recursive, which is required in order to implement IGMPv3
  in a thread-safe way.

Modified:
  head/sys/netinet/ip_output.c

Modified: head/sys/netinet/ip_output.c
==============================================================================
--- head/sys/netinet/ip_output.c	Wed Mar  4 03:45:02 2009	(r189358)
+++ head/sys/netinet/ip_output.c	Wed Mar  4 03:45:34 2009	(r189359)
@@ -112,6 +112,7 @@ static void	ip_mloopback
 	(struct ifnet *, struct mbuf *, struct sockaddr_in *, int);
 
 
+extern int in_mcast_loop;
 extern	struct protosw inetsw[];
 
 /*
@@ -293,8 +294,6 @@ again:
 		mtu = ifp->if_mtu;
 	}
 	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
-		struct in_multi *inm;
-
 		m->m_flags |= M_MCAST;
 		/*
 		 * IP destination address is multicast.  Make sure "dst"
@@ -334,20 +333,17 @@ again:
 				ip->ip_src = IA_SIN(ia)->sin_addr;
 		}
 
-		IN_MULTI_LOCK();
-		IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
-		if (inm != NULL &&
-		   (imo == NULL || imo->imo_multicast_loop)) {
-			IN_MULTI_UNLOCK();
+		if ((imo == NULL && in_mcast_loop) ||
+		    (imo && imo->imo_multicast_loop)) {
 			/*
-			 * If we belong to the destination multicast group
-			 * on the outgoing interface, and the caller did not
-			 * forbid loopback, loop back a copy.
+			 * Loop back multicast datagram if not expressly
+			 * forbidden to do so, even if we are not a member
+			 * of the group; ip_input() will filter it later,
+			 * thus deferring a hash lookup and mutex acquisition
+			 * at the expense of a cheap copy using m_copym().
 			 */
 			ip_mloopback(ifp, m, dst, hlen);
-		}
-		else {
-			IN_MULTI_UNLOCK();
+		} else {
 			/*
 			 * If we are acting as a multicast router, perform
 			 * multicast forwarding as if the packet had just
@@ -382,8 +378,9 @@ again:
 		 * back, above, but must not be transmitted on a network.
 		 * Also, multicasts addressed to the loopback interface
 		 * are not sent -- the above call to ip_mloopback() will
-		 * loop back a copy if this host actually belongs to the
-		 * destination group on the loopback interface.
+		 * loop back a copy. ip_input() will drop the copy if
+		 * this host does not belong to the destination group on
+		 * the loopback interface.
 		 */
 		if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) {
 			m_freem(m);
@@ -758,7 +755,7 @@ smart_frag_failure:
 		/*
 		 * In the first mbuf, leave room for the link header, then
 		 * copy the original IP header including options. The payload
-		 * goes into an additional mbuf chain returned by m_copy().
+		 * goes into an additional mbuf chain returned by m_copym().
 		 */
 		m->m_data += max_linkhdr;
 		mhip = mtod(m, struct ip *);
@@ -777,7 +774,7 @@ smart_frag_failure:
 		} else
 			mhip->ip_off |= IP_MF;
 		mhip->ip_len = htons((u_short)(len + mhlen));
-		m->m_next = m_copy(m0, off, len);
+		m->m_next = m_copym(m0, off, len, M_DONTWAIT);
 		if (m->m_next == NULL) {	/* copy failed */
 			m_free(m);
 			error = ENOBUFS;	/* ??? */



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