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