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