60a73990017c2a3683d112e0fc03a746276b2bbe
[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 (vport->egress.legacy.drop_counter) {
83                 drop_counter = vport->egress.legacy.drop_counter;
84         } else if (MLX5_CAP_ESW_EGRESS_ACL(esw->dev, flow_counter)) {
85                 drop_counter = mlx5_fc_create(esw->dev, false);
86                 if (IS_ERR(drop_counter)) {
87                         esw_warn(esw->dev,
88                                  "vport[%d] configure egress drop rule counter err(%ld)\n",
89                                  vport->vport, PTR_ERR(drop_counter));
90                         drop_counter = NULL;
91                 }
92                 vport->egress.legacy.drop_counter = drop_counter;
93         }
94
95         esw_acl_egress_lgcy_rules_destroy(vport);
96
97         if (!vport->info.vlan && !vport->info.qos) {
98                 esw_acl_egress_lgcy_cleanup(esw, vport);
99                 return 0;
100         }
101
102         if (!vport->egress.acl) {
103                 vport->egress.acl = esw_acl_table_create(esw, vport,
104                                                          MLX5_FLOW_NAMESPACE_ESW_EGRESS,
105                                                          table_size);
106                 if (IS_ERR(vport->egress.acl)) {
107                         err = PTR_ERR(vport->egress.acl);
108                         vport->egress.acl = NULL;
109                         goto out;
110                 }
111
112                 err = esw_acl_egress_lgcy_groups_create(esw, vport);
113                 if (err)
114                         goto out;
115         }
116
117         esw_debug(esw->dev,
118                   "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
119                   vport->vport, vport->info.vlan, vport->info.qos);
120
121         /* Allowed vlan rule */
122         err = esw_egress_acl_vlan_create(esw, vport, NULL, vport->info.vlan,
123                                          MLX5_FLOW_CONTEXT_ACTION_ALLOW);
124         if (err)
125                 goto out;
126
127         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
128
129         /* Attach egress drop flow counter */
130         if (drop_counter) {
131                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
132                 drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
133                 drop_ctr_dst.counter_id = mlx5_fc_id(drop_counter);
134                 dst = &drop_ctr_dst;
135                 dest_num++;
136         }
137         vport->egress.legacy.drop_rule =
138                 mlx5_add_flow_rules(vport->egress.acl, NULL,
139                                     &flow_act, dst, dest_num);
140         if (IS_ERR(vport->egress.legacy.drop_rule)) {
141                 err = PTR_ERR(vport->egress.legacy.drop_rule);
142                 esw_warn(esw->dev,
143                          "vport[%d] configure egress drop rule failed, err(%d)\n",
144                          vport->vport, err);
145                 vport->egress.legacy.drop_rule = NULL;
146                 goto out;
147         }
148
149         return err;
150
151 out:
152         esw_acl_egress_lgcy_cleanup(esw, vport);
153         return err;
154 }
155
156 void esw_acl_egress_lgcy_cleanup(struct mlx5_eswitch *esw,
157                                  struct mlx5_vport *vport)
158 {
159         if (IS_ERR_OR_NULL(vport->egress.acl))
160                 goto clean_drop_counter;
161
162         esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport);
163
164         esw_acl_egress_lgcy_rules_destroy(vport);
165         esw_acl_egress_lgcy_groups_destroy(vport);
166         esw_acl_egress_table_destroy(vport);
167
168 clean_drop_counter:
169         if (vport->egress.legacy.drop_counter) {
170                 mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter);
171                 vport->egress.legacy.drop_counter = NULL;
172         }
173 }