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);
220 for (; i < rif_count; i++) {
221 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
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);
251 devlink_dpipe_entry_clear(&entry);
255 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
257 struct mlxsw_sp *mlxsw_sp = priv;
261 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
262 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
267 mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
268 MLXSW_SP_RIF_COUNTER_EGRESS);
270 mlxsw_sp_rif_counter_free(mlxsw_sp, rif,
271 MLXSW_SP_RIF_COUNTER_EGRESS);
277 static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
279 struct mlxsw_sp *mlxsw_sp = priv;
281 return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
284 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
285 .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
286 .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
287 .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
288 .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
289 .size_get = mlxsw_sp_dpipe_table_erif_size_get,
292 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
294 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
296 return devlink_dpipe_table_register(devlink,
297 MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
302 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
304 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
306 devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
309 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
311 struct devlink_dpipe_match match = {0};
314 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
315 match.header = &mlxsw_sp_dpipe_header_metadata;
316 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
318 err = devlink_dpipe_match_put(skb, &match);
324 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
325 match.header = &devlink_dpipe_header_ipv4;
326 match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
329 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
330 match.header = &devlink_dpipe_header_ipv6;
331 match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
338 return devlink_dpipe_match_put(skb, &match);
342 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
344 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
348 mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
350 struct devlink_dpipe_action action = {0};
352 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
353 action.header = &devlink_dpipe_header_ethernet;
354 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
356 return devlink_dpipe_action_put(skb, &action);
359 enum mlxsw_sp_dpipe_table_host_match {
360 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
361 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
362 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
366 mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
367 struct devlink_dpipe_action *action,
370 struct devlink_dpipe_match *match;
372 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
373 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
374 match->header = &mlxsw_sp_dpipe_header_metadata;
375 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
377 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
378 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
381 match->header = &devlink_dpipe_header_ipv4;
382 match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
385 match->header = &devlink_dpipe_header_ipv6;
386 match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
393 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
394 action->header = &devlink_dpipe_header_ethernet;
395 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
399 mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
400 struct devlink_dpipe_value *match_values,
401 struct devlink_dpipe_match *matches,
402 struct devlink_dpipe_value *action_value,
403 struct devlink_dpipe_action *action,
406 struct devlink_dpipe_value *match_value;
407 struct devlink_dpipe_match *match;
409 entry->match_values = match_values;
410 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
412 entry->action_values = action_value;
413 entry->action_values_count = 1;
415 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
416 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
418 match_value->match = match;
419 match_value->value_size = sizeof(u32);
420 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
421 if (!match_value->value)
424 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
425 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
427 match_value->match = match;
430 match_value->value_size = sizeof(u32);
433 match_value->value_size = sizeof(struct in6_addr);
440 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
441 if (!match_value->value)
444 action_value->action = action;
445 action_value->value_size = sizeof(u64);
446 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
447 if (!action_value->value)
454 __mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
455 struct mlxsw_sp_rif *rif,
456 unsigned char *ha, void *dip)
458 struct devlink_dpipe_value *value;
462 /* Set Match RIF index */
463 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
465 rif_value = value->value;
466 *rif_value = mlxsw_sp_rif_index(rif);
467 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
468 value->mapping_valid = true;
471 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
472 memcpy(value->value, dip, value->value_size);
474 /* Set Action DMAC */
475 value = entry->action_values;
476 ha_value = value->value;
477 ether_addr_copy(ha_value, ha);
481 mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
482 struct mlxsw_sp_neigh_entry *neigh_entry,
483 struct mlxsw_sp_rif *rif)
488 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
489 dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
490 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
494 mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
495 struct mlxsw_sp_neigh_entry *neigh_entry,
496 struct mlxsw_sp_rif *rif)
498 struct in6_addr *dip;
501 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
502 dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
504 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
508 mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
509 struct devlink_dpipe_entry *entry,
510 struct mlxsw_sp_neigh_entry *neigh_entry,
511 struct mlxsw_sp_rif *rif,
518 mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
521 mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
528 err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
531 entry->counter_valid = true;
535 mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
536 struct devlink_dpipe_entry *entry,
537 bool counters_enabled,
538 struct devlink_dpipe_dump_ctx *dump_ctx,
541 int rif_neigh_count = 0;
542 int rif_neigh_skip = 0;
550 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
552 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
554 goto err_ctx_prepare;
556 rif_neigh_skip = rif_neigh_count;
557 for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
558 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
559 struct mlxsw_sp_neigh_entry *neigh_entry;
565 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
566 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
568 if (neigh_type != type)
571 if (neigh_type == AF_INET6 &&
572 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
575 if (rif_neigh_count < rif_neigh_skip)
578 mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
581 entry->index = neigh_count;
582 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
584 if (err == -EMSGSIZE) {
586 goto err_entry_append;
590 goto err_entry_append;
600 devlink_dpipe_entry_ctx_close(dump_ctx);
614 mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
615 bool counters_enabled,
616 struct devlink_dpipe_dump_ctx *dump_ctx,
619 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
620 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
621 struct devlink_dpipe_value action_value;
622 struct devlink_dpipe_action action = {0};
623 struct devlink_dpipe_entry entry = {0};
626 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
628 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
629 sizeof(match_values[0]));
630 memset(&action_value, 0, sizeof(action_value));
632 mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
633 err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
634 matches, &action_value,
639 err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
640 counters_enabled, dump_ctx,
643 devlink_dpipe_entry_clear(&entry);
648 mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
649 struct devlink_dpipe_dump_ctx *dump_ctx)
651 struct mlxsw_sp *mlxsw_sp = priv;
653 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
659 mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
660 bool enable, int type)
665 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
666 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
667 struct mlxsw_sp_neigh_entry *neigh_entry;
671 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
672 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
674 if (neigh_type != type)
677 if (neigh_type == AF_INET6 &&
678 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
681 mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
689 static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
691 struct mlxsw_sp *mlxsw_sp = priv;
693 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
698 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
704 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
705 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
706 struct mlxsw_sp_neigh_entry *neigh_entry;
710 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
711 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
713 if (neigh_type != type)
716 if (neigh_type == AF_INET6 &&
717 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
728 static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
730 struct mlxsw_sp *mlxsw_sp = priv;
732 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
735 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
736 .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
737 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
738 .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
739 .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
740 .size_get = mlxsw_sp_dpipe_table_host4_size_get,
743 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1
745 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
747 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
750 err = devlink_dpipe_table_register(devlink,
751 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
757 err = devlink_dpipe_table_resource_set(devlink,
758 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
759 MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
760 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4);
762 goto err_resource_set;
767 devlink_dpipe_table_unregister(devlink,
768 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
772 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
774 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
776 devlink_dpipe_table_unregister(devlink,
777 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
781 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
783 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
787 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
788 struct devlink_dpipe_dump_ctx *dump_ctx)
790 struct mlxsw_sp *mlxsw_sp = priv;
792 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
797 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
799 struct mlxsw_sp *mlxsw_sp = priv;
801 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
805 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
807 struct mlxsw_sp *mlxsw_sp = priv;
809 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
812 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
813 .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
814 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
815 .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
816 .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
817 .size_get = mlxsw_sp_dpipe_table_host6_size_get,
820 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2
822 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
824 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
827 err = devlink_dpipe_table_register(devlink,
828 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
834 err = devlink_dpipe_table_resource_set(devlink,
835 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
836 MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
837 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6);
839 goto err_resource_set;
844 devlink_dpipe_table_unregister(devlink,
845 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
849 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
851 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
853 devlink_dpipe_table_unregister(devlink,
854 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
857 static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
860 struct devlink_dpipe_match match = {0};
863 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
864 match.header = &mlxsw_sp_dpipe_header_metadata;
865 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
867 err = devlink_dpipe_match_put(skb, &match);
871 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
872 match.header = &mlxsw_sp_dpipe_header_metadata;
873 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
875 err = devlink_dpipe_match_put(skb, &match);
879 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
880 match.header = &mlxsw_sp_dpipe_header_metadata;
881 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
883 return devlink_dpipe_match_put(skb, &match);
886 static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
889 struct devlink_dpipe_action action = {0};
892 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
893 action.header = &devlink_dpipe_header_ethernet;
894 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
896 err = devlink_dpipe_action_put(skb, &action);
900 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
901 action.header = &mlxsw_sp_dpipe_header_metadata;
902 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
904 return devlink_dpipe_action_put(skb, &action);
907 static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
909 struct mlxsw_sp_nexthop *nh;
912 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
913 if (mlxsw_sp_nexthop_offload(nh) &&
914 !mlxsw_sp_nexthop_group_has_ipip(nh))
919 enum mlxsw_sp_dpipe_table_adj_match {
920 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
921 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE,
922 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
923 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
926 enum mlxsw_sp_dpipe_table_adj_action {
927 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
928 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
929 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
933 mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
934 struct devlink_dpipe_action *actions)
936 struct devlink_dpipe_action *action;
937 struct devlink_dpipe_match *match;
939 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
940 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
941 match->header = &mlxsw_sp_dpipe_header_metadata;
942 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
944 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
945 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
946 match->header = &mlxsw_sp_dpipe_header_metadata;
947 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
949 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
950 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
951 match->header = &mlxsw_sp_dpipe_header_metadata;
952 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
954 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
955 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
956 action->header = &devlink_dpipe_header_ethernet;
957 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
959 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
960 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
961 action->header = &mlxsw_sp_dpipe_header_metadata;
962 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
966 mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
967 struct devlink_dpipe_value *match_values,
968 struct devlink_dpipe_match *matches,
969 struct devlink_dpipe_value *action_values,
970 struct devlink_dpipe_action *actions)
971 { struct devlink_dpipe_value *action_value;
972 struct devlink_dpipe_value *match_value;
973 struct devlink_dpipe_action *action;
974 struct devlink_dpipe_match *match;
976 entry->match_values = match_values;
977 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
979 entry->action_values = action_values;
980 entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
982 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
983 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
985 match_value->match = match;
986 match_value->value_size = sizeof(u32);
987 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
988 if (!match_value->value)
991 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
992 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
994 match_value->match = match;
995 match_value->value_size = sizeof(u32);
996 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
997 if (!match_value->value)
1000 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1001 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1003 match_value->match = match;
1004 match_value->value_size = sizeof(u32);
1005 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1006 if (!match_value->value)
1009 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1010 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1012 action_value->action = action;
1013 action_value->value_size = sizeof(u64);
1014 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1015 if (!action_value->value)
1018 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1019 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1021 action_value->action = action;
1022 action_value->value_size = sizeof(u32);
1023 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1024 if (!action_value->value)
1031 __mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
1032 u32 adj_index, u32 adj_size,
1033 u32 adj_hash_index, unsigned char *ha,
1034 struct mlxsw_sp_rif *rif)
1036 struct devlink_dpipe_value *value;
1040 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1041 p_index = value->value;
1042 *p_index = adj_index;
1044 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
1045 p_index = value->value;
1046 *p_index = adj_size;
1048 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1049 p_index = value->value;
1050 *p_index = adj_hash_index;
1052 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1053 ether_addr_copy(value->value, ha);
1055 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1056 p_rif_value = value->value;
1057 *p_rif_value = mlxsw_sp_rif_index(rif);
1058 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
1059 value->mapping_valid = true;
1062 static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
1063 struct mlxsw_sp_nexthop *nh,
1064 struct devlink_dpipe_entry *entry)
1066 struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
1067 unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
1068 u32 adj_hash_index = 0;
1073 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index);
1074 __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size,
1075 adj_hash_index, ha, rif);
1076 err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
1078 entry->counter_valid = true;
1082 mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
1083 struct devlink_dpipe_entry *entry,
1084 bool counters_enabled,
1085 struct devlink_dpipe_dump_ctx *dump_ctx)
1087 struct mlxsw_sp_nexthop *nh;
1088 int entry_index = 0;
1096 nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1098 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
1100 goto err_ctx_prepare;
1104 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1105 if (!mlxsw_sp_nexthop_offload(nh) ||
1106 mlxsw_sp_nexthop_group_has_ipip(nh))
1109 if (nh_count < nh_skip)
1112 mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
1113 entry->index = entry_index;
1114 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
1116 if (err == -EMSGSIZE) {
1118 goto err_entry_append;
1121 goto err_entry_append;
1129 devlink_dpipe_entry_ctx_close(dump_ctx);
1130 if (nh_count != nh_count_max)
1143 mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
1144 struct devlink_dpipe_dump_ctx *dump_ctx)
1146 struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1147 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1148 struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1149 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1150 struct devlink_dpipe_entry entry = {0};
1151 struct mlxsw_sp *mlxsw_sp = priv;
1154 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1155 sizeof(matches[0]));
1156 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1157 sizeof(match_values[0]));
1158 memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1159 sizeof(actions[0]));
1160 memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1161 sizeof(action_values[0]));
1163 mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
1164 err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
1165 match_values, matches,
1166 action_values, actions);
1170 err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
1171 counters_enabled, dump_ctx);
1173 devlink_dpipe_entry_clear(&entry);
1177 static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
1179 struct mlxsw_sp *mlxsw_sp = priv;
1180 struct mlxsw_sp_nexthop *nh;
1181 u32 adj_hash_index = 0;
1185 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1186 if (!mlxsw_sp_nexthop_offload(nh) ||
1187 mlxsw_sp_nexthop_group_has_ipip(nh))
1190 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size,
1193 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
1195 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
1196 mlxsw_sp_nexthop_update(mlxsw_sp,
1197 adj_index + adj_hash_index, nh);
1203 mlxsw_sp_dpipe_table_adj_size_get(void *priv)
1205 struct mlxsw_sp *mlxsw_sp = priv;
1209 size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1215 static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
1216 .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
1217 .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
1218 .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
1219 .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
1220 .size_get = mlxsw_sp_dpipe_table_adj_size_get,
1223 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
1225 static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
1227 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1230 err = devlink_dpipe_table_register(devlink,
1231 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1232 &mlxsw_sp_dpipe_table_adj_ops,
1237 err = devlink_dpipe_table_resource_set(devlink,
1238 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1239 MLXSW_SP_RESOURCE_KVD_LINEAR,
1240 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ);
1242 goto err_resource_set;
1247 devlink_dpipe_table_unregister(devlink,
1248 MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1252 static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
1254 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1256 devlink_dpipe_table_unregister(devlink,
1257 MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1260 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
1262 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1265 err = devlink_dpipe_headers_register(devlink,
1266 &mlxsw_sp_dpipe_headers);
1269 err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
1271 goto err_erif_table_init;
1273 err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
1275 goto err_host4_table_init;
1277 err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
1279 goto err_host6_table_init;
1281 err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
1283 goto err_adj_table_init;
1287 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1288 err_host6_table_init:
1289 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1290 err_host4_table_init:
1291 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1292 err_erif_table_init:
1293 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
1297 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
1299 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1301 mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
1302 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1303 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1304 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1305 devlink_dpipe_headers_unregister(devlink);