[dpdk-dev,v2,03/18] net/ixgbe: store L2 tunnel filter
Checks
Commit Message
Add support for storing L2 tunnel filter in SW.
Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
Signed-off-by: Wei Zhao <wei.zhao1@intel.com>
---
v2:
--add a L2 tunnel initialization function in device start process
---
drivers/net/ixgbe/ixgbe_ethdev.c | 157 +++++++++++++++++++++++++++++++++++++++
drivers/net/ixgbe/ixgbe_ethdev.h | 24 ++++++
2 files changed, 181 insertions(+)
Comments
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Wei Zhao
> Sent: Friday, December 30, 2016 3:53 PM
> To: dev@dpdk.org
> Cc: Lu, Wenzhuo <wenzhuo.lu@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: [dpdk-dev] [PATCH v2 03/18] net/ixgbe: store L2 tunnel filter
>
> Add support for storing L2 tunnel filter in SW.
>
> Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
> Signed-off-by: Wei Zhao <wei.zhao1@intel.com>
> ---
>
>
> +static inline struct ixgbe_l2_tn_filter *
> +ixgbe_l2_tn_filter_lookup(struct ixgbe_l2_tn_info *l2_tn_info,
> + struct ixgbe_l2_tn_key *key)
> +{
> + int ret = 0;
Needles initialization since ret will be set bellow, it can be removed.
And this initialization can be removed in other filter lookup/insert/delete functions, either.
> +
> + ret = rte_hash_lookup(l2_tn_info->hash_handle, (const void *)key);
> + if (ret < 0)
> + return NULL;
> +
> + return l2_tn_info->hash_map[ret];
> +}
> +
> +static inline int
> +ixgbe_insert_l2_tn_filter(struct ixgbe_l2_tn_info *l2_tn_info,
> + struct ixgbe_l2_tn_filter *l2_tn_filter) {
> + int ret = 0;
> +
> + ret = rte_hash_add_key(l2_tn_info->hash_handle,
> + &l2_tn_filter->key);
> +
> + if (ret < 0) {
> + PMD_DRV_LOG(ERR,
> + "Failed to insert L2 tunnel filter"
> + " to hash table %d!",
> + ret);
> + return ret;
> + }
> +
> + l2_tn_info->hash_map[ret] = l2_tn_filter;
> +
> + TAILQ_INSERT_TAIL(&l2_tn_info->l2_tn_list, l2_tn_filter, entries);
> +
> + return 0;
> +}
> /* Add l2 tunnel filter */
> static int
> ixgbe_dev_l2_tunnel_filter_add(struct rte_eth_dev *dev,
> struct rte_eth_l2_tunnel_conf *l2_tunnel) {
> int ret = 0;
> + struct ixgbe_l2_tn_info *l2_tn_info =
> + IXGBE_DEV_PRIVATE_TO_L2_TN_INFO(dev->data->dev_private);
> + struct ixgbe_l2_tn_key key;
> + struct ixgbe_l2_tn_filter *node;
> +
> + key.l2_tn_type = l2_tunnel->l2_tunnel_type;
> + key.tn_id = l2_tunnel->tunnel_id;
> +
> + node = ixgbe_l2_tn_filter_lookup(l2_tn_info, &key);
> +
> + if (node) {
> + PMD_DRV_LOG(ERR, "The L2 tunnel filter already exists!");
> + return -EINVAL;
> + }
> +
> + node = rte_zmalloc("ixgbe_l2_tn",
> + sizeof(struct ixgbe_l2_tn_filter),
> + 0);
> + if (!node)
> + return -ENOMEM;
> +
> + (void)rte_memcpy(&node->key,
> + &key,
> + sizeof(struct ixgbe_l2_tn_key));
> + node->pool = l2_tunnel->pool;
> + ret = ixgbe_insert_l2_tn_filter(l2_tn_info, node);
> + if (ret < 0) {
> + rte_free(node);
> + return ret;
> + }
>
> switch (l2_tunnel->l2_tunnel_type) {
> case RTE_L2_TUNNEL_TYPE_E_TAG:
> @@ -7195,6 +7340,9 @@ ixgbe_dev_l2_tunnel_filter_add(struct rte_eth_dev
> *dev,
> break;
> }
>
> + if (ret < 0)
> + (void)ixgbe_remove_l2_tn_filter(l2_tn_info, &key);
Some confusion, why remove l2_tn_filter here? Can this check be moved before ixgbe_insert_l2_tn_filter?
> +
> return ret;
> }
>
> @@ -7204,6 +7352,15 @@ ixgbe_dev_l2_tunnel_filter_del(struct rte_eth_dev
> *dev,
> struct rte_eth_l2_tunnel_conf *l2_tunnel) {
> int ret = 0;
> + struct ixgbe_l2_tn_info *l2_tn_info =
> + IXGBE_DEV_PRIVATE_TO_L2_TN_INFO(dev->data->dev_private);
> + struct ixgbe_l2_tn_key key;
> +
> + key.l2_tn_type = l2_tunnel->l2_tunnel_type;
> + key.tn_id = l2_tunnel->tunnel_id;
> + ret = ixgbe_remove_l2_tn_filter(l2_tn_info, &key);
> + if (ret < 0)
> + return ret;
>
> switch (l2_tunnel->l2_tunnel_type) {
> case RTE_L2_TUNNEL_TYPE_E_TAG:
> diff --git a/drivers/net/ixgbe/ixgbe_ethdev.h
> b/drivers/net/ixgbe/ixgbe_ethdev.h
> index 8310220..6663fc9 100644
> --- a/drivers/net/ixgbe/ixgbe_ethdev.h
> +++ b/drivers/net/ixgbe/ixgbe_ethdev.h
> @@ -132,6 +132,7 @@
> #define IXGBE_RX_VEC_START
> RTE_INTR_VEC_RXTX_OFFSET
>
> #define IXGBE_MAX_FDIR_FILTER_NUM (1024 * 32)
> +#define IXGBE_MAX_L2_TN_FILTER_NUM 128
>
> /*
> * Information about the fdir mode.
> @@ -283,6 +284,25 @@ struct ixgbe_filter_info {
> uint32_t syn_info;
> };
>
> +struct ixgbe_l2_tn_key {
> + enum rte_eth_tunnel_type l2_tn_type;
> + uint32_t tn_id;
> +};
> +
> +struct ixgbe_l2_tn_filter {
> + TAILQ_ENTRY(ixgbe_l2_tn_filter) entries;
> + struct ixgbe_l2_tn_key key;
> + uint32_t pool;
Maybe more comments here will be helpful.
> +};
> +
@@ -167,6 +167,7 @@ enum ixgbevf_xcast_modes {
static int eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev);
static int eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev);
static int ixgbe_fdir_filter_init(struct rte_eth_dev *eth_dev);
+static int ixgbe_l2_tn_filter_init(struct rte_eth_dev *eth_dev);
static int ixgbe_dev_configure(struct rte_eth_dev *dev);
static int ixgbe_dev_start(struct rte_eth_dev *dev);
static void ixgbe_dev_stop(struct rte_eth_dev *dev);
@@ -1281,6 +1282,8 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
/* initialize flow director filter list & hash */
ixgbe_fdir_filter_init(eth_dev);
+ /* initialize l2 tunnel filter list & hash */
+ ixgbe_l2_tn_filter_init(eth_dev);
return 0;
}
@@ -1291,7 +1294,10 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)
struct ixgbe_hw *hw;
struct ixgbe_hw_fdir_info *fdir_info =
IXGBE_DEV_PRIVATE_TO_FDIR_INFO(eth_dev->data->dev_private);
+ struct ixgbe_l2_tn_info *l2_tn_info =
+ IXGBE_DEV_PRIVATE_TO_L2_TN_INFO(eth_dev->data->dev_private);
struct ixgbe_fdir_filter *fdir_filter;
+ struct ixgbe_l2_tn_filter *l2_tn_filter;
PMD_INIT_FUNC_TRACE();
@@ -1338,6 +1344,19 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)
rte_free(fdir_filter);
}
+ /* remove all the L2 tunnel filters & hash */
+ if (l2_tn_info->hash_map)
+ rte_free(l2_tn_info->hash_map);
+ if (l2_tn_info->hash_handle)
+ rte_hash_free(l2_tn_info->hash_handle);
+
+ while ((l2_tn_filter = TAILQ_FIRST(&l2_tn_info->l2_tn_list))) {
+ TAILQ_REMOVE(&l2_tn_info->l2_tn_list,
+ l2_tn_filter,
+ entries);
+ rte_free(l2_tn_filter);
+ }
+
return 0;
}
@@ -1372,6 +1391,40 @@ static int ixgbe_fdir_filter_init(struct rte_eth_dev *eth_dev)
"Failed to allocate memory for fdir hash map!");
return -ENOMEM;
}
+ return 0;
+}
+
+static int ixgbe_l2_tn_filter_init(struct rte_eth_dev *eth_dev)
+{
+ struct ixgbe_l2_tn_info *l2_tn_info =
+ IXGBE_DEV_PRIVATE_TO_L2_TN_INFO(eth_dev->data->dev_private);
+ char l2_tn_hash_name[RTE_HASH_NAMESIZE];
+ struct rte_hash_parameters l2_tn_hash_params = {
+ .name = l2_tn_hash_name,
+ .entries = IXGBE_MAX_L2_TN_FILTER_NUM,
+ .key_len = sizeof(struct ixgbe_l2_tn_key),
+ .hash_func = rte_hash_crc,
+ .hash_func_init_val = 0,
+ .socket_id = rte_socket_id(),
+ };
+
+ TAILQ_INIT(&l2_tn_info->l2_tn_list);
+ snprintf(l2_tn_hash_name, RTE_HASH_NAMESIZE,
+ "l2_tn_%s", eth_dev->data->name);
+ l2_tn_info->hash_handle = rte_hash_create(&l2_tn_hash_params);
+ if (!l2_tn_info->hash_handle) {
+ PMD_INIT_LOG(ERR, "Failed to create L2 TN hash table!");
+ return -EINVAL;
+ }
+ l2_tn_info->hash_map = rte_zmalloc("ixgbe",
+ sizeof(struct ixgbe_l2_tn_filter *) *
+ IXGBE_MAX_L2_TN_FILTER_NUM,
+ 0);
+ if (!l2_tn_info->hash_map) {
+ PMD_INIT_LOG(ERR,
+ "Failed to allocate memory for L2 TN hash map!");
+ return -ENOMEM;
+ }
return 0;
}
@@ -7178,12 +7231,104 @@ ixgbe_e_tag_filter_add(struct rte_eth_dev *dev,
return -EINVAL;
}
+static inline struct ixgbe_l2_tn_filter *
+ixgbe_l2_tn_filter_lookup(struct ixgbe_l2_tn_info *l2_tn_info,
+ struct ixgbe_l2_tn_key *key)
+{
+ int ret = 0;
+
+ ret = rte_hash_lookup(l2_tn_info->hash_handle, (const void *)key);
+ if (ret < 0)
+ return NULL;
+
+ return l2_tn_info->hash_map[ret];
+}
+
+static inline int
+ixgbe_insert_l2_tn_filter(struct ixgbe_l2_tn_info *l2_tn_info,
+ struct ixgbe_l2_tn_filter *l2_tn_filter)
+{
+ int ret = 0;
+
+ ret = rte_hash_add_key(l2_tn_info->hash_handle,
+ &l2_tn_filter->key);
+
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR,
+ "Failed to insert L2 tunnel filter"
+ " to hash table %d!",
+ ret);
+ return ret;
+ }
+
+ l2_tn_info->hash_map[ret] = l2_tn_filter;
+
+ TAILQ_INSERT_TAIL(&l2_tn_info->l2_tn_list, l2_tn_filter, entries);
+
+ return 0;
+}
+
+static inline int
+ixgbe_remove_l2_tn_filter(struct ixgbe_l2_tn_info *l2_tn_info,
+ struct ixgbe_l2_tn_key *key)
+{
+ int ret = 0;
+ struct ixgbe_l2_tn_filter *l2_tn_filter;
+
+ ret = rte_hash_del_key(l2_tn_info->hash_handle, key);
+
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR,
+ "No such L2 tunnel filter to delete %d!",
+ ret);
+ return ret;
+ }
+
+ l2_tn_filter = l2_tn_info->hash_map[ret];
+ l2_tn_info->hash_map[ret] = NULL;
+
+ TAILQ_REMOVE(&l2_tn_info->l2_tn_list, l2_tn_filter, entries);
+ rte_free(l2_tn_filter);
+
+ return 0;
+}
+
/* Add l2 tunnel filter */
static int
ixgbe_dev_l2_tunnel_filter_add(struct rte_eth_dev *dev,
struct rte_eth_l2_tunnel_conf *l2_tunnel)
{
int ret = 0;
+ struct ixgbe_l2_tn_info *l2_tn_info =
+ IXGBE_DEV_PRIVATE_TO_L2_TN_INFO(dev->data->dev_private);
+ struct ixgbe_l2_tn_key key;
+ struct ixgbe_l2_tn_filter *node;
+
+ key.l2_tn_type = l2_tunnel->l2_tunnel_type;
+ key.tn_id = l2_tunnel->tunnel_id;
+
+ node = ixgbe_l2_tn_filter_lookup(l2_tn_info, &key);
+
+ if (node) {
+ PMD_DRV_LOG(ERR, "The L2 tunnel filter already exists!");
+ return -EINVAL;
+ }
+
+ node = rte_zmalloc("ixgbe_l2_tn",
+ sizeof(struct ixgbe_l2_tn_filter),
+ 0);
+ if (!node)
+ return -ENOMEM;
+
+ (void)rte_memcpy(&node->key,
+ &key,
+ sizeof(struct ixgbe_l2_tn_key));
+ node->pool = l2_tunnel->pool;
+ ret = ixgbe_insert_l2_tn_filter(l2_tn_info, node);
+ if (ret < 0) {
+ rte_free(node);
+ return ret;
+ }
switch (l2_tunnel->l2_tunnel_type) {
case RTE_L2_TUNNEL_TYPE_E_TAG:
@@ -7195,6 +7340,9 @@ ixgbe_dev_l2_tunnel_filter_add(struct rte_eth_dev *dev,
break;
}
+ if (ret < 0)
+ (void)ixgbe_remove_l2_tn_filter(l2_tn_info, &key);
+
return ret;
}
@@ -7204,6 +7352,15 @@ ixgbe_dev_l2_tunnel_filter_del(struct rte_eth_dev *dev,
struct rte_eth_l2_tunnel_conf *l2_tunnel)
{
int ret = 0;
+ struct ixgbe_l2_tn_info *l2_tn_info =
+ IXGBE_DEV_PRIVATE_TO_L2_TN_INFO(dev->data->dev_private);
+ struct ixgbe_l2_tn_key key;
+
+ key.l2_tn_type = l2_tunnel->l2_tunnel_type;
+ key.tn_id = l2_tunnel->tunnel_id;
+ ret = ixgbe_remove_l2_tn_filter(l2_tn_info, &key);
+ if (ret < 0)
+ return ret;
switch (l2_tunnel->l2_tunnel_type) {
case RTE_L2_TUNNEL_TYPE_E_TAG:
@@ -132,6 +132,7 @@
#define IXGBE_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET
#define IXGBE_MAX_FDIR_FILTER_NUM (1024 * 32)
+#define IXGBE_MAX_L2_TN_FILTER_NUM 128
/*
* Information about the fdir mode.
@@ -283,6 +284,25 @@ struct ixgbe_filter_info {
uint32_t syn_info;
};
+struct ixgbe_l2_tn_key {
+ enum rte_eth_tunnel_type l2_tn_type;
+ uint32_t tn_id;
+};
+
+struct ixgbe_l2_tn_filter {
+ TAILQ_ENTRY(ixgbe_l2_tn_filter) entries;
+ struct ixgbe_l2_tn_key key;
+ uint32_t pool;
+};
+
+TAILQ_HEAD(ixgbe_l2_tn_filter_list, ixgbe_l2_tn_filter);
+
+struct ixgbe_l2_tn_info {
+ struct ixgbe_l2_tn_filter_list l2_tn_list;
+ struct ixgbe_l2_tn_filter **hash_map;
+ struct rte_hash *hash_handle;
+};
+
/*
* Structure to store private data for each driver instance (for each port).
*/
@@ -302,6 +322,7 @@ struct ixgbe_adapter {
struct ixgbe_bypass_info bps;
#endif /* RTE_NIC_BYPASS */
struct ixgbe_filter_info filter;
+ struct ixgbe_l2_tn_info l2_tn;
bool rx_bulk_alloc_allowed;
bool rx_vec_allowed;
@@ -346,6 +367,9 @@ struct ixgbe_adapter {
#define IXGBE_DEV_PRIVATE_TO_FILTER_INFO(adapter) \
(&((struct ixgbe_adapter *)adapter)->filter)
+#define IXGBE_DEV_PRIVATE_TO_L2_TN_INFO(adapter) \
+ (&((struct ixgbe_adapter *)adapter)->l2_tn)
+
/*
* RX/TX function prototypes
*/