Commit 670224f1 authored by Greg Rose's avatar Greg Rose Committed by Jeff Kirsher

ixgbe: Retain VLAN filtering in promiscuous + VT mode

When using the new bridge FDB interface to allow SR-IOV virtual function
network devices to communicate with SW bridged network devices the
physical function is placed into promiscuous mode and hardware VLAN
filtering is disabled.  This defeats the ability to use VLAN tagging
to isolate user networks.  When the device is in promiscuous mode and
VT mode simultaneously ensure that VLAN hardware filtering remains
enabled.
Signed-off-by: default avatarGreg Rose <gregory.v.rose@intel.com>
Tested-by: default avatarStephen Ko <stephen.s.ko@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 60ff779c
...@@ -3724,8 +3724,15 @@ void ixgbe_set_rx_mode(struct net_device *netdev) ...@@ -3724,8 +3724,15 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
hw->addr_ctrl.user_set_promisc = true; hw->addr_ctrl.user_set_promisc = true;
fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
vmolr |= (IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE); vmolr |= (IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE);
/* don't hardware filter vlans in promisc mode */ /* Only disable hardware filter vlans in promiscuous mode
ixgbe_vlan_filter_disable(adapter); * if SR-IOV and VMDQ are disabled - otherwise ensure
* that hardware VLAN filters remain enabled.
*/
if (!(adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
IXGBE_FLAG_SRIOV_ENABLED)))
ixgbe_vlan_filter_disable(adapter);
else
ixgbe_vlan_filter_enable(adapter);
} else { } else {
if (netdev->flags & IFF_ALLMULTI) { if (netdev->flags & IFF_ALLMULTI) {
fctrl |= IXGBE_FCTRL_MPE; fctrl |= IXGBE_FCTRL_MPE;
......
...@@ -768,6 +768,29 @@ static int ixgbe_set_vf_mac_addr(struct ixgbe_adapter *adapter, ...@@ -768,6 +768,29 @@ static int ixgbe_set_vf_mac_addr(struct ixgbe_adapter *adapter,
return ixgbe_set_vf_mac(adapter, vf, new_mac) < 0; return ixgbe_set_vf_mac(adapter, vf, new_mac) < 0;
} }
static int ixgbe_find_vlvf_entry(struct ixgbe_hw *hw, u32 vlan)
{
u32 vlvf;
s32 regindex;
/* short cut the special case */
if (vlan == 0)
return 0;
/* Search for the vlan id in the VLVF entries */
for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) {
vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex));
if ((vlvf & VLAN_VID_MASK) == vlan)
break;
}
/* Return a negative value if not found */
if (regindex >= IXGBE_VLVF_ENTRIES)
regindex = -1;
return regindex;
}
static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter, static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
u32 *msgbuf, u32 vf) u32 *msgbuf, u32 vf)
{ {
...@@ -775,6 +798,9 @@ static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter, ...@@ -775,6 +798,9 @@ static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
int add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT; int add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
int vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK); int vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
int err; int err;
s32 reg_ndx;
u32 vlvf;
u32 bits;
u8 tcs = netdev_get_num_tc(adapter->netdev); u8 tcs = netdev_get_num_tc(adapter->netdev);
if (adapter->vfinfo[vf].pf_vlan || tcs) { if (adapter->vfinfo[vf].pf_vlan || tcs) {
...@@ -790,10 +816,50 @@ static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter, ...@@ -790,10 +816,50 @@ static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
else if (adapter->vfinfo[vf].vlan_count) else if (adapter->vfinfo[vf].vlan_count)
adapter->vfinfo[vf].vlan_count--; adapter->vfinfo[vf].vlan_count--;
/* in case of promiscuous mode any VLAN filter set for a VF must
* also have the PF pool added to it.
*/
if (add && adapter->netdev->flags & IFF_PROMISC)
err = ixgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
err = ixgbe_set_vf_vlan(adapter, add, vid, vf); err = ixgbe_set_vf_vlan(adapter, add, vid, vf);
if (!err && adapter->vfinfo[vf].spoofchk_enabled) if (!err && adapter->vfinfo[vf].spoofchk_enabled)
hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf); hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
/* Go through all the checks to see if the VLAN filter should
* be wiped completely.
*/
if (!add && adapter->netdev->flags & IFF_PROMISC) {
reg_ndx = ixgbe_find_vlvf_entry(hw, vid);
if (reg_ndx < 0)
goto out;
vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(reg_ndx));
/* See if any other pools are set for this VLAN filter
* entry other than the PF.
*/
if (VMDQ_P(0) < 32) {
bits = IXGBE_READ_REG(hw, IXGBE_VLVFB(reg_ndx * 2));
bits &= ~(1 << VMDQ_P(0));
bits |= IXGBE_READ_REG(hw,
IXGBE_VLVFB(reg_ndx * 2) + 1);
} else {
bits = IXGBE_READ_REG(hw,
IXGBE_VLVFB(reg_ndx * 2) + 1);
bits &= ~(1 << (VMDQ_P(0) - 32));
bits |= IXGBE_READ_REG(hw, IXGBE_VLVFB(reg_ndx * 2));
}
/* If the filter was removed then ensure PF pool bit
* is cleared if the PF only added itself to the pool
* because the PF is in promiscuous mode.
*/
if ((vlvf & VLAN_VID_MASK) == vid &&
!test_bit(vid, adapter->active_vlans) && !bits)
ixgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
}
out:
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment