xref: /openbmc/linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c (revision 28efb0046512e8a13ed9f9bdf0d68d10bbfbe9cf)
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 	MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
47 	MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
48 };
49 
50 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
51 	{
52 		.name = "erif_port",
53 		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
54 		.bitwidth = 32,
55 		.mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
56 	},
57 	{
58 		.name = "l3_forward",
59 		.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
60 		.bitwidth = 1,
61 	},
62 	{
63 		.name = "l3_drop",
64 		.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
65 		.bitwidth = 1,
66 	},
67 	{
68 		.name = "adj_index",
69 		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
70 		.bitwidth = 32,
71 	},
72 	{
73 		.name = "adj_hash_index",
74 		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
75 		.bitwidth = 32,
76 	},
77 };
78 
79 enum mlxsw_sp_dpipe_header_id {
80 	MLXSW_SP_DPIPE_HEADER_METADATA,
81 };
82 
83 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
84 	.name = "mlxsw_meta",
85 	.id = MLXSW_SP_DPIPE_HEADER_METADATA,
86 	.fields = mlxsw_sp_dpipe_fields_metadata,
87 	.fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
88 };
89 
90 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
91 	&mlxsw_sp_dpipe_header_metadata,
92 	&devlink_dpipe_header_ethernet,
93 	&devlink_dpipe_header_ipv4,
94 	&devlink_dpipe_header_ipv6,
95 };
96 
97 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
98 	.headers = mlxsw_dpipe_headers,
99 	.headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
100 };
101 
102 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
103 						  struct sk_buff *skb)
104 {
105 	struct devlink_dpipe_action action = {0};
106 	int err;
107 
108 	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
109 	action.header = &mlxsw_sp_dpipe_header_metadata;
110 	action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
111 
112 	err = devlink_dpipe_action_put(skb, &action);
113 	if (err)
114 		return err;
115 
116 	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
117 	action.header = &mlxsw_sp_dpipe_header_metadata;
118 	action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
119 
120 	return devlink_dpipe_action_put(skb, &action);
121 }
122 
123 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
124 						  struct sk_buff *skb)
125 {
126 	struct devlink_dpipe_match match = {0};
127 
128 	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
129 	match.header = &mlxsw_sp_dpipe_header_metadata;
130 	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
131 
132 	return devlink_dpipe_match_put(skb, &match);
133 }
134 
135 static void
136 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
137 				   struct devlink_dpipe_action *action)
138 {
139 	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
140 	action->header = &mlxsw_sp_dpipe_header_metadata;
141 	action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
142 
143 	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
144 	match->header = &mlxsw_sp_dpipe_header_metadata;
145 	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
146 }
147 
148 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
149 				       struct devlink_dpipe_value *match_value,
150 				       struct devlink_dpipe_match *match,
151 				       struct devlink_dpipe_value *action_value,
152 				       struct devlink_dpipe_action *action)
153 {
154 	entry->match_values = match_value;
155 	entry->match_values_count = 1;
156 
157 	entry->action_values = action_value;
158 	entry->action_values_count = 1;
159 
160 	match_value->match = match;
161 	match_value->value_size = sizeof(u32);
162 	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
163 	if (!match_value->value)
164 		return -ENOMEM;
165 
166 	action_value->action = action;
167 	action_value->value_size = sizeof(u32);
168 	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
169 	if (!action_value->value)
170 		goto err_action_alloc;
171 	return 0;
172 
173 err_action_alloc:
174 	kfree(match_value->value);
175 	return -ENOMEM;
176 }
177 
178 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
179 				   struct devlink_dpipe_entry *entry,
180 				   struct mlxsw_sp_rif *rif,
181 				   bool counters_enabled)
182 {
183 	u32 *action_value;
184 	u32 *rif_value;
185 	u64 cnt;
186 	int err;
187 
188 	/* Set Match RIF index */
189 	rif_value = entry->match_values->value;
190 	*rif_value = mlxsw_sp_rif_index(rif);
191 	entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
192 	entry->match_values->mapping_valid = true;
193 
194 	/* Set Action Forwarding */
195 	action_value = entry->action_values->value;
196 	*action_value = 1;
197 
198 	entry->counter_valid = false;
199 	entry->counter = 0;
200 	entry->index = mlxsw_sp_rif_index(rif);
201 
202 	if (!counters_enabled)
203 		return 0;
204 
205 	err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
206 					     MLXSW_SP_RIF_COUNTER_EGRESS,
207 					     &cnt);
208 	if (!err) {
209 		entry->counter = cnt;
210 		entry->counter_valid = true;
211 	}
212 	return 0;
213 }
214 
215 static int
216 mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
217 				       struct devlink_dpipe_dump_ctx *dump_ctx)
218 {
219 	struct devlink_dpipe_value match_value, action_value;
220 	struct devlink_dpipe_action action = {0};
221 	struct devlink_dpipe_match match = {0};
222 	struct devlink_dpipe_entry entry = {0};
223 	struct mlxsw_sp *mlxsw_sp = priv;
224 	unsigned int rif_count;
225 	int i, j;
226 	int err;
227 
228 	memset(&match_value, 0, sizeof(match_value));
229 	memset(&action_value, 0, sizeof(action_value));
230 
231 	mlxsw_sp_erif_match_action_prepare(&match, &action);
232 	err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
233 					  &action_value, &action);
234 	if (err)
235 		return err;
236 
237 	rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
238 	rtnl_lock();
239 	i = 0;
240 start_again:
241 	err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
242 	if (err)
243 		return err;
244 	j = 0;
245 	for (; i < rif_count; i++) {
246 		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
247 
248 		if (!rif)
249 			continue;
250 		err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif,
251 					      counters_enabled);
252 		if (err)
253 			goto err_entry_get;
254 		err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
255 		if (err) {
256 			if (err == -EMSGSIZE) {
257 				if (!j)
258 					goto err_entry_append;
259 				break;
260 			}
261 			goto err_entry_append;
262 		}
263 		j++;
264 	}
265 
266 	devlink_dpipe_entry_ctx_close(dump_ctx);
267 	if (i != rif_count)
268 		goto start_again;
269 	rtnl_unlock();
270 
271 	devlink_dpipe_entry_clear(&entry);
272 	return 0;
273 err_entry_append:
274 err_entry_get:
275 	rtnl_unlock();
276 	devlink_dpipe_entry_clear(&entry);
277 	return err;
278 }
279 
280 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
281 {
282 	struct mlxsw_sp *mlxsw_sp = priv;
283 	int i;
284 
285 	rtnl_lock();
286 	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
287 		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
288 
289 		if (!rif)
290 			continue;
291 		if (enable)
292 			mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
293 						   MLXSW_SP_RIF_COUNTER_EGRESS);
294 		else
295 			mlxsw_sp_rif_counter_free(mlxsw_sp, rif,
296 						  MLXSW_SP_RIF_COUNTER_EGRESS);
297 	}
298 	rtnl_unlock();
299 	return 0;
300 }
301 
302 static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
303 {
304 	struct mlxsw_sp *mlxsw_sp = priv;
305 
306 	return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
307 }
308 
309 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
310 	.matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
311 	.actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
312 	.entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
313 	.counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
314 	.size_get = mlxsw_sp_dpipe_table_erif_size_get,
315 };
316 
317 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
318 {
319 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
320 
321 	return devlink_dpipe_table_register(devlink,
322 					    MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
323 					    &mlxsw_sp_erif_ops,
324 					    mlxsw_sp, false);
325 }
326 
327 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
328 {
329 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
330 
331 	devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
332 }
333 
334 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
335 {
336 	struct devlink_dpipe_match match = {0};
337 	int err;
338 
339 	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
340 	match.header = &mlxsw_sp_dpipe_header_metadata;
341 	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
342 
343 	err = devlink_dpipe_match_put(skb, &match);
344 	if (err)
345 		return err;
346 
347 	switch (type) {
348 	case AF_INET:
349 		match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
350 		match.header = &devlink_dpipe_header_ipv4;
351 		match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
352 		break;
353 	case AF_INET6:
354 		match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
355 		match.header = &devlink_dpipe_header_ipv6;
356 		match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
357 		break;
358 	default:
359 		WARN_ON(1);
360 		return -EINVAL;
361 	}
362 
363 	return devlink_dpipe_match_put(skb, &match);
364 }
365 
366 static int
367 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
368 {
369 	return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
370 }
371 
372 static int
373 mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
374 {
375 	struct devlink_dpipe_action action = {0};
376 
377 	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
378 	action.header = &devlink_dpipe_header_ethernet;
379 	action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
380 
381 	return devlink_dpipe_action_put(skb, &action);
382 }
383 
384 enum mlxsw_sp_dpipe_table_host_match {
385 	MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
386 	MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
387 	MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
388 };
389 
390 static void
391 mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
392 					       struct devlink_dpipe_action *action,
393 					       int type)
394 {
395 	struct devlink_dpipe_match *match;
396 
397 	match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
398 	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
399 	match->header = &mlxsw_sp_dpipe_header_metadata;
400 	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
401 
402 	match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
403 	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
404 	switch (type) {
405 	case AF_INET:
406 		match->header = &devlink_dpipe_header_ipv4;
407 		match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
408 		break;
409 	case AF_INET6:
410 		match->header = &devlink_dpipe_header_ipv6;
411 		match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
412 		break;
413 	default:
414 		WARN_ON(1);
415 		return;
416 	}
417 
418 	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
419 	action->header = &devlink_dpipe_header_ethernet;
420 	action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
421 }
422 
423 static int
424 mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
425 					struct devlink_dpipe_value *match_values,
426 					struct devlink_dpipe_match *matches,
427 					struct devlink_dpipe_value *action_value,
428 					struct devlink_dpipe_action *action,
429 					int type)
430 {
431 	struct devlink_dpipe_value *match_value;
432 	struct devlink_dpipe_match *match;
433 
434 	entry->match_values = match_values;
435 	entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
436 
437 	entry->action_values = action_value;
438 	entry->action_values_count = 1;
439 
440 	match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
441 	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
442 
443 	match_value->match = match;
444 	match_value->value_size = sizeof(u32);
445 	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
446 	if (!match_value->value)
447 		return -ENOMEM;
448 
449 	match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
450 	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
451 
452 	match_value->match = match;
453 	switch (type) {
454 	case AF_INET:
455 		match_value->value_size = sizeof(u32);
456 		break;
457 	case AF_INET6:
458 		match_value->value_size = sizeof(struct in6_addr);
459 		break;
460 	default:
461 		WARN_ON(1);
462 		return -EINVAL;
463 	}
464 
465 	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
466 	if (!match_value->value)
467 		return -ENOMEM;
468 
469 	action_value->action = action;
470 	action_value->value_size = sizeof(u64);
471 	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
472 	if (!action_value->value)
473 		return -ENOMEM;
474 
475 	return 0;
476 }
477 
478 static void
479 __mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
480 				       struct mlxsw_sp_rif *rif,
481 				       unsigned char *ha, void *dip)
482 {
483 	struct devlink_dpipe_value *value;
484 	u32 *rif_value;
485 	u8 *ha_value;
486 
487 	/* Set Match RIF index */
488 	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
489 
490 	rif_value = value->value;
491 	*rif_value = mlxsw_sp_rif_index(rif);
492 	value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
493 	value->mapping_valid = true;
494 
495 	/* Set Match DIP */
496 	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
497 	memcpy(value->value, dip, value->value_size);
498 
499 	/* Set Action DMAC */
500 	value = entry->action_values;
501 	ha_value = value->value;
502 	ether_addr_copy(ha_value, ha);
503 }
504 
505 static void
506 mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
507 				      struct mlxsw_sp_neigh_entry *neigh_entry,
508 				      struct mlxsw_sp_rif *rif)
509 {
510 	unsigned char *ha;
511 	u32 dip;
512 
513 	ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
514 	dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
515 	__mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
516 }
517 
518 static void
519 mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
520 				      struct mlxsw_sp_neigh_entry *neigh_entry,
521 				      struct mlxsw_sp_rif *rif)
522 {
523 	struct in6_addr *dip;
524 	unsigned char *ha;
525 
526 	ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
527 	dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
528 
529 	__mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
530 }
531 
532 static void
533 mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
534 				     struct devlink_dpipe_entry *entry,
535 				     struct mlxsw_sp_neigh_entry *neigh_entry,
536 				     struct mlxsw_sp_rif *rif,
537 				     int type)
538 {
539 	int err;
540 
541 	switch (type) {
542 	case AF_INET:
543 		mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
544 		break;
545 	case AF_INET6:
546 		mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
547 		break;
548 	default:
549 		WARN_ON(1);
550 		return;
551 	}
552 
553 	err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
554 					 &entry->counter);
555 	if (!err)
556 		entry->counter_valid = true;
557 }
558 
559 static int
560 mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
561 				      struct devlink_dpipe_entry *entry,
562 				      bool counters_enabled,
563 				      struct devlink_dpipe_dump_ctx *dump_ctx,
564 				      int type)
565 {
566 	int rif_neigh_count = 0;
567 	int rif_neigh_skip = 0;
568 	int neigh_count = 0;
569 	int rif_count;
570 	int i, j;
571 	int err;
572 
573 	rtnl_lock();
574 	i = 0;
575 	rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
576 start_again:
577 	err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
578 	if (err)
579 		goto err_ctx_prepare;
580 	j = 0;
581 	rif_neigh_skip = rif_neigh_count;
582 	for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
583 		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
584 		struct mlxsw_sp_neigh_entry *neigh_entry;
585 
586 		if (!rif)
587 			continue;
588 
589 		rif_neigh_count = 0;
590 		mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
591 			int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
592 
593 			if (neigh_type != type)
594 				continue;
595 
596 			if (neigh_type == AF_INET6 &&
597 			    mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
598 				continue;
599 
600 			if (rif_neigh_count < rif_neigh_skip)
601 				goto skip;
602 
603 			mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
604 							     neigh_entry, rif,
605 							     type);
606 			entry->index = neigh_count;
607 			err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
608 			if (err) {
609 				if (err == -EMSGSIZE) {
610 					if (!j)
611 						goto err_entry_append;
612 					else
613 						goto out;
614 				}
615 				goto err_entry_append;
616 			}
617 			neigh_count++;
618 			j++;
619 skip:
620 			rif_neigh_count++;
621 		}
622 		rif_neigh_skip = 0;
623 	}
624 out:
625 	devlink_dpipe_entry_ctx_close(dump_ctx);
626 	if (i != rif_count)
627 		goto start_again;
628 
629 	rtnl_unlock();
630 	return 0;
631 
632 err_ctx_prepare:
633 err_entry_append:
634 	rtnl_unlock();
635 	return err;
636 }
637 
638 static int
639 mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
640 				       bool counters_enabled,
641 				       struct devlink_dpipe_dump_ctx *dump_ctx,
642 				       int type)
643 {
644 	struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
645 	struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
646 	struct devlink_dpipe_value action_value;
647 	struct devlink_dpipe_action action = {0};
648 	struct devlink_dpipe_entry entry = {0};
649 	int err;
650 
651 	memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
652 			   sizeof(matches[0]));
653 	memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
654 				sizeof(match_values[0]));
655 	memset(&action_value, 0, sizeof(action_value));
656 
657 	mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
658 	err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
659 						      matches, &action_value,
660 						      &action, type);
661 	if (err)
662 		goto out;
663 
664 	err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
665 						    counters_enabled, dump_ctx,
666 						    type);
667 out:
668 	devlink_dpipe_entry_clear(&entry);
669 	return err;
670 }
671 
672 static int
673 mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
674 					struct devlink_dpipe_dump_ctx *dump_ctx)
675 {
676 	struct mlxsw_sp *mlxsw_sp = priv;
677 
678 	return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
679 						      counters_enabled,
680 						      dump_ctx, AF_INET);
681 }
682 
683 static void
684 mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
685 					  bool enable, int type)
686 {
687 	int i;
688 
689 	rtnl_lock();
690 	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
691 		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
692 		struct mlxsw_sp_neigh_entry *neigh_entry;
693 
694 		if (!rif)
695 			continue;
696 		mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
697 			int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
698 
699 			if (neigh_type != type)
700 				continue;
701 
702 			if (neigh_type == AF_INET6 &&
703 			    mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
704 				continue;
705 
706 			mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
707 							    neigh_entry,
708 							    enable);
709 		}
710 	}
711 	rtnl_unlock();
712 }
713 
714 static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
715 {
716 	struct mlxsw_sp *mlxsw_sp = priv;
717 
718 	mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
719 	return 0;
720 }
721 
722 static u64
723 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
724 {
725 	u64 size = 0;
726 	int i;
727 
728 	rtnl_lock();
729 	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
730 		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
731 		struct mlxsw_sp_neigh_entry *neigh_entry;
732 
733 		if (!rif)
734 			continue;
735 		mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
736 			int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
737 
738 			if (neigh_type != type)
739 				continue;
740 
741 			if (neigh_type == AF_INET6 &&
742 			    mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
743 				continue;
744 
745 			size++;
746 		}
747 	}
748 	rtnl_unlock();
749 
750 	return size;
751 }
752 
753 static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
754 {
755 	struct mlxsw_sp *mlxsw_sp = priv;
756 
757 	return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
758 }
759 
760 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
761 	.matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
762 	.actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
763 	.entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
764 	.counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
765 	.size_get = mlxsw_sp_dpipe_table_host4_size_get,
766 };
767 
768 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
769 {
770 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
771 
772 	return devlink_dpipe_table_register(devlink,
773 					    MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
774 					    &mlxsw_sp_host4_ops,
775 					    mlxsw_sp, false);
776 }
777 
778 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
779 {
780 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
781 
782 	devlink_dpipe_table_unregister(devlink,
783 				       MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
784 }
785 
786 static int
787 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
788 {
789 	return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
790 }
791 
792 static int
793 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
794 					struct devlink_dpipe_dump_ctx *dump_ctx)
795 {
796 	struct mlxsw_sp *mlxsw_sp = priv;
797 
798 	return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
799 						      counters_enabled,
800 						      dump_ctx, AF_INET6);
801 }
802 
803 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
804 {
805 	struct mlxsw_sp *mlxsw_sp = priv;
806 
807 	mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
808 	return 0;
809 }
810 
811 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
812 {
813 	struct mlxsw_sp *mlxsw_sp = priv;
814 
815 	return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
816 }
817 
818 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
819 	.matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
820 	.actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
821 	.entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
822 	.counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
823 	.size_get = mlxsw_sp_dpipe_table_host6_size_get,
824 };
825 
826 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
827 {
828 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
829 
830 	return devlink_dpipe_table_register(devlink,
831 					    MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
832 					    &mlxsw_sp_host6_ops,
833 					    mlxsw_sp, false);
834 }
835 
836 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
837 {
838 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
839 
840 	devlink_dpipe_table_unregister(devlink,
841 				       MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
842 }
843 
844 static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
845 						 struct sk_buff *skb)
846 {
847 	struct devlink_dpipe_match match = {0};
848 	int err;
849 
850 	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
851 	match.header = &mlxsw_sp_dpipe_header_metadata;
852 	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
853 
854 	err = devlink_dpipe_match_put(skb, &match);
855 	if (err)
856 		return err;
857 
858 	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
859 	match.header = &mlxsw_sp_dpipe_header_metadata;
860 	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
861 
862 	return devlink_dpipe_match_put(skb, &match);
863 }
864 
865 static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
866 						 struct sk_buff *skb)
867 {
868 	struct devlink_dpipe_action action = {0};
869 	int err;
870 
871 	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
872 	action.header = &devlink_dpipe_header_ethernet;
873 	action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
874 
875 	err = devlink_dpipe_action_put(skb, &action);
876 	if (err)
877 		return err;
878 
879 	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
880 	action.header = &mlxsw_sp_dpipe_header_metadata;
881 	action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
882 
883 	return devlink_dpipe_action_put(skb, &action);
884 }
885 
886 static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
887 {
888 	struct mlxsw_sp_nexthop *nh;
889 	u64 size = 0;
890 
891 	mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
892 		if (mlxsw_sp_nexthop_offload(nh) &&
893 		    !mlxsw_sp_nexthop_group_has_ipip(nh))
894 			size++;
895 	return size;
896 }
897 
898 enum mlxsw_sp_dpipe_table_adj_match {
899 	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
900 	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
901 	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
902 };
903 
904 enum mlxsw_sp_dpipe_table_adj_action {
905 	MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
906 	MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
907 	MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
908 };
909 
910 static void
911 mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
912 					      struct devlink_dpipe_action *actions)
913 {
914 	struct devlink_dpipe_action *action;
915 	struct devlink_dpipe_match *match;
916 
917 	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
918 	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
919 	match->header = &mlxsw_sp_dpipe_header_metadata;
920 	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
921 
922 	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
923 	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
924 	match->header = &mlxsw_sp_dpipe_header_metadata;
925 	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
926 
927 	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
928 	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
929 	action->header = &devlink_dpipe_header_ethernet;
930 	action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
931 
932 	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
933 	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
934 	action->header = &mlxsw_sp_dpipe_header_metadata;
935 	action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
936 }
937 
938 static int
939 mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
940 				       struct devlink_dpipe_value *match_values,
941 				       struct devlink_dpipe_match *matches,
942 				       struct devlink_dpipe_value *action_values,
943 				       struct devlink_dpipe_action *actions)
944 {	struct devlink_dpipe_value *action_value;
945 	struct devlink_dpipe_value *match_value;
946 	struct devlink_dpipe_action *action;
947 	struct devlink_dpipe_match *match;
948 
949 	entry->match_values = match_values;
950 	entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
951 
952 	entry->action_values = action_values;
953 	entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
954 
955 	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
956 	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
957 
958 	match_value->match = match;
959 	match_value->value_size = sizeof(u32);
960 	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
961 	if (!match_value->value)
962 		return -ENOMEM;
963 
964 	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
965 	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
966 
967 	match_value->match = match;
968 	match_value->value_size = sizeof(u32);
969 	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
970 	if (!match_value->value)
971 		return -ENOMEM;
972 
973 	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
974 	action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
975 
976 	action_value->action = action;
977 	action_value->value_size = sizeof(u64);
978 	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
979 	if (!action_value->value)
980 		return -ENOMEM;
981 
982 	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
983 	action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
984 
985 	action_value->action = action;
986 	action_value->value_size = sizeof(u32);
987 	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
988 	if (!action_value->value)
989 		return -ENOMEM;
990 
991 	return 0;
992 }
993 
994 static void
995 __mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
996 				      u32 adj_index, u32 adj_hash_index,
997 				      unsigned char *ha,
998 				      struct mlxsw_sp_rif *rif)
999 {
1000 	struct devlink_dpipe_value *value;
1001 	u32 *p_rif_value;
1002 	u32 *p_index;
1003 
1004 	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1005 	p_index = value->value;
1006 	*p_index = adj_index;
1007 
1008 	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1009 	p_index = value->value;
1010 	*p_index = adj_hash_index;
1011 
1012 	value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1013 	ether_addr_copy(value->value, ha);
1014 
1015 	value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1016 	p_rif_value = value->value;
1017 	*p_rif_value = mlxsw_sp_rif_index(rif);
1018 	value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
1019 	value->mapping_valid = true;
1020 }
1021 
1022 static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
1023 						struct mlxsw_sp_nexthop *nh,
1024 						struct devlink_dpipe_entry *entry)
1025 {
1026 	struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
1027 	unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
1028 	u32 adj_hash_index = 0;
1029 	u32 adj_index = 0;
1030 	int err;
1031 
1032 	mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_hash_index);
1033 	__mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index,
1034 					      adj_hash_index, ha, rif);
1035 	err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
1036 	if (!err)
1037 		entry->counter_valid = true;
1038 }
1039 
1040 static int
1041 mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
1042 				     struct devlink_dpipe_entry *entry,
1043 				     bool counters_enabled,
1044 				     struct devlink_dpipe_dump_ctx *dump_ctx)
1045 {
1046 	struct mlxsw_sp_nexthop *nh;
1047 	int entry_index = 0;
1048 	int nh_count_max;
1049 	int nh_count = 0;
1050 	int nh_skip;
1051 	int j;
1052 	int err;
1053 
1054 	rtnl_lock();
1055 	nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1056 start_again:
1057 	err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
1058 	if (err)
1059 		goto err_ctx_prepare;
1060 	j = 0;
1061 	nh_skip = nh_count;
1062 	mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1063 		if (!mlxsw_sp_nexthop_offload(nh) ||
1064 		    mlxsw_sp_nexthop_group_has_ipip(nh))
1065 			continue;
1066 
1067 		if (nh_count < nh_skip)
1068 			goto skip;
1069 
1070 		mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
1071 		entry->index = entry_index;
1072 		err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
1073 		if (err) {
1074 			if (err == -EMSGSIZE) {
1075 				if (!j)
1076 					goto err_entry_append;
1077 				break;
1078 			}
1079 			goto err_entry_append;
1080 		}
1081 		entry_index++;
1082 		j++;
1083 skip:
1084 		nh_count++;
1085 	}
1086 
1087 	devlink_dpipe_entry_ctx_close(dump_ctx);
1088 	if (nh_count != nh_count_max)
1089 		goto start_again;
1090 	rtnl_unlock();
1091 
1092 	return 0;
1093 
1094 err_ctx_prepare:
1095 err_entry_append:
1096 	rtnl_unlock();
1097 	return err;
1098 }
1099 
1100 static int
1101 mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
1102 				      struct devlink_dpipe_dump_ctx *dump_ctx)
1103 {
1104 	struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1105 	struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1106 	struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1107 	struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1108 	struct devlink_dpipe_entry entry = {0};
1109 	struct mlxsw_sp *mlxsw_sp = priv;
1110 	int err;
1111 
1112 	memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1113 			   sizeof(matches[0]));
1114 	memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1115 				sizeof(match_values[0]));
1116 	memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1117 			   sizeof(actions[0]));
1118 	memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1119 				 sizeof(action_values[0]));
1120 
1121 	mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
1122 	err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
1123 						     match_values, matches,
1124 						     action_values, actions);
1125 	if (err)
1126 		goto out;
1127 
1128 	err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
1129 						   counters_enabled, dump_ctx);
1130 out:
1131 	devlink_dpipe_entry_clear(&entry);
1132 	return err;
1133 }
1134 
1135 static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
1136 {
1137 	struct mlxsw_sp *mlxsw_sp = priv;
1138 	struct mlxsw_sp_nexthop *nh;
1139 	u32 adj_hash_index = 0;
1140 	u32 adj_index = 0;
1141 
1142 	mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1143 		if (!mlxsw_sp_nexthop_offload(nh) ||
1144 		    mlxsw_sp_nexthop_group_has_ipip(nh))
1145 			continue;
1146 
1147 		mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_hash_index);
1148 		if (enable)
1149 			mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
1150 		else
1151 			mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
1152 		mlxsw_sp_nexthop_update(mlxsw_sp,
1153 					adj_index + adj_hash_index, nh);
1154 	}
1155 	return 0;
1156 }
1157 
1158 static u64
1159 mlxsw_sp_dpipe_table_adj_size_get(void *priv)
1160 {
1161 	struct mlxsw_sp *mlxsw_sp = priv;
1162 	u64 size;
1163 
1164 	rtnl_lock();
1165 	size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1166 	rtnl_unlock();
1167 
1168 	return size;
1169 }
1170 
1171 static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
1172 	.matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
1173 	.actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
1174 	.entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
1175 	.counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
1176 	.size_get = mlxsw_sp_dpipe_table_adj_size_get,
1177 };
1178 
1179 static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
1180 {
1181 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1182 
1183 	return devlink_dpipe_table_register(devlink,
1184 					    MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1185 					    &mlxsw_sp_dpipe_table_adj_ops,
1186 					    mlxsw_sp, false);
1187 }
1188 
1189 static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
1190 {
1191 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1192 
1193 	devlink_dpipe_table_unregister(devlink,
1194 				       MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1195 }
1196 
1197 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
1198 {
1199 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1200 	int err;
1201 
1202 	err = devlink_dpipe_headers_register(devlink,
1203 					     &mlxsw_sp_dpipe_headers);
1204 	if (err)
1205 		return err;
1206 	err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
1207 	if (err)
1208 		goto err_erif_table_init;
1209 
1210 	err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
1211 	if (err)
1212 		goto err_host4_table_init;
1213 
1214 	err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
1215 	if (err)
1216 		goto err_host6_table_init;
1217 
1218 	err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
1219 	if (err)
1220 		goto err_adj_table_init;
1221 
1222 	return 0;
1223 err_adj_table_init:
1224 	mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1225 err_host6_table_init:
1226 	mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1227 err_host4_table_init:
1228 	mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1229 err_erif_table_init:
1230 	devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
1231 	return err;
1232 }
1233 
1234 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
1235 {
1236 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1237 
1238 	mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
1239 	mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1240 	mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1241 	mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1242 	devlink_dpipe_headers_unregister(devlink);
1243 }
1244