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>