3
3
4
4
#include <linux/mlx5/fs.h>
5
5
#include "eswitch.h"
6
+ #include "fs_core.h"
6
7
7
8
struct mlx5_termtbl_handle {
8
9
struct hlist_node termtbl_hlist ;
@@ -28,6 +29,10 @@ mlx5_eswitch_termtbl_hash(struct mlx5_flow_act *flow_act,
28
29
sizeof (dest -> vport .num ), hash );
29
30
hash = jhash ((const void * )& dest -> vport .vhca_id ,
30
31
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 );
31
36
return hash ;
32
37
}
33
38
@@ -37,11 +42,19 @@ mlx5_eswitch_termtbl_cmp(struct mlx5_flow_act *flow_act1,
37
42
struct mlx5_flow_act * flow_act2 ,
38
43
struct mlx5_flow_destination * dest2 )
39
44
{
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 ;
45
58
}
46
59
47
60
static int
@@ -62,7 +75,8 @@ mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
62
75
/* As this is the terminating action then the termination table is the
63
76
* same prio as the slow path
64
77
*/
65
- ft_attr .flags = MLX5_FLOW_TABLE_TERMINATION ;
78
+ ft_attr .flags = MLX5_FLOW_TABLE_TERMINATION |
79
+ MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT ;
66
80
ft_attr .prio = FDB_SLOW_PATH ;
67
81
ft_attr .max_fte = 1 ;
68
82
ft_attr .autogroup .max_num_groups = 1 ;
@@ -74,7 +88,6 @@ mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
74
88
75
89
tt -> rule = mlx5_add_flow_rules (tt -> termtbl , NULL , flow_act ,
76
90
& tt -> dest , 1 );
77
-
78
91
if (IS_ERR (tt -> rule )) {
79
92
esw_warn (dev , "Failed to create termination table rule\n" );
80
93
goto add_flow_err ;
@@ -92,15 +105,15 @@ mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
92
105
static struct mlx5_termtbl_handle *
93
106
mlx5_eswitch_termtbl_get_create (struct mlx5_eswitch * esw ,
94
107
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 )
96
110
{
97
111
struct mlx5_termtbl_handle * tt ;
98
112
bool found = false;
99
113
u32 hash_key ;
100
114
int err ;
101
115
102
116
mutex_lock (& esw -> offloads .termtbl_mutex );
103
-
104
117
hash_key = mlx5_eswitch_termtbl_hash (flow_act , dest );
105
118
hash_for_each_possible (esw -> offloads .termtbl_tbl , tt ,
106
119
termtbl_hlist , hash_key ) {
@@ -122,6 +135,7 @@ mlx5_eswitch_termtbl_get_create(struct mlx5_eswitch *esw,
122
135
tt -> dest .type = MLX5_FLOW_DESTINATION_TYPE_VPORT ;
123
136
tt -> dest .vport .num = dest -> vport .num ;
124
137
tt -> dest .vport .vhca_id = dest -> vport .vhca_id ;
138
+ tt -> dest .vport .flags = dest -> vport .flags ;
125
139
memcpy (& tt -> flow_act , flow_act , sizeof (* flow_act ));
126
140
127
141
err = mlx5_eswitch_termtbl_create (esw -> dev , tt , flow_act );
@@ -156,25 +170,44 @@ mlx5_eswitch_termtbl_put(struct mlx5_eswitch *esw,
156
170
}
157
171
}
158
172
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
+
159
186
static void
160
187
mlx5_eswitch_termtbl_actions_move (struct mlx5_flow_act * src ,
161
188
struct mlx5_flow_act * dst )
162
189
{
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
+ }
173
203
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
+ }
178
211
}
179
212
180
213
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,
199
232
struct mlx5_flow_act * flow_act ,
200
233
struct mlx5_flow_spec * spec )
201
234
{
235
+ int i ;
236
+
202
237
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 ))
204
240
return false;
205
241
206
242
/* 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;
209
252
}
210
253
211
254
struct mlx5_flow_handle *
@@ -235,7 +278,7 @@ mlx5_eswitch_add_termtbl_rule(struct mlx5_eswitch *esw,
235
278
236
279
/* get the terminating table for the action list */
237
280
tt = mlx5_eswitch_termtbl_get_create (esw , & term_tbl_act ,
238
- & dest [i ]);
281
+ & dest [i ], attr );
239
282
if (IS_ERR (tt )) {
240
283
esw_warn (esw -> dev , "Failed to create termination table\n" );
241
284
goto revert_changes ;
0 commit comments