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