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