Module Name: src
Committed By: msaitoh
Date: Wed Jul 17 03:26:24 UTC 2019
Modified Files:
src/sbin/ifconfig: ether.c
src/sys/dev/pci/ixgbe: ixgbe.c ixgbe.h ixv.c
src/sys/net: if_ether.h if_ethersubr.c if_vlan.c
Log Message:
Implement VLAN hardware filter function(ETHERCAP_VLAN_HWFILTER).
First proposed by jmcneill in 2017 and modified by me.
How to use:
- Set callback function:
ether_set_vlan_cb(struct ethercom *, ether_vlancb_t)
- Callback. This function is called when a vlan is attached/detached to the
parent interface:
int (*ether_vlancb_t)(struct ethercom *ec, uint16_t vlanid, bool set);
- ifconfig(8)
ifconfig ixg0 [-]vlan-hwfilter
Note that ETHERCAP_VLAN_HWFILTER is set by default on ixg(4) because
the PF driver usually enable "all block" filter by default.
To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sbin/ifconfig/ether.c
cvs rdiff -u -r1.192 -r1.193 src/sys/dev/pci/ixgbe/ixgbe.c
cvs rdiff -u -r1.55 -r1.56 src/sys/dev/pci/ixgbe/ixgbe.h
cvs rdiff -u -r1.119 -r1.120 src/sys/dev/pci/ixgbe/ixv.c
cvs rdiff -u -r1.80 -r1.81 src/sys/net/if_ether.h
cvs rdiff -u -r1.275 -r1.276 src/sys/net/if_ethersubr.c
cvs rdiff -u -r1.140 -r1.141 src/sys/net/if_vlan.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sbin/ifconfig/ether.c
diff -u src/sbin/ifconfig/ether.c:1.5 src/sbin/ifconfig/ether.c:1.6
--- src/sbin/ifconfig/ether.c:1.5 Wed Jul 17 03:09:16 2019
+++ src/sbin/ifconfig/ether.c Wed Jul 17 03:26:24 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: ether.c,v 1.5 2019/07/17 03:09:16 msaitoh Exp $ */
+/* $NetBSD: ether.c,v 1.6 2019/07/17 03:26:24 msaitoh Exp $ */
/*
* Copyright (c) 1983, 1993
@@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: ether.c,v 1.5 2019/07/17 03:09:16 msaitoh Exp $");
+__RCSID("$NetBSD: ether.c,v 1.6 2019/07/17 03:26:24 msaitoh Exp $");
#endif /* not lint */
#include <sys/param.h>
@@ -64,9 +64,7 @@ static cmdloop_branch_t branch;
#define MAX_PRINT_LEN 55
static const struct kwinst ethercapskw[] = {
-#if 0 /* notyet */
IFKW("vlan-hwfilter", ETHERCAP_VLAN_HWFILTER),
-#endif
IFKW("vlan-hwtagging", ETHERCAP_VLAN_HWTAGGING),
IFKW("eee", ETHERCAP_EEE)
};
Index: src/sys/dev/pci/ixgbe/ixgbe.c
diff -u src/sys/dev/pci/ixgbe/ixgbe.c:1.192 src/sys/dev/pci/ixgbe/ixgbe.c:1.193
--- src/sys/dev/pci/ixgbe/ixgbe.c:1.192 Thu Jul 4 09:02:24 2019
+++ src/sys/dev/pci/ixgbe/ixgbe.c Wed Jul 17 03:26:24 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe.c,v 1.192 2019/07/04 09:02:24 msaitoh Exp $ */
+/* $NetBSD: ixgbe.c,v 1.193 2019/07/17 03:26:24 msaitoh Exp $ */
/******************************************************************************
@@ -220,10 +220,9 @@ static u8 * ixgbe_mc_array_itr(struct ix
static void ixgbe_eitr_write(struct adapter *, uint32_t, uint32_t);
static void ixgbe_setup_vlan_hw_support(struct adapter *);
-#if 0
-static void ixgbe_register_vlan(void *, struct ifnet *, u16);
-static void ixgbe_unregister_vlan(void *, struct ifnet *, u16);
-#endif
+static int ixgbe_vlan_cb(struct ethercom *, uint16_t, bool);
+static int ixgbe_register_vlan(void *, struct ifnet *, u16);
+static int ixgbe_unregister_vlan(void *, struct ifnet *, u16);
static void ixgbe_add_device_sysctls(struct adapter *);
static void ixgbe_add_hw_stats(struct adapter *);
@@ -905,6 +904,9 @@ ixgbe_attach(device_t parent, device_t d
/* Enable WoL (if supported) */
ixgbe_check_wol_support(adapter);
+ /* Register for VLAN events */
+ ether_set_vlan_cb(&adapter->osdep.ec, ixgbe_vlan_cb);
+
/* Verify adapter fan is still functional (if applicable) */
if (adapter->feat_en & IXGBE_FEATURE_FAN_FAIL) {
u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
@@ -2299,7 +2301,20 @@ ixgbe_sysctl_rdt_handler(SYSCTLFN_ARGS)
return sysctl_lookup(SYSCTLFN_CALL(&node));
} /* ixgbe_sysctl_rdt_handler */
-#if 0 /* XXX Badly need to overhaul vlan(4) on NetBSD. */
+static int
+ixgbe_vlan_cb(struct ethercom *ec, uint16_t vid, bool set)
+{
+ struct ifnet *ifp = &ec->ec_if;
+ int rv;
+
+ if (set)
+ rv = ixgbe_register_vlan(ifp->if_softc, ifp, vid);
+ else
+ rv = ixgbe_unregister_vlan(ifp->if_softc, ifp, vid);
+
+ return rv;
+}
+
/************************************************************************
* ixgbe_register_vlan
*
@@ -2308,24 +2323,30 @@ ixgbe_sysctl_rdt_handler(SYSCTLFN_ARGS)
* just creates the entry in the soft version of the
* VFTA, init will repopulate the real table.
************************************************************************/
-static void
+static int
ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
{
struct adapter *adapter = ifp->if_softc;
u16 index, bit;
+ int error;
if (ifp->if_softc != arg) /* Not our event */
- return;
+ return EINVAL;
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
- return;
+ return EINVAL;
IXGBE_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
adapter->shadow_vfta[index] |= (1 << bit);
- ixgbe_setup_vlan_hw_support(adapter);
+ error = adapter->hw.mac.ops.set_vfta(&adapter->hw, vtag, 0, true,
+ true);
IXGBE_CORE_UNLOCK(adapter);
+ if (error != 0)
+ error = EACCES;
+
+ return error;
} /* ixgbe_register_vlan */
/************************************************************************
@@ -2333,27 +2354,31 @@ ixgbe_register_vlan(void *arg, struct if
*
* Run via vlan unconfig EVENT, remove our entry in the soft vfta.
************************************************************************/
-static void
+static int
ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
{
struct adapter *adapter = ifp->if_softc;
u16 index, bit;
+ int error;
if (ifp->if_softc != arg)
- return;
+ return EINVAL;
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
- return;
+ return EINVAL;
IXGBE_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
adapter->shadow_vfta[index] &= ~(1 << bit);
- /* Re-init to load the changes */
- ixgbe_setup_vlan_hw_support(adapter);
+ error = adapter->hw.mac.ops.set_vfta(&adapter->hw, vtag, 0, false,
+ true);
IXGBE_CORE_UNLOCK(adapter);
+ if (error != 0)
+ error = EACCES;
+
+ return error;
} /* ixgbe_unregister_vlan */
-#endif
static void
ixgbe_setup_vlan_hw_support(struct adapter *adapter)
@@ -2363,6 +2388,7 @@ ixgbe_setup_vlan_hw_support(struct adapt
struct rx_ring *rxr;
int i;
u32 ctrl;
+ struct vlanid_list *vlanidp;
bool hwtagging;
/*
@@ -2391,14 +2417,21 @@ ixgbe_setup_vlan_hw_support(struct adapt
rxr->vtag_strip = hwtagging ? TRUE : FALSE;
}
- /*
- * A soft reset zero's out the VFTA, so
- * we need to repopulate it now.
- */
+ /* Cleanup shadow_vfta */
+ for (i = 0; i < IXGBE_VFTA_SIZE; i++)
+ adapter->shadow_vfta[i] = 0;
+ /* Generate shadow_vfta from ec_vids */
+ mutex_enter(ec->ec_lock);
+ SIMPLEQ_FOREACH(vlanidp, &ec->ec_vids, vid_list) {
+ uint32_t idx;
+
+ idx = vlanidp->vid / 32;
+ KASSERT(idx < IXGBE_VFTA_SIZE);
+ adapter->shadow_vfta[idx] |= 1 << vlanidp->vid % 32;
+ }
+ mutex_exit(ec->ec_lock);
for (i = 0; i < IXGBE_VFTA_SIZE; i++)
- if (adapter->shadow_vfta[i] != 0)
- IXGBE_WRITE_REG(hw, IXGBE_VFTA(i),
- adapter->shadow_vfta[i]);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), adapter->shadow_vfta[i]);
ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
/* Enable the Filter Table if enabled */
@@ -4107,6 +4140,7 @@ ixgbe_init_locked(struct adapter *adapte
/* Update saved flags. See ixgbe_ifflags_cb() */
adapter->if_flags = ifp->if_flags;
+ adapter->ec_capenable = adapter->osdep.ec.ec_capenable;
/* Now inform the stack we're ready */
ifp->if_flags |= IFF_RUNNING;
@@ -6151,8 +6185,23 @@ ixgbe_ifflags_cb(struct ethercom *ec)
} else if ((change & IFF_PROMISC) != 0)
ixgbe_set_promisc(adapter);
+ /* Check for ec_capenable. */
+ change = ec->ec_capenable ^ adapter->ec_capenable;
+ adapter->ec_capenable = ec->ec_capenable;
+ if ((change & ~(ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_HWTAGGING
+ | ETHERCAP_VLAN_HWFILTER)) != 0) {
+ rv = ENETRESET;
+ goto out;
+ }
+
+ /*
+ * Special handling is not required for ETHERCAP_VLAN_MTU.
+ * MAXFRS(MHADD) does not include the 4bytes of the VLAN header.
+ */
+
/* Set up VLAN support and filter */
- ixgbe_setup_vlan_hw_support(adapter);
+ if ((change & (ETHERCAP_VLAN_HWTAGGING | ETHERCAP_VLAN_HWFILTER)) != 0)
+ ixgbe_setup_vlan_hw_support(adapter);
out:
IXGBE_CORE_UNLOCK(adapter);
Index: src/sys/dev/pci/ixgbe/ixgbe.h
diff -u src/sys/dev/pci/ixgbe/ixgbe.h:1.55 src/sys/dev/pci/ixgbe/ixgbe.h:1.56
--- src/sys/dev/pci/ixgbe/ixgbe.h:1.55 Thu Jun 27 05:55:40 2019
+++ src/sys/dev/pci/ixgbe/ixgbe.h Wed Jul 17 03:26:24 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe.h,v 1.55 2019/06/27 05:55:40 msaitoh Exp $ */
+/* $NetBSD: ixgbe.h,v 1.56 2019/07/17 03:26:24 msaitoh Exp $ */
/******************************************************************************
SPDX-License-Identifier: BSD-3-Clause
@@ -475,7 +475,8 @@ struct adapter {
struct ifmedia media;
callout_t timer;
- int if_flags;
+ int if_flags; /* saved ifp->if_flags */
+ int ec_capenable; /* saved ec->ec_capenable */
kmutex_t core_mtx;
Index: src/sys/dev/pci/ixgbe/ixv.c
diff -u src/sys/dev/pci/ixgbe/ixv.c:1.119 src/sys/dev/pci/ixgbe/ixv.c:1.120
--- src/sys/dev/pci/ixgbe/ixv.c:1.119 Wed Jul 17 03:09:16 2019
+++ src/sys/dev/pci/ixgbe/ixv.c Wed Jul 17 03:26:24 2019
@@ -1,4 +1,4 @@
-/*$NetBSD: ixv.c,v 1.119 2019/07/17 03:09:16 msaitoh Exp $*/
+/*$NetBSD: ixv.c,v 1.120 2019/07/17 03:26:24 msaitoh Exp $*/
/******************************************************************************
@@ -120,11 +120,10 @@ static void ixv_configure_ivars(struct a
static u8 * ixv_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *);
static void ixv_eitr_write(struct adapter *, uint32_t, uint32_t);
-static void ixv_setup_vlan_support(struct adapter *);
-#if 0
-static void ixv_register_vlan(void *, struct ifnet *, u16);
-static void ixv_unregister_vlan(void *, struct ifnet *, u16);
-#endif
+static int ixv_setup_vlan_support(struct adapter *);
+static int ixv_vlan_cb(struct ethercom *, uint16_t, bool);
+static int ixv_register_vlan(void *, struct ifnet *, u16);
+static int ixv_unregister_vlan(void *, struct ifnet *, u16);
static void ixv_add_device_sysctls(struct adapter *);
static void ixv_save_stats(struct adapter *);
@@ -471,12 +470,7 @@ ixv_attach(device_t parent, device_t dev
}
/* Register for VLAN events */
-#if 0 /* XXX delete after write? */
- adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
- ixv_register_vlan, adapter, EVENTHANDLER_PRI_FIRST);
- adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
- ixv_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST);
-#endif
+ ether_set_vlan_cb(&adapter->osdep.ec, ixv_vlan_cb);
/* Sysctls for limiting the amount of work done in the taskqueues */
ixv_set_sysctl_value(adapter, "rx_processing_limit",
@@ -618,14 +612,6 @@ ixv_detach(device_t dev, int flags)
/* Drain the Mailbox(link) queue */
softint_disestablish(adapter->link_si);
- /* Unregister VLAN events */
-#if 0 /* XXX msaitoh delete after write? */
- if (adapter->vlan_attach != NULL)
- EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach);
- if (adapter->vlan_detach != NULL)
- EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach);
-#endif
-
ether_ifdetach(adapter->ifp);
callout_halt(&adapter->timer, NULL);
@@ -823,6 +809,7 @@ ixv_init_locked(struct adapter *adapter)
/* Update saved flags. See ixgbe_ifflags_cb() */
adapter->if_flags = ifp->if_flags;
+ adapter->ec_capenable = adapter->osdep.ec.ec_capenable;
/* Now inform the stack we're ready */
ifp->if_flags |= IFF_RUNNING;
@@ -1557,7 +1544,8 @@ ixv_setup_interface(device_t dev, struct
| IFCAP_TSOv6;
ifp->if_capenable = 0;
- ec->ec_capabilities |= ETHERCAP_VLAN_HWTAGGING
+ ec->ec_capabilities |= ETHERCAP_VLAN_HWFILTER
+ | ETHERCAP_VLAN_HWTAGGING
| ETHERCAP_VLAN_HWCSUM
| ETHERCAP_JUMBO_MTU
| ETHERCAP_VLAN_MTU;
@@ -1954,19 +1942,23 @@ ixv_sysctl_rdt_handler(SYSCTLFN_ARGS)
/************************************************************************
* ixv_setup_vlan_support
************************************************************************/
-static void
+static int
ixv_setup_vlan_support(struct adapter *adapter)
{
struct ethercom *ec = &adapter->osdep.ec;
struct ixgbe_hw *hw = &adapter->hw;
struct rx_ring *rxr;
u32 ctrl, vid, vfta, retry;
+ struct vlanid_list *vlanidp;
+ int rv, error = 0;
+ bool usevlan;
bool hwtagging;
/*
* This function is called from both if_init and ifflags_cb()
* on NetBSD.
*/
+ usevlan = VLAN_ATTACHED(ec);
/* Enable HW tagging only if any vlan is attached */
hwtagging = (ec->ec_capenable & ETHERCAP_VLAN_HWTAGGING)
@@ -1988,11 +1980,23 @@ ixv_setup_vlan_support(struct adapter *a
rxr->vtag_strip = hwtagging ? TRUE : FALSE;
}
- /* XXX dirty hack. Enable all VIDs if any VLAN is attached */
- for (int i = 0; i < IXGBE_VFTA_SIZE; i++)
- adapter->shadow_vfta[i]
- = VLAN_ATTACHED(&adapter->osdep.ec) ? 0xffffffff : 0;
+ if (!usevlan)
+ return 0;
+ /* Cleanup shadow_vfta */
+ for (int i = 0; i < IXGBE_VFTA_SIZE; i++)
+ adapter->shadow_vfta[i] = 0;
+ /* Generate shadow_vfta from ec_vids */
+ mutex_enter(ec->ec_lock);
+ SIMPLEQ_FOREACH(vlanidp, &ec->ec_vids, vid_list) {
+ uint32_t idx;
+
+ idx = vlanidp->vid / 32;
+ KASSERT(idx < IXGBE_VFTA_SIZE);
+ adapter->shadow_vfta[idx] |= 1 << vlanidp->vid % 32;
+ }
+ mutex_exit(ec->ec_lock);
+
/*
* A soft reset zero's out the VFTA, so
* we need to repopulate it now.
@@ -2011,16 +2015,41 @@ ixv_setup_vlan_support(struct adapter *a
if ((vfta & (1 << j)) == 0)
continue;
vid = (i * 32) + j;
+
/* Call the shared code mailbox routine */
- while (hw->mac.ops.set_vfta(hw, vid, 0, TRUE, FALSE)) {
- if (++retry > 5)
+ while ((rv = hw->mac.ops.set_vfta(hw, vid, 0, TRUE,
+ FALSE)) != 0) {
+ if (++retry > 5) {
+ device_printf(adapter->dev,
+ "%s: max retry exceeded\n",
+ __func__);
break;
+ }
+ }
+ if (rv != 0) {
+ device_printf(adapter->dev,
+ "failed to set vlan %d\n", vid);
+ error = EACCES;
}
}
}
+ return error;
} /* ixv_setup_vlan_support */
-#if 0 /* XXX Badly need to overhaul vlan(4) on NetBSD. */
+static int
+ixv_vlan_cb(struct ethercom *ec, uint16_t vid, bool set)
+{
+ struct ifnet *ifp = &ec->ec_if;
+ int rv;
+
+ if (set)
+ rv = ixv_register_vlan(ifp->if_softc, ifp, vid);
+ else
+ rv = ixv_unregister_vlan(ifp->if_softc, ifp, vid);
+
+ return rv;
+}
+
/************************************************************************
* ixv_register_vlan
*
@@ -2029,25 +2058,32 @@ ixv_setup_vlan_support(struct adapter *a
* creates the entry in the soft version of the VFTA, init
* will repopulate the real table.
************************************************************************/
-static void
+static int
ixv_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
{
struct adapter *adapter = ifp->if_softc;
+ struct ixgbe_hw *hw = &adapter->hw;
u16 index, bit;
+ int error;
if (ifp->if_softc != arg) /* Not our event */
- return;
+ return EINVAL;
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
- return;
-
+ return EINVAL;
IXGBE_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
adapter->shadow_vfta[index] |= (1 << bit);
- /* Re-init to load the changes */
- ixv_init_locked(adapter);
+ error = hw->mac.ops.set_vfta(hw, vtag, 0, true, false);
IXGBE_CORE_UNLOCK(adapter);
+
+ if (error != 0) {
+ device_printf(adapter->dev, "failed to register vlan %hu\n",
+ vtag);
+ error = EACCES;
+ }
+ return error;
} /* ixv_register_vlan */
/************************************************************************
@@ -2056,27 +2092,34 @@ ixv_register_vlan(void *arg, struct ifne
* Run via a vlan unconfig EVENT, remove our entry
* in the soft vfta.
************************************************************************/
-static void
+static int
ixv_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
{
struct adapter *adapter = ifp->if_softc;
+ struct ixgbe_hw *hw = &adapter->hw;
u16 index, bit;
+ int error;
if (ifp->if_softc != arg)
- return;
+ return EINVAL;
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
- return;
+ return EINVAL;
IXGBE_CORE_LOCK(adapter);
index = (vtag >> 5) & 0x7F;
bit = vtag & 0x1F;
adapter->shadow_vfta[index] &= ~(1 << bit);
- /* Re-init to load the changes */
- ixv_init_locked(adapter);
+ error = hw->mac.ops.set_vfta(hw, vtag, 0, false, false);
IXGBE_CORE_UNLOCK(adapter);
+
+ if (error != 0) {
+ device_printf(adapter->dev, "failed to unregister vlan %hu\n",
+ vtag);
+ error = EIO;
+ }
+ return error;
} /* ixv_unregister_vlan */
-#endif
/************************************************************************
* ixv_enable_intr
@@ -2742,8 +2785,23 @@ ixv_ifflags_cb(struct ethercom *ec)
goto out;
}
+ /* Check for ec_capenable. */
+ change = ec->ec_capenable ^ adapter->ec_capenable;
+ adapter->ec_capenable = ec->ec_capenable;
+ if ((change & ~(ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_HWTAGGING
+ | ETHERCAP_VLAN_HWFILTER)) != 0) {
+ rv = ENETRESET;
+ goto out;
+ }
+
+ /*
+ * Special handling is not required for ETHERCAP_VLAN_MTU.
+ * PF's MAXFRS(MHADD) does not include the 4bytes of the VLAN header.
+ */
+
/* Set up VLAN support and filter */
- ixv_setup_vlan_support(adapter);
+ if ((change & (ETHERCAP_VLAN_HWTAGGING | ETHERCAP_VLAN_HWFILTER)) != 0)
+ rv = ixv_setup_vlan_support(adapter);
out:
IXGBE_CORE_UNLOCK(adapter);
Index: src/sys/net/if_ether.h
diff -u src/sys/net/if_ether.h:1.80 src/sys/net/if_ether.h:1.81
--- src/sys/net/if_ether.h:1.80 Wed Jul 17 03:09:16 2019
+++ src/sys/net/if_ether.h Wed Jul 17 03:26:24 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: if_ether.h,v 1.80 2019/07/17 03:09:16 msaitoh Exp $ */
+/* $NetBSD: if_ether.h,v 1.81 2019/07/17 03:26:24 msaitoh Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@@ -163,6 +163,7 @@ struct mii_data;
struct ethercom;
typedef int (*ether_cb_t)(struct ethercom *);
+typedef int (*ether_vlancb_t)(struct ethercom *, uint16_t, bool);
/*
* Structure shared between the ethernet driver modules and
@@ -181,6 +182,7 @@ struct ethercom {
capabilities to enable */
int ec_nvlans; /* # VLANs on this interface */
+ SIMPLEQ_HEAD(, vlanid_list) ec_vids; /* list of VLAN IDs */
/* The device handle for the MII bus child device. */
struct mii_data *ec_mii;
struct ifmedia *ec_ifmedia;
@@ -190,6 +192,12 @@ struct ethercom {
* ec_if.if_init, 0 on success, not 0 on failure.
*/
ether_cb_t ec_ifflags_cb;
+ /*
+ * Called whenever a vlan interface is configured or unconfigured.
+ * Args include the vlan tag and a flag indicating whether the tag is
+ * being added or removed.
+ */
+ ether_vlancb_t ec_vlan_cb;
kmutex_t *ec_lock;
/* Flags used only by the kernel */
int ec_flags;
@@ -241,6 +249,7 @@ extern const uint8_t ether_ipmulticast_m
extern const uint8_t ether_ipmulticast_max[ETHER_ADDR_LEN];
void ether_set_ifflags_cb(struct ethercom *, ether_cb_t);
+void ether_set_vlan_cb(struct ethercom *, ether_vlancb_t);
int ether_ioctl(struct ifnet *, u_long, void *);
int ether_addmulti(const struct sockaddr *, struct ethercom *);
int ether_delmulti(const struct sockaddr *, struct ethercom *);
@@ -336,6 +345,12 @@ ether_first_multi(struct ether_multistep
* Ethernet 802.1Q VLAN structures.
*/
+/* for ethercom */
+struct vlanid_list {
+ uint16_t vid;
+ SIMPLEQ_ENTRY(vlanid_list) vid_list;
+};
+
/* add VLAN tag to input/received packet */
static __inline void
vlan_set_tag(struct mbuf *m, uint16_t vlantag)
Index: src/sys/net/if_ethersubr.c
diff -u src/sys/net/if_ethersubr.c:1.275 src/sys/net/if_ethersubr.c:1.276
--- src/sys/net/if_ethersubr.c:1.275 Wed May 29 10:07:30 2019
+++ src/sys/net/if_ethersubr.c Wed Jul 17 03:26:24 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: if_ethersubr.c,v 1.275 2019/05/29 10:07:30 msaitoh Exp $ */
+/* $NetBSD: if_ethersubr.c,v 1.276 2019/07/17 03:26:24 msaitoh Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.275 2019/05/29 10:07:30 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.276 2019/07/17 03:26:24 msaitoh Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -996,6 +996,7 @@ ether_ifattach(struct ifnet *ifp, const
if_set_sadl(ifp, lla, ETHER_ADDR_LEN, !ETHER_IS_LOCAL(lla));
LIST_INIT(&ec->ec_multiaddrs);
+ SIMPLEQ_INIT(&ec->ec_vids);
ec->ec_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
ec->ec_flags = 0;
ifp->if_broadcastaddr = etherbroadcastaddr;
@@ -1042,6 +1043,7 @@ ether_ifdetach(struct ifnet *ifp)
#endif
ETHER_LOCK(ec);
+ KASSERT(ec->ec_nvlans == 0);
while ((enm = LIST_FIRST(&ec->ec_multiaddrs)) != NULL) {
LIST_REMOVE(enm, enm_list);
kmem_free(enm, sizeof(*enm));
@@ -1372,6 +1374,13 @@ ether_set_ifflags_cb(struct ethercom *ec
ec->ec_ifflags_cb = cb;
}
+void
+ether_set_vlan_cb(struct ethercom *ec, ether_vlancb_t cb)
+{
+
+ ec->ec_vlan_cb = cb;
+}
+
static int
ether_ioctl_reinit(struct ethercom *ec)
{
Index: src/sys/net/if_vlan.c
diff -u src/sys/net/if_vlan.c:1.140 src/sys/net/if_vlan.c:1.141
--- src/sys/net/if_vlan.c:1.140 Wed Jul 17 03:09:16 2019
+++ src/sys/net/if_vlan.c Wed Jul 17 03:26:24 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: if_vlan.c,v 1.140 2019/07/17 03:09:16 msaitoh Exp $ */
+/* $NetBSD: if_vlan.c,v 1.141 2019/07/17 03:26:24 msaitoh Exp $ */
/*
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@@ -78,7 +78,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.140 2019/07/17 03:09:16 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.141 2019/07/17 03:26:24 msaitoh Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -130,15 +130,10 @@ struct vlan_mc_entry {
* used since multiple sockaddr may mapped into the same
* ether_multi (e.g., AF_UNSPEC).
*/
- union {
- struct ether_multi *mcu_enm;
- } mc_u;
+ struct ether_multi *mc_enm;
struct sockaddr_storage mc_addr;
};
-#define mc_enm mc_u.mcu_enm
-
-
struct ifvlan_linkmib {
struct ifvlan *ifvm_ifvlan;
const struct vlan_multisw *ifvm_msw;
@@ -153,9 +148,7 @@ struct ifvlan_linkmib {
};
struct ifvlan {
- union {
- struct ethercom ifvu_ec;
- } ifv_u;
+ struct ethercom ifv_ec;
struct ifvlan_linkmib *ifv_mib; /*
* reader must use vlan_getref_linkmib()
* instead of direct dereference
@@ -171,8 +164,6 @@ struct ifvlan {
#define IFVF_PROMISC 0x01 /* promiscuous mode enabled */
-#define ifv_ec ifv_u.ifvu_ec
-
#define ifv_if ifv_ec.ec_if
#define ifv_msw ifv_mib.ifvm_msw
@@ -466,6 +457,8 @@ vlan_config(struct ifvlan *ifv, struct i
case IFT_ETHER:
{
struct ethercom *ec = (void *)p;
+ struct vlanid_list *vidmem;
+
nmib->ifvm_msw = &vlan_ether_multisw;
nmib->ifvm_encaplen = ETHER_VLAN_ENCAP_LEN;
nmib->ifvm_mintu = ETHERMIN;
@@ -492,7 +485,36 @@ vlan_config(struct ifvlan *ifv, struct i
}
error = 0;
}
-
+ /*
+ * Add a vid to the list even if it's not enabled in case
+ * it's enabled later.
+ */
+ if (ec->ec_capabilities & ETHERCAP_VLAN_HWFILTER) {
+ vidmem = kmem_alloc(sizeof(struct vlanid_list),
+ KM_SLEEP);
+ if (vidmem == NULL){
+ ec->ec_nvlans--;
+ if (ec->ec_nvlans == 0)
+ (void)ether_disable_vlan_mtu(p);
+ error = ENOMEM;
+ goto done;
+ }
+ vidmem->vid = vid;
+ mutex_enter(ec->ec_lock);
+ SIMPLEQ_INSERT_TAIL(&ec->ec_vids, vidmem, vid_list);
+ mutex_exit(ec->ec_lock);
+ }
+ if (ec->ec_capenable & ETHERCAP_VLAN_HWFILTER) {
+ if (ec->ec_vlan_cb != NULL) {
+ error = (*ec->ec_vlan_cb)(ec, vid, true);
+ if (error) {
+ ec->ec_nvlans--;
+ if (ec->ec_nvlans == 0)
+ (void)ether_disable_vlan_mtu(p);
+ goto done;
+ }
+ }
+ }
/*
* If the parent interface can do hardware-assisted
* VLAN encapsulation, then propagate its hardware-
@@ -618,6 +640,20 @@ vlan_unconfig_locked(struct ifvlan *ifv,
case IFT_ETHER:
{
struct ethercom *ec = (void *)p;
+ struct vlanid_list *vlanidp, *tmpp;
+ uint16_t vid = EVL_VLANOFTAG(nmib->ifvm_tag);
+
+ mutex_enter(ec->ec_lock);
+ SIMPLEQ_FOREACH_SAFE(vlanidp, &ec->ec_vids, vid_list, tmpp) {
+ if (vlanidp->vid == vid) {
+ SIMPLEQ_REMOVE(&ec->ec_vids, vlanidp,
+ vlanid_list, vid_list);
+ kmem_free(vlanidp, sizeof(*vlanidp));
+ }
+ }
+ mutex_exit(ec->ec_lock);
+ if (ec->ec_vlan_cb != NULL)
+ (void)(*ec->ec_vlan_cb)(ec, vid, false);
if (--ec->ec_nvlans == 0) {
IFNET_LOCK(p);
(void)ether_disable_vlan_mtu(p);
@@ -999,6 +1035,7 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
error = ENOENT;
break;
}
+
error = vlan_config(ifv, pr, vlr.vlr_tag);
if (error != 0)
break;