]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
net: switchdev: zero-initialize struct switchdev_notifier_fdb_info emitted by drivers...
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / mellanox / mlx5 / core / esw / bridge.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2021 Mellanox Technologies. */
3
4 #include <linux/list.h>
5 #include <linux/notifier.h>
6 #include <net/netevent.h>
7 #include <net/switchdev.h>
8 #include "bridge.h"
9 #include "eswitch.h"
10 #include "bridge_priv.h"
11 #define CREATE_TRACE_POINTS
12 #include "diag/bridge_tracepoint.h"
13
14 #define MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE 64000
15 #define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_FROM 0
16 #define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE / 4 - 1)
17 #define MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_FROM \
18 (MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO + 1)
19 #define MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO \
20 (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE / 2 - 1)
21 #define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_FROM \
22 (MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO + 1)
23 #define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_TO (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE - 1)
24
25 #define MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE 64000
26 #define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_FROM 0
27 #define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE / 2 - 1)
28 #define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_FROM \
29 (MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO + 1)
30 #define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE - 1)
31
32 #define MLX5_ESW_BRIDGE_SKIP_TABLE_SIZE 0
33
34 enum {
35 MLX5_ESW_BRIDGE_LEVEL_INGRESS_TABLE,
36 MLX5_ESW_BRIDGE_LEVEL_EGRESS_TABLE,
37 MLX5_ESW_BRIDGE_LEVEL_SKIP_TABLE,
38 };
39
40 static const struct rhashtable_params fdb_ht_params = {
41 .key_offset = offsetof(struct mlx5_esw_bridge_fdb_entry, key),
42 .key_len = sizeof(struct mlx5_esw_bridge_fdb_key),
43 .head_offset = offsetof(struct mlx5_esw_bridge_fdb_entry, ht_node),
44 .automatic_shrinking = true,
45 };
46
47 enum {
48 MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG = BIT(0),
49 };
50
51 struct mlx5_esw_bridge {
52 int ifindex;
53 int refcnt;
54 struct list_head list;
55 struct mlx5_esw_bridge_offloads *br_offloads;
56
57 struct list_head fdb_list;
58 struct rhashtable fdb_ht;
59 struct xarray vports;
60
61 struct mlx5_flow_table *egress_ft;
62 struct mlx5_flow_group *egress_vlan_fg;
63 struct mlx5_flow_group *egress_mac_fg;
64 unsigned long ageing_time;
65 u32 flags;
66 };
67
68 static void
69 mlx5_esw_bridge_fdb_offload_notify(struct net_device *dev, const unsigned char *addr, u16 vid,
70 unsigned long val)
71 {
72 struct switchdev_notifier_fdb_info send_info = {};
73
74 send_info.addr = addr;
75 send_info.vid = vid;
76 send_info.offloaded = true;
77 call_switchdev_notifiers(val, dev, &send_info.info, NULL);
78 }
79
80 static struct mlx5_flow_table *
81 mlx5_esw_bridge_table_create(int max_fte, u32 level, struct mlx5_eswitch *esw)
82 {
83 struct mlx5_flow_table_attr ft_attr = {};
84 struct mlx5_core_dev *dev = esw->dev;
85 struct mlx5_flow_namespace *ns;
86 struct mlx5_flow_table *fdb;
87
88 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
89 if (!ns) {
90 esw_warn(dev, "Failed to get FDB namespace\n");
91 return ERR_PTR(-ENOENT);
92 }
93
94 ft_attr.flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
95 ft_attr.max_fte = max_fte;
96 ft_attr.level = level;
97 ft_attr.prio = FDB_BR_OFFLOAD;
98 fdb = mlx5_create_flow_table(ns, &ft_attr);
99 if (IS_ERR(fdb))
100 esw_warn(dev, "Failed to create bridge FDB Table (err=%ld)\n", PTR_ERR(fdb));
101
102 return fdb;
103 }
104
105 static struct mlx5_flow_group *
106 mlx5_esw_bridge_ingress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *ingress_ft)
107 {
108 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
109 struct mlx5_flow_group *fg;
110 u32 *in, *match;
111
112 in = kvzalloc(inlen, GFP_KERNEL);
113 if (!in)
114 return ERR_PTR(-ENOMEM);
115
116 MLX5_SET(create_flow_group_in, in, match_criteria_enable,
117 MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2);
118 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
119
120 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16);
121 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0);
122 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
123 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.first_vid);
124
125 MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0,
126 mlx5_eswitch_get_vport_metadata_mask());
127
128 MLX5_SET(create_flow_group_in, in, start_flow_index,
129 MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_FROM);
130 MLX5_SET(create_flow_group_in, in, end_flow_index,
131 MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO);
132
133 fg = mlx5_create_flow_group(ingress_ft, in);
134 kvfree(in);
135 if (IS_ERR(fg))
136 esw_warn(esw->dev,
137 "Failed to create VLAN flow group for bridge ingress table (err=%ld)\n",
138 PTR_ERR(fg));
139
140 return fg;
141 }
142
143 static struct mlx5_flow_group *
144 mlx5_esw_bridge_ingress_filter_fg_create(struct mlx5_eswitch *esw,
145 struct mlx5_flow_table *ingress_ft)
146 {
147 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
148 struct mlx5_flow_group *fg;
149 u32 *in, *match;
150
151 in = kvzalloc(inlen, GFP_KERNEL);
152 if (!in)
153 return ERR_PTR(-ENOMEM);
154
155 MLX5_SET(create_flow_group_in, in, match_criteria_enable,
156 MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2);
157 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
158
159 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16);
160 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0);
161 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
162
163 MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0,
164 mlx5_eswitch_get_vport_metadata_mask());
165
166 MLX5_SET(create_flow_group_in, in, start_flow_index,
167 MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_FROM);
168 MLX5_SET(create_flow_group_in, in, end_flow_index,
169 MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO);
170
171 fg = mlx5_create_flow_group(ingress_ft, in);
172 if (IS_ERR(fg))
173 esw_warn(esw->dev,
174 "Failed to create bridge ingress table VLAN filter flow group (err=%ld)\n",
175 PTR_ERR(fg));
176
177 kvfree(in);
178 return fg;
179 }
180
181 static struct mlx5_flow_group *
182 mlx5_esw_bridge_ingress_mac_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *ingress_ft)
183 {
184 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
185 struct mlx5_flow_group *fg;
186 u32 *in, *match;
187
188 in = kvzalloc(inlen, GFP_KERNEL);
189 if (!in)
190 return ERR_PTR(-ENOMEM);
191
192 MLX5_SET(create_flow_group_in, in, match_criteria_enable,
193 MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2);
194 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
195
196 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16);
197 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0);
198
199 MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0,
200 mlx5_eswitch_get_vport_metadata_mask());
201
202 MLX5_SET(create_flow_group_in, in, start_flow_index,
203 MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_FROM);
204 MLX5_SET(create_flow_group_in, in, end_flow_index,
205 MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_TO);
206
207 fg = mlx5_create_flow_group(ingress_ft, in);
208 if (IS_ERR(fg))
209 esw_warn(esw->dev,
210 "Failed to create MAC flow group for bridge ingress table (err=%ld)\n",
211 PTR_ERR(fg));
212
213 kvfree(in);
214 return fg;
215 }
216
217 static struct mlx5_flow_group *
218 mlx5_esw_bridge_egress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft)
219 {
220 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
221 struct mlx5_flow_group *fg;
222 u32 *in, *match;
223
224 in = kvzalloc(inlen, GFP_KERNEL);
225 if (!in)
226 return ERR_PTR(-ENOMEM);
227
228 MLX5_SET(create_flow_group_in, in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
229 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
230
231 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_47_16);
232 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_15_0);
233 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
234 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.first_vid);
235
236 MLX5_SET(create_flow_group_in, in, start_flow_index,
237 MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_FROM);
238 MLX5_SET(create_flow_group_in, in, end_flow_index,
239 MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO);
240
241 fg = mlx5_create_flow_group(egress_ft, in);
242 if (IS_ERR(fg))
243 esw_warn(esw->dev,
244 "Failed to create VLAN flow group for bridge egress table (err=%ld)\n",
245 PTR_ERR(fg));
246 kvfree(in);
247 return fg;
248 }
249
250 static struct mlx5_flow_group *
251 mlx5_esw_bridge_egress_mac_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft)
252 {
253 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
254 struct mlx5_flow_group *fg;
255 u32 *in, *match;
256
257 in = kvzalloc(inlen, GFP_KERNEL);
258 if (!in)
259 return ERR_PTR(-ENOMEM);
260
261 MLX5_SET(create_flow_group_in, in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
262 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
263
264 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_47_16);
265 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_15_0);
266
267 MLX5_SET(create_flow_group_in, in, start_flow_index,
268 MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_FROM);
269 MLX5_SET(create_flow_group_in, in, end_flow_index,
270 MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO);
271
272 fg = mlx5_create_flow_group(egress_ft, in);
273 if (IS_ERR(fg))
274 esw_warn(esw->dev,
275 "Failed to create bridge egress table MAC flow group (err=%ld)\n",
276 PTR_ERR(fg));
277 kvfree(in);
278 return fg;
279 }
280
281 static int
282 mlx5_esw_bridge_ingress_table_init(struct mlx5_esw_bridge_offloads *br_offloads)
283 {
284 struct mlx5_flow_group *mac_fg, *filter_fg, *vlan_fg;
285 struct mlx5_flow_table *ingress_ft, *skip_ft;
286 int err;
287
288 if (!mlx5_eswitch_vport_match_metadata_enabled(br_offloads->esw))
289 return -EOPNOTSUPP;
290
291 ingress_ft = mlx5_esw_bridge_table_create(MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE,
292 MLX5_ESW_BRIDGE_LEVEL_INGRESS_TABLE,
293 br_offloads->esw);
294 if (IS_ERR(ingress_ft))
295 return PTR_ERR(ingress_ft);
296
297 skip_ft = mlx5_esw_bridge_table_create(MLX5_ESW_BRIDGE_SKIP_TABLE_SIZE,
298 MLX5_ESW_BRIDGE_LEVEL_SKIP_TABLE,
299 br_offloads->esw);
300 if (IS_ERR(skip_ft)) {
301 err = PTR_ERR(skip_ft);
302 goto err_skip_tbl;
303 }
304
305 vlan_fg = mlx5_esw_bridge_ingress_vlan_fg_create(br_offloads->esw, ingress_ft);
306 if (IS_ERR(vlan_fg)) {
307 err = PTR_ERR(vlan_fg);
308 goto err_vlan_fg;
309 }
310
311 filter_fg = mlx5_esw_bridge_ingress_filter_fg_create(br_offloads->esw, ingress_ft);
312 if (IS_ERR(filter_fg)) {
313 err = PTR_ERR(filter_fg);
314 goto err_filter_fg;
315 }
316
317 mac_fg = mlx5_esw_bridge_ingress_mac_fg_create(br_offloads->esw, ingress_ft);
318 if (IS_ERR(mac_fg)) {
319 err = PTR_ERR(mac_fg);
320 goto err_mac_fg;
321 }
322
323 br_offloads->ingress_ft = ingress_ft;
324 br_offloads->skip_ft = skip_ft;
325 br_offloads->ingress_vlan_fg = vlan_fg;
326 br_offloads->ingress_filter_fg = filter_fg;
327 br_offloads->ingress_mac_fg = mac_fg;
328 return 0;
329
330 err_mac_fg:
331 mlx5_destroy_flow_group(filter_fg);
332 err_filter_fg:
333 mlx5_destroy_flow_group(vlan_fg);
334 err_vlan_fg:
335 mlx5_destroy_flow_table(skip_ft);
336 err_skip_tbl:
337 mlx5_destroy_flow_table(ingress_ft);
338 return err;
339 }
340
341 static void
342 mlx5_esw_bridge_ingress_table_cleanup(struct mlx5_esw_bridge_offloads *br_offloads)
343 {
344 mlx5_destroy_flow_group(br_offloads->ingress_mac_fg);
345 br_offloads->ingress_mac_fg = NULL;
346 mlx5_destroy_flow_group(br_offloads->ingress_filter_fg);
347 br_offloads->ingress_filter_fg = NULL;
348 mlx5_destroy_flow_group(br_offloads->ingress_vlan_fg);
349 br_offloads->ingress_vlan_fg = NULL;
350 mlx5_destroy_flow_table(br_offloads->skip_ft);
351 br_offloads->skip_ft = NULL;
352 mlx5_destroy_flow_table(br_offloads->ingress_ft);
353 br_offloads->ingress_ft = NULL;
354 }
355
356 static int
357 mlx5_esw_bridge_egress_table_init(struct mlx5_esw_bridge_offloads *br_offloads,
358 struct mlx5_esw_bridge *bridge)
359 {
360 struct mlx5_flow_group *mac_fg, *vlan_fg;
361 struct mlx5_flow_table *egress_ft;
362 int err;
363
364 egress_ft = mlx5_esw_bridge_table_create(MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE,
365 MLX5_ESW_BRIDGE_LEVEL_EGRESS_TABLE,
366 br_offloads->esw);
367 if (IS_ERR(egress_ft))
368 return PTR_ERR(egress_ft);
369
370 vlan_fg = mlx5_esw_bridge_egress_vlan_fg_create(br_offloads->esw, egress_ft);
371 if (IS_ERR(vlan_fg)) {
372 err = PTR_ERR(vlan_fg);
373 goto err_vlan_fg;
374 }
375
376 mac_fg = mlx5_esw_bridge_egress_mac_fg_create(br_offloads->esw, egress_ft);
377 if (IS_ERR(mac_fg)) {
378 err = PTR_ERR(mac_fg);
379 goto err_mac_fg;
380 }
381
382 bridge->egress_ft = egress_ft;
383 bridge->egress_vlan_fg = vlan_fg;
384 bridge->egress_mac_fg = mac_fg;
385 return 0;
386
387 err_mac_fg:
388 mlx5_destroy_flow_group(vlan_fg);
389 err_vlan_fg:
390 mlx5_destroy_flow_table(egress_ft);
391 return err;
392 }
393
394 static void
395 mlx5_esw_bridge_egress_table_cleanup(struct mlx5_esw_bridge *bridge)
396 {
397 mlx5_destroy_flow_group(bridge->egress_mac_fg);
398 mlx5_destroy_flow_group(bridge->egress_vlan_fg);
399 mlx5_destroy_flow_table(bridge->egress_ft);
400 }
401
402 static struct mlx5_flow_handle *
403 mlx5_esw_bridge_ingress_flow_create(u16 vport_num, const unsigned char *addr,
404 struct mlx5_esw_bridge_vlan *vlan, u32 counter_id,
405 struct mlx5_esw_bridge *bridge)
406 {
407 struct mlx5_esw_bridge_offloads *br_offloads = bridge->br_offloads;
408 struct mlx5_flow_act flow_act = {
409 .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_COUNT,
410 .flags = FLOW_ACT_NO_APPEND,
411 };
412 struct mlx5_flow_destination dests[2] = {};
413 struct mlx5_flow_spec *rule_spec;
414 struct mlx5_flow_handle *handle;
415 u8 *smac_v, *smac_c;
416
417 rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL);
418 if (!rule_spec)
419 return ERR_PTR(-ENOMEM);
420
421 rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2;
422
423 smac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value,
424 outer_headers.smac_47_16);
425 ether_addr_copy(smac_v, addr);
426 smac_c = MLX5_ADDR_OF(fte_match_param, rule_spec->match_criteria,
427 outer_headers.smac_47_16);
428 eth_broadcast_addr(smac_c);
429
430 MLX5_SET(fte_match_param, rule_spec->match_criteria,
431 misc_parameters_2.metadata_reg_c_0, mlx5_eswitch_get_vport_metadata_mask());
432 MLX5_SET(fte_match_param, rule_spec->match_value, misc_parameters_2.metadata_reg_c_0,
433 mlx5_eswitch_get_vport_metadata_for_match(br_offloads->esw, vport_num));
434
435 if (vlan && vlan->pkt_reformat_push) {
436 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
437 flow_act.pkt_reformat = vlan->pkt_reformat_push;
438 } else if (vlan) {
439 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
440 outer_headers.cvlan_tag);
441 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
442 outer_headers.cvlan_tag);
443 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
444 outer_headers.first_vid);
445 MLX5_SET(fte_match_param, rule_spec->match_value, outer_headers.first_vid,
446 vlan->vid);
447 }
448
449 dests[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
450 dests[0].ft = bridge->egress_ft;
451 dests[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
452 dests[1].counter_id = counter_id;
453
454 handle = mlx5_add_flow_rules(br_offloads->ingress_ft, rule_spec, &flow_act, dests,
455 ARRAY_SIZE(dests));
456
457 kvfree(rule_spec);
458 return handle;
459 }
460
461 static struct mlx5_flow_handle *
462 mlx5_esw_bridge_ingress_filter_flow_create(u16 vport_num, const unsigned char *addr,
463 struct mlx5_esw_bridge *bridge)
464 {
465 struct mlx5_esw_bridge_offloads *br_offloads = bridge->br_offloads;
466 struct mlx5_flow_destination dest = {
467 .type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE,
468 .ft = br_offloads->skip_ft,
469 };
470 struct mlx5_flow_act flow_act = {
471 .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
472 .flags = FLOW_ACT_NO_APPEND,
473 };
474 struct mlx5_flow_spec *rule_spec;
475 struct mlx5_flow_handle *handle;
476 u8 *smac_v, *smac_c;
477
478 rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL);
479 if (!rule_spec)
480 return ERR_PTR(-ENOMEM);
481
482 rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2;
483
484 smac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value,
485 outer_headers.smac_47_16);
486 ether_addr_copy(smac_v, addr);
487 smac_c = MLX5_ADDR_OF(fte_match_param, rule_spec->match_criteria,
488 outer_headers.smac_47_16);
489 eth_broadcast_addr(smac_c);
490
491 MLX5_SET(fte_match_param, rule_spec->match_criteria,
492 misc_parameters_2.metadata_reg_c_0, mlx5_eswitch_get_vport_metadata_mask());
493 MLX5_SET(fte_match_param, rule_spec->match_value, misc_parameters_2.metadata_reg_c_0,
494 mlx5_eswitch_get_vport_metadata_for_match(br_offloads->esw, vport_num));
495
496 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
497 outer_headers.cvlan_tag);
498 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
499 outer_headers.cvlan_tag);
500
501 handle = mlx5_add_flow_rules(br_offloads->ingress_ft, rule_spec, &flow_act, &dest, 1);
502
503 kvfree(rule_spec);
504 return handle;
505 }
506
507 static struct mlx5_flow_handle *
508 mlx5_esw_bridge_egress_flow_create(u16 vport_num, const unsigned char *addr,
509 struct mlx5_esw_bridge_vlan *vlan,
510 struct mlx5_esw_bridge *bridge)
511 {
512 struct mlx5_flow_destination dest = {
513 .type = MLX5_FLOW_DESTINATION_TYPE_VPORT,
514 .vport.num = vport_num,
515 };
516 struct mlx5_flow_act flow_act = {
517 .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
518 .flags = FLOW_ACT_NO_APPEND,
519 };
520 struct mlx5_flow_spec *rule_spec;
521 struct mlx5_flow_handle *handle;
522 u8 *dmac_v, *dmac_c;
523
524 rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL);
525 if (!rule_spec)
526 return ERR_PTR(-ENOMEM);
527
528 rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
529
530 dmac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value,
531 outer_headers.dmac_47_16);
532 ether_addr_copy(dmac_v, addr);
533 dmac_c = MLX5_ADDR_OF(fte_match_param, rule_spec->match_criteria,
534 outer_headers.dmac_47_16);
535 eth_broadcast_addr(dmac_c);
536
537 if (vlan) {
538 if (vlan->pkt_reformat_pop) {
539 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
540 flow_act.pkt_reformat = vlan->pkt_reformat_pop;
541 }
542
543 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
544 outer_headers.cvlan_tag);
545 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
546 outer_headers.cvlan_tag);
547 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
548 outer_headers.first_vid);
549 MLX5_SET(fte_match_param, rule_spec->match_value, outer_headers.first_vid,
550 vlan->vid);
551 }
552
553 handle = mlx5_add_flow_rules(bridge->egress_ft, rule_spec, &flow_act, &dest, 1);
554
555 kvfree(rule_spec);
556 return handle;
557 }
558
559 static struct mlx5_esw_bridge *mlx5_esw_bridge_create(int ifindex,
560 struct mlx5_esw_bridge_offloads *br_offloads)
561 {
562 struct mlx5_esw_bridge *bridge;
563 int err;
564
565 bridge = kvzalloc(sizeof(*bridge), GFP_KERNEL);
566 if (!bridge)
567 return ERR_PTR(-ENOMEM);
568
569 bridge->br_offloads = br_offloads;
570 err = mlx5_esw_bridge_egress_table_init(br_offloads, bridge);
571 if (err)
572 goto err_egress_tbl;
573
574 err = rhashtable_init(&bridge->fdb_ht, &fdb_ht_params);
575 if (err)
576 goto err_fdb_ht;
577
578 INIT_LIST_HEAD(&bridge->fdb_list);
579 xa_init(&bridge->vports);
580 bridge->ifindex = ifindex;
581 bridge->refcnt = 1;
582 bridge->ageing_time = clock_t_to_jiffies(BR_DEFAULT_AGEING_TIME);
583 list_add(&bridge->list, &br_offloads->bridges);
584
585 return bridge;
586
587 err_fdb_ht:
588 mlx5_esw_bridge_egress_table_cleanup(bridge);
589 err_egress_tbl:
590 kvfree(bridge);
591 return ERR_PTR(err);
592 }
593
594 static void mlx5_esw_bridge_get(struct mlx5_esw_bridge *bridge)
595 {
596 bridge->refcnt++;
597 }
598
599 static void mlx5_esw_bridge_put(struct mlx5_esw_bridge_offloads *br_offloads,
600 struct mlx5_esw_bridge *bridge)
601 {
602 if (--bridge->refcnt)
603 return;
604
605 mlx5_esw_bridge_egress_table_cleanup(bridge);
606 WARN_ON(!xa_empty(&bridge->vports));
607 list_del(&bridge->list);
608 rhashtable_destroy(&bridge->fdb_ht);
609 kvfree(bridge);
610
611 if (list_empty(&br_offloads->bridges))
612 mlx5_esw_bridge_ingress_table_cleanup(br_offloads);
613 }
614
615 static struct mlx5_esw_bridge *
616 mlx5_esw_bridge_lookup(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads)
617 {
618 struct mlx5_esw_bridge *bridge;
619
620 ASSERT_RTNL();
621
622 list_for_each_entry(bridge, &br_offloads->bridges, list) {
623 if (bridge->ifindex == ifindex) {
624 mlx5_esw_bridge_get(bridge);
625 return bridge;
626 }
627 }
628
629 if (!br_offloads->ingress_ft) {
630 int err = mlx5_esw_bridge_ingress_table_init(br_offloads);
631
632 if (err)
633 return ERR_PTR(err);
634 }
635
636 bridge = mlx5_esw_bridge_create(ifindex, br_offloads);
637 if (IS_ERR(bridge) && list_empty(&br_offloads->bridges))
638 mlx5_esw_bridge_ingress_table_cleanup(br_offloads);
639 return bridge;
640 }
641
642 static int mlx5_esw_bridge_port_insert(struct mlx5_esw_bridge_port *port,
643 struct mlx5_esw_bridge *bridge)
644 {
645 return xa_insert(&bridge->vports, port->vport_num, port, GFP_KERNEL);
646 }
647
648 static struct mlx5_esw_bridge_port *
649 mlx5_esw_bridge_port_lookup(u16 vport_num, struct mlx5_esw_bridge *bridge)
650 {
651 return xa_load(&bridge->vports, vport_num);
652 }
653
654 static void mlx5_esw_bridge_port_erase(struct mlx5_esw_bridge_port *port,
655 struct mlx5_esw_bridge *bridge)
656 {
657 xa_erase(&bridge->vports, port->vport_num);
658 }
659
660 static void mlx5_esw_bridge_fdb_entry_refresh(unsigned long lastuse,
661 struct mlx5_esw_bridge_fdb_entry *entry)
662 {
663 trace_mlx5_esw_bridge_fdb_entry_refresh(entry);
664
665 entry->lastuse = lastuse;
666 mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
667 entry->key.vid,
668 SWITCHDEV_FDB_ADD_TO_BRIDGE);
669 }
670
671 static void
672 mlx5_esw_bridge_fdb_entry_cleanup(struct mlx5_esw_bridge_fdb_entry *entry,
673 struct mlx5_esw_bridge *bridge)
674 {
675 trace_mlx5_esw_bridge_fdb_entry_cleanup(entry);
676
677 rhashtable_remove_fast(&bridge->fdb_ht, &entry->ht_node, fdb_ht_params);
678 mlx5_del_flow_rules(entry->egress_handle);
679 if (entry->filter_handle)
680 mlx5_del_flow_rules(entry->filter_handle);
681 mlx5_del_flow_rules(entry->ingress_handle);
682 mlx5_fc_destroy(bridge->br_offloads->esw->dev, entry->ingress_counter);
683 list_del(&entry->vlan_list);
684 list_del(&entry->list);
685 kvfree(entry);
686 }
687
688 static void mlx5_esw_bridge_fdb_flush(struct mlx5_esw_bridge *bridge)
689 {
690 struct mlx5_esw_bridge_fdb_entry *entry, *tmp;
691
692 list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list) {
693 if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER))
694 mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
695 entry->key.vid,
696 SWITCHDEV_FDB_DEL_TO_BRIDGE);
697 mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
698 }
699 }
700
701 static struct mlx5_esw_bridge_vlan *
702 mlx5_esw_bridge_vlan_lookup(u16 vid, struct mlx5_esw_bridge_port *port)
703 {
704 return xa_load(&port->vlans, vid);
705 }
706
707 static int
708 mlx5_esw_bridge_vlan_push_create(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw)
709 {
710 struct {
711 __be16 h_vlan_proto;
712 __be16 h_vlan_TCI;
713 } vlan_hdr = { htons(ETH_P_8021Q), htons(vlan->vid) };
714 struct mlx5_pkt_reformat_params reformat_params = {};
715 struct mlx5_pkt_reformat *pkt_reformat;
716
717 if (!BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat_insert)) ||
718 MLX5_CAP_GEN_2(esw->dev, max_reformat_insert_size) < sizeof(vlan_hdr) ||
719 MLX5_CAP_GEN_2(esw->dev, max_reformat_insert_offset) <
720 offsetof(struct vlan_ethhdr, h_vlan_proto)) {
721 esw_warn(esw->dev, "Packet reformat INSERT_HEADER is not supported\n");
722 return -EOPNOTSUPP;
723 }
724
725 reformat_params.type = MLX5_REFORMAT_TYPE_INSERT_HDR;
726 reformat_params.param_0 = MLX5_REFORMAT_CONTEXT_ANCHOR_MAC_START;
727 reformat_params.param_1 = offsetof(struct vlan_ethhdr, h_vlan_proto);
728 reformat_params.size = sizeof(vlan_hdr);
729 reformat_params.data = &vlan_hdr;
730 pkt_reformat = mlx5_packet_reformat_alloc(esw->dev,
731 &reformat_params,
732 MLX5_FLOW_NAMESPACE_FDB);
733 if (IS_ERR(pkt_reformat)) {
734 esw_warn(esw->dev, "Failed to alloc packet reformat INSERT_HEADER (err=%ld)\n",
735 PTR_ERR(pkt_reformat));
736 return PTR_ERR(pkt_reformat);
737 }
738
739 vlan->pkt_reformat_push = pkt_reformat;
740 return 0;
741 }
742
743 static void
744 mlx5_esw_bridge_vlan_push_cleanup(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw)
745 {
746 mlx5_packet_reformat_dealloc(esw->dev, vlan->pkt_reformat_push);
747 vlan->pkt_reformat_push = NULL;
748 }
749
750 static int
751 mlx5_esw_bridge_vlan_pop_create(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw)
752 {
753 struct mlx5_pkt_reformat_params reformat_params = {};
754 struct mlx5_pkt_reformat *pkt_reformat;
755
756 if (!BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat_remove)) ||
757 MLX5_CAP_GEN_2(esw->dev, max_reformat_remove_size) < sizeof(struct vlan_hdr) ||
758 MLX5_CAP_GEN_2(esw->dev, max_reformat_remove_offset) <
759 offsetof(struct vlan_ethhdr, h_vlan_proto)) {
760 esw_warn(esw->dev, "Packet reformat REMOVE_HEADER is not supported\n");
761 return -EOPNOTSUPP;
762 }
763
764 reformat_params.type = MLX5_REFORMAT_TYPE_REMOVE_HDR;
765 reformat_params.param_0 = MLX5_REFORMAT_CONTEXT_ANCHOR_MAC_START;
766 reformat_params.param_1 = offsetof(struct vlan_ethhdr, h_vlan_proto);
767 reformat_params.size = sizeof(struct vlan_hdr);
768 pkt_reformat = mlx5_packet_reformat_alloc(esw->dev,
769 &reformat_params,
770 MLX5_FLOW_NAMESPACE_FDB);
771 if (IS_ERR(pkt_reformat)) {
772 esw_warn(esw->dev, "Failed to alloc packet reformat REMOVE_HEADER (err=%ld)\n",
773 PTR_ERR(pkt_reformat));
774 return PTR_ERR(pkt_reformat);
775 }
776
777 vlan->pkt_reformat_pop = pkt_reformat;
778 return 0;
779 }
780
781 static void
782 mlx5_esw_bridge_vlan_pop_cleanup(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw)
783 {
784 mlx5_packet_reformat_dealloc(esw->dev, vlan->pkt_reformat_pop);
785 vlan->pkt_reformat_pop = NULL;
786 }
787
788 static struct mlx5_esw_bridge_vlan *
789 mlx5_esw_bridge_vlan_create(u16 vid, u16 flags, struct mlx5_esw_bridge_port *port,
790 struct mlx5_eswitch *esw)
791 {
792 struct mlx5_esw_bridge_vlan *vlan;
793 int err;
794
795 vlan = kvzalloc(sizeof(*vlan), GFP_KERNEL);
796 if (!vlan)
797 return ERR_PTR(-ENOMEM);
798
799 vlan->vid = vid;
800 vlan->flags = flags;
801 INIT_LIST_HEAD(&vlan->fdb_list);
802
803 if (flags & BRIDGE_VLAN_INFO_PVID) {
804 err = mlx5_esw_bridge_vlan_push_create(vlan, esw);
805 if (err)
806 goto err_vlan_push;
807 }
808 if (flags & BRIDGE_VLAN_INFO_UNTAGGED) {
809 err = mlx5_esw_bridge_vlan_pop_create(vlan, esw);
810 if (err)
811 goto err_vlan_pop;
812 }
813
814 err = xa_insert(&port->vlans, vid, vlan, GFP_KERNEL);
815 if (err)
816 goto err_xa_insert;
817
818 trace_mlx5_esw_bridge_vlan_create(vlan);
819 return vlan;
820
821 err_xa_insert:
822 if (vlan->pkt_reformat_pop)
823 mlx5_esw_bridge_vlan_pop_cleanup(vlan, esw);
824 err_vlan_pop:
825 if (vlan->pkt_reformat_push)
826 mlx5_esw_bridge_vlan_push_cleanup(vlan, esw);
827 err_vlan_push:
828 kvfree(vlan);
829 return ERR_PTR(err);
830 }
831
832 static void mlx5_esw_bridge_vlan_erase(struct mlx5_esw_bridge_port *port,
833 struct mlx5_esw_bridge_vlan *vlan)
834 {
835 xa_erase(&port->vlans, vlan->vid);
836 }
837
838 static void mlx5_esw_bridge_vlan_flush(struct mlx5_esw_bridge_vlan *vlan,
839 struct mlx5_esw_bridge *bridge)
840 {
841 struct mlx5_esw_bridge_fdb_entry *entry, *tmp;
842
843 list_for_each_entry_safe(entry, tmp, &vlan->fdb_list, vlan_list) {
844 if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER))
845 mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
846 entry->key.vid,
847 SWITCHDEV_FDB_DEL_TO_BRIDGE);
848 mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
849 }
850
851 if (vlan->pkt_reformat_pop)
852 mlx5_esw_bridge_vlan_pop_cleanup(vlan, bridge->br_offloads->esw);
853 if (vlan->pkt_reformat_push)
854 mlx5_esw_bridge_vlan_push_cleanup(vlan, bridge->br_offloads->esw);
855 }
856
857 static void mlx5_esw_bridge_vlan_cleanup(struct mlx5_esw_bridge_port *port,
858 struct mlx5_esw_bridge_vlan *vlan,
859 struct mlx5_esw_bridge *bridge)
860 {
861 trace_mlx5_esw_bridge_vlan_cleanup(vlan);
862 mlx5_esw_bridge_vlan_flush(vlan, bridge);
863 mlx5_esw_bridge_vlan_erase(port, vlan);
864 kvfree(vlan);
865 }
866
867 static void mlx5_esw_bridge_port_vlans_flush(struct mlx5_esw_bridge_port *port,
868 struct mlx5_esw_bridge *bridge)
869 {
870 struct mlx5_esw_bridge_vlan *vlan;
871 unsigned long index;
872
873 xa_for_each(&port->vlans, index, vlan)
874 mlx5_esw_bridge_vlan_cleanup(port, vlan, bridge);
875 }
876
877 static struct mlx5_esw_bridge_vlan *
878 mlx5_esw_bridge_port_vlan_lookup(u16 vid, u16 vport_num, struct mlx5_esw_bridge *bridge,
879 struct mlx5_eswitch *esw)
880 {
881 struct mlx5_esw_bridge_port *port;
882 struct mlx5_esw_bridge_vlan *vlan;
883
884 port = mlx5_esw_bridge_port_lookup(vport_num, bridge);
885 if (!port) {
886 /* FDB is added asynchronously on wq while port might have been deleted
887 * concurrently. Report on 'info' logging level and skip the FDB offload.
888 */
889 esw_info(esw->dev, "Failed to lookup bridge port (vport=%u)\n", vport_num);
890 return ERR_PTR(-EINVAL);
891 }
892
893 vlan = mlx5_esw_bridge_vlan_lookup(vid, port);
894 if (!vlan) {
895 /* FDB is added asynchronously on wq while vlan might have been deleted
896 * concurrently. Report on 'info' logging level and skip the FDB offload.
897 */
898 esw_info(esw->dev, "Failed to lookup bridge port vlan metadata (vport=%u)\n",
899 vport_num);
900 return ERR_PTR(-EINVAL);
901 }
902
903 return vlan;
904 }
905
906 static struct mlx5_esw_bridge_fdb_entry *
907 mlx5_esw_bridge_fdb_entry_init(struct net_device *dev, u16 vport_num, const unsigned char *addr,
908 u16 vid, bool added_by_user, struct mlx5_eswitch *esw,
909 struct mlx5_esw_bridge *bridge)
910 {
911 struct mlx5_esw_bridge_vlan *vlan = NULL;
912 struct mlx5_esw_bridge_fdb_entry *entry;
913 struct mlx5_flow_handle *handle;
914 struct mlx5_fc *counter;
915 struct mlx5e_priv *priv;
916 int err;
917
918 if (bridge->flags & MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG && vid) {
919 vlan = mlx5_esw_bridge_port_vlan_lookup(vid, vport_num, bridge, esw);
920 if (IS_ERR(vlan))
921 return ERR_CAST(vlan);
922 }
923
924 priv = netdev_priv(dev);
925 entry = kvzalloc(sizeof(*entry), GFP_KERNEL);
926 if (!entry)
927 return ERR_PTR(-ENOMEM);
928
929 ether_addr_copy(entry->key.addr, addr);
930 entry->key.vid = vid;
931 entry->dev = dev;
932 entry->vport_num = vport_num;
933 entry->lastuse = jiffies;
934 if (added_by_user)
935 entry->flags |= MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER;
936
937 counter = mlx5_fc_create(priv->mdev, true);
938 if (IS_ERR(counter)) {
939 err = PTR_ERR(counter);
940 goto err_ingress_fc_create;
941 }
942 entry->ingress_counter = counter;
943
944 handle = mlx5_esw_bridge_ingress_flow_create(vport_num, addr, vlan, mlx5_fc_id(counter),
945 bridge);
946 if (IS_ERR(handle)) {
947 err = PTR_ERR(handle);
948 esw_warn(esw->dev, "Failed to create ingress flow(vport=%u,err=%d)\n",
949 vport_num, err);
950 goto err_ingress_flow_create;
951 }
952 entry->ingress_handle = handle;
953
954 if (bridge->flags & MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG) {
955 handle = mlx5_esw_bridge_ingress_filter_flow_create(vport_num, addr, bridge);
956 if (IS_ERR(handle)) {
957 err = PTR_ERR(handle);
958 esw_warn(esw->dev, "Failed to create ingress filter(vport=%u,err=%d)\n",
959 vport_num, err);
960 goto err_ingress_filter_flow_create;
961 }
962 entry->filter_handle = handle;
963 }
964
965 handle = mlx5_esw_bridge_egress_flow_create(vport_num, addr, vlan, bridge);
966 if (IS_ERR(handle)) {
967 err = PTR_ERR(handle);
968 esw_warn(esw->dev, "Failed to create egress flow(vport=%u,err=%d)\n",
969 vport_num, err);
970 goto err_egress_flow_create;
971 }
972 entry->egress_handle = handle;
973
974 err = rhashtable_insert_fast(&bridge->fdb_ht, &entry->ht_node, fdb_ht_params);
975 if (err) {
976 esw_warn(esw->dev, "Failed to insert FDB flow(vport=%u,err=%d)\n", vport_num, err);
977 goto err_ht_init;
978 }
979
980 if (vlan)
981 list_add(&entry->vlan_list, &vlan->fdb_list);
982 else
983 INIT_LIST_HEAD(&entry->vlan_list);
984 list_add(&entry->list, &bridge->fdb_list);
985
986 trace_mlx5_esw_bridge_fdb_entry_init(entry);
987 return entry;
988
989 err_ht_init:
990 mlx5_del_flow_rules(entry->egress_handle);
991 err_egress_flow_create:
992 if (entry->filter_handle)
993 mlx5_del_flow_rules(entry->filter_handle);
994 err_ingress_filter_flow_create:
995 mlx5_del_flow_rules(entry->ingress_handle);
996 err_ingress_flow_create:
997 mlx5_fc_destroy(priv->mdev, entry->ingress_counter);
998 err_ingress_fc_create:
999 kvfree(entry);
1000 return ERR_PTR(err);
1001 }
1002
1003 int mlx5_esw_bridge_ageing_time_set(unsigned long ageing_time, struct mlx5_eswitch *esw,
1004 struct mlx5_vport *vport)
1005 {
1006 if (!vport->bridge)
1007 return -EINVAL;
1008
1009 vport->bridge->ageing_time = clock_t_to_jiffies(ageing_time);
1010 return 0;
1011 }
1012
1013 int mlx5_esw_bridge_vlan_filtering_set(bool enable, struct mlx5_eswitch *esw,
1014 struct mlx5_vport *vport)
1015 {
1016 struct mlx5_esw_bridge *bridge;
1017 bool filtering;
1018
1019 if (!vport->bridge)
1020 return -EINVAL;
1021
1022 bridge = vport->bridge;
1023 filtering = bridge->flags & MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG;
1024 if (filtering == enable)
1025 return 0;
1026
1027 mlx5_esw_bridge_fdb_flush(bridge);
1028 if (enable)
1029 bridge->flags |= MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG;
1030 else
1031 bridge->flags &= ~MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG;
1032
1033 return 0;
1034 }
1035
1036 static int mlx5_esw_bridge_vport_init(struct mlx5_esw_bridge_offloads *br_offloads,
1037 struct mlx5_esw_bridge *bridge,
1038 struct mlx5_vport *vport)
1039 {
1040 struct mlx5_eswitch *esw = br_offloads->esw;
1041 struct mlx5_esw_bridge_port *port;
1042 int err;
1043
1044 port = kvzalloc(sizeof(*port), GFP_KERNEL);
1045 if (!port) {
1046 err = -ENOMEM;
1047 goto err_port_alloc;
1048 }
1049
1050 port->vport_num = vport->vport;
1051 xa_init(&port->vlans);
1052 err = mlx5_esw_bridge_port_insert(port, bridge);
1053 if (err) {
1054 esw_warn(esw->dev, "Failed to insert port metadata (vport=%u,err=%d)\n",
1055 vport->vport, err);
1056 goto err_port_insert;
1057 }
1058 trace_mlx5_esw_bridge_vport_init(port);
1059
1060 vport->bridge = bridge;
1061 return 0;
1062
1063 err_port_insert:
1064 kvfree(port);
1065 err_port_alloc:
1066 mlx5_esw_bridge_put(br_offloads, bridge);
1067 return err;
1068 }
1069
1070 static int mlx5_esw_bridge_vport_cleanup(struct mlx5_esw_bridge_offloads *br_offloads,
1071 struct mlx5_vport *vport)
1072 {
1073 struct mlx5_esw_bridge *bridge = vport->bridge;
1074 struct mlx5_esw_bridge_fdb_entry *entry, *tmp;
1075 struct mlx5_esw_bridge_port *port;
1076
1077 list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list)
1078 if (entry->vport_num == vport->vport)
1079 mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
1080
1081 port = mlx5_esw_bridge_port_lookup(vport->vport, bridge);
1082 if (!port) {
1083 WARN(1, "Vport %u metadata not found on bridge", vport->vport);
1084 return -EINVAL;
1085 }
1086
1087 trace_mlx5_esw_bridge_vport_cleanup(port);
1088 mlx5_esw_bridge_port_vlans_flush(port, bridge);
1089 mlx5_esw_bridge_port_erase(port, bridge);
1090 kvfree(port);
1091 mlx5_esw_bridge_put(br_offloads, bridge);
1092 vport->bridge = NULL;
1093 return 0;
1094 }
1095
1096 int mlx5_esw_bridge_vport_link(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads,
1097 struct mlx5_vport *vport, struct netlink_ext_ack *extack)
1098 {
1099 struct mlx5_esw_bridge *bridge;
1100 int err;
1101
1102 WARN_ON(vport->bridge);
1103
1104 bridge = mlx5_esw_bridge_lookup(ifindex, br_offloads);
1105 if (IS_ERR(bridge)) {
1106 NL_SET_ERR_MSG_MOD(extack, "Error checking for existing bridge with same ifindex");
1107 return PTR_ERR(bridge);
1108 }
1109
1110 err = mlx5_esw_bridge_vport_init(br_offloads, bridge, vport);
1111 if (err)
1112 NL_SET_ERR_MSG_MOD(extack, "Error initializing port");
1113 return err;
1114 }
1115
1116 int mlx5_esw_bridge_vport_unlink(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads,
1117 struct mlx5_vport *vport, struct netlink_ext_ack *extack)
1118 {
1119 struct mlx5_esw_bridge *bridge = vport->bridge;
1120 int err;
1121
1122 if (!bridge) {
1123 NL_SET_ERR_MSG_MOD(extack, "Port is not attached to any bridge");
1124 return -EINVAL;
1125 }
1126 if (bridge->ifindex != ifindex) {
1127 NL_SET_ERR_MSG_MOD(extack, "Port is attached to another bridge");
1128 return -EINVAL;
1129 }
1130
1131 err = mlx5_esw_bridge_vport_cleanup(br_offloads, vport);
1132 if (err)
1133 NL_SET_ERR_MSG_MOD(extack, "Port cleanup failed");
1134 return err;
1135 }
1136
1137 int mlx5_esw_bridge_port_vlan_add(u16 vid, u16 flags, struct mlx5_eswitch *esw,
1138 struct mlx5_vport *vport, struct netlink_ext_ack *extack)
1139 {
1140 struct mlx5_esw_bridge_port *port;
1141 struct mlx5_esw_bridge_vlan *vlan;
1142
1143 port = mlx5_esw_bridge_port_lookup(vport->vport, vport->bridge);
1144 if (!port)
1145 return -EINVAL;
1146
1147 vlan = mlx5_esw_bridge_vlan_lookup(vid, port);
1148 if (vlan) {
1149 if (vlan->flags == flags)
1150 return 0;
1151 mlx5_esw_bridge_vlan_cleanup(port, vlan, vport->bridge);
1152 }
1153
1154 vlan = mlx5_esw_bridge_vlan_create(vid, flags, port, esw);
1155 if (IS_ERR(vlan)) {
1156 NL_SET_ERR_MSG_MOD(extack, "Failed to create VLAN entry");
1157 return PTR_ERR(vlan);
1158 }
1159 return 0;
1160 }
1161
1162 void mlx5_esw_bridge_port_vlan_del(u16 vid, struct mlx5_eswitch *esw, struct mlx5_vport *vport)
1163 {
1164 struct mlx5_esw_bridge_port *port;
1165 struct mlx5_esw_bridge_vlan *vlan;
1166
1167 port = mlx5_esw_bridge_port_lookup(vport->vport, vport->bridge);
1168 if (!port)
1169 return;
1170
1171 vlan = mlx5_esw_bridge_vlan_lookup(vid, port);
1172 if (!vlan)
1173 return;
1174 mlx5_esw_bridge_vlan_cleanup(port, vlan, vport->bridge);
1175 }
1176
1177 void mlx5_esw_bridge_fdb_create(struct net_device *dev, struct mlx5_eswitch *esw,
1178 struct mlx5_vport *vport,
1179 struct switchdev_notifier_fdb_info *fdb_info)
1180 {
1181 struct mlx5_esw_bridge *bridge = vport->bridge;
1182 struct mlx5_esw_bridge_fdb_entry *entry;
1183 u16 vport_num = vport->vport;
1184
1185 if (!bridge) {
1186 esw_info(esw->dev, "Vport is not assigned to bridge (vport=%u)\n", vport_num);
1187 return;
1188 }
1189
1190 entry = mlx5_esw_bridge_fdb_entry_init(dev, vport_num, fdb_info->addr, fdb_info->vid,
1191 fdb_info->added_by_user, esw, bridge);
1192 if (IS_ERR(entry))
1193 return;
1194
1195 if (entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER)
1196 mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid,
1197 SWITCHDEV_FDB_OFFLOADED);
1198 else
1199 /* Take over dynamic entries to prevent kernel bridge from aging them out. */
1200 mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid,
1201 SWITCHDEV_FDB_ADD_TO_BRIDGE);
1202 }
1203
1204 void mlx5_esw_bridge_fdb_remove(struct net_device *dev, struct mlx5_eswitch *esw,
1205 struct mlx5_vport *vport,
1206 struct switchdev_notifier_fdb_info *fdb_info)
1207 {
1208 struct mlx5_esw_bridge *bridge = vport->bridge;
1209 struct mlx5_esw_bridge_fdb_entry *entry;
1210 struct mlx5_esw_bridge_fdb_key key;
1211 u16 vport_num = vport->vport;
1212
1213 if (!bridge) {
1214 esw_warn(esw->dev, "Vport is not assigned to bridge (vport=%u)\n", vport_num);
1215 return;
1216 }
1217
1218 ether_addr_copy(key.addr, fdb_info->addr);
1219 key.vid = fdb_info->vid;
1220 entry = rhashtable_lookup_fast(&bridge->fdb_ht, &key, fdb_ht_params);
1221 if (!entry) {
1222 esw_warn(esw->dev,
1223 "FDB entry with specified key not found (MAC=%pM,vid=%u,vport=%u)\n",
1224 key.addr, key.vid, vport_num);
1225 return;
1226 }
1227
1228 if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER))
1229 mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid,
1230 SWITCHDEV_FDB_DEL_TO_BRIDGE);
1231 mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
1232 }
1233
1234 void mlx5_esw_bridge_update(struct mlx5_esw_bridge_offloads *br_offloads)
1235 {
1236 struct mlx5_esw_bridge_fdb_entry *entry, *tmp;
1237 struct mlx5_esw_bridge *bridge;
1238
1239 list_for_each_entry(bridge, &br_offloads->bridges, list) {
1240 list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list) {
1241 unsigned long lastuse =
1242 (unsigned long)mlx5_fc_query_lastuse(entry->ingress_counter);
1243
1244 if (entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER)
1245 continue;
1246
1247 if (time_after(lastuse, entry->lastuse)) {
1248 mlx5_esw_bridge_fdb_entry_refresh(lastuse, entry);
1249 } else if (time_is_before_jiffies(entry->lastuse + bridge->ageing_time)) {
1250 mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
1251 entry->key.vid,
1252 SWITCHDEV_FDB_DEL_TO_BRIDGE);
1253 mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
1254 }
1255 }
1256 }
1257 }
1258
1259 static void mlx5_esw_bridge_flush(struct mlx5_esw_bridge_offloads *br_offloads)
1260 {
1261 struct mlx5_eswitch *esw = br_offloads->esw;
1262 struct mlx5_vport *vport;
1263 unsigned long i;
1264
1265 mlx5_esw_for_each_vport(esw, i, vport)
1266 if (vport->bridge)
1267 mlx5_esw_bridge_vport_cleanup(br_offloads, vport);
1268
1269 WARN_ONCE(!list_empty(&br_offloads->bridges),
1270 "Cleaning up bridge offloads while still having bridges attached\n");
1271 }
1272
1273 struct mlx5_esw_bridge_offloads *mlx5_esw_bridge_init(struct mlx5_eswitch *esw)
1274 {
1275 struct mlx5_esw_bridge_offloads *br_offloads;
1276
1277 br_offloads = kvzalloc(sizeof(*br_offloads), GFP_KERNEL);
1278 if (!br_offloads)
1279 return ERR_PTR(-ENOMEM);
1280
1281 INIT_LIST_HEAD(&br_offloads->bridges);
1282 br_offloads->esw = esw;
1283 esw->br_offloads = br_offloads;
1284
1285 return br_offloads;
1286 }
1287
1288 void mlx5_esw_bridge_cleanup(struct mlx5_eswitch *esw)
1289 {
1290 struct mlx5_esw_bridge_offloads *br_offloads = esw->br_offloads;
1291
1292 if (!br_offloads)
1293 return;
1294
1295 mlx5_esw_bridge_flush(br_offloads);
1296
1297 esw->br_offloads = NULL;
1298 kvfree(br_offloads);
1299 }