Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_dpipe.c
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3
4 #include <linux/kernel.h>
5 #include <net/devlink.h>
6
7 #include "spectrum.h"
8 #include "spectrum_dpipe.h"
9 #include "spectrum_router.h"
10
11 enum mlxsw_sp_field_metadata_id {
12         MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
13         MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
14         MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
15         MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
16         MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
17         MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
18 };
19
20 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
21         {
22                 .name = "erif_port",
23                 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
24                 .bitwidth = 32,
25                 .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
26         },
27         {
28                 .name = "l3_forward",
29                 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
30                 .bitwidth = 1,
31         },
32         {
33                 .name = "l3_drop",
34                 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
35                 .bitwidth = 1,
36         },
37         {
38                 .name = "adj_index",
39                 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
40                 .bitwidth = 32,
41         },
42         {
43                 .name = "adj_size",
44                 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
45                 .bitwidth = 32,
46         },
47         {
48                 .name = "adj_hash_index",
49                 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
50                 .bitwidth = 32,
51         },
52 };
53
54 enum mlxsw_sp_dpipe_header_id {
55         MLXSW_SP_DPIPE_HEADER_METADATA,
56 };
57
58 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
59         .name = "mlxsw_meta",
60         .id = MLXSW_SP_DPIPE_HEADER_METADATA,
61         .fields = mlxsw_sp_dpipe_fields_metadata,
62         .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
63 };
64
65 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
66         &mlxsw_sp_dpipe_header_metadata,
67         &devlink_dpipe_header_ethernet,
68         &devlink_dpipe_header_ipv4,
69         &devlink_dpipe_header_ipv6,
70 };
71
72 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
73         .headers = mlxsw_dpipe_headers,
74         .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
75 };
76
77 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
78                                                   struct sk_buff *skb)
79 {
80         struct devlink_dpipe_action action = {0};
81         int err;
82
83         action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
84         action.header = &mlxsw_sp_dpipe_header_metadata;
85         action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
86
87         err = devlink_dpipe_action_put(skb, &action);
88         if (err)
89                 return err;
90
91         action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
92         action.header = &mlxsw_sp_dpipe_header_metadata;
93         action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
94
95         return devlink_dpipe_action_put(skb, &action);
96 }
97
98 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
99                                                   struct sk_buff *skb)
100 {
101         struct devlink_dpipe_match match = {0};
102
103         match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
104         match.header = &mlxsw_sp_dpipe_header_metadata;
105         match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
106
107         return devlink_dpipe_match_put(skb, &match);
108 }
109
110 static void
111 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
112                                    struct devlink_dpipe_action *action)
113 {
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;
117
118         match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
119         match->header = &mlxsw_sp_dpipe_header_metadata;
120         match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
121 }
122
123 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
124                                        struct devlink_dpipe_value *match_value,
125                                        struct devlink_dpipe_match *match,
126                                        struct devlink_dpipe_value *action_value,
127                                        struct devlink_dpipe_action *action)
128 {
129         entry->match_values = match_value;
130         entry->match_values_count = 1;
131
132         entry->action_values = action_value;
133         entry->action_values_count = 1;
134
135         match_value->match = match;
136         match_value->value_size = sizeof(u32);
137         match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
138         if (!match_value->value)
139                 return -ENOMEM;
140
141         action_value->action = action;
142         action_value->value_size = sizeof(u32);
143         action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
144         if (!action_value->value)
145                 goto err_action_alloc;
146         return 0;
147
148 err_action_alloc:
149         kfree(match_value->value);
150         return -ENOMEM;
151 }
152
153 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
154                                    struct devlink_dpipe_entry *entry,
155                                    struct mlxsw_sp_rif *rif,
156                                    bool counters_enabled)
157 {
158         u32 *action_value;
159         u32 *rif_value;
160         u64 cnt;
161         int err;
162
163         /* Set Match RIF index */
164         rif_value = entry->match_values->value;
165         *rif_value = mlxsw_sp_rif_index(rif);
166         entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
167         entry->match_values->mapping_valid = true;
168
169         /* Set Action Forwarding */
170         action_value = entry->action_values->value;
171         *action_value = 1;
172
173         entry->counter_valid = false;
174         entry->counter = 0;
175         entry->index = mlxsw_sp_rif_index(rif);
176
177         if (!counters_enabled)
178                 return 0;
179
180         err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
181                                              MLXSW_SP_RIF_COUNTER_EGRESS,
182                                              &cnt);
183         if (!err) {
184                 entry->counter = cnt;
185                 entry->counter_valid = true;
186         }
187         return 0;
188 }
189
190 static int
191 mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
192                                        struct devlink_dpipe_dump_ctx *dump_ctx)
193 {
194         struct devlink_dpipe_value match_value, action_value;
195         struct devlink_dpipe_action action = {0};
196         struct devlink_dpipe_match match = {0};
197         struct devlink_dpipe_entry entry = {0};
198         struct mlxsw_sp *mlxsw_sp = priv;
199         unsigned int rif_count;
200         int i, j;
201         int err;
202
203         memset(&match_value, 0, sizeof(match_value));
204         memset(&action_value, 0, sizeof(action_value));
205
206         mlxsw_sp_erif_match_action_prepare(&match, &action);
207         err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
208                                           &action_value, &action);
209         if (err)
210                 return err;
211
212         rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
213         rtnl_lock();
214         i = 0;
215 start_again:
216         err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
217         if (err)
218                 goto err_ctx_prepare;
219         j = 0;
220         for (; i < rif_count; i++) {
221                 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
222
223                 if (!rif || !mlxsw_sp_rif_dev(rif))
224                         continue;
225                 err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif,
226                                               counters_enabled);
227                 if (err)
228                         goto err_entry_get;
229                 err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
230                 if (err) {
231                         if (err == -EMSGSIZE) {
232                                 if (!j)
233                                         goto err_entry_append;
234                                 break;
235                         }
236                         goto err_entry_append;
237                 }
238                 j++;
239         }
240
241         devlink_dpipe_entry_ctx_close(dump_ctx);
242         if (i != rif_count)
243                 goto start_again;
244         rtnl_unlock();
245
246         devlink_dpipe_entry_clear(&entry);
247         return 0;
248 err_entry_append:
249 err_entry_get:
250 err_ctx_prepare:
251         rtnl_unlock();
252         devlink_dpipe_entry_clear(&entry);
253         return err;
254 }
255
256 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
257 {
258         struct mlxsw_sp *mlxsw_sp = priv;
259         int i;
260
261         rtnl_lock();
262         for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
263                 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
264
265                 if (!rif)
266                         continue;
267                 if (enable)
268                         mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
269                                                    MLXSW_SP_RIF_COUNTER_EGRESS);
270                 else
271                         mlxsw_sp_rif_counter_free(mlxsw_sp, rif,
272                                                   MLXSW_SP_RIF_COUNTER_EGRESS);
273         }
274         rtnl_unlock();
275         return 0;
276 }
277
278 static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
279 {
280         struct mlxsw_sp *mlxsw_sp = priv;
281
282         return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
283 }
284
285 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
286         .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
287         .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
288         .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
289         .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
290         .size_get = mlxsw_sp_dpipe_table_erif_size_get,
291 };
292
293 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
294 {
295         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
296
297         return devlink_dpipe_table_register(devlink,
298                                             MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
299                                             &mlxsw_sp_erif_ops,
300                                             mlxsw_sp, false);
301 }
302
303 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
304 {
305         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
306
307         devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
308 }
309
310 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
311 {
312         struct devlink_dpipe_match match = {0};
313         int err;
314
315         match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
316         match.header = &mlxsw_sp_dpipe_header_metadata;
317         match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
318
319         err = devlink_dpipe_match_put(skb, &match);
320         if (err)
321                 return err;
322
323         switch (type) {
324         case AF_INET:
325                 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
326                 match.header = &devlink_dpipe_header_ipv4;
327                 match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
328                 break;
329         case AF_INET6:
330                 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
331                 match.header = &devlink_dpipe_header_ipv6;
332                 match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
333                 break;
334         default:
335                 WARN_ON(1);
336                 return -EINVAL;
337         }
338
339         return devlink_dpipe_match_put(skb, &match);
340 }
341
342 static int
343 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
344 {
345         return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
346 }
347
348 static int
349 mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
350 {
351         struct devlink_dpipe_action action = {0};
352
353         action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
354         action.header = &devlink_dpipe_header_ethernet;
355         action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
356
357         return devlink_dpipe_action_put(skb, &action);
358 }
359
360 enum mlxsw_sp_dpipe_table_host_match {
361         MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
362         MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
363         MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
364 };
365
366 static void
367 mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
368                                                struct devlink_dpipe_action *action,
369                                                int type)
370 {
371         struct devlink_dpipe_match *match;
372
373         match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
374         match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
375         match->header = &mlxsw_sp_dpipe_header_metadata;
376         match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
377
378         match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
379         match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
380         switch (type) {
381         case AF_INET:
382                 match->header = &devlink_dpipe_header_ipv4;
383                 match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
384                 break;
385         case AF_INET6:
386                 match->header = &devlink_dpipe_header_ipv6;
387                 match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
388                 break;
389         default:
390                 WARN_ON(1);
391                 return;
392         }
393
394         action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
395         action->header = &devlink_dpipe_header_ethernet;
396         action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
397 }
398
399 static int
400 mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
401                                         struct devlink_dpipe_value *match_values,
402                                         struct devlink_dpipe_match *matches,
403                                         struct devlink_dpipe_value *action_value,
404                                         struct devlink_dpipe_action *action,
405                                         int type)
406 {
407         struct devlink_dpipe_value *match_value;
408         struct devlink_dpipe_match *match;
409
410         entry->match_values = match_values;
411         entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
412
413         entry->action_values = action_value;
414         entry->action_values_count = 1;
415
416         match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
417         match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
418
419         match_value->match = match;
420         match_value->value_size = sizeof(u32);
421         match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
422         if (!match_value->value)
423                 return -ENOMEM;
424
425         match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
426         match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
427
428         match_value->match = match;
429         switch (type) {
430         case AF_INET:
431                 match_value->value_size = sizeof(u32);
432                 break;
433         case AF_INET6:
434                 match_value->value_size = sizeof(struct in6_addr);
435                 break;
436         default:
437                 WARN_ON(1);
438                 return -EINVAL;
439         }
440
441         match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
442         if (!match_value->value)
443                 return -ENOMEM;
444
445         action_value->action = action;
446         action_value->value_size = sizeof(u64);
447         action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
448         if (!action_value->value)
449                 return -ENOMEM;
450
451         return 0;
452 }
453
454 static void
455 __mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
456                                        struct mlxsw_sp_rif *rif,
457                                        unsigned char *ha, void *dip)
458 {
459         struct devlink_dpipe_value *value;
460         u32 *rif_value;
461         u8 *ha_value;
462
463         /* Set Match RIF index */
464         value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
465
466         rif_value = value->value;
467         *rif_value = mlxsw_sp_rif_index(rif);
468         value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
469         value->mapping_valid = true;
470
471         /* Set Match DIP */
472         value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
473         memcpy(value->value, dip, value->value_size);
474
475         /* Set Action DMAC */
476         value = entry->action_values;
477         ha_value = value->value;
478         ether_addr_copy(ha_value, ha);
479 }
480
481 static void
482 mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
483                                       struct mlxsw_sp_neigh_entry *neigh_entry,
484                                       struct mlxsw_sp_rif *rif)
485 {
486         unsigned char *ha;
487         u32 dip;
488
489         ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
490         dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
491         __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
492 }
493
494 static void
495 mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
496                                       struct mlxsw_sp_neigh_entry *neigh_entry,
497                                       struct mlxsw_sp_rif *rif)
498 {
499         struct in6_addr *dip;
500         unsigned char *ha;
501
502         ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
503         dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
504
505         __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
506 }
507
508 static void
509 mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
510                                      struct devlink_dpipe_entry *entry,
511                                      struct mlxsw_sp_neigh_entry *neigh_entry,
512                                      struct mlxsw_sp_rif *rif,
513                                      int type)
514 {
515         int err;
516
517         switch (type) {
518         case AF_INET:
519                 mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
520                 break;
521         case AF_INET6:
522                 mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
523                 break;
524         default:
525                 WARN_ON(1);
526                 return;
527         }
528
529         err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
530                                          &entry->counter);
531         if (!err)
532                 entry->counter_valid = true;
533 }
534
535 static int
536 mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
537                                       struct devlink_dpipe_entry *entry,
538                                       bool counters_enabled,
539                                       struct devlink_dpipe_dump_ctx *dump_ctx,
540                                       int type)
541 {
542         int rif_neigh_count = 0;
543         int rif_neigh_skip = 0;
544         int neigh_count = 0;
545         int rif_count;
546         int i, j;
547         int err;
548
549         rtnl_lock();
550         i = 0;
551         rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
552 start_again:
553         err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
554         if (err)
555                 goto err_ctx_prepare;
556         j = 0;
557         rif_neigh_skip = rif_neigh_count;
558         for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
559                 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
560                 struct mlxsw_sp_neigh_entry *neigh_entry;
561
562                 if (!rif)
563                         continue;
564
565                 rif_neigh_count = 0;
566                 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
567                         int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
568
569                         if (neigh_type != type)
570                                 continue;
571
572                         if (neigh_type == AF_INET6 &&
573                             mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
574                                 continue;
575
576                         if (rif_neigh_count < rif_neigh_skip)
577                                 goto skip;
578
579                         mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
580                                                              neigh_entry, rif,
581                                                              type);
582                         entry->index = neigh_count;
583                         err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
584                         if (err) {
585                                 if (err == -EMSGSIZE) {
586                                         if (!j)
587                                                 goto err_entry_append;
588                                         else
589                                                 goto out;
590                                 }
591                                 goto err_entry_append;
592                         }
593                         neigh_count++;
594                         j++;
595 skip:
596                         rif_neigh_count++;
597                 }
598                 rif_neigh_skip = 0;
599         }
600 out:
601         devlink_dpipe_entry_ctx_close(dump_ctx);
602         if (i != rif_count)
603                 goto start_again;
604
605         rtnl_unlock();
606         return 0;
607
608 err_ctx_prepare:
609 err_entry_append:
610         rtnl_unlock();
611         return err;
612 }
613
614 static int
615 mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
616                                        bool counters_enabled,
617                                        struct devlink_dpipe_dump_ctx *dump_ctx,
618                                        int type)
619 {
620         struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
621         struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
622         struct devlink_dpipe_value action_value;
623         struct devlink_dpipe_action action = {0};
624         struct devlink_dpipe_entry entry = {0};
625         int err;
626
627         memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
628                            sizeof(matches[0]));
629         memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
630                                 sizeof(match_values[0]));
631         memset(&action_value, 0, sizeof(action_value));
632
633         mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
634         err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
635                                                       matches, &action_value,
636                                                       &action, type);
637         if (err)
638                 goto out;
639
640         err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
641                                                     counters_enabled, dump_ctx,
642                                                     type);
643 out:
644         devlink_dpipe_entry_clear(&entry);
645         return err;
646 }
647
648 static int
649 mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
650                                         struct devlink_dpipe_dump_ctx *dump_ctx)
651 {
652         struct mlxsw_sp *mlxsw_sp = priv;
653
654         return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
655                                                       counters_enabled,
656                                                       dump_ctx, AF_INET);
657 }
658
659 static void
660 mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
661                                           bool enable, int type)
662 {
663         int i;
664
665         rtnl_lock();
666         for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
667                 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
668                 struct mlxsw_sp_neigh_entry *neigh_entry;
669
670                 if (!rif)
671                         continue;
672                 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
673                         int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
674
675                         if (neigh_type != type)
676                                 continue;
677
678                         if (neigh_type == AF_INET6 &&
679                             mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
680                                 continue;
681
682                         mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
683                                                             neigh_entry,
684                                                             enable);
685                 }
686         }
687         rtnl_unlock();
688 }
689
690 static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
691 {
692         struct mlxsw_sp *mlxsw_sp = priv;
693
694         mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
695         return 0;
696 }
697
698 static u64
699 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
700 {
701         u64 size = 0;
702         int i;
703
704         rtnl_lock();
705         for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
706                 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
707                 struct mlxsw_sp_neigh_entry *neigh_entry;
708
709                 if (!rif)
710                         continue;
711                 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
712                         int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
713
714                         if (neigh_type != type)
715                                 continue;
716
717                         if (neigh_type == AF_INET6 &&
718                             mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
719                                 continue;
720
721                         size++;
722                 }
723         }
724         rtnl_unlock();
725
726         return size;
727 }
728
729 static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
730 {
731         struct mlxsw_sp *mlxsw_sp = priv;
732
733         return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
734 }
735
736 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
737         .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
738         .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
739         .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
740         .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
741         .size_get = mlxsw_sp_dpipe_table_host4_size_get,
742 };
743
744 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1
745
746 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
747 {
748         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
749         int err;
750
751         err = devlink_dpipe_table_register(devlink,
752                                            MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
753                                            &mlxsw_sp_host4_ops,
754                                            mlxsw_sp, false);
755         if (err)
756                 return err;
757
758         err = devlink_dpipe_table_resource_set(devlink,
759                                                MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
760                                                MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
761                                                MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4);
762         if (err)
763                 goto err_resource_set;
764
765         return 0;
766
767 err_resource_set:
768         devlink_dpipe_table_unregister(devlink,
769                                        MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
770         return err;
771 }
772
773 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
774 {
775         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
776
777         devlink_dpipe_table_unregister(devlink,
778                                        MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
779 }
780
781 static int
782 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
783 {
784         return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
785 }
786
787 static int
788 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
789                                         struct devlink_dpipe_dump_ctx *dump_ctx)
790 {
791         struct mlxsw_sp *mlxsw_sp = priv;
792
793         return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
794                                                       counters_enabled,
795                                                       dump_ctx, AF_INET6);
796 }
797
798 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
799 {
800         struct mlxsw_sp *mlxsw_sp = priv;
801
802         mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
803         return 0;
804 }
805
806 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
807 {
808         struct mlxsw_sp *mlxsw_sp = priv;
809
810         return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
811 }
812
813 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
814         .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
815         .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
816         .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
817         .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
818         .size_get = mlxsw_sp_dpipe_table_host6_size_get,
819 };
820
821 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2
822
823 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
824 {
825         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
826         int err;
827
828         err = devlink_dpipe_table_register(devlink,
829                                            MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
830                                            &mlxsw_sp_host6_ops,
831                                            mlxsw_sp, false);
832         if (err)
833                 return err;
834
835         err = devlink_dpipe_table_resource_set(devlink,
836                                                MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
837                                                MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
838                                                MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6);
839         if (err)
840                 goto err_resource_set;
841
842         return 0;
843
844 err_resource_set:
845         devlink_dpipe_table_unregister(devlink,
846                                        MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
847         return err;
848 }
849
850 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
851 {
852         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
853
854         devlink_dpipe_table_unregister(devlink,
855                                        MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
856 }
857
858 static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
859                                                  struct sk_buff *skb)
860 {
861         struct devlink_dpipe_match match = {0};
862         int err;
863
864         match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
865         match.header = &mlxsw_sp_dpipe_header_metadata;
866         match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
867
868         err = devlink_dpipe_match_put(skb, &match);
869         if (err)
870                 return err;
871
872         match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
873         match.header = &mlxsw_sp_dpipe_header_metadata;
874         match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
875
876         err = devlink_dpipe_match_put(skb, &match);
877         if (err)
878                 return err;
879
880         match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
881         match.header = &mlxsw_sp_dpipe_header_metadata;
882         match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
883
884         return devlink_dpipe_match_put(skb, &match);
885 }
886
887 static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
888                                                  struct sk_buff *skb)
889 {
890         struct devlink_dpipe_action action = {0};
891         int err;
892
893         action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
894         action.header = &devlink_dpipe_header_ethernet;
895         action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
896
897         err = devlink_dpipe_action_put(skb, &action);
898         if (err)
899                 return err;
900
901         action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
902         action.header = &mlxsw_sp_dpipe_header_metadata;
903         action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
904
905         return devlink_dpipe_action_put(skb, &action);
906 }
907
908 static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
909 {
910         struct mlxsw_sp_nexthop *nh;
911         u64 size = 0;
912
913         mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
914                 if (mlxsw_sp_nexthop_offload(nh) &&
915                     !mlxsw_sp_nexthop_group_has_ipip(nh))
916                         size++;
917         return size;
918 }
919
920 enum mlxsw_sp_dpipe_table_adj_match {
921         MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
922         MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE,
923         MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
924         MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
925 };
926
927 enum mlxsw_sp_dpipe_table_adj_action {
928         MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
929         MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
930         MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
931 };
932
933 static void
934 mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
935                                               struct devlink_dpipe_action *actions)
936 {
937         struct devlink_dpipe_action *action;
938         struct devlink_dpipe_match *match;
939
940         match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
941         match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
942         match->header = &mlxsw_sp_dpipe_header_metadata;
943         match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
944
945         match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
946         match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
947         match->header = &mlxsw_sp_dpipe_header_metadata;
948         match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
949
950         match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
951         match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
952         match->header = &mlxsw_sp_dpipe_header_metadata;
953         match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
954
955         action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
956         action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
957         action->header = &devlink_dpipe_header_ethernet;
958         action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
959
960         action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
961         action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
962         action->header = &mlxsw_sp_dpipe_header_metadata;
963         action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
964 }
965
966 static int
967 mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
968                                        struct devlink_dpipe_value *match_values,
969                                        struct devlink_dpipe_match *matches,
970                                        struct devlink_dpipe_value *action_values,
971                                        struct devlink_dpipe_action *actions)
972 {       struct devlink_dpipe_value *action_value;
973         struct devlink_dpipe_value *match_value;
974         struct devlink_dpipe_action *action;
975         struct devlink_dpipe_match *match;
976
977         entry->match_values = match_values;
978         entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
979
980         entry->action_values = action_values;
981         entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
982
983         match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
984         match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
985
986         match_value->match = match;
987         match_value->value_size = sizeof(u32);
988         match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
989         if (!match_value->value)
990                 return -ENOMEM;
991
992         match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
993         match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
994
995         match_value->match = match;
996         match_value->value_size = sizeof(u32);
997         match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
998         if (!match_value->value)
999                 return -ENOMEM;
1000
1001         match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1002         match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1003
1004         match_value->match = match;
1005         match_value->value_size = sizeof(u32);
1006         match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1007         if (!match_value->value)
1008                 return -ENOMEM;
1009
1010         action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1011         action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1012
1013         action_value->action = action;
1014         action_value->value_size = sizeof(u64);
1015         action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1016         if (!action_value->value)
1017                 return -ENOMEM;
1018
1019         action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1020         action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1021
1022         action_value->action = action;
1023         action_value->value_size = sizeof(u32);
1024         action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1025         if (!action_value->value)
1026                 return -ENOMEM;
1027
1028         return 0;
1029 }
1030
1031 static void
1032 __mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
1033                                       u32 adj_index, u32 adj_size,
1034                                       u32 adj_hash_index, unsigned char *ha,
1035                                       struct mlxsw_sp_rif *rif)
1036 {
1037         struct devlink_dpipe_value *value;
1038         u32 *p_rif_value;
1039         u32 *p_index;
1040
1041         value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1042         p_index = value->value;
1043         *p_index = adj_index;
1044
1045         value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
1046         p_index = value->value;
1047         *p_index = adj_size;
1048
1049         value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1050         p_index = value->value;
1051         *p_index = adj_hash_index;
1052
1053         value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1054         ether_addr_copy(value->value, ha);
1055
1056         value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1057         p_rif_value = value->value;
1058         *p_rif_value = mlxsw_sp_rif_index(rif);
1059         value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
1060         value->mapping_valid = true;
1061 }
1062
1063 static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
1064                                                 struct mlxsw_sp_nexthop *nh,
1065                                                 struct devlink_dpipe_entry *entry)
1066 {
1067         struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
1068         unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
1069         u32 adj_hash_index = 0;
1070         u32 adj_index = 0;
1071         u32 adj_size = 0;
1072         int err;
1073
1074         mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index);
1075         __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size,
1076                                               adj_hash_index, ha, rif);
1077         err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
1078         if (!err)
1079                 entry->counter_valid = true;
1080 }
1081
1082 static int
1083 mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
1084                                      struct devlink_dpipe_entry *entry,
1085                                      bool counters_enabled,
1086                                      struct devlink_dpipe_dump_ctx *dump_ctx)
1087 {
1088         struct mlxsw_sp_nexthop *nh;
1089         int entry_index = 0;
1090         int nh_count_max;
1091         int nh_count = 0;
1092         int nh_skip;
1093         int j;
1094         int err;
1095
1096         rtnl_lock();
1097         nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1098 start_again:
1099         err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
1100         if (err)
1101                 goto err_ctx_prepare;
1102         j = 0;
1103         nh_skip = nh_count;
1104         nh_count = 0;
1105         mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1106                 if (!mlxsw_sp_nexthop_offload(nh) ||
1107                     mlxsw_sp_nexthop_group_has_ipip(nh))
1108                         continue;
1109
1110                 if (nh_count < nh_skip)
1111                         goto skip;
1112
1113                 mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
1114                 entry->index = entry_index;
1115                 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
1116                 if (err) {
1117                         if (err == -EMSGSIZE) {
1118                                 if (!j)
1119                                         goto err_entry_append;
1120                                 break;
1121                         }
1122                         goto err_entry_append;
1123                 }
1124                 entry_index++;
1125                 j++;
1126 skip:
1127                 nh_count++;
1128         }
1129
1130         devlink_dpipe_entry_ctx_close(dump_ctx);
1131         if (nh_count != nh_count_max)
1132                 goto start_again;
1133         rtnl_unlock();
1134
1135         return 0;
1136
1137 err_ctx_prepare:
1138 err_entry_append:
1139         rtnl_unlock();
1140         return err;
1141 }
1142
1143 static int
1144 mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
1145                                       struct devlink_dpipe_dump_ctx *dump_ctx)
1146 {
1147         struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1148         struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1149         struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1150         struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1151         struct devlink_dpipe_entry entry = {0};
1152         struct mlxsw_sp *mlxsw_sp = priv;
1153         int err;
1154
1155         memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1156                            sizeof(matches[0]));
1157         memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1158                                 sizeof(match_values[0]));
1159         memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1160                            sizeof(actions[0]));
1161         memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1162                                  sizeof(action_values[0]));
1163
1164         mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
1165         err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
1166                                                      match_values, matches,
1167                                                      action_values, actions);
1168         if (err)
1169                 goto out;
1170
1171         err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
1172                                                    counters_enabled, dump_ctx);
1173 out:
1174         devlink_dpipe_entry_clear(&entry);
1175         return err;
1176 }
1177
1178 static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
1179 {
1180         struct mlxsw_sp *mlxsw_sp = priv;
1181         struct mlxsw_sp_nexthop *nh;
1182         u32 adj_hash_index = 0;
1183         u32 adj_index = 0;
1184         u32 adj_size = 0;
1185
1186         mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1187                 if (!mlxsw_sp_nexthop_offload(nh) ||
1188                     mlxsw_sp_nexthop_group_has_ipip(nh))
1189                         continue;
1190
1191                 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size,
1192                                          &adj_hash_index);
1193                 if (enable)
1194                         mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
1195                 else
1196                         mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
1197                 mlxsw_sp_nexthop_update(mlxsw_sp,
1198                                         adj_index + adj_hash_index, nh);
1199         }
1200         return 0;
1201 }
1202
1203 static u64
1204 mlxsw_sp_dpipe_table_adj_size_get(void *priv)
1205 {
1206         struct mlxsw_sp *mlxsw_sp = priv;
1207         u64 size;
1208
1209         rtnl_lock();
1210         size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1211         rtnl_unlock();
1212
1213         return size;
1214 }
1215
1216 static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
1217         .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
1218         .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
1219         .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
1220         .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
1221         .size_get = mlxsw_sp_dpipe_table_adj_size_get,
1222 };
1223
1224 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
1225
1226 static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
1227 {
1228         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1229         int err;
1230
1231         err = devlink_dpipe_table_register(devlink,
1232                                            MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1233                                            &mlxsw_sp_dpipe_table_adj_ops,
1234                                            mlxsw_sp, false);
1235         if (err)
1236                 return err;
1237
1238         err = devlink_dpipe_table_resource_set(devlink,
1239                                                MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1240                                                MLXSW_SP_RESOURCE_KVD_LINEAR,
1241                                                MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ);
1242         if (err)
1243                 goto err_resource_set;
1244
1245         return 0;
1246
1247 err_resource_set:
1248         devlink_dpipe_table_unregister(devlink,
1249                                        MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1250         return err;
1251 }
1252
1253 static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
1254 {
1255         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1256
1257         devlink_dpipe_table_unregister(devlink,
1258                                        MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1259 }
1260
1261 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
1262 {
1263         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1264         int err;
1265
1266         err = devlink_dpipe_headers_register(devlink,
1267                                              &mlxsw_sp_dpipe_headers);
1268         if (err)
1269                 return err;
1270         err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
1271         if (err)
1272                 goto err_erif_table_init;
1273
1274         err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
1275         if (err)
1276                 goto err_host4_table_init;
1277
1278         err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
1279         if (err)
1280                 goto err_host6_table_init;
1281
1282         err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
1283         if (err)
1284                 goto err_adj_table_init;
1285
1286         return 0;
1287 err_adj_table_init:
1288         mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1289 err_host6_table_init:
1290         mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1291 err_host4_table_init:
1292         mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1293 err_erif_table_init:
1294         devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
1295         return err;
1296 }
1297
1298 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
1299 {
1300         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1301
1302         mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
1303         mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1304         mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1305         mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1306         devlink_dpipe_headers_unregister(devlink);
1307 }