net/i40e: store ethertype filter
authorBeilei Xing <beilei.xing@intel.com>
Fri, 6 Jan 2017 05:27:03 +0000 (13:27 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 17 Jan 2017 18:40:53 +0000 (19:40 +0100)
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>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
drivers/net/i40e/Makefile
drivers/net/i40e/i40e_ethdev.c
drivers/net/i40e/i40e_ethdev.h

index 66997b6..11175c4 100644 (file)
@@ -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
index 3d7f954..e36a0fe 100644 (file)
@@ -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"
@@ -463,6 +464,12 @@ 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 int i40e_sw_ethertype_filter_insert(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) },
@@ -930,6 +937,49 @@ config_floating_veb(struct rte_eth_dev *dev)
 #define I40E_L2_TAGS_S_TAG_SHIFT 1
 #define I40E_L2_TAGS_S_TAG_MASK I40E_MASK(0x1, I40E_L2_TAGS_S_TAG_SHIFT)
 
+static int
+i40e_init_ethtype_filter_list(struct rte_eth_dev *dev)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
+       char ethertype_hash_name[RTE_HASH_NAMESIZE];
+       int ret;
+
+       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,
+       };
+
+       /* 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!");
+               return -EINVAL;
+       }
+       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);
+
+       return ret;
+}
+
 static int
 eth_i40e_dev_init(struct rte_eth_dev *dev)
 {
@@ -1186,8 +1236,14 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                pf->flags &= ~I40E_FLAG_DCB;
        }
 
+       ret = i40e_init_ethtype_filter_list(dev);
+       if (ret < 0)
+               goto err_init_ethtype_filter_list;
+
        return 0;
 
+err_init_ethtype_filter_list:
+       rte_free(dev->data->mac_addrs);
 err_mac_alloc:
        i40e_vsi_release(pf->main_vsi);
 err_setup_pf_switch:
@@ -1207,9 +1263,30 @@ err_sync_phy_type:
        return ret;
 }
 
+static void
+i40e_rm_ethtype_filter_list(struct i40e_pf *pf)
+{
+       struct i40e_ethertype_filter *p_ethertype;
+       struct i40e_ethertype_rule *ethertype_rule;
+
+       ethertype_rule = &pf->ethertype;
+       /* Remove all ethertype filter 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);
+       }
+}
+
 static int
 eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 {
+       struct i40e_pf *pf;
        struct rte_pci_device *pci_dev;
        struct rte_intr_handle *intr_handle;
        struct i40e_hw *hw;
@@ -1222,6 +1299,7 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
        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 = I40E_DEV_TO_PCI(dev);
        intr_handle = &pci_dev->intr_handle;
@@ -1260,6 +1338,8 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
        rte_intr_callback_unregister(intr_handle,
                                     i40e_dev_interrupt_handler, dev);
 
+       i40e_rm_ethtype_filter_list(pf);
+
        return 0;
 }
 
@@ -8008,6 +8088,82 @@ 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 */
+struct i40e_ethertype_filter *
+i40e_sw_ethertype_filter_lookup(struct i40e_ethertype_rule *ethertype_rule,
+                               const struct i40e_ethertype_filter_input *input)
+{
+       int ret;
+
+       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 *rule = &pf->ethertype;
+       int ret;
+
+       ret = rte_hash_add_key(rule->hash_table, &filter->input);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR,
+                           "Failed to insert ethertype filter"
+                           " to hash table %d!",
+                           ret);
+               return ret;
+       }
+       rule->hash_map[ret] = filter;
+
+       TAILQ_INSERT_TAIL(&rule->ethertype_list, filter, rules);
+
+       return 0;
+}
+
+/* Delete ethertype filter in SW list */
+int
+i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
+                            struct i40e_ethertype_filter_input *input)
+{
+       struct i40e_ethertype_rule *rule = &pf->ethertype;
+       struct i40e_ethertype_filter *filter;
+       int ret;
+
+       ret = rte_hash_del_key(rule->hash_table, input);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR,
+                           "Failed to delete ethertype filter"
+                           " to hash table %d!",
+                           ret);
+               return ret;
+       }
+       filter = rule->hash_map[ret];
+       rule->hash_map[ret] = NULL;
+
+       TAILQ_REMOVE(&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
@@ -8018,6 +8174,9 @@ 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_ethertype_filter check_filter;
        struct i40e_control_filter_stats stats;
        uint16_t flags = 0;
        int ret;
@@ -8036,6 +8195,21 @@ 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 */
+       memset(&check_filter, 0, sizeof(check_filter));
+       i40e_ethertype_filter_convert(filter, &check_filter);
+       node = i40e_sw_ethertype_filter_lookup(ethertype_rule,
+                                              &check_filter.input);
+       if (add && node) {
+               PMD_DRV_LOG(ERR, "Conflict with existing ethertype rules!");
+               return -EINVAL;
+       }
+
+       if (!add && !node) {
+               PMD_DRV_LOG(ERR, "There's no corresponding 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)
@@ -8056,7 +8230,19 @@ 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) {
+               ethertype_filter = rte_zmalloc("ethertype_filter",
+                                      sizeof(*ethertype_filter), 0);
+               rte_memcpy(ethertype_filter, &check_filter,
+                          sizeof(check_filter));
+               ret = i40e_sw_ethertype_filter_insert(pf, ethertype_filter);
+       } else {
+               ret = i40e_sw_ethertype_filter_del(pf, &node->input);
+       }
+
+       return ret;
 }
 
 /*
index b0363f9..dbfcf9f 100644 (file)
@@ -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 */
@@ -616,6 +642,11 @@ void i40e_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
        struct rte_eth_rxq_info *qinfo);
 void i40e_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
        struct rte_eth_txq_info *qinfo);
+struct i40e_ethertype_filter *
+i40e_sw_ethertype_filter_lookup(struct i40e_ethertype_rule *ethertype_rule,
+                       const struct i40e_ethertype_filter_input *input);
+int i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
+                                struct i40e_ethertype_filter_input *input);
 
 #define I40E_DEV_TO_PCI(eth_dev) \
        RTE_DEV_TO_PCI((eth_dev)->device)