From owner-svn-src-projects@FreeBSD.ORG Sun Dec 14 01:12:55 2008 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id AE45D106564A; Sun, 14 Dec 2008 01:12:55 +0000 (UTC) (envelope-from kmacy@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 9EC688FC18; Sun, 14 Dec 2008 01:12:55 +0000 (UTC) (envelope-from kmacy@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id mBE1CtQo045203; Sun, 14 Dec 2008 01:12:55 GMT (envelope-from kmacy@svn.freebsd.org) Received: (from kmacy@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id mBE1Ctur045200; Sun, 14 Dec 2008 01:12:55 GMT (envelope-from kmacy@svn.freebsd.org) Message-Id: <200812140112.mBE1Ctur045200@svn.freebsd.org> From: Kip Macy Date: Sun, 14 Dec 2008 01:12:55 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r186070 - projects/arpv2_merge_1/sys/netinet6 X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 14 Dec 2008 01:12:55 -0000 Author: kmacy Date: Sun Dec 14 01:12:55 2008 New Revision: 186070 URL: http://svn.freebsd.org/changeset/base/186070 Log: Avoid a lock recursion in the call to if_output from nd6_output_lle by creating a chain of packets to be sent after the nd6_output_lle caller drops the lle lock. Modified: projects/arpv2_merge_1/sys/netinet6/nd6.c projects/arpv2_merge_1/sys/netinet6/nd6.h projects/arpv2_merge_1/sys/netinet6/nd6_nbr.c Modified: projects/arpv2_merge_1/sys/netinet6/nd6.c ============================================================================== --- projects/arpv2_merge_1/sys/netinet6/nd6.c Sun Dec 14 00:40:14 2008 (r186069) +++ projects/arpv2_merge_1/sys/netinet6/nd6.c Sun Dec 14 01:12:55 2008 (r186070) @@ -1404,6 +1404,8 @@ nd6_cache_lladdr(struct ifnet *ifp, stru int llchange; int flags = 0; int newstate = 0; + struct sockaddr_in6 sin6; + struct mbuf *chain = NULL; IF_AFDATA_UNLOCK_ASSERT(ifp); @@ -1519,8 +1521,10 @@ nd6_cache_lladdr(struct ifnet *ifp, stru * just set the 2nd argument as the * 1st one. */ - nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln); + nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln, &chain); } + if (chain) + memcpy(&sin6, L3_ADDR_SIN6(ln), sizeof(sin6)); } } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* probe right away */ @@ -1593,6 +1597,17 @@ nd6_cache_lladdr(struct ifnet *ifp, stru break; } + if (ln) { + if (flags & ND6_EXCLUSIVE) + LLE_WUNLOCK(ln); + else + LLE_RUNLOCK(ln); + if (ln->la_flags & LLE_STATIC) + ln = NULL; + } + if (chain) + nd6_output_flush(ifp, ifp, chain, &sin6, NULL); + /* * When the link-layer address of a router changes, select the * best router again. In particular, when the neighbor entry is newly @@ -1609,18 +1624,13 @@ nd6_cache_lladdr(struct ifnet *ifp, stru * cases for safety. */ if (do_update && ln->ln_router && !V_ip6_forwarding && V_ip6_accept_rtadv) { -#ifdef notyet - /* - * XXX implement the boiler plate - */ - taskqueue_enqueue(ipv6_taskq, defrouter_select_task); -#endif /* * guaranteed recursion */ defrouter_select(); } + return (ln); done: if (ln) { if (flags & ND6_EXCLUSIVE) @@ -1669,7 +1679,7 @@ nd6_output(struct ifnet *ifp, struct ifn struct sockaddr_in6 *dst, struct rtentry *rt0) { - return (nd6_output_lle(ifp, origifp, m0, dst, rt0, NULL)); + return (nd6_output_lle(ifp, origifp, m0, dst, rt0, NULL, NULL)); } @@ -1685,7 +1695,8 @@ nd6_output(struct ifnet *ifp, struct ifn int nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, - struct sockaddr_in6 *dst, struct rtentry *rt0, struct llentry *lle) + struct sockaddr_in6 *dst, struct rtentry *rt0, struct llentry *lle, + struct mbuf **tail) { INIT_VNET_INET6(curvnet); struct mbuf *m = m0; @@ -1695,8 +1706,12 @@ nd6_output_lle(struct ifnet *ifp, struct int flags = 0; #ifdef INVARIANTS - if (lle) + if (lle) { + LLE_WLOCK_ASSERT(lle); + + KASSERT(tail != NULL, (" lle locked but no tail pointer passed")); + } #endif if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; @@ -1715,7 +1730,7 @@ nd6_output_lle(struct ifnet *ifp, struct * or an anycast address(i.e. not a multicast). */ - flags = (m || lle) ? LLE_EXCLUSIVE : 0; + flags = ((m != NULL) || (lle != NULL)) ? LLE_EXCLUSIVE : 0; if (ln == NULL) { retry: IF_AFDATA_LOCK(rt->rt_ifp); @@ -1863,6 +1878,13 @@ nd6_output_lle(struct ifnet *ifp, struct #ifdef MAC mac_netinet6_nd6_send(ifp, m); #endif + if (lle != NULL) { + if (*tail == NULL) + *tail = m; + else + (*tail)->m_nextpkt = m; + return (error); + } if ((ifp->if_flags & IFF_LOOPBACK) != 0) { return ((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, rt)); @@ -1887,6 +1909,37 @@ nd6_output_lle(struct ifnet *ifp, struct } #undef senderr + +int +nd6_output_flush(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *chain, + struct sockaddr_in6 *dst, struct rtentry *rt) +{ + struct mbuf *m, *m_head; + struct ifnet *outifp; + int error = 0; + + m_head = chain; + if ((ifp->if_flags & IFF_LOOPBACK) != 0) + outifp = origifp; + else + outifp = ifp; + + while (m_head) { + m = m_head; + m_head = m_head->m_nextpkt; + error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt); + } + + /* + * XXX + * note that intermediate errors are blindly ignored - but this is + * the same convention as used with nd6_output when called by + * nd6_cache_lladdr + */ + return (error); +} + + int nd6_need_cache(struct ifnet *ifp) { Modified: projects/arpv2_merge_1/sys/netinet6/nd6.h ============================================================================== --- projects/arpv2_merge_1/sys/netinet6/nd6.h Sun Dec 14 00:40:14 2008 (r186069) +++ projects/arpv2_merge_1/sys/netinet6/nd6.h Sun Dec 14 01:12:55 2008 (r186070) @@ -392,7 +392,10 @@ struct llentry *nd6_cache_lladdr __P((st int nd6_output __P((struct ifnet *, struct ifnet *, struct mbuf *, struct sockaddr_in6 *, struct rtentry *)); int nd6_output_lle __P((struct ifnet *, struct ifnet *, struct mbuf *, - struct sockaddr_in6 *, struct rtentry *, struct llentry *)); + struct sockaddr_in6 *, struct rtentry *, struct llentry *, + struct mbuf **)); +int nd6_output_flush __P((struct ifnet *, struct ifnet *, struct mbuf *, + struct sockaddr_in6 *, struct rtentry *)); int nd6_need_cache __P((struct ifnet *)); int nd6_storelladdr __P((struct ifnet *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *, struct llentry **)); Modified: projects/arpv2_merge_1/sys/netinet6/nd6_nbr.c ============================================================================== --- projects/arpv2_merge_1/sys/netinet6/nd6_nbr.c Sun Dec 14 00:40:14 2008 (r186069) +++ projects/arpv2_merge_1/sys/netinet6/nd6_nbr.c Sun Dec 14 01:12:55 2008 (r186070) @@ -606,6 +606,8 @@ nd6_na_input(struct mbuf *m, int off, in struct ifaddr *ifa; struct llentry *ln = NULL; union nd_opts ndopts; + struct mbuf *chain = NULL; + struct sockaddr_in6 sin6; char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; if (ip6->ip6_hlim != 255) { @@ -872,13 +874,18 @@ nd6_na_input(struct mbuf *m, int off, in * we assume ifp is not a loopback here, so just set * the 2nd argument as the 1st one. */ - nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln); + nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln, &chain); } } freeit: - if (ln) + if (ln) { + if (chain) + memcpy(&sin6, L3_ADDR_SIN6(ln), sizeof(sin6)); LLE_WUNLOCK(ln); + if (chain) + nd6_output_flush(ifp, ifp, chain, &sin6, NULL); + } m_freem(m); return;