i40e: Add vf-true-promisc-support priv flag
authorAnjali Singhai Jain <anjali.singhai@intel.com>
Tue, 3 May 2016 22:13:12 +0000 (15:13 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 14 May 2016 05:48:46 +0000 (22:48 -0700)
This patch adds priv-flag knob to configure global true promisc
support. With this patch the user can decide the flavor of
promiscuous that the VFs will see when promiscuous mode is enabled
on the interface. Since this a global setting for the whole device,
the priv-flag is exposed only on the first PF of the device.

The default is true promisc support is off, which means the promisc
mode for the VF will be limited/defport mode.

For the PF, we still will be in limited promisc unless in MFP mode
irrespective of the flavor picked through this knob.

Usage:
On PF0
ethtool --show-priv-flags p261p1
Private flags for p261p1:
MFP                    : off
LinkPolling            : off
flow-director-atr      : on
veb-stats              : off
hw-atr-eviction        : off
vf-true-promisc-support: off

to enable setting true promisc
ethtool --set-priv-flags p261p1 vf-true-promisc-support on

At this point if the VF is set to trust and promisc is enabled
on the VF through
ip link set ... promisc on
The VF/VFs will be able to see ALL ingress traffic

Change-Id: I8fac4b6eb1af9ca77b5376b79c50bdce5055bd94
Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_prototype.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c

index 01cc732195c0e9ccacd7d88da7dcd99824eb824c..9c44739da5e28f6352b4f8ae833d95517cbcd014 100644 (file)
 #define I40E_INT_NAME_STR_LEN        (IFNAMSIZ + 16)
 
 /* Ethtool Private Flags */
-#define I40E_PRIV_FLAGS_NPAR_FLAG      BIT(0)
-#define I40E_PRIV_FLAGS_LINKPOLL_FLAG  BIT(1)
-#define I40E_PRIV_FLAGS_FD_ATR         BIT(2)
-#define I40E_PRIV_FLAGS_VEB_STATS      BIT(3)
-#define I40E_PRIV_FLAGS_HW_ATR_EVICT   BIT(5)
+#define        I40E_PRIV_FLAGS_MFP_FLAG                BIT(0)
+#define        I40E_PRIV_FLAGS_LINKPOLL_FLAG           BIT(1)
+#define I40E_PRIV_FLAGS_FD_ATR                 BIT(2)
+#define I40E_PRIV_FLAGS_VEB_STATS              BIT(3)
+#define I40E_PRIV_FLAGS_HW_ATR_EVICT           BIT(4)
+#define I40E_PRIV_FLAGS_TRUE_PROMISC_SUPPORT   BIT(5)
 
 #define I40E_NVM_VERSION_LO_SHIFT  0
 #define I40E_NVM_VERSION_LO_MASK   (0xff << I40E_NVM_VERSION_LO_SHIFT)
@@ -358,6 +359,7 @@ struct i40e_pf {
 #define I40E_FLAG_STOP_FW_LLDP                 BIT_ULL(47)
 #define I40E_FLAG_HAVE_10GBASET_PHY            BIT_ULL(48)
 #define I40E_FLAG_PF_MAC                       BIT_ULL(50)
+#define I40E_FLAG_TRUE_PROMISC_SUPPORT         BIT_ULL(51)
 
        /* tracks features that get auto disabled by errors */
        u64 auto_disable_flags;
index 4739a9ca60d28e26503d60876bcf7700875bfbc6..27c6f9ddf684b45dddedcf753036591fc81e33d3 100644 (file)
@@ -1972,10 +1972,12 @@ aq_add_vsi_exit:
  * @seid: vsi number
  * @set: set unicast promiscuous enable/disable
  * @cmd_details: pointer to command details structure or NULL
+ * @rx_only_promisc: flag to decide if egress traffic gets mirrored in promisc
  **/
 i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
                                u16 seid, bool set,
-                               struct i40e_asq_cmd_details *cmd_details)
+                               struct i40e_asq_cmd_details *cmd_details,
+                               bool rx_only_promisc)
 {
        struct i40e_aq_desc desc;
        struct i40e_aqc_set_vsi_promiscuous_modes *cmd =
@@ -1988,8 +1990,9 @@ i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
 
        if (set) {
                flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST;
-               if (((hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver >= 5)) ||
-                   (hw->aq.api_maj_ver > 1))
+               if (rx_only_promisc &&
+                   (((hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver >= 5)) ||
+                    (hw->aq.api_maj_ver > 1)))
                        flags |= I40E_AQC_SET_VSI_PROMISC_TX;
        }
 
index 6fa05c44826864a1e1ce0cd42fa09c1d7cf0c3f5..52b58e37d863574619f7cec4f4cc10f252bf9e8d 100644 (file)
@@ -230,6 +230,17 @@ static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = {
 
 #define I40E_TEST_LEN (sizeof(i40e_gstrings_test) / ETH_GSTRING_LEN)
 
+static const char i40e_priv_flags_strings_gl[][ETH_GSTRING_LEN] = {
+       "MFP",
+       "LinkPolling",
+       "flow-director-atr",
+       "veb-stats",
+       "hw-atr-eviction",
+       "vf-true-promisc-support",
+};
+
+#define I40E_PRIV_FLAGS_GL_STR_LEN ARRAY_SIZE(i40e_priv_flags_strings_gl)
+
 static const char i40e_priv_flags_strings[][ETH_GSTRING_LEN] = {
        "NPAR",
        "LinkPolling",
@@ -1158,6 +1169,10 @@ static void i40e_get_drvinfo(struct net_device *netdev,
                sizeof(drvinfo->fw_version));
        strlcpy(drvinfo->bus_info, pci_name(pf->pdev),
                sizeof(drvinfo->bus_info));
+       if (pf->hw.pf_id == 0)
+               drvinfo->n_priv_flags = I40E_PRIV_FLAGS_GL_STR_LEN;
+       else
+               drvinfo->n_priv_flags = I40E_PRIV_FLAGS_STR_LEN;
 }
 
 static void i40e_get_ringparam(struct net_device *netdev,
@@ -1385,7 +1400,10 @@ static int i40e_get_sset_count(struct net_device *netdev, int sset)
                        return I40E_VSI_STATS_LEN(netdev);
                }
        case ETH_SS_PRIV_FLAGS:
-               return I40E_PRIV_FLAGS_STR_LEN;
+               if (pf->hw.pf_id == 0)
+                       return I40E_PRIV_FLAGS_GL_STR_LEN;
+               else
+                       return I40E_PRIV_FLAGS_STR_LEN;
        default:
                return -EOPNOTSUPP;
        }
@@ -1583,10 +1601,18 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset,
                /* BUG_ON(p - data != I40E_STATS_LEN * ETH_GSTRING_LEN); */
                break;
        case ETH_SS_PRIV_FLAGS:
-               for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) {
-                       memcpy(data, i40e_priv_flags_strings[i],
-                              ETH_GSTRING_LEN);
-                       data += ETH_GSTRING_LEN;
+               if (pf->hw.pf_id == 0) {
+                       for (i = 0; i < I40E_PRIV_FLAGS_GL_STR_LEN; i++) {
+                               memcpy(data, i40e_priv_flags_strings_gl[i],
+                                      ETH_GSTRING_LEN);
+                               data += ETH_GSTRING_LEN;
+                       }
+               } else {
+                       for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) {
+                               memcpy(data, i40e_priv_flags_strings[i],
+                                      ETH_GSTRING_LEN);
+                               data += ETH_GSTRING_LEN;
+                       }
                }
                break;
        default:
