]> Git Repo - linux.git/blob - net/devlink/dpipe.c
Linux 6.14-rc3
[linux.git] / net / devlink / dpipe.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2016 Jiri Pirko <[email protected]>
5  */
6
7 #include "devl_internal.h"
8
9 static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
10         {
11                 .name = "destination mac",
12                 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
13                 .bitwidth = 48,
14         },
15 };
16
17 struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
18         .name = "ethernet",
19         .id = DEVLINK_DPIPE_HEADER_ETHERNET,
20         .fields = devlink_dpipe_fields_ethernet,
21         .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
22         .global = true,
23 };
24 EXPORT_SYMBOL_GPL(devlink_dpipe_header_ethernet);
25
26 static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
27         {
28                 .name = "destination ip",
29                 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
30                 .bitwidth = 32,
31         },
32 };
33
34 struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
35         .name = "ipv4",
36         .id = DEVLINK_DPIPE_HEADER_IPV4,
37         .fields = devlink_dpipe_fields_ipv4,
38         .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
39         .global = true,
40 };
41 EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv4);
42
43 static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
44         {
45                 .name = "destination ip",
46                 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
47                 .bitwidth = 128,
48         },
49 };
50
51 struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
52         .name = "ipv6",
53         .id = DEVLINK_DPIPE_HEADER_IPV6,
54         .fields = devlink_dpipe_fields_ipv6,
55         .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
56         .global = true,
57 };
58 EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv6);
59
60 int devlink_dpipe_match_put(struct sk_buff *skb,
61                             struct devlink_dpipe_match *match)
62 {
63         struct devlink_dpipe_header *header = match->header;
64         struct devlink_dpipe_field *field = &header->fields[match->field_id];
65         struct nlattr *match_attr;
66
67         match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
68         if (!match_attr)
69                 return -EMSGSIZE;
70
71         if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
72             nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
73             nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
74             nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
75             nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
76                 goto nla_put_failure;
77
78         nla_nest_end(skb, match_attr);
79         return 0;
80
81 nla_put_failure:
82         nla_nest_cancel(skb, match_attr);
83         return -EMSGSIZE;
84 }
85 EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
86
87 static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
88                                      struct sk_buff *skb)
89 {
90         struct nlattr *matches_attr;
91
92         matches_attr = nla_nest_start_noflag(skb,
93                                              DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
94         if (!matches_attr)
95                 return -EMSGSIZE;
96
97         if (table->table_ops->matches_dump(table->priv, skb))
98                 goto nla_put_failure;
99
100         nla_nest_end(skb, matches_attr);
101         return 0;
102
103 nla_put_failure:
104         nla_nest_cancel(skb, matches_attr);
105         return -EMSGSIZE;
106 }
107
108 int devlink_dpipe_action_put(struct sk_buff *skb,
109                              struct devlink_dpipe_action *action)
110 {
111         struct devlink_dpipe_header *header = action->header;
112         struct devlink_dpipe_field *field = &header->fields[action->field_id];
113         struct nlattr *action_attr;
114
115         action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
116         if (!action_attr)
117                 return -EMSGSIZE;
118
119         if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
120             nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
121             nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
122             nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
123             nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
124                 goto nla_put_failure;
125
126         nla_nest_end(skb, action_attr);
127         return 0;
128
129 nla_put_failure:
130         nla_nest_cancel(skb, action_attr);
131         return -EMSGSIZE;
132 }
133 EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
134
135 static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
136                                      struct sk_buff *skb)
137 {
138         struct nlattr *actions_attr;
139
140         actions_attr = nla_nest_start_noflag(skb,
141                                              DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
142         if (!actions_attr)
143                 return -EMSGSIZE;
144
145         if (table->table_ops->actions_dump(table->priv, skb))
146                 goto nla_put_failure;
147
148         nla_nest_end(skb, actions_attr);
149         return 0;
150
151 nla_put_failure:
152         nla_nest_cancel(skb, actions_attr);
153         return -EMSGSIZE;
154 }
155
156 static int devlink_dpipe_table_put(struct sk_buff *skb,
157                                    struct devlink_dpipe_table *table)
158 {
159         struct nlattr *table_attr;
160         u64 table_size;
161
162         table_size = table->table_ops->size_get(table->priv);
163         table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
164         if (!table_attr)
165                 return -EMSGSIZE;
166
167         if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
168             devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size))
169                 goto nla_put_failure;
170         if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
171                        table->counters_enabled))
172                 goto nla_put_failure;
173
174         if (table->resource_valid) {
175                 if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
176                                        table->resource_id) ||
177                     devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
178                                        table->resource_units))
179                         goto nla_put_failure;
180         }
181         if (devlink_dpipe_matches_put(table, skb))
182                 goto nla_put_failure;
183
184         if (devlink_dpipe_actions_put(table, skb))
185                 goto nla_put_failure;
186
187         nla_nest_end(skb, table_attr);
188         return 0;
189
190 nla_put_failure:
191         nla_nest_cancel(skb, table_attr);
192         return -EMSGSIZE;
193 }
194
195 static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
196                                             struct genl_info *info)
197 {
198         int err;
199
200         if (*pskb) {
201                 err = genlmsg_reply(*pskb, info);
202                 if (err)
203                         return err;
204         }
205         *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
206         if (!*pskb)
207                 return -ENOMEM;
208         return 0;
209 }
210
211 static int devlink_dpipe_tables_fill(struct genl_info *info,
212                                      enum devlink_command cmd, int flags,
213                                      struct list_head *dpipe_tables,
214                                      const char *table_name)
215 {
216         struct devlink *devlink = info->user_ptr[0];
217         struct devlink_dpipe_table *table;
218         struct nlattr *tables_attr;
219         struct sk_buff *skb = NULL;
220         struct nlmsghdr *nlh;
221         bool incomplete;
222         void *hdr;
223         int i;
224         int err;
225
226         table = list_first_entry(dpipe_tables,
227                                  struct devlink_dpipe_table, list);
228 start_again:
229         err = devlink_dpipe_send_and_alloc_skb(&skb, info);
230         if (err)
231                 return err;
232
233         hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
234                           &devlink_nl_family, NLM_F_MULTI, cmd);
235         if (!hdr) {
236                 nlmsg_free(skb);
237                 return -EMSGSIZE;
238         }
239
240         if (devlink_nl_put_handle(skb, devlink))
241                 goto nla_put_failure;
242         tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
243         if (!tables_attr)
244                 goto nla_put_failure;
245
246         i = 0;
247         incomplete = false;
248         list_for_each_entry_from(table, dpipe_tables, list) {
249                 if (!table_name) {
250                         err = devlink_dpipe_table_put(skb, table);
251                         if (err) {
252                                 if (!i)
253                                         goto err_table_put;
254                                 incomplete = true;
255                                 break;
256                         }
257                 } else {
258                         if (!strcmp(table->name, table_name)) {
259                                 err = devlink_dpipe_table_put(skb, table);
260                                 if (err)
261                                         break;
262                         }
263                 }
264                 i++;
265         }
266
267         nla_nest_end(skb, tables_attr);
268         genlmsg_end(skb, hdr);
269         if (incomplete)
270                 goto start_again;
271
272 send_done:
273         nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
274                         NLMSG_DONE, 0, flags | NLM_F_MULTI);
275         if (!nlh) {
276                 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
277                 if (err)
278                         return err;
279                 goto send_done;
280         }
281
282         return genlmsg_reply(skb, info);
283
284 nla_put_failure:
285         err = -EMSGSIZE;
286 err_table_put:
287         nlmsg_free(skb);
288         return err;
289 }
290
291 int devlink_nl_dpipe_table_get_doit(struct sk_buff *skb, struct genl_info *info)
292 {
293         struct devlink *devlink = info->user_ptr[0];
294         const char *table_name =  NULL;
295
296         if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
297                 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
298
299         return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
300                                          &devlink->dpipe_table_list,
301                                          table_name);
302 }
303
304 static int devlink_dpipe_value_put(struct sk_buff *skb,
305                                    struct devlink_dpipe_value *value)
306 {
307         if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
308                     value->value_size, value->value))
309                 return -EMSGSIZE;
310         if (value->mask)
311                 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
312                             value->value_size, value->mask))
313                         return -EMSGSIZE;
314         if (value->mapping_valid)
315                 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
316                                 value->mapping_value))
317                         return -EMSGSIZE;
318         return 0;
319 }
320
321 static int devlink_dpipe_action_value_put(struct sk_buff *skb,
322                                           struct devlink_dpipe_value *value)
323 {
324         if (!value->action)
325                 return -EINVAL;
326         if (devlink_dpipe_action_put(skb, value->action))
327                 return -EMSGSIZE;
328         if (devlink_dpipe_value_put(skb, value))
329                 return -EMSGSIZE;
330         return 0;
331 }
332
333 static int devlink_dpipe_action_values_put(struct sk_buff *skb,
334                                            struct devlink_dpipe_value *values,
335                                            unsigned int values_count)
336 {
337         struct nlattr *action_attr;
338         int i;
339         int err;
340
341         for (i = 0; i < values_count; i++) {
342                 action_attr = nla_nest_start_noflag(skb,
343                                                     DEVLINK_ATTR_DPIPE_ACTION_VALUE);
344                 if (!action_attr)
345                         return -EMSGSIZE;
346                 err = devlink_dpipe_action_value_put(skb, &values[i]);
347                 if (err)
348                         goto err_action_value_put;
349                 nla_nest_end(skb, action_attr);
350         }
351         return 0;
352
353 err_action_value_put:
354         nla_nest_cancel(skb, action_attr);
355         return err;
356 }
357
358 static int devlink_dpipe_match_value_put(struct sk_buff *skb,
359                                          struct devlink_dpipe_value *value)
360 {
361         if (!value->match)
362                 return -EINVAL;
363         if (devlink_dpipe_match_put(skb, value->match))
364                 return -EMSGSIZE;
365         if (devlink_dpipe_value_put(skb, value))
366                 return -EMSGSIZE;
367         return 0;
368 }
369
370 static int devlink_dpipe_match_values_put(struct sk_buff *skb,
371                                           struct devlink_dpipe_value *values,
372                                           unsigned int values_count)
373 {
374         struct nlattr *match_attr;
375         int i;
376         int err;
377
378         for (i = 0; i < values_count; i++) {
379                 match_attr = nla_nest_start_noflag(skb,
380                                                    DEVLINK_ATTR_DPIPE_MATCH_VALUE);
381                 if (!match_attr)
382                         return -EMSGSIZE;
383                 err = devlink_dpipe_match_value_put(skb, &values[i]);
384                 if (err)
385                         goto err_match_value_put;
386                 nla_nest_end(skb, match_attr);
387         }
388         return 0;
389
390 err_match_value_put:
391         nla_nest_cancel(skb, match_attr);
392         return err;
393 }
394
395 static int devlink_dpipe_entry_put(struct sk_buff *skb,
396                                    struct devlink_dpipe_entry *entry)
397 {
398         struct nlattr *entry_attr, *matches_attr, *actions_attr;
399         int err;
400
401         entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
402         if (!entry_attr)
403                 return  -EMSGSIZE;
404
405         if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index))
406                 goto nla_put_failure;
407         if (entry->counter_valid)
408                 if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
409                                        entry->counter))
410                         goto nla_put_failure;
411
412         matches_attr = nla_nest_start_noflag(skb,
413                                              DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
414         if (!matches_attr)
415                 goto nla_put_failure;
416
417         err = devlink_dpipe_match_values_put(skb, entry->match_values,
418                                              entry->match_values_count);
419         if (err) {
420                 nla_nest_cancel(skb, matches_attr);
421                 goto err_match_values_put;
422         }
423         nla_nest_end(skb, matches_attr);
424
425         actions_attr = nla_nest_start_noflag(skb,
426                                              DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
427         if (!actions_attr)
428                 goto nla_put_failure;
429
430         err = devlink_dpipe_action_values_put(skb, entry->action_values,
431                                               entry->action_values_count);
432         if (err) {
433                 nla_nest_cancel(skb, actions_attr);
434                 goto err_action_values_put;
435         }
436         nla_nest_end(skb, actions_attr);
437
438         nla_nest_end(skb, entry_attr);
439         return 0;
440
441 nla_put_failure:
442         err = -EMSGSIZE;
443 err_match_values_put:
444 err_action_values_put:
445         nla_nest_cancel(skb, entry_attr);
446         return err;
447 }
448
449 static struct devlink_dpipe_table *
450 devlink_dpipe_table_find(struct list_head *dpipe_tables,
451                          const char *table_name, struct devlink *devlink)
452 {
453         struct devlink_dpipe_table *table;
454
455         list_for_each_entry_rcu(table, dpipe_tables, list,
456                                 lockdep_is_held(&devlink->lock)) {
457                 if (!strcmp(table->name, table_name))
458                         return table;
459         }
460         return NULL;
461 }
462
463 int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
464 {
465         struct devlink *devlink;
466         int err;
467
468         err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
469                                                dump_ctx->info);
470         if (err)
471                 return err;
472
473         dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
474                                     dump_ctx->info->snd_portid,
475                                     dump_ctx->info->snd_seq,
476                                     &devlink_nl_family, NLM_F_MULTI,
477                                     dump_ctx->cmd);
478         if (!dump_ctx->hdr)
479                 goto nla_put_failure;
480
481         devlink = dump_ctx->info->user_ptr[0];
482         if (devlink_nl_put_handle(dump_ctx->skb, devlink))
483                 goto nla_put_failure;
484         dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
485                                                DEVLINK_ATTR_DPIPE_ENTRIES);
486         if (!dump_ctx->nest)
487                 goto nla_put_failure;
488         return 0;
489
490 nla_put_failure:
491         nlmsg_free(dump_ctx->skb);
492         return -EMSGSIZE;
493 }
494 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
495
496 int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
497                                    struct devlink_dpipe_entry *entry)
498 {
499         return devlink_dpipe_entry_put(dump_ctx->skb, entry);
500 }
501 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
502
503 int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
504 {
505         nla_nest_end(dump_ctx->skb, dump_ctx->nest);
506         genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
507         return 0;
508 }
509 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
510
511 void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
512
513 {
514         unsigned int value_count, value_index;
515         struct devlink_dpipe_value *value;
516
517         value = entry->action_values;
518         value_count = entry->action_values_count;
519         for (value_index = 0; value_index < value_count; value_index++) {
520                 kfree(value[value_index].value);
521                 kfree(value[value_index].mask);
522         }
523
524         value = entry->match_values;
525         value_count = entry->match_values_count;
526         for (value_index = 0; value_index < value_count; value_index++) {
527                 kfree(value[value_index].value);
528                 kfree(value[value_index].mask);
529         }
530 }
531 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_clear);
532
533 static int devlink_dpipe_entries_fill(struct genl_info *info,
534                                       enum devlink_command cmd, int flags,
535                                       struct devlink_dpipe_table *table)
536 {
537         struct devlink_dpipe_dump_ctx dump_ctx;
538         struct nlmsghdr *nlh;
539         int err;
540
541         dump_ctx.skb = NULL;
542         dump_ctx.cmd = cmd;
543         dump_ctx.info = info;
544
545         err = table->table_ops->entries_dump(table->priv,
546                                              table->counters_enabled,
547                                              &dump_ctx);
548         if (err)
549                 return err;
550
551 send_done:
552         nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
553                         NLMSG_DONE, 0, flags | NLM_F_MULTI);
554         if (!nlh) {
555                 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
556                 if (err)
557                         return err;
558                 goto send_done;
559         }
560         return genlmsg_reply(dump_ctx.skb, info);
561 }
562
563 int devlink_nl_dpipe_entries_get_doit(struct sk_buff *skb,
564                                       struct genl_info *info)
565 {
566         struct devlink *devlink = info->user_ptr[0];
567         struct devlink_dpipe_table *table;
568         const char *table_name;
569
570         if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME))
571                 return -EINVAL;
572
573         table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
574         table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
575                                          table_name, devlink);
576         if (!table)
577                 return -EINVAL;
578
579         if (!table->table_ops->entries_dump)
580                 return -EINVAL;
581
582         return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
583                                           0, table);
584 }
585
586 static int devlink_dpipe_fields_put(struct sk_buff *skb,
587                                     const struct devlink_dpipe_header *header)
588 {
589         struct devlink_dpipe_field *field;
590         struct nlattr *field_attr;
591         int i;
592
593         for (i = 0; i < header->fields_count; i++) {
594                 field = &header->fields[i];
595                 field_attr = nla_nest_start_noflag(skb,
596                                                    DEVLINK_ATTR_DPIPE_FIELD);
597                 if (!field_attr)
598                         return -EMSGSIZE;
599                 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
600                     nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
601                     nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
602                     nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
603                         goto nla_put_failure;
604                 nla_nest_end(skb, field_attr);
605         }
606         return 0;
607
608 nla_put_failure:
609         nla_nest_cancel(skb, field_attr);
610         return -EMSGSIZE;
611 }
612
613 static int devlink_dpipe_header_put(struct sk_buff *skb,
614                                     struct devlink_dpipe_header *header)
615 {
616         struct nlattr *fields_attr, *header_attr;
617         int err;
618
619         header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
620         if (!header_attr)
621                 return -EMSGSIZE;
622
623         if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
624             nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
625             nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
626                 goto nla_put_failure;
627
628         fields_attr = nla_nest_start_noflag(skb,
629                                             DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
630         if (!fields_attr)
631                 goto nla_put_failure;
632
633         err = devlink_dpipe_fields_put(skb, header);
634         if (err) {
635                 nla_nest_cancel(skb, fields_attr);
636                 goto nla_put_failure;
637         }
638         nla_nest_end(skb, fields_attr);
639         nla_nest_end(skb, header_attr);
640         return 0;
641
642 nla_put_failure:
643         err = -EMSGSIZE;
644         nla_nest_cancel(skb, header_attr);
645         return err;
646 }
647
648 static int devlink_dpipe_headers_fill(struct genl_info *info,
649                                       enum devlink_command cmd, int flags,
650                                       struct devlink_dpipe_headers *
651                                       dpipe_headers)
652 {
653         struct devlink *devlink = info->user_ptr[0];
654         struct nlattr *headers_attr;
655         struct sk_buff *skb = NULL;
656         struct nlmsghdr *nlh;
657         void *hdr;
658         int i, j;
659         int err;
660
661         i = 0;
662 start_again:
663         err = devlink_dpipe_send_and_alloc_skb(&skb, info);
664         if (err)
665                 return err;
666
667         hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
668                           &devlink_nl_family, NLM_F_MULTI, cmd);
669         if (!hdr) {
670                 nlmsg_free(skb);
671                 return -EMSGSIZE;
672         }
673
674         if (devlink_nl_put_handle(skb, devlink))
675                 goto nla_put_failure;
676         headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
677         if (!headers_attr)
678                 goto nla_put_failure;
679
680         j = 0;
681         for (; i < dpipe_headers->headers_count; i++) {
682                 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
683                 if (err) {
684                         if (!j)
685                                 goto err_table_put;
686                         break;
687                 }
688                 j++;
689         }
690         nla_nest_end(skb, headers_attr);
691         genlmsg_end(skb, hdr);
692         if (i != dpipe_headers->headers_count)
693                 goto start_again;
694
695 send_done:
696         nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
697                         NLMSG_DONE, 0, flags | NLM_F_MULTI);
698         if (!nlh) {
699                 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
700                 if (err)
701                         return err;
702                 goto send_done;
703         }
704         return genlmsg_reply(skb, info);
705
706 nla_put_failure:
707         err = -EMSGSIZE;
708 err_table_put:
709         nlmsg_free(skb);
710         return err;
711 }
712
713 int devlink_nl_dpipe_headers_get_doit(struct sk_buff *skb,
714                                       struct genl_info *info)
715 {
716         struct devlink *devlink = info->user_ptr[0];
717
718         if (!devlink->dpipe_headers)
719                 return -EOPNOTSUPP;
720         return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
721                                           0, devlink->dpipe_headers);
722 }
723
724 static int devlink_dpipe_table_counters_set(struct devlink *devlink,
725                                             const char *table_name,
726                                             bool enable)
727 {
728         struct devlink_dpipe_table *table;
729
730         table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
731                                          table_name, devlink);
732         if (!table)
733                 return -EINVAL;
734
735         if (table->counter_control_extern)
736                 return -EOPNOTSUPP;
737
738         if (!(table->counters_enabled ^ enable))
739                 return 0;
740
741         table->counters_enabled = enable;
742         if (table->table_ops->counters_set_update)
743                 table->table_ops->counters_set_update(table->priv, enable);
744         return 0;
745 }
746
747 int devlink_nl_dpipe_table_counters_set_doit(struct sk_buff *skb,
748                                              struct genl_info *info)
749 {
750         struct devlink *devlink = info->user_ptr[0];
751         const char *table_name;
752         bool counters_enable;
753
754         if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME) ||
755             GENL_REQ_ATTR_CHECK(info,
756                                 DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED))
757                 return -EINVAL;
758
759         table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
760         counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
761
762         return devlink_dpipe_table_counters_set(devlink, table_name,
763                                                 counters_enable);
764 }
765
766 /**
767  * devl_dpipe_headers_register - register dpipe headers
768  *
769  * @devlink: devlink
770  * @dpipe_headers: dpipe header array
771  *
772  * Register the headers supported by hardware.
773  */
774 void devl_dpipe_headers_register(struct devlink *devlink,
775                                  struct devlink_dpipe_headers *dpipe_headers)
776 {
777         lockdep_assert_held(&devlink->lock);
778
779         devlink->dpipe_headers = dpipe_headers;
780 }
781 EXPORT_SYMBOL_GPL(devl_dpipe_headers_register);
782
783 /**
784  * devl_dpipe_headers_unregister - unregister dpipe headers
785  *
786  * @devlink: devlink
787  *
788  * Unregister the headers supported by hardware.
789  */
790 void devl_dpipe_headers_unregister(struct devlink *devlink)
791 {
792         lockdep_assert_held(&devlink->lock);
793
794         devlink->dpipe_headers = NULL;
795 }
796 EXPORT_SYMBOL_GPL(devl_dpipe_headers_unregister);
797
798 /**
799  *      devlink_dpipe_table_counter_enabled - check if counter allocation
800  *                                            required
801  *      @devlink: devlink
802  *      @table_name: tables name
803  *
804  *      Used by driver to check if counter allocation is required.
805  *      After counter allocation is turned on the table entries
806  *      are updated to include counter statistics.
807  *
808  *      After that point on the driver must respect the counter
809  *      state so that each entry added to the table is added
810  *      with a counter.
811  */
812 bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
813                                          const char *table_name)
814 {
815         struct devlink_dpipe_table *table;
816         bool enabled;
817
818         rcu_read_lock();
819         table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
820                                          table_name, devlink);
821         enabled = false;
822         if (table)
823                 enabled = table->counters_enabled;
824         rcu_read_unlock();
825         return enabled;
826 }
827 EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
828
829 /**
830  * devl_dpipe_table_register - register dpipe table
831  *
832  * @devlink: devlink
833  * @table_name: table name
834  * @table_ops: table ops
835  * @priv: priv
836  * @counter_control_extern: external control for counters
837  */
838 int devl_dpipe_table_register(struct devlink *devlink,
839                               const char *table_name,
840                               const struct devlink_dpipe_table_ops *table_ops,
841                               void *priv, bool counter_control_extern)
842 {
843         struct devlink_dpipe_table *table;
844
845         lockdep_assert_held(&devlink->lock);
846
847         if (WARN_ON(!table_ops->size_get))
848                 return -EINVAL;
849
850         if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
851                                      devlink))
852                 return -EEXIST;
853
854         table = kzalloc(sizeof(*table), GFP_KERNEL);
855         if (!table)
856                 return -ENOMEM;
857
858         table->name = table_name;
859         table->table_ops = table_ops;
860         table->priv = priv;
861         table->counter_control_extern = counter_control_extern;
862
863         list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
864
865         return 0;
866 }
867 EXPORT_SYMBOL_GPL(devl_dpipe_table_register);
868
869 /**
870  * devl_dpipe_table_unregister - unregister dpipe table
871  *
872  * @devlink: devlink
873  * @table_name: table name
874  */
875 void devl_dpipe_table_unregister(struct devlink *devlink,
876                                  const char *table_name)
877 {
878         struct devlink_dpipe_table *table;
879
880         lockdep_assert_held(&devlink->lock);
881
882         table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
883                                          table_name, devlink);
884         if (!table)
885                 return;
886         list_del_rcu(&table->list);
887         kfree_rcu(table, rcu);
888 }
889 EXPORT_SYMBOL_GPL(devl_dpipe_table_unregister);
890
891 /**
892  * devl_dpipe_table_resource_set - set the resource id
893  *
894  * @devlink: devlink
895  * @table_name: table name
896  * @resource_id: resource id
897  * @resource_units: number of resource's units consumed per table's entry
898  */
899 int devl_dpipe_table_resource_set(struct devlink *devlink,
900                                   const char *table_name, u64 resource_id,
901                                   u64 resource_units)
902 {
903         struct devlink_dpipe_table *table;
904
905         table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
906                                          table_name, devlink);
907         if (!table)
908                 return -EINVAL;
909
910         table->resource_id = resource_id;
911         table->resource_units = resource_units;
912         table->resource_valid = true;
913         return 0;
914 }
915 EXPORT_SYMBOL_GPL(devl_dpipe_table_resource_set);
This page took 0.101542 seconds and 4 git commands to generate.