From owner-svn-src-all@FreeBSD.ORG Mon Aug 4 00:58:13 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 5E8B1A1F for ; Mon, 4 Aug 2014 00:58:13 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 3CB942620 for ; Mon, 4 Aug 2014 00:58:13 +0000 (UTC) Received: from mav (uid 1131) (envelope-from mav@FreeBSD.org) id 5d4c by svn.freebsd.org (DragonFly Mail Agent v0.9+); Mon, 04 Aug 2014 00:58:12 +0000 From: Alexander Motin Date: Mon, 4 Aug 2014 00:58:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r269492 - head/sys/net X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-Id: <53dedaa5.5d4c.7dda49d8@svn.freebsd.org> X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Aug 2014 00:58:13 -0000 Author: mav Date: Mon Aug 4 00:58:12 2014 New Revision: 269492 URL: http://svnweb.freebsd.org/changeset/base/269492 Log: Improve locking of multicast addresses in VLAN and LAGG interfaces. This fixes several scenarios of reproducible panics, cause by races between multicast address changes and interface destruction. MFC after: 2 weeks Modified: head/sys/net/if_lagg.c head/sys/net/if_lagg.h head/sys/net/if_vlan.c Modified: head/sys/net/if_lagg.c ============================================================================== --- head/sys/net/if_lagg.c Mon Aug 4 00:51:57 2014 (r269491) +++ head/sys/net/if_lagg.c Mon Aug 4 00:58:12 2014 (r269492) @@ -1217,35 +1217,39 @@ lagg_ether_cmdmulti(struct lagg_port *lp struct ifnet *ifp = lp->lp_ifp; struct ifnet *scifp = sc->sc_ifp; struct lagg_mc *mc; - struct ifmultiaddr *ifma, *rifma = NULL; - struct sockaddr_dl sdl; + struct ifmultiaddr *ifma; int error; LAGG_WLOCK_ASSERT(sc); - link_init_sdl(ifp, (struct sockaddr *)&sdl, IFT_ETHER); - sdl.sdl_alen = ETHER_ADDR_LEN; - if (set) { + IF_ADDR_WLOCK(scifp); TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - LLADDR(&sdl), ETHER_ADDR_LEN); - - error = if_addmulti(ifp, (struct sockaddr *)&sdl, &rifma); - if (error) - return (error); mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT); - if (mc == NULL) + if (mc == NULL) { + IF_ADDR_WUNLOCK(scifp); return (ENOMEM); - mc->mc_ifma = rifma; + } + bcopy(ifma->ifma_addr, &mc->mc_addr, + ifma->ifma_addr->sa_len); + mc->mc_addr.sdl_index = ifp->if_index; + mc->mc_ifma = NULL; SLIST_INSERT_HEAD(&lp->lp_mc_head, mc, mc_entries); } + IF_ADDR_WUNLOCK(scifp); + SLIST_FOREACH (mc, &lp->lp_mc_head, mc_entries) { + error = if_addmulti(ifp, + (struct sockaddr *)&mc->mc_addr, &mc->mc_ifma); + if (error) + return (error); + } } else { while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) { SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries); - if_delmulti_ifma(mc->mc_ifma); + if (mc->mc_ifma && !lp->lp_detaching) + if_delmulti_ifma(mc->mc_ifma); free(mc, M_DEVBUF); } } Modified: head/sys/net/if_lagg.h ============================================================================== --- head/sys/net/if_lagg.h Mon Aug 4 00:51:57 2014 (r269491) +++ head/sys/net/if_lagg.h Mon Aug 4 00:58:12 2014 (r269492) @@ -174,6 +174,7 @@ struct lagg_lb { }; struct lagg_mc { + struct sockaddr_dl mc_addr; struct ifmultiaddr *mc_ifma; SLIST_ENTRY(lagg_mc) mc_entries; }; Modified: head/sys/net/if_vlan.c ============================================================================== --- head/sys/net/if_vlan.c Mon Aug 4 00:51:57 2014 (r269491) +++ head/sys/net/if_vlan.c Mon Aug 4 00:58:12 2014 (r269492) @@ -460,48 +460,48 @@ trunk_destroy(struct ifvlantrunk *trunk) * traffic that it doesn't really want, which ends up being discarded * later by the upper protocol layers. Unfortunately, there's no way * to avoid this: there really is only one physical interface. - * - * XXX: There is a possible race here if more than one thread is - * modifying the multicast state of the vlan interface at the same time. */ static int vlan_setmulti(struct ifnet *ifp) { struct ifnet *ifp_p; - struct ifmultiaddr *ifma, *rifma = NULL; + struct ifmultiaddr *ifma; struct ifvlan *sc; struct vlan_mc_entry *mc; int error; - /*VLAN_LOCK_ASSERT();*/ - /* Find the parent. */ sc = ifp->if_softc; + TRUNK_LOCK_ASSERT(TRUNK(sc)); ifp_p = PARENT(sc); CURVNET_SET_QUIET(ifp_p->if_vnet); /* First, remove any existing filter entries. */ while ((mc = SLIST_FIRST(&sc->vlan_mc_listhead)) != NULL) { - error = if_delmulti(ifp_p, (struct sockaddr *)&mc->mc_addr); - if (error) - return (error); SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries); + (void)if_delmulti(ifp_p, (struct sockaddr *)&mc->mc_addr); free(mc, M_VLAN); } /* Now program new ones. */ + IF_ADDR_WLOCK(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT); - if (mc == NULL) + if (mc == NULL) { + IF_ADDR_WUNLOCK(ifp); return (ENOMEM); + } bcopy(ifma->ifma_addr, &mc->mc_addr, ifma->ifma_addr->sa_len); mc->mc_addr.sdl_index = ifp_p->if_index; SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries); + } + IF_ADDR_WUNLOCK(ifp); + SLIST_FOREACH (mc, &sc->vlan_mc_listhead, mc_entries) { error = if_addmulti(ifp_p, (struct sockaddr *)&mc->mc_addr, - &rifma); + NULL); if (error) return (error); } @@ -1374,7 +1374,7 @@ vlan_unconfig_locked(struct ifnet *ifp, * Check if we were the last. */ if (trunk->refcnt == 0) { - trunk->parent->if_vlantrunk = NULL; + parent->if_vlantrunk = NULL; /* * XXXGL: If some ithread has already entered * vlan_input() and is now blocked on the trunk @@ -1568,6 +1568,7 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd struct ifreq *ifr; struct ifaddr *ifa; struct ifvlan *ifv; + struct ifvlantrunk *trunk; struct vlanreq vlr; int error = 0; @@ -1712,8 +1713,12 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd * If we don't have a parent, just remember the membership for * when we do. */ - if (TRUNK(ifv) != NULL) + trunk = TRUNK(ifv); + if (trunk != NULL) { + TRUNK_LOCK(trunk); error = vlan_setmulti(ifp); + TRUNK_UNLOCK(trunk); + } break; default: