igb: Add Anti-spoofing feature support
authorGreg Rose <gregory.v.rose@intel.com>
Sat, 6 Nov 2010 02:08:26 +0000 (02:08 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 25 Dec 2010 05:36:51 +0000 (21:36 -0800)
Add support for the anti-spoofing feature in the HW.  Packets from
VF devices with spoofed MAC addresses or VLAN tags will be blocked
and an event generated.  When the watchdog task runs it will call a
function to check if any spoof events occurred.  If an event was
detected then a warning message is dumped to the system log.

Signed-off-by: Greg Rose <gregory.v.rose@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/igb/e1000_82575.c
drivers/net/igb/e1000_82575.h
drivers/net/igb/e1000_regs.h
drivers/net/igb/igb.h
drivers/net/igb/igb_main.c

index 50f6e9649845c99df79dbfc50a9479b6d1139cef..0a2368fa6bc660906b2120a84e69570e4c1962d7 100644 (file)
@@ -1479,6 +1479,39 @@ out:
        return ret_val;
 }
 
+/**
+ *  igb_vmdq_set_anti_spoofing_pf - enable or disable anti-spoofing
+ *  @hw: pointer to the hardware struct
+ *  @enable: state to enter, either enabled or disabled
+ *  @pf: Physical Function pool - do not set anti-spoofing for the PF
+ *
+ *  enables/disables L2 switch anti-spoofing functionality.
+ **/
+void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf)
+{
+       u32 dtxswc;
+
+       switch (hw->mac.type) {
+       case e1000_82576:
+       case e1000_i350:
+               dtxswc = rd32(E1000_DTXSWC);
+               if (enable) {
+                       dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK |
+                                  E1000_DTXSWC_VLAN_SPOOF_MASK);
+                       /* The PF can spoof - it has to in order to
+                        * support emulation mode NICs */
+                       dtxswc ^= (1 << pf | 1 << (pf + MAX_NUM_VFS));
+               } else {
+                       dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
+                                   E1000_DTXSWC_VLAN_SPOOF_MASK);
+               }
+               wr32(E1000_DTXSWC, dtxswc);
+               break;
+       default:
+               break;
+       }
+}
+
 /**
  *  igb_vmdq_set_loopback_pf - enable or disable vmdq loopback
  *  @hw: pointer to the hardware struct
index cbd1e1259e4d4c8ec43faf3ee1b1e9bcb5c947ac..1d01af2472e719ca745b06ba5d9a8f6ce8e80f0f 100644 (file)
@@ -194,6 +194,10 @@ struct e1000_adv_tx_context_desc {
 #define E1000_NVM_APME_82575          0x0400
 #define MAX_NUM_VFS                   8
 
+#define E1000_DTXSWC_MAC_SPOOF_MASK   0x000000FF /* Per VF MAC spoof control */
+#define E1000_DTXSWC_VLAN_SPOOF_MASK  0x0000FF00 /* Per VF VLAN spoof control */
+#define E1000_DTXSWC_LLE_MASK         0x00FF0000 /* Per VF Local LB enables */
+#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8
 #define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31)  /* global VF LB enable */
 
 /* Easy defines for setting default pool, would normally be left a zero */
@@ -243,6 +247,7 @@ struct e1000_adv_tx_context_desc {
 
 /* RX packet buffer size defines */
 #define E1000_RXPBS_SIZE_MASK_82576  0x0000007F
+void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *, bool, int);
 void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
 void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
 u16 igb_rxpbs_adjust_82580(u32 data);
index abb7333a1fbfaa563d82868fe10ceaba80e218d9..8ac83c5190d5ea21835183eb0a944b8a569decda 100644 (file)
 #define E1000_VFTE      0x00C90 /* VF Transmit Enables */
 #define E1000_QDE       0x02408 /* Queue Drop Enable - RW */
 #define E1000_DTXSWC    0x03500 /* DMA Tx Switch Control - RW */
+#define E1000_WVBR      0x03554 /* VM Wrong Behavior - RWS */
 #define E1000_RPLOLR    0x05AF0 /* Replication Offload - RW */
 #define E1000_UTA       0x0A000 /* Unicast Table Array - RW */
 #define E1000_IOVTCL    0x05BBC /* IOV Control Register */
index edab9c442399448bc6f930d5cae1a3a7e75ffd61..92a4ef09e55c37bb6a2a98505803b6c44b5a8772 100644 (file)
@@ -324,6 +324,7 @@ struct igb_adapter {
        unsigned int vfs_allocated_count;
        struct vf_data_storage *vf_data;
        u32 rss_queues;
+       u32 wvbr;
 };
 
 #define IGB_FLAG_HAS_MSI           (1 << 0)
index a364ae69ab372b7c93c9d67a42a2b033de083a10..58c665b7513d1cea3ff9a80464e92260def6deff 100644 (file)
@@ -3366,6 +3366,45 @@ static void igb_set_rx_mode(struct net_device *netdev)
        igb_restore_vf_multicasts(adapter);
 }
 
+static void igb_check_wvbr(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 wvbr = 0;
+
+       switch (hw->mac.type) {
+       case e1000_82576:
+       case e1000_i350:
+               if (!(wvbr = rd32(E1000_WVBR)))
+                       return;
+               break;
+       default:
+               break;
+       }
+
+       adapter->wvbr |= wvbr;
+}
+
+#define IGB_STAGGERED_QUEUE_OFFSET 8
+
+static void igb_spoof_check(struct igb_adapter *adapter)
+{
+       int j;
+
+       if (!adapter->wvbr)
+               return;
+
+       for(j = 0; j < adapter->vfs_allocated_count; j++) {
+               if (adapter->wvbr & (1 << j) ||
+                   adapter->wvbr & (1 << (j + IGB_STAGGERED_QUEUE_OFFSET))) {
+                       dev_warn(&adapter->pdev->dev,
+                               "Spoof event(s) detected on VF %d\n", j);
+                       adapter->wvbr &=
+                               ~((1 << j) |
+                                 (1 << (j + IGB_STAGGERED_QUEUE_OFFSET)));
+               }
+       }
+}
+
 /* Need to wait a few seconds after link up to get diagnostic information from
  * the phy */
 static void igb_update_phy_info(unsigned long data)
@@ -3525,6 +3564,8 @@ static void igb_watchdog_task(struct work_struct *work)
                wr32(E1000_ICS, E1000_ICS_RXDMT0);
        }
 
+       igb_spoof_check(adapter);
+
        /* Reset the timer */
        if (!test_bit(__IGB_DOWN, &adapter->state))
                mod_timer(&adapter->watchdog_timer,
@@ -4521,6 +4562,10 @@ static irqreturn_t igb_msix_other(int irq, void *data)
        if (icr & E1000_ICR_DOUTSYNC) {
                /* HW is reporting DMA is out of sync */
                adapter->stats.doosync++;
+               /* The DMA Out of Sync is also indication of a spoof event
+                * in IOV mode. Check the Wrong VM Behavior register to
+                * see if it is really a spoof event. */
+               igb_check_wvbr(adapter);
        }
 
        /* Check for a mailbox event */
@@ -6595,6 +6640,8 @@ static void igb_vmm_control(struct igb_adapter *adapter)
        if (adapter->vfs_allocated_count) {
                igb_vmdq_set_loopback_pf(hw, true);
                igb_vmdq_set_replication_pf(hw, true);
+               igb_vmdq_set_anti_spoofing_pf(hw, true,
+                                               adapter->vfs_allocated_count);
        } else {
                igb_vmdq_set_loopback_pf(hw, false);
                igb_vmdq_set_replication_pf(hw, false);