[dpdk-dev,v2,01/17] net/i40e: store ethertype filter
Checks
Commit Message
Currently there's no ethertype filter stored in SW.
This patch stores ethertype filter with cuckoo hash
in SW, also adds protection if an ethertype filter
has been added.
Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
drivers/net/i40e/Makefile | 1 +
drivers/net/i40e/i40e_ethdev.c | 164 ++++++++++++++++++++++++++++++++++++++++-
drivers/net/i40e/i40e_ethdev.h | 26 +++++++
3 files changed, 190 insertions(+), 1 deletion(-)
Comments
> +
> +/* Delete ethertype filter in SW list */ static int
> +i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
> + struct i40e_ethertype_filter *filter) {
> + struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
> + int ret = 0;
> +
> + ret = rte_hash_del_key(ethertype_rule->hash_table,
> + &filter->input);
> + if (ret < 0)
> + PMD_DRV_LOG(ERR,
> + "Failed to delete ethertype filter"
> + " to hash table %d!",
> + ret);
> + ethertype_rule->hash_map[ret] = NULL;
> +
> + TAILQ_REMOVE(ðertype_rule->ethertype_list, filter, rules);
> + rte_free(filter);
It's better to free filter out of del function because the filter is also the input argument.
Or you can define this function to use key as argument but not filter.
> /*
> * Configure ethertype filter, which can director packet by filtering
> * with mac address and ether_type or only ether_type @@ -7964,6 +8099,8
> @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
> bool add)
> {
> struct i40e_hw *hw = I40E_PF_TO_HW(pf);
> + struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
> + struct i40e_ethertype_filter *ethertype_filter, *node;
> struct i40e_control_filter_stats stats;
> uint16_t flags = 0;
> int ret;
> @@ -7982,6 +8119,22 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
> PMD_DRV_LOG(WARNING, "filter vlan ether_type in first tag is"
> " not supported.");
>
> + /* Check if there is the filter in SW list */
> + ethertype_filter = rte_zmalloc("ethertype_filter",
> + sizeof(*ethertype_filter), 0);
> + i40e_ethertype_filter_convert(filter, ethertype_filter);
> + node = i40e_sw_ethertype_filter_lookup(ethertype_rule,
> + ðertype_filter->input);
> + if (add && node) {
> + PMD_DRV_LOG(ERR, "Conflict with existing ethertype rules!");
> + rte_free(ethertype_filter);
> + return -EINVAL;
> + } else if (!add && !node) {
> + PMD_DRV_LOG(ERR, "There's no corresponding ethertype
> filter!");
> + rte_free(ethertype_filter);
> + return -EINVAL;
> + }
How about malloc ethertype_filter after check? Especially, no need to malloc it when delete a filter.
Thanks
Jingjing
On Tue, Dec 27, 2016 at 02:26:08PM +0800, Beilei Xing wrote:
> Currently there's no ethertype filter stored in SW.
> This patch stores ethertype filter with cuckoo hash
> in SW, also adds protection if an ethertype filter
> has been added.
>
> Signed-off-by: Beilei Xing <beilei.xing@intel.com>
> ---
> drivers/net/i40e/Makefile | 1 +
> drivers/net/i40e/i40e_ethdev.c | 164 ++++++++++++++++++++++++++++++++++++++++-
> drivers/net/i40e/i40e_ethdev.h | 26 +++++++
> 3 files changed, 190 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/i40e/Makefile b/drivers/net/i40e/Makefile
> index 66997b6..11175c4 100644
> --- a/drivers/net/i40e/Makefile
> +++ b/drivers/net/i40e/Makefile
> @@ -117,5 +117,6 @@ DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_eal lib/librte_ether
> DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_mempool lib/librte_mbuf
> DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_net
> DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_kvargs
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_hash
>
> include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
> index f42f4ba..80dd8d7 100644
> --- a/drivers/net/i40e/i40e_ethdev.c
> +++ b/drivers/net/i40e/i40e_ethdev.c
[...]
> @@ -1203,23 +1249,40 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
> static int
> eth_i40e_dev_uninit(struct rte_eth_dev *dev)
> {
> + struct i40e_pf *pf;
> struct rte_pci_device *pci_dev;
> struct i40e_hw *hw;
> struct i40e_filter_control_settings settings;
> + struct i40e_ethertype_filter *p_ethertype;
> int ret;
> uint8_t aq_fail = 0;
> + struct i40e_ethertype_rule *ethertype_rule;
>
> PMD_INIT_FUNC_TRACE();
>
> if (rte_eal_process_type() != RTE_PROC_PRIMARY)
> return 0;
>
> + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
> hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
> pci_dev = dev->pci_dev;
> + ethertype_rule = &pf->ethertype;
>
> if (hw->adapter_stopped == 0)
> i40e_dev_close(dev);
>
> + /* Remove all ethertype director rules and hash */
> + if (ethertype_rule->hash_map)
> + rte_free(ethertype_rule->hash_map);
> + if (ethertype_rule->hash_table)
> + rte_hash_free(ethertype_rule->hash_table);
> +
> + while ((p_ethertype = TAILQ_FIRST(ðertype_rule->ethertype_list))) {
There is a redundant pair of parentheses, or you should compare with
NULL.
> + TAILQ_REMOVE(ðertype_rule->ethertype_list,
> + p_ethertype, rules);
> + rte_free(p_ethertype);
> + }
> +
> dev->dev_ops = NULL;
> dev->rx_pkt_burst = NULL;
> dev->tx_pkt_burst = NULL;
> @@ -7954,6 +8017,78 @@ i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
> return ret;
> }
>
> +/* Convert ethertype filter structure */
> +static int
> +i40e_ethertype_filter_convert(const struct rte_eth_ethertype_filter *input,
> + struct i40e_ethertype_filter *filter)
> +{
> + rte_memcpy(&filter->input.mac_addr, &input->mac_addr, ETHER_ADDR_LEN);
> + filter->input.ether_type = input->ether_type;
> + filter->flags = input->flags;
> + filter->queue = input->queue;
> +
> + return 0;
> +}
> +
> +/* Check if there exists the ehtertype filter */
> +static struct i40e_ethertype_filter *
> +i40e_sw_ethertype_filter_lookup(struct i40e_ethertype_rule *ethertype_rule,
> + const struct i40e_ethertype_filter_input *input)
> +{
> + int ret = 0;
> +
The initialization is meaningless, as it will be written by the below
assignment unconditionally.
> + ret = rte_hash_lookup(ethertype_rule->hash_table, (const void *)input);
> + if (ret < 0)
> + return NULL;
> +
> + return ethertype_rule->hash_map[ret];
> +}
> +
> +/* Add ethertype filter in SW list */
> +static int
> +i40e_sw_ethertype_filter_insert(struct i40e_pf *pf,
> + struct i40e_ethertype_filter *filter)
> +{
> + struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
> + int ret = 0;
> +
Same here.
> + ret = rte_hash_add_key(ethertype_rule->hash_table,
> + &filter->input);
> + if (ret < 0)
> + PMD_DRV_LOG(ERR,
> + "Failed to insert ethertype filter"
> + " to hash table %d!",
> + ret);
Function should return when ret < 0.
> + ethertype_rule->hash_map[ret] = filter;
> +
> + TAILQ_INSERT_TAIL(ðertype_rule->ethertype_list, filter, rules);
> +
> + return 0;
> +}
> +
> +/* Delete ethertype filter in SW list */
> +static int
> +i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
> + struct i40e_ethertype_filter *filter)
> +{
> + struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
> + int ret = 0;
> +
Same here.
> + ret = rte_hash_del_key(ethertype_rule->hash_table,
> + &filter->input);
> + if (ret < 0)
> + PMD_DRV_LOG(ERR,
> + "Failed to delete ethertype filter"
> + " to hash table %d!",
> + ret);
Function should return when ret < 0.
> + ethertype_rule->hash_map[ret] = NULL;
> +
> + TAILQ_REMOVE(ðertype_rule->ethertype_list, filter, rules);
> + rte_free(filter);
> +
> + return 0;
> +}
> +
> /*
> * Configure ethertype filter, which can director packet by filtering
> * with mac address and ether_type or only ether_type
> @@ -7964,6 +8099,8 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
> bool add)
> {
> struct i40e_hw *hw = I40E_PF_TO_HW(pf);
> + struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
> + struct i40e_ethertype_filter *ethertype_filter, *node;
> struct i40e_control_filter_stats stats;
> uint16_t flags = 0;
> int ret;
> @@ -7982,6 +8119,22 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
> PMD_DRV_LOG(WARNING, "filter vlan ether_type in first tag is"
> " not supported.");
>
> + /* Check if there is the filter in SW list */
> + ethertype_filter = rte_zmalloc("ethertype_filter",
> + sizeof(*ethertype_filter), 0);
> + i40e_ethertype_filter_convert(filter, ethertype_filter);
> + node = i40e_sw_ethertype_filter_lookup(ethertype_rule,
> + ðertype_filter->input);
> + if (add && node) {
> + PMD_DRV_LOG(ERR, "Conflict with existing ethertype rules!");
> + rte_free(ethertype_filter);
> + return -EINVAL;
> + } else if (!add && !node) {
When `if (add && node)' is true, function will return. There is no need
to use `else' here.
Best regards,
Tiwei Bie
> -----Original Message-----
> From: Wu, Jingjing
> Sent: Wednesday, December 28, 2016 10:22 AM
> To: Xing, Beilei <beilei.xing@intel.com>; Zhang, Helin
> <helin.zhang@intel.com>
> Cc: dev@dpdk.org
> Subject: RE: [PATCH v2 01/17] net/i40e: store ethertype filter
>
> > +
> > +/* Delete ethertype filter in SW list */ static int
> > +i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
> > + struct i40e_ethertype_filter *filter) {
> > + struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
> > + int ret = 0;
> > +
> > + ret = rte_hash_del_key(ethertype_rule->hash_table,
> > + &filter->input);
> > + if (ret < 0)
> > + PMD_DRV_LOG(ERR,
> > + "Failed to delete ethertype filter"
> > + " to hash table %d!",
> > + ret);
> > + ethertype_rule->hash_map[ret] = NULL;
> > +
> > + TAILQ_REMOVE(ðertype_rule->ethertype_list, filter, rules);
> > + rte_free(filter);
>
> It's better to free filter out of del function because the filter is also the input
> argument.
> Or you can define this function to use key as argument but not filter.
Thanks for the suggestion, I'll use the key as parameter in the next version.
>
> > /*
> > * Configure ethertype filter, which can director packet by filtering
> > * with mac address and ether_type or only ether_type @@ -7964,6
> > +8099,8 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
> > bool add)
> > {
> > struct i40e_hw *hw = I40E_PF_TO_HW(pf);
> > + struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
> > + struct i40e_ethertype_filter *ethertype_filter, *node;
> > struct i40e_control_filter_stats stats;
> > uint16_t flags = 0;
> > int ret;
> > @@ -7982,6 +8119,22 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
> > PMD_DRV_LOG(WARNING, "filter vlan ether_type in first tag
> is"
> > " not supported.");
> >
> > + /* Check if there is the filter in SW list */
> > + ethertype_filter = rte_zmalloc("ethertype_filter",
> > + sizeof(*ethertype_filter), 0);
> > + i40e_ethertype_filter_convert(filter, ethertype_filter);
> > + node = i40e_sw_ethertype_filter_lookup(ethertype_rule,
> > + ðertype_filter->input);
> > + if (add && node) {
> > + PMD_DRV_LOG(ERR, "Conflict with existing ethertype
> rules!");
> > + rte_free(ethertype_filter);
> > + return -EINVAL;
> > + } else if (!add && !node) {
> > + PMD_DRV_LOG(ERR, "There's no corresponding ethertype
> > filter!");
> > + rte_free(ethertype_filter);
> > + return -EINVAL;
> > + }
> How about malloc ethertype_filter after check? Especially, no need to malloc
> it when delete a filter.
Malloc ethertype_filter because i40e_ethertype_filter_convert is involved first, and then check if a rule exists with ethertype_filter->input.
>
> Thanks
> Jingjing
> -----Original Message-----
> From: Xing, Beilei
> Sent: Thursday, December 29, 2016 12:03 PM
> To: Wu, Jingjing <jingjing.wu@intel.com>; Zhang, Helin
> <helin.zhang@intel.com>
> Cc: dev@dpdk.org
> Subject: RE: [PATCH v2 01/17] net/i40e: store ethertype filter
>
> > -----Original Message-----
> > From: Wu, Jingjing
> > Sent: Wednesday, December 28, 2016 10:22 AM
> > To: Xing, Beilei <beilei.xing@intel.com>; Zhang, Helin
> > <helin.zhang@intel.com>
> > Cc: dev@dpdk.org
> > Subject: RE: [PATCH v2 01/17] net/i40e: store ethertype filter
> >
> > > +
> > > +/* Delete ethertype filter in SW list */ static int
> > > +i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
> > > + struct i40e_ethertype_filter *filter) {
> > > + struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
> > > + int ret = 0;
> > > +
> > > + ret = rte_hash_del_key(ethertype_rule->hash_table,
> > > + &filter->input);
> > > + if (ret < 0)
> > > + PMD_DRV_LOG(ERR,
> > > + "Failed to delete ethertype filter"
> > > + " to hash table %d!",
> > > + ret);
> > > + ethertype_rule->hash_map[ret] = NULL;
> > > +
> > > + TAILQ_REMOVE(ðertype_rule->ethertype_list, filter, rules);
> > > + rte_free(filter);
> >
> > It's better to free filter out of del function because the filter is
> > also the input argument.
> > Or you can define this function to use key as argument but not filter.
>
> Thanks for the suggestion, I'll use the key as parameter in the next version.
>
> >
> > > /*
> > > * Configure ethertype filter, which can director packet by filtering
> > > * with mac address and ether_type or only ether_type @@ -7964,6
> > > +8099,8 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
> > > bool add)
> > > {
> > > struct i40e_hw *hw = I40E_PF_TO_HW(pf);
> > > + struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
> > > + struct i40e_ethertype_filter *ethertype_filter, *node;
> > > struct i40e_control_filter_stats stats;
> > > uint16_t flags = 0;
> > > int ret;
> > > @@ -7982,6 +8119,22 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
> > > PMD_DRV_LOG(WARNING, "filter vlan ether_type in first tag
> > is"
> > > " not supported.");
> > >
> > > + /* Check if there is the filter in SW list */
> > > + ethertype_filter = rte_zmalloc("ethertype_filter",
> > > + sizeof(*ethertype_filter), 0);
> > > + i40e_ethertype_filter_convert(filter, ethertype_filter);
> > > + node = i40e_sw_ethertype_filter_lookup(ethertype_rule,
> > > + ðertype_filter->input);
> > > + if (add && node) {
> > > + PMD_DRV_LOG(ERR, "Conflict with existing ethertype
> > rules!");
> > > + rte_free(ethertype_filter);
> > > + return -EINVAL;
> > > + } else if (!add && !node) {
> > > + PMD_DRV_LOG(ERR, "There's no corresponding ethertype
> > > filter!");
> > > + rte_free(ethertype_filter);
> > > + return -EINVAL;
> > > + }
> > How about malloc ethertype_filter after check? Especially, no need to
> > malloc it when delete a filter.
>
> Malloc ethertype_filter because i40e_ethertype_filter_convert is involved
> first, and then check if a rule exists with ethertype_filter->input.
Sorry, you are right. In fact I needn't to malloc before convert. Will update it in next version.
>
> >
> > Thanks
> > Jingjing
@@ -117,5 +117,6 @@ DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_eal lib/librte_ether
DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_mempool lib/librte_mbuf
DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_net
DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_kvargs
+DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_hash
include $(RTE_SDK)/mk/rte.lib.mk
@@ -51,6 +51,7 @@
#include <rte_dev.h>
#include <rte_eth_ctrl.h>
#include <rte_tailq.h>
+#include <rte_hash_crc.h>
#include "i40e_logs.h"
#include "base/i40e_prototype.h"
@@ -461,6 +462,17 @@ static void i40e_set_default_mac_addr(struct rte_eth_dev *dev,
static int i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
+static int i40e_ethertype_filter_convert(
+ const struct rte_eth_ethertype_filter *input,
+ struct i40e_ethertype_filter *filter);
+static struct i40e_ethertype_filter *
+i40e_sw_ethertype_filter_lookup(struct i40e_ethertype_rule *ethertype_rule,
+ const struct i40e_ethertype_filter_input *input);
+static int i40e_sw_ethertype_filter_insert(struct i40e_pf *pf,
+ struct i40e_ethertype_filter *filter);
+static int i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
+ struct i40e_ethertype_filter *filter);
+
static const struct rte_pci_id pci_id_i40e_map[] = {
{ RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710) },
{ RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QEMU) },
@@ -937,9 +949,18 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
int ret;
uint32_t len;
uint8_t aq_fail = 0;
+ struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
PMD_INIT_FUNC_TRACE();
+ char ethertype_hash_name[RTE_HASH_NAMESIZE];
+ struct rte_hash_parameters ethertype_hash_params = {
+ .name = ethertype_hash_name,
+ .entries = I40E_MAX_ETHERTYPE_FILTER_NUM,
+ .key_len = sizeof(struct i40e_ethertype_filter_input),
+ .hash_func = rte_hash_crc,
+ };
+
dev->dev_ops = &i40e_eth_dev_ops;
dev->rx_pkt_burst = i40e_recv_pkts;
dev->tx_pkt_burst = i40e_xmit_pkts;
@@ -1179,8 +1200,33 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
pf->flags &= ~I40E_FLAG_DCB;
}
+ /* Initialize ethertype filter rule list and hash */
+ TAILQ_INIT(ðertype_rule->ethertype_list);
+ snprintf(ethertype_hash_name, RTE_HASH_NAMESIZE,
+ "ethertype_%s", dev->data->name);
+ ethertype_rule->hash_table = rte_hash_create(ðertype_hash_params);
+ if (!ethertype_rule->hash_table) {
+ PMD_INIT_LOG(ERR, "Failed to create ethertype hash table!");
+ ret = -EINVAL;
+ goto err_ethertype_hash_table_create;
+ }
+ ethertype_rule->hash_map = rte_zmalloc("i40e_ethertype_hash_map",
+ sizeof(struct i40e_ethertype_filter *) *
+ I40E_MAX_ETHERTYPE_FILTER_NUM,
+ 0);
+ if (!ethertype_rule->hash_map) {
+ PMD_INIT_LOG(ERR,
+ "Failed to allocate memory for ethertype hash map!");
+ ret = -ENOMEM;
+ goto err_ethertype_hash_map_alloc;
+ }
+
return 0;
+err_ethertype_hash_map_alloc:
+ rte_hash_free(ethertype_rule->hash_table);
+err_ethertype_hash_table_create:
+ rte_free(dev->data->mac_addrs);
err_mac_alloc:
i40e_vsi_release(pf->main_vsi);
err_setup_pf_switch:
@@ -1203,23 +1249,40 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
static int
eth_i40e_dev_uninit(struct rte_eth_dev *dev)
{
+ struct i40e_pf *pf;
struct rte_pci_device *pci_dev;
struct i40e_hw *hw;
struct i40e_filter_control_settings settings;
+ struct i40e_ethertype_filter *p_ethertype;
int ret;
uint8_t aq_fail = 0;
+ struct i40e_ethertype_rule *ethertype_rule;
PMD_INIT_FUNC_TRACE();
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return 0;
+ pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
pci_dev = dev->pci_dev;
+ ethertype_rule = &pf->ethertype;
if (hw->adapter_stopped == 0)
i40e_dev_close(dev);
+ /* Remove all ethertype director rules and hash */
+ if (ethertype_rule->hash_map)
+ rte_free(ethertype_rule->hash_map);
+ if (ethertype_rule->hash_table)
+ rte_hash_free(ethertype_rule->hash_table);
+
+ while ((p_ethertype = TAILQ_FIRST(ðertype_rule->ethertype_list))) {
+ TAILQ_REMOVE(ðertype_rule->ethertype_list,
+ p_ethertype, rules);
+ rte_free(p_ethertype);
+ }
+
dev->dev_ops = NULL;
dev->rx_pkt_burst = NULL;
dev->tx_pkt_burst = NULL;
@@ -7954,6 +8017,78 @@ i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
return ret;
}
+/* Convert ethertype filter structure */
+static int
+i40e_ethertype_filter_convert(const struct rte_eth_ethertype_filter *input,
+ struct i40e_ethertype_filter *filter)
+{
+ rte_memcpy(&filter->input.mac_addr, &input->mac_addr, ETHER_ADDR_LEN);
+ filter->input.ether_type = input->ether_type;
+ filter->flags = input->flags;
+ filter->queue = input->queue;
+
+ return 0;
+}
+
+/* Check if there exists the ehtertype filter */
+static struct i40e_ethertype_filter *
+i40e_sw_ethertype_filter_lookup(struct i40e_ethertype_rule *ethertype_rule,
+ const struct i40e_ethertype_filter_input *input)
+{
+ int ret = 0;
+
+ ret = rte_hash_lookup(ethertype_rule->hash_table, (const void *)input);
+ if (ret < 0)
+ return NULL;
+
+ return ethertype_rule->hash_map[ret];
+}
+
+/* Add ethertype filter in SW list */
+static int
+i40e_sw_ethertype_filter_insert(struct i40e_pf *pf,
+ struct i40e_ethertype_filter *filter)
+{
+ struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
+ int ret = 0;
+
+ ret = rte_hash_add_key(ethertype_rule->hash_table,
+ &filter->input);
+ if (ret < 0)
+ PMD_DRV_LOG(ERR,
+ "Failed to insert ethertype filter"
+ " to hash table %d!",
+ ret);
+ ethertype_rule->hash_map[ret] = filter;
+
+ TAILQ_INSERT_TAIL(ðertype_rule->ethertype_list, filter, rules);
+
+ return 0;
+}
+
+/* Delete ethertype filter in SW list */
+static int
+i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
+ struct i40e_ethertype_filter *filter)
+{
+ struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
+ int ret = 0;
+
+ ret = rte_hash_del_key(ethertype_rule->hash_table,
+ &filter->input);
+ if (ret < 0)
+ PMD_DRV_LOG(ERR,
+ "Failed to delete ethertype filter"
+ " to hash table %d!",
+ ret);
+ ethertype_rule->hash_map[ret] = NULL;
+
+ TAILQ_REMOVE(ðertype_rule->ethertype_list, filter, rules);
+ rte_free(filter);
+
+ return 0;
+}
+
/*
* Configure ethertype filter, which can director packet by filtering
* with mac address and ether_type or only ether_type
@@ -7964,6 +8099,8 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
bool add)
{
struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+ struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
+ struct i40e_ethertype_filter *ethertype_filter, *node;
struct i40e_control_filter_stats stats;
uint16_t flags = 0;
int ret;
@@ -7982,6 +8119,22 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
PMD_DRV_LOG(WARNING, "filter vlan ether_type in first tag is"
" not supported.");
+ /* Check if there is the filter in SW list */
+ ethertype_filter = rte_zmalloc("ethertype_filter",
+ sizeof(*ethertype_filter), 0);
+ i40e_ethertype_filter_convert(filter, ethertype_filter);
+ node = i40e_sw_ethertype_filter_lookup(ethertype_rule,
+ ðertype_filter->input);
+ if (add && node) {
+ PMD_DRV_LOG(ERR, "Conflict with existing ethertype rules!");
+ rte_free(ethertype_filter);
+ return -EINVAL;
+ } else if (!add && !node) {
+ PMD_DRV_LOG(ERR, "There's no corresponding ethertype filter!");
+ rte_free(ethertype_filter);
+ return -EINVAL;
+ }
+
if (!(filter->flags & RTE_ETHTYPE_FLAGS_MAC))
flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC;
if (filter->flags & RTE_ETHTYPE_FLAGS_DROP)
@@ -8002,7 +8155,16 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
stats.mac_etype_free, stats.etype_free);
if (ret < 0)
return -ENOSYS;
- return 0;
+
+ /* Add or delete a filter in SW list */
+ if (add) {
+ ret = i40e_sw_ethertype_filter_insert(pf, ethertype_filter);
+ } else {
+ ret = i40e_sw_ethertype_filter_del(pf, node);
+ rte_free(ethertype_filter);
+ }
+
+ return ret;
}
/*
@@ -37,6 +37,7 @@
#include <rte_eth_ctrl.h>
#include <rte_time.h>
#include <rte_kvargs.h>
+#include <rte_hash.h>
#define I40E_VLAN_TAG_SIZE 4
@@ -396,6 +397,30 @@ struct i40e_fdir_info {
struct i40e_fdir_flex_mask flex_mask[I40E_FILTER_PCTYPE_MAX];
};
+/* Ethertype filter number HW supports */
+#define I40E_MAX_ETHERTYPE_FILTER_NUM 768
+
+/* Ethertype filter struct */
+struct i40e_ethertype_filter_input {
+ struct ether_addr mac_addr; /* Mac address to match */
+ uint16_t ether_type; /* Ether type to match */
+};
+
+struct i40e_ethertype_filter {
+ TAILQ_ENTRY(i40e_ethertype_filter) rules;
+ struct i40e_ethertype_filter_input input;
+ uint16_t flags; /* Flags from RTE_ETHTYPE_FLAGS_* */
+ uint16_t queue; /* Queue assigned to when match */
+};
+
+TAILQ_HEAD(i40e_ethertype_filter_list, i40e_ethertype_filter);
+
+struct i40e_ethertype_rule {
+ struct i40e_ethertype_filter_list ethertype_list;
+ struct i40e_ethertype_filter **hash_map;
+ struct rte_hash *hash_table;
+};
+
#define I40E_MIRROR_MAX_ENTRIES_PER_RULE 64
#define I40E_MAX_MIRROR_RULES 64
/*
@@ -466,6 +491,7 @@ struct i40e_pf {
struct i40e_vmdq_info *vmdq;
struct i40e_fdir_info fdir; /* flow director info */
+ struct i40e_ethertype_rule ethertype; /* Ethertype filter rule */
struct i40e_fc_conf fc_conf; /* Flow control conf */
struct i40e_mirror_rule_list mirror_list;
uint16_t nb_mirror_rule; /* The number of mirror rules */