net/mlx5: DR, Expose steering table functionality
Tables are objects which are used for storing matchers, each table belongs to a domain and defined by the domain type. When a packet reaches the table it is being processed by each of its matchers until a successful match. Tables can hold multiple matchers ordered by matcher priority. Each table has a level. Signed-off-by: Alex Vesker <valex@mellanox.com> Reviewed-by: Erez Shitrit <erezsh@mellanox.com> Reviewed-by: Mark Bloch <markb@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
This commit is contained in:
Родитель
4ec9e7b026
Коммит
7838e17253
|
@ -0,0 +1,294 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
/* Copyright (c) 2019 Mellanox Technologies. */
|
||||
|
||||
#include "dr_types.h"
|
||||
|
||||
int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl,
|
||||
struct mlx5dr_action *action)
|
||||
{
|
||||
struct mlx5dr_matcher *last_matcher = NULL;
|
||||
struct mlx5dr_htbl_connect_info info;
|
||||
struct mlx5dr_ste_htbl *last_htbl;
|
||||
int ret;
|
||||
|
||||
if (action && action->action_type != DR_ACTION_TYP_FT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&tbl->dmn->mutex);
|
||||
|
||||
if (!list_empty(&tbl->matcher_list))
|
||||
last_matcher = list_last_entry(&tbl->matcher_list,
|
||||
struct mlx5dr_matcher,
|
||||
matcher_list);
|
||||
|
||||
if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX ||
|
||||
tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) {
|
||||
if (last_matcher)
|
||||
last_htbl = last_matcher->rx.e_anchor;
|
||||
else
|
||||
last_htbl = tbl->rx.s_anchor;
|
||||
|
||||
tbl->rx.default_icm_addr = action ?
|
||||
action->dest_tbl.tbl->rx.s_anchor->chunk->icm_addr :
|
||||
tbl->rx.nic_dmn->default_icm_addr;
|
||||
|
||||
info.type = CONNECT_MISS;
|
||||
info.miss_icm_addr = tbl->rx.default_icm_addr;
|
||||
|
||||
ret = mlx5dr_ste_htbl_init_and_postsend(tbl->dmn,
|
||||
tbl->rx.nic_dmn,
|
||||
last_htbl,
|
||||
&info, true);
|
||||
if (ret) {
|
||||
mlx5dr_dbg(tbl->dmn, "Failed to set RX miss action, ret %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX ||
|
||||
tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) {
|
||||
if (last_matcher)
|
||||
last_htbl = last_matcher->tx.e_anchor;
|
||||
else
|
||||
last_htbl = tbl->tx.s_anchor;
|
||||
|
||||
tbl->tx.default_icm_addr = action ?
|
||||
action->dest_tbl.tbl->tx.s_anchor->chunk->icm_addr :
|
||||
tbl->tx.nic_dmn->default_icm_addr;
|
||||
|
||||
info.type = CONNECT_MISS;
|
||||
info.miss_icm_addr = tbl->tx.default_icm_addr;
|
||||
|
||||
ret = mlx5dr_ste_htbl_init_and_postsend(tbl->dmn,
|
||||
tbl->tx.nic_dmn,
|
||||
last_htbl, &info, true);
|
||||
if (ret) {
|
||||
mlx5dr_dbg(tbl->dmn, "Failed to set TX miss action, ret %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release old action */
|
||||
if (tbl->miss_action)
|
||||
refcount_dec(&tbl->miss_action->refcount);
|
||||
|
||||
/* Set new miss action */
|
||||
tbl->miss_action = action;
|
||||
if (tbl->miss_action)
|
||||
refcount_inc(&action->refcount);
|
||||
|
||||
out:
|
||||
mutex_unlock(&tbl->dmn->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dr_table_uninit_nic(struct mlx5dr_table_rx_tx *nic_tbl)
|
||||
{
|
||||
mlx5dr_htbl_put(nic_tbl->s_anchor);
|
||||
}
|
||||
|
||||
static void dr_table_uninit_fdb(struct mlx5dr_table *tbl)
|
||||
{
|
||||
dr_table_uninit_nic(&tbl->rx);
|
||||
dr_table_uninit_nic(&tbl->tx);
|
||||
}
|
||||
|
||||
static void dr_table_uninit(struct mlx5dr_table *tbl)
|
||||
{
|
||||
mutex_lock(&tbl->dmn->mutex);
|
||||
|
||||
switch (tbl->dmn->type) {
|
||||
case MLX5DR_DOMAIN_TYPE_NIC_RX:
|
||||
dr_table_uninit_nic(&tbl->rx);
|
||||
break;
|
||||
case MLX5DR_DOMAIN_TYPE_NIC_TX:
|
||||
dr_table_uninit_nic(&tbl->tx);
|
||||
break;
|
||||
case MLX5DR_DOMAIN_TYPE_FDB:
|
||||
dr_table_uninit_fdb(tbl);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(true);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&tbl->dmn->mutex);
|
||||
}
|
||||
|
||||
static int dr_table_init_nic(struct mlx5dr_domain *dmn,
|
||||
struct mlx5dr_table_rx_tx *nic_tbl)
|
||||
{
|
||||
struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
|
||||
struct mlx5dr_htbl_connect_info info;
|
||||
int ret;
|
||||
|
||||
nic_tbl->default_icm_addr = nic_dmn->default_icm_addr;
|
||||
|
||||
nic_tbl->s_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
|
||||
DR_CHUNK_SIZE_1,
|
||||
MLX5DR_STE_LU_TYPE_DONT_CARE,
|
||||
0);
|
||||
if (!nic_tbl->s_anchor)
|
||||
return -ENOMEM;
|
||||
|
||||
info.type = CONNECT_MISS;
|
||||
info.miss_icm_addr = nic_dmn->default_icm_addr;
|
||||
ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
|
||||
nic_tbl->s_anchor,
|
||||
&info, true);
|
||||
if (ret)
|
||||
goto free_s_anchor;
|
||||
|
||||
mlx5dr_htbl_get(nic_tbl->s_anchor);
|
||||
|
||||
return 0;
|
||||
|
||||
free_s_anchor:
|
||||
mlx5dr_ste_htbl_free(nic_tbl->s_anchor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dr_table_init_fdb(struct mlx5dr_table *tbl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dr_table_init_nic(tbl->dmn, &tbl->rx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dr_table_init_nic(tbl->dmn, &tbl->tx);
|
||||
if (ret)
|
||||
goto destroy_rx;
|
||||
|
||||
return 0;
|
||||
|
||||
destroy_rx:
|
||||
dr_table_uninit_nic(&tbl->rx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dr_table_init(struct mlx5dr_table *tbl)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
INIT_LIST_HEAD(&tbl->matcher_list);
|
||||
|
||||
mutex_lock(&tbl->dmn->mutex);
|
||||
|
||||
switch (tbl->dmn->type) {
|
||||
case MLX5DR_DOMAIN_TYPE_NIC_RX:
|
||||
tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_RX;
|
||||
tbl->rx.nic_dmn = &tbl->dmn->info.rx;
|
||||
ret = dr_table_init_nic(tbl->dmn, &tbl->rx);
|
||||
break;
|
||||
case MLX5DR_DOMAIN_TYPE_NIC_TX:
|
||||
tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_TX;
|
||||
tbl->tx.nic_dmn = &tbl->dmn->info.tx;
|
||||
ret = dr_table_init_nic(tbl->dmn, &tbl->tx);
|
||||
break;
|
||||
case MLX5DR_DOMAIN_TYPE_FDB:
|
||||
tbl->table_type = MLX5_FLOW_TABLE_TYPE_FDB;
|
||||
tbl->rx.nic_dmn = &tbl->dmn->info.rx;
|
||||
tbl->tx.nic_dmn = &tbl->dmn->info.tx;
|
||||
ret = dr_table_init_fdb(tbl);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(true);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&tbl->dmn->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dr_table_destroy_sw_owned_tbl(struct mlx5dr_table *tbl)
|
||||
{
|
||||
return mlx5dr_cmd_destroy_flow_table(tbl->dmn->mdev,
|
||||
tbl->table_id,
|
||||
tbl->table_type);
|
||||
}
|
||||
|
||||
static int dr_table_create_sw_owned_tbl(struct mlx5dr_table *tbl)
|
||||
{
|
||||
u64 icm_addr_rx = 0;
|
||||
u64 icm_addr_tx = 0;
|
||||
int ret;
|
||||
|
||||
if (tbl->rx.s_anchor)
|
||||
icm_addr_rx = tbl->rx.s_anchor->chunk->icm_addr;
|
||||
|
||||
if (tbl->tx.s_anchor)
|
||||
icm_addr_tx = tbl->tx.s_anchor->chunk->icm_addr;
|
||||
|
||||
ret = mlx5dr_cmd_create_flow_table(tbl->dmn->mdev,
|
||||
tbl->table_type,
|
||||
icm_addr_rx,
|
||||
icm_addr_tx,
|
||||
tbl->dmn->info.caps.max_ft_level - 1,
|
||||
true, false, NULL,
|
||||
&tbl->table_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_domain *dmn, u32 level)
|
||||
{
|
||||
struct mlx5dr_table *tbl;
|
||||
int ret;
|
||||
|
||||
refcount_inc(&dmn->refcount);
|
||||
|
||||
tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
|
||||
if (!tbl)
|
||||
goto dec_ref;
|
||||
|
||||
tbl->dmn = dmn;
|
||||
tbl->level = level;
|
||||
refcount_set(&tbl->refcount, 1);
|
||||
|
||||
ret = dr_table_init(tbl);
|
||||
if (ret)
|
||||
goto free_tbl;
|
||||
|
||||
ret = dr_table_create_sw_owned_tbl(tbl);
|
||||
if (ret)
|
||||
goto uninit_tbl;
|
||||
|
||||
return tbl;
|
||||
|
||||
uninit_tbl:
|
||||
dr_table_uninit(tbl);
|
||||
free_tbl:
|
||||
kfree(tbl);
|
||||
dec_ref:
|
||||
refcount_dec(&dmn->refcount);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mlx5dr_table_destroy(struct mlx5dr_table *tbl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (refcount_read(&tbl->refcount) > 1)
|
||||
return -EBUSY;
|
||||
|
||||
ret = dr_table_destroy_sw_owned_tbl(tbl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dr_table_uninit(tbl);
|
||||
|
||||
if (tbl->miss_action)
|
||||
refcount_dec(&tbl->miss_action->refcount);
|
||||
|
||||
refcount_dec(&tbl->dmn->refcount);
|
||||
kfree(tbl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 mlx5dr_table_get_id(struct mlx5dr_table *tbl)
|
||||
{
|
||||
return tbl->table_id;
|
||||
}
|
Загрузка…
Ссылка в новой задаче