Skip to content

Commit

Permalink
net/mlx5e: Add cache for HW modify header IDs
Browse files Browse the repository at this point in the history
Packets belonging to flows which are different by matching may still need
to go through the same header re-write. Add a cache for header re-write IDs
keyed by the binary chain of modify header actions.

The caching is supported for both eswitch and NIC use-cases, where the
actual conversion of the code to use caching comes in next patches, one
per use-case.

Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Reviewed-by: Paul Blakey <paulb@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
  • Loading branch information
Or Gerlitz authored and Saeed Mahameed committed Jun 8, 2017
1 parent 513f8f7 commit 11c9c54
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 1 deletion.
2 changes: 2 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en.h
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,8 @@ struct mlx5e_tc_table {

struct rhashtable_params ht_params;
struct rhashtable ht;

DECLARE_HASHTABLE(mod_hdr_tbl, 8);
};

struct mlx5e_vlan_table {
Expand Down
134 changes: 133 additions & 1 deletion drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ struct mlx5e_tc_flow {
u64 cookie;
u8 flags;
struct mlx5_flow_handle *rule;
struct list_head encap; /* flows sharing the same encap */
struct list_head encap; /* flows sharing the same encap ID */
struct list_head mod_hdr; /* flows sharing the same mod hdr ID */
union {
struct mlx5_esw_flow_attr esw_attr[0];
struct mlx5_nic_flow_attr nic_attr[0];
Expand All @@ -90,6 +91,135 @@ enum {
#define MLX5E_TC_TABLE_NUM_ENTRIES 1024
#define MLX5E_TC_TABLE_NUM_GROUPS 4

struct mod_hdr_key {
int num_actions;
void *actions;
};

struct mlx5e_mod_hdr_entry {
/* a node of a hash table which keeps all the mod_hdr entries */
struct hlist_node mod_hdr_hlist;

/* flows sharing the same mod_hdr entry */
struct list_head flows;

struct mod_hdr_key key;

u32 mod_hdr_id;
};

#define MLX5_MH_ACT_SZ MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)

static inline u32 hash_mod_hdr_info(struct mod_hdr_key *key)
{
return jhash(key->actions,
key->num_actions * MLX5_MH_ACT_SZ, 0);
}

static inline int cmp_mod_hdr_info(struct mod_hdr_key *a,
struct mod_hdr_key *b)
{
if (a->num_actions != b->num_actions)
return 1;

return memcmp(a->actions, b->actions, a->num_actions * MLX5_MH_ACT_SZ);
}

static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow,
struct mlx5e_tc_flow_parse_attr *parse_attr)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
int num_actions, actions_size, namespace, err;
struct mlx5e_mod_hdr_entry *mh;
struct mod_hdr_key key;
bool found = false;
u32 hash_key;

num_actions = parse_attr->num_mod_hdr_actions;
actions_size = MLX5_MH_ACT_SZ * num_actions;

key.actions = parse_attr->mod_hdr_actions;
key.num_actions = num_actions;

hash_key = hash_mod_hdr_info(&key);

if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
namespace = MLX5_FLOW_NAMESPACE_FDB;
hash_for_each_possible(esw->offloads.mod_hdr_tbl, mh,
mod_hdr_hlist, hash_key) {
if (!cmp_mod_hdr_info(&mh->key, &key)) {
found = true;
break;
}
}
} else {
namespace = MLX5_FLOW_NAMESPACE_KERNEL;
hash_for_each_possible(priv->fs.tc.mod_hdr_tbl, mh,
mod_hdr_hlist, hash_key) {
if (!cmp_mod_hdr_info(&mh->key, &key)) {
found = true;
break;
}
}
}

if (found)
goto attach_flow;

mh = kzalloc(sizeof(*mh) + actions_size, GFP_KERNEL);
if (!mh)
return -ENOMEM;

mh->key.actions = (void *)mh + sizeof(*mh);
memcpy(mh->key.actions, key.actions, actions_size);
mh->key.num_actions = num_actions;
INIT_LIST_HEAD(&mh->flows);

err = mlx5_modify_header_alloc(priv->mdev, namespace,
mh->key.num_actions,
mh->key.actions,
&mh->mod_hdr_id);
if (err)
goto out_err;

if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
hash_add(esw->offloads.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key);
else
hash_add(priv->fs.tc.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key);

attach_flow:
list_add(&flow->mod_hdr, &mh->flows);
if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
flow->esw_attr->mod_hdr_id = mh->mod_hdr_id;
else
flow->nic_attr->mod_hdr_id = mh->mod_hdr_id;

return 0;

out_err:
kfree(mh);
return err;
}

static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow)
{
struct list_head *next = flow->mod_hdr.next;

list_del(&flow->mod_hdr);

if (list_empty(next)) {
struct mlx5e_mod_hdr_entry *mh;

mh = list_entry(next, struct mlx5e_mod_hdr_entry, flows);

mlx5_modify_header_dealloc(priv->mdev, mh->mod_hdr_id);
hash_del(&mh->mod_hdr_hlist);
kfree(mh);
}
}

static struct mlx5_flow_handle *
mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow_parse_attr *parse_attr,
Expand Down Expand Up @@ -1939,6 +2069,8 @@ int mlx5e_tc_init(struct mlx5e_priv *priv)
{
struct mlx5e_tc_table *tc = &priv->fs.tc;

hash_init(tc->mod_hdr_tbl);

tc->ht_params = mlx5e_tc_flow_ht_params;
return rhashtable_init(&tc->ht, &tc->ht_params);
}
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
Original file line number Diff line number Diff line change
Expand Up @@ -1769,6 +1769,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
}

hash_init(esw->offloads.encap_tbl);
hash_init(esw->offloads.mod_hdr_tbl);
mutex_init(&esw->state_lock);

for (vport_num = 0; vport_num < total_vports; vport_num++) {
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ struct mlx5_esw_offload {
struct mlx5_flow_group *vport_rx_group;
struct mlx5_eswitch_rep *vport_reps;
DECLARE_HASHTABLE(encap_tbl, 8);
DECLARE_HASHTABLE(mod_hdr_tbl, 8);
u8 inline_mode;
u64 num_flows;
u8 encap;
Expand Down

0 comments on commit 11c9c54

Please sign in to comment.