Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[cris-mirror.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_dpipe.c
blobf56fa18d6b2612183ae1dd5fc3d53f070e7ef406
1 /*
2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Arkadi Sharshevsky <arakdis@mellanox.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <linux/kernel.h>
36 #include <net/devlink.h>
38 #include "spectrum.h"
39 #include "spectrum_dpipe.h"
40 #include "spectrum_router.h"
42 enum mlxsw_sp_field_metadata_id {
43 MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
44 MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
45 MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
46 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
47 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
48 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
51 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
53 .name = "erif_port",
54 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
55 .bitwidth = 32,
56 .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
59 .name = "l3_forward",
60 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
61 .bitwidth = 1,
64 .name = "l3_drop",
65 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
66 .bitwidth = 1,
69 .name = "adj_index",
70 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
71 .bitwidth = 32,
74 .name = "adj_size",
75 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
76 .bitwidth = 32,
79 .name = "adj_hash_index",
80 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
81 .bitwidth = 32,
85 enum mlxsw_sp_dpipe_header_id {
86 MLXSW_SP_DPIPE_HEADER_METADATA,
89 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
90 .name = "mlxsw_meta",
91 .id = MLXSW_SP_DPIPE_HEADER_METADATA,
92 .fields = mlxsw_sp_dpipe_fields_metadata,
93 .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
96 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
97 &mlxsw_sp_dpipe_header_metadata,
98 &devlink_dpipe_header_ethernet,
99 &devlink_dpipe_header_ipv4,
100 &devlink_dpipe_header_ipv6,
103 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
104 .headers = mlxsw_dpipe_headers,
105 .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
108 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
109 struct sk_buff *skb)
111 struct devlink_dpipe_action action = {0};
112 int err;
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 err = devlink_dpipe_action_put(skb, &action);
119 if (err)
120 return err;
122 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
123 action.header = &mlxsw_sp_dpipe_header_metadata;
124 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
126 return devlink_dpipe_action_put(skb, &action);
129 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
130 struct sk_buff *skb)
132 struct devlink_dpipe_match match = {0};
134 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
135 match.header = &mlxsw_sp_dpipe_header_metadata;
136 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
138 return devlink_dpipe_match_put(skb, &match);
141 static void
142 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
143 struct devlink_dpipe_action *action)
145 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
146 action->header = &mlxsw_sp_dpipe_header_metadata;
147 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
149 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
150 match->header = &mlxsw_sp_dpipe_header_metadata;
151 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
154 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
155 struct devlink_dpipe_value *match_value,
156 struct devlink_dpipe_match *match,
157 struct devlink_dpipe_value *action_value,
158 struct devlink_dpipe_action *action)
160 entry->match_values = match_value;
161 entry->match_values_count = 1;
163 entry->action_values = action_value;
164 entry->action_values_count = 1;
166 match_value->match = match;
167 match_value->value_size = sizeof(u32);
168 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
169 if (!match_value->value)
170 return -ENOMEM;
172 action_value->action = action;
173 action_value->value_size = sizeof(u32);
174 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
175 if (!action_value->value)
176 goto err_action_alloc;
177 return 0;
179 err_action_alloc:
180 kfree(match_value->value);
181 return -ENOMEM;
184 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
185 struct devlink_dpipe_entry *entry,
186 struct mlxsw_sp_rif *rif,
187 bool counters_enabled)
189 u32 *action_value;
190 u32 *rif_value;
191 u64 cnt;
192 int err;
194 /* Set Match RIF index */
195 rif_value = entry->match_values->value;
196 *rif_value = mlxsw_sp_rif_index(rif);
197 entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
198 entry->match_values->mapping_valid = true;
200 /* Set Action Forwarding */
201 action_value = entry->action_values->value;
202 *action_value = 1;
204 entry->counter_valid = false;
205 entry->counter = 0;
206 entry->index = mlxsw_sp_rif_index(rif);
208 if (!counters_enabled)
209 return 0;
211 err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
212 MLXSW_SP_RIF_COUNTER_EGRESS,
213 &cnt);
214 if (!err) {
215 entry->counter = cnt;
216 entry->counter_valid = true;
218 return 0;
221 static int
222 mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
223 struct devlink_dpipe_dump_ctx *dump_ctx)
225 struct devlink_dpipe_value match_value, action_value;
226 struct devlink_dpipe_action action = {0};
227 struct devlink_dpipe_match match = {0};
228 struct devlink_dpipe_entry entry = {0};
229 struct mlxsw_sp *mlxsw_sp = priv;
230 unsigned int rif_count;
231 int i, j;
232 int err;
234 memset(&match_value, 0, sizeof(match_value));
235 memset(&action_value, 0, sizeof(action_value));
237 mlxsw_sp_erif_match_action_prepare(&match, &action);
238 err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
239 &action_value, &action);
240 if (err)
241 return err;
243 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
244 rtnl_lock();
245 i = 0;
246 start_again:
247 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
248 if (err)
249 return err;
250 j = 0;
251 for (; i < rif_count; i++) {
252 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
254 if (!rif)
255 continue;
256 err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif,
257 counters_enabled);
258 if (err)
259 goto err_entry_get;
260 err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
261 if (err) {
262 if (err == -EMSGSIZE) {
263 if (!j)
264 goto err_entry_append;
265 break;
267 goto err_entry_append;
269 j++;
272 devlink_dpipe_entry_ctx_close(dump_ctx);
273 if (i != rif_count)
274 goto start_again;
275 rtnl_unlock();
277 devlink_dpipe_entry_clear(&entry);
278 return 0;
279 err_entry_append:
280 err_entry_get:
281 rtnl_unlock();
282 devlink_dpipe_entry_clear(&entry);
283 return err;
286 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
288 struct mlxsw_sp *mlxsw_sp = priv;
289 int i;
291 rtnl_lock();
292 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
293 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
295 if (!rif)
296 continue;
297 if (enable)
298 mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
299 MLXSW_SP_RIF_COUNTER_EGRESS);
300 else
301 mlxsw_sp_rif_counter_free(mlxsw_sp, rif,
302 MLXSW_SP_RIF_COUNTER_EGRESS);
304 rtnl_unlock();
305 return 0;
308 static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
310 struct mlxsw_sp *mlxsw_sp = priv;
312 return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
315 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
316 .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
317 .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
318 .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
319 .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
320 .size_get = mlxsw_sp_dpipe_table_erif_size_get,
323 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
325 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
327 return devlink_dpipe_table_register(devlink,
328 MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
329 &mlxsw_sp_erif_ops,
330 mlxsw_sp, false);
333 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
335 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
337 devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
340 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
342 struct devlink_dpipe_match match = {0};
343 int err;
345 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
346 match.header = &mlxsw_sp_dpipe_header_metadata;
347 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
349 err = devlink_dpipe_match_put(skb, &match);
350 if (err)
351 return err;
353 switch (type) {
354 case AF_INET:
355 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
356 match.header = &devlink_dpipe_header_ipv4;
357 match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
358 break;
359 case AF_INET6:
360 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
361 match.header = &devlink_dpipe_header_ipv6;
362 match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
363 break;
364 default:
365 WARN_ON(1);
366 return -EINVAL;
369 return devlink_dpipe_match_put(skb, &match);
372 static int
373 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
375 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
378 static int
379 mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
381 struct devlink_dpipe_action action = {0};
383 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
384 action.header = &devlink_dpipe_header_ethernet;
385 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
387 return devlink_dpipe_action_put(skb, &action);
390 enum mlxsw_sp_dpipe_table_host_match {
391 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
392 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
393 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
396 static void
397 mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
398 struct devlink_dpipe_action *action,
399 int type)
401 struct devlink_dpipe_match *match;
403 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
404 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
405 match->header = &mlxsw_sp_dpipe_header_metadata;
406 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
408 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
409 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
410 switch (type) {
411 case AF_INET:
412 match->header = &devlink_dpipe_header_ipv4;
413 match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
414 break;
415 case AF_INET6:
416 match->header = &devlink_dpipe_header_ipv6;
417 match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
418 break;
419 default:
420 WARN_ON(1);
421 return;
424 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
425 action->header = &devlink_dpipe_header_ethernet;
426 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
429 static int
430 mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
431 struct devlink_dpipe_value *match_values,
432 struct devlink_dpipe_match *matches,
433 struct devlink_dpipe_value *action_value,
434 struct devlink_dpipe_action *action,
435 int type)
437 struct devlink_dpipe_value *match_value;
438 struct devlink_dpipe_match *match;
440 entry->match_values = match_values;
441 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
443 entry->action_values = action_value;
444 entry->action_values_count = 1;
446 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
447 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
449 match_value->match = match;
450 match_value->value_size = sizeof(u32);
451 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
452 if (!match_value->value)
453 return -ENOMEM;
455 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
456 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
458 match_value->match = match;
459 switch (type) {
460 case AF_INET:
461 match_value->value_size = sizeof(u32);
462 break;
463 case AF_INET6:
464 match_value->value_size = sizeof(struct in6_addr);
465 break;
466 default:
467 WARN_ON(1);
468 return -EINVAL;
471 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
472 if (!match_value->value)
473 return -ENOMEM;
475 action_value->action = action;
476 action_value->value_size = sizeof(u64);
477 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
478 if (!action_value->value)
479 return -ENOMEM;
481 return 0;
484 static void
485 __mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
486 struct mlxsw_sp_rif *rif,
487 unsigned char *ha, void *dip)
489 struct devlink_dpipe_value *value;
490 u32 *rif_value;
491 u8 *ha_value;
493 /* Set Match RIF index */
494 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
496 rif_value = value->value;
497 *rif_value = mlxsw_sp_rif_index(rif);
498 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
499 value->mapping_valid = true;
501 /* Set Match DIP */
502 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
503 memcpy(value->value, dip, value->value_size);
505 /* Set Action DMAC */
506 value = entry->action_values;
507 ha_value = value->value;
508 ether_addr_copy(ha_value, ha);
511 static void
512 mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
513 struct mlxsw_sp_neigh_entry *neigh_entry,
514 struct mlxsw_sp_rif *rif)
516 unsigned char *ha;
517 u32 dip;
519 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
520 dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
521 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
524 static void
525 mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
526 struct mlxsw_sp_neigh_entry *neigh_entry,
527 struct mlxsw_sp_rif *rif)
529 struct in6_addr *dip;
530 unsigned char *ha;
532 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
533 dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
535 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
538 static void
539 mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
540 struct devlink_dpipe_entry *entry,
541 struct mlxsw_sp_neigh_entry *neigh_entry,
542 struct mlxsw_sp_rif *rif,
543 int type)
545 int err;
547 switch (type) {
548 case AF_INET:
549 mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
550 break;
551 case AF_INET6:
552 mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
553 break;
554 default:
555 WARN_ON(1);
556 return;
559 err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
560 &entry->counter);
561 if (!err)
562 entry->counter_valid = true;
565 static int
566 mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
567 struct devlink_dpipe_entry *entry,
568 bool counters_enabled,
569 struct devlink_dpipe_dump_ctx *dump_ctx,
570 int type)
572 int rif_neigh_count = 0;
573 int rif_neigh_skip = 0;
574 int neigh_count = 0;
575 int rif_count;
576 int i, j;
577 int err;
579 rtnl_lock();
580 i = 0;
581 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
582 start_again:
583 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
584 if (err)
585 goto err_ctx_prepare;
586 j = 0;
587 rif_neigh_skip = rif_neigh_count;
588 for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
589 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
590 struct mlxsw_sp_neigh_entry *neigh_entry;
592 if (!rif)
593 continue;
595 rif_neigh_count = 0;
596 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
597 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
599 if (neigh_type != type)
600 continue;
602 if (neigh_type == AF_INET6 &&
603 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
604 continue;
606 if (rif_neigh_count < rif_neigh_skip)
607 goto skip;
609 mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
610 neigh_entry, rif,
611 type);
612 entry->index = neigh_count;
613 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
614 if (err) {
615 if (err == -EMSGSIZE) {
616 if (!j)
617 goto err_entry_append;
618 else
619 goto out;
621 goto err_entry_append;
623 neigh_count++;
624 j++;
625 skip:
626 rif_neigh_count++;
628 rif_neigh_skip = 0;
630 out:
631 devlink_dpipe_entry_ctx_close(dump_ctx);
632 if (i != rif_count)
633 goto start_again;
635 rtnl_unlock();
636 return 0;
638 err_ctx_prepare:
639 err_entry_append:
640 rtnl_unlock();
641 return err;
644 static int
645 mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
646 bool counters_enabled,
647 struct devlink_dpipe_dump_ctx *dump_ctx,
648 int type)
650 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
651 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
652 struct devlink_dpipe_value action_value;
653 struct devlink_dpipe_action action = {0};
654 struct devlink_dpipe_entry entry = {0};
655 int err;
657 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
658 sizeof(matches[0]));
659 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
660 sizeof(match_values[0]));
661 memset(&action_value, 0, sizeof(action_value));
663 mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
664 err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
665 matches, &action_value,
666 &action, type);
667 if (err)
668 goto out;
670 err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
671 counters_enabled, dump_ctx,
672 type);
673 out:
674 devlink_dpipe_entry_clear(&entry);
675 return err;
678 static int
679 mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
680 struct devlink_dpipe_dump_ctx *dump_ctx)
682 struct mlxsw_sp *mlxsw_sp = priv;
684 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
685 counters_enabled,
686 dump_ctx, AF_INET);
689 static void
690 mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
691 bool enable, int type)
693 int i;
695 rtnl_lock();
696 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
697 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
698 struct mlxsw_sp_neigh_entry *neigh_entry;
700 if (!rif)
701 continue;
702 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
703 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
705 if (neigh_type != type)
706 continue;
708 if (neigh_type == AF_INET6 &&
709 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
710 continue;
712 mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
713 neigh_entry,
714 enable);
717 rtnl_unlock();
720 static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
722 struct mlxsw_sp *mlxsw_sp = priv;
724 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
725 return 0;
728 static u64
729 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
731 u64 size = 0;
732 int i;
734 rtnl_lock();
735 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
736 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
737 struct mlxsw_sp_neigh_entry *neigh_entry;
739 if (!rif)
740 continue;
741 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
742 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
744 if (neigh_type != type)
745 continue;
747 if (neigh_type == AF_INET6 &&
748 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
749 continue;
751 size++;
754 rtnl_unlock();
756 return size;
759 static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
761 struct mlxsw_sp *mlxsw_sp = priv;
763 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
766 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
767 .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
768 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
769 .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
770 .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
771 .size_get = mlxsw_sp_dpipe_table_host4_size_get,
774 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1
776 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
778 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
779 int err;
781 err = devlink_dpipe_table_register(devlink,
782 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
783 &mlxsw_sp_host4_ops,
784 mlxsw_sp, false);
785 if (err)
786 return err;
788 err = devlink_dpipe_table_resource_set(devlink,
789 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
790 MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
791 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4);
792 if (err)
793 goto err_resource_set;
795 return 0;
797 err_resource_set:
798 devlink_dpipe_table_unregister(devlink,
799 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
800 return err;
803 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
805 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
807 devlink_dpipe_table_unregister(devlink,
808 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
811 static int
812 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
814 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
817 static int
818 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
819 struct devlink_dpipe_dump_ctx *dump_ctx)
821 struct mlxsw_sp *mlxsw_sp = priv;
823 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
824 counters_enabled,
825 dump_ctx, AF_INET6);
828 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
830 struct mlxsw_sp *mlxsw_sp = priv;
832 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
833 return 0;
836 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
838 struct mlxsw_sp *mlxsw_sp = priv;
840 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
843 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
844 .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
845 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
846 .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
847 .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
848 .size_get = mlxsw_sp_dpipe_table_host6_size_get,
851 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2
853 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
855 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
856 int err;
858 err = devlink_dpipe_table_register(devlink,
859 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
860 &mlxsw_sp_host6_ops,
861 mlxsw_sp, false);
862 if (err)
863 return err;
865 err = devlink_dpipe_table_resource_set(devlink,
866 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
867 MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
868 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6);
869 if (err)
870 goto err_resource_set;
872 return 0;
874 err_resource_set:
875 devlink_dpipe_table_unregister(devlink,
876 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
877 return err;
880 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
882 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
884 devlink_dpipe_table_unregister(devlink,
885 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
888 static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
889 struct sk_buff *skb)
891 struct devlink_dpipe_match match = {0};
892 int err;
894 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
895 match.header = &mlxsw_sp_dpipe_header_metadata;
896 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
898 err = devlink_dpipe_match_put(skb, &match);
899 if (err)
900 return err;
902 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
903 match.header = &mlxsw_sp_dpipe_header_metadata;
904 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
906 err = devlink_dpipe_match_put(skb, &match);
907 if (err)
908 return err;
910 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
911 match.header = &mlxsw_sp_dpipe_header_metadata;
912 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
914 return devlink_dpipe_match_put(skb, &match);
917 static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
918 struct sk_buff *skb)
920 struct devlink_dpipe_action action = {0};
921 int err;
923 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
924 action.header = &devlink_dpipe_header_ethernet;
925 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
927 err = devlink_dpipe_action_put(skb, &action);
928 if (err)
929 return err;
931 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
932 action.header = &mlxsw_sp_dpipe_header_metadata;
933 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
935 return devlink_dpipe_action_put(skb, &action);
938 static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
940 struct mlxsw_sp_nexthop *nh;
941 u64 size = 0;
943 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
944 if (mlxsw_sp_nexthop_offload(nh) &&
945 !mlxsw_sp_nexthop_group_has_ipip(nh))
946 size++;
947 return size;
950 enum mlxsw_sp_dpipe_table_adj_match {
951 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
952 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE,
953 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
954 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
957 enum mlxsw_sp_dpipe_table_adj_action {
958 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
959 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
960 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
963 static void
964 mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
965 struct devlink_dpipe_action *actions)
967 struct devlink_dpipe_action *action;
968 struct devlink_dpipe_match *match;
970 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
971 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
972 match->header = &mlxsw_sp_dpipe_header_metadata;
973 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
975 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
976 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
977 match->header = &mlxsw_sp_dpipe_header_metadata;
978 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
980 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
981 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
982 match->header = &mlxsw_sp_dpipe_header_metadata;
983 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
985 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
986 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
987 action->header = &devlink_dpipe_header_ethernet;
988 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
990 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
991 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
992 action->header = &mlxsw_sp_dpipe_header_metadata;
993 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
996 static int
997 mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
998 struct devlink_dpipe_value *match_values,
999 struct devlink_dpipe_match *matches,
1000 struct devlink_dpipe_value *action_values,
1001 struct devlink_dpipe_action *actions)
1002 { struct devlink_dpipe_value *action_value;
1003 struct devlink_dpipe_value *match_value;
1004 struct devlink_dpipe_action *action;
1005 struct devlink_dpipe_match *match;
1007 entry->match_values = match_values;
1008 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
1010 entry->action_values = action_values;
1011 entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
1013 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1014 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1016 match_value->match = match;
1017 match_value->value_size = sizeof(u32);
1018 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1019 if (!match_value->value)
1020 return -ENOMEM;
1022 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
1023 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
1025 match_value->match = match;
1026 match_value->value_size = sizeof(u32);
1027 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1028 if (!match_value->value)
1029 return -ENOMEM;
1031 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1032 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1034 match_value->match = match;
1035 match_value->value_size = sizeof(u32);
1036 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1037 if (!match_value->value)
1038 return -ENOMEM;
1040 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1041 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1043 action_value->action = action;
1044 action_value->value_size = sizeof(u64);
1045 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1046 if (!action_value->value)
1047 return -ENOMEM;
1049 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1050 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1052 action_value->action = action;
1053 action_value->value_size = sizeof(u32);
1054 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1055 if (!action_value->value)
1056 return -ENOMEM;
1058 return 0;
1061 static void
1062 __mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
1063 u32 adj_index, u32 adj_size,
1064 u32 adj_hash_index, unsigned char *ha,
1065 struct mlxsw_sp_rif *rif)
1067 struct devlink_dpipe_value *value;
1068 u32 *p_rif_value;
1069 u32 *p_index;
1071 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1072 p_index = value->value;
1073 *p_index = adj_index;
1075 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
1076 p_index = value->value;
1077 *p_index = adj_size;
1079 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1080 p_index = value->value;
1081 *p_index = adj_hash_index;
1083 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1084 ether_addr_copy(value->value, ha);
1086 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1087 p_rif_value = value->value;
1088 *p_rif_value = mlxsw_sp_rif_index(rif);
1089 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
1090 value->mapping_valid = true;
1093 static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
1094 struct mlxsw_sp_nexthop *nh,
1095 struct devlink_dpipe_entry *entry)
1097 struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
1098 unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
1099 u32 adj_hash_index = 0;
1100 u32 adj_index = 0;
1101 u32 adj_size = 0;
1102 int err;
1104 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index);
1105 __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size,
1106 adj_hash_index, ha, rif);
1107 err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
1108 if (!err)
1109 entry->counter_valid = true;
1112 static int
1113 mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
1114 struct devlink_dpipe_entry *entry,
1115 bool counters_enabled,
1116 struct devlink_dpipe_dump_ctx *dump_ctx)
1118 struct mlxsw_sp_nexthop *nh;
1119 int entry_index = 0;
1120 int nh_count_max;
1121 int nh_count = 0;
1122 int nh_skip;
1123 int j;
1124 int err;
1126 rtnl_lock();
1127 nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1128 start_again:
1129 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
1130 if (err)
1131 goto err_ctx_prepare;
1132 j = 0;
1133 nh_skip = nh_count;
1134 nh_count = 0;
1135 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1136 if (!mlxsw_sp_nexthop_offload(nh) ||
1137 mlxsw_sp_nexthop_group_has_ipip(nh))
1138 continue;
1140 if (nh_count < nh_skip)
1141 goto skip;
1143 mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
1144 entry->index = entry_index;
1145 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
1146 if (err) {
1147 if (err == -EMSGSIZE) {
1148 if (!j)
1149 goto err_entry_append;
1150 break;
1152 goto err_entry_append;
1154 entry_index++;
1155 j++;
1156 skip:
1157 nh_count++;
1160 devlink_dpipe_entry_ctx_close(dump_ctx);
1161 if (nh_count != nh_count_max)
1162 goto start_again;
1163 rtnl_unlock();
1165 return 0;
1167 err_ctx_prepare:
1168 err_entry_append:
1169 rtnl_unlock();
1170 return err;
1173 static int
1174 mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
1175 struct devlink_dpipe_dump_ctx *dump_ctx)
1177 struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1178 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1179 struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1180 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1181 struct devlink_dpipe_entry entry = {0};
1182 struct mlxsw_sp *mlxsw_sp = priv;
1183 int err;
1185 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1186 sizeof(matches[0]));
1187 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1188 sizeof(match_values[0]));
1189 memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1190 sizeof(actions[0]));
1191 memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1192 sizeof(action_values[0]));
1194 mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
1195 err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
1196 match_values, matches,
1197 action_values, actions);
1198 if (err)
1199 goto out;
1201 err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
1202 counters_enabled, dump_ctx);
1203 out:
1204 devlink_dpipe_entry_clear(&entry);
1205 return err;
1208 static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
1210 struct mlxsw_sp *mlxsw_sp = priv;
1211 struct mlxsw_sp_nexthop *nh;
1212 u32 adj_hash_index = 0;
1213 u32 adj_index = 0;
1214 u32 adj_size = 0;
1216 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1217 if (!mlxsw_sp_nexthop_offload(nh) ||
1218 mlxsw_sp_nexthop_group_has_ipip(nh))
1219 continue;
1221 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size,
1222 &adj_hash_index);
1223 if (enable)
1224 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
1225 else
1226 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
1227 mlxsw_sp_nexthop_update(mlxsw_sp,
1228 adj_index + adj_hash_index, nh);
1230 return 0;
1233 static u64
1234 mlxsw_sp_dpipe_table_adj_size_get(void *priv)
1236 struct mlxsw_sp *mlxsw_sp = priv;
1237 u64 size;
1239 rtnl_lock();
1240 size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1241 rtnl_unlock();
1243 return size;
1246 static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
1247 .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
1248 .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
1249 .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
1250 .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
1251 .size_get = mlxsw_sp_dpipe_table_adj_size_get,
1254 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
1256 static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
1258 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1259 int err;
1261 err = devlink_dpipe_table_register(devlink,
1262 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1263 &mlxsw_sp_dpipe_table_adj_ops,
1264 mlxsw_sp, false);
1265 if (err)
1266 return err;
1268 err = devlink_dpipe_table_resource_set(devlink,
1269 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1270 MLXSW_SP_RESOURCE_KVD_LINEAR,
1271 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ);
1272 if (err)
1273 goto err_resource_set;
1275 return 0;
1277 err_resource_set:
1278 devlink_dpipe_table_unregister(devlink,
1279 MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1280 return err;
1283 static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
1285 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1287 devlink_dpipe_table_unregister(devlink,
1288 MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1291 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
1293 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1294 int err;
1296 err = devlink_dpipe_headers_register(devlink,
1297 &mlxsw_sp_dpipe_headers);
1298 if (err)
1299 return err;
1300 err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
1301 if (err)
1302 goto err_erif_table_init;
1304 err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
1305 if (err)
1306 goto err_host4_table_init;
1308 err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
1309 if (err)
1310 goto err_host6_table_init;
1312 err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
1313 if (err)
1314 goto err_adj_table_init;
1316 return 0;
1317 err_adj_table_init:
1318 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1319 err_host6_table_init:
1320 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1321 err_host4_table_init:
1322 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1323 err_erif_table_init:
1324 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
1325 return err;
1328 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
1330 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1332 mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
1333 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1334 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1335 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1336 devlink_dpipe_headers_unregister(devlink);