Skip to content

Commit 249ccc3

Browse files
Eli CohenSaeed Mahameed
authored andcommitted
net/mlx5e: Add support for offloading traffic from uplink to uplink
Termination tables change the direction of a packet in hw from RX to SX pipeline. Use that to offload hairpin flows received from uplink and sent back to uplink. Currently termination tables are used for pushing VLAN to packets received from uplink and targeting a VF. Extend the implementation to allow forwarding packets to uplink. These packets can either be encapsulated or not. In case encapsulation is needed before forwarding, move the reformat object to the termination table as required. Extend the hash table key to include tunnel information for the sake of reusing reformat objects. Signed-off-by: Eli Cohen <[email protected]> Reviewed-by: Oz Shlomo <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent d8a2034 commit 249ccc3

File tree

1 file changed

+70
-27
lines changed

1 file changed

+70
-27
lines changed

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

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <linux/mlx5/fs.h>
55
#include "eswitch.h"
6+
#include "fs_core.h"
67

78
struct mlx5_termtbl_handle {
89
struct hlist_node termtbl_hlist;
@@ -28,6 +29,10 @@ mlx5_eswitch_termtbl_hash(struct mlx5_flow_act *flow_act,
2829
sizeof(dest->vport.num), hash);
2930
hash = jhash((const void *)&dest->vport.vhca_id,
3031
sizeof(dest->vport.num), hash);
32+
if (dest->vport.pkt_reformat)
33+
hash = jhash(dest->vport.pkt_reformat,
34+
sizeof(*dest->vport.pkt_reformat),
35+
hash);
3136
return hash;
3237
}
3338

@@ -37,11 +42,19 @@ mlx5_eswitch_termtbl_cmp(struct mlx5_flow_act *flow_act1,
3742
struct mlx5_flow_act *flow_act2,
3843
struct mlx5_flow_destination *dest2)
3944
{
40-
return flow_act1->action != flow_act2->action ||
41-
dest1->vport.num != dest2->vport.num ||
42-
dest1->vport.vhca_id != dest2->vport.vhca_id ||
43-
memcmp(&flow_act1->vlan, &flow_act2->vlan,
44-
sizeof(flow_act1->vlan));
45+
int ret;
46+
47+
ret = flow_act1->action != flow_act2->action ||
48+
dest1->vport.num != dest2->vport.num ||
49+
dest1->vport.vhca_id != dest2->vport.vhca_id ||
50+
memcmp(&flow_act1->vlan, &flow_act2->vlan,
51+
sizeof(flow_act1->vlan));
52+
if (ret)
53+
return ret;
54+
55+
return dest1->vport.pkt_reformat && dest2->vport.pkt_reformat ?
56+
memcmp(dest1->vport.pkt_reformat, dest2->vport.pkt_reformat,
57+
sizeof(*dest1->vport.pkt_reformat)) : 0;
4558
}
4659

4760
static int
@@ -62,7 +75,8 @@ mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
6275
/* As this is the terminating action then the termination table is the
6376
* same prio as the slow path
6477
*/
65-
ft_attr.flags = MLX5_FLOW_TABLE_TERMINATION;
78+
ft_attr.flags = MLX5_FLOW_TABLE_TERMINATION |
79+
MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
6680
ft_attr.prio = FDB_SLOW_PATH;
6781
ft_attr.max_fte = 1;
6882
ft_attr.autogroup.max_num_groups = 1;
@@ -74,7 +88,6 @@ mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
7488

7589
tt->rule = mlx5_add_flow_rules(tt->termtbl, NULL, flow_act,
7690
&tt->dest, 1);
77-
7891
if (IS_ERR(tt->rule)) {
7992
esw_warn(dev, "Failed to create termination table rule\n");
8093
goto add_flow_err;
@@ -92,15 +105,15 @@ mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
92105
static struct mlx5_termtbl_handle *
93106
mlx5_eswitch_termtbl_get_create(struct mlx5_eswitch *esw,
94107
struct mlx5_flow_act *flow_act,
95-
struct mlx5_flow_destination *dest)
108+
struct mlx5_flow_destination *dest,
109+
struct mlx5_esw_flow_attr *attr)
96110
{
97111
struct mlx5_termtbl_handle *tt;
98112
bool found = false;
99113
u32 hash_key;
100114
int err;
101115

102116
mutex_lock(&esw->offloads.termtbl_mutex);
103-
104117
hash_key = mlx5_eswitch_termtbl_hash(flow_act, dest);
105118
hash_for_each_possible(esw->offloads.termtbl_tbl, tt,
106119
termtbl_hlist, hash_key) {
@@ -122,6 +135,7 @@ mlx5_eswitch_termtbl_get_create(struct mlx5_eswitch *esw,
122135
tt->dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
123136
tt->dest.vport.num = dest->vport.num;
124137
tt->dest.vport.vhca_id = dest->vport.vhca_id;
138+
tt->dest.vport.flags = dest->vport.flags;
125139
memcpy(&tt->flow_act, flow_act, sizeof(*flow_act));
126140

127141
err = mlx5_eswitch_termtbl_create(esw->dev, tt, flow_act);
@@ -156,25 +170,44 @@ mlx5_eswitch_termtbl_put(struct mlx5_eswitch *esw,
156170
}
157171
}
158172

173+
static bool mlx5_eswitch_termtbl_is_encap_reformat(struct mlx5_pkt_reformat *rt)
174+
{
175+
switch (rt->reformat_type) {
176+
case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
177+
case MLX5_REFORMAT_TYPE_L2_TO_NVGRE:
178+
case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
179+
case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
180+
return true;
181+
default:
182+
return false;
183+
}
184+
}
185+
159186
static void
160187
mlx5_eswitch_termtbl_actions_move(struct mlx5_flow_act *src,
161188
struct mlx5_flow_act *dst)
162189
{
163-
if (!(src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH))
164-
return;
165-
166-
src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
167-
dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
168-
memcpy(&dst->vlan[0], &src->vlan[0], sizeof(src->vlan[0]));
169-
memset(&src->vlan[0], 0, sizeof(src->vlan[0]));
170-
171-
if (!(src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2))
172-
return;
190+
if (src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
191+
src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
192+
dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
193+
memcpy(&dst->vlan[0], &src->vlan[0], sizeof(src->vlan[0]));
194+
memset(&src->vlan[0], 0, sizeof(src->vlan[0]));
195+
196+
if (src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
197+
src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
198+
dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
199+
memcpy(&dst->vlan[1], &src->vlan[1], sizeof(src->vlan[1]));
200+
memset(&src->vlan[1], 0, sizeof(src->vlan[1]));
201+
}
202+
}
173203

174-
src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
175-
dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
176-
memcpy(&dst->vlan[1], &src->vlan[1], sizeof(src->vlan[1]));
177-
memset(&src->vlan[1], 0, sizeof(src->vlan[1]));
204+
if (src->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT &&
205+
mlx5_eswitch_termtbl_is_encap_reformat(src->pkt_reformat)) {
206+
src->action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
207+
dst->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
208+
dst->pkt_reformat = src->pkt_reformat;
209+
src->pkt_reformat = NULL;
210+
}
178211
}
179212

180213
static bool mlx5_eswitch_offload_is_uplink_port(const struct mlx5_eswitch *esw,
@@ -199,13 +232,23 @@ mlx5_eswitch_termtbl_required(struct mlx5_eswitch *esw,
199232
struct mlx5_flow_act *flow_act,
200233
struct mlx5_flow_spec *spec)
201234
{
235+
int i;
236+
202237
if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, termination_table) ||
203-
attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH)
238+
attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH ||
239+
!mlx5_eswitch_offload_is_uplink_port(esw, spec))
204240
return false;
205241

206242
/* push vlan on RX */
207-
return (flow_act->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) &&
208-
mlx5_eswitch_offload_is_uplink_port(esw, spec);
243+
if (flow_act->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH)
244+
return true;
245+
246+
/* hairpin */
247+
for (i = attr->split_count; i < attr->out_count; i++)
248+
if (attr->dests[i].rep->vport == MLX5_VPORT_UPLINK)
249+
return true;
250+
251+
return false;
209252
}
210253

211254
struct mlx5_flow_handle *
@@ -235,7 +278,7 @@ mlx5_eswitch_add_termtbl_rule(struct mlx5_eswitch *esw,
235278

236279
/* get the terminating table for the action list */
237280
tt = mlx5_eswitch_termtbl_get_create(esw, &term_tbl_act,
238-
&dest[i]);
281+
&dest[i], attr);
239282
if (IS_ERR(tt)) {
240283
esw_warn(esw->dev, "Failed to create termination table\n");
241284
goto revert_changes;

0 commit comments

Comments
 (0)