@@ -2848,8 +2874,6 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
        struct i40e_pf *pf = vsi->back;
        u32 ret_flags = 0;
 
-       ret_flags |= pf->hw.func_caps.npar_enable ?
-               I40E_PRIV_FLAGS_NPAR_FLAG : 0;
        ret_flags |= pf->flags & I40E_FLAG_LINK_POLLING_ENABLED ?
                I40E_PRIV_FLAGS_LINKPOLL_FLAG : 0;
        ret_flags |= pf->flags & I40E_FLAG_FD_ATR_ENABLED ?
@@ -2858,6 +2882,10 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
                I40E_PRIV_FLAGS_VEB_STATS : 0;
        ret_flags |= pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE ?
                0 : I40E_PRIV_FLAGS_HW_ATR_EVICT;
+       if (pf->hw.pf_id == 0) {
+               ret_flags |= pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT ?
+                       I40E_PRIV_FLAGS_TRUE_PROMISC_SUPPORT : 0;
+       }
 
        return ret_flags;
 }
@@ -2872,7 +2900,10 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
        struct i40e_netdev_priv *np = netdev_priv(dev);
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
+       u16 sw_flags = 0, valid_flags = 0;
        bool reset_required = false;
+       bool promisc_change = false;
+       int ret;
 
        /* NOTE: MFP is not settable */
 
@@ -2902,6 +2933,33 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
                reset_required = true;
        }
 
+       if (pf->hw.pf_id == 0) {
+               if ((flags & I40E_PRIV_FLAGS_TRUE_PROMISC_SUPPORT) &&
+                   !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {
+                       pf->flags |= I40E_FLAG_TRUE_PROMISC_SUPPORT;
+                       promisc_change = true;
+               } else if (!(flags & I40E_PRIV_FLAGS_TRUE_PROMISC_SUPPORT) &&
+                          (pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {
+                       pf->flags &= ~I40E_FLAG_TRUE_PROMISC_SUPPORT;
+                       promisc_change = true;
+               }
+       }
+       if (promisc_change) {
+               if (!(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))
+                       sw_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
+               valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
+               ret = i40e_aq_set_switch_config(&pf->hw, sw_flags, valid_flags,
+                                               NULL);
+               if (ret && pf->hw.aq.asq_last_status != I40E_AQ_RC_ESRCH) {
+                       dev_info(&pf->pdev->dev,
+                                "couldn't set switch config bits, err %s aq_err %s\n",
+                                i40e_stat_str(&pf->hw, ret),
+                                i40e_aq_str(&pf->hw,
+                                            pf->hw.aq.asq_last_status));
+                       /* not a fatal problem, just keep going */
+               }
+       }
+
        if ((flags & I40E_PRIV_FLAGS_HW_ATR_EVICT) &&
            (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))
                pf->auto_disable_flags &= ~I40E_FLAG_HW_ATR_EVICT_CAPABLE;
index 46a3a674c635b98ba4aaf1dc038279401df08f0d..f8038d09c1c236cdaade241fea0b7d795bb698f2 100644 (file)
@@ -2128,7 +2128,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                        aq_ret = i40e_aq_set_vsi_unicast_promiscuous(
                                                          &vsi->back->hw,
                                                          vsi->seid,
-                                                         cur_promisc, NULL);
+                                                         cur_promisc, NULL,
+                                                         true);
                        if (aq_ret) {
                                retval =
                                i40e_aq_rc_to_posix(aq_ret,
@@ -10407,6 +10408,7 @@ int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig)
  **/
 static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
 {
+       u16 flags = 0;
        int ret;
 
        /* find out what's out there already */
@@ -10420,6 +10422,32 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
        }
        i40e_pf_reset_stats(pf);
 
+       /* set the switch config bit for the whole device to
+        * support limited promisc or true promisc
+        * when user requests promisc. The default is limited
+        * promisc.
+       */
+
+       if ((pf->hw.pf_id == 0) &&
+           !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))
+               flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
+
+       if (pf->hw.pf_id == 0) {
+               u16 valid_flags;
+
+               valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
+               ret = i40e_aq_set_switch_config(&pf->hw, flags, valid_flags,
+                                               NULL);
+               if (ret && pf->hw.aq.asq_last_status != I40E_AQ_RC_ESRCH) {
+                       dev_info(&pf->pdev->dev,
+                                "couldn't set switch config bits, err %s aq_err %s\n",
+                                i40e_stat_str(&pf->hw, ret),
+                                i40e_aq_str(&pf->hw,
+                                            pf->hw.aq.asq_last_status));
+                       /* not a fatal problem, just keep going */
+               }
+       }
+
        /* first time setup */
        if (pf->lan_vsi == I40E_NO_VSI || reinit) {
                struct i40e_vsi *vsi = NULL;
index b76b1587743c9bf45a461d735d415756e617bd63..80403c6ee7f073fccd2211ba3eec4e847014519e 100644 (file)
@@ -130,7 +130,8 @@ i40e_status i40e_aq_set_vsi_broadcast(struct i40e_hw *hw,
                                u16 vsi_id, bool set_filter,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
-               u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
+               u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details,
+               bool rx_only_promisc);
 i40e_status i40e_aq_set_vsi_multicast_promiscuous(struct i40e_hw *hw,
                u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
 enum i40e_status_code i40e_aq_set_vsi_mc_promisc_on_vlan(struct i40e_hw *hw,
index a9b04e72df82142138a606970fcf6c5a9e1f7d93..6430933f99b3e675cbfab1d8a30fb6a14f974f98 100644 (file)
@@ -1562,7 +1562,8 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
                }
        } else {
                aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
-                                                            allmulti, NULL);
+                                                            allmulti, NULL,
+                                                            true);
                aq_err = pf->hw.aq.asq_last_status;
                if (aq_ret)
                        dev_err(&pf->pdev->dev,