Skip to content

Commit

Permalink
igb: Retain HW VLAN filtering while in promiscuous + VT mode
Browse files Browse the repository at this point in the history
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: Greg Rose <gregory.v.rose@intel.com>
Tested-by: Sibai Li <sibai.li@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
  • Loading branch information
Greg Rose authored and Jeff Kirsher committed Apr 25, 2013
1 parent c0ba477 commit 6f3dc31
Showing 1 changed file with 68 additions and 1 deletion.
69 changes: 68 additions & 1 deletion drivers/net/ethernet/intel/igb/igb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3736,6 +3736,10 @@ static void igb_set_rx_mode(struct net_device *netdev)
rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE);

if (netdev->flags & IFF_PROMISC) {
u32 mrqc = rd32(E1000_MRQC);
/* retain VLAN HW filtering if in VT mode */
if (mrqc & E1000_MRQC_ENABLE_VMDQ)
rctl |= E1000_RCTL_VFE;
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME);
} else {
Expand Down Expand Up @@ -5520,12 +5524,75 @@ static int igb_ndo_set_vf_vlan(struct net_device *netdev,
return err;
}

static int igb_find_vlvf_entry(struct igb_adapter *adapter, int vid)
{
struct e1000_hw *hw = &adapter->hw;
int i;
u32 reg;

/* Find the vlan filter for this id */
for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
reg = rd32(E1000_VLVF(i));
if ((reg & E1000_VLVF_VLANID_ENABLE) &&
vid == (reg & E1000_VLVF_VLANID_MASK))
break;
}

if (i >= E1000_VLVF_ARRAY_SIZE)
i = -1;

return i;
}

static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
{
struct e1000_hw *hw = &adapter->hw;
int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
int err = 0;

return igb_vlvf_set(adapter, vid, add, vf);
/* If in promiscuous mode we need to make sure the PF also has
* the VLAN filter set.
*/
if (add && (adapter->netdev->flags & IFF_PROMISC))
err = igb_vlvf_set(adapter, vid, add,
adapter->vfs_allocated_count);
if (err)
goto out;

err = igb_vlvf_set(adapter, vid, add, vf);

if (err)
goto out;

/* Go through all the checks to see if the VLAN filter should
* be wiped completely.
*/
if (!add && (adapter->netdev->flags & IFF_PROMISC)) {
u32 vlvf, bits;

int regndx = igb_find_vlvf_entry(adapter, vid);
if (regndx < 0)
goto out;
/* See if any other pools are set for this VLAN filter
* entry other than the PF.
*/
vlvf = bits = rd32(E1000_VLVF(regndx));
bits &= 1 << (E1000_VLVF_POOLSEL_SHIFT +
adapter->vfs_allocated_count);
/* 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)
igb_vlvf_set(adapter, vid, add,
adapter->vfs_allocated_count);
}

out:
return err;
}

static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
Expand Down

0 comments on commit 6f3dc31

Please sign in to comment.