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;