@@ -604,6 +604,7 @@ struct i40e_pf {
* in abilities field of i40e_aq_set_phy_config structure
*/
#define I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED BIT(27)
+#define I40E_FLAG_VF_SOURCE_PRUNING BIT(31)
struct i40e_client_instance *cinst;
bool stat_offsets_loaded;
@@ -1288,6 +1289,7 @@ void i40e_ptp_stop(struct i40e_pf *pf);
int i40e_ptp_alloc_pins(struct i40e_pf *pf);
int i40e_update_adq_vsi_queues(struct i40e_vsi *vsi, int vsi_offset);
int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi);
+i40e_status i40e_configure_source_pruning(struct i40e_vsi *vsi, bool enable);
i40e_status i40e_get_partition_bw_setting(struct i40e_pf *pf);
i40e_status i40e_set_partition_bw_setting(struct i40e_pf *pf);
i40e_status i40e_commit_partition_bw_setting(struct i40e_pf *pf);
@@ -457,6 +457,7 @@ static const struct i40e_priv_flags i40e_gstrings_priv_flags[] = {
I40E_PRIV_FLAG("base-r-fec", I40E_FLAG_BASE_R_FEC, 0),
I40E_PRIV_FLAG("vf-vlan-pruning",
I40E_FLAG_VF_VLAN_PRUNING, 0),
+ I40E_PRIV_FLAG("vf-source-pruning", I40E_FLAG_VF_SOURCE_PRUNING, 0),
};
#define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gstrings_priv_flags)
@@ -5294,7 +5295,8 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP)
reset_needed = I40E_PF_RESET_AND_REBUILD_FLAG;
if (changed_flags & (I40E_FLAG_VEB_STATS_ENABLED |
- I40E_FLAG_LEGACY_RX | I40E_FLAG_SOURCE_PRUNING_DISABLED))
+ I40E_FLAG_LEGACY_RX | I40E_FLAG_SOURCE_PRUNING_DISABLED |
+ I40E_FLAG_VF_SOURCE_PRUNING))
reset_needed = BIT(__I40E_PF_RESET_REQUESTED);
/* Before we finalize any flag changes, we need to perform some
@@ -5446,6 +5448,15 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
}
}
+ if (changed_flags & I40E_FLAG_VF_SOURCE_PRUNING) {
+ if (orig_flags & I40E_FLAG_VF_SOURCE_PRUNING)
+ dev_info(&pf->pdev->dev,
+ "VF source pruning disabled. To take effect please make sure to disable spoof checking and enable trust on selected VF's\n");
+ else
+ dev_info(&pf->pdev->dev,
+ "VF source pruning enabled on all VF's\n");
+ }
+
/* Now that we've checked to ensure that the new flags are valid, load
* them into place. Since we only modify flags either (a) during
* initialization or (b) while holding the RTNL lock, we don't need
@@ -12874,6 +12874,9 @@ static int i40e_sw_init(struct i40e_pf *pf)
dev_info(&pf->pdev->dev,
"total-port-shutdown was enabled, link-down-on-close is forced on\n");
}
+ /* VSIs by default have source pruning enabled */
+ pf->flags |= I40E_FLAG_VF_SOURCE_PRUNING;
+
mutex_init(&pf->switch_mutex);
sw_init_done:
@@ -13906,6 +13909,54 @@ int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi)
return 0;
}
+/**
+ * i40e_configure_source_pruning
+ * @vsi: VSI to disable source pruning on
+ * @enable: enable or disable pruning
+ *
+ * Enable/disable vsi source pruning based on enable flag
+ **/
+i40e_status i40e_configure_source_pruning(struct i40e_vsi *vsi, bool enable)
+{
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_hw *hw = &pf->hw;
+ struct i40e_vsi_context ctxt;
+ i40e_status ret;
+
+ memset(&ctxt, 0, sizeof(ctxt));
+
+ ctxt.seid = vsi->seid;
+ ctxt.pf_num = hw->pf_id;
+ if (vsi->type == I40E_VSI_SRIOV)
+ ctxt.vf_num = vsi->vf_id + hw->func_caps.vf_base_id;
+ ret = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "couldn't get vsi config, err %s\n",
+ i40e_stat_str(hw, ret));
+ return ret;
+ }
+
+ if (vsi->type == I40E_VSI_MAIN)
+ ctxt.flags = I40E_AQ_VSI_TYPE_PF;
+ else if (vsi->type == I40E_VSI_SRIOV)
+ ctxt.flags = I40E_AQ_VSI_TYPE_VF;
+
+ ctxt.info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+ if (enable)
+ ctxt.info.switch_id &=
+ ~cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB);
+ else
+ ctxt.info.switch_id |=
+ cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB);
+ ret = i40e_aq_update_vsi_params(&pf->hw, &ctxt, NULL);
+ if (ret)
+ dev_err(&pf->pdev->dev,
+ "Update VSI failed, err %s\n",
+ i40e_stat_str(&pf->hw, ret));
+ return ret;
+}
+
/**
* i40e_add_vsi - Add a VSI to the switch
* @vsi: the VSI being configured
@@ -13960,24 +14011,9 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
* the VSI to disable source pruning.
*/
if (pf->flags & I40E_FLAG_SOURCE_PRUNING_DISABLED) {
- memset(&ctxt, 0, sizeof(ctxt));
- ctxt.seid = pf->main_vsi_seid;
- ctxt.pf_num = pf->hw.pf_id;
- ctxt.vf_num = 0;
- ctxt.info.valid_sections |=
- cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
- ctxt.info.switch_id =
- cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB);
- ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
- if (ret) {
- dev_info(&pf->pdev->dev,
- "update vsi failed, err %s aq_err %s\n",
- i40e_stat_str(&pf->hw, ret),
- i40e_aq_str(&pf->hw,
- pf->hw.aq.asq_last_status));
- ret = -ENOENT;
+ ret = i40e_configure_source_pruning(vsi, false);
+ if (ret)
goto err;
- }
}
/* MFP mode setup queue map and update VSI */
@@ -591,6 +591,61 @@ i40e_config_rdma_qvlist(struct i40e_vf *vf,
return ret;
}
+/**
+ * i40e_set_source_pruning
+ * @vf: pointer to the VF info
+ *
+ * This function set appropriate source pruning flag for vf.
+ * To disable source pruning on selected VFs the PF should set
+ * private flag 'vf-source-pruning' off, and VF should be set
+ * 'trusted' on and 'spoofchk' off.
+ * Otherwise, source pruning should still be enabled on VF.
+ **/
+static int i40e_set_source_pruning(struct i40e_vf *vf)
+{
+ struct i40e_pf *pf = vf->pf;
+ struct i40e_vsi *vsi;
+ bool pf_sp;
+
+ vsi = pf->vsi[vf->lan_vsi_idx];
+ pf_sp = !!(pf->flags & I40E_FLAG_VF_SOURCE_PRUNING);
+
+ if (pf_sp) {
+ if (!vf->source_pruning) {
+ vf->source_pruning = true;
+ dev_info(&pf->pdev->dev,
+ "Source pruning enabled on VF %d\n",
+ vf->vf_id);
+ }
+ return 0;
+ }
+
+ if (!vf->source_pruning && (!vf->trusted || vf->spoofchk)) {
+ if (vf->spoofchk &&
+ test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+ /* enable source pruning beyond vf reset */
+ if (i40e_configure_source_pruning(vsi, true))
+ return -EIO;
+ }
+ vf->source_pruning = true;
+ dev_info(&pf->pdev->dev,
+ "Source pruning enabled on VF %d\n", vf->vf_id);
+ } else if ((vf->source_pruning && vf->trusted &&
+ !vf->spoofchk) || !vf->source_pruning) {
+ if (i40e_configure_source_pruning(vsi, false))
+ return -EIO;
+
+ if (vf->source_pruning) {
+ vf->source_pruning = false;
+ dev_info(&pf->pdev->dev,
+ "Source pruning disabled on VF %d\n",
+ vf->vf_id);
+ }
+ }
+
+ return 0;
+}
+
/**
* i40e_config_vsi_tx_queue
* @vf: pointer to the VF info
@@ -848,6 +903,9 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, u8 idx)
vf->vf_id, ret);
}
+ if (!idx)
+ ret = i40e_set_source_pruning(vf);
+
error_alloc_vsi_res:
return ret;
}
@@ -1830,6 +1888,8 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
set_bit(I40E_VF_STATE_PRE_ENABLE, &vfs[i].vf_states);
+ /* assign source pruning default value */
+ vfs[i].source_pruning = true;
}
pf->num_alloc_vfs = num_alloc_vfs;
@@ -4718,7 +4778,6 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable)
if (enable == vf->spoofchk)
goto out;
- vf->spoofchk = enable;
memset(&ctxt, 0, sizeof(ctxt));
ctxt.seid = pf->vsi[vf->lan_vsi_idx]->seid;
ctxt.pf_num = pf->hw.pf_id;
@@ -4731,7 +4790,12 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable)
dev_err(&pf->pdev->dev, "Error %d updating VSI parameters\n",
ret);
ret = -EIO;
+ goto out;
}
+ vf->spoofchk = enable;
+
+ ret = i40e_set_source_pruning(vf);
+
out:
clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
return ret;
@@ -80,6 +80,8 @@ struct i40e_vf {
u16 port_vlan_id;
bool pf_set_mac; /* The VMM admin set the VF MAC address */
bool trusted;
+ bool source_pruning;
+
/* VSI indices - actual VSI pointers are maintained in the PF structure
* When assigned, these will be non-zero, because VSI 0 is always