Skip to content

Commit 1217e69

Browse files
mark-blochkuba-moo
authored andcommitted
net/mlx5: fs, add support for no append at software level
Native capability for some steering engines lacks support for adding an additional match with the same value to the same flow group. To accommodate the NO APPEND flag in these scenarios, we include the new rule in the existing flow table entry (fte) without immediate hardware commitment. When a request is made to delete the corresponding hardware rule, we then commit the pending rule to hardware. Only one pending rule is supported because NO_APPEND is primarily used during replacement operations. In this scenario, a rule is initially added. When it needs replacement, the new rule is added with NO_APPEND set. Only after the insertion of the new rule is the original rule deleted. Signed-off-by: Mark Bloch <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]> Reviewed-by: Jacob Keller <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ef7b79b commit 1217e69

File tree

4 files changed

+242
-16
lines changed

4 files changed

+242
-16
lines changed

drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@ static int mlx5_cmd_create_match_definer(struct mlx5_flow_root_namespace *ns,
10711071
static u32 mlx5_cmd_get_capabilities(struct mlx5_flow_root_namespace *ns,
10721072
enum fs_flow_table_type ft_type)
10731073
{
1074-
return 0;
1074+
return MLX5_FLOW_STEERING_CAP_DUPLICATE_MATCH;
10751075
}
10761076

10771077
static const struct mlx5_flow_cmds mlx5_flow_cmds = {

drivers/net/ethernet/mellanox/mlx5/core/fs_core.c

Lines changed: 232 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,31 @@ static void modify_fte(struct fs_fte *fte)
613613
fte->act_dests.modify_mask = 0;
614614
}
615615

616+
static void del_sw_hw_dup_rule(struct fs_node *node)
617+
{
618+
struct mlx5_flow_rule *rule;
619+
struct fs_fte *fte;
620+
621+
fs_get_obj(rule, node);
622+
fs_get_obj(fte, rule->node.parent);
623+
trace_mlx5_fs_del_rule(rule);
624+
625+
if (is_fwd_next_action(rule->sw_action)) {
626+
mutex_lock(&rule->dest_attr.ft->lock);
627+
list_del(&rule->next_ft);
628+
mutex_unlock(&rule->dest_attr.ft->lock);
629+
}
630+
631+
/* If a pending rule is being deleted it means
632+
* this is a NO APPEND rule, so there are no partial deletions,
633+
* all the rules of the mlx5_flow_handle are going to be deleted
634+
* and the rules aren't shared with any other mlx5_flow_handle instance
635+
* so no need to do any bookkeeping like in del_sw_hw_rule().
636+
*/
637+
638+
kfree(rule);
639+
}
640+
616641
static void del_sw_hw_rule(struct fs_node *node)
617642
{
618643
struct mlx5_flow_rule *rule;
@@ -658,12 +683,33 @@ static void del_sw_hw_rule(struct fs_node *node)
658683
kfree(rule);
659684
}
660685

686+
static void switch_to_pending_act_dests(struct fs_fte *fte)
687+
{
688+
struct fs_node *iter;
689+
690+
memcpy(&fte->act_dests, &fte->dup->act_dests, sizeof(fte->act_dests));
691+
692+
list_bulk_move_tail(&fte->node.children,
693+
fte->dup->children.next,
694+
fte->dup->children.prev);
695+
696+
list_for_each_entry(iter, &fte->node.children, list)
697+
iter->del_sw_func = del_sw_hw_rule;
698+
699+
/* Make sure the fte isn't deleted
700+
* as mlx5_del_flow_rules() decreases the refcount
701+
* of the fte to trigger deletion.
702+
*/
703+
tree_get_node(&fte->node);
704+
}
705+
661706
static void del_hw_fte(struct fs_node *node)
662707
{
663708
struct mlx5_flow_root_namespace *root;
664709
struct mlx5_flow_table *ft;
665710
struct mlx5_flow_group *fg;
666711
struct mlx5_core_dev *dev;
712+
bool pending_used = false;
667713
struct fs_fte *fte;
668714
int err;
669715

@@ -675,16 +721,33 @@ static void del_hw_fte(struct fs_node *node)
675721
WARN_ON(fte->act_dests.dests_size);
676722
dev = get_dev(&ft->node);
677723
root = find_root(&ft->node);
724+
725+
if (fte->dup && !list_empty(&fte->dup->children)) {
726+
switch_to_pending_act_dests(fte);
727+
pending_used = true;
728+
} else {
729+
/* Avoid double call to del_hw_fte */
730+
node->del_hw_func = NULL;
731+
}
732+
678733
if (node->active) {
679-
err = root->cmds->delete_fte(root, ft, fte);
680-
if (err)
681-
mlx5_core_warn(dev,
682-
"flow steering can't delete fte in index %d of flow group id %d\n",
683-
fte->index, fg->id);
684-
node->active = false;
734+
if (pending_used) {
735+
err = root->cmds->update_fte(root, ft, fg,
736+
fte->act_dests.modify_mask, fte);
737+
if (err)
738+
mlx5_core_warn(dev,
739+
"flow steering can't update to pending rule in index %d of flow group id %d\n",
740+
fte->index, fg->id);
741+
fte->act_dests.modify_mask = 0;
742+
} else {
743+
err = root->cmds->delete_fte(root, ft, fte);
744+
if (err)
745+
mlx5_core_warn(dev,
746+
"flow steering can't delete fte in index %d of flow group id %d\n",
747+
fte->index, fg->id);
748+
node->active = false;
749+
}
685750
}
686-
/* Avoid double call to del_hw_fte */
687-
fte->node.del_hw_func = NULL;
688751
}
689752

690753
static void del_sw_fte(struct fs_node *node)
@@ -702,6 +765,7 @@ static void del_sw_fte(struct fs_node *node)
702765
rhash_fte);
703766
WARN_ON(err);
704767
ida_free(&fg->fte_allocator, fte->index - fg->start_index);
768+
kvfree(fte->dup);
705769
kmem_cache_free(steering->ftes_cache, fte);
706770
}
707771

@@ -1105,27 +1169,55 @@ static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio
11051169
return err;
11061170
}
11071171

1172+
static bool rule_is_pending(struct fs_fte *fte, struct mlx5_flow_rule *rule)
1173+
{
1174+
struct mlx5_flow_rule *tmp_rule;
1175+
struct fs_node *iter;
1176+
1177+
if (!fte->dup || list_empty(&fte->dup->children))
1178+
return false;
1179+
1180+
list_for_each_entry(iter, &fte->dup->children, list) {
1181+
tmp_rule = container_of(iter, struct mlx5_flow_rule, node);
1182+
1183+
if (tmp_rule == rule)
1184+
return true;
1185+
}
1186+
1187+
return false;
1188+
}
1189+
11081190
static int _mlx5_modify_rule_destination(struct mlx5_flow_rule *rule,
11091191
struct mlx5_flow_destination *dest)
11101192
{
11111193
struct mlx5_flow_root_namespace *root;
1194+
struct fs_fte_action *act_dests;
11121195
struct mlx5_flow_table *ft;
11131196
struct mlx5_flow_group *fg;
1197+
bool pending = false;
11141198
struct fs_fte *fte;
11151199
int modify_mask = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST);
11161200
int err = 0;
11171201

11181202
fs_get_obj(fte, rule->node.parent);
1119-
if (!(fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
1203+
1204+
pending = rule_is_pending(fte, rule);
1205+
if (pending)
1206+
act_dests = &fte->dup->act_dests;
1207+
else
1208+
act_dests = &fte->act_dests;
1209+
1210+
if (!(act_dests->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
11201211
return -EINVAL;
11211212
down_write_ref_node(&fte->node, false);
11221213
fs_get_obj(fg, fte->node.parent);
11231214
fs_get_obj(ft, fg->node.parent);
11241215

11251216
memcpy(&rule->dest_attr, dest, sizeof(*dest));
11261217
root = find_root(&ft->node);
1127-
err = root->cmds->update_fte(root, ft, fg,
1128-
modify_mask, fte);
1218+
if (!pending)
1219+
err = root->cmds->update_fte(root, ft, fg,
1220+
modify_mask, fte);
11291221
up_write_ref_node(&fte->node, false);
11301222

11311223
return err;
@@ -1455,6 +1547,16 @@ static struct mlx5_flow_handle *alloc_handle(int num_rules)
14551547
return handle;
14561548
}
14571549

1550+
static void destroy_flow_handle_dup(struct mlx5_flow_handle *handle,
1551+
int i)
1552+
{
1553+
for (; --i >= 0;) {
1554+
list_del(&handle->rule[i]->node.list);
1555+
kfree(handle->rule[i]);
1556+
}
1557+
kfree(handle);
1558+
}
1559+
14581560
static void destroy_flow_handle(struct fs_fte *fte,
14591561
struct mlx5_flow_handle *handle,
14601562
struct mlx5_flow_destination *dest,
@@ -1470,6 +1572,61 @@ static void destroy_flow_handle(struct fs_fte *fte,
14701572
kfree(handle);
14711573
}
14721574

1575+
static struct mlx5_flow_handle *
1576+
create_flow_handle_dup(struct list_head *children,
1577+
struct mlx5_flow_destination *dest,
1578+
int dest_num,
1579+
struct fs_fte_action *act_dests)
1580+
{
1581+
static int dst = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST);
1582+
static int count = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_FLOW_COUNTERS);
1583+
struct mlx5_flow_rule *rule = NULL;
1584+
struct mlx5_flow_handle *handle;
1585+
int i = 0;
1586+
int type;
1587+
1588+
handle = alloc_handle((dest_num) ? dest_num : 1);
1589+
if (!handle)
1590+
return NULL;
1591+
1592+
do {
1593+
rule = alloc_rule(dest + i);
1594+
if (!rule)
1595+
goto free_rules;
1596+
1597+
/* Add dest to dests list- we need flow tables to be in the
1598+
* end of the list for forward to next prio rules.
1599+
*/
1600+
tree_init_node(&rule->node, NULL, del_sw_hw_dup_rule);
1601+
if (dest &&
1602+
dest[i].type != MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE)
1603+
list_add(&rule->node.list, children);
1604+
else
1605+
list_add_tail(&rule->node.list, children);
1606+
1607+
if (dest) {
1608+
act_dests->dests_size++;
1609+
1610+
if (is_fwd_dest_type(dest[i].type))
1611+
act_dests->fwd_dests++;
1612+
1613+
type = dest[i].type ==
1614+
MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1615+
act_dests->modify_mask |= type ? count : dst;
1616+
}
1617+
handle->rule[i] = rule;
1618+
} while (++i < dest_num);
1619+
1620+
return handle;
1621+
1622+
free_rules:
1623+
destroy_flow_handle_dup(handle, i);
1624+
act_dests->dests_size = 0;
1625+
act_dests->fwd_dests = 0;
1626+
1627+
return NULL;
1628+
}
1629+
14731630
static struct mlx5_flow_handle *
14741631
create_flow_handle(struct fs_fte *fte,
14751632
struct mlx5_flow_destination *dest,
@@ -1963,6 +2120,62 @@ lookup_fte_locked(struct mlx5_flow_group *g,
19632120
return fte_tmp;
19642121
}
19652122

2123+
/* Native capability lacks support for adding an additional match with the same value
2124+
* to the same flow group. To accommodate the NO APPEND flag in these scenarios,
2125+
* we include the new rule in the existing flow table entry (fte) without immediate
2126+
* hardware commitment. When a request is made to delete the corresponding hardware rule,
2127+
* we then commit the pending rule to hardware.
2128+
*/
2129+
static struct mlx5_flow_handle *
2130+
add_rule_dup_match_fte(struct fs_fte *fte,
2131+
const struct mlx5_flow_spec *spec,
2132+
struct mlx5_flow_act *flow_act,
2133+
struct mlx5_flow_destination *dest,
2134+
int dest_num)
2135+
{
2136+
struct mlx5_flow_handle *handle;
2137+
struct fs_fte_dup *dup;
2138+
int i = 0;
2139+
2140+
if (!fte->dup) {
2141+
dup = kvzalloc(sizeof(*dup), GFP_KERNEL);
2142+
if (!dup)
2143+
return ERR_PTR(-ENOMEM);
2144+
/* dup will be freed when the fte is freed
2145+
* this way we don't allocate / free dup on every rule deletion
2146+
* or creation
2147+
*/
2148+
INIT_LIST_HEAD(&dup->children);
2149+
fte->dup = dup;
2150+
}
2151+
2152+
if (!list_empty(&fte->dup->children)) {
2153+
mlx5_core_warn(get_dev(&fte->node),
2154+
"Can have only a single duplicate rule\n");
2155+
2156+
return ERR_PTR(-EEXIST);
2157+
}
2158+
2159+
fte->dup->act_dests.action = *flow_act;
2160+
fte->dup->act_dests.flow_context = spec->flow_context;
2161+
fte->dup->act_dests.dests_size = 0;
2162+
fte->dup->act_dests.fwd_dests = 0;
2163+
fte->dup->act_dests.modify_mask = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_ACTION);
2164+
2165+
handle = create_flow_handle_dup(&fte->dup->children,
2166+
dest, dest_num,
2167+
&fte->dup->act_dests);
2168+
if (!handle)
2169+
return ERR_PTR(-ENOMEM);
2170+
2171+
for (i = 0; i < handle->num_rules; i++) {
2172+
tree_add_node(&handle->rule[i]->node, &fte->node);
2173+
trace_mlx5_fs_add_rule(handle->rule[i]);
2174+
}
2175+
2176+
return handle;
2177+
}
2178+
19662179
static struct mlx5_flow_handle *
19672180
try_add_to_existing_fg(struct mlx5_flow_table *ft,
19682181
struct list_head *match_head,
@@ -1973,6 +2186,7 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
19732186
int ft_version)
19742187
{
19752188
struct mlx5_flow_steering *steering = get_steering(&ft->node);
2189+
struct mlx5_flow_root_namespace *root = find_root(&ft->node);
19762190
struct mlx5_flow_group *g;
19772191
struct mlx5_flow_handle *rule;
19782192
struct match_list *iter;
@@ -1986,7 +2200,9 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
19862200
return ERR_PTR(-ENOMEM);
19872201

19882202
search_again_locked:
1989-
if (flow_act->flags & FLOW_ACT_NO_APPEND)
2203+
if (flow_act->flags & FLOW_ACT_NO_APPEND &&
2204+
(root->cmds->get_capabilities(root, root->table_type) &
2205+
MLX5_FLOW_STEERING_CAP_DUPLICATE_MATCH))
19902206
goto skip_search;
19912207
version = matched_fgs_get_version(match_head);
19922208
/* Try to find an fte with identical match value and attempt update its
@@ -1999,7 +2215,10 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
19992215
fte_tmp = lookup_fte_locked(g, spec->match_value, take_write);
20002216
if (!fte_tmp)
20012217
continue;
2002-
rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte_tmp);
2218+
if (flow_act->flags & FLOW_ACT_NO_APPEND)
2219+
rule = add_rule_dup_match_fte(fte_tmp, spec, flow_act, dest, dest_num);
2220+
else
2221+
rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte_tmp);
20032222
/* No error check needed here, because insert_fte() is not called */
20042223
up_write_ref_node(&fte_tmp->node, false);
20052224
tree_put_node(&fte_tmp->node, false);

drivers/net/ethernet/mellanox/mlx5/core/fs_core.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ enum mlx5_flow_steering_capabilty {
133133
MLX5_FLOW_STEERING_CAP_VLAN_PUSH_ON_RX = 1UL << 0,
134134
MLX5_FLOW_STEERING_CAP_VLAN_POP_ON_TX = 1UL << 1,
135135
MLX5_FLOW_STEERING_CAP_MATCH_RANGES = 1UL << 2,
136+
MLX5_FLOW_STEERING_CAP_DUPLICATE_MATCH = 1UL << 3,
136137
};
137138

138139
struct mlx5_flow_steering {
@@ -238,12 +239,18 @@ struct fs_fte_action {
238239
struct mlx5_flow_act action;
239240
};
240241

242+
struct fs_fte_dup {
243+
struct list_head children;
244+
struct fs_fte_action act_dests;
245+
};
246+
241247
/* Type of children is mlx5_flow_rule */
242248
struct fs_fte {
243249
struct fs_node node;
244250
struct mlx5_fs_dr_rule fs_dr_rule;
245251
u32 val[MLX5_ST_SZ_DW_MATCH_PARAM];
246252
struct fs_fte_action act_dests;
253+
struct fs_fte_dup *dup;
247254
u32 index;
248255
enum fs_fte_status status;
249256
struct rhash_head hash;

drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -813,11 +813,11 @@ static int mlx5_cmd_dr_destroy_ns(struct mlx5_flow_root_namespace *ns)
813813
static u32 mlx5_cmd_dr_get_capabilities(struct mlx5_flow_root_namespace *ns,
814814
enum fs_flow_table_type ft_type)
815815
{
816-
u32 steering_caps = 0;
816+
u32 steering_caps = MLX5_FLOW_STEERING_CAP_DUPLICATE_MATCH;
817817

818818
if (ft_type != FS_FT_FDB ||
819819
MLX5_CAP_GEN(ns->dev, steering_format_version) == MLX5_STEERING_FORMAT_CONNECTX_5)
820-
return 0;
820+
return steering_caps;
821821

822822
steering_caps |= MLX5_FLOW_STEERING_CAP_VLAN_PUSH_ON_RX;
823823
steering_caps |= MLX5_FLOW_STEERING_CAP_VLAN_POP_ON_TX;

0 commit comments

Comments
 (0)