1 /*-
2 * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD$
26 */
27
28 #include <linux/etherdevice.h>
29 #include <dev/mlx5/driver.h>
30 #include <dev/mlx5/flow_table.h>
31 #include <dev/mlx5/eswitch_vacl.h>
32 #include "mlx5_core.h"
33
34 enum {
35 MLX5_ACL_LOOPBACK_GROUP_IDX = 0,
36 MLX5_ACL_UNTAGGED_GROUP_IDX = 1,
37 MLX5_ACL_VLAN_GROUP_IDX = 2,
38 MLX5_ACL_UNKNOWN_VLAN_GROUP_IDX = 3,
39 MLX5_ACL_DEFAULT_GROUP_IDX = 4,
40 MLX5_ACL_GROUPS_NUM,
41 };
42
43 struct mlx_vacl_fr {
44 bool applied;
45 u32 fi;
46 u16 action;
47 };
48
49 struct mlx5_vacl_table {
50 struct mlx5_core_dev *dev;
51 u16 vport;
52 void *ft;
53 int max_ft_size;
54 int acl_type;
55
56 struct mlx_vacl_fr loopback_fr;
57 struct mlx_vacl_fr untagged_fr;
58 struct mlx_vacl_fr unknown_vlan_fr;
59 struct mlx_vacl_fr default_fr;
60
61 bool vlan_filter_enabled;
62 bool vlan_filter_applied;
63 unsigned long *vlan_allowed_bitmap;
64 u32 vlan_fi_table[4096];
65
66 bool spoofchk_enabled;
67 u8 smac[ETH_ALEN];
68 };
69
mlx5_vacl_table_allow_vlan(void * acl_t,u16 vlan)70 static int mlx5_vacl_table_allow_vlan(void *acl_t, u16 vlan)
71 {
72 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
73 u32 *flow_context = NULL;
74 void *in_match_criteria = NULL;
75 void *in_match_value = NULL;
76 u8 *smac;
77 int vlan_mc_enable = MLX5_MATCH_OUTER_HEADERS;
78 int err = 0;
79
80 if (!test_bit(vlan, acl_table->vlan_allowed_bitmap))
81 return -EINVAL;
82
83 flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context));
84 if (!flow_context) {
85 err = -ENOMEM;
86 goto out;
87 }
88
89 in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
90 if (!in_match_criteria) {
91 err = -ENOMEM;
92 goto out;
93 }
94
95 /* Apply vlan rule */
96 MLX5_SET(flow_context, flow_context, action,
97 MLX5_FLOW_CONTEXT_ACTION_ALLOW);
98 in_match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
99 MLX5_SET(fte_match_param, in_match_value, outer_headers.vlan_tag, 1);
100 MLX5_SET(fte_match_param, in_match_value, outer_headers.first_vid,
101 vlan);
102 MLX5_SET(fte_match_param, in_match_criteria, outer_headers.vlan_tag, 1);
103 MLX5_SET(fte_match_param, in_match_criteria, outer_headers.first_vid,
104 0xfff);
105 if (acl_table->spoofchk_enabled) {
106 smac = MLX5_ADDR_OF(fte_match_param,
107 in_match_value,
108 outer_headers.smac_47_16);
109 ether_addr_copy(smac, acl_table->smac);
110 smac = MLX5_ADDR_OF(fte_match_param,
111 in_match_criteria,
112 outer_headers.smac_47_16);
113 memset(smac, 0xff, ETH_ALEN);
114 }
115 err = mlx5_add_flow_table_entry(acl_table->ft, vlan_mc_enable,
116 in_match_criteria, flow_context,
117 &acl_table->vlan_fi_table[vlan]);
118 out:
119 if (flow_context)
120 vfree(flow_context);
121 if (in_match_criteria)
122 vfree(in_match_criteria);
123 return err;
124 }
125
mlx5_vacl_table_apply_loopback_filter(void * acl_t,u16 new_action)126 static int mlx5_vacl_table_apply_loopback_filter(void *acl_t, u16 new_action)
127 {
128 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
129 u8 loopback_mc_enable = MLX5_MATCH_MISC_PARAMETERS;
130 u32 *flow_context = NULL;
131 void *in_match_criteria = NULL;
132 void *in_match_value = NULL;
133 void *mv_misc = NULL;
134 void *mc_misc = NULL;
135 int err = 0;
136
137 flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context));
138 if (!flow_context) {
139 err = -ENOMEM;
140 goto out;
141 }
142
143 in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
144 if (!in_match_criteria) {
145 err = -ENOMEM;
146 goto out;
147 }
148
149 if (acl_table->loopback_fr.applied)
150 mlx5_del_flow_table_entry(acl_table->ft,
151 acl_table->loopback_fr.fi);
152
153 /* Apply new loopback rule */
154 MLX5_SET(flow_context, flow_context, action, new_action);
155 in_match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
156 mv_misc = MLX5_ADDR_OF(fte_match_param, in_match_value,
157 misc_parameters);
158 mc_misc = MLX5_ADDR_OF(fte_match_param, in_match_criteria,
159 misc_parameters);
160 MLX5_SET(fte_match_set_misc, mv_misc, source_port, acl_table->vport);
161
162 MLX5_SET_TO_ONES(fte_match_set_misc, mc_misc, source_port);
163
164 err = mlx5_add_flow_table_entry(acl_table->ft, loopback_mc_enable,
165 in_match_criteria, flow_context,
166 &acl_table->loopback_fr.fi);
167 if (err) {
168 acl_table->loopback_fr.applied = false;
169 } else {
170 acl_table->loopback_fr.applied = true;
171 acl_table->loopback_fr.action = new_action;
172 }
173
174 out:
175 if (flow_context)
176 vfree(flow_context);
177 if (in_match_criteria)
178 vfree(in_match_criteria);
179 return err;
180 }
181
mlx5_vacl_table_apply_default(void * acl_t,u16 new_action)182 static int mlx5_vacl_table_apply_default(void *acl_t, u16 new_action)
183 {
184 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
185 u8 default_mc_enable = 0;
186 u32 *flow_context = NULL;
187 void *in_match_criteria = NULL;
188 int err = 0;
189
190 if (!acl_table->spoofchk_enabled)
191 return -EINVAL;
192
193 flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context));
194 if (!flow_context) {
195 err = -ENOMEM;
196 goto out;
197 }
198
199 in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
200 if (!in_match_criteria) {
201 err = -ENOMEM;
202 goto out;
203 }
204
205 if (acl_table->default_fr.applied)
206 mlx5_del_flow_table_entry(acl_table->ft,
207 acl_table->default_fr.fi);
208
209 /* Apply new default rule */
210 MLX5_SET(flow_context, flow_context, action, new_action);
211 err = mlx5_add_flow_table_entry(acl_table->ft, default_mc_enable,
212 in_match_criteria, flow_context,
213 &acl_table->default_fr.fi);
214 if (err) {
215 acl_table->default_fr.applied = false;
216 } else {
217 acl_table->default_fr.applied = true;
218 acl_table->default_fr.action = new_action;
219 }
220
221 out:
222 if (flow_context)
223 vfree(flow_context);
224 if (in_match_criteria)
225 vfree(in_match_criteria);
226 return err;
227 }
228
mlx5_vacl_table_apply_untagged(void * acl_t,u16 new_action)229 static int mlx5_vacl_table_apply_untagged(void *acl_t, u16 new_action)
230 {
231 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
232 u8 untagged_mc_enable = MLX5_MATCH_OUTER_HEADERS;
233 u8 *smac;
234 u32 *flow_context = NULL;
235 void *in_match_criteria = NULL;
236 void *in_match_value = NULL;
237 int err = 0;
238
239 flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context));
240 if (!flow_context) {
241 err = -ENOMEM;
242 goto out;
243 }
244
245 in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
246 if (!in_match_criteria) {
247 err = -ENOMEM;
248 goto out;
249 }
250
251 if (acl_table->untagged_fr.applied)
252 mlx5_del_flow_table_entry(acl_table->ft,
253 acl_table->untagged_fr.fi);
254
255 /* Apply new untagged rule */
256 MLX5_SET(flow_context, flow_context, action, new_action);
257 in_match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
258 MLX5_SET(fte_match_param, in_match_value, outer_headers.vlan_tag, 0);
259 MLX5_SET(fte_match_param, in_match_criteria, outer_headers.vlan_tag, 1);
260 if (acl_table->spoofchk_enabled) {
261 smac = MLX5_ADDR_OF(fte_match_param,
262 in_match_value,
263 outer_headers.smac_47_16);
264 ether_addr_copy(smac, acl_table->smac);
265 smac = MLX5_ADDR_OF(fte_match_param,
266 in_match_criteria,
267 outer_headers.smac_47_16);
268 memset(smac, 0xff, ETH_ALEN);
269 }
270 err = mlx5_add_flow_table_entry(acl_table->ft, untagged_mc_enable,
271 in_match_criteria, flow_context,
272 &acl_table->untagged_fr.fi);
273 if (err) {
274 acl_table->untagged_fr.applied = false;
275 } else {
276 acl_table->untagged_fr.applied = true;
277 acl_table->untagged_fr.action = new_action;
278 }
279
280 out:
281 if (flow_context)
282 vfree(flow_context);
283 if (in_match_criteria)
284 vfree(in_match_criteria);
285 return err;
286 }
287
mlx5_vacl_table_apply_unknown_vlan(void * acl_t,u16 new_action)288 static int mlx5_vacl_table_apply_unknown_vlan(void *acl_t, u16 new_action)
289 {
290 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
291 u8 default_mc_enable = (!acl_table->spoofchk_enabled) ? 0 :
292 MLX5_MATCH_OUTER_HEADERS;
293 u32 *flow_context = NULL;
294 void *in_match_criteria = NULL;
295 void *in_match_value = NULL;
296 u8 *smac;
297 int err = 0;
298
299 flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context));
300 if (!flow_context) {
301 err = -ENOMEM;
302 goto out;
303 }
304
305 in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
306 if (!in_match_criteria) {
307 err = -ENOMEM;
308 goto out;
309 }
310
311 if (acl_table->unknown_vlan_fr.applied)
312 mlx5_del_flow_table_entry(acl_table->ft,
313 acl_table->unknown_vlan_fr.fi);
314
315 /* Apply new unknown vlan rule */
316 MLX5_SET(flow_context, flow_context, action, new_action);
317 if (acl_table->spoofchk_enabled) {
318 in_match_value = MLX5_ADDR_OF(flow_context, flow_context,
319 match_value);
320 smac = MLX5_ADDR_OF(fte_match_param,
321 in_match_value,
322 outer_headers.smac_47_16);
323 ether_addr_copy(smac, acl_table->smac);
324 smac = MLX5_ADDR_OF(fte_match_param,
325 in_match_criteria,
326 outer_headers.smac_47_16);
327 memset(smac, 0xff, ETH_ALEN);
328 }
329 err = mlx5_add_flow_table_entry(acl_table->ft, default_mc_enable,
330 in_match_criteria, flow_context,
331 &acl_table->unknown_vlan_fr.fi);
332 if (err) {
333 acl_table->unknown_vlan_fr.applied = false;
334 } else {
335 acl_table->unknown_vlan_fr.applied = true;
336 acl_table->unknown_vlan_fr.action = new_action;
337 }
338
339 out:
340 if (flow_context)
341 vfree(flow_context);
342 if (in_match_criteria)
343 vfree(in_match_criteria);
344 return err;
345 }
346
mlx5_vacl_table_apply_vlan_filter(void * acl_t)347 static int mlx5_vacl_table_apply_vlan_filter(void *acl_t)
348 {
349 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
350 int index = 0;
351 int err_index = 0;
352 int err = 0;
353
354 if (acl_table->vlan_filter_applied)
355 return 0;
356
357 for (index = find_first_bit(acl_table->vlan_allowed_bitmap, 4096);
358 index < 4096;
359 index = find_next_bit(acl_table->vlan_allowed_bitmap,
360 4096, ++index)) {
361 err = mlx5_vacl_table_allow_vlan(acl_t, index);
362 if (err)
363 goto err_disable_vlans;
364 }
365
366 acl_table->vlan_filter_applied = true;
367 return 0;
368
369 err_disable_vlans:
370 for (err_index = find_first_bit(acl_table->vlan_allowed_bitmap, 4096);
371 err_index < index;
372 err_index = find_next_bit(acl_table->vlan_allowed_bitmap, 4096,
373 ++err_index)) {
374 mlx5_del_flow_table_entry(acl_table->ft,
375 acl_table->vlan_fi_table[err_index]);
376 }
377 return err;
378 }
379
mlx5_vacl_table_disapply_vlan_filter(void * acl_t)380 static void mlx5_vacl_table_disapply_vlan_filter(void *acl_t)
381 {
382 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
383 int index = 0;
384
385 if (!acl_table->vlan_filter_applied)
386 return;
387
388 for (index = find_first_bit(acl_table->vlan_allowed_bitmap, 4096);
389 index < 4096;
390 index = find_next_bit(acl_table->vlan_allowed_bitmap, 4096,
391 ++index)) {
392 mlx5_del_flow_table_entry(acl_table->ft,
393 acl_table->vlan_fi_table[index]);
394 }
395
396 acl_table->vlan_filter_applied = false;
397 }
398
mlx5_vacl_table_disapply_all_filters(void * acl_t)399 static void mlx5_vacl_table_disapply_all_filters(void *acl_t)
400 {
401 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
402
403 if (acl_table->default_fr.applied) {
404 mlx5_del_flow_table_entry(acl_table->ft,
405 acl_table->default_fr.fi);
406 acl_table->default_fr.applied = false;
407 }
408 if (acl_table->unknown_vlan_fr.applied) {
409 mlx5_del_flow_table_entry(acl_table->ft,
410 acl_table->unknown_vlan_fr.fi);
411 acl_table->unknown_vlan_fr.applied = false;
412 }
413 if (acl_table->loopback_fr.applied) {
414 mlx5_del_flow_table_entry(acl_table->ft,
415 acl_table->loopback_fr.fi);
416 acl_table->loopback_fr.applied = false;
417 }
418 if (acl_table->untagged_fr.applied) {
419 mlx5_del_flow_table_entry(acl_table->ft,
420 acl_table->untagged_fr.fi);
421 acl_table->untagged_fr.applied = false;
422 }
423 if (acl_table->vlan_filter_applied) {
424 mlx5_vacl_table_disapply_vlan_filter(acl_t);
425 acl_table->vlan_filter_applied = false;
426 }
427 }
428
mlx5_vacl_table_apply_all_filters(void * acl_t)429 static int mlx5_vacl_table_apply_all_filters(void *acl_t)
430 {
431 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
432 int err = 0;
433
434 if (!acl_table->default_fr.applied && acl_table->spoofchk_enabled) {
435 err = mlx5_vacl_table_apply_default(acl_table,
436 acl_table->default_fr.action);
437 if (err)
438 goto err_disapply_all;
439 }
440
441 if (!acl_table->unknown_vlan_fr.applied) {
442 err = mlx5_vacl_table_apply_unknown_vlan(acl_table,
443 acl_table->unknown_vlan_fr.action);
444 if (err)
445 goto err_disapply_all;
446 }
447
448 if (!acl_table->loopback_fr.applied &&
449 acl_table->acl_type == MLX5_FLOW_TABLE_TYPE_EGRESS_ACL) {
450 err = mlx5_vacl_table_apply_loopback_filter(
451 acl_table,
452 acl_table->loopback_fr.action);
453 if (err)
454 goto err_disapply_all;
455 }
456
457 if (!acl_table->untagged_fr.applied) {
458 err = mlx5_vacl_table_apply_untagged(acl_table,
459 acl_table->untagged_fr.action);
460 if (err)
461 goto err_disapply_all;
462 }
463
464 if (!acl_table->vlan_filter_applied && acl_table->vlan_filter_enabled) {
465 err = mlx5_vacl_table_apply_vlan_filter(acl_t);
466 if (err)
467 goto err_disapply_all;
468 }
469
470 goto out;
471
472 err_disapply_all:
473 mlx5_vacl_table_disapply_all_filters(acl_t);
474
475 out:
476 return err;
477 }
478
mlx5_vacl_table_destroy_ft(void * acl_t)479 static void mlx5_vacl_table_destroy_ft(void *acl_t)
480 {
481 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
482
483 mlx5_vacl_table_disapply_all_filters(acl_t);
484 if (acl_table->ft)
485 mlx5_destroy_flow_table(acl_table->ft);
486 acl_table->ft = NULL;
487 }
488
mlx5_vacl_table_create_ft(void * acl_t,bool spoofchk)489 static int mlx5_vacl_table_create_ft(void *acl_t, bool spoofchk)
490 {
491 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
492 int log_acl_ft_size;
493 int err = 0;
494 int groups_num = MLX5_ACL_GROUPS_NUM - 1;
495 int shift_idx = MLX5_ACL_UNTAGGED_GROUP_IDX;
496 u8 *smac;
497 struct mlx5_flow_table_group *g;
498
499 if (acl_table->ft)
500 return -EINVAL;
501
502 g = kcalloc(MLX5_ACL_GROUPS_NUM, sizeof(*g), GFP_KERNEL);
503 if (!g)
504 goto out;
505
506 acl_table->spoofchk_enabled = spoofchk;
507
508 /*
509 * for vlan group
510 */
511 log_acl_ft_size = 4096;
512 /*
513 * for loopback filter rule
514 */
515 log_acl_ft_size += 1;
516 /*
517 * for untagged rule
518 */
519 log_acl_ft_size += 1;
520 /*
521 * for unknown vlan rule
522 */
523 log_acl_ft_size += 1;
524 /*
525 * for default rule
526 */
527 log_acl_ft_size += 1;
528
529 log_acl_ft_size = order_base_2(log_acl_ft_size);
530 log_acl_ft_size = min_t(int, log_acl_ft_size, acl_table->max_ft_size);
531
532 if (log_acl_ft_size < 2)
533 goto out;
534
535 if (acl_table->acl_type == MLX5_FLOW_TABLE_TYPE_EGRESS_ACL) {
536 /* Loopback filter group */
537 g[MLX5_ACL_LOOPBACK_GROUP_IDX].log_sz = 0;
538 g[MLX5_ACL_LOOPBACK_GROUP_IDX].match_criteria_enable =
539 MLX5_MATCH_MISC_PARAMETERS;
540 MLX5_SET_TO_ONES(fte_match_param,
541 g[MLX5_ACL_LOOPBACK_GROUP_IDX].match_criteria,
542 misc_parameters.source_port);
543 groups_num++;
544 shift_idx = MLX5_ACL_LOOPBACK_GROUP_IDX;
545 }
546 /* Untagged traffic group */
547 g[MLX5_ACL_UNTAGGED_GROUP_IDX - shift_idx].log_sz = 0;
548 g[MLX5_ACL_UNTAGGED_GROUP_IDX - shift_idx].match_criteria_enable =
549 MLX5_MATCH_OUTER_HEADERS;
550 MLX5_SET(fte_match_param,
551 g[MLX5_ACL_UNTAGGED_GROUP_IDX - shift_idx].match_criteria,
552 outer_headers.vlan_tag, 1);
553 if (spoofchk) {
554 smac = MLX5_ADDR_OF(fte_match_param,
555 g[MLX5_ACL_UNTAGGED_GROUP_IDX - shift_idx]
556 .match_criteria,
557 outer_headers.smac_47_16);
558 memset(smac, 0xff, ETH_ALEN);
559 }
560
561 /* Allowed vlans group */
562 g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx].log_sz = log_acl_ft_size - 1;
563 g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx].match_criteria_enable =
564 MLX5_MATCH_OUTER_HEADERS;
565 MLX5_SET(fte_match_param,
566 g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx].match_criteria,
567 outer_headers.vlan_tag, 1);
568 MLX5_SET(fte_match_param,
569 g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx].match_criteria,
570 outer_headers.first_vid, 0xfff);
571 if (spoofchk) {
572 smac = MLX5_ADDR_OF(fte_match_param,
573 g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx]
574 .match_criteria,
575 outer_headers.smac_47_16);
576 memset(smac, 0xff, ETH_ALEN);
577 }
578
579 /* Unknown vlan traffic group */
580 g[MLX5_ACL_UNKNOWN_VLAN_GROUP_IDX - shift_idx].log_sz = 0;
581 g[MLX5_ACL_UNKNOWN_VLAN_GROUP_IDX - shift_idx].match_criteria_enable =
582 (spoofchk ? MLX5_MATCH_OUTER_HEADERS : 0);
583 if (spoofchk) {
584 smac = MLX5_ADDR_OF(
585 fte_match_param,
586 g[MLX5_ACL_UNKNOWN_VLAN_GROUP_IDX - shift_idx]
587 .match_criteria,
588 outer_headers.smac_47_16);
589 memset(smac, 0xff, ETH_ALEN);
590 }
591
592 /*
593 * Default group - for spoofchk only.
594 */
595 g[MLX5_ACL_DEFAULT_GROUP_IDX - shift_idx].log_sz = 0;
596 g[MLX5_ACL_DEFAULT_GROUP_IDX - shift_idx].match_criteria_enable = 0;
597
598 acl_table->ft = mlx5_create_flow_table(acl_table->dev,
599 0,
600 acl_table->acl_type,
601 acl_table->vport,
602 groups_num,
603 g);
604 if (!acl_table->ft) {
605 err = -ENOMEM;
606 goto out;
607 }
608
609 err = mlx5_vacl_table_apply_all_filters(acl_t);
610 if (err)
611 goto err_destroy_ft;
612
613 goto out;
614
615 err_destroy_ft:
616 mlx5_vacl_table_destroy_ft(acl_table->ft);
617 acl_table->ft = NULL;
618
619 out:
620 kfree(g);
621 return err;
622 }
623
mlx5_vacl_table_create(struct mlx5_core_dev * dev,u16 vport,bool is_egress)624 void *mlx5_vacl_table_create(struct mlx5_core_dev *dev,
625 u16 vport, bool is_egress)
626 {
627 struct mlx5_vacl_table *acl_table;
628 int err = 0;
629
630 if (is_egress && !MLX5_CAP_ESW_FLOWTABLE_EGRESS_ACL(dev, ft_support))
631 return NULL;
632
633 if (!is_egress && !MLX5_CAP_ESW_FLOWTABLE_INGRESS_ACL(dev, ft_support))
634 return NULL;
635
636 acl_table = kzalloc(sizeof(*acl_table), GFP_KERNEL);
637 if (!acl_table)
638 return NULL;
639
640 acl_table->acl_type = is_egress ? MLX5_FLOW_TABLE_TYPE_EGRESS_ACL :
641 MLX5_FLOW_TABLE_TYPE_INGRESS_ACL;
642 acl_table->max_ft_size = (is_egress ?
643 MLX5_CAP_ESW_FLOWTABLE_EGRESS_ACL(dev,
644 log_max_ft_size) :
645 MLX5_CAP_ESW_FLOWTABLE_INGRESS_ACL(dev,
646 log_max_ft_size));
647 acl_table->dev = dev;
648 acl_table->vport = vport;
649
650 /*
651 * default behavior : Allow and if spoofchk drop the default
652 */
653 acl_table->default_fr.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
654 acl_table->loopback_fr.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
655 acl_table->unknown_vlan_fr.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
656 acl_table->untagged_fr.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
657 err = mlx5_vacl_table_create_ft(acl_table, false);
658 if (err)
659 goto err_free_acl_table;
660
661 acl_table->vlan_allowed_bitmap = kcalloc(BITS_TO_LONGS(4096),
662 sizeof(uintptr_t),
663 GFP_KERNEL);
664 if (!acl_table->vlan_allowed_bitmap)
665 goto err_destroy_ft;
666
667 goto out;
668
669 err_destroy_ft:
670 mlx5_vacl_table_destroy_ft(acl_table->ft);
671 acl_table->ft = NULL;
672
673 err_free_acl_table:
674 kfree(acl_table);
675 acl_table = NULL;
676
677 out:
678 return (void *)acl_table;
679 }
680 EXPORT_SYMBOL(mlx5_vacl_table_create);
681
mlx5_vacl_table_cleanup(void * acl_t)682 void mlx5_vacl_table_cleanup(void *acl_t)
683 {
684 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
685
686 mlx5_vacl_table_destroy_ft(acl_t);
687 kfree(acl_table->vlan_allowed_bitmap);
688 kfree(acl_table);
689 }
690 EXPORT_SYMBOL(mlx5_vacl_table_cleanup);
691
mlx5_vacl_table_add_vlan(void * acl_t,u16 vlan)692 int mlx5_vacl_table_add_vlan(void *acl_t, u16 vlan)
693 {
694 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
695 int err = 0;
696
697 if (test_bit(vlan, acl_table->vlan_allowed_bitmap))
698 return 0;
699 __set_bit(vlan, acl_table->vlan_allowed_bitmap);
700 if (!acl_table->vlan_filter_applied)
701 return 0;
702
703 err = mlx5_vacl_table_allow_vlan(acl_t, vlan);
704 if (err)
705 goto err_clear_vbit;
706
707 goto out;
708
709 err_clear_vbit:
710 __clear_bit(vlan, acl_table->vlan_allowed_bitmap);
711
712 out:
713 return err;
714 }
715 EXPORT_SYMBOL(mlx5_vacl_table_add_vlan);
716
mlx5_vacl_table_del_vlan(void * acl_t,u16 vlan)717 void mlx5_vacl_table_del_vlan(void *acl_t, u16 vlan)
718 {
719 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
720
721 if (!test_bit(vlan, acl_table->vlan_allowed_bitmap))
722 return;
723
724 __clear_bit(vlan, acl_table->vlan_allowed_bitmap);
725
726 if (!acl_table->vlan_filter_applied)
727 return;
728
729 mlx5_del_flow_table_entry(acl_table->ft,
730 acl_table->vlan_fi_table[vlan]);
731 }
732 EXPORT_SYMBOL(mlx5_vacl_table_del_vlan);
733
mlx5_vacl_table_enable_vlan_filter(void * acl_t)734 int mlx5_vacl_table_enable_vlan_filter(void *acl_t)
735 {
736 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
737
738 acl_table->vlan_filter_enabled = true;
739 return mlx5_vacl_table_apply_vlan_filter(acl_t);
740 }
741 EXPORT_SYMBOL(mlx5_vacl_table_enable_vlan_filter);
742
mlx5_vacl_table_disable_vlan_filter(void * acl_t)743 void mlx5_vacl_table_disable_vlan_filter(void *acl_t)
744 {
745 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
746
747 acl_table->vlan_filter_enabled = false;
748 mlx5_vacl_table_disapply_vlan_filter(acl_t);
749 }
750 EXPORT_SYMBOL(mlx5_vacl_table_disable_vlan_filter);
751
mlx5_vacl_table_drop_untagged(void * acl_t)752 int mlx5_vacl_table_drop_untagged(void *acl_t)
753 {
754 return mlx5_vacl_table_apply_untagged(acl_t,
755 MLX5_FLOW_CONTEXT_ACTION_DROP);
756 }
757 EXPORT_SYMBOL(mlx5_vacl_table_drop_untagged);
758
mlx5_vacl_table_allow_untagged(void * acl_t)759 int mlx5_vacl_table_allow_untagged(void *acl_t)
760 {
761 return mlx5_vacl_table_apply_untagged(acl_t,
762 MLX5_FLOW_CONTEXT_ACTION_ALLOW);
763 }
764 EXPORT_SYMBOL(mlx5_vacl_table_allow_untagged);
765
mlx5_vacl_table_drop_unknown_vlan(void * acl_t)766 int mlx5_vacl_table_drop_unknown_vlan(void *acl_t)
767 {
768 return mlx5_vacl_table_apply_unknown_vlan(acl_t,
769 MLX5_FLOW_CONTEXT_ACTION_DROP);
770 }
771 EXPORT_SYMBOL(mlx5_vacl_table_drop_unknown_vlan);
772
mlx5_vacl_table_allow_unknown_vlan(void * acl_t)773 int mlx5_vacl_table_allow_unknown_vlan(void *acl_t)
774 {
775 return mlx5_vacl_table_apply_unknown_vlan(acl_t,
776 MLX5_FLOW_CONTEXT_ACTION_ALLOW);
777 }
778 EXPORT_SYMBOL(mlx5_vacl_table_allow_unknown_vlan);
779
mlx5_vacl_table_set_spoofchk(void * acl_t,bool spoofchk,u8 * vport_mac)780 int mlx5_vacl_table_set_spoofchk(void *acl_t, bool spoofchk, u8 *vport_mac)
781 {
782 struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t;
783 int err = 0;
784
785 if (spoofchk == acl_table->spoofchk_enabled) {
786 if (!spoofchk ||
787 (spoofchk && !memcmp(acl_table->smac, vport_mac, ETH_ALEN)))
788 return 0;
789 }
790
791 ether_addr_copy(acl_table->smac, vport_mac);
792 if (spoofchk != acl_table->spoofchk_enabled) {
793 mlx5_vacl_table_destroy_ft(acl_t);
794 err = mlx5_vacl_table_create_ft(acl_t, spoofchk);
795 } else {
796 mlx5_vacl_table_disapply_all_filters(acl_t);
797 err = mlx5_vacl_table_apply_all_filters(acl_t);
798 }
799
800 return err;
801 }
802 EXPORT_SYMBOL(mlx5_vacl_table_set_spoofchk);
803
804