0399a396d1662d7b553141cbb3f2646701ab0ebf
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / esw / acl / egress_lgcy.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2020 Mellanox Technologies Inc. All rights reserved. */
3
4 #include "mlx5_core.h"
5 #include "eswitch.h"
6 #include "helper.h"
7 #include "lgcy.h"
8
9 static void esw_acl_egress_lgcy_rules_destroy(struct mlx5_vport *vport)
10 {
11         esw_acl_egress_vlan_destroy(vport);
12         if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_rule)) {
13                 mlx5_del_flow_rules(vport->egress.legacy.drop_rule);
14                 vport->egress.legacy.drop_rule = NULL;
15         }
16 }
17
18 static int esw_acl_egress_lgcy_groups_create(struct mlx5_eswitch *esw,
19                                              struct mlx5_vport *vport)
20 {
21         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
22         struct mlx5_core_dev *dev = esw->dev;
23         struct mlx5_flow_group *drop_grp;
24         u32 *flow_group_in;
25         int err = 0;
26
27         err = esw_acl_egress_vlan_grp_create(esw, vport);
28         if (err)
29                 return err;
30
31         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
32         if (!flow_group_in) {
33                 err = -ENOMEM;
34                 goto alloc_err;
35         }
36
37         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
38         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
39         drop_grp = mlx5_create_flow_group(vport->egress.acl, flow_group_in);
40         if (IS_ERR(drop_grp)) {
41                 err = PTR_ERR(drop_grp);
42                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress drop flow group, err(%d)\n",
43                          vport->vport, err);
44                 goto drop_grp_err;
45         }
46
47         vport->egress.legacy.drop_grp = drop_grp;
48         kvfree(flow_group_in);
49         return 0;
50
51 drop_grp_err:
52         kvfree(flow_group_in);
53 alloc_err:
54         esw_acl_egress_vlan_grp_destroy(vport);
55         return err;
56 }
57
58 static void esw_acl_egress_lgcy_groups_destroy(struct mlx5_vport *vport)
59 {
60         if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_grp)) {
61                 mlx5_destroy_flow_group(vport->egress.legacy.drop_grp);
62                 vport->egress.legacy.drop_grp = NULL;
63         }
64         esw_acl_egress_vlan_grp_destroy(vport);
65 }
66
67 int esw_acl_egress_lgcy_setup(struct mlx5_eswitch *esw,
68                               struct mlx5_vport *vport)
69 {
70         struct mlx5_flow_destination drop_ctr_dst = {};
71         struct mlx5_flow_destination *dst = NULL;
72         struct mlx5_fc *drop_counter = NULL;
73         struct mlx5_flow_act flow_act = {};
74         /* The egress acl table contains 2 rules:
75          * 1)Allow traffic with vlan_tag=vst_vlan_id
76          * 2)Drop all other traffic.
77          */
78         int table_size = 2;
79         int dest_num = 0;
80         int err = 0;
81
82         if (MLX5_CAP_ESW_EGRESS_ACL(esw->dev, flow_counter)) {
83                 drop_counter = mlx5_fc_create(esw->dev, false);
84                 if (IS_ERR(drop_counter))
85                         esw_warn(esw->dev,
86                                  "vport[%d] configure egress drop rule counter err(%ld)\n",
87                                  vport->vport, PTR_ERR(drop_counter));
88                 vport->egress.legacy.drop_counter = drop_counter;
89         }
90
91         esw_acl_egress_lgcy_rules_destroy(vport);
92
93         if (!vport->info.vlan && !vport->info.qos) {
94                 esw_acl_egress_lgcy_cleanup(esw, vport);
95                 return 0;
96         }
97
98         if (!vport->egress.acl) {
99                 vport->egress.acl = esw_acl_table_create(esw, vport,
100                                                          MLX5_FLOW_NAMESPACE_ESW_EGRESS,
101                                                          table_size);
102                 if (IS_ERR(vport->egress.acl)) {
103                         err = PTR_ERR(vport->egress.acl);
104                         vport->egress.acl = NULL;
105                         goto out;
106                 }
107
108                 err = esw_acl_egress_lgcy_groups_create(esw, vport);
109                 if (err)
110                         goto out;
111         }
112
113         esw_debug(esw->dev,
114                   "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
115                   vport->vport, vport->info.vlan, vport->info.qos);
116
117         /* Allowed vlan rule */
118         err = esw_egress_acl_vlan_create(esw, vport, NULL, vport->info.vlan,
119                                          MLX5_FLOW_CONTEXT_ACTION_ALLOW);
120         if (err)
121                 goto out;
122
123         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
124
125         /* Attach egress drop flow counter */
126         if (!IS_ERR_OR_NULL(drop_counter)) {
127                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
128                 drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
129                 drop_ctr_dst.counter_id = mlx5_fc_id(drop_counter);
130                 dst = &drop_ctr_dst;
131                 dest_num++;
132         }
133         vport->egress.legacy.drop_rule =
134                 mlx5_add_flow_rules(vport->egress.acl, NULL,
135                                     &flow_act, dst, dest_num);
136         if (IS_ERR(vport->egress.legacy.drop_rule)) {
137                 err = PTR_ERR(vport->egress.legacy.drop_rule);
138                 esw_warn(esw->dev,
139                          "vport[%d] configure egress drop rule failed, err(%d)\n",
140                          vport->vport, err);
141                 vport->egress.legacy.drop_rule = NULL;
142                 goto out;
143         }
144
145         return err;
146
147 out:
148         esw_acl_egress_lgcy_cleanup(esw, vport);
149         return err;
150 }
151
152 void esw_acl_egress_lgcy_cleanup(struct mlx5_eswitch *esw,
153                                  struct mlx5_vport *vport)
154 {
155         if (IS_ERR_OR_NULL(vport->egress.acl))
156                 goto clean_drop_counter;
157
158         esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport);
159
160         esw_acl_egress_lgcy_rules_destroy(vport);
161         esw_acl_egress_lgcy_groups_destroy(vport);
162         esw_acl_egress_table_destroy(vport);
163
164 clean_drop_counter:
165         if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_counter)) {
166                 mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter);
167                 vport->egress.legacy.drop_counter = NULL;
168         }
169 }