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->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 }
170