summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2010-05-17 19:36:56 +0000
committerjhb <jhb@FreeBSD.org>2010-05-17 19:36:56 +0000
commit7df2d528cf045cabdde0958dcab7be61d3383c5f (patch)
treed8735b798a10bd7fe360adddef13fee1f295d067 /sys/net
parentb503e7f715283991d86dae898ab32a0d787943be (diff)
downloadFreeBSD-src-7df2d528cf045cabdde0958dcab7be61d3383c5f.zip
FreeBSD-src-7df2d528cf045cabdde0958dcab7be61d3383c5f.tar.gz
Ignore failures from removing multicast addresses from the parent (trunk)
interface when tearing down a vlan interface. If a trunk interface is detached, all of its multicast addresses are removed before the ifnet departure eventhandlers are invoked. This means that all of the multicast addresses are removed before the vlan interfaces are removed which causes the if_delmulti() calls in the vlan teardown to fail. In the VLAN_ARRAY case, this left vlan interfaces referencing a no longer valid parent interface. In the !VLAN_ARRAY case, the eventhandler gets stuck in an infinite loop retrying vlan_unconfig_locked() forever. In general the callers of vlan_unconfig_locked() do not expect nor handle failure, so I believe it is safer to ignore the errors and tear down as much of the vlan state as possible. Silence from: net@ MFC after: 4 days
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_vlan.c27
1 files changed, 14 insertions, 13 deletions
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 01a8297..9235bd3 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -187,8 +187,8 @@ static int vlan_setflag(struct ifnet *ifp, int flag, int status,
int (*func)(struct ifnet *, int));
static int vlan_setflags(struct ifnet *ifp, int status);
static int vlan_setmulti(struct ifnet *ifp);
-static int vlan_unconfig(struct ifnet *ifp);
-static int vlan_unconfig_locked(struct ifnet *ifp);
+static void vlan_unconfig(struct ifnet *ifp);
+static void vlan_unconfig_locked(struct ifnet *ifp);
static int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag);
static void vlan_link_state(struct ifnet *ifp);
static void vlan_capabilities(struct ifvlan *ifv);
@@ -1128,25 +1128,22 @@ done:
return (error);
}
-static int
+static void
vlan_unconfig(struct ifnet *ifp)
{
- int ret;
VLAN_LOCK();
- ret = vlan_unconfig_locked(ifp);
+ vlan_unconfig_locked(ifp);
VLAN_UNLOCK();
- return (ret);
}
-static int
+static void
vlan_unconfig_locked(struct ifnet *ifp)
{
struct ifvlantrunk *trunk;
struct vlan_mc_entry *mc;
struct ifvlan *ifv;
struct ifnet *parent;
- int error;
VLAN_LOCK_ASSERT();
@@ -1175,9 +1172,15 @@ vlan_unconfig_locked(struct ifnet *ifp)
while ((mc = SLIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
bcopy((char *)&mc->mc_addr, LLADDR(&sdl),
ETHER_ADDR_LEN);
- error = if_delmulti(parent, (struct sockaddr *)&sdl);
- if (error)
- return (error);
+
+ /*
+ * This may fail if the parent interface is
+ * being detached. Regardless, we should do a
+ * best effort to free this interface as much
+ * as possible as all callers expect vlan
+ * destruction to succeed.
+ */
+ (void)if_delmulti(parent, (struct sockaddr *)&sdl);
SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
free(mc, M_VLAN);
}
@@ -1223,8 +1226,6 @@ vlan_unconfig_locked(struct ifnet *ifp)
*/
if (parent != NULL)
EVENTHANDLER_INVOKE(vlan_unconfig, parent, ifv->ifv_tag);
-
- return (0);
}
/* Handle a reference counted flag that should be set on the parent as well */
OpenPOWER on IntegriCloud