xref: /linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c (revision fcc8487d477a3452a1d0ccbdd4c5e0e1e3cb8bed)
1 /*
2  * drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
3  * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2017 Arkadi Sharshevsky <arakdis@mellanox.com>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the names of the copyright holders nor the names of its
15  *    contributors may be used to endorse or promote products derived from
16  *    this software without specific prior written permission.
17  *
18  * Alternatively, this software may be distributed under the terms of the
19  * GNU General Public License ("GPL") version 2 as published by the Free
20  * Software Foundation.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <linux/kernel.h>
36 #include <net/devlink.h>
37 
38 #include "spectrum.h"
39 #include "spectrum_dpipe.h"
40 #include "spectrum_router.h"
41 
42 enum mlxsw_sp_field_metadata_id {
43 	MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
44 	MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
45 	MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
46 };
47 
48 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
49 	{ .name = "erif_port",
50 	  .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
51 	  .bitwidth = 32,
52 	  .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
53 	},
54 	{ .name = "l3_forward",
55 	  .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
56 	  .bitwidth = 1,
57 	},
58 	{ .name = "l3_drop",
59 	  .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
60 	  .bitwidth = 1,
61 	},
62 };
63 
64 enum mlxsw_sp_dpipe_header_id {
65 	MLXSW_SP_DPIPE_HEADER_METADATA,
66 };
67 
68 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
69 	.name = "mlxsw_meta",
70 	.id = MLXSW_SP_DPIPE_HEADER_METADATA,
71 	.fields = mlxsw_sp_dpipe_fields_metadata,
72 	.fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
73 };
74 
75 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
76 	&mlxsw_sp_dpipe_header_metadata,
77 };
78 
79 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
80 	.headers = mlxsw_dpipe_headers,
81 	.headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
82 };
83 
84 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
85 						  struct sk_buff *skb)
86 {
87 	struct devlink_dpipe_action action = {0};
88 	int err;
89 
90 	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
91 	action.header = &mlxsw_sp_dpipe_header_metadata;
92 	action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
93 
94 	err = devlink_dpipe_action_put(skb, &action);
95 	if (err)
96 		return err;
97 
98 	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
99 	action.header = &mlxsw_sp_dpipe_header_metadata;
100 	action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
101 
102 	return devlink_dpipe_action_put(skb, &action);
103 }
104 
105 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
106 						  struct sk_buff *skb)
107 {
108 	struct devlink_dpipe_match match = {0};
109 
110 	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
111 	match.header = &mlxsw_sp_dpipe_header_metadata;
112 	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
113 
114 	return devlink_dpipe_match_put(skb, &match);
115 }
116 
117 static void mlxsw_sp_erif_entry_clear(struct devlink_dpipe_entry *entry)
118 {
119 	unsigned int value_count, value_index;
120 	struct devlink_dpipe_value *value;
121 
122 	value = entry->action_values;
123 	value_count = entry->action_values_count;
124 	for (value_index = 0; value_index < value_count; value_index++) {
125 		kfree(value[value_index].value);
126 		kfree(value[value_index].mask);
127 	}
128 
129 	value = entry->match_values;
130 	value_count = entry->match_values_count;
131 	for (value_index = 0; value_index < value_count; value_index++) {
132 		kfree(value[value_index].value);
133 		kfree(value[value_index].mask);
134 	}
135 }
136 
137 static void
138 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
139 				   struct devlink_dpipe_action *action)
140 {
141 	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
142 	action->header = &mlxsw_sp_dpipe_header_metadata;
143 	action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
144 
145 	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
146 	match->header = &mlxsw_sp_dpipe_header_metadata;
147 	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
148 }
149 
150 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
151 				       struct devlink_dpipe_value *match_value,
152 				       struct devlink_dpipe_match *match,
153 				       struct devlink_dpipe_value *action_value,
154 				       struct devlink_dpipe_action *action)
155 {
156 	entry->match_values = match_value;
157 	entry->match_values_count = 1;
158 
159 	entry->action_values = action_value;
160 	entry->action_values_count = 1;
161 
162 	match_value->match = match;
163 	match_value->value_size = sizeof(u32);
164 	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
165 	if (!match_value->value)
166 		return -ENOMEM;
167 
168 	action_value->action = action;
169 	action_value->value_size = sizeof(u32);
170 	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
171 	if (!action_value->value)
172 		goto err_action_alloc;
173 	return 0;
174 
175 err_action_alloc:
176 	kfree(match_value->value);
177 	return -ENOMEM;
178 }
179 
180 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
181 				   struct devlink_dpipe_entry *entry,
182 				   struct mlxsw_sp_rif *rif,
183 				   bool counters_enabled)
184 {
185 	u32 *action_value;
186 	u32 *rif_value;
187 	u64 cnt;
188 	int err;
189 
190 	/* Set Match RIF index */
191 	rif_value = entry->match_values->value;
192 	*rif_value = mlxsw_sp_rif_index(rif);
193 	entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
194 	entry->match_values->mapping_valid = true;
195 
196 	/* Set Action Forwarding */
197 	action_value = entry->action_values->value;
198 	*action_value = 1;
199 
200 	entry->counter_valid = false;
201 	entry->counter = 0;
202 	if (!counters_enabled)
203 		return 0;
204 
205 	entry->index = mlxsw_sp_rif_index(rif);
206 	err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
207 					     MLXSW_SP_RIF_COUNTER_EGRESS,
208 					     &cnt);
209 	if (!err) {
210 		entry->counter = cnt;
211 		entry->counter_valid = true;
212 	}
213 	return 0;
214 }
215 
216 static int
217 mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled,
218 				 struct devlink_dpipe_dump_ctx *dump_ctx)
219 {
220 	struct devlink_dpipe_value match_value = {{0}}, action_value = {{0}};
221 	struct devlink_dpipe_action action = {0};
222 	struct devlink_dpipe_match match = {0};
223 	struct devlink_dpipe_entry entry = {0};
224 	struct mlxsw_sp *mlxsw_sp = priv;
225 	unsigned int rif_count;
226 	int i, j;
227 	int err;
228 
229 	mlxsw_sp_erif_match_action_prepare(&match, &action);
230 	err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
231 					  &action_value, &action);
232 	if (err)
233 		return err;
234 
235 	rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
236 	rtnl_lock();
237 	i = 0;
238 start_again:
239 	err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
240 	if (err)
241 		return err;
242 	j = 0;
243 	for (; i < rif_count; i++) {
244 		if (!mlxsw_sp->rifs[i])
245 			continue;
246 		err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry,
247 					      mlxsw_sp->rifs[i],
248 					      counters_enabled);
249 		if (err)
250 			goto err_entry_get;
251 		err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
252 		if (err) {
253 			if (err == -EMSGSIZE) {
254 				if (!j)
255 					goto err_entry_append;
256 				break;
257 			}
258 			goto err_entry_append;
259 		}
260 		j++;
261 	}
262 
263 	devlink_dpipe_entry_ctx_close(dump_ctx);
264 	if (i != rif_count)
265 		goto start_again;
266 	rtnl_unlock();
267 
268 	mlxsw_sp_erif_entry_clear(&entry);
269 	return 0;
270 err_entry_append:
271 err_entry_get:
272 	rtnl_unlock();
273 	mlxsw_sp_erif_entry_clear(&entry);
274 	return err;
275 }
276 
277 static int mlxsw_sp_table_erif_counters_update(void *priv, bool enable)
278 {
279 	struct mlxsw_sp *mlxsw_sp = priv;
280 	int i;
281 
282 	rtnl_lock();
283 	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
284 		if (!mlxsw_sp->rifs[i])
285 			continue;
286 		if (enable)
287 			mlxsw_sp_rif_counter_alloc(mlxsw_sp,
288 						   mlxsw_sp->rifs[i],
289 						   MLXSW_SP_RIF_COUNTER_EGRESS);
290 		else
291 			mlxsw_sp_rif_counter_free(mlxsw_sp,
292 						  mlxsw_sp->rifs[i],
293 						  MLXSW_SP_RIF_COUNTER_EGRESS);
294 	}
295 	rtnl_unlock();
296 	return 0;
297 }
298 
299 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
300 	.matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
301 	.actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
302 	.entries_dump = mlxsw_sp_table_erif_entries_dump,
303 	.counters_set_update = mlxsw_sp_table_erif_counters_update,
304 };
305 
306 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
307 {
308 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
309 	u64 table_size;
310 
311 	table_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
312 	return devlink_dpipe_table_register(devlink,
313 					    MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
314 					    &mlxsw_sp_erif_ops,
315 					    mlxsw_sp, table_size,
316 					    false);
317 }
318 
319 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
320 {
321 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
322 
323 	devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
324 }
325 
326 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
327 {
328 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
329 	int err;
330 
331 	err = devlink_dpipe_headers_register(devlink,
332 					     &mlxsw_sp_dpipe_headers);
333 	if (err)
334 		return err;
335 	err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
336 	if (err)
337 		goto err_erif_register;
338 	return 0;
339 
340 err_erif_register:
341 	devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
342 	return err;
343 }
344 
345 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
346 {
347 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
348 
349 	mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
350 	devlink_dpipe_headers_unregister(devlink);
351 }
352