]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mlx5/mlx5_core/mlx5_eswitch_vacl.c
Update llvm to trunk r256633.
[FreeBSD/FreeBSD.git] / sys / dev / mlx5 / mlx5_core / mlx5_eswitch_vacl.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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