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