1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
4 #include <linux/kernel.h>
5 #include <net/devlink.h>
8 #include "spectrum_dpipe.h"
9 #include "spectrum_router.h"
11 enum mlxsw_sp_field_metadata_id {
12 MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
13 MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
14 MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
15 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
16 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
17 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
20 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
23 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
25 .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
29 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
34 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
39 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
44 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
48 .name = "adj_hash_index",
49 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
54 enum mlxsw_sp_dpipe_header_id {
55 MLXSW_SP_DPIPE_HEADER_METADATA,
58 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
60 .id = MLXSW_SP_DPIPE_HEADER_METADATA,
61 .fields = mlxsw_sp_dpipe_fields_metadata,
62 .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
65 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
66 &mlxsw_sp_dpipe_header_metadata,
67 &devlink_dpipe_header_ethernet,
68 &devlink_dpipe_header_ipv4,
69 &devlink_dpipe_header_ipv6,
72 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
73 .headers = mlxsw_dpipe_headers,
74 .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
77 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
80 struct devlink_dpipe_action action = {0};
83 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
84 action.header = &mlxsw_sp_dpipe_header_metadata;
85 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
87 err = devlink_dpipe_action_put(skb, &action);
91 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
92 action.header = &mlxsw_sp_dpipe_header_metadata;
93 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
95 return devlink_dpipe_action_put(skb, &action);
98 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
101 struct devlink_dpipe_match match = {0};
103 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
104 match.header = &mlxsw_sp_dpipe_header_metadata;
105 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
107 return devlink_dpipe_match_put(skb, &match);
111 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
112 struct devlink_dpipe_action *action)
114 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
115 action->header = &mlxsw_sp_dpipe_header_metadata;
116 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
118 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
119 match->header = &mlxsw_sp_dpipe_header_metadata;
120 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
123 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
124 struct devlink_dpipe_value *match_value,
125 struct devlink_dpipe_match *match,
126 struct devlink_dpipe_value *action_value,
127 struct devlink_dpipe_action *action)
129 entry->match_values = match_value;
130 entry->match_values_count = 1;
132 entry->action_values = action_value;
133 entry->action_values_count = 1;
135 match_value->match = match;
136 match_value->value_size = sizeof(u32);
137 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
138 if (!match_value->value)
141 action_value->action = action;
142 action_value->value_size = sizeof(u32);
143 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
144 if (!action_value->value)
145 goto err_action_alloc;
149 kfree(match_value->value);
153 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
154 struct devlink_dpipe_entry *entry,
155 struct mlxsw_sp_rif *rif,
156 bool counters_enabled)
163 /* Set Match RIF index */
164 rif_value = entry->match_values->value;
165 *rif_value = mlxsw_sp_rif_index(rif);
166 entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
167 entry->match_values->mapping_valid = true;
169 /* Set Action Forwarding */
170 action_value = entry->action_values->value;
173 entry->counter_valid = false;
175 entry->index = mlxsw_sp_rif_index(rif);
177 if (!counters_enabled)
180 err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
181 MLXSW_SP_RIF_COUNTER_EGRESS,
184 entry->counter = cnt;
185 entry->counter_valid = true;
191 mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
192 struct devlink_dpipe_dump_ctx *dump_ctx)
194 struct devlink_dpipe_value match_value, action_value;
195 struct devlink_dpipe_action action = {0};
196 struct devlink_dpipe_match match = {0};
197 struct devlink_dpipe_entry entry = {0};
198 struct mlxsw_sp *mlxsw_sp = priv;
199 unsigned int rif_count;
203 memset(&match_value, 0, sizeof(match_value));
204 memset(&action_value, 0, sizeof(action_value));
206 mlxsw_sp_erif_match_action_prepare(&match, &action);
207 err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
208 &action_value, &action);
212 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
216 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
218 goto err_ctx_prepare;
220 for (; i < rif_count; i++) {
221 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
223 if (!rif || !mlxsw_sp_rif_dev(rif))
225 err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif,
229 err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
231 if (err == -EMSGSIZE) {
233 goto err_entry_append;
236 goto err_entry_append;
241 devlink_dpipe_entry_ctx_close(dump_ctx);
246 devlink_dpipe_entry_clear(&entry);
252 devlink_dpipe_entry_clear(&entry);
256 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
258 struct mlxsw_sp *mlxsw_sp = priv;
262 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
263 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
268 mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
269 MLXSW_SP_RIF_COUNTER_EGRESS);
271 mlxsw_sp_rif_counter_free(mlxsw_sp, rif,
272 MLXSW_SP_RIF_COUNTER_EGRESS);
278 static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
280 struct mlxsw_sp *mlxsw_sp = priv;
282 return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
285 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
286 .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
287 .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
288 .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
289 .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
290 .size_get = mlxsw_sp_dpipe_table_erif_size_get,
293 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
295 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
297 return devlink_dpipe_table_register(devlink,
298 MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
303 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
305 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
307 devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
310 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
312 struct devlink_dpipe_match match = {0};
315 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
316 match.header = &mlxsw_sp_dpipe_header_metadata;
317 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
319 err = devlink_dpipe_match_put(skb, &match);
325 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
326 match.header = &devlink_dpipe_header_ipv4;
327 match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
330 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
331 match.header = &devlink_dpipe_header_ipv6;
332 match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
339 return devlink_dpipe_match_put(skb, &match);
343 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
345 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
349 mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
351 struct devlink_dpipe_action action = {0};
353 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
354 action.header = &devlink_dpipe_header_ethernet;
355 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
357 return devlink_dpipe_action_put(skb, &action);
360 enum mlxsw_sp_dpipe_table_host_match {
361 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
362 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
363 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
367 mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
368 struct devlink_dpipe_action *action,
371 struct devlink_dpipe_match *match;
373 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
374 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
375 match->header = &mlxsw_sp_dpipe_header_metadata;
376 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
378 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
379 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
382 match->header = &devlink_dpipe_header_ipv4;
383 match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
386 match->header = &devlink_dpipe_header_ipv6;
387 match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
394 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
395 action->header = &devlink_dpipe_header_ethernet;
396 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
400 mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
401 struct devlink_dpipe_value *match_values,
402 struct devlink_dpipe_match *matches,
403 struct devlink_dpipe_value *action_value,
404 struct devlink_dpipe_action *action,
407 struct devlink_dpipe_value *match_value;
408 struct devlink_dpipe_match *match;
410 entry->match_values = match_values;
411 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
413 entry->action_values = action_value;
414 entry->action_values_count = 1;
416 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
417 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
419 match_value->match = match;
420 match_value->value_size = sizeof(u32);
421 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
422 if (!match_value->value)
425 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
426 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
428 match_value->match = match;
431 match_value->value_size = sizeof(u32);
434 match_value->value_size = sizeof(struct in6_addr);
441 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
442 if (!match_value->value)
445 action_value->action = action;
446 action_value->value_size = sizeof(u64);
447 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
448 if (!action_value->value)
455 __mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
456 struct mlxsw_sp_rif *rif,
457 unsigned char *ha, void *dip)
459 struct devlink_dpipe_value *value;
463 /* Set Match RIF index */
464 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
466 rif_value = value->value;
467 *rif_value = mlxsw_sp_rif_index(rif);
468 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
469 value->mapping_valid = true;
472 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
473 memcpy(value->value, dip, value->value_size);
475 /* Set Action DMAC */
476 value = entry->action_values;
477 ha_value = value->value;
478 ether_addr_copy(ha_value, ha);
482 mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
483 struct mlxsw_sp_neigh_entry *neigh_entry,
484 struct mlxsw_sp_rif *rif)
489 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
490 dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
491 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
495 mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
496 struct mlxsw_sp_neigh_entry *neigh_entry,
497 struct mlxsw_sp_rif *rif)
499 struct in6_addr *dip;
502 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
503 dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
505 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
509 mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
510 struct devlink_dpipe_entry *entry,
511 struct mlxsw_sp_neigh_entry *neigh_entry,
512 struct mlxsw_sp_rif *rif,
519 mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
522 mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
529 err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
532 entry->counter_valid = true;
536 mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
537 struct devlink_dpipe_entry *entry,
538 bool counters_enabled,
539 struct devlink_dpipe_dump_ctx *dump_ctx,
542 int rif_neigh_count = 0;
543 int rif_neigh_skip = 0;
551 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
553 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
555 goto err_ctx_prepare;
557 rif_neigh_skip = rif_neigh_count;
558 for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
559 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
560 struct mlxsw_sp_neigh_entry *neigh_entry;
566 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
567 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
569 if (neigh_type != type)
572 if (neigh_type == AF_INET6 &&
573 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
576 if (rif_neigh_count < rif_neigh_skip)
579 mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
582 entry->index = neigh_count;
583 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
585 if (err == -EMSGSIZE) {
587 goto err_entry_append;
591 goto err_entry_append;
601 devlink_dpipe_entry_ctx_close(dump_ctx);
615 mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
616 bool counters_enabled,
617 struct devlink_dpipe_dump_ctx *dump_ctx,
620 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
621 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
622 struct devlink_dpipe_value action_value;
623 struct devlink_dpipe_action action = {0};
624 struct devlink_dpipe_entry entry = {0};
627 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
629 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
630 sizeof(match_values[0]));
631 memset(&action_value, 0, sizeof(action_value));
633 mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
634 err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
635 matches, &action_value,
640 err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
641 counters_enabled, dump_ctx,
644 devlink_dpipe_entry_clear(&entry);
649 mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
650 struct devlink_dpipe_dump_ctx *dump_ctx)
652 struct mlxsw_sp *mlxsw_sp = priv;
654 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
660 mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
661 bool enable, int type)
666 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
667 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
668 struct mlxsw_sp_neigh_entry *neigh_entry;
672 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
673 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
675 if (neigh_type != type)
678 if (neigh_type == AF_INET6 &&
679 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
682 mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
690 static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
692 struct mlxsw_sp *mlxsw_sp = priv;
694 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
699 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
705 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
706 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
707 struct mlxsw_sp_neigh_entry *neigh_entry;
711 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
712 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
714 if (neigh_type != type)
717 if (neigh_type == AF_INET6 &&
718 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
729 static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
731 struct mlxsw_sp *mlxsw_sp = priv;
733 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
736 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
737 .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
738 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
739 .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
740 .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
741 .size_get = mlxsw_sp_dpipe_table_host4_size_get,
744 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1
746 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
748 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
751 err = devlink_dpipe_table_register(devlink,
752 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
758 err = devlink_dpipe_table_resource_set(devlink,
759 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
760 MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
761 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4);
763 goto err_resource_set;
768 devlink_dpipe_table_unregister(devlink,
769 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
773 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
775 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
777 devlink_dpipe_table_unregister(devlink,
778 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
782 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
784 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
788 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
789 struct devlink_dpipe_dump_ctx *dump_ctx)
791 struct mlxsw_sp *mlxsw_sp = priv;
793 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
798 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
800 struct mlxsw_sp *mlxsw_sp = priv;
802 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
806 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
808 struct mlxsw_sp *mlxsw_sp = priv;
810 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
813 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
814 .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
815 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
816 .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
817 .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
818 .size_get = mlxsw_sp_dpipe_table_host6_size_get,
821 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2
823 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
825 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
828 err = devlink_dpipe_table_register(devlink,
829 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
835 err = devlink_dpipe_table_resource_set(devlink,
836 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
837 MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
838 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6);
840 goto err_resource_set;
845 devlink_dpipe_table_unregister(devlink,
846 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
850 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
852 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
854 devlink_dpipe_table_unregister(devlink,
855 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
858 static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
861 struct devlink_dpipe_match match = {0};
864 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
865 match.header = &mlxsw_sp_dpipe_header_metadata;
866 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
868 err = devlink_dpipe_match_put(skb, &match);
872 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
873 match.header = &mlxsw_sp_dpipe_header_metadata;
874 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
876 err = devlink_dpipe_match_put(skb, &match);
880 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
881 match.header = &mlxsw_sp_dpipe_header_metadata;
882 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
884 return devlink_dpipe_match_put(skb, &match);
887 static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
890 struct devlink_dpipe_action action = {0};
893 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
894 action.header = &devlink_dpipe_header_ethernet;
895 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
897 err = devlink_dpipe_action_put(skb, &action);
901 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
902 action.header = &mlxsw_sp_dpipe_header_metadata;
903 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
905 return devlink_dpipe_action_put(skb, &action);
908 static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
910 struct mlxsw_sp_nexthop *nh;
913 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
914 if (mlxsw_sp_nexthop_offload(nh) &&
915 !mlxsw_sp_nexthop_group_has_ipip(nh))
920 enum mlxsw_sp_dpipe_table_adj_match {
921 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
922 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE,
923 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
924 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
927 enum mlxsw_sp_dpipe_table_adj_action {
928 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
929 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
930 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
934 mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
935 struct devlink_dpipe_action *actions)
937 struct devlink_dpipe_action *action;
938 struct devlink_dpipe_match *match;
940 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
941 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
942 match->header = &mlxsw_sp_dpipe_header_metadata;
943 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
945 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
946 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
947 match->header = &mlxsw_sp_dpipe_header_metadata;
948 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
950 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
951 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
952 match->header = &mlxsw_sp_dpipe_header_metadata;
953 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
955 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
956 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
957 action->header = &devlink_dpipe_header_ethernet;
958 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
960 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
961 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
962 action->header = &mlxsw_sp_dpipe_header_metadata;
963 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
967 mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
968 struct devlink_dpipe_value *match_values,
969 struct devlink_dpipe_match *matches,
970 struct devlink_dpipe_value *action_values,
971 struct devlink_dpipe_action *actions)
972 { struct devlink_dpipe_value *action_value;
973 struct devlink_dpipe_value *match_value;
974 struct devlink_dpipe_action *action;
975 struct devlink_dpipe_match *match;
977 entry->match_values = match_values;
978 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
980 entry->action_values = action_values;
981 entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
983 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
984 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
986 match_value->match = match;
987 match_value->value_size = sizeof(u32);
988 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
989 if (!match_value->value)
992 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
993 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
995 match_value->match = match;
996 match_value->value_size = sizeof(u32);
997 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
998 if (!match_value->value)
1001 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1002 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1004 match_value->match = match;
1005 match_value->value_size = sizeof(u32);
1006 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1007 if (!match_value->value)
1010 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1011 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1013 action_value->action = action;
1014 action_value->value_size = sizeof(u64);
1015 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1016 if (!action_value->value)
1019 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1020 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1022 action_value->action = action;
1023 action_value->value_size = sizeof(u32);
1024 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1025 if (!action_value->value)
1032 __mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
1033 u32 adj_index, u32 adj_size,
1034 u32 adj_hash_index, unsigned char *ha,
1035 struct mlxsw_sp_rif *rif)
1037 struct devlink_dpipe_value *value;
1041 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1042 p_index = value->value;
1043 *p_index = adj_index;
1045 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
1046 p_index = value->value;
1047 *p_index = adj_size;
1049 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1050 p_index = value->value;
1051 *p_index = adj_hash_index;
1053 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1054 ether_addr_copy(value->value, ha);
1056 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1057 p_rif_value = value->value;
1058 *p_rif_value = mlxsw_sp_rif_index(rif);
1059 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
1060 value->mapping_valid = true;
1063 static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
1064 struct mlxsw_sp_nexthop *nh,
1065 struct devlink_dpipe_entry *entry)
1067 struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
1068 unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
1069 u32 adj_hash_index = 0;
1074 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index);
1075 __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size,
1076 adj_hash_index, ha, rif);
1077 err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
1079 entry->counter_valid = true;
1083 mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
1084 struct devlink_dpipe_entry *entry,
1085 bool counters_enabled,
1086 struct devlink_dpipe_dump_ctx *dump_ctx)
1088 struct mlxsw_sp_nexthop *nh;
1089 int entry_index = 0;
1097 nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1099 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
1101 goto err_ctx_prepare;
1105 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1106 if (!mlxsw_sp_nexthop_offload(nh) ||
1107 mlxsw_sp_nexthop_group_has_ipip(nh))
1110 if (nh_count < nh_skip)
1113 mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
1114 entry->index = entry_index;
1115 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
1117 if (err == -EMSGSIZE) {
1119 goto err_entry_append;
1122 goto err_entry_append;
1130 devlink_dpipe_entry_ctx_close(dump_ctx);
1131 if (nh_count != nh_count_max)
1144 mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
1145 struct devlink_dpipe_dump_ctx *dump_ctx)
1147 struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1148 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1149 struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1150 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1151 struct devlink_dpipe_entry entry = {0};
1152 struct mlxsw_sp *mlxsw_sp = priv;
1155 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1156 sizeof(matches[0]));
1157 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1158 sizeof(match_values[0]));
1159 memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1160 sizeof(actions[0]));
1161 memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1162 sizeof(action_values[0]));
1164 mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
1165 err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
1166 match_values, matches,
1167 action_values, actions);
1171 err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
1172 counters_enabled, dump_ctx);
1174 devlink_dpipe_entry_clear(&entry);
1178 static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
1180 struct mlxsw_sp *mlxsw_sp = priv;
1181 struct mlxsw_sp_nexthop *nh;
1182 u32 adj_hash_index = 0;
1186 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1187 if (!mlxsw_sp_nexthop_offload(nh) ||
1188 mlxsw_sp_nexthop_group_has_ipip(nh))
1191 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size,
1194 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
1196 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
1197 mlxsw_sp_nexthop_update(mlxsw_sp,
1198 adj_index + adj_hash_index, nh);
1204 mlxsw_sp_dpipe_table_adj_size_get(void *priv)
1206 struct mlxsw_sp *mlxsw_sp = priv;
1210 size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1216 static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
1217 .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
1218 .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
1219 .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
1220 .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
1221 .size_get = mlxsw_sp_dpipe_table_adj_size_get,
1224 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
1226 static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
1228 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1231 err = devlink_dpipe_table_register(devlink,
1232 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1233 &mlxsw_sp_dpipe_table_adj_ops,
1238 err = devlink_dpipe_table_resource_set(devlink,
1239 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1240 MLXSW_SP_RESOURCE_KVD_LINEAR,
1241 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ);
1243 goto err_resource_set;
1248 devlink_dpipe_table_unregister(devlink,
1249 MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1253 static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
1255 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1257 devlink_dpipe_table_unregister(devlink,
1258 MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1261 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
1263 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1266 err = devlink_dpipe_headers_register(devlink,
1267 &mlxsw_sp_dpipe_headers);
1270 err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
1272 goto err_erif_table_init;
1274 err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
1276 goto err_host4_table_init;
1278 err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
1280 goto err_host6_table_init;
1282 err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
1284 goto err_adj_table_init;
1288 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1289 err_host6_table_init:
1290 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1291 err_host4_table_init:
1292 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1293 err_erif_table_init:
1294 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
1298 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
1300 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1302 mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
1303 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1304 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1305 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1306 devlink_dpipe_headers_unregister(devlink);