@@ -124,6 +124,34 @@ Runtime Config Options
will switch PF interrupt from IntN to Int0 to avoid interrupt conflict between
DPDK and Linux Kernel.
+- ``Support VF VLAN anti-spoof`` (default ``disable``)
+
+ This is a work around to enable vlan antispoof on VF to support customer with
+ this specific requirement, the reason not make it as a default config is:
+ due to hardware limitation, when turn on this feature, some global register will
+ be re-write and some device default behaviour will be changed. (see below for
+ more detail). ``devargs`` parameter ``support-vf-vlan-antispoof`` is introduced,
+ for example::
+
+ -w 84:00.0,support-vf-vlan-antispoof=1
+
+ By default its off, when it turn on, will have below impact:
+
+ Multi-driver is not supported since some global register is changed in DPDK driver
+ during init which is no expected by kernel driver.
+
+ Unicast / Multicase promiscuous mode can not be configured separately. So, function
+ ``rte_pmd_i40e_set_vf_unicast_promics`` and ``rte_pmd_i40e_set_vf_multicast_promisc``
+ will fail and new funciton rte_pmd_i40e_set_vf_promics is introduced as a coarse-grain
+ API.
+
+ VLAN anti-spoof and Mac anti-spoof are always enable/disable together.
+ (``rte_eth_set_vf_mac_anti_spoof`` and ``rte_eth_set_vf_vlan_anti_spoof`` now do the
+ same thing).
+
+ When VLAN/MAC anti-spoof is turn on, vlan tag will be added to vlan promisc table, so
+ in the rx path, mac address match will be ignored, only vlan will be matched.
+
- ``Support VF Port Representor`` (default ``not enabled``)
The i40e PF PMD supports the creation of VF port representors for the control
@@ -327,7 +327,7 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
static int i40e_dev_get_dcb_info(struct rte_eth_dev *dev,
struct rte_eth_dcb_info *dcb_info);
static int i40e_dev_sync_phy_type(struct i40e_hw *hw);
-static void i40e_configure_registers(struct i40e_hw *hw);
+static void i40e_configure_registers(struct rte_eth_dev *dev);
static void i40e_hw_init(struct rte_eth_dev *dev);
static int i40e_config_qinq(struct i40e_hw *hw, struct i40e_vsi *vsi);
static enum i40e_status_code i40e_aq_del_mirror_rule(struct i40e_hw *hw,
@@ -1097,45 +1097,54 @@ i40e_init_queue_region_conf(struct rte_eth_dev *dev)
memset(info, 0, sizeof(struct i40e_queue_regions));
}
-#define ETH_I40E_SUPPORT_MULTI_DRIVER "support-multi-driver"
+#define ETH_I40E_SUPPORT_MULTI_DRIVER "support-multi-driver"
+#define ETH_I40E_SUPPORT_VF_VLAN_ANTI_SPOOF "support-vf-vlan-antispoof"
static int
-i40e_parse_multi_drv_handler(__rte_unused const char *key,
- const char *value,
- void *opaque)
+i40e_parse_config_handler(__rte_unused const char *key,
+ const char *value,
+ void *opaque)
{
struct i40e_pf *pf;
- unsigned long support_multi_driver;
+ unsigned long flag;
char *end;
pf = (struct i40e_pf *)opaque;
errno = 0;
- support_multi_driver = strtoul(value, &end, 10);
+ flag = strtoul(value, &end, 10);
if (errno != 0 || end == value || *end != 0) {
PMD_DRV_LOG(WARNING, "Wrong global configuration");
return -(EINVAL);
}
- if (support_multi_driver == 1 || support_multi_driver == 0)
- pf->support_multi_driver = (bool)support_multi_driver;
- else
- PMD_DRV_LOG(WARNING, "%s must be 1 or 0,",
- "enable global configuration by default."
- ETH_I40E_SUPPORT_MULTI_DRIVER);
+ if (flag == 1 || flag == 0) {
+ if (!strcmp(ETH_I40E_SUPPORT_MULTI_DRIVER, key))
+ pf->support_multi_driver = (bool)flag;
+ else if (!strcmp(ETH_I40E_SUPPORT_VF_VLAN_ANTI_SPOOF, key))
+ pf->support_vf_vlan_antispoof = (bool)flag;
+ } else {
+ PMD_DRV_LOG(WARNING, "%s must be 1 or 0, use default config 0",
+ key);
+ }
+
return 0;
}
static int
-i40e_support_multi_driver(struct rte_eth_dev *dev)
+i40e_parse_device_args(struct rte_eth_dev *dev)
{
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
static const char *const valid_keys[] = {
- ETH_I40E_SUPPORT_MULTI_DRIVER, NULL};
+ ETH_I40E_SUPPORT_MULTI_DRIVER,
+ ETH_I40E_SUPPORT_VF_VLAN_ANTI_SPOOF,
+ NULL};
struct rte_kvargs *kvlist;
/* Enable global configuration by default */
pf->support_multi_driver = false;
+ /* vlan antispoof is not supported by default */
+ pf->support_vf_vlan_antispoof = false;
if (!dev->device->devargs)
return 0;
@@ -1150,7 +1159,18 @@ i40e_support_multi_driver(struct rte_eth_dev *dev)
ETH_I40E_SUPPORT_MULTI_DRIVER);
if (rte_kvargs_process(kvlist, ETH_I40E_SUPPORT_MULTI_DRIVER,
- i40e_parse_multi_drv_handler, pf) < 0) {
+ i40e_parse_config_handler, pf) < 0) {
+ rte_kvargs_free(kvlist);
+ return -EINVAL;
+ }
+
+ if (rte_kvargs_count(kvlist, ETH_I40E_SUPPORT_VF_VLAN_ANTI_SPOOF) > 1)
+ PMD_DRV_LOG(WARNING, "More than one argument \"%s\" and only "
+ "the first invalid or last valid one is used !",
+ ETH_I40E_SUPPORT_VF_VLAN_ANTI_SPOOF);
+
+ if (rte_kvargs_process(kvlist, ETH_I40E_SUPPORT_VF_VLAN_ANTI_SPOOF,
+ i40e_parse_config_handler, pf) < 0) {
rte_kvargs_free(kvlist);
return -EINVAL;
}
@@ -1236,8 +1256,12 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
hw->bus.func = pci_dev->addr.function;
hw->adapter_stopped = 0;
- /* Check if need to support multi-driver */
- i40e_support_multi_driver(dev);
+ /* check multi driver and vlan anti-spoof in devargs */
+ i40e_parse_device_args(dev);
+
+ /* vf vlan anti spoof is conflict with multi driver support */
+ if (pf->support_multi_driver && pf->support_vf_vlan_antispoof)
+ return -ENOTSUP;
/* Make sure all is clean before doing PF reset */
i40e_clear_hw(hw);
@@ -1316,7 +1340,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
* registers. Note that the workaround can be removed when it is fixed
* in firmware in the future.
*/
- i40e_configure_registers(hw);
+ i40e_configure_registers(dev);
/* Get hw capabilities */
ret = i40e_get_cap(hw);
@@ -2436,6 +2460,13 @@ i40e_dev_promiscuous_enable(struct rte_eth_dev *dev)
struct i40e_vsi *vsi = pf->main_vsi;
int status;
+ if (pf->support_vf_vlan_antispoof) {
+ status = i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
+ if (status != I40E_SUCCESS)
+ PMD_DRV_LOG(ERR, "Failed to enable promiscuous");
+ return;
+ }
+
status = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
true, NULL, true);
if (status != I40E_SUCCESS)
@@ -2456,6 +2487,13 @@ i40e_dev_promiscuous_disable(struct rte_eth_dev *dev)
struct i40e_vsi *vsi = pf->main_vsi;
int status;
+ if (pf->support_vf_vlan_antispoof) {
+ status = i40e_aq_clear_default_vsi(hw, vsi->seid, NULL);
+ if (status != I40E_SUCCESS)
+ PMD_DRV_LOG(ERR, "Failed to disable promiscuous");
+ return;
+ }
+
status = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
false, NULL, true);
if (status != I40E_SUCCESS)
@@ -10006,8 +10044,11 @@ i40e_dev_sync_phy_type(struct i40e_hw *hw)
}
static void
-i40e_configure_registers(struct i40e_hw *hw)
+i40e_configure_registers(struct rte_eth_dev *dev)
{
+ struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
static struct {
uint32_t addr;
uint64_t val;
@@ -10076,6 +10117,21 @@ i40e_configure_registers(struct i40e_hw *hw)
PMD_DRV_LOG(DEBUG, "Write 0x%"PRIx64" to the address of "
"0x%"PRIx32, reg_table[i].val, reg_table[i].addr);
}
+
+ if (pf->support_vf_vlan_antispoof) {
+ /**
+ * To enable vlan antispoof, we need write some undocumented
+ * glboal registers, cast below spell to trigger the magic.
+ */
+ i40e_aq_debug_write_register(hw, 0x00269624, 0xa0C38886, NULL);
+ i40e_aq_debug_write_register(hw, 0x00269EA4, 0x00003FE0, NULL);
+ i40e_aq_debug_write_register(hw, 0x002696A4, 0xA0C18886, NULL);
+ i40e_aq_debug_write_register(hw, 0x00269EE4, 0x0FFF1FFF, NULL);
+ i40e_aq_debug_write_register(hw, 0x00269F24, 0x00008000, NULL);
+ i40e_aq_debug_write_register(hw, 0x00269BE8, 0x07000200, NULL);
+ i40e_aq_debug_write_register(hw, 0x0026CDC8, 0x01010000, NULL);
+ i40e_aq_debug_write_register(hw, 0x0026CE08, 0x013F0000, NULL);
+ }
}
#define I40E_VSI_TSR(_i) (0x00050800 + ((_i) * 4))
@@ -12390,4 +12446,5 @@ i40e_init_log(void)
RTE_PMD_REGISTER_PARAM_STRING(net_i40e,
QUEUE_NUM_PER_VF_ARG "=1|2|4|8|16"
- ETH_I40E_SUPPORT_MULTI_DRIVER "=1");
+ ETH_I40E_SUPPORT_MULTI_DRIVER "=1"
+ ETH_I40E_SUPPORT_VF_VLAN_ANTI_SPOOF "=1");
@@ -960,6 +960,7 @@ struct i40e_pf {
bool qinq_replace_flag; /* QINQ filter replace is done */
struct i40e_tm_conf tm_conf;
bool support_multi_driver; /* 1 - support multiple driver */
+ bool support_vf_vlan_antispoof; /* 1 - support vf's vlan antispoof */
/* Dynamic Device Personalization */
bool gtp_support; /* 1 - support GTP-C and GTP-U */
@@ -1009,15 +1009,31 @@ i40e_pf_host_process_cmd_config_promisc_mode(
if (promisc->flags & FLAG_VF_UNICAST_PROMISC)
unicast = TRUE;
- ret = i40e_aq_set_vsi_unicast_promiscuous(hw,
- vf->vsi->seid, unicast, NULL, true);
- if (ret != I40E_SUCCESS)
- goto send_msg;
-
if (promisc->flags & FLAG_VF_MULTICAST_PROMISC)
multicast = TRUE;
- ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vf->vsi->seid,
- multicast, NULL);
+
+ if (vf->pf->support_vf_vlan_antispoof) {
+ if (unicast && multicast)
+ ret = i40e_aq_set_default_vsi(hw, vf->vsi->seid, NULL);
+ else if (!unicast && !multicast)
+ ret = i40e_aq_clear_default_vsi(hw,
+ vf->vsi->seid,
+ NULL);
+ else
+ ret = I40E_ERR_DEVICE_NOT_SUPPORTED;
+
+ if (ret != I40E_SUCCESS)
+ PMD_DRV_LOG(ERR,
+ "Failed to enable/disable promiscuous");
+ } else {
+ ret = i40e_aq_set_vsi_unicast_promiscuous(hw,
+ vf->vsi->seid, unicast, NULL, true);
+ if (ret != I40E_SUCCESS)
+ goto send_msg;
+
+ ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vf->vsi->seid,
+ multicast, NULL);
+ }
send_msg:
i40e_pf_host_send_msg_to_vf(vf,
@@ -37,36 +37,71 @@ rte_pmd_i40e_ping_vfs(uint16_t port, uint16_t vf)
return 0;
}
-int
-rte_pmd_i40e_set_vf_mac_anti_spoof(uint16_t port, uint16_t vf_id, uint8_t on)
+static int
+set_vlan_promisc(struct i40e_hw *hw,
+ uint16_t seid,
+ uint16_t vid,
+ bool enable)
{
- struct rte_eth_dev *dev;
- struct i40e_pf *pf;
- struct i40e_vsi *vsi;
- struct i40e_hw *hw;
- struct i40e_vsi_context ctxt;
- int ret;
+ struct i40e_aq_desc desc;
+ struct i40e_aqc_set_vsi_promiscuous_modes *cmd =
+ (struct i40e_aqc_set_vsi_promiscuous_modes *)&desc.params.raw;
- RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
+ i40e_fill_default_direct_cmd_desc(&desc,
+ i40e_aqc_opc_set_vsi_promiscuous_modes);
- dev = &rte_eth_devices[port];
+ if (enable)
+ cmd->promiscuous_flags = CPU_TO_LE16(0x8011);
- if (!is_i40e_supported(dev))
- return -ENOTSUP;
+ cmd->valid_flags = CPU_TO_LE16(0x8011);
+ cmd->seid = CPU_TO_LE16(seid);
+ cmd->vlan_tag = CPU_TO_LE16(vid | 0x8000);
- pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ return i40e_asq_send_command(hw, &desc, NULL, 0, NULL);
+}
- if (vf_id >= pf->vf_num || !pf->vfs) {
- PMD_DRV_LOG(ERR, "Invalid argument.");
- return -EINVAL;
- }
+static int
+set_all_vlan_promisc(struct i40e_vsi *vsi, uint8_t enable)
+{
+ struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+ uint32_t j, k;
+ uint16_t vlan_id;
+ int ret;
- vsi = pf->vfs[vf_id].vsi;
- if (!vsi) {
- PMD_DRV_LOG(ERR, "Invalid VSI.");
- return -EINVAL;
+ for (j = 0; j < I40E_VFTA_SIZE; j++) {
+ if (!vsi->vfta[j])
+ continue;
+
+ for (k = 0; k < I40E_UINT32_BIT_SIZE; k++) {
+ if (!(vsi->vfta[j] & (1 << k)))
+ continue;
+
+ vlan_id = j * I40E_UINT32_BIT_SIZE + k;
+ if (!vlan_id)
+ continue;
+
+ ret = set_vlan_promisc(hw, vsi->seid, vlan_id, enable);
+ if (ret != I40E_SUCCESS) {
+ PMD_DRV_LOG(ERR,
+ "Failed to set vlan antispoof: vid=%d",
+ vlan_id);
+ return ret;
+ }
+ }
}
+ return I40E_SUCCESS;
+}
+
+static int
+_i40e_set_vf_mac_anti_spoof(struct i40e_pf *pf,
+ struct i40e_vsi *vsi,
+ uint8_t on)
+{
+ struct i40e_hw *hw;
+ struct i40e_vsi_context ctxt;
+ int ret;
+
/* Check if it has been already on or off */
if (vsi->info.valid_sections &
rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SECURITY_VALID)) {
@@ -88,6 +123,11 @@ rte_pmd_i40e_set_vf_mac_anti_spoof(uint16_t port, uint16_t vf_id, uint8_t on)
else
vsi->info.sec_flags &= ~I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
+ if (pf->support_vf_vlan_antispoof) {
+ vsi->vlan_anti_spoof_on = on;
+ set_all_vlan_promisc(vsi, on);
+ }
+
memset(&ctxt, 0, sizeof(ctxt));
rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
ctxt.seid = vsi->seid;
@@ -103,6 +143,36 @@ rte_pmd_i40e_set_vf_mac_anti_spoof(uint16_t port, uint16_t vf_id, uint8_t on)
}
int
+rte_pmd_i40e_set_vf_mac_anti_spoof(uint16_t port, uint16_t vf_id, uint8_t on)
+{
+ struct rte_eth_dev *dev;
+ struct i40e_pf *pf;
+ struct i40e_vsi *vsi;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
+
+ dev = &rte_eth_devices[port];
+
+ if (!is_i40e_supported(dev))
+ return -ENOTSUP;
+
+ pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+
+ if (vf_id >= pf->vf_num || !pf->vfs) {
+ PMD_DRV_LOG(ERR, "Invalid argument.");
+ return -EINVAL;
+ }
+
+ vsi = pf->vfs[vf_id].vsi;
+ if (!vsi) {
+ PMD_DRV_LOG(ERR, "Invalid VSI.");
+ return -EINVAL;
+ }
+
+ return _i40e_set_vf_mac_anti_spoof(pf, vsi, on);
+}
+
+int
rte_pmd_i40e_set_vf_vlan_anti_spoof(uint16_t port, uint16_t vf_id, uint8_t on)
{
struct rte_eth_dev *dev;
@@ -132,6 +202,9 @@ rte_pmd_i40e_set_vf_vlan_anti_spoof(uint16_t port, uint16_t vf_id, uint8_t on)
return -EINVAL;
}
+ if (pf->support_vf_vlan_antispoof)
+ return _i40e_set_vf_mac_anti_spoof(pf, vsi, on);
+
/* Check if it has been already on or off */
if (vsi->vlan_anti_spoof_on == on)
return 0; /* already on or off */
@@ -384,6 +457,53 @@ rte_pmd_i40e_set_tx_loopback(uint16_t port, uint8_t on)
}
int
+rte_pmd_i40e_set_vf_promisc(uint16_t port, uint16_t vf_id, uint8_t on)
+{
+ struct rte_eth_dev *dev;
+ struct i40e_pf *pf;
+ struct i40e_vsi *vsi;
+ struct i40e_hw *hw;
+ int ret;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
+
+ dev = &rte_eth_devices[port];
+
+ if (!is_i40e_supported(dev))
+ return -ENOTSUP;
+
+ pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+
+ if (vf_id >= pf->vf_num || !pf->vfs) {
+ PMD_DRV_LOG(ERR, "Invalid argument.");
+ return -EINVAL;
+ }
+
+ vsi = pf->vfs[vf_id].vsi;
+ if (!vsi) {
+ PMD_DRV_LOG(ERR, "Invalid VSI.");
+ return -EINVAL;
+ }
+
+ if (!pf->support_vf_vlan_antispoof)
+ return -ENOTSUP;
+
+ hw = I40E_VSI_TO_HW(vsi);
+
+ if (on)
+ ret = i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
+ else
+ ret = i40e_aq_clear_default_vsi(hw, vsi->seid, NULL);
+
+ if (ret != I40E_SUCCESS) {
+ ret = -ENOTSUP;
+ PMD_DRV_LOG(ERR, "Failed to set promiscuous mode");
+ }
+
+ return ret;
+}
+
+int
rte_pmd_i40e_set_vf_unicast_promisc(uint16_t port, uint16_t vf_id, uint8_t on)
{
struct rte_eth_dev *dev;
@@ -412,6 +532,9 @@ rte_pmd_i40e_set_vf_unicast_promisc(uint16_t port, uint16_t vf_id, uint8_t on)
return -EINVAL;
}
+ if (pf->support_vf_vlan_antispoof)
+ return -ENOTSUP;
+
hw = I40E_VSI_TO_HW(vsi);
ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
@@ -453,6 +576,9 @@ rte_pmd_i40e_set_vf_multicast_promisc(uint16_t port, uint16_t vf_id, uint8_t on)
return -EINVAL;
}
+ if (pf->support_vf_vlan_antispoof)
+ return -ENOTSUP;
+
hw = I40E_VSI_TO_HW(vsi);
ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid,
@@ -840,6 +966,9 @@ int rte_pmd_i40e_set_vf_vlan_filter(uint16_t port, uint16_t vlan_id,
ret = i40e_vsi_add_vlan(vsi, vlan_id);
else
ret = i40e_vsi_delete_vlan(vsi, vlan_id);
+ if (vsi->vlan_anti_spoof_on)
+ ret = set_vlan_promisc(hw, vsi->seid,
+ vlan_id, on);
}
}
@@ -395,6 +395,26 @@ int rte_pmd_i40e_set_tx_loopback(uint16_t port,
uint8_t on);
/**
+ * Enable/Disable VF promiscuous mode.
+ *
+ * @param port
+ * The port identifier of the Ethernet device.
+ * @param vf_id
+ * VF on which to set.
+ * @param on
+ * 1 - Enable.
+ * 0 - Disable.
+ * @return
+ * - (0) if successful.
+ * - (-ENODEV) if *port* invalid.
+ * - (-EINVAL) if bad parameter.
+ * - (-ENOTSUP) if support-vf-anti-spoof is off.
+ */
+int rte_pmd_i40e_set_vf_promisc(uint16_t port,
+ uint16_t vf_id,
+ uint8_t on);
+
+/**
* Enable/Disable VF unicast promiscuous mode.
*
* @param port
@@ -408,6 +428,7 @@ int rte_pmd_i40e_set_tx_loopback(uint16_t port,
* - (0) if successful.
* - (-ENODEV) if *port* invalid.
* - (-EINVAL) if bad parameter.
+ * - (-ENOTSUP) if support-vf-anti-spoof is on.
*/
int rte_pmd_i40e_set_vf_unicast_promisc(uint16_t port,
uint16_t vf_id,
@@ -427,6 +448,7 @@ int rte_pmd_i40e_set_vf_unicast_promisc(uint16_t port,
* - (0) if successful.
* - (-ENODEV) if *port* invalid.
* - (-EINVAL) if bad parameter.
+ * - (-ENOTSUP) if support-vf-anti-spoof is on.
*/
int rte_pmd_i40e_set_vf_multicast_promisc(uint16_t port,
uint16_t vf_id,
@@ -64,4 +64,10 @@ DPDK_18.02 {
rte_pmd_i40e_inset_get;
rte_pmd_i40e_inset_set;
-} DPDK_17.11;
\ No newline at end of file
+} DPDK_17.11;
+
+DPDK_18.08 {
+ global:
+
+ rte_pmd_i40e_set_vf_promisc;
+} DPDK_18.2;