[dpdk-dev,v2,01/17] net/i40e: store ethertype filter

Message ID 1482819984-14120-2-git-send-email-beilei.xing@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel compilation fail Compilation issues

Commit Message

Xing, Beilei Dec. 27, 2016, 6:26 a.m. UTC
  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

Jingjing Wu Dec. 28, 2016, 2:22 a.m. UTC | #1
> +
> +/* 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(&ethertype_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,
> +					       &ethertype_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
  
Tiwei Bie Dec. 28, 2016, 3:22 a.m. UTC | #2
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(&ethertype_rule->ethertype_list))) {

There is a redundant pair of parentheses, or you should compare with
NULL.

> +		TAILQ_REMOVE(&ethertype_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(&ethertype_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(&ethertype_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,
> +					       &ethertype_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
  
Xing, Beilei Dec. 29, 2016, 4:03 a.m. UTC | #3
> -----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(&ethertype_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,
> > +					       &ethertype_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
  
Xing, Beilei Dec. 29, 2016, 4:36 a.m. UTC | #4
> -----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(&ethertype_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,
> > > +					       &ethertype_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
  

Patch

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
@@ -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(&ethertype_rule->ethertype_list);
+	snprintf(ethertype_hash_name, RTE_HASH_NAMESIZE,
+		 "ethertype_%s", dev->data->name);
+	ethertype_rule->hash_table = rte_hash_create(&ethertype_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(&ethertype_rule->ethertype_list))) {
+		TAILQ_REMOVE(&ethertype_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(&ethertype_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(&ethertype_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,
+					       &ethertype_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;
 }
 
 /*
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 298cef4..316af80 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -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 */