Skip to content

Commit b3638e1

Browse files
Maor Gottliebdledford
authored andcommitted
net/mlx5_core: Introduce forward to next priority action
Add support to create flow rule that forward packets to the first flow table in the next priority (next priority could be the first priority in the next namespace or the next priority in the same namespace). This feature could be used for DONT_TRAP rules or rules that only want to mark the packet with flow tag. In order to do it optimally, each flow table has list of all rules that point to this flow table, when a flow table is destroyed/created, we update the list head correspondingly. This kind of rule is created when destination is NULL and action is MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO. Signed-off-by: Maor Gottlieb <[email protected]> Reviewed-by: Matan Barak <[email protected]> Signed-off-by: Doug Ledford <[email protected]>
1 parent 153fefb commit b3638e1

File tree

4 files changed

+188
-13
lines changed

4 files changed

+188
-13
lines changed

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

Lines changed: 173 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,10 @@ static void tree_put_node(struct fs_node *node)
201201

202202
static int tree_remove_node(struct fs_node *node)
203203
{
204-
if (atomic_read(&node->refcount) > 1)
205-
return -EPERM;
204+
if (atomic_read(&node->refcount) > 1) {
205+
atomic_dec(&node->refcount);
206+
return -EEXIST;
207+
}
206208
tree_put_node(node);
207209
return 0;
208210
}
@@ -365,6 +367,11 @@ static void del_rule(struct fs_node *node)
365367
memcpy(match_value, fte->val, sizeof(fte->val));
366368
fs_get_obj(ft, fg->node.parent);
367369
list_del(&rule->node.list);
370+
if (rule->sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) {
371+
mutex_lock(&rule->dest_attr.ft->lock);
372+
list_del(&rule->next_ft);
373+
mutex_unlock(&rule->dest_attr.ft->lock);
374+
}
368375
fte->dests_size--;
369376
if (fte->dests_size) {
370377
err = mlx5_cmd_update_fte(dev, ft,
@@ -470,6 +477,8 @@ static struct mlx5_flow_table *alloc_flow_table(int level, int max_fte,
470477
ft->node.type = FS_TYPE_FLOW_TABLE;
471478
ft->type = table_type;
472479
ft->max_fte = max_fte;
480+
INIT_LIST_HEAD(&ft->fwd_rules);
481+
mutex_init(&ft->lock);
473482

474483
return ft;
475484
}
@@ -606,9 +615,63 @@ static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio
606615
return err;
607616
}
608617

618+
static int mlx5_modify_rule_destination(struct mlx5_flow_rule *rule,
619+
struct mlx5_flow_destination *dest)
620+
{
621+
struct mlx5_flow_table *ft;
622+
struct mlx5_flow_group *fg;
623+
struct fs_fte *fte;
624+
int err = 0;
625+
626+
fs_get_obj(fte, rule->node.parent);
627+
if (!(fte->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
628+
return -EINVAL;
629+
lock_ref_node(&fte->node);
630+
fs_get_obj(fg, fte->node.parent);
631+
fs_get_obj(ft, fg->node.parent);
632+
633+
memcpy(&rule->dest_attr, dest, sizeof(*dest));
634+
err = mlx5_cmd_update_fte(get_dev(&ft->node),
635+
ft, fg->id, fte);
636+
unlock_ref_node(&fte->node);
637+
638+
return err;
639+
}
640+
641+
/* Modify/set FWD rules that point on old_next_ft to point on new_next_ft */
642+
static int connect_fwd_rules(struct mlx5_core_dev *dev,
643+
struct mlx5_flow_table *new_next_ft,
644+
struct mlx5_flow_table *old_next_ft)
645+
{
646+
struct mlx5_flow_destination dest;
647+
struct mlx5_flow_rule *iter;
648+
int err = 0;
649+
650+
/* new_next_ft and old_next_ft could be NULL only
651+
* when we create/destroy the anchor flow table.
652+
*/
653+
if (!new_next_ft || !old_next_ft)
654+
return 0;
655+
656+
dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
657+
dest.ft = new_next_ft;
658+
659+
mutex_lock(&old_next_ft->lock);
660+
list_splice_init(&old_next_ft->fwd_rules, &new_next_ft->fwd_rules);
661+
mutex_unlock(&old_next_ft->lock);
662+
list_for_each_entry(iter, &new_next_ft->fwd_rules, next_ft) {
663+
err = mlx5_modify_rule_destination(iter, &dest);
664+
if (err)
665+
pr_err("mlx5_core: failed to modify rule to point on flow table %d\n",
666+
new_next_ft->id);
667+
}
668+
return 0;
669+
}
670+
609671
static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table *ft,
610672
struct fs_prio *prio)
611673
{
674+
struct mlx5_flow_table *next_ft;
612675
int err = 0;
613676

614677
/* Connect_prev_fts and update_root_ft_create are mutually exclusive */
@@ -617,6 +680,11 @@ static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table
617680
err = connect_prev_fts(dev, ft, prio);
618681
if (err)
619682
return err;
683+
684+
next_ft = find_next_chained_ft(prio);
685+
err = connect_fwd_rules(dev, ft, next_ft);
686+
if (err)
687+
return err;
620688
}
621689

622690
if (MLX5_CAP_FLOWTABLE(dev,
@@ -767,6 +835,7 @@ static struct mlx5_flow_rule *alloc_rule(struct mlx5_flow_destination *dest)
767835
if (!rule)
768836
return NULL;
769837

838+
INIT_LIST_HEAD(&rule->next_ft);
770839
rule->node.type = FS_TYPE_FLOW_DEST;
771840
memcpy(&rule->dest_attr, dest, sizeof(*dest));
772841

@@ -787,9 +856,14 @@ static struct mlx5_flow_rule *add_rule_fte(struct fs_fte *fte,
787856
return ERR_PTR(-ENOMEM);
788857

789858
fs_get_obj(ft, fg->node.parent);
790-
/* Add dest to dests list- added as first element after the head */
859+
/* Add dest to dests list- we need flow tables to be in the
860+
* end of the list for forward to next prio rules.
861+
*/
791862
tree_init_node(&rule->node, 1, del_rule);
792-
list_add_tail(&rule->node.list, &fte->node.children);
863+
if (dest && dest->type != MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE)
864+
list_add(&rule->node.list, &fte->node.children);
865+
else
866+
list_add_tail(&rule->node.list, &fte->node.children);
793867
fte->dests_size++;
794868
if (fte->dests_size == 1)
795869
err = mlx5_cmd_create_fte(get_dev(&ft->node),
@@ -908,6 +982,25 @@ static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft,
908982
return fg;
909983
}
910984

985+
static struct mlx5_flow_rule *find_flow_rule(struct fs_fte *fte,
986+
struct mlx5_flow_destination *dest)
987+
{
988+
struct mlx5_flow_rule *rule;
989+
990+
list_for_each_entry(rule, &fte->node.children, node.list) {
991+
if (rule->dest_attr.type == dest->type) {
992+
if ((dest->type == MLX5_FLOW_DESTINATION_TYPE_VPORT &&
993+
dest->vport_num == rule->dest_attr.vport_num) ||
994+
(dest->type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE &&
995+
dest->ft == rule->dest_attr.ft) ||
996+
(dest->type == MLX5_FLOW_DESTINATION_TYPE_TIR &&
997+
dest->tir_num == rule->dest_attr.tir_num))
998+
return rule;
999+
}
1000+
}
1001+
return NULL;
1002+
}
1003+
9111004
static struct mlx5_flow_rule *add_rule_fg(struct mlx5_flow_group *fg,
9121005
u32 *match_value,
9131006
u8 action,
@@ -924,6 +1017,13 @@ static struct mlx5_flow_rule *add_rule_fg(struct mlx5_flow_group *fg,
9241017
nested_lock_ref_node(&fte->node, FS_MUTEX_CHILD);
9251018
if (compare_match_value(&fg->mask, match_value, &fte->val) &&
9261019
action == fte->action && flow_tag == fte->flow_tag) {
1020+
rule = find_flow_rule(fte, dest);
1021+
if (rule) {
1022+
atomic_inc(&rule->node.refcount);
1023+
unlock_ref_node(&fte->node);
1024+
unlock_ref_node(&fg->node);
1025+
return rule;
1026+
}
9271027
rule = add_rule_fte(fte, fg, dest);
9281028
unlock_ref_node(&fte->node);
9291029
if (IS_ERR(rule))
@@ -989,14 +1089,14 @@ static struct mlx5_flow_rule *add_rule_to_auto_fg(struct mlx5_flow_table *ft,
9891089
return rule;
9901090
}
9911091

992-
struct mlx5_flow_rule *
993-
mlx5_add_flow_rule(struct mlx5_flow_table *ft,
994-
u8 match_criteria_enable,
995-
u32 *match_criteria,
996-
u32 *match_value,
997-
u32 action,
998-
u32 flow_tag,
999-
struct mlx5_flow_destination *dest)
1092+
static struct mlx5_flow_rule *
1093+
_mlx5_add_flow_rule(struct mlx5_flow_table *ft,
1094+
u8 match_criteria_enable,
1095+
u32 *match_criteria,
1096+
u32 *match_value,
1097+
u32 action,
1098+
u32 flow_tag,
1099+
struct mlx5_flow_destination *dest)
10001100
{
10011101
struct mlx5_flow_group *g;
10021102
struct mlx5_flow_rule *rule;
@@ -1019,6 +1119,63 @@ mlx5_add_flow_rule(struct mlx5_flow_table *ft,
10191119
unlock_ref_node(&ft->node);
10201120
return rule;
10211121
}
1122+
1123+
static bool fwd_next_prio_supported(struct mlx5_flow_table *ft)
1124+
{
1125+
return ((ft->type == FS_FT_NIC_RX) &&
1126+
(MLX5_CAP_FLOWTABLE(get_dev(&ft->node), nic_rx_multi_path_tirs)));
1127+
}
1128+
1129+
struct mlx5_flow_rule *
1130+
mlx5_add_flow_rule(struct mlx5_flow_table *ft,
1131+
u8 match_criteria_enable,
1132+
u32 *match_criteria,
1133+
u32 *match_value,
1134+
u32 action,
1135+
u32 flow_tag,
1136+
struct mlx5_flow_destination *dest)
1137+
{
1138+
struct mlx5_flow_root_namespace *root = find_root(&ft->node);
1139+
struct mlx5_flow_destination gen_dest;
1140+
struct mlx5_flow_table *next_ft = NULL;
1141+
struct mlx5_flow_rule *rule = NULL;
1142+
u32 sw_action = action;
1143+
struct fs_prio *prio;
1144+
1145+
fs_get_obj(prio, ft->node.parent);
1146+
if (action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) {
1147+
if (!fwd_next_prio_supported(ft))
1148+
return ERR_PTR(-EOPNOTSUPP);
1149+
if (dest)
1150+
return ERR_PTR(-EINVAL);
1151+
mutex_lock(&root->chain_lock);
1152+
next_ft = find_next_chained_ft(prio);
1153+
if (next_ft) {
1154+
gen_dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1155+
gen_dest.ft = next_ft;
1156+
dest = &gen_dest;
1157+
action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1158+
} else {
1159+
mutex_unlock(&root->chain_lock);
1160+
return ERR_PTR(-EOPNOTSUPP);
1161+
}
1162+
}
1163+
1164+
rule = _mlx5_add_flow_rule(ft, match_criteria_enable, match_criteria,
1165+
match_value, action, flow_tag, dest);
1166+
1167+
if (sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) {
1168+
if (!IS_ERR_OR_NULL(rule) &&
1169+
(list_empty(&rule->next_ft))) {
1170+
mutex_lock(&next_ft->lock);
1171+
list_add(&rule->next_ft, &next_ft->fwd_rules);
1172+
mutex_unlock(&next_ft->lock);
1173+
rule->sw_action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
1174+
}
1175+
mutex_unlock(&root->chain_lock);
1176+
}
1177+
return rule;
1178+
}
10221179
EXPORT_SYMBOL(mlx5_add_flow_rule);
10231180

10241181
void mlx5_del_flow_rule(struct mlx5_flow_rule *rule)
@@ -1082,6 +1239,10 @@ static int disconnect_flow_table(struct mlx5_flow_table *ft)
10821239
return 0;
10831240

10841241
next_ft = find_next_chained_ft(prio);
1242+
err = connect_fwd_rules(dev, next_ft, ft);
1243+
if (err)
1244+
return err;
1245+
10851246
err = connect_prev_fts(dev, next_ft, prio);
10861247
if (err)
10871248
mlx5_core_warn(dev, "Failed to disconnect flow table %d\n",

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ struct fs_node {
6868
struct mlx5_flow_rule {
6969
struct fs_node node;
7070
struct mlx5_flow_destination dest_attr;
71+
/* next_ft should be accessed under chain_lock and only of
72+
* destination type is FWD_NEXT_fT.
73+
*/
74+
struct list_head next_ft;
75+
u32 sw_action;
7176
};
7277

7378
/* Type of children is mlx5_flow_group */
@@ -82,6 +87,10 @@ struct mlx5_flow_table {
8287
unsigned int required_groups;
8388
unsigned int num_groups;
8489
} autogroup;
90+
/* Protect fwd_rules */
91+
struct mutex lock;
92+
/* FWD rules that point on this flow table */
93+
struct list_head fwd_rules;
8594
};
8695

8796
/* Type of children is mlx5_flow_rule */

include/linux/mlx5/fs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838

3939
#define MLX5_FS_DEFAULT_FLOW_TAG 0x0
4040

41+
enum {
42+
MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO = 1 << 16,
43+
};
44+
4145
#define LEFTOVERS_RULE_NUM 2
4246
static inline void build_leftovers_ft_param(int *priority,
4347
int *n_ent,

include/linux/mlx5/mlx5_ifc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,8 @@ struct mlx5_ifc_ads_bits {
458458
};
459459

460460
struct mlx5_ifc_flow_table_nic_cap_bits {
461-
u8 reserved_at_0[0x200];
461+
u8 nic_rx_multi_path_tirs[0x1];
462+
u8 reserved_at_1[0x1ff];
462463

463464
struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_receive;
464465

0 commit comments

Comments
 (0)