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 <linux/mutex.h>
6 #include <net/devlink.h>
9 #include "spectrum_dpipe.h"
10 #include "spectrum_router.h"
12 enum mlxsw_sp_field_metadata_id {
13 MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
14 MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
15 MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
16 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
17 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
18 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
21 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
24 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
26 .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
30 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
35 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
40 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
45 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
49 .name = "adj_hash_index",
50 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
55 enum mlxsw_sp_dpipe_header_id {
56 MLXSW_SP_DPIPE_HEADER_METADATA,
59 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
61 .id = MLXSW_SP_DPIPE_HEADER_METADATA,
62 .fields = mlxsw_sp_dpipe_fields_metadata,
63 .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
66 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
67 &mlxsw_sp_dpipe_header_metadata,
68 &devlink_dpipe_header_ethernet,
69 &devlink_dpipe_header_ipv4,
70 &devlink_dpipe_header_ipv6,
73 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
74 .headers = mlxsw_dpipe_headers,
75 .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
78 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
81 struct devlink_dpipe_action action = {0};
84 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
85 action.header = &mlxsw_sp_dpipe_header_metadata;
86 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
88 err = devlink_dpipe_action_put(skb, &action);
92 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
93 action.header = &mlxsw_sp_dpipe_header_metadata;
94 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
96 return devlink_dpipe_action_put(skb, &action);
99 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
102 struct devlink_dpipe_match match = {0};
104 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
105 match.header = &mlxsw_sp_dpipe_header_metadata;
106 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
108 return devlink_dpipe_match_put(skb, &match);
112 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
113 struct devlink_dpipe_action *action)
115 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
116 action->header = &mlxsw_sp_dpipe_header_metadata;
117 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
119 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
120 match->header = &mlxsw_sp_dpipe_header_metadata;
121 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
124 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
125 struct devlink_dpipe_value *match_value,
126 struct devlink_dpipe_match *match,
127 struct devlink_dpipe_value *action_value,
128 struct devlink_dpipe_action *action)
130 entry->match_values = match_value;
131 entry->match_values_count = 1;
133 entry->action_values = action_value;
134 entry->action_values_count = 1;
136 match_value->match = match;
137 match_value->value_size = sizeof(u32);
138 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
139 if (!match_value->value)
142 action_value->action = action;
143 action_value->value_size = sizeof(u32);
144 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
145 if (!action_value->value)
146 goto err_action_alloc;
150 kfree(match_value->value);
154 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
155 struct devlink_dpipe_entry *entry,
156 struct mlxsw_sp_rif *rif,
157 bool counters_enabled)
164 /* Set Match RIF index */
165 rif_value = entry->match_values->value;
166 *rif_value = mlxsw_sp_rif_index(rif);
167 entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
168 entry->match_values->mapping_valid = true;
170 /* Set Action Forwarding */
171 action_value = entry->action_values->value;
174 entry->counter_valid = false;
176 entry->index = mlxsw_sp_rif_index(rif);
178 if (!counters_enabled)
181 err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
182 MLXSW_SP_RIF_COUNTER_EGRESS,
185 entry->counter = cnt;
186 entry->counter_valid = true;
192 mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
193 struct devlink_dpipe_dump_ctx *dump_ctx)
195 struct devlink_dpipe_value match_value, action_value;
196 struct devlink_dpipe_action action = {0};
197 struct devlink_dpipe_match match = {0};
198 struct devlink_dpipe_entry entry = {0};
199 struct mlxsw_sp *mlxsw_sp = priv;
200 unsigned int rif_count;
204 memset(&match_value, 0, sizeof(match_value));
205 memset(&action_value, 0, sizeof(action_value));
207 mlxsw_sp_erif_match_action_prepare(&match, &action);
208 err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
209 &action_value, &action);
213 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
214 mutex_lock(&mlxsw_sp->router->lock);
217 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
219 goto err_ctx_prepare;
221 for (; i < rif_count; i++) {
222 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
224 if (!rif || !mlxsw_sp_rif_has_dev(rif))
226 err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif,
230 err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
232 if (err == -EMSGSIZE) {
234 goto err_entry_append;
237 goto err_entry_append;
242 devlink_dpipe_entry_ctx_close(dump_ctx);
245 mutex_unlock(&mlxsw_sp->router->lock);
247 devlink_dpipe_entry_clear(&entry);
252 mutex_unlock(&mlxsw_sp->router->lock);
253 devlink_dpipe_entry_clear(&entry);
257 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
259 struct mlxsw_sp *mlxsw_sp = priv;
262 mutex_lock(&mlxsw_sp->router->lock);
263 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
264 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
269 mlxsw_sp_rif_counter_alloc(rif,
270 MLXSW_SP_RIF_COUNTER_EGRESS);
272 mlxsw_sp_rif_counter_free(rif,
273 MLXSW_SP_RIF_COUNTER_EGRESS);
275 mutex_unlock(&mlxsw_sp->router->lock);
279 static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
281 struct mlxsw_sp *mlxsw_sp = priv;
283 return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
286 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
287 .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
288 .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
289 .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
290 .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
291 .size_get = mlxsw_sp_dpipe_table_erif_size_get,
294 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
296 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
298 return devl_dpipe_table_register(devlink,
299 MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
304 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
306 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
308 devl_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
311 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
313 struct devlink_dpipe_match match = {0};
316 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
317 match.header = &mlxsw_sp_dpipe_header_metadata;
318 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
320 err = devlink_dpipe_match_put(skb, &match);
326 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
327 match.header = &devlink_dpipe_header_ipv4;
328 match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
331 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
332 match.header = &devlink_dpipe_header_ipv6;
333 match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
340 return devlink_dpipe_match_put(skb, &match);
344 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
346 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
350 mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
352 struct devlink_dpipe_action action = {0};
354 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
355 action.header = &devlink_dpipe_header_ethernet;
356 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
358 return devlink_dpipe_action_put(skb, &action);
361 enum mlxsw_sp_dpipe_table_host_match {
362 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
363 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
364 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
368 mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
369 struct devlink_dpipe_action *action,
372 struct devlink_dpipe_match *match;
374 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
375 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
376 match->header = &mlxsw_sp_dpipe_header_metadata;
377 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
379 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
380 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
383 match->header = &devlink_dpipe_header_ipv4;
384 match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
387 match->header = &devlink_dpipe_header_ipv6;
388 match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
395 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
396 action->header = &devlink_dpipe_header_ethernet;
397 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
401 mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
402 struct devlink_dpipe_value *match_values,
403 struct devlink_dpipe_match *matches,
404 struct devlink_dpipe_value *action_value,
405 struct devlink_dpipe_action *action,
408 struct devlink_dpipe_value *match_value;
409 struct devlink_dpipe_match *match;
411 entry->match_values = match_values;
412 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
414 entry->action_values = action_value;
415 entry->action_values_count = 1;
417 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
418 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
420 match_value->match = match;
421 match_value->value_size = sizeof(u32);
422 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
423 if (!match_value->value)
426 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
427 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
429 match_value->match = match;
432 match_value->value_size = sizeof(u32);
435 match_value->value_size = sizeof(struct in6_addr);
442 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
443 if (!match_value->value)
446 action_value->action = action;
447 action_value->value_size = sizeof(u64);
448 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
449 if (!action_value->value)
456 __mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
457 struct mlxsw_sp_rif *rif,
458 unsigned char *ha, void *dip)
460 struct devlink_dpipe_value *value;
464 /* Set Match RIF index */
465 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
467 rif_value = value->value;
468 *rif_value = mlxsw_sp_rif_index(rif);
469 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
470 value->mapping_valid = true;
473 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
474 memcpy(value->value, dip, value->value_size);
476 /* Set Action DMAC */
477 value = entry->action_values;
478 ha_value = value->value;
479 ether_addr_copy(ha_value, ha);
483 mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
484 struct mlxsw_sp_neigh_entry *neigh_entry,
485 struct mlxsw_sp_rif *rif)
490 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
491 dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
492 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
496 mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
497 struct mlxsw_sp_neigh_entry *neigh_entry,
498 struct mlxsw_sp_rif *rif)
500 struct in6_addr *dip;
503 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
504 dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
506 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
510 mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
511 struct devlink_dpipe_entry *entry,
512 struct mlxsw_sp_neigh_entry *neigh_entry,
513 struct mlxsw_sp_rif *rif,
520 mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
523 mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
530 err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
533 entry->counter_valid = true;
537 mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
538 struct devlink_dpipe_entry *entry,
539 bool counters_enabled,
540 struct devlink_dpipe_dump_ctx *dump_ctx,
543 int rif_neigh_count = 0;
544 int rif_neigh_skip = 0;
550 mutex_lock(&mlxsw_sp->router->lock);
552 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
554 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
556 goto err_ctx_prepare;
558 rif_neigh_skip = rif_neigh_count;
559 for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
560 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
561 struct mlxsw_sp_neigh_entry *neigh_entry;
567 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
568 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
570 if (neigh_type != type)
573 if (neigh_type == AF_INET6 &&
574 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
577 if (rif_neigh_count < rif_neigh_skip)
580 mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
583 entry->index = neigh_count;
584 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
586 if (err == -EMSGSIZE) {
588 goto err_entry_append;
592 goto err_entry_append;
602 devlink_dpipe_entry_ctx_close(dump_ctx);
606 mutex_unlock(&mlxsw_sp->router->lock);
611 mutex_unlock(&mlxsw_sp->router->lock);
616 mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
617 bool counters_enabled,
618 struct devlink_dpipe_dump_ctx *dump_ctx,
621 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
622 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
623 struct devlink_dpipe_value action_value;
624 struct devlink_dpipe_action action = {0};
625 struct devlink_dpipe_entry entry = {0};
628 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
630 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
631 sizeof(match_values[0]));
632 memset(&action_value, 0, sizeof(action_value));
634 mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
635 err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
636 matches, &action_value,
641 err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
642 counters_enabled, dump_ctx,
645 devlink_dpipe_entry_clear(&entry);
650 mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
651 struct devlink_dpipe_dump_ctx *dump_ctx)
653 struct mlxsw_sp *mlxsw_sp = priv;
655 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
661 mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
662 bool enable, int type)
666 mutex_lock(&mlxsw_sp->router->lock);
667 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
668 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
669 struct mlxsw_sp_neigh_entry *neigh_entry;
673 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
674 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
676 if (neigh_type != type)
679 if (neigh_type == AF_INET6 &&
680 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
683 mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
688 mutex_unlock(&mlxsw_sp->router->lock);
691 static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
693 struct mlxsw_sp *mlxsw_sp = priv;
695 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
700 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
705 mutex_lock(&mlxsw_sp->router->lock);
706 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
707 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
708 struct mlxsw_sp_neigh_entry *neigh_entry;
712 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
713 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
715 if (neigh_type != type)
718 if (neigh_type == AF_INET6 &&
719 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
725 mutex_unlock(&mlxsw_sp->router->lock);
730 static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
732 struct mlxsw_sp *mlxsw_sp = priv;
734 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
737 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
738 .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
739 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
740 .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
741 .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
742 .size_get = mlxsw_sp_dpipe_table_host4_size_get,
745 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1
747 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
749 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
752 err = devl_dpipe_table_register(devlink,
753 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
759 err = devl_dpipe_table_resource_set(devlink,
760 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
761 MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
762 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4);
764 goto err_resource_set;
769 devl_dpipe_table_unregister(devlink,
770 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
774 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
776 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
778 devl_dpipe_table_unregister(devlink,
779 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
783 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
785 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
789 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
790 struct devlink_dpipe_dump_ctx *dump_ctx)
792 struct mlxsw_sp *mlxsw_sp = priv;
794 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
799 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
801 struct mlxsw_sp *mlxsw_sp = priv;
803 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
807 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
809 struct mlxsw_sp *mlxsw_sp = priv;
811 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
814 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
815 .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
816 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
817 .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
818 .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
819 .size_get = mlxsw_sp_dpipe_table_host6_size_get,
822 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2
824 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
826 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
829 err = devl_dpipe_table_register(devlink,
830 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
836 err = devl_dpipe_table_resource_set(devlink,
837 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
838 MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
839 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6);
841 goto err_resource_set;
846 devl_dpipe_table_unregister(devlink,
847 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
851 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
853 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
855 devl_dpipe_table_unregister(devlink,
856 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
859 static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
862 struct devlink_dpipe_match match = {0};
865 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
866 match.header = &mlxsw_sp_dpipe_header_metadata;
867 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
869 err = devlink_dpipe_match_put(skb, &match);
873 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
874 match.header = &mlxsw_sp_dpipe_header_metadata;
875 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
877 err = devlink_dpipe_match_put(skb, &match);
881 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
882 match.header = &mlxsw_sp_dpipe_header_metadata;
883 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
885 return devlink_dpipe_match_put(skb, &match);
888 static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
891 struct devlink_dpipe_action action = {0};
894 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
895 action.header = &devlink_dpipe_header_ethernet;
896 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
898 err = devlink_dpipe_action_put(skb, &action);
902 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
903 action.header = &mlxsw_sp_dpipe_header_metadata;
904 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
906 return devlink_dpipe_action_put(skb, &action);
909 static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
911 struct mlxsw_sp_nexthop *nh;
914 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
915 if (mlxsw_sp_nexthop_is_forward(nh) &&
916 !mlxsw_sp_nexthop_group_has_ipip(nh))
921 enum mlxsw_sp_dpipe_table_adj_match {
922 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
923 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE,
924 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
925 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
928 enum mlxsw_sp_dpipe_table_adj_action {
929 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
930 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
931 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
935 mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
936 struct devlink_dpipe_action *actions)
938 struct devlink_dpipe_action *action;
939 struct devlink_dpipe_match *match;
941 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
942 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
943 match->header = &mlxsw_sp_dpipe_header_metadata;
944 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
946 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
947 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
948 match->header = &mlxsw_sp_dpipe_header_metadata;
949 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
951 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
952 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
953 match->header = &mlxsw_sp_dpipe_header_metadata;
954 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
956 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
957 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
958 action->header = &devlink_dpipe_header_ethernet;
959 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
961 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
962 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
963 action->header = &mlxsw_sp_dpipe_header_metadata;
964 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
968 mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
969 struct devlink_dpipe_value *match_values,
970 struct devlink_dpipe_match *matches,
971 struct devlink_dpipe_value *action_values,
972 struct devlink_dpipe_action *actions)
973 { struct devlink_dpipe_value *action_value;
974 struct devlink_dpipe_value *match_value;
975 struct devlink_dpipe_action *action;
976 struct devlink_dpipe_match *match;
978 entry->match_values = match_values;
979 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
981 entry->action_values = action_values;
982 entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
984 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
985 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
987 match_value->match = match;
988 match_value->value_size = sizeof(u32);
989 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
990 if (!match_value->value)
993 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
994 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
996 match_value->match = match;
997 match_value->value_size = sizeof(u32);
998 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
999 if (!match_value->value)
1002 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1003 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1005 match_value->match = match;
1006 match_value->value_size = sizeof(u32);
1007 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1008 if (!match_value->value)
1011 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1012 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1014 action_value->action = action;
1015 action_value->value_size = sizeof(u64);
1016 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1017 if (!action_value->value)
1020 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1021 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1023 action_value->action = action;
1024 action_value->value_size = sizeof(u32);
1025 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1026 if (!action_value->value)
1033 __mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
1034 u32 adj_index, u32 adj_size,
1035 u32 adj_hash_index, unsigned char *ha,
1036 struct mlxsw_sp_rif *rif)
1038 struct devlink_dpipe_value *value;
1042 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1043 p_index = value->value;
1044 *p_index = adj_index;
1046 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
1047 p_index = value->value;
1048 *p_index = adj_size;
1050 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1051 p_index = value->value;
1052 *p_index = adj_hash_index;
1054 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1055 ether_addr_copy(value->value, ha);
1057 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1058 p_rif_value = value->value;
1059 *p_rif_value = mlxsw_sp_rif_index(rif);
1060 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
1061 value->mapping_valid = true;
1064 static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
1065 struct mlxsw_sp_nexthop *nh,
1066 struct devlink_dpipe_entry *entry)
1068 struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
1069 unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
1070 u32 adj_hash_index = 0;
1075 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index);
1076 __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size,
1077 adj_hash_index, ha, rif);
1078 err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
1080 entry->counter_valid = true;
1084 mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
1085 struct devlink_dpipe_entry *entry,
1086 bool counters_enabled,
1087 struct devlink_dpipe_dump_ctx *dump_ctx)
1089 struct mlxsw_sp_nexthop *nh;
1090 int entry_index = 0;
1097 mutex_lock(&mlxsw_sp->router->lock);
1098 nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1100 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
1102 goto err_ctx_prepare;
1106 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1107 if (!mlxsw_sp_nexthop_is_forward(nh) ||
1108 mlxsw_sp_nexthop_group_has_ipip(nh))
1111 if (nh_count < nh_skip)
1114 mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
1115 entry->index = entry_index;
1116 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
1118 if (err == -EMSGSIZE) {
1120 goto err_entry_append;
1123 goto err_entry_append;
1131 devlink_dpipe_entry_ctx_close(dump_ctx);
1132 if (nh_count != nh_count_max)
1134 mutex_unlock(&mlxsw_sp->router->lock);
1140 mutex_unlock(&mlxsw_sp->router->lock);
1145 mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
1146 struct devlink_dpipe_dump_ctx *dump_ctx)
1148 struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1149 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1150 struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1151 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1152 struct devlink_dpipe_entry entry = {0};
1153 struct mlxsw_sp *mlxsw_sp = priv;
1156 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1157 sizeof(matches[0]));
1158 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1159 sizeof(match_values[0]));
1160 memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1161 sizeof(actions[0]));
1162 memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1163 sizeof(action_values[0]));
1165 mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
1166 err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
1167 match_values, matches,
1168 action_values, actions);
1172 err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
1173 counters_enabled, dump_ctx);
1175 devlink_dpipe_entry_clear(&entry);
1179 static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
1181 char ratr_pl[MLXSW_REG_RATR_LEN];
1182 struct mlxsw_sp *mlxsw_sp = priv;
1183 struct mlxsw_sp_nexthop *nh;
1184 u32 adj_hash_index = 0;
1188 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1189 if (!mlxsw_sp_nexthop_is_forward(nh) ||
1190 mlxsw_sp_nexthop_group_has_ipip(nh))
1193 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size,
1196 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
1198 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
1199 mlxsw_sp_nexthop_eth_update(mlxsw_sp,
1200 adj_index + adj_hash_index, nh,
1207 mlxsw_sp_dpipe_table_adj_size_get(void *priv)
1209 struct mlxsw_sp *mlxsw_sp = priv;
1212 mutex_lock(&mlxsw_sp->router->lock);
1213 size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1214 mutex_unlock(&mlxsw_sp->router->lock);
1219 static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
1220 .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
1221 .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
1222 .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
1223 .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
1224 .size_get = mlxsw_sp_dpipe_table_adj_size_get,
1227 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
1229 static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
1231 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1234 err = devl_dpipe_table_register(devlink,
1235 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1236 &mlxsw_sp_dpipe_table_adj_ops,
1241 err = devl_dpipe_table_resource_set(devlink,
1242 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1243 MLXSW_SP_RESOURCE_KVD_LINEAR,
1244 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ);
1246 goto err_resource_set;
1251 devl_dpipe_table_unregister(devlink,
1252 MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1256 static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
1258 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1260 devl_dpipe_table_unregister(devlink,
1261 MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1264 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
1266 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1269 devl_dpipe_headers_register(devlink, &mlxsw_sp_dpipe_headers);
1271 err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
1273 goto err_erif_table_init;
1275 err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
1277 goto err_host4_table_init;
1279 err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
1281 goto err_host6_table_init;
1283 err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
1285 goto err_adj_table_init;
1289 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1290 err_host6_table_init:
1291 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1292 err_host4_table_init:
1293 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1294 err_erif_table_init:
1295 devl_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
1299 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
1301 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1303 mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
1304 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1305 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1306 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1307 devl_dpipe_headers_unregister(devlink);