1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35#include <linux/kernel.h>
36#include <net/devlink.h>
37
38#include "spectrum.h"
39#include "spectrum_dpipe.h"
40#include "spectrum_router.h"
41
42enum 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};
47
48static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
49 { .name = "erif_port",
50 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
51 .bitwidth = 32,
52 .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
53 },
54 { .name = "l3_forward",
55 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
56 .bitwidth = 1,
57 },
58 { .name = "l3_drop",
59 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
60 .bitwidth = 1,
61 },
62};
63
64enum mlxsw_sp_dpipe_header_id {
65 MLXSW_SP_DPIPE_HEADER_METADATA,
66};
67
68static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
69 .name = "mlxsw_meta",
70 .id = MLXSW_SP_DPIPE_HEADER_METADATA,
71 .fields = mlxsw_sp_dpipe_fields_metadata,
72 .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
73};
74
75static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
76 &mlxsw_sp_dpipe_header_metadata,
77 &devlink_dpipe_header_ethernet,
78 &devlink_dpipe_header_ipv4,
79 &devlink_dpipe_header_ipv6,
80};
81
82static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
83 .headers = mlxsw_dpipe_headers,
84 .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
85};
86
87static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
88 struct sk_buff *skb)
89{
90 struct devlink_dpipe_action action = {0};
91 int err;
92
93 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
94 action.header = &mlxsw_sp_dpipe_header_metadata;
95 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
96
97 err = devlink_dpipe_action_put(skb, &action);
98 if (err)
99 return err;
100
101 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
102 action.header = &mlxsw_sp_dpipe_header_metadata;
103 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
104
105 return devlink_dpipe_action_put(skb, &action);
106}
107
108static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
109 struct sk_buff *skb)
110{
111 struct devlink_dpipe_match match = {0};
112
113 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
114 match.header = &mlxsw_sp_dpipe_header_metadata;
115 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
116
117 return devlink_dpipe_match_put(skb, &match);
118}
119
120static void
121mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
122 struct devlink_dpipe_action *action)
123{
124 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
125 action->header = &mlxsw_sp_dpipe_header_metadata;
126 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
127
128 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
129 match->header = &mlxsw_sp_dpipe_header_metadata;
130 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
131}
132
133static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
134 struct devlink_dpipe_value *match_value,
135 struct devlink_dpipe_match *match,
136 struct devlink_dpipe_value *action_value,
137 struct devlink_dpipe_action *action)
138{
139 entry->match_values = match_value;
140 entry->match_values_count = 1;
141
142 entry->action_values = action_value;
143 entry->action_values_count = 1;
144
145 match_value->match = match;
146 match_value->value_size = sizeof(u32);
147 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
148 if (!match_value->value)
149 return -ENOMEM;
150
151 action_value->action = action;
152 action_value->value_size = sizeof(u32);
153 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
154 if (!action_value->value)
155 goto err_action_alloc;
156 return 0;
157
158err_action_alloc:
159 kfree(match_value->value);
160 return -ENOMEM;
161}
162
163static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
164 struct devlink_dpipe_entry *entry,
165 struct mlxsw_sp_rif *rif,
166 bool counters_enabled)
167{
168 u32 *action_value;
169 u32 *rif_value;
170 u64 cnt;
171 int err;
172
173
174 rif_value = entry->match_values->value;
175 *rif_value = mlxsw_sp_rif_index(rif);
176 entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
177 entry->match_values->mapping_valid = true;
178
179
180 action_value = entry->action_values->value;
181 *action_value = 1;
182
183 entry->counter_valid = false;
184 entry->counter = 0;
185 entry->index = mlxsw_sp_rif_index(rif);
186
187 if (!counters_enabled)
188 return 0;
189
190 err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
191 MLXSW_SP_RIF_COUNTER_EGRESS,
192 &cnt);
193 if (!err) {
194 entry->counter = cnt;
195 entry->counter_valid = true;
196 }
197 return 0;
198}
199
200static int
201mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
202 struct devlink_dpipe_dump_ctx *dump_ctx)
203{
204 struct devlink_dpipe_value match_value, action_value;
205 struct devlink_dpipe_action action = {0};
206 struct devlink_dpipe_match match = {0};
207 struct devlink_dpipe_entry entry = {0};
208 struct mlxsw_sp *mlxsw_sp = priv;
209 unsigned int rif_count;
210 int i, j;
211 int err;
212
213 memset(&match_value, 0, sizeof(match_value));
214 memset(&action_value, 0, sizeof(action_value));
215
216 mlxsw_sp_erif_match_action_prepare(&match, &action);
217 err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
218 &action_value, &action);
219 if (err)
220 return err;
221
222 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
223 rtnl_lock();
224 i = 0;
225start_again:
226 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
227 if (err)
228 return err;
229 j = 0;
230 for (; i < rif_count; i++) {
231 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
232
233 if (!rif)
234 continue;
235 err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif,
236 counters_enabled);
237 if (err)
238 goto err_entry_get;
239 err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
240 if (err) {
241 if (err == -EMSGSIZE) {
242 if (!j)
243 goto err_entry_append;
244 break;
245 }
246 goto err_entry_append;
247 }
248 j++;
249 }
250
251 devlink_dpipe_entry_ctx_close(dump_ctx);
252 if (i != rif_count)
253 goto start_again;
254 rtnl_unlock();
255
256 devlink_dpipe_entry_clear(&entry);
257 return 0;
258err_entry_append:
259err_entry_get:
260 rtnl_unlock();
261 devlink_dpipe_entry_clear(&entry);
262 return err;
263}
264
265static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
266{
267 struct mlxsw_sp *mlxsw_sp = priv;
268 int i;
269
270 rtnl_lock();
271 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
272 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
273
274 if (!rif)
275 continue;
276 if (enable)
277 mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
278 MLXSW_SP_RIF_COUNTER_EGRESS);
279 else
280 mlxsw_sp_rif_counter_free(mlxsw_sp, rif,
281 MLXSW_SP_RIF_COUNTER_EGRESS);
282 }
283 rtnl_unlock();
284 return 0;
285}
286
287static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
288{
289 struct mlxsw_sp *mlxsw_sp = priv;
290
291 return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
292}
293
294static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
295 .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
296 .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
297 .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
298 .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
299 .size_get = mlxsw_sp_dpipe_table_erif_size_get,
300};
301
302static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
303{
304 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
305
306 return devlink_dpipe_table_register(devlink,
307 MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
308 &mlxsw_sp_erif_ops,
309 mlxsw_sp, false);
310}
311
312static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
313{
314 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
315
316 devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
317}
318
319static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
320{
321 struct devlink_dpipe_match match = {0};
322 int err;
323
324 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
325 match.header = &mlxsw_sp_dpipe_header_metadata;
326 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
327
328 err = devlink_dpipe_match_put(skb, &match);
329 if (err)
330 return err;
331
332 switch (type) {
333 case AF_INET:
334 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
335 match.header = &devlink_dpipe_header_ipv4;
336 match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
337 break;
338 case AF_INET6:
339 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
340 match.header = &devlink_dpipe_header_ipv6;
341 match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
342 break;
343 default:
344 WARN_ON(1);
345 return -EINVAL;
346 }
347
348 return devlink_dpipe_match_put(skb, &match);
349}
350
351static int
352mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
353{
354 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
355}
356
357static int
358mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
359{
360 struct devlink_dpipe_action action = {0};
361
362 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
363 action.header = &devlink_dpipe_header_ethernet;
364 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
365
366 return devlink_dpipe_action_put(skb, &action);
367}
368
369enum mlxsw_sp_dpipe_table_host_match {
370 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
371 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
372 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
373};
374
375static void
376mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
377 struct devlink_dpipe_action *action,
378 int type)
379{
380 struct devlink_dpipe_match *match;
381
382 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
383 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
384 match->header = &mlxsw_sp_dpipe_header_metadata;
385 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
386
387 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
388 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
389 switch (type) {
390 case AF_INET:
391 match->header = &devlink_dpipe_header_ipv4;
392 match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
393 break;
394 case AF_INET6:
395 match->header = &devlink_dpipe_header_ipv6;
396 match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
397 break;
398 default:
399 WARN_ON(1);
400 return;
401 }
402
403 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
404 action->header = &devlink_dpipe_header_ethernet;
405 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
406}
407
408static int
409mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
410 struct devlink_dpipe_value *match_values,
411 struct devlink_dpipe_match *matches,
412 struct devlink_dpipe_value *action_value,
413 struct devlink_dpipe_action *action,
414 int type)
415{
416 struct devlink_dpipe_value *match_value;
417 struct devlink_dpipe_match *match;
418
419 entry->match_values = match_values;
420 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
421
422 entry->action_values = action_value;
423 entry->action_values_count = 1;
424
425 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
426 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
427
428 match_value->match = match;
429 match_value->value_size = sizeof(u32);
430 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
431 if (!match_value->value)
432 return -ENOMEM;
433
434 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
435 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
436
437 match_value->match = match;
438 switch (type) {
439 case AF_INET:
440 match_value->value_size = sizeof(u32);
441 break;
442 case AF_INET6:
443 match_value->value_size = sizeof(struct in6_addr);
444 break;
445 default:
446 WARN_ON(1);
447 return -EINVAL;
448 }
449
450 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
451 if (!match_value->value)
452 return -ENOMEM;
453
454 action_value->action = action;
455 action_value->value_size = sizeof(u64);
456 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
457 if (!action_value->value)
458 return -ENOMEM;
459
460 return 0;
461}
462
463static void
464__mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
465 struct mlxsw_sp_rif *rif,
466 unsigned char *ha, void *dip)
467{
468 struct devlink_dpipe_value *value;
469 u32 *rif_value;
470 u8 *ha_value;
471
472
473 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
474
475 rif_value = value->value;
476 *rif_value = mlxsw_sp_rif_index(rif);
477 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
478 value->mapping_valid = true;
479
480
481 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
482 memcpy(value->value, dip, value->value_size);
483
484
485 value = entry->action_values;
486 ha_value = value->value;
487 ether_addr_copy(ha_value, ha);
488}
489
490static void
491mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
492 struct mlxsw_sp_neigh_entry *neigh_entry,
493 struct mlxsw_sp_rif *rif)
494{
495 unsigned char *ha;
496 u32 dip;
497
498 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
499 dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
500 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
501}
502
503static void
504mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
505 struct mlxsw_sp_neigh_entry *neigh_entry,
506 struct mlxsw_sp_rif *rif)
507{
508 struct in6_addr *dip;
509 unsigned char *ha;
510
511 ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
512 dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
513
514 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
515}
516
517static void
518mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
519 struct devlink_dpipe_entry *entry,
520 struct mlxsw_sp_neigh_entry *neigh_entry,
521 struct mlxsw_sp_rif *rif,
522 int type)
523{
524 int err;
525
526 switch (type) {
527 case AF_INET:
528 mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
529 break;
530 case AF_INET6:
531 mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
532 break;
533 default:
534 WARN_ON(1);
535 return;
536 }
537
538 err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
539 &entry->counter);
540 if (!err)
541 entry->counter_valid = true;
542}
543
544static int
545mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
546 struct devlink_dpipe_entry *entry,
547 bool counters_enabled,
548 struct devlink_dpipe_dump_ctx *dump_ctx,
549 int type)
550{
551 int rif_neigh_count = 0;
552 int rif_neigh_skip = 0;
553 int neigh_count = 0;
554 int rif_count;
555 int i, j;
556 int err;
557
558 rtnl_lock();
559 i = 0;
560 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
561start_again:
562 err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
563 if (err)
564 goto err_ctx_prepare;
565 j = 0;
566 rif_neigh_skip = rif_neigh_count;
567 for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
568 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
569 struct mlxsw_sp_neigh_entry *neigh_entry;
570
571 if (!rif)
572 continue;
573
574 rif_neigh_count = 0;
575 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
576 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
577
578 if (neigh_type != type)
579 continue;
580
581 if (neigh_type == AF_INET6 &&
582 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
583 continue;
584
585 if (rif_neigh_count < rif_neigh_skip)
586 goto skip;
587
588 mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
589 neigh_entry, rif,
590 type);
591 entry->index = neigh_count;
592 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
593 if (err) {
594 if (err == -EMSGSIZE) {
595 if (!j)
596 goto err_entry_append;
597 else
598 goto out;
599 }
600 goto err_entry_append;
601 }
602 neigh_count++;
603 j++;
604skip:
605 rif_neigh_count++;
606 }
607 rif_neigh_skip = 0;
608 }
609out:
610 devlink_dpipe_entry_ctx_close(dump_ctx);
611 if (i != rif_count)
612 goto start_again;
613
614 rtnl_unlock();
615 return 0;
616
617err_ctx_prepare:
618err_entry_append:
619 rtnl_unlock();
620 return err;
621}
622
623static int
624mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
625 bool counters_enabled,
626 struct devlink_dpipe_dump_ctx *dump_ctx,
627 int type)
628{
629 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
630 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
631 struct devlink_dpipe_value action_value;
632 struct devlink_dpipe_action action = {0};
633 struct devlink_dpipe_entry entry = {0};
634 int err;
635
636 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
637 sizeof(matches[0]));
638 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
639 sizeof(match_values[0]));
640 memset(&action_value, 0, sizeof(action_value));
641
642 mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
643 err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
644 matches, &action_value,
645 &action, type);
646 if (err)
647 goto out;
648
649 err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
650 counters_enabled, dump_ctx,
651 type);
652out:
653 devlink_dpipe_entry_clear(&entry);
654 return err;
655}
656
657static int
658mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
659 struct devlink_dpipe_dump_ctx *dump_ctx)
660{
661 struct mlxsw_sp *mlxsw_sp = priv;
662
663 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
664 counters_enabled,
665 dump_ctx, AF_INET);
666}
667
668static void
669mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
670 bool enable, int type)
671{
672 int i;
673
674 rtnl_lock();
675 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
676 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
677 struct mlxsw_sp_neigh_entry *neigh_entry;
678
679 if (!rif)
680 continue;
681 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
682 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
683
684 if (neigh_type != type)
685 continue;
686
687 if (neigh_type == AF_INET6 &&
688 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
689 continue;
690
691 mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
692 neigh_entry,
693 enable);
694 }
695 }
696 rtnl_unlock();
697}
698
699static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
700{
701 struct mlxsw_sp *mlxsw_sp = priv;
702
703 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
704 return 0;
705}
706
707static u64
708mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
709{
710 u64 size = 0;
711 int i;
712
713 rtnl_lock();
714 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
715 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
716 struct mlxsw_sp_neigh_entry *neigh_entry;
717
718 if (!rif)
719 continue;
720 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
721 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
722
723 if (neigh_type != type)
724 continue;
725
726 if (neigh_type == AF_INET6 &&
727 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
728 continue;
729
730 size++;
731 }
732 }
733 rtnl_unlock();
734
735 return size;
736}
737
738static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
739{
740 struct mlxsw_sp *mlxsw_sp = priv;
741
742 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
743}
744
745static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
746 .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
747 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
748 .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
749 .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
750 .size_get = mlxsw_sp_dpipe_table_host4_size_get,
751};
752
753static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
754{
755 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
756
757 return devlink_dpipe_table_register(devlink,
758 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
759 &mlxsw_sp_host4_ops,
760 mlxsw_sp, false);
761}
762
763static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
764{
765 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
766
767 devlink_dpipe_table_unregister(devlink,
768 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
769}
770
771static int
772mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
773{
774 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
775}
776
777static int
778mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
779 struct devlink_dpipe_dump_ctx *dump_ctx)
780{
781 struct mlxsw_sp *mlxsw_sp = priv;
782
783 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
784 counters_enabled,
785 dump_ctx, AF_INET6);
786}
787
788static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
789{
790 struct mlxsw_sp *mlxsw_sp = priv;
791
792 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
793 return 0;
794}
795
796static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
797{
798 struct mlxsw_sp *mlxsw_sp = priv;
799
800 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
801}
802
803static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
804 .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
805 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
806 .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
807 .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
808 .size_get = mlxsw_sp_dpipe_table_host6_size_get,
809};
810
811static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
812{
813 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
814
815 return devlink_dpipe_table_register(devlink,
816 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
817 &mlxsw_sp_host6_ops,
818 mlxsw_sp, false);
819}
820
821static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
822{
823 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
824
825 devlink_dpipe_table_unregister(devlink,
826 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
827}
828
829int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
830{
831 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
832 int err;
833
834 err = devlink_dpipe_headers_register(devlink,
835 &mlxsw_sp_dpipe_headers);
836 if (err)
837 return err;
838 err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
839 if (err)
840 goto err_erif_table_init;
841
842 err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
843 if (err)
844 goto err_host4_table_init;
845
846 err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
847 if (err)
848 goto err_host6_table_init;
849 return 0;
850
851err_host6_table_init:
852 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
853err_host4_table_init:
854 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
855err_erif_table_init:
856 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
857 return err;
858}
859
860void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
861{
862 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
863
864 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
865 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
866 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
867 devlink_dpipe_headers_unregister(devlink);
868}
869