Commit d30d8cde authored by Gal Pressman's avatar Gal Pressman Committed by Saeed Mahameed

net/mlx5e: Vxlan, replace ports radix-tree with hash table

The VXLAN database is accessed in the data path for each VXLAN TX skb in
order to check whether the UDP port is being offloaded or not.
The number of elements in the database is relatively small, we can
simplify the radix-tree to a hash table and speedup the lookup process.

Measuring mlx5e_vxlan_lookup_port execution time:

                  Radix Tree   Hash Table
 --------------- ------------ ------------
  Single Stream   161 ns       79  ns (51% improvement)
  Multi Stream    259 ns       136 ns (47% improvement)

Measuring UDP stream packet rate, single fully utilized TX core:
Radix Tree: 498,300 PPS
Hash Table: 555,468 PPS (11% improvement)
Signed-off-by: default avatarGal Pressman <galp@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 22a65aa8
...@@ -656,7 +656,8 @@ enum { ...@@ -656,7 +656,8 @@ enum {
struct mlx5e_vxlan_db { struct mlx5e_vxlan_db {
spinlock_t lock; /* protect vxlan table */ spinlock_t lock; /* protect vxlan table */
struct radix_tree_root tree; /* max_num_ports is usuallly 4, 16 buckets is more than enough */
DECLARE_HASHTABLE(htable, 4);
int num_ports; int num_ports;
}; };
......
...@@ -43,7 +43,7 @@ void mlx5e_vxlan_init(struct mlx5e_priv *priv) ...@@ -43,7 +43,7 @@ void mlx5e_vxlan_init(struct mlx5e_priv *priv)
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan; struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
spin_lock_init(&vxlan_db->lock); spin_lock_init(&vxlan_db->lock);
INIT_RADIX_TREE(&vxlan_db->tree, GFP_ATOMIC); hash_init(vxlan_db->htable);
if (mlx5e_vxlan_allowed(priv->mdev)) if (mlx5e_vxlan_allowed(priv->mdev))
/* Hardware adds 4789 by default. /* Hardware adds 4789 by default.
...@@ -79,13 +79,27 @@ static int mlx5e_vxlan_core_del_port_cmd(struct mlx5_core_dev *mdev, u16 port) ...@@ -79,13 +79,27 @@ static int mlx5e_vxlan_core_del_port_cmd(struct mlx5_core_dev *mdev, u16 port)
return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
} }
static struct mlx5e_vxlan *mlx5e_vxlan_lookup_port_locked(struct mlx5e_priv *priv,
u16 port)
{
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
struct mlx5e_vxlan *vxlan;
hash_for_each_possible(vxlan_db->htable, vxlan, hlist, port) {
if (vxlan->udp_port == port)
return vxlan;
}
return NULL;
}
struct mlx5e_vxlan *mlx5e_vxlan_lookup_port(struct mlx5e_priv *priv, u16 port) struct mlx5e_vxlan *mlx5e_vxlan_lookup_port(struct mlx5e_priv *priv, u16 port)
{ {
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan; struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
struct mlx5e_vxlan *vxlan; struct mlx5e_vxlan *vxlan;
spin_lock_bh(&vxlan_db->lock); spin_lock_bh(&vxlan_db->lock);
vxlan = radix_tree_lookup(&vxlan_db->tree, port); vxlan = mlx5e_vxlan_lookup_port_locked(priv, port);
spin_unlock_bh(&vxlan_db->lock); spin_unlock_bh(&vxlan_db->lock);
return vxlan; return vxlan;
...@@ -95,7 +109,6 @@ static void mlx5e_vxlan_add_port(struct mlx5e_priv *priv, u16 port) ...@@ -95,7 +109,6 @@ static void mlx5e_vxlan_add_port(struct mlx5e_priv *priv, u16 port)
{ {
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan; struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
struct mlx5e_vxlan *vxlan; struct mlx5e_vxlan *vxlan;
int err;
vxlan = mlx5e_vxlan_lookup_port(priv, port); vxlan = mlx5e_vxlan_lookup_port(priv, port);
if (vxlan) { if (vxlan) {
...@@ -121,16 +134,12 @@ static void mlx5e_vxlan_add_port(struct mlx5e_priv *priv, u16 port) ...@@ -121,16 +134,12 @@ static void mlx5e_vxlan_add_port(struct mlx5e_priv *priv, u16 port)
atomic_set(&vxlan->refcount, 1); atomic_set(&vxlan->refcount, 1);
spin_lock_bh(&vxlan_db->lock); spin_lock_bh(&vxlan_db->lock);
err = radix_tree_insert(&vxlan_db->tree, vxlan->udp_port, vxlan); hash_add(vxlan_db->htable, &vxlan->hlist, port);
spin_unlock_bh(&vxlan_db->lock); spin_unlock_bh(&vxlan_db->lock);
if (err)
goto err_free;
vxlan_db->num_ports++; vxlan_db->num_ports++;
return; return;
err_free:
kfree(vxlan);
err_delete_port: err_delete_port:
mlx5e_vxlan_core_del_port_cmd(priv->mdev, port); mlx5e_vxlan_core_del_port_cmd(priv->mdev, port);
} }
...@@ -161,12 +170,12 @@ static void mlx5e_vxlan_del_work(struct work_struct *work) ...@@ -161,12 +170,12 @@ static void mlx5e_vxlan_del_work(struct work_struct *work)
mutex_lock(&priv->state_lock); mutex_lock(&priv->state_lock);
spin_lock_bh(&vxlan_db->lock); spin_lock_bh(&vxlan_db->lock);
vxlan = radix_tree_lookup(&vxlan_db->tree, port); vxlan = mlx5e_vxlan_lookup_port_locked(priv, port);
if (!vxlan) if (!vxlan)
goto out_unlock; goto out_unlock;
if (atomic_dec_and_test(&vxlan->refcount)) { if (atomic_dec_and_test(&vxlan->refcount)) {
radix_tree_delete(&vxlan_db->tree, port); hash_del(&vxlan->hlist);
remove = true; remove = true;
} }
...@@ -206,13 +215,13 @@ void mlx5e_vxlan_cleanup(struct mlx5e_priv *priv) ...@@ -206,13 +215,13 @@ void mlx5e_vxlan_cleanup(struct mlx5e_priv *priv)
{ {
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan; struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
struct mlx5e_vxlan *vxlan; struct mlx5e_vxlan *vxlan;
unsigned int port = 0; struct hlist_node *tmp;
int bkt;
/* Lockless since we are the only radix-tree consumers, wq is disabled */ /* Lockless since we are the only hash table consumers, wq and TX are disabled */
while (radix_tree_gang_lookup(&vxlan_db->tree, (void **)&vxlan, port, 1)) { hash_for_each_safe(vxlan_db->htable, bkt, tmp, vxlan, hlist) {
port = vxlan->udp_port; hash_del(&vxlan->hlist);
radix_tree_delete(&vxlan_db->tree, port); mlx5e_vxlan_core_del_port_cmd(priv->mdev, vxlan->udp_port);
mlx5e_vxlan_core_del_port_cmd(priv->mdev, port);
kfree(vxlan); kfree(vxlan);
} }
} }
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "en.h" #include "en.h"
struct mlx5e_vxlan { struct mlx5e_vxlan {
struct hlist_node hlist;
atomic_t refcount; atomic_t refcount;
u16 udp_port; u16 udp_port;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment