]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - net/core/devlink.c
devlink: Add health get command
[thirdparty/kernel/stable.git] / net / core / devlink.c
CommitLineData
bfcd3a46
JP
1/*
2 * net/core/devlink.c - Network physical/parent device Netlink interface
3 *
4 * Heavily inspired by net/wireless/
5 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
6 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/slab.h>
18#include <linux/gfp.h>
19#include <linux/device.h>
20#include <linux/list.h>
21#include <linux/netdevice.h>
22#include <rdma/ib_verbs.h>
23#include <net/netlink.h>
24#include <net/genetlink.h>
25#include <net/rtnetlink.h>
26#include <net/net_namespace.h>
27#include <net/sock.h>
28#include <net/devlink.h>
e5224f0f
JP
29#define CREATE_TRACE_POINTS
30#include <trace/events/devlink.h>
31
11770091
AS
32static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
33 {
12bdc5e1 34 .name = "destination mac",
11770091
AS
35 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
36 .bitwidth = 48,
37 },
38};
39
40struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
41 .name = "ethernet",
42 .id = DEVLINK_DPIPE_HEADER_ETHERNET,
43 .fields = devlink_dpipe_fields_ethernet,
44 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
45 .global = true,
46};
47EXPORT_SYMBOL(devlink_dpipe_header_ethernet);
48
3fb886ec
AS
49static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
50 {
51 .name = "destination ip",
52 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
53 .bitwidth = 32,
54 },
55};
56
57struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
58 .name = "ipv4",
59 .id = DEVLINK_DPIPE_HEADER_IPV4,
60 .fields = devlink_dpipe_fields_ipv4,
61 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
62 .global = true,
63};
64EXPORT_SYMBOL(devlink_dpipe_header_ipv4);
65
1797f5b3
AS
66static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
67 {
68 .name = "destination ip",
69 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
70 .bitwidth = 128,
71 },
72};
73
74struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
75 .name = "ipv6",
76 .id = DEVLINK_DPIPE_HEADER_IPV6,
77 .fields = devlink_dpipe_fields_ipv6,
78 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
79 .global = true,
80};
81EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
82
e5224f0f 83EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
57186a5f 84EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
bfcd3a46
JP
85
86static LIST_HEAD(devlink_list);
87
88/* devlink_mutex
89 *
90 * An overall lock guarding every operation coming from userspace.
91 * It also guards devlink devices list and it is taken when
92 * driver registers/unregisters it.
93 */
94static DEFINE_MUTEX(devlink_mutex);
95
bfcd3a46
JP
96static struct net *devlink_net(const struct devlink *devlink)
97{
98 return read_pnet(&devlink->_net);
99}
100
101static void devlink_net_set(struct devlink *devlink, struct net *net)
102{
103 write_pnet(&devlink->_net, net);
104}
105
106static struct devlink *devlink_get_from_attrs(struct net *net,
107 struct nlattr **attrs)
108{
109 struct devlink *devlink;
110 char *busname;
111 char *devname;
112
113 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
114 return ERR_PTR(-EINVAL);
115
116 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
117 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
118
119 list_for_each_entry(devlink, &devlink_list, list) {
120 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
121 strcmp(dev_name(devlink->dev), devname) == 0 &&
122 net_eq(devlink_net(devlink), net))
123 return devlink;
124 }
125
126 return ERR_PTR(-ENODEV);
127}
128
129static struct devlink *devlink_get_from_info(struct genl_info *info)
130{
131 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
132}
133
134static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
135 int port_index)
136{
137 struct devlink_port *devlink_port;
138
139 list_for_each_entry(devlink_port, &devlink->port_list, list) {
140 if (devlink_port->index == port_index)
141 return devlink_port;
142 }
143 return NULL;
144}
145
146static bool devlink_port_index_exists(struct devlink *devlink, int port_index)
147{
148 return devlink_port_get_by_index(devlink, port_index);
149}
150
151static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
152 struct nlattr **attrs)
153{
154 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
155 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
156 struct devlink_port *devlink_port;
157
158 devlink_port = devlink_port_get_by_index(devlink, port_index);
159 if (!devlink_port)
160 return ERR_PTR(-ENODEV);
161 return devlink_port;
162 }
163 return ERR_PTR(-EINVAL);
164}
165
166static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
167 struct genl_info *info)
168{
169 return devlink_port_get_from_attrs(devlink, info->attrs);
170}
171
bf797471
JP
172struct devlink_sb {
173 struct list_head list;
174 unsigned int index;
175 u32 size;
176 u16 ingress_pools_count;
177 u16 egress_pools_count;
178 u16 ingress_tc_count;
179 u16 egress_tc_count;
180};
181
182static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
183{
184 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
185}
186
187static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
188 unsigned int sb_index)
189{
190 struct devlink_sb *devlink_sb;
191
192 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
193 if (devlink_sb->index == sb_index)
194 return devlink_sb;
195 }
196 return NULL;
197}
198
199static bool devlink_sb_index_exists(struct devlink *devlink,
200 unsigned int sb_index)
201{
202 return devlink_sb_get_by_index(devlink, sb_index);
203}
204
205static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
206 struct nlattr **attrs)
207{
208 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
209 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
210 struct devlink_sb *devlink_sb;
211
212 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
213 if (!devlink_sb)
214 return ERR_PTR(-ENODEV);
215 return devlink_sb;
216 }
217 return ERR_PTR(-EINVAL);
218}
219
220static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
221 struct genl_info *info)
222{
223 return devlink_sb_get_from_attrs(devlink, info->attrs);
224}
225
226static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
227 struct nlattr **attrs,
228 u16 *p_pool_index)
229{
230 u16 val;
231
232 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
233 return -EINVAL;
234
235 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
236 if (val >= devlink_sb_pool_count(devlink_sb))
237 return -EINVAL;
238 *p_pool_index = val;
239 return 0;
240}
241
242static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
243 struct genl_info *info,
244 u16 *p_pool_index)
245{
246 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
247 p_pool_index);
248}
249
250static int
251devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
252 enum devlink_sb_pool_type *p_pool_type)
253{
254 u8 val;
255
256 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
257 return -EINVAL;
258
259 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
260 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
261 val != DEVLINK_SB_POOL_TYPE_EGRESS)
262 return -EINVAL;
263 *p_pool_type = val;
264 return 0;
265}
266
267static int
268devlink_sb_pool_type_get_from_info(struct genl_info *info,
269 enum devlink_sb_pool_type *p_pool_type)
270{
271 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
272}
273
274static int
275devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
276 enum devlink_sb_threshold_type *p_th_type)
277{
278 u8 val;
279
280 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
281 return -EINVAL;
282
283 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
284 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
285 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
286 return -EINVAL;
287 *p_th_type = val;
288 return 0;
289}
290
291static int
292devlink_sb_th_type_get_from_info(struct genl_info *info,
293 enum devlink_sb_threshold_type *p_th_type)
294{
295 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
296}
297
298static int
299devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
300 struct nlattr **attrs,
301 enum devlink_sb_pool_type pool_type,
302 u16 *p_tc_index)
303{
304 u16 val;
305
306 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
307 return -EINVAL;
308
309 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
310 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
311 val >= devlink_sb->ingress_tc_count)
312 return -EINVAL;
313 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
314 val >= devlink_sb->egress_tc_count)
315 return -EINVAL;
316 *p_tc_index = val;
317 return 0;
318}
319
320static int
321devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
322 struct genl_info *info,
323 enum devlink_sb_pool_type pool_type,
324 u16 *p_tc_index)
325{
326 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
327 pool_type, p_tc_index);
328}
329
b16ebe92
AV
330struct devlink_region {
331 struct devlink *devlink;
332 struct list_head list;
333 const char *name;
334 struct list_head snapshot_list;
335 u32 max_snapshots;
336 u32 cur_snapshots;
337 u64 size;
338};
339
d7e52722
AV
340struct devlink_snapshot {
341 struct list_head list;
342 struct devlink_region *region;
343 devlink_snapshot_data_dest_t *data_destructor;
344 u64 data_len;
345 u8 *data;
346 u32 id;
347};
348
b16ebe92
AV
349static struct devlink_region *
350devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
351{
352 struct devlink_region *region;
353
354 list_for_each_entry(region, &devlink->region_list, list)
355 if (!strcmp(region->name, region_name))
356 return region;
357
358 return NULL;
359}
360
d7e52722
AV
361static struct devlink_snapshot *
362devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
363{
364 struct devlink_snapshot *snapshot;
365
366 list_for_each_entry(snapshot, &region->snapshot_list, list)
367 if (snapshot->id == id)
368 return snapshot;
369
370 return NULL;
371}
372
373static void devlink_region_snapshot_del(struct devlink_snapshot *snapshot)
374{
375 snapshot->region->cur_snapshots--;
376 list_del(&snapshot->list);
377 (*snapshot->data_destructor)(snapshot->data);
378 kfree(snapshot);
379}
380
1fc2257e
JP
381#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
382#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
bf797471 383#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
2406e7e5
AS
384
385/* The per devlink instance lock is taken by default in the pre-doit
386 * operation, yet several commands do not require this. The global
387 * devlink lock is taken and protects from disruption by user-calls.
388 */
389#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
bfcd3a46
JP
390
391static int devlink_nl_pre_doit(const struct genl_ops *ops,
392 struct sk_buff *skb, struct genl_info *info)
393{
394 struct devlink *devlink;
2406e7e5 395 int err;
bfcd3a46
JP
396
397 mutex_lock(&devlink_mutex);
398 devlink = devlink_get_from_info(info);
399 if (IS_ERR(devlink)) {
400 mutex_unlock(&devlink_mutex);
401 return PTR_ERR(devlink);
402 }
2406e7e5
AS
403 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
404 mutex_lock(&devlink->lock);
1fc2257e
JP
405 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
406 info->user_ptr[0] = devlink;
407 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
bfcd3a46
JP
408 struct devlink_port *devlink_port;
409
bfcd3a46
JP
410 devlink_port = devlink_port_get_from_info(devlink, info);
411 if (IS_ERR(devlink_port)) {
2406e7e5
AS
412 err = PTR_ERR(devlink_port);
413 goto unlock;
bfcd3a46 414 }
1fc2257e 415 info->user_ptr[0] = devlink_port;
bfcd3a46 416 }
bf797471
JP
417 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
418 struct devlink_sb *devlink_sb;
419
420 devlink_sb = devlink_sb_get_from_info(devlink, info);
421 if (IS_ERR(devlink_sb)) {
2406e7e5
AS
422 err = PTR_ERR(devlink_sb);
423 goto unlock;
bf797471
JP
424 }
425 info->user_ptr[1] = devlink_sb;
426 }
bfcd3a46 427 return 0;
2406e7e5
AS
428
429unlock:
430 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
431 mutex_unlock(&devlink->lock);
432 mutex_unlock(&devlink_mutex);
433 return err;
bfcd3a46
JP
434}
435
436static void devlink_nl_post_doit(const struct genl_ops *ops,
437 struct sk_buff *skb, struct genl_info *info)
438{
2406e7e5
AS
439 struct devlink *devlink;
440
441 devlink = devlink_get_from_info(info);
442 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
443 mutex_unlock(&devlink->lock);
bfcd3a46
JP
444 mutex_unlock(&devlink_mutex);
445}
446
489111e5 447static struct genl_family devlink_nl_family;
bfcd3a46
JP
448
449enum devlink_multicast_groups {
450 DEVLINK_MCGRP_CONFIG,
451};
452
453static const struct genl_multicast_group devlink_nl_mcgrps[] = {
454 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
455};
456
457static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
458{
459 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
460 return -EMSGSIZE;
461 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
462 return -EMSGSIZE;
463 return 0;
464}
465
466static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
467 enum devlink_command cmd, u32 portid,
468 u32 seq, int flags)
469{
470 void *hdr;
471
472 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
473 if (!hdr)
474 return -EMSGSIZE;
475
476 if (devlink_nl_put_handle(msg, devlink))
477 goto nla_put_failure;
478
479 genlmsg_end(msg, hdr);
480 return 0;
481
482nla_put_failure:
483 genlmsg_cancel(msg, hdr);
484 return -EMSGSIZE;
485}
486
487static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
488{
489 struct sk_buff *msg;
490 int err;
491
492 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
493
494 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
495 if (!msg)
496 return;
497
498 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
499 if (err) {
500 nlmsg_free(msg);
501 return;
502 }
503
504 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
505 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
506}
507
b9ffcbaf
JP
508static int devlink_nl_port_attrs_put(struct sk_buff *msg,
509 struct devlink_port *devlink_port)
510{
511 struct devlink_port_attrs *attrs = &devlink_port->attrs;
512
513 if (!attrs->set)
514 return 0;
5ec1380a
JP
515 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
516 return -EMSGSIZE;
b9ffcbaf
JP
517 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER, attrs->port_number))
518 return -EMSGSIZE;
519 if (!attrs->split)
520 return 0;
521 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP, attrs->port_number))
522 return -EMSGSIZE;
523 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
524 attrs->split_subport_number))
525 return -EMSGSIZE;
526 return 0;
527}
528
bfcd3a46
JP
529static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
530 struct devlink_port *devlink_port,
531 enum devlink_command cmd, u32 portid,
532 u32 seq, int flags)
533{
534 void *hdr;
535
536 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
537 if (!hdr)
538 return -EMSGSIZE;
539
540 if (devlink_nl_put_handle(msg, devlink))
541 goto nla_put_failure;
542 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
543 goto nla_put_failure;
544 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
545 goto nla_put_failure;
546 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
547 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
548 devlink_port->desired_type))
549 goto nla_put_failure;
550 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
551 struct net_device *netdev = devlink_port->type_dev;
552
553 if (netdev &&
554 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
555 netdev->ifindex) ||
556 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
557 netdev->name)))
558 goto nla_put_failure;
559 }
560 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
561 struct ib_device *ibdev = devlink_port->type_dev;
562
563 if (ibdev &&
564 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
565 ibdev->name))
566 goto nla_put_failure;
567 }
b9ffcbaf 568 if (devlink_nl_port_attrs_put(msg, devlink_port))
bfcd3a46
JP
569 goto nla_put_failure;
570
571 genlmsg_end(msg, hdr);
572 return 0;
573
574nla_put_failure:
575 genlmsg_cancel(msg, hdr);
576 return -EMSGSIZE;
577}
578
579static void devlink_port_notify(struct devlink_port *devlink_port,
580 enum devlink_command cmd)
581{
582 struct devlink *devlink = devlink_port->devlink;
583 struct sk_buff *msg;
584 int err;
585
586 if (!devlink_port->registered)
587 return;
588
589 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
590
591 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
592 if (!msg)
593 return;
594
595 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
596 if (err) {
597 nlmsg_free(msg);
598 return;
599 }
600
601 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
602 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
603}
604
605static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
606{
607 struct devlink *devlink = info->user_ptr[0];
608 struct sk_buff *msg;
609 int err;
610
611 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
612 if (!msg)
613 return -ENOMEM;
614
615 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
616 info->snd_portid, info->snd_seq, 0);
617 if (err) {
618 nlmsg_free(msg);
619 return err;
620 }
621
622 return genlmsg_reply(msg, info);
623}
624
625static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
626 struct netlink_callback *cb)
627{
628 struct devlink *devlink;
629 int start = cb->args[0];
630 int idx = 0;
631 int err;
632
633 mutex_lock(&devlink_mutex);
634 list_for_each_entry(devlink, &devlink_list, list) {
635 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
636 continue;
637 if (idx < start) {
638 idx++;
639 continue;
640 }
641 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
642 NETLINK_CB(cb->skb).portid,
643 cb->nlh->nlmsg_seq, NLM_F_MULTI);
644 if (err)
645 goto out;
646 idx++;
647 }
648out:
649 mutex_unlock(&devlink_mutex);
650
651 cb->args[0] = idx;
652 return msg->len;
653}
654
655static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
656 struct genl_info *info)
657{
1fc2257e
JP
658 struct devlink_port *devlink_port = info->user_ptr[0];
659 struct devlink *devlink = devlink_port->devlink;
bfcd3a46
JP
660 struct sk_buff *msg;
661 int err;
662
663 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
664 if (!msg)
665 return -ENOMEM;
666
667 err = devlink_nl_port_fill(msg, devlink, devlink_port,
668 DEVLINK_CMD_PORT_NEW,
669 info->snd_portid, info->snd_seq, 0);
670 if (err) {
671 nlmsg_free(msg);
672 return err;
673 }
674
675 return genlmsg_reply(msg, info);
676}
677
678static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
679 struct netlink_callback *cb)
680{
681 struct devlink *devlink;
682 struct devlink_port *devlink_port;
683 int start = cb->args[0];
684 int idx = 0;
685 int err;
686
687 mutex_lock(&devlink_mutex);
bfcd3a46
JP
688 list_for_each_entry(devlink, &devlink_list, list) {
689 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
690 continue;
2406e7e5 691 mutex_lock(&devlink->lock);
bfcd3a46
JP
692 list_for_each_entry(devlink_port, &devlink->port_list, list) {
693 if (idx < start) {
694 idx++;
695 continue;
696 }
697 err = devlink_nl_port_fill(msg, devlink, devlink_port,
698 DEVLINK_CMD_NEW,
699 NETLINK_CB(cb->skb).portid,
700 cb->nlh->nlmsg_seq,
701 NLM_F_MULTI);
2406e7e5
AS
702 if (err) {
703 mutex_unlock(&devlink->lock);
bfcd3a46 704 goto out;
2406e7e5 705 }
bfcd3a46
JP
706 idx++;
707 }
2406e7e5 708 mutex_unlock(&devlink->lock);
bfcd3a46
JP
709 }
710out:
bfcd3a46
JP
711 mutex_unlock(&devlink_mutex);
712
713 cb->args[0] = idx;
714 return msg->len;
715}
716
717static int devlink_port_type_set(struct devlink *devlink,
718 struct devlink_port *devlink_port,
719 enum devlink_port_type port_type)
720
721{
722 int err;
723
724 if (devlink->ops && devlink->ops->port_type_set) {
725 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
726 return -EINVAL;
6edf1017
ER
727 if (port_type == devlink_port->type)
728 return 0;
bfcd3a46
JP
729 err = devlink->ops->port_type_set(devlink_port, port_type);
730 if (err)
731 return err;
732 devlink_port->desired_type = port_type;
733 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
734 return 0;
735 }
736 return -EOPNOTSUPP;
737}
738
739static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
740 struct genl_info *info)
741{
1fc2257e
JP
742 struct devlink_port *devlink_port = info->user_ptr[0];
743 struct devlink *devlink = devlink_port->devlink;
bfcd3a46
JP
744 int err;
745
746 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
747 enum devlink_port_type port_type;
748
749 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
750 err = devlink_port_type_set(devlink, devlink_port, port_type);
751 if (err)
752 return err;
753 }
754 return 0;
755}
756
ac0fc8a1
DA
757static int devlink_port_split(struct devlink *devlink, u32 port_index,
758 u32 count, struct netlink_ext_ack *extack)
bfcd3a46
JP
759
760{
761 if (devlink->ops && devlink->ops->port_split)
ac0fc8a1
DA
762 return devlink->ops->port_split(devlink, port_index, count,
763 extack);
bfcd3a46
JP
764 return -EOPNOTSUPP;
765}
766
767static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
768 struct genl_info *info)
769{
770 struct devlink *devlink = info->user_ptr[0];
771 u32 port_index;
772 u32 count;
773
774 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
775 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
776 return -EINVAL;
777
778 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
779 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
ac0fc8a1 780 return devlink_port_split(devlink, port_index, count, info->extack);
bfcd3a46
JP
781}
782
ac0fc8a1
DA
783static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
784 struct netlink_ext_ack *extack)
bfcd3a46
JP
785
786{
787 if (devlink->ops && devlink->ops->port_unsplit)
ac0fc8a1 788 return devlink->ops->port_unsplit(devlink, port_index, extack);
bfcd3a46
JP
789 return -EOPNOTSUPP;
790}
791
792static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
793 struct genl_info *info)
794{
795 struct devlink *devlink = info->user_ptr[0];
796 u32 port_index;
797
798 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
799 return -EINVAL;
800
801 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
ac0fc8a1 802 return devlink_port_unsplit(devlink, port_index, info->extack);
bfcd3a46
JP
803}
804
bf797471
JP
805static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
806 struct devlink_sb *devlink_sb,
807 enum devlink_command cmd, u32 portid,
808 u32 seq, int flags)
809{
810 void *hdr;
811
812 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
813 if (!hdr)
814 return -EMSGSIZE;
815
816 if (devlink_nl_put_handle(msg, devlink))
817 goto nla_put_failure;
818 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
819 goto nla_put_failure;
820 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
821 goto nla_put_failure;
822 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
823 devlink_sb->ingress_pools_count))
824 goto nla_put_failure;
825 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
826 devlink_sb->egress_pools_count))
827 goto nla_put_failure;
828 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
829 devlink_sb->ingress_tc_count))
830 goto nla_put_failure;
831 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
832 devlink_sb->egress_tc_count))
833 goto nla_put_failure;
834
835 genlmsg_end(msg, hdr);
836 return 0;
837
838nla_put_failure:
839 genlmsg_cancel(msg, hdr);
840 return -EMSGSIZE;
841}
842
843static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
844 struct genl_info *info)
845{
846 struct devlink *devlink = info->user_ptr[0];
847 struct devlink_sb *devlink_sb = info->user_ptr[1];
848 struct sk_buff *msg;
849 int err;
850
851 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
852 if (!msg)
853 return -ENOMEM;
854
855 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
856 DEVLINK_CMD_SB_NEW,
857 info->snd_portid, info->snd_seq, 0);
858 if (err) {
859 nlmsg_free(msg);
860 return err;
861 }
862
863 return genlmsg_reply(msg, info);
864}
865
866static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
867 struct netlink_callback *cb)
868{
869 struct devlink *devlink;
870 struct devlink_sb *devlink_sb;
871 int start = cb->args[0];
872 int idx = 0;
873 int err;
874
875 mutex_lock(&devlink_mutex);
876 list_for_each_entry(devlink, &devlink_list, list) {
877 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
878 continue;
2406e7e5 879 mutex_lock(&devlink->lock);
bf797471
JP
880 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
881 if (idx < start) {
882 idx++;
883 continue;
884 }
885 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
886 DEVLINK_CMD_SB_NEW,
887 NETLINK_CB(cb->skb).portid,
888 cb->nlh->nlmsg_seq,
889 NLM_F_MULTI);
2406e7e5
AS
890 if (err) {
891 mutex_unlock(&devlink->lock);
bf797471 892 goto out;
2406e7e5 893 }
bf797471
JP
894 idx++;
895 }
2406e7e5 896 mutex_unlock(&devlink->lock);
bf797471
JP
897 }
898out:
899 mutex_unlock(&devlink_mutex);
900
901 cb->args[0] = idx;
902 return msg->len;
903}
904
905static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
906 struct devlink_sb *devlink_sb,
907 u16 pool_index, enum devlink_command cmd,
908 u32 portid, u32 seq, int flags)
909{
910 struct devlink_sb_pool_info pool_info;
911 void *hdr;
912 int err;
913
914 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
915 pool_index, &pool_info);
916 if (err)
917 return err;
918
919 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
920 if (!hdr)
921 return -EMSGSIZE;
922
923 if (devlink_nl_put_handle(msg, devlink))
924 goto nla_put_failure;
925 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
926 goto nla_put_failure;
927 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
928 goto nla_put_failure;
929 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
930 goto nla_put_failure;
931 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
932 goto nla_put_failure;
933 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
934 pool_info.threshold_type))
935 goto nla_put_failure;
bff5731d
JK
936 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
937 pool_info.cell_size))
938 goto nla_put_failure;
bf797471
JP
939
940 genlmsg_end(msg, hdr);
941 return 0;
942
943nla_put_failure:
944 genlmsg_cancel(msg, hdr);
945 return -EMSGSIZE;
946}
947
948static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
949 struct genl_info *info)
950{
951 struct devlink *devlink = info->user_ptr[0];
952 struct devlink_sb *devlink_sb = info->user_ptr[1];
953 struct sk_buff *msg;
954 u16 pool_index;
955 int err;
956
957 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
958 &pool_index);
959 if (err)
960 return err;
961
962 if (!devlink->ops || !devlink->ops->sb_pool_get)
963 return -EOPNOTSUPP;
964
965 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
966 if (!msg)
967 return -ENOMEM;
968
969 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
970 DEVLINK_CMD_SB_POOL_NEW,
971 info->snd_portid, info->snd_seq, 0);
972 if (err) {
973 nlmsg_free(msg);
974 return err;
975 }
976
977 return genlmsg_reply(msg, info);
978}
979
980static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
981 struct devlink *devlink,
982 struct devlink_sb *devlink_sb,
983 u32 portid, u32 seq)
984{
985 u16 pool_count = devlink_sb_pool_count(devlink_sb);
986 u16 pool_index;
987 int err;
988
989 for (pool_index = 0; pool_index < pool_count; pool_index++) {
990 if (*p_idx < start) {
991 (*p_idx)++;
992 continue;
993 }
994 err = devlink_nl_sb_pool_fill(msg, devlink,
995 devlink_sb,
996 pool_index,
997 DEVLINK_CMD_SB_POOL_NEW,
998 portid, seq, NLM_F_MULTI);
999 if (err)
1000 return err;
1001 (*p_idx)++;
1002 }
1003 return 0;
1004}
1005
1006static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1007 struct netlink_callback *cb)
1008{
1009 struct devlink *devlink;
1010 struct devlink_sb *devlink_sb;
1011 int start = cb->args[0];
1012 int idx = 0;
1013 int err;
1014
1015 mutex_lock(&devlink_mutex);
1016 list_for_each_entry(devlink, &devlink_list, list) {
1017 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1018 !devlink->ops || !devlink->ops->sb_pool_get)
1019 continue;
2406e7e5 1020 mutex_lock(&devlink->lock);
bf797471
JP
1021 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1022 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1023 devlink_sb,
1024 NETLINK_CB(cb->skb).portid,
1025 cb->nlh->nlmsg_seq);
2406e7e5
AS
1026 if (err && err != -EOPNOTSUPP) {
1027 mutex_unlock(&devlink->lock);
bf797471 1028 goto out;
2406e7e5 1029 }
bf797471 1030 }
2406e7e5 1031 mutex_unlock(&devlink->lock);
bf797471
JP
1032 }
1033out:
1034 mutex_unlock(&devlink_mutex);
1035
1036 cb->args[0] = idx;
1037 return msg->len;
1038}
1039
1040static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1041 u16 pool_index, u32 size,
1042 enum devlink_sb_threshold_type threshold_type)
1043
1044{
1045 const struct devlink_ops *ops = devlink->ops;
1046
1047 if (ops && ops->sb_pool_set)
1048 return ops->sb_pool_set(devlink, sb_index, pool_index,
1049 size, threshold_type);
1050 return -EOPNOTSUPP;
1051}
1052
1053static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1054 struct genl_info *info)
1055{
1056 struct devlink *devlink = info->user_ptr[0];
1057 struct devlink_sb *devlink_sb = info->user_ptr[1];
1058 enum devlink_sb_threshold_type threshold_type;
1059 u16 pool_index;
1060 u32 size;
1061 int err;
1062
1063 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1064 &pool_index);
1065 if (err)
1066 return err;
1067
1068 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1069 if (err)
1070 return err;
1071
1072 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1073 return -EINVAL;
1074
1075 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1076 return devlink_sb_pool_set(devlink, devlink_sb->index,
1077 pool_index, size, threshold_type);
1078}
1079
1080static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1081 struct devlink *devlink,
1082 struct devlink_port *devlink_port,
1083 struct devlink_sb *devlink_sb,
1084 u16 pool_index,
1085 enum devlink_command cmd,
1086 u32 portid, u32 seq, int flags)
1087{
df38dafd 1088 const struct devlink_ops *ops = devlink->ops;
bf797471
JP
1089 u32 threshold;
1090 void *hdr;
1091 int err;
1092
df38dafd
JP
1093 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1094 pool_index, &threshold);
bf797471
JP
1095 if (err)
1096 return err;
1097
1098 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1099 if (!hdr)
1100 return -EMSGSIZE;
1101
1102 if (devlink_nl_put_handle(msg, devlink))
1103 goto nla_put_failure;
1104 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1105 goto nla_put_failure;
1106 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1107 goto nla_put_failure;
1108 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1109 goto nla_put_failure;
1110 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1111 goto nla_put_failure;
1112
df38dafd
JP
1113 if (ops->sb_occ_port_pool_get) {
1114 u32 cur;
1115 u32 max;
1116
1117 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1118 pool_index, &cur, &max);
1119 if (err && err != -EOPNOTSUPP)
1120 return err;
1121 if (!err) {
1122 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1123 goto nla_put_failure;
1124 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1125 goto nla_put_failure;
1126 }
1127 }
1128
bf797471
JP
1129 genlmsg_end(msg, hdr);
1130 return 0;
1131
1132nla_put_failure:
1133 genlmsg_cancel(msg, hdr);
1134 return -EMSGSIZE;
1135}
1136
1137static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1138 struct genl_info *info)
1139{
1140 struct devlink_port *devlink_port = info->user_ptr[0];
1141 struct devlink *devlink = devlink_port->devlink;
1142 struct devlink_sb *devlink_sb = info->user_ptr[1];
1143 struct sk_buff *msg;
1144 u16 pool_index;
1145 int err;
1146
1147 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1148 &pool_index);
1149 if (err)
1150 return err;
1151
1152 if (!devlink->ops || !devlink->ops->sb_port_pool_get)
1153 return -EOPNOTSUPP;
1154
1155 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1156 if (!msg)
1157 return -ENOMEM;
1158
1159 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1160 devlink_sb, pool_index,
1161 DEVLINK_CMD_SB_PORT_POOL_NEW,
1162 info->snd_portid, info->snd_seq, 0);
1163 if (err) {
1164 nlmsg_free(msg);
1165 return err;
1166 }
1167
1168 return genlmsg_reply(msg, info);
1169}
1170
1171static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1172 struct devlink *devlink,
1173 struct devlink_sb *devlink_sb,
1174 u32 portid, u32 seq)
1175{
1176 struct devlink_port *devlink_port;
1177 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1178 u16 pool_index;
1179 int err;
1180
1181 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1182 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1183 if (*p_idx < start) {
1184 (*p_idx)++;
1185 continue;
1186 }
1187 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1188 devlink_port,
1189 devlink_sb,
1190 pool_index,
1191 DEVLINK_CMD_SB_PORT_POOL_NEW,
1192 portid, seq,
1193 NLM_F_MULTI);
1194 if (err)
1195 return err;
1196 (*p_idx)++;
1197 }
1198 }
1199 return 0;
1200}
1201
1202static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1203 struct netlink_callback *cb)
1204{
1205 struct devlink *devlink;
1206 struct devlink_sb *devlink_sb;
1207 int start = cb->args[0];
1208 int idx = 0;
1209 int err;
1210
1211 mutex_lock(&devlink_mutex);
bf797471
JP
1212 list_for_each_entry(devlink, &devlink_list, list) {
1213 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1214 !devlink->ops || !devlink->ops->sb_port_pool_get)
1215 continue;
2406e7e5 1216 mutex_lock(&devlink->lock);
bf797471
JP
1217 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1218 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1219 devlink, devlink_sb,
1220 NETLINK_CB(cb->skb).portid,
1221 cb->nlh->nlmsg_seq);
2406e7e5
AS
1222 if (err && err != -EOPNOTSUPP) {
1223 mutex_unlock(&devlink->lock);
bf797471 1224 goto out;
2406e7e5 1225 }
bf797471 1226 }
2406e7e5 1227 mutex_unlock(&devlink->lock);
bf797471
JP
1228 }
1229out:
bf797471
JP
1230 mutex_unlock(&devlink_mutex);
1231
1232 cb->args[0] = idx;
1233 return msg->len;
1234}
1235
1236static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1237 unsigned int sb_index, u16 pool_index,
1238 u32 threshold)
1239
1240{
1241 const struct devlink_ops *ops = devlink_port->devlink->ops;
1242
1243 if (ops && ops->sb_port_pool_set)
1244 return ops->sb_port_pool_set(devlink_port, sb_index,
1245 pool_index, threshold);
1246 return -EOPNOTSUPP;
1247}
1248
1249static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1250 struct genl_info *info)
1251{
1252 struct devlink_port *devlink_port = info->user_ptr[0];
1253 struct devlink_sb *devlink_sb = info->user_ptr[1];
1254 u16 pool_index;
1255 u32 threshold;
1256 int err;
1257
1258 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1259 &pool_index);
1260 if (err)
1261 return err;
1262
1263 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1264 return -EINVAL;
1265
1266 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1267 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
1268 pool_index, threshold);
1269}
1270
1271static int
1272devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1273 struct devlink_port *devlink_port,
1274 struct devlink_sb *devlink_sb, u16 tc_index,
1275 enum devlink_sb_pool_type pool_type,
1276 enum devlink_command cmd,
1277 u32 portid, u32 seq, int flags)
1278{
df38dafd 1279 const struct devlink_ops *ops = devlink->ops;
bf797471
JP
1280 u16 pool_index;
1281 u32 threshold;
1282 void *hdr;
1283 int err;
1284
df38dafd
JP
1285 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1286 tc_index, pool_type,
1287 &pool_index, &threshold);
bf797471
JP
1288 if (err)
1289 return err;
1290
1291 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1292 if (!hdr)
1293 return -EMSGSIZE;
1294
1295 if (devlink_nl_put_handle(msg, devlink))
1296 goto nla_put_failure;
1297 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1298 goto nla_put_failure;
1299 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1300 goto nla_put_failure;
1301 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1302 goto nla_put_failure;
1303 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1304 goto nla_put_failure;
1305 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1306 goto nla_put_failure;
1307 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1308 goto nla_put_failure;
1309
df38dafd
JP
1310 if (ops->sb_occ_tc_port_bind_get) {
1311 u32 cur;
1312 u32 max;
1313
1314 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1315 devlink_sb->index,
1316 tc_index, pool_type,
1317 &cur, &max);
1318 if (err && err != -EOPNOTSUPP)
1319 return err;
1320 if (!err) {
1321 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1322 goto nla_put_failure;
1323 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1324 goto nla_put_failure;
1325 }
1326 }
1327
bf797471
JP
1328 genlmsg_end(msg, hdr);
1329 return 0;
1330
1331nla_put_failure:
1332 genlmsg_cancel(msg, hdr);
1333 return -EMSGSIZE;
1334}
1335
1336static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1337 struct genl_info *info)
1338{
1339 struct devlink_port *devlink_port = info->user_ptr[0];
1340 struct devlink *devlink = devlink_port->devlink;
1341 struct devlink_sb *devlink_sb = info->user_ptr[1];
1342 struct sk_buff *msg;
1343 enum devlink_sb_pool_type pool_type;
1344 u16 tc_index;
1345 int err;
1346
1347 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1348 if (err)
1349 return err;
1350
1351 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1352 pool_type, &tc_index);
1353 if (err)
1354 return err;
1355
1356 if (!devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
1357 return -EOPNOTSUPP;
1358
1359 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1360 if (!msg)
1361 return -ENOMEM;
1362
1363 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1364 devlink_sb, tc_index, pool_type,
1365 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1366 info->snd_portid,
1367 info->snd_seq, 0);
1368 if (err) {
1369 nlmsg_free(msg);
1370 return err;
1371 }
1372
1373 return genlmsg_reply(msg, info);
1374}
1375
1376static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1377 int start, int *p_idx,
1378 struct devlink *devlink,
1379 struct devlink_sb *devlink_sb,
1380 u32 portid, u32 seq)
1381{
1382 struct devlink_port *devlink_port;
1383 u16 tc_index;
1384 int err;
1385
1386 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1387 for (tc_index = 0;
1388 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1389 if (*p_idx < start) {
1390 (*p_idx)++;
1391 continue;
1392 }
1393 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1394 devlink_port,
1395 devlink_sb,
1396 tc_index,
1397 DEVLINK_SB_POOL_TYPE_INGRESS,
1398 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1399 portid, seq,
1400 NLM_F_MULTI);
1401 if (err)
1402 return err;
1403 (*p_idx)++;
1404 }
1405 for (tc_index = 0;
1406 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1407 if (*p_idx < start) {
1408 (*p_idx)++;
1409 continue;
1410 }
1411 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1412 devlink_port,
1413 devlink_sb,
1414 tc_index,
1415 DEVLINK_SB_POOL_TYPE_EGRESS,
1416 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1417 portid, seq,
1418 NLM_F_MULTI);
1419 if (err)
1420 return err;
1421 (*p_idx)++;
1422 }
1423 }
1424 return 0;
1425}
1426
1427static int
1428devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1429 struct netlink_callback *cb)
1430{
1431 struct devlink *devlink;
1432 struct devlink_sb *devlink_sb;
1433 int start = cb->args[0];
1434 int idx = 0;
1435 int err;
1436
1437 mutex_lock(&devlink_mutex);
bf797471
JP
1438 list_for_each_entry(devlink, &devlink_list, list) {
1439 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1440 !devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
1441 continue;
2406e7e5
AS
1442
1443 mutex_lock(&devlink->lock);
bf797471
JP
1444 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1445 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1446 devlink,
1447 devlink_sb,
1448 NETLINK_CB(cb->skb).portid,
1449 cb->nlh->nlmsg_seq);
2406e7e5
AS
1450 if (err && err != -EOPNOTSUPP) {
1451 mutex_unlock(&devlink->lock);
bf797471 1452 goto out;
2406e7e5 1453 }
bf797471 1454 }
2406e7e5 1455 mutex_unlock(&devlink->lock);
bf797471
JP
1456 }
1457out:
bf797471
JP
1458 mutex_unlock(&devlink_mutex);
1459
1460 cb->args[0] = idx;
1461 return msg->len;
1462}
1463
1464static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1465 unsigned int sb_index, u16 tc_index,
1466 enum devlink_sb_pool_type pool_type,
1467 u16 pool_index, u32 threshold)
1468
1469{
1470 const struct devlink_ops *ops = devlink_port->devlink->ops;
1471
1472 if (ops && ops->sb_tc_pool_bind_set)
1473 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1474 tc_index, pool_type,
1475 pool_index, threshold);
1476 return -EOPNOTSUPP;
1477}
1478
1479static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1480 struct genl_info *info)
1481{
1482 struct devlink_port *devlink_port = info->user_ptr[0];
1483 struct devlink_sb *devlink_sb = info->user_ptr[1];
1484 enum devlink_sb_pool_type pool_type;
1485 u16 tc_index;
1486 u16 pool_index;
1487 u32 threshold;
1488 int err;
1489
1490 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1491 if (err)
1492 return err;
1493
1494 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1495 pool_type, &tc_index);
1496 if (err)
1497 return err;
1498
1499 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1500 &pool_index);
1501 if (err)
1502 return err;
1503
1504 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1505 return -EINVAL;
1506
1507 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1508 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1509 tc_index, pool_type,
1510 pool_index, threshold);
1511}
1512
df38dafd
JP
1513static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1514 struct genl_info *info)
1515{
1516 struct devlink *devlink = info->user_ptr[0];
1517 struct devlink_sb *devlink_sb = info->user_ptr[1];
1518 const struct devlink_ops *ops = devlink->ops;
1519
1520 if (ops && ops->sb_occ_snapshot)
1521 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1522 return -EOPNOTSUPP;
1523}
1524
1525static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1526 struct genl_info *info)
1527{
1528 struct devlink *devlink = info->user_ptr[0];
1529 struct devlink_sb *devlink_sb = info->user_ptr[1];
1530 const struct devlink_ops *ops = devlink->ops;
1531
1532 if (ops && ops->sb_occ_max_clear)
1533 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1534 return -EOPNOTSUPP;
1535}
1536
21e3d2dd
JP
1537static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1538 enum devlink_command cmd, u32 portid,
1539 u32 seq, int flags)
08f4b591 1540{
59bfde01 1541 const struct devlink_ops *ops = devlink->ops;
f43e9b06 1542 u8 inline_mode, encap_mode;
08f4b591 1543 void *hdr;
59bfde01
RD
1544 int err = 0;
1545 u16 mode;
08f4b591
OG
1546
1547 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1548 if (!hdr)
1549 return -EMSGSIZE;
1550
59bfde01
RD
1551 err = devlink_nl_put_handle(msg, devlink);
1552 if (err)
1a6aa36b 1553 goto nla_put_failure;
08f4b591 1554
4456f61c
JP
1555 if (ops->eswitch_mode_get) {
1556 err = ops->eswitch_mode_get(devlink, &mode);
1557 if (err)
1558 goto nla_put_failure;
1559 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1560 if (err)
1561 goto nla_put_failure;
1562 }
59bfde01
RD
1563
1564 if (ops->eswitch_inline_mode_get) {
1565 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1566 if (err)
1a6aa36b 1567 goto nla_put_failure;
59bfde01
RD
1568 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1569 inline_mode);
1570 if (err)
1a6aa36b 1571 goto nla_put_failure;
59bfde01 1572 }
08f4b591 1573
f43e9b06
RD
1574 if (ops->eswitch_encap_mode_get) {
1575 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1576 if (err)
1577 goto nla_put_failure;
1578 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1579 if (err)
1580 goto nla_put_failure;
1581 }
1582
08f4b591
OG
1583 genlmsg_end(msg, hdr);
1584 return 0;
1585
1a6aa36b 1586nla_put_failure:
08f4b591 1587 genlmsg_cancel(msg, hdr);
59bfde01 1588 return err;
08f4b591
OG
1589}
1590
adf200f3
JP
1591static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1592 struct genl_info *info)
08f4b591
OG
1593{
1594 struct devlink *devlink = info->user_ptr[0];
1595 const struct devlink_ops *ops = devlink->ops;
1596 struct sk_buff *msg;
08f4b591
OG
1597 int err;
1598
4456f61c 1599 if (!ops)
08f4b591
OG
1600 return -EOPNOTSUPP;
1601
08f4b591
OG
1602 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1603 if (!msg)
1604 return -ENOMEM;
1605
21e3d2dd
JP
1606 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1607 info->snd_portid, info->snd_seq, 0);
08f4b591
OG
1608
1609 if (err) {
1610 nlmsg_free(msg);
1611 return err;
1612 }
1613
1614 return genlmsg_reply(msg, info);
1615}
1616
adf200f3
JP
1617static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1618 struct genl_info *info)
08f4b591
OG
1619{
1620 struct devlink *devlink = info->user_ptr[0];
1621 const struct devlink_ops *ops = devlink->ops;
f43e9b06 1622 u8 inline_mode, encap_mode;
59bfde01 1623 int err = 0;
f43e9b06 1624 u16 mode;
08f4b591 1625
59bfde01
RD
1626 if (!ops)
1627 return -EOPNOTSUPP;
08f4b591 1628
59bfde01
RD
1629 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1630 if (!ops->eswitch_mode_set)
1631 return -EOPNOTSUPP;
1632 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
db7ff19e 1633 err = ops->eswitch_mode_set(devlink, mode, info->extack);
59bfde01
RD
1634 if (err)
1635 return err;
1636 }
08f4b591 1637
59bfde01
RD
1638 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1639 if (!ops->eswitch_inline_mode_set)
1640 return -EOPNOTSUPP;
1641 inline_mode = nla_get_u8(
1642 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
db7ff19e
EB
1643 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1644 info->extack);
59bfde01
RD
1645 if (err)
1646 return err;
1647 }
f43e9b06
RD
1648
1649 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1650 if (!ops->eswitch_encap_mode_set)
1651 return -EOPNOTSUPP;
1652 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
db7ff19e
EB
1653 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1654 info->extack);
f43e9b06
RD
1655 if (err)
1656 return err;
1657 }
1658
1555d204
AS
1659 return 0;
1660}
1661
1662int devlink_dpipe_match_put(struct sk_buff *skb,
1663 struct devlink_dpipe_match *match)
1664{
1665 struct devlink_dpipe_header *header = match->header;
1666 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1667 struct nlattr *match_attr;
1668
1669 match_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_MATCH);
1670 if (!match_attr)
1671 return -EMSGSIZE;
1672
1673 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1674 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1675 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1676 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1677 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1678 goto nla_put_failure;
1679
1680 nla_nest_end(skb, match_attr);
1681 return 0;
1682
1683nla_put_failure:
1684 nla_nest_cancel(skb, match_attr);
1685 return -EMSGSIZE;
1686}
1687EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1688
1689static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1690 struct sk_buff *skb)
1691{
1692 struct nlattr *matches_attr;
1693
1694 matches_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
1695 if (!matches_attr)
1696 return -EMSGSIZE;
1697
1698 if (table->table_ops->matches_dump(table->priv, skb))
1699 goto nla_put_failure;
1700
1701 nla_nest_end(skb, matches_attr);
1702 return 0;
1703
1704nla_put_failure:
1705 nla_nest_cancel(skb, matches_attr);
1706 return -EMSGSIZE;
1707}
1708
1709int devlink_dpipe_action_put(struct sk_buff *skb,
1710 struct devlink_dpipe_action *action)
1711{
1712 struct devlink_dpipe_header *header = action->header;
1713 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1714 struct nlattr *action_attr;
1715
1716 action_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ACTION);
1717 if (!action_attr)
1718 return -EMSGSIZE;
1719
1720 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1721 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1722 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1723 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1724 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1725 goto nla_put_failure;
1726
1727 nla_nest_end(skb, action_attr);
1728 return 0;
1729
1730nla_put_failure:
1731 nla_nest_cancel(skb, action_attr);
1732 return -EMSGSIZE;
1733}
1734EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1735
1736static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1737 struct sk_buff *skb)
1738{
1739 struct nlattr *actions_attr;
1740
1741 actions_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
1742 if (!actions_attr)
1743 return -EMSGSIZE;
1744
1745 if (table->table_ops->actions_dump(table->priv, skb))
1746 goto nla_put_failure;
1747
1748 nla_nest_end(skb, actions_attr);
1749 return 0;
1750
1751nla_put_failure:
1752 nla_nest_cancel(skb, actions_attr);
1753 return -EMSGSIZE;
1754}
1755
1756static int devlink_dpipe_table_put(struct sk_buff *skb,
1757 struct devlink_dpipe_table *table)
1758{
1759 struct nlattr *table_attr;
ffd3cdcc 1760 u64 table_size;
1555d204 1761
ffd3cdcc 1762 table_size = table->table_ops->size_get(table->priv);
1555d204
AS
1763 table_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE);
1764 if (!table_attr)
1765 return -EMSGSIZE;
1766
1767 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
ffd3cdcc 1768 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
1555d204
AS
1769 DEVLINK_ATTR_PAD))
1770 goto nla_put_failure;
1771 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1772 table->counters_enabled))
1773 goto nla_put_failure;
1774
56dc7cd0 1775 if (table->resource_valid) {
3d18e4f1
AS
1776 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1777 table->resource_id, DEVLINK_ATTR_PAD) ||
1778 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1779 table->resource_units, DEVLINK_ATTR_PAD))
1780 goto nla_put_failure;
56dc7cd0 1781 }
1555d204
AS
1782 if (devlink_dpipe_matches_put(table, skb))
1783 goto nla_put_failure;
1784
1785 if (devlink_dpipe_actions_put(table, skb))
1786 goto nla_put_failure;
1787
1788 nla_nest_end(skb, table_attr);
1789 return 0;
1790
1791nla_put_failure:
1792 nla_nest_cancel(skb, table_attr);
1793 return -EMSGSIZE;
1794}
1795
1796static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1797 struct genl_info *info)
1798{
1799 int err;
1800
1801 if (*pskb) {
1802 err = genlmsg_reply(*pskb, info);
1803 if (err)
1804 return err;
1805 }
1806 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1807 if (!*pskb)
1808 return -ENOMEM;
1809 return 0;
1810}
1811
1812static int devlink_dpipe_tables_fill(struct genl_info *info,
1813 enum devlink_command cmd, int flags,
1814 struct list_head *dpipe_tables,
1815 const char *table_name)
1816{
1817 struct devlink *devlink = info->user_ptr[0];
1818 struct devlink_dpipe_table *table;
1819 struct nlattr *tables_attr;
1820 struct sk_buff *skb = NULL;
1821 struct nlmsghdr *nlh;
1822 bool incomplete;
1823 void *hdr;
1824 int i;
1825 int err;
1826
1827 table = list_first_entry(dpipe_tables,
1828 struct devlink_dpipe_table, list);
1829start_again:
1830 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1831 if (err)
1832 return err;
1833
1834 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1835 &devlink_nl_family, NLM_F_MULTI, cmd);
6044bd4a
HY
1836 if (!hdr) {
1837 nlmsg_free(skb);
1555d204 1838 return -EMSGSIZE;
6044bd4a 1839 }
1555d204
AS
1840
1841 if (devlink_nl_put_handle(skb, devlink))
1842 goto nla_put_failure;
1843 tables_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLES);
1844 if (!tables_attr)
1845 goto nla_put_failure;
1846
1847 i = 0;
1848 incomplete = false;
1849 list_for_each_entry_from(table, dpipe_tables, list) {
1850 if (!table_name) {
1851 err = devlink_dpipe_table_put(skb, table);
1852 if (err) {
1853 if (!i)
1854 goto err_table_put;
1855 incomplete = true;
1856 break;
1857 }
1858 } else {
1859 if (!strcmp(table->name, table_name)) {
1860 err = devlink_dpipe_table_put(skb, table);
1861 if (err)
1862 break;
1863 }
1864 }
1865 i++;
1866 }
1867
1868 nla_nest_end(skb, tables_attr);
1869 genlmsg_end(skb, hdr);
1870 if (incomplete)
1871 goto start_again;
1872
1873send_done:
1874 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1875 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1876 if (!nlh) {
1877 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1878 if (err)
7fe4d6dc 1879 return err;
1555d204
AS
1880 goto send_done;
1881 }
1882
1883 return genlmsg_reply(skb, info);
1884
1885nla_put_failure:
1886 err = -EMSGSIZE;
1887err_table_put:
1555d204
AS
1888 nlmsg_free(skb);
1889 return err;
1890}
1891
1892static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
1893 struct genl_info *info)
1894{
1895 struct devlink *devlink = info->user_ptr[0];
1896 const char *table_name = NULL;
1897
1898 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
1899 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
1900
1901 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
1902 &devlink->dpipe_table_list,
1903 table_name);
1904}
1905
1906static int devlink_dpipe_value_put(struct sk_buff *skb,
1907 struct devlink_dpipe_value *value)
1908{
1909 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
1910 value->value_size, value->value))
1911 return -EMSGSIZE;
1912 if (value->mask)
1913 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
1914 value->value_size, value->mask))
1915 return -EMSGSIZE;
1916 if (value->mapping_valid)
1917 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
1918 value->mapping_value))
1919 return -EMSGSIZE;
1920 return 0;
1921}
1922
1923static int devlink_dpipe_action_value_put(struct sk_buff *skb,
1924 struct devlink_dpipe_value *value)
1925{
1926 if (!value->action)
1927 return -EINVAL;
1928 if (devlink_dpipe_action_put(skb, value->action))
1929 return -EMSGSIZE;
1930 if (devlink_dpipe_value_put(skb, value))
1931 return -EMSGSIZE;
1932 return 0;
1933}
1934
1935static int devlink_dpipe_action_values_put(struct sk_buff *skb,
1936 struct devlink_dpipe_value *values,
1937 unsigned int values_count)
1938{
1939 struct nlattr *action_attr;
1940 int i;
1941 int err;
1942
1943 for (i = 0; i < values_count; i++) {
1944 action_attr = nla_nest_start(skb,
1945 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
1946 if (!action_attr)
1947 return -EMSGSIZE;
1948 err = devlink_dpipe_action_value_put(skb, &values[i]);
1949 if (err)
1950 goto err_action_value_put;
1951 nla_nest_end(skb, action_attr);
1952 }
1953 return 0;
1954
1955err_action_value_put:
1956 nla_nest_cancel(skb, action_attr);
1957 return err;
1958}
1959
1960static int devlink_dpipe_match_value_put(struct sk_buff *skb,
1961 struct devlink_dpipe_value *value)
1962{
1963 if (!value->match)
1964 return -EINVAL;
1965 if (devlink_dpipe_match_put(skb, value->match))
1966 return -EMSGSIZE;
1967 if (devlink_dpipe_value_put(skb, value))
1968 return -EMSGSIZE;
1969 return 0;
1970}
1971
1972static int devlink_dpipe_match_values_put(struct sk_buff *skb,
1973 struct devlink_dpipe_value *values,
1974 unsigned int values_count)
1975{
1976 struct nlattr *match_attr;
1977 int i;
1978 int err;
1979
1980 for (i = 0; i < values_count; i++) {
1981 match_attr = nla_nest_start(skb,
1982 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
1983 if (!match_attr)
1984 return -EMSGSIZE;
1985 err = devlink_dpipe_match_value_put(skb, &values[i]);
1986 if (err)
1987 goto err_match_value_put;
1988 nla_nest_end(skb, match_attr);
1989 }
1990 return 0;
1991
1992err_match_value_put:
1993 nla_nest_cancel(skb, match_attr);
1994 return err;
1995}
1996
1997static int devlink_dpipe_entry_put(struct sk_buff *skb,
1998 struct devlink_dpipe_entry *entry)
1999{
2000 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2001 int err;
2002
2003 entry_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ENTRY);
2004 if (!entry_attr)
2005 return -EMSGSIZE;
2006
2007 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2008 DEVLINK_ATTR_PAD))
2009 goto nla_put_failure;
2010 if (entry->counter_valid)
2011 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2012 entry->counter, DEVLINK_ATTR_PAD))
2013 goto nla_put_failure;
2014
2015 matches_attr = nla_nest_start(skb,
2016 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
2017 if (!matches_attr)
2018 goto nla_put_failure;
2019
2020 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2021 entry->match_values_count);
2022 if (err) {
2023 nla_nest_cancel(skb, matches_attr);
2024 goto err_match_values_put;
2025 }
2026 nla_nest_end(skb, matches_attr);
2027
2028 actions_attr = nla_nest_start(skb,
2029 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
2030 if (!actions_attr)
2031 goto nla_put_failure;
2032
2033 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2034 entry->action_values_count);
2035 if (err) {
2036 nla_nest_cancel(skb, actions_attr);
2037 goto err_action_values_put;
2038 }
2039 nla_nest_end(skb, actions_attr);
59bfde01 2040
1555d204 2041 nla_nest_end(skb, entry_attr);
59bfde01 2042 return 0;
1555d204
AS
2043
2044nla_put_failure:
2045 err = -EMSGSIZE;
2046err_match_values_put:
2047err_action_values_put:
2048 nla_nest_cancel(skb, entry_attr);
2049 return err;
2050}
2051
2052static struct devlink_dpipe_table *
2053devlink_dpipe_table_find(struct list_head *dpipe_tables,
2054 const char *table_name)
2055{
2056 struct devlink_dpipe_table *table;
2057
2058 list_for_each_entry_rcu(table, dpipe_tables, list) {
2059 if (!strcmp(table->name, table_name))
2060 return table;
2061 }
2062 return NULL;
2063}
2064
2065int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2066{
2067 struct devlink *devlink;
2068 int err;
2069
2070 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2071 dump_ctx->info);
2072 if (err)
2073 return err;
2074
2075 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2076 dump_ctx->info->snd_portid,
2077 dump_ctx->info->snd_seq,
2078 &devlink_nl_family, NLM_F_MULTI,
2079 dump_ctx->cmd);
2080 if (!dump_ctx->hdr)
2081 goto nla_put_failure;
2082
2083 devlink = dump_ctx->info->user_ptr[0];
2084 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2085 goto nla_put_failure;
2086 dump_ctx->nest = nla_nest_start(dump_ctx->skb,
2087 DEVLINK_ATTR_DPIPE_ENTRIES);
2088 if (!dump_ctx->nest)
2089 goto nla_put_failure;
2090 return 0;
2091
2092nla_put_failure:
1555d204
AS
2093 nlmsg_free(dump_ctx->skb);
2094 return -EMSGSIZE;
2095}
2096EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2097
2098int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2099 struct devlink_dpipe_entry *entry)
2100{
2101 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2102}
2103EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2104
2105int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2106{
2107 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2108 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2109 return 0;
2110}
2111EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2112
35807324
AS
2113void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2114
2115{
2116 unsigned int value_count, value_index;
2117 struct devlink_dpipe_value *value;
2118
2119 value = entry->action_values;
2120 value_count = entry->action_values_count;
2121 for (value_index = 0; value_index < value_count; value_index++) {
2122 kfree(value[value_index].value);
2123 kfree(value[value_index].mask);
2124 }
2125
2126 value = entry->match_values;
2127 value_count = entry->match_values_count;
2128 for (value_index = 0; value_index < value_count; value_index++) {
2129 kfree(value[value_index].value);
2130 kfree(value[value_index].mask);
2131 }
2132}
2133EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2134
1555d204
AS
2135static int devlink_dpipe_entries_fill(struct genl_info *info,
2136 enum devlink_command cmd, int flags,
2137 struct devlink_dpipe_table *table)
2138{
2139 struct devlink_dpipe_dump_ctx dump_ctx;
2140 struct nlmsghdr *nlh;
2141 int err;
2142
2143 dump_ctx.skb = NULL;
2144 dump_ctx.cmd = cmd;
2145 dump_ctx.info = info;
2146
2147 err = table->table_ops->entries_dump(table->priv,
2148 table->counters_enabled,
2149 &dump_ctx);
2150 if (err)
7fe4d6dc 2151 return err;
1555d204
AS
2152
2153send_done:
2154 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2155 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2156 if (!nlh) {
2157 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2158 if (err)
7fe4d6dc 2159 return err;
1555d204
AS
2160 goto send_done;
2161 }
2162 return genlmsg_reply(dump_ctx.skb, info);
1555d204
AS
2163}
2164
2165static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2166 struct genl_info *info)
2167{
2168 struct devlink *devlink = info->user_ptr[0];
2169 struct devlink_dpipe_table *table;
2170 const char *table_name;
2171
2172 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2173 return -EINVAL;
2174
2175 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2176 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2177 table_name);
2178 if (!table)
2179 return -EINVAL;
2180
2181 if (!table->table_ops->entries_dump)
2182 return -EINVAL;
2183
2184 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2185 0, table);
2186}
2187
2188static int devlink_dpipe_fields_put(struct sk_buff *skb,
2189 const struct devlink_dpipe_header *header)
2190{
2191 struct devlink_dpipe_field *field;
2192 struct nlattr *field_attr;
2193 int i;
2194
2195 for (i = 0; i < header->fields_count; i++) {
2196 field = &header->fields[i];
2197 field_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_FIELD);
2198 if (!field_attr)
2199 return -EMSGSIZE;
2200 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2201 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2202 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2203 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2204 goto nla_put_failure;
2205 nla_nest_end(skb, field_attr);
2206 }
2207 return 0;
2208
2209nla_put_failure:
2210 nla_nest_cancel(skb, field_attr);
2211 return -EMSGSIZE;
2212}
2213
2214static int devlink_dpipe_header_put(struct sk_buff *skb,
2215 struct devlink_dpipe_header *header)
2216{
2217 struct nlattr *fields_attr, *header_attr;
2218 int err;
2219
2220 header_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER);
cb6bf9cf 2221 if (!header_attr)
1555d204
AS
2222 return -EMSGSIZE;
2223
2224 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2225 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2226 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2227 goto nla_put_failure;
2228
2229 fields_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
2230 if (!fields_attr)
2231 goto nla_put_failure;
2232
2233 err = devlink_dpipe_fields_put(skb, header);
2234 if (err) {
2235 nla_nest_cancel(skb, fields_attr);
2236 goto nla_put_failure;
2237 }
2238 nla_nest_end(skb, fields_attr);
2239 nla_nest_end(skb, header_attr);
2240 return 0;
2241
2242nla_put_failure:
2243 err = -EMSGSIZE;
2244 nla_nest_cancel(skb, header_attr);
2245 return err;
2246}
2247
2248static int devlink_dpipe_headers_fill(struct genl_info *info,
2249 enum devlink_command cmd, int flags,
2250 struct devlink_dpipe_headers *
2251 dpipe_headers)
2252{
2253 struct devlink *devlink = info->user_ptr[0];
2254 struct nlattr *headers_attr;
2255 struct sk_buff *skb = NULL;
2256 struct nlmsghdr *nlh;
2257 void *hdr;
2258 int i, j;
2259 int err;
2260
2261 i = 0;
2262start_again:
2263 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2264 if (err)
2265 return err;
2266
2267 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2268 &devlink_nl_family, NLM_F_MULTI, cmd);
6044bd4a
HY
2269 if (!hdr) {
2270 nlmsg_free(skb);
1555d204 2271 return -EMSGSIZE;
6044bd4a 2272 }
1555d204
AS
2273
2274 if (devlink_nl_put_handle(skb, devlink))
2275 goto nla_put_failure;
2276 headers_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADERS);
2277 if (!headers_attr)
2278 goto nla_put_failure;
2279
2280 j = 0;
2281 for (; i < dpipe_headers->headers_count; i++) {
2282 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2283 if (err) {
2284 if (!j)
2285 goto err_table_put;
2286 break;
2287 }
2288 j++;
2289 }
2290 nla_nest_end(skb, headers_attr);
2291 genlmsg_end(skb, hdr);
2292 if (i != dpipe_headers->headers_count)
2293 goto start_again;
2294
2295send_done:
2296 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2297 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2298 if (!nlh) {
2299 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2300 if (err)
7fe4d6dc 2301 return err;
1555d204
AS
2302 goto send_done;
2303 }
2304 return genlmsg_reply(skb, info);
2305
2306nla_put_failure:
2307 err = -EMSGSIZE;
2308err_table_put:
1555d204
AS
2309 nlmsg_free(skb);
2310 return err;
2311}
2312
2313static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2314 struct genl_info *info)
2315{
2316 struct devlink *devlink = info->user_ptr[0];
2317
2318 if (!devlink->dpipe_headers)
2319 return -EOPNOTSUPP;
2320 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2321 0, devlink->dpipe_headers);
2322}
2323
2324static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2325 const char *table_name,
2326 bool enable)
2327{
2328 struct devlink_dpipe_table *table;
2329
2330 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2331 table_name);
2332 if (!table)
2333 return -EINVAL;
2334
2335 if (table->counter_control_extern)
2336 return -EOPNOTSUPP;
2337
2338 if (!(table->counters_enabled ^ enable))
2339 return 0;
2340
2341 table->counters_enabled = enable;
2342 if (table->table_ops->counters_set_update)
2343 table->table_ops->counters_set_update(table->priv, enable);
2344 return 0;
2345}
2346
2347static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2348 struct genl_info *info)
2349{
2350 struct devlink *devlink = info->user_ptr[0];
2351 const char *table_name;
2352 bool counters_enable;
2353
2354 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2355 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2356 return -EINVAL;
2357
2358 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2359 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2360
2361 return devlink_dpipe_table_counters_set(devlink, table_name,
2362 counters_enable);
08f4b591
OG
2363}
2364
43dd7512 2365static struct devlink_resource *
d9f9b9a4
AS
2366devlink_resource_find(struct devlink *devlink,
2367 struct devlink_resource *resource, u64 resource_id)
2368{
2369 struct list_head *resource_list;
2370
2371 if (resource)
2372 resource_list = &resource->resource_list;
2373 else
2374 resource_list = &devlink->resource_list;
2375
2376 list_for_each_entry(resource, resource_list, list) {
2377 struct devlink_resource *child_resource;
2378
2379 if (resource->id == resource_id)
2380 return resource;
2381
2382 child_resource = devlink_resource_find(devlink, resource,
2383 resource_id);
2384 if (child_resource)
2385 return child_resource;
2386 }
2387 return NULL;
2388}
2389
43dd7512
WY
2390static void
2391devlink_resource_validate_children(struct devlink_resource *resource)
d9f9b9a4
AS
2392{
2393 struct devlink_resource *child_resource;
2394 bool size_valid = true;
2395 u64 parts_size = 0;
2396
2397 if (list_empty(&resource->resource_list))
2398 goto out;
2399
2400 list_for_each_entry(child_resource, &resource->resource_list, list)
2401 parts_size += child_resource->size_new;
2402
b9d17175 2403 if (parts_size > resource->size_new)
d9f9b9a4
AS
2404 size_valid = false;
2405out:
2406 resource->size_valid = size_valid;
2407}
2408
cc944ead
AS
2409static int
2410devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2411 struct netlink_ext_ack *extack)
2412{
2413 u64 reminder;
2414 int err = 0;
2415
0f3e9c97 2416 if (size > resource->size_params.size_max) {
cc944ead
AS
2417 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2418 err = -EINVAL;
2419 }
2420
0f3e9c97 2421 if (size < resource->size_params.size_min) {
cc944ead
AS
2422 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2423 err = -EINVAL;
2424 }
2425
0f3e9c97 2426 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
cc944ead
AS
2427 if (reminder) {
2428 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2429 err = -EINVAL;
2430 }
2431
2432 return err;
2433}
2434
d9f9b9a4
AS
2435static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2436 struct genl_info *info)
2437{
2438 struct devlink *devlink = info->user_ptr[0];
2439 struct devlink_resource *resource;
2440 u64 resource_id;
2441 u64 size;
2442 int err;
2443
2444 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2445 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2446 return -EINVAL;
2447 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2448
2449 resource = devlink_resource_find(devlink, NULL, resource_id);
2450 if (!resource)
2451 return -EINVAL;
2452
d9f9b9a4 2453 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
cc944ead 2454 err = devlink_resource_validate_size(resource, size, info->extack);
d9f9b9a4
AS
2455 if (err)
2456 return err;
2457
2458 resource->size_new = size;
2459 devlink_resource_validate_children(resource);
2460 if (resource->parent)
2461 devlink_resource_validate_children(resource->parent);
2462 return 0;
2463}
2464
3d18e4f1 2465static int
d9f9b9a4
AS
2466devlink_resource_size_params_put(struct devlink_resource *resource,
2467 struct sk_buff *skb)
2468{
2469 struct devlink_resource_size_params *size_params;
2470
77d27096 2471 size_params = &resource->size_params;
3d18e4f1
AS
2472 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2473 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2474 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2475 size_params->size_max, DEVLINK_ATTR_PAD) ||
2476 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2477 size_params->size_min, DEVLINK_ATTR_PAD) ||
2478 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2479 return -EMSGSIZE;
2480 return 0;
d9f9b9a4
AS
2481}
2482
fc56be47
JP
2483static int devlink_resource_occ_put(struct devlink_resource *resource,
2484 struct sk_buff *skb)
2485{
2486 if (!resource->occ_get)
2487 return 0;
2488 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2489 resource->occ_get(resource->occ_get_priv),
2490 DEVLINK_ATTR_PAD);
2491}
2492
d9f9b9a4
AS
2493static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2494 struct devlink_resource *resource)
2495{
2496 struct devlink_resource *child_resource;
2497 struct nlattr *child_resource_attr;
2498 struct nlattr *resource_attr;
2499
2500 resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE);
2501 if (!resource_attr)
2502 return -EMSGSIZE;
2503
2504 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2505 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2506 DEVLINK_ATTR_PAD) ||
2507 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2508 DEVLINK_ATTR_PAD))
2509 goto nla_put_failure;
2510 if (resource->size != resource->size_new)
2511 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2512 resource->size_new, DEVLINK_ATTR_PAD);
fc56be47
JP
2513 if (devlink_resource_occ_put(resource, skb))
2514 goto nla_put_failure;
3d18e4f1
AS
2515 if (devlink_resource_size_params_put(resource, skb))
2516 goto nla_put_failure;
d9f9b9a4
AS
2517 if (list_empty(&resource->resource_list))
2518 goto out;
2519
2520 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2521 resource->size_valid))
2522 goto nla_put_failure;
2523
2524 child_resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2525 if (!child_resource_attr)
2526 goto nla_put_failure;
2527
2528 list_for_each_entry(child_resource, &resource->resource_list, list) {
2529 if (devlink_resource_put(devlink, skb, child_resource))
2530 goto resource_put_failure;
2531 }
2532
2533 nla_nest_end(skb, child_resource_attr);
2534out:
2535 nla_nest_end(skb, resource_attr);
2536 return 0;
2537
2538resource_put_failure:
2539 nla_nest_cancel(skb, child_resource_attr);
2540nla_put_failure:
2541 nla_nest_cancel(skb, resource_attr);
2542 return -EMSGSIZE;
2543}
2544
2545static int devlink_resource_fill(struct genl_info *info,
2546 enum devlink_command cmd, int flags)
2547{
2548 struct devlink *devlink = info->user_ptr[0];
2549 struct devlink_resource *resource;
2550 struct nlattr *resources_attr;
2551 struct sk_buff *skb = NULL;
2552 struct nlmsghdr *nlh;
2553 bool incomplete;
2554 void *hdr;
2555 int i;
2556 int err;
2557
2558 resource = list_first_entry(&devlink->resource_list,
2559 struct devlink_resource, list);
2560start_again:
2561 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2562 if (err)
2563 return err;
2564
2565 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2566 &devlink_nl_family, NLM_F_MULTI, cmd);
2567 if (!hdr) {
2568 nlmsg_free(skb);
2569 return -EMSGSIZE;
2570 }
2571
2572 if (devlink_nl_put_handle(skb, devlink))
2573 goto nla_put_failure;
2574
2575 resources_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2576 if (!resources_attr)
2577 goto nla_put_failure;
2578
2579 incomplete = false;
2580 i = 0;
2581 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2582 err = devlink_resource_put(devlink, skb, resource);
2583 if (err) {
2584 if (!i)
2585 goto err_resource_put;
2586 incomplete = true;
2587 break;
2588 }
2589 i++;
2590 }
2591 nla_nest_end(skb, resources_attr);
2592 genlmsg_end(skb, hdr);
2593 if (incomplete)
2594 goto start_again;
2595send_done:
2596 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2597 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2598 if (!nlh) {
2599 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2600 if (err)
83fe9a96 2601 return err;
d9f9b9a4
AS
2602 goto send_done;
2603 }
2604 return genlmsg_reply(skb, info);
2605
2606nla_put_failure:
2607 err = -EMSGSIZE;
2608err_resource_put:
d9f9b9a4
AS
2609 nlmsg_free(skb);
2610 return err;
2611}
2612
2613static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2614 struct genl_info *info)
2615{
2616 struct devlink *devlink = info->user_ptr[0];
2617
2618 if (list_empty(&devlink->resource_list))
2619 return -EOPNOTSUPP;
2620
2621 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2622}
2623
2d8dc5bb
AS
2624static int
2625devlink_resources_validate(struct devlink *devlink,
2626 struct devlink_resource *resource,
2627 struct genl_info *info)
2628{
2629 struct list_head *resource_list;
2630 int err = 0;
2631
2632 if (resource)
2633 resource_list = &resource->resource_list;
2634 else
2635 resource_list = &devlink->resource_list;
2636
2637 list_for_each_entry(resource, resource_list, list) {
2638 if (!resource->size_valid)
2639 return -EINVAL;
2640 err = devlink_resources_validate(devlink, resource, info);
2641 if (err)
2642 return err;
2643 }
2644 return err;
2645}
2646
2647static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2648{
2649 struct devlink *devlink = info->user_ptr[0];
2650 int err;
2651
2652 if (!devlink->ops->reload)
2653 return -EOPNOTSUPP;
2654
2655 err = devlink_resources_validate(devlink, NULL, info);
2656 if (err) {
2657 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2658 return err;
2659 }
ac0fc8a1 2660 return devlink->ops->reload(devlink, info->extack);
2d8dc5bb
AS
2661}
2662
036467c3
MS
2663static const struct devlink_param devlink_param_generic[] = {
2664 {
2665 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
2666 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
2667 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
2668 },
2669 {
2670 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
2671 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
2672 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
2673 },
f567bcda
VV
2674 {
2675 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
2676 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
2677 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
2678 },
f6a69885
AV
2679 {
2680 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
2681 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
2682 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
2683 },
e3b51061
VV
2684 {
2685 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
2686 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
2687 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
2688 },
f61cba42
VV
2689 {
2690 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
2691 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
2692 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
2693 },
16511789
VV
2694 {
2695 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
2696 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
2697 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
2698 },
846e980a
ST
2699 {
2700 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
2701 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
2702 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
2703 },
b639583f
VV
2704 {
2705 .id = DEVLINK_PARAM_GENERIC_ID_WOL,
2706 .name = DEVLINK_PARAM_GENERIC_WOL_NAME,
2707 .type = DEVLINK_PARAM_GENERIC_WOL_TYPE,
2708 },
036467c3 2709};
eabaef18
MS
2710
2711static int devlink_param_generic_verify(const struct devlink_param *param)
2712{
2713 /* verify it match generic parameter by id and name */
2714 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
2715 return -EINVAL;
2716 if (strcmp(param->name, devlink_param_generic[param->id].name))
2717 return -ENOENT;
2718
2719 WARN_ON(param->type != devlink_param_generic[param->id].type);
2720
2721 return 0;
2722}
2723
2724static int devlink_param_driver_verify(const struct devlink_param *param)
2725{
2726 int i;
2727
2728 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
2729 return -EINVAL;
2730 /* verify no such name in generic params */
2731 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
2732 if (!strcmp(param->name, devlink_param_generic[i].name))
2733 return -EEXIST;
2734
2735 return 0;
2736}
2737
2738static struct devlink_param_item *
2739devlink_param_find_by_name(struct list_head *param_list,
2740 const char *param_name)
2741{
2742 struct devlink_param_item *param_item;
2743
2744 list_for_each_entry(param_item, param_list, list)
2745 if (!strcmp(param_item->param->name, param_name))
2746 return param_item;
2747 return NULL;
2748}
2749
ec01aeb1
MS
2750static struct devlink_param_item *
2751devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
2752{
2753 struct devlink_param_item *param_item;
2754
2755 list_for_each_entry(param_item, param_list, list)
2756 if (param_item->param->id == param_id)
2757 return param_item;
2758 return NULL;
2759}
2760
45f05def
MS
2761static bool
2762devlink_param_cmode_is_supported(const struct devlink_param *param,
2763 enum devlink_param_cmode cmode)
2764{
2765 return test_bit(cmode, &param->supported_cmodes);
2766}
2767
2768static int devlink_param_get(struct devlink *devlink,
2769 const struct devlink_param *param,
2770 struct devlink_param_gset_ctx *ctx)
2771{
2772 if (!param->get)
2773 return -EOPNOTSUPP;
2774 return param->get(devlink, param->id, ctx);
2775}
2776
e3b7ca18
MS
2777static int devlink_param_set(struct devlink *devlink,
2778 const struct devlink_param *param,
2779 struct devlink_param_gset_ctx *ctx)
2780{
2781 if (!param->set)
2782 return -EOPNOTSUPP;
2783 return param->set(devlink, param->id, ctx);
2784}
2785
45f05def
MS
2786static int
2787devlink_param_type_to_nla_type(enum devlink_param_type param_type)
2788{
2789 switch (param_type) {
2790 case DEVLINK_PARAM_TYPE_U8:
2791 return NLA_U8;
2792 case DEVLINK_PARAM_TYPE_U16:
2793 return NLA_U16;
2794 case DEVLINK_PARAM_TYPE_U32:
2795 return NLA_U32;
2796 case DEVLINK_PARAM_TYPE_STRING:
2797 return NLA_STRING;
2798 case DEVLINK_PARAM_TYPE_BOOL:
2799 return NLA_FLAG;
2800 default:
2801 return -EINVAL;
2802 }
2803}
2804
2805static int
2806devlink_nl_param_value_fill_one(struct sk_buff *msg,
2807 enum devlink_param_type type,
2808 enum devlink_param_cmode cmode,
2809 union devlink_param_value val)
2810{
2811 struct nlattr *param_value_attr;
2812
2813 param_value_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUE);
2814 if (!param_value_attr)
2815 goto nla_put_failure;
2816
2817 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
2818 goto value_nest_cancel;
2819
2820 switch (type) {
2821 case DEVLINK_PARAM_TYPE_U8:
2822 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
2823 goto value_nest_cancel;
2824 break;
2825 case DEVLINK_PARAM_TYPE_U16:
2826 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
2827 goto value_nest_cancel;
2828 break;
2829 case DEVLINK_PARAM_TYPE_U32:
2830 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
2831 goto value_nest_cancel;
2832 break;
2833 case DEVLINK_PARAM_TYPE_STRING:
2834 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
2835 val.vstr))
2836 goto value_nest_cancel;
2837 break;
2838 case DEVLINK_PARAM_TYPE_BOOL:
2839 if (val.vbool &&
2840 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
2841 goto value_nest_cancel;
2842 break;
2843 }
2844
2845 nla_nest_end(msg, param_value_attr);
2846 return 0;
2847
2848value_nest_cancel:
2849 nla_nest_cancel(msg, param_value_attr);
2850nla_put_failure:
2851 return -EMSGSIZE;
2852}
2853
2854static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
f4601dee 2855 unsigned int port_index,
45f05def
MS
2856 struct devlink_param_item *param_item,
2857 enum devlink_command cmd,
2858 u32 portid, u32 seq, int flags)
2859{
2860 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
2861 const struct devlink_param *param = param_item->param;
2862 struct devlink_param_gset_ctx ctx;
2863 struct nlattr *param_values_list;
2864 struct nlattr *param_attr;
2865 int nla_type;
2866 void *hdr;
2867 int err;
2868 int i;
2869
2870 /* Get value from driver part to driverinit configuration mode */
2871 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
2872 if (!devlink_param_cmode_is_supported(param, i))
2873 continue;
2874 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
2875 if (!param_item->driverinit_value_valid)
2876 return -EOPNOTSUPP;
2877 param_value[i] = param_item->driverinit_value;
2878 } else {
2879 ctx.cmode = i;
2880 err = devlink_param_get(devlink, param, &ctx);
2881 if (err)
2882 return err;
2883 param_value[i] = ctx.val;
2884 }
2885 }
2886
2887 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
2888 if (!hdr)
2889 return -EMSGSIZE;
2890
2891 if (devlink_nl_put_handle(msg, devlink))
2892 goto genlmsg_cancel;
f4601dee 2893
c1e5786d
VV
2894 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
2895 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
2896 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
f4601dee
VV
2897 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
2898 goto genlmsg_cancel;
2899
45f05def
MS
2900 param_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM);
2901 if (!param_attr)
2902 goto genlmsg_cancel;
2903 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
2904 goto param_nest_cancel;
2905 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
2906 goto param_nest_cancel;
2907
2908 nla_type = devlink_param_type_to_nla_type(param->type);
2909 if (nla_type < 0)
2910 goto param_nest_cancel;
2911 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
2912 goto param_nest_cancel;
2913
2914 param_values_list = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUES_LIST);
2915 if (!param_values_list)
2916 goto param_nest_cancel;
2917
2918 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
2919 if (!devlink_param_cmode_is_supported(param, i))
2920 continue;
2921 err = devlink_nl_param_value_fill_one(msg, param->type,
2922 i, param_value[i]);
2923 if (err)
2924 goto values_list_nest_cancel;
2925 }
2926
2927 nla_nest_end(msg, param_values_list);
2928 nla_nest_end(msg, param_attr);
2929 genlmsg_end(msg, hdr);
2930 return 0;
2931
2932values_list_nest_cancel:
2933 nla_nest_end(msg, param_values_list);
2934param_nest_cancel:
2935 nla_nest_cancel(msg, param_attr);
2936genlmsg_cancel:
2937 genlmsg_cancel(msg, hdr);
2938 return -EMSGSIZE;
2939}
2940
ea601e17 2941static void devlink_param_notify(struct devlink *devlink,
c1e5786d 2942 unsigned int port_index,
ea601e17
MS
2943 struct devlink_param_item *param_item,
2944 enum devlink_command cmd)
2945{
2946 struct sk_buff *msg;
2947 int err;
2948
c1e5786d
VV
2949 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
2950 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
2951 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
ea601e17
MS
2952
2953 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2954 if (!msg)
2955 return;
c1e5786d
VV
2956 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
2957 0, 0, 0);
ea601e17
MS
2958 if (err) {
2959 nlmsg_free(msg);
2960 return;
2961 }
2962
2963 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
2964 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
2965}
2966
45f05def
MS
2967static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
2968 struct netlink_callback *cb)
2969{
2970 struct devlink_param_item *param_item;
2971 struct devlink *devlink;
2972 int start = cb->args[0];
2973 int idx = 0;
2974 int err;
2975
2976 mutex_lock(&devlink_mutex);
2977 list_for_each_entry(devlink, &devlink_list, list) {
2978 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
2979 continue;
2980 mutex_lock(&devlink->lock);
2981 list_for_each_entry(param_item, &devlink->param_list, list) {
2982 if (idx < start) {
2983 idx++;
2984 continue;
2985 }
f4601dee 2986 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
2987 DEVLINK_CMD_PARAM_GET,
2988 NETLINK_CB(cb->skb).portid,
2989 cb->nlh->nlmsg_seq,
2990 NLM_F_MULTI);
2991 if (err) {
2992 mutex_unlock(&devlink->lock);
2993 goto out;
2994 }
2995 idx++;
2996 }
2997 mutex_unlock(&devlink->lock);
2998 }
2999out:
3000 mutex_unlock(&devlink_mutex);
3001
3002 cb->args[0] = idx;
3003 return msg->len;
3004}
3005
e3b7ca18
MS
3006static int
3007devlink_param_type_get_from_info(struct genl_info *info,
3008 enum devlink_param_type *param_type)
3009{
3010 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3011 return -EINVAL;
3012
3013 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3014 case NLA_U8:
3015 *param_type = DEVLINK_PARAM_TYPE_U8;
3016 break;
3017 case NLA_U16:
3018 *param_type = DEVLINK_PARAM_TYPE_U16;
3019 break;
3020 case NLA_U32:
3021 *param_type = DEVLINK_PARAM_TYPE_U32;
3022 break;
3023 case NLA_STRING:
3024 *param_type = DEVLINK_PARAM_TYPE_STRING;
3025 break;
3026 case NLA_FLAG:
3027 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3028 break;
3029 default:
3030 return -EINVAL;
3031 }
3032
3033 return 0;
3034}
3035
3036static int
3037devlink_param_value_get_from_info(const struct devlink_param *param,
3038 struct genl_info *info,
3039 union devlink_param_value *value)
3040{
f355cfcd
MS
3041 int len;
3042
e3b7ca18
MS
3043 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3044 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3045 return -EINVAL;
3046
3047 switch (param->type) {
3048 case DEVLINK_PARAM_TYPE_U8:
3049 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3050 break;
3051 case DEVLINK_PARAM_TYPE_U16:
3052 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3053 break;
3054 case DEVLINK_PARAM_TYPE_U32:
3055 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3056 break;
3057 case DEVLINK_PARAM_TYPE_STRING:
f355cfcd
MS
3058 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3059 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3060 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
bde74ad1 3061 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
e3b7ca18 3062 return -EINVAL;
f355cfcd
MS
3063 strcpy(value->vstr,
3064 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
e3b7ca18
MS
3065 break;
3066 case DEVLINK_PARAM_TYPE_BOOL:
3067 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3068 true : false;
3069 break;
3070 }
3071 return 0;
3072}
3073
45f05def 3074static struct devlink_param_item *
f4601dee 3075devlink_param_get_from_info(struct list_head *param_list,
45f05def
MS
3076 struct genl_info *info)
3077{
3078 char *param_name;
3079
3080 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3081 return NULL;
3082
3083 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
f4601dee 3084 return devlink_param_find_by_name(param_list, param_name);
45f05def
MS
3085}
3086
3087static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3088 struct genl_info *info)
3089{
3090 struct devlink *devlink = info->user_ptr[0];
3091 struct devlink_param_item *param_item;
3092 struct sk_buff *msg;
3093 int err;
3094
f4601dee 3095 param_item = devlink_param_get_from_info(&devlink->param_list, info);
45f05def
MS
3096 if (!param_item)
3097 return -EINVAL;
3098
3099 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3100 if (!msg)
3101 return -ENOMEM;
3102
f4601dee 3103 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
3104 DEVLINK_CMD_PARAM_GET,
3105 info->snd_portid, info->snd_seq, 0);
3106 if (err) {
3107 nlmsg_free(msg);
3108 return err;
3109 }
3110
3111 return genlmsg_reply(msg, info);
3112}
3113
9c54873b 3114static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
c1e5786d 3115 unsigned int port_index,
9c54873b
VV
3116 struct list_head *param_list,
3117 struct genl_info *info,
3118 enum devlink_command cmd)
e3b7ca18 3119{
e3b7ca18
MS
3120 enum devlink_param_type param_type;
3121 struct devlink_param_gset_ctx ctx;
3122 enum devlink_param_cmode cmode;
3123 struct devlink_param_item *param_item;
3124 const struct devlink_param *param;
3125 union devlink_param_value value;
3126 int err = 0;
3127
9c54873b 3128 param_item = devlink_param_get_from_info(param_list, info);
e3b7ca18
MS
3129 if (!param_item)
3130 return -EINVAL;
3131 param = param_item->param;
3132 err = devlink_param_type_get_from_info(info, &param_type);
3133 if (err)
3134 return err;
3135 if (param_type != param->type)
3136 return -EINVAL;
3137 err = devlink_param_value_get_from_info(param, info, &value);
3138 if (err)
3139 return err;
3140 if (param->validate) {
3141 err = param->validate(devlink, param->id, value, info->extack);
3142 if (err)
3143 return err;
3144 }
3145
3146 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3147 return -EINVAL;
3148 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3149 if (!devlink_param_cmode_is_supported(param, cmode))
3150 return -EOPNOTSUPP;
3151
3152 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
1276534c
MS
3153 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3154 strcpy(param_item->driverinit_value.vstr, value.vstr);
3155 else
3156 param_item->driverinit_value = value;
e3b7ca18
MS
3157 param_item->driverinit_value_valid = true;
3158 } else {
3159 if (!param->set)
3160 return -EOPNOTSUPP;
3161 ctx.val = value;
3162 ctx.cmode = cmode;
3163 err = devlink_param_set(devlink, param, &ctx);
3164 if (err)
3165 return err;
3166 }
3167
c1e5786d 3168 devlink_param_notify(devlink, port_index, param_item, cmd);
e3b7ca18
MS
3169 return 0;
3170}
3171
9c54873b
VV
3172static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3173 struct genl_info *info)
3174{
3175 struct devlink *devlink = info->user_ptr[0];
3176
c1e5786d 3177 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
9c54873b
VV
3178 info, DEVLINK_CMD_PARAM_NEW);
3179}
3180
eabaef18 3181static int devlink_param_register_one(struct devlink *devlink,
c1e5786d 3182 unsigned int port_index,
39e6160e 3183 struct list_head *param_list,
c1e5786d
VV
3184 const struct devlink_param *param,
3185 enum devlink_command cmd)
eabaef18
MS
3186{
3187 struct devlink_param_item *param_item;
3188
39e6160e 3189 if (devlink_param_find_by_name(param_list, param->name))
eabaef18
MS
3190 return -EEXIST;
3191
3192 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3193 WARN_ON(param->get || param->set);
3194 else
3195 WARN_ON(!param->get || !param->set);
3196
3197 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3198 if (!param_item)
3199 return -ENOMEM;
3200 param_item->param = param;
3201
39e6160e 3202 list_add_tail(&param_item->list, param_list);
c1e5786d 3203 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3204 return 0;
3205}
3206
3207static void devlink_param_unregister_one(struct devlink *devlink,
c1e5786d 3208 unsigned int port_index,
39e6160e 3209 struct list_head *param_list,
c1e5786d
VV
3210 const struct devlink_param *param,
3211 enum devlink_command cmd)
eabaef18
MS
3212{
3213 struct devlink_param_item *param_item;
3214
39e6160e 3215 param_item = devlink_param_find_by_name(param_list, param->name);
eabaef18 3216 WARN_ON(!param_item);
c1e5786d 3217 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3218 list_del(&param_item->list);
3219 kfree(param_item);
3220}
3221
f4601dee
VV
3222static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3223 struct netlink_callback *cb)
3224{
3225 struct devlink_param_item *param_item;
3226 struct devlink_port *devlink_port;
3227 struct devlink *devlink;
3228 int start = cb->args[0];
3229 int idx = 0;
3230 int err;
3231
3232 mutex_lock(&devlink_mutex);
3233 list_for_each_entry(devlink, &devlink_list, list) {
3234 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3235 continue;
3236 mutex_lock(&devlink->lock);
3237 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3238 list_for_each_entry(param_item,
3239 &devlink_port->param_list, list) {
3240 if (idx < start) {
3241 idx++;
3242 continue;
3243 }
3244 err = devlink_nl_param_fill(msg,
3245 devlink_port->devlink,
3246 devlink_port->index, param_item,
3247 DEVLINK_CMD_PORT_PARAM_GET,
3248 NETLINK_CB(cb->skb).portid,
3249 cb->nlh->nlmsg_seq,
3250 NLM_F_MULTI);
3251 if (err) {
3252 mutex_unlock(&devlink->lock);
3253 goto out;
3254 }
3255 idx++;
3256 }
3257 }
3258 mutex_unlock(&devlink->lock);
3259 }
3260out:
3261 mutex_unlock(&devlink_mutex);
3262
3263 cb->args[0] = idx;
3264 return msg->len;
3265}
3266
3267static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3268 struct genl_info *info)
3269{
3270 struct devlink_port *devlink_port = info->user_ptr[0];
3271 struct devlink_param_item *param_item;
3272 struct sk_buff *msg;
3273 int err;
3274
3275 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3276 info);
3277 if (!param_item)
3278 return -EINVAL;
3279
3280 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3281 if (!msg)
3282 return -ENOMEM;
3283
3284 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3285 devlink_port->index, param_item,
3286 DEVLINK_CMD_PORT_PARAM_GET,
3287 info->snd_portid, info->snd_seq, 0);
3288 if (err) {
3289 nlmsg_free(msg);
3290 return err;
3291 }
3292
3293 return genlmsg_reply(msg, info);
3294}
3295
9c54873b
VV
3296static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3297 struct genl_info *info)
3298{
3299 struct devlink_port *devlink_port = info->user_ptr[0];
3300
3301 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
c1e5786d
VV
3302 devlink_port->index,
3303 &devlink_port->param_list, info,
3304 DEVLINK_CMD_PORT_PARAM_NEW);
9c54873b
VV
3305}
3306
a006d467
AV
3307static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3308 struct devlink *devlink,
3309 struct devlink_snapshot *snapshot)
3310{
3311 struct nlattr *snap_attr;
3312 int err;
3313
3314 snap_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
3315 if (!snap_attr)
3316 return -EINVAL;
3317
3318 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3319 if (err)
3320 goto nla_put_failure;
3321
3322 nla_nest_end(msg, snap_attr);
3323 return 0;
3324
3325nla_put_failure:
3326 nla_nest_cancel(msg, snap_attr);
3327 return err;
3328}
3329
3330static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3331 struct devlink *devlink,
3332 struct devlink_region *region)
3333{
3334 struct devlink_snapshot *snapshot;
3335 struct nlattr *snapshots_attr;
3336 int err;
3337
3338 snapshots_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOTS);
3339 if (!snapshots_attr)
3340 return -EINVAL;
3341
3342 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3343 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3344 if (err)
3345 goto nla_put_failure;
3346 }
3347
3348 nla_nest_end(msg, snapshots_attr);
3349 return 0;
3350
3351nla_put_failure:
3352 nla_nest_cancel(msg, snapshots_attr);
3353 return err;
3354}
3355
d8db7ea5
AV
3356static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3357 enum devlink_command cmd, u32 portid,
3358 u32 seq, int flags,
3359 struct devlink_region *region)
3360{
3361 void *hdr;
3362 int err;
3363
3364 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3365 if (!hdr)
3366 return -EMSGSIZE;
3367
3368 err = devlink_nl_put_handle(msg, devlink);
3369 if (err)
3370 goto nla_put_failure;
3371
3372 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3373 if (err)
3374 goto nla_put_failure;
3375
3376 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3377 region->size,
3378 DEVLINK_ATTR_PAD);
3379 if (err)
3380 goto nla_put_failure;
3381
a006d467
AV
3382 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3383 if (err)
3384 goto nla_put_failure;
3385
d8db7ea5
AV
3386 genlmsg_end(msg, hdr);
3387 return 0;
3388
3389nla_put_failure:
3390 genlmsg_cancel(msg, hdr);
3391 return err;
3392}
3393
866319bb
AV
3394static void devlink_nl_region_notify(struct devlink_region *region,
3395 struct devlink_snapshot *snapshot,
3396 enum devlink_command cmd)
3397{
3398 struct devlink *devlink = region->devlink;
3399 struct sk_buff *msg;
3400 void *hdr;
3401 int err;
3402
3403 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3404
3405 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3406 if (!msg)
3407 return;
3408
3409 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3410 if (!hdr)
3411 goto out_free_msg;
3412
3413 err = devlink_nl_put_handle(msg, devlink);
3414 if (err)
3415 goto out_cancel_msg;
3416
3417 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3418 region->name);
3419 if (err)
3420 goto out_cancel_msg;
3421
3422 if (snapshot) {
3423 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3424 snapshot->id);
3425 if (err)
3426 goto out_cancel_msg;
3427 } else {
3428 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3429 region->size, DEVLINK_ATTR_PAD);
3430 if (err)
3431 goto out_cancel_msg;
3432 }
3433 genlmsg_end(msg, hdr);
3434
3435 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3436 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3437
3438 return;
3439
3440out_cancel_msg:
3441 genlmsg_cancel(msg, hdr);
3442out_free_msg:
3443 nlmsg_free(msg);
3444}
3445
d8db7ea5
AV
3446static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3447 struct genl_info *info)
3448{
3449 struct devlink *devlink = info->user_ptr[0];
3450 struct devlink_region *region;
3451 const char *region_name;
3452 struct sk_buff *msg;
3453 int err;
3454
3455 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3456 return -EINVAL;
3457
3458 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3459 region = devlink_region_get_by_name(devlink, region_name);
3460 if (!region)
3461 return -EINVAL;
3462
3463 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3464 if (!msg)
3465 return -ENOMEM;
3466
3467 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3468 info->snd_portid, info->snd_seq, 0,
3469 region);
3470 if (err) {
3471 nlmsg_free(msg);
3472 return err;
3473 }
3474
3475 return genlmsg_reply(msg, info);
3476}
3477
3478static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3479 struct netlink_callback *cb)
3480{
3481 struct devlink_region *region;
3482 struct devlink *devlink;
3483 int start = cb->args[0];
3484 int idx = 0;
3485 int err;
3486
3487 mutex_lock(&devlink_mutex);
3488 list_for_each_entry(devlink, &devlink_list, list) {
3489 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3490 continue;
3491
3492 mutex_lock(&devlink->lock);
3493 list_for_each_entry(region, &devlink->region_list, list) {
3494 if (idx < start) {
3495 idx++;
3496 continue;
3497 }
3498 err = devlink_nl_region_fill(msg, devlink,
3499 DEVLINK_CMD_REGION_GET,
3500 NETLINK_CB(cb->skb).portid,
3501 cb->nlh->nlmsg_seq,
3502 NLM_F_MULTI, region);
3503 if (err) {
3504 mutex_unlock(&devlink->lock);
3505 goto out;
3506 }
3507 idx++;
3508 }
3509 mutex_unlock(&devlink->lock);
3510 }
3511out:
3512 mutex_unlock(&devlink_mutex);
3513 cb->args[0] = idx;
3514 return msg->len;
3515}
3516
866319bb
AV
3517static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3518 struct genl_info *info)
3519{
3520 struct devlink *devlink = info->user_ptr[0];
3521 struct devlink_snapshot *snapshot;
3522 struct devlink_region *region;
3523 const char *region_name;
3524 u32 snapshot_id;
3525
3526 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3527 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3528 return -EINVAL;
3529
3530 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3531 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3532
3533 region = devlink_region_get_by_name(devlink, region_name);
3534 if (!region)
3535 return -EINVAL;
3536
3537 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3538 if (!snapshot)
3539 return -EINVAL;
3540
3541 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3542 devlink_region_snapshot_del(snapshot);
3543 return 0;
3544}
3545
4e54795a
AV
3546static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3547 struct devlink *devlink,
3548 u8 *chunk, u32 chunk_size,
3549 u64 addr)
3550{
3551 struct nlattr *chunk_attr;
3552 int err;
3553
3554 chunk_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_CHUNK);
3555 if (!chunk_attr)
3556 return -EINVAL;
3557
3558 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3559 if (err)
3560 goto nla_put_failure;
3561
3562 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3563 DEVLINK_ATTR_PAD);
3564 if (err)
3565 goto nla_put_failure;
3566
3567 nla_nest_end(msg, chunk_attr);
3568 return 0;
3569
3570nla_put_failure:
3571 nla_nest_cancel(msg, chunk_attr);
3572 return err;
3573}
3574
3575#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3576
3577static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3578 struct devlink *devlink,
3579 struct devlink_region *region,
3580 struct nlattr **attrs,
3581 u64 start_offset,
3582 u64 end_offset,
3583 bool dump,
3584 u64 *new_offset)
3585{
3586 struct devlink_snapshot *snapshot;
3587 u64 curr_offset = start_offset;
3588 u32 snapshot_id;
3589 int err = 0;
3590
3591 *new_offset = start_offset;
3592
3593 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3594 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3595 if (!snapshot)
3596 return -EINVAL;
3597
3598 if (end_offset > snapshot->data_len || dump)
3599 end_offset = snapshot->data_len;
3600
3601 while (curr_offset < end_offset) {
3602 u32 data_size;
3603 u8 *data;
3604
3605 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3606 data_size = end_offset - curr_offset;
3607 else
3608 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3609
3610 data = &snapshot->data[curr_offset];
3611 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3612 data, data_size,
3613 curr_offset);
3614 if (err)
3615 break;
3616
3617 curr_offset += data_size;
3618 }
3619 *new_offset = curr_offset;
3620
3621 return err;
3622}
3623
3624static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3625 struct netlink_callback *cb)
3626{
3627 u64 ret_offset, start_offset, end_offset = 0;
3628 struct nlattr *attrs[DEVLINK_ATTR_MAX + 1];
3629 const struct genl_ops *ops = cb->data;
3630 struct devlink_region *region;
3631 struct nlattr *chunks_attr;
3632 const char *region_name;
3633 struct devlink *devlink;
3634 bool dump = true;
3635 void *hdr;
3636 int err;
3637
3638 start_offset = *((u64 *)&cb->args[0]);
3639
3640 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + devlink_nl_family.hdrsize,
dac9c979 3641 attrs, DEVLINK_ATTR_MAX, ops->policy, cb->extack);
4e54795a
AV
3642 if (err)
3643 goto out;
3644
3645 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
3646 if (IS_ERR(devlink))
3647 goto out;
3648
3649 mutex_lock(&devlink_mutex);
3650 mutex_lock(&devlink->lock);
3651
3652 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
3653 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3654 goto out_unlock;
3655
3656 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3657 region = devlink_region_get_by_name(devlink, region_name);
3658 if (!region)
3659 goto out_unlock;
3660
3661 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3662 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3663 DEVLINK_CMD_REGION_READ);
3664 if (!hdr)
3665 goto out_unlock;
3666
3667 err = devlink_nl_put_handle(skb, devlink);
3668 if (err)
3669 goto nla_put_failure;
3670
3671 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3672 if (err)
3673 goto nla_put_failure;
3674
3675 chunks_attr = nla_nest_start(skb, DEVLINK_ATTR_REGION_CHUNKS);
3676 if (!chunks_attr)
3677 goto nla_put_failure;
3678
3679 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3680 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3681 if (!start_offset)
3682 start_offset =
3683 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3684
3685 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3686 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3687 dump = false;
3688 }
3689
3690 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3691 region, attrs,
3692 start_offset,
3693 end_offset, dump,
3694 &ret_offset);
3695
3696 if (err && err != -EMSGSIZE)
3697 goto nla_put_failure;
3698
3699 /* Check if there was any progress done to prevent infinite loop */
3700 if (ret_offset == start_offset)
3701 goto nla_put_failure;
3702
3703 *((u64 *)&cb->args[0]) = ret_offset;
3704
3705 nla_nest_end(skb, chunks_attr);
3706 genlmsg_end(skb, hdr);
3707 mutex_unlock(&devlink->lock);
3708 mutex_unlock(&devlink_mutex);
3709
3710 return skb->len;
3711
3712nla_put_failure:
3713 genlmsg_cancel(skb, hdr);
3714out_unlock:
3715 mutex_unlock(&devlink->lock);
3716 mutex_unlock(&devlink_mutex);
3717out:
3718 return 0;
3719}
3720
f9cf2288
JK
3721struct devlink_info_req {
3722 struct sk_buff *msg;
3723};
3724
3725int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3726{
3727 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3728}
3729EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3730
3731int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3732{
3733 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3734}
3735EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3736
fc6fae7d
JK
3737static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3738 const char *version_name,
3739 const char *version_value)
3740{
3741 struct nlattr *nest;
3742 int err;
3743
3744 nest = nla_nest_start(req->msg, attr);
3745 if (!nest)
3746 return -EMSGSIZE;
3747
3748 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3749 version_name);
3750 if (err)
3751 goto nla_put_failure;
3752
3753 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3754 version_value);
3755 if (err)
3756 goto nla_put_failure;
3757
3758 nla_nest_end(req->msg, nest);
3759
3760 return 0;
3761
3762nla_put_failure:
3763 nla_nest_cancel(req->msg, nest);
3764 return err;
3765}
3766
3767int devlink_info_version_fixed_put(struct devlink_info_req *req,
3768 const char *version_name,
3769 const char *version_value)
3770{
3771 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3772 version_name, version_value);
3773}
3774EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3775
3776int devlink_info_version_stored_put(struct devlink_info_req *req,
3777 const char *version_name,
3778 const char *version_value)
3779{
3780 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3781 version_name, version_value);
3782}
3783EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3784
3785int devlink_info_version_running_put(struct devlink_info_req *req,
3786 const char *version_name,
3787 const char *version_value)
3788{
3789 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3790 version_name, version_value);
3791}
3792EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3793
f9cf2288
JK
3794static int
3795devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3796 enum devlink_command cmd, u32 portid,
3797 u32 seq, int flags, struct netlink_ext_ack *extack)
3798{
3799 struct devlink_info_req req;
3800 void *hdr;
3801 int err;
3802
3803 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3804 if (!hdr)
3805 return -EMSGSIZE;
3806
3807 err = -EMSGSIZE;
3808 if (devlink_nl_put_handle(msg, devlink))
3809 goto err_cancel_msg;
3810
3811 req.msg = msg;
3812 err = devlink->ops->info_get(devlink, &req, extack);
3813 if (err)
3814 goto err_cancel_msg;
3815
3816 genlmsg_end(msg, hdr);
3817 return 0;
3818
3819err_cancel_msg:
3820 genlmsg_cancel(msg, hdr);
3821 return err;
3822}
3823
3824static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
3825 struct genl_info *info)
3826{
3827 struct devlink *devlink = info->user_ptr[0];
3828 struct sk_buff *msg;
3829 int err;
3830
3831 if (!devlink->ops || !devlink->ops->info_get)
3832 return -EOPNOTSUPP;
3833
3834 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3835 if (!msg)
3836 return -ENOMEM;
3837
3838 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3839 info->snd_portid, info->snd_seq, 0,
3840 info->extack);
3841 if (err) {
3842 nlmsg_free(msg);
3843 return err;
3844 }
3845
3846 return genlmsg_reply(msg, info);
3847}
3848
3849static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
3850 struct netlink_callback *cb)
3851{
3852 struct devlink *devlink;
3853 int start = cb->args[0];
3854 int idx = 0;
3855 int err;
3856
3857 mutex_lock(&devlink_mutex);
3858 list_for_each_entry(devlink, &devlink_list, list) {
3859 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3860 continue;
3861 if (idx < start) {
3862 idx++;
3863 continue;
3864 }
3865
3866 mutex_lock(&devlink->lock);
3867 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3868 NETLINK_CB(cb->skb).portid,
3869 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3870 cb->extack);
3871 mutex_unlock(&devlink->lock);
3872 if (err)
3873 break;
3874 idx++;
3875 }
3876 mutex_unlock(&devlink_mutex);
3877
3878 cb->args[0] = idx;
3879 return msg->len;
3880}
3881
1db64e87
EBE
3882struct devlink_fmsg_item {
3883 struct list_head list;
3884 int attrtype;
3885 u8 nla_type;
3886 u16 len;
3887 int value[0];
3888};
3889
3890struct devlink_fmsg {
3891 struct list_head item_list;
3892};
3893
3894static struct devlink_fmsg *devlink_fmsg_alloc(void)
3895{
3896 struct devlink_fmsg *fmsg;
3897
3898 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
3899 if (!fmsg)
3900 return NULL;
3901
3902 INIT_LIST_HEAD(&fmsg->item_list);
3903
3904 return fmsg;
3905}
3906
3907static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
3908{
3909 struct devlink_fmsg_item *item, *tmp;
3910
3911 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
3912 list_del(&item->list);
3913 kfree(item);
3914 }
3915 kfree(fmsg);
3916}
3917
3918static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
3919 int attrtype)
3920{
3921 struct devlink_fmsg_item *item;
3922
3923 item = kzalloc(sizeof(*item), GFP_KERNEL);
3924 if (!item)
3925 return -ENOMEM;
3926
3927 item->attrtype = attrtype;
3928 list_add_tail(&item->list, &fmsg->item_list);
3929
3930 return 0;
3931}
3932
3933int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
3934{
3935 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
3936}
3937EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
3938
3939static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
3940{
3941 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
3942}
3943
3944int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
3945{
3946 return devlink_fmsg_nest_end(fmsg);
3947}
3948EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
3949
3950#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
3951
3952static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
3953{
3954 struct devlink_fmsg_item *item;
3955
3956 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
3957 return -EMSGSIZE;
3958
3959 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
3960 if (!item)
3961 return -ENOMEM;
3962
3963 item->nla_type = NLA_NUL_STRING;
3964 item->len = strlen(name) + 1;
3965 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
3966 memcpy(&item->value, name, item->len);
3967 list_add_tail(&item->list, &fmsg->item_list);
3968
3969 return 0;
3970}
3971
3972int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
3973{
3974 int err;
3975
3976 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
3977 if (err)
3978 return err;
3979
3980 err = devlink_fmsg_put_name(fmsg, name);
3981 if (err)
3982 return err;
3983
3984 return 0;
3985}
3986EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
3987
3988int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
3989{
3990 return devlink_fmsg_nest_end(fmsg);
3991}
3992EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
3993
3994int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
3995 const char *name)
3996{
3997 int err;
3998
3999 err = devlink_fmsg_pair_nest_start(fmsg, name);
4000 if (err)
4001 return err;
4002
4003 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4004 if (err)
4005 return err;
4006
4007 return 0;
4008}
4009EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4010
4011int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4012{
4013 int err;
4014
4015 err = devlink_fmsg_nest_end(fmsg);
4016 if (err)
4017 return err;
4018
4019 err = devlink_fmsg_nest_end(fmsg);
4020 if (err)
4021 return err;
4022
4023 return 0;
4024}
4025EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4026
4027static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4028 const void *value, u16 value_len,
4029 u8 value_nla_type)
4030{
4031 struct devlink_fmsg_item *item;
4032
4033 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4034 return -EMSGSIZE;
4035
4036 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4037 if (!item)
4038 return -ENOMEM;
4039
4040 item->nla_type = value_nla_type;
4041 item->len = value_len;
4042 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4043 memcpy(&item->value, value, item->len);
4044 list_add_tail(&item->list, &fmsg->item_list);
4045
4046 return 0;
4047}
4048
4049int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4050{
4051 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4052}
4053EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4054
4055int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4056{
4057 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4058}
4059EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4060
4061int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4062{
4063 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4064}
4065EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4066
4067int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4068{
4069 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4070}
4071EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4072
4073int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4074{
4075 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4076 NLA_NUL_STRING);
4077}
4078EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4079
4080int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4081 u16 value_len)
4082{
4083 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4084}
4085EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4086
4087int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4088 bool value)
4089{
4090 int err;
4091
4092 err = devlink_fmsg_pair_nest_start(fmsg, name);
4093 if (err)
4094 return err;
4095
4096 err = devlink_fmsg_bool_put(fmsg, value);
4097 if (err)
4098 return err;
4099
4100 err = devlink_fmsg_pair_nest_end(fmsg);
4101 if (err)
4102 return err;
4103
4104 return 0;
4105}
4106EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4107
4108int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4109 u8 value)
4110{
4111 int err;
4112
4113 err = devlink_fmsg_pair_nest_start(fmsg, name);
4114 if (err)
4115 return err;
4116
4117 err = devlink_fmsg_u8_put(fmsg, value);
4118 if (err)
4119 return err;
4120
4121 err = devlink_fmsg_pair_nest_end(fmsg);
4122 if (err)
4123 return err;
4124
4125 return 0;
4126}
4127EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4128
4129int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4130 u32 value)
4131{
4132 int err;
4133
4134 err = devlink_fmsg_pair_nest_start(fmsg, name);
4135 if (err)
4136 return err;
4137
4138 err = devlink_fmsg_u32_put(fmsg, value);
4139 if (err)
4140 return err;
4141
4142 err = devlink_fmsg_pair_nest_end(fmsg);
4143 if (err)
4144 return err;
4145
4146 return 0;
4147}
4148EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4149
4150int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4151 u64 value)
4152{
4153 int err;
4154
4155 err = devlink_fmsg_pair_nest_start(fmsg, name);
4156 if (err)
4157 return err;
4158
4159 err = devlink_fmsg_u64_put(fmsg, value);
4160 if (err)
4161 return err;
4162
4163 err = devlink_fmsg_pair_nest_end(fmsg);
4164 if (err)
4165 return err;
4166
4167 return 0;
4168}
4169EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4170
4171int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4172 const char *value)
4173{
4174 int err;
4175
4176 err = devlink_fmsg_pair_nest_start(fmsg, name);
4177 if (err)
4178 return err;
4179
4180 err = devlink_fmsg_string_put(fmsg, value);
4181 if (err)
4182 return err;
4183
4184 err = devlink_fmsg_pair_nest_end(fmsg);
4185 if (err)
4186 return err;
4187
4188 return 0;
4189}
4190EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4191
4192int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4193 const void *value, u16 value_len)
4194{
4195 int err;
4196
4197 err = devlink_fmsg_pair_nest_start(fmsg, name);
4198 if (err)
4199 return err;
4200
4201 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4202 if (err)
4203 return err;
4204
4205 err = devlink_fmsg_pair_nest_end(fmsg);
4206 if (err)
4207 return err;
4208
4209 return 0;
4210}
4211EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4212
4213static int
4214devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4215{
4216 switch (msg->nla_type) {
4217 case NLA_FLAG:
4218 case NLA_U8:
4219 case NLA_U32:
4220 case NLA_U64:
4221 case NLA_NUL_STRING:
4222 case NLA_BINARY:
4223 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4224 msg->nla_type);
4225 default:
4226 return -EINVAL;
4227 }
4228}
4229
4230static int
4231devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4232{
4233 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4234 u8 tmp;
4235
4236 switch (msg->nla_type) {
4237 case NLA_FLAG:
4238 /* Always provide flag data, regardless of its value */
4239 tmp = *(bool *) msg->value;
4240
4241 return nla_put_u8(skb, attrtype, tmp);
4242 case NLA_U8:
4243 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4244 case NLA_U32:
4245 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4246 case NLA_U64:
4247 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4248 DEVLINK_ATTR_PAD);
4249 case NLA_NUL_STRING:
4250 return nla_put_string(skb, attrtype, (char *) &msg->value);
4251 case NLA_BINARY:
4252 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4253 default:
4254 return -EINVAL;
4255 }
4256}
4257
4258static int
4259devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4260 int *start)
4261{
4262 struct devlink_fmsg_item *item;
4263 struct nlattr *fmsg_nlattr;
4264 int i = 0;
4265 int err;
4266
4267 fmsg_nlattr = nla_nest_start(skb, DEVLINK_ATTR_FMSG);
4268 if (!fmsg_nlattr)
4269 return -EMSGSIZE;
4270
4271 list_for_each_entry(item, &fmsg->item_list, list) {
4272 if (i < *start) {
4273 i++;
4274 continue;
4275 }
4276
4277 switch (item->attrtype) {
4278 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4279 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4280 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4281 case DEVLINK_ATTR_FMSG_NEST_END:
4282 err = nla_put_flag(skb, item->attrtype);
4283 break;
4284 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4285 err = devlink_fmsg_item_fill_type(item, skb);
4286 if (err)
4287 break;
4288 err = devlink_fmsg_item_fill_data(item, skb);
4289 break;
4290 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4291 err = nla_put_string(skb, item->attrtype,
4292 (char *) &item->value);
4293 break;
4294 default:
4295 err = -EINVAL;
4296 break;
4297 }
4298 if (!err)
4299 *start = ++i;
4300 else
4301 break;
4302 }
4303
4304 nla_nest_end(skb, fmsg_nlattr);
4305 return err;
4306}
4307
4308static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4309 struct genl_info *info,
4310 enum devlink_command cmd, int flags)
4311{
4312 struct nlmsghdr *nlh;
4313 struct sk_buff *skb;
4314 bool last = false;
4315 int index = 0;
4316 void *hdr;
4317 int err;
4318
4319 while (!last) {
4320 int tmp_index = index;
4321
4322 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4323 if (!skb)
4324 return -ENOMEM;
4325
4326 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4327 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4328 if (!hdr) {
4329 err = -EMSGSIZE;
4330 goto nla_put_failure;
4331 }
4332
4333 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4334 if (!err)
4335 last = true;
4336 else if (err != -EMSGSIZE || tmp_index == index)
4337 goto nla_put_failure;
4338
4339 genlmsg_end(skb, hdr);
4340 err = genlmsg_reply(skb, info);
4341 if (err)
4342 return err;
4343 }
4344
4345 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4346 if (!skb)
4347 return -ENOMEM;
4348 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4349 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4350 if (!nlh) {
4351 err = -EMSGSIZE;
4352 goto nla_put_failure;
4353 }
4354 err = genlmsg_reply(skb, info);
4355 if (err)
4356 return err;
4357
4358 return 0;
4359
4360nla_put_failure:
4361 nlmsg_free(skb);
4362 return err;
4363}
4364
a0bdcc59
EBE
4365struct devlink_health_reporter {
4366 struct list_head list;
4367 void *priv;
4368 const struct devlink_health_reporter_ops *ops;
4369 struct devlink *devlink;
c8e1da0b
EBE
4370 struct devlink_fmsg *dump_fmsg;
4371 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
a0bdcc59
EBE
4372 u64 graceful_period;
4373 bool auto_recover;
4374 u8 health_state;
c8e1da0b
EBE
4375 u64 dump_ts;
4376 u64 error_count;
4377 u64 recovery_count;
4378 u64 last_recovery_ts;
4379};
4380
4381enum devlink_health_reporter_state {
4382 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
4383 DEVLINK_HEALTH_REPORTER_STATE_ERROR,
a0bdcc59
EBE
4384};
4385
4386void *
4387devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4388{
4389 return reporter->priv;
4390}
4391EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4392
4393static struct devlink_health_reporter *
4394devlink_health_reporter_find_by_name(struct devlink *devlink,
4395 const char *reporter_name)
4396{
4397 struct devlink_health_reporter *reporter;
4398
4399 list_for_each_entry(reporter, &devlink->reporter_list, list)
4400 if (!strcmp(reporter->ops->name, reporter_name))
4401 return reporter;
4402 return NULL;
4403}
4404
4405/**
4406 * devlink_health_reporter_create - create devlink health reporter
4407 *
4408 * @devlink: devlink
4409 * @ops: ops
4410 * @graceful_period: to avoid recovery loops, in msecs
4411 * @auto_recover: auto recover when error occurs
4412 * @priv: priv
4413 */
4414struct devlink_health_reporter *
4415devlink_health_reporter_create(struct devlink *devlink,
4416 const struct devlink_health_reporter_ops *ops,
4417 u64 graceful_period, bool auto_recover,
4418 void *priv)
4419{
4420 struct devlink_health_reporter *reporter;
4421
4422 mutex_lock(&devlink->lock);
4423 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4424 reporter = ERR_PTR(-EEXIST);
4425 goto unlock;
4426 }
4427
4428 if (WARN_ON(auto_recover && !ops->recover) ||
4429 WARN_ON(graceful_period && !ops->recover)) {
4430 reporter = ERR_PTR(-EINVAL);
4431 goto unlock;
4432 }
4433
4434 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4435 if (!reporter) {
4436 reporter = ERR_PTR(-ENOMEM);
4437 goto unlock;
4438 }
4439
4440 reporter->priv = priv;
4441 reporter->ops = ops;
4442 reporter->devlink = devlink;
4443 reporter->graceful_period = graceful_period;
4444 reporter->auto_recover = auto_recover;
c8e1da0b 4445 mutex_init(&reporter->dump_lock);
a0bdcc59
EBE
4446 list_add_tail(&reporter->list, &devlink->reporter_list);
4447unlock:
4448 mutex_unlock(&devlink->lock);
4449 return reporter;
4450}
4451EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4452
4453/**
4454 * devlink_health_reporter_destroy - destroy devlink health reporter
4455 *
4456 * @reporter: devlink health reporter to destroy
4457 */
4458void
4459devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4460{
4461 mutex_lock(&reporter->devlink->lock);
4462 list_del(&reporter->list);
4463 mutex_unlock(&reporter->devlink->lock);
c8e1da0b
EBE
4464 if (reporter->dump_fmsg)
4465 devlink_fmsg_free(reporter->dump_fmsg);
a0bdcc59
EBE
4466 kfree(reporter);
4467}
4468EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4469
c8e1da0b
EBE
4470static int
4471devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4472 void *priv_ctx)
4473{
4474 int err;
4475
4476 if (!reporter->ops->recover)
4477 return -EOPNOTSUPP;
4478
4479 err = reporter->ops->recover(reporter, priv_ctx);
4480 if (err)
4481 return err;
4482
4483 reporter->recovery_count++;
4484 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4485 reporter->last_recovery_ts = jiffies;
4486
4487 return 0;
4488}
4489
4490static void
4491devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4492{
4493 if (!reporter->dump_fmsg)
4494 return;
4495 devlink_fmsg_free(reporter->dump_fmsg);
4496 reporter->dump_fmsg = NULL;
4497}
4498
4499static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4500 void *priv_ctx)
4501{
4502 int err;
4503
4504 if (!reporter->ops->dump)
4505 return 0;
4506
4507 if (reporter->dump_fmsg)
4508 return 0;
4509
4510 reporter->dump_fmsg = devlink_fmsg_alloc();
4511 if (!reporter->dump_fmsg) {
4512 err = -ENOMEM;
4513 return err;
4514 }
4515
4516 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4517 if (err)
4518 goto dump_err;
4519
4520 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4521 priv_ctx);
4522 if (err)
4523 goto dump_err;
4524
4525 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4526 if (err)
4527 goto dump_err;
4528
4529 reporter->dump_ts = jiffies;
4530
4531 return 0;
4532
4533dump_err:
4534 devlink_health_dump_clear(reporter);
4535 return err;
4536}
4537
4538int devlink_health_report(struct devlink_health_reporter *reporter,
4539 const char *msg, void *priv_ctx)
4540{
4541 struct devlink *devlink = reporter->devlink;
4542
4543 /* write a log message of the current error */
4544 WARN_ON(!msg);
4545 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4546 reporter->error_count++;
4547
4548 /* abort if the previous error wasn't recovered */
4549 if (reporter->auto_recover &&
4550 (reporter->health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
4551 jiffies - reporter->last_recovery_ts <
4552 msecs_to_jiffies(reporter->graceful_period))) {
4553 trace_devlink_health_recover_aborted(devlink,
4554 reporter->ops->name,
4555 reporter->health_state,
4556 jiffies -
4557 reporter->last_recovery_ts);
4558 return -ECANCELED;
4559 }
4560
4561 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4562
4563 mutex_lock(&reporter->dump_lock);
4564 /* store current dump of current error, for later analysis */
4565 devlink_health_do_dump(reporter, priv_ctx);
4566 mutex_unlock(&reporter->dump_lock);
4567
4568 if (reporter->auto_recover)
4569 return devlink_health_reporter_recover(reporter, priv_ctx);
4570
4571 return 0;
4572}
4573EXPORT_SYMBOL_GPL(devlink_health_report);
4574
7afe335a
EBE
4575static struct devlink_health_reporter *
4576devlink_health_reporter_get_from_info(struct devlink *devlink,
4577 struct genl_info *info)
4578{
4579 char *reporter_name;
4580
4581 if (!info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
4582 return NULL;
4583
4584 reporter_name =
4585 nla_data(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
4586 return devlink_health_reporter_find_by_name(devlink, reporter_name);
4587}
4588
4589static int
4590devlink_nl_health_reporter_fill(struct sk_buff *msg,
4591 struct devlink *devlink,
4592 struct devlink_health_reporter *reporter,
4593 enum devlink_command cmd, u32 portid,
4594 u32 seq, int flags)
4595{
4596 struct nlattr *reporter_attr;
4597 void *hdr;
4598
4599 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4600 if (!hdr)
4601 return -EMSGSIZE;
4602
4603 if (devlink_nl_put_handle(msg, devlink))
4604 goto genlmsg_cancel;
4605
4606 reporter_attr = nla_nest_start(msg, DEVLINK_ATTR_HEALTH_REPORTER);
4607 if (!reporter_attr)
4608 goto genlmsg_cancel;
4609 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4610 reporter->ops->name))
4611 goto reporter_nest_cancel;
4612 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4613 reporter->health_state))
4614 goto reporter_nest_cancel;
4615 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR,
4616 reporter->error_count, DEVLINK_ATTR_PAD))
4617 goto reporter_nest_cancel;
4618 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER,
4619 reporter->recovery_count, DEVLINK_ATTR_PAD))
4620 goto reporter_nest_cancel;
4621 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
4622 reporter->graceful_period,
4623 DEVLINK_ATTR_PAD))
4624 goto reporter_nest_cancel;
4625 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
4626 reporter->auto_recover))
4627 goto reporter_nest_cancel;
4628 if (reporter->dump_fmsg &&
4629 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4630 jiffies_to_msecs(reporter->dump_ts),
4631 DEVLINK_ATTR_PAD))
4632 goto reporter_nest_cancel;
4633
4634 nla_nest_end(msg, reporter_attr);
4635 genlmsg_end(msg, hdr);
4636 return 0;
4637
4638reporter_nest_cancel:
4639 nla_nest_end(msg, reporter_attr);
4640genlmsg_cancel:
4641 genlmsg_cancel(msg, hdr);
4642 return -EMSGSIZE;
4643}
4644
4645static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4646 struct genl_info *info)
4647{
4648 struct devlink *devlink = info->user_ptr[0];
4649 struct devlink_health_reporter *reporter;
4650 struct sk_buff *msg;
4651 int err;
4652
4653 reporter = devlink_health_reporter_get_from_info(devlink, info);
4654 if (!reporter)
4655 return -EINVAL;
4656
4657 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4658 if (!msg)
4659 return -ENOMEM;
4660
4661 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4662 DEVLINK_CMD_HEALTH_REPORTER_GET,
4663 info->snd_portid, info->snd_seq,
4664 0);
4665 if (err) {
4666 nlmsg_free(msg);
4667 return err;
4668 }
4669
4670 return genlmsg_reply(msg, info);
4671}
4672
4673static int
4674devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4675 struct netlink_callback *cb)
4676{
4677 struct devlink_health_reporter *reporter;
4678 struct devlink *devlink;
4679 int start = cb->args[0];
4680 int idx = 0;
4681 int err;
4682
4683 mutex_lock(&devlink_mutex);
4684 list_for_each_entry(devlink, &devlink_list, list) {
4685 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4686 continue;
4687 mutex_lock(&devlink->lock);
4688 list_for_each_entry(reporter, &devlink->reporter_list,
4689 list) {
4690 if (idx < start) {
4691 idx++;
4692 continue;
4693 }
4694 err = devlink_nl_health_reporter_fill(msg, devlink,
4695 reporter,
4696 DEVLINK_CMD_HEALTH_REPORTER_GET,
4697 NETLINK_CB(cb->skb).portid,
4698 cb->nlh->nlmsg_seq,
4699 NLM_F_MULTI);
4700 if (err) {
4701 mutex_unlock(&devlink->lock);
4702 goto out;
4703 }
4704 idx++;
4705 }
4706 mutex_unlock(&devlink->lock);
4707 }
4708out:
4709 mutex_unlock(&devlink_mutex);
4710
4711 cb->args[0] = idx;
4712 return msg->len;
4713}
4714
bfcd3a46
JP
4715static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
4716 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
4717 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
4718 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
4719 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
4720 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
bf797471
JP
4721 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
4722 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
4723 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
4724 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
4725 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
4726 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
4727 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
08f4b591 4728 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
59bfde01 4729 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
f43e9b06 4730 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
1555d204
AS
4731 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
4732 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
d9f9b9a4
AS
4733 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
4734 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
e3b7ca18
MS
4735 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
4736 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
4737 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
d8db7ea5 4738 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
866319bb 4739 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
7afe335a 4740 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
bfcd3a46
JP
4741};
4742
4743static const struct genl_ops devlink_nl_ops[] = {
4744 {
4745 .cmd = DEVLINK_CMD_GET,
4746 .doit = devlink_nl_cmd_get_doit,
4747 .dumpit = devlink_nl_cmd_get_dumpit,
4748 .policy = devlink_nl_policy,
1fc2257e 4749 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
bfcd3a46
JP
4750 /* can be retrieved by unprivileged users */
4751 },
4752 {
4753 .cmd = DEVLINK_CMD_PORT_GET,
4754 .doit = devlink_nl_cmd_port_get_doit,
4755 .dumpit = devlink_nl_cmd_port_get_dumpit,
4756 .policy = devlink_nl_policy,
4757 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4758 /* can be retrieved by unprivileged users */
4759 },
4760 {
4761 .cmd = DEVLINK_CMD_PORT_SET,
4762 .doit = devlink_nl_cmd_port_set_doit,
4763 .policy = devlink_nl_policy,
4764 .flags = GENL_ADMIN_PERM,
4765 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4766 },
4767 {
4768 .cmd = DEVLINK_CMD_PORT_SPLIT,
4769 .doit = devlink_nl_cmd_port_split_doit,
4770 .policy = devlink_nl_policy,
4771 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
4772 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4773 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46
JP
4774 },
4775 {
4776 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
4777 .doit = devlink_nl_cmd_port_unsplit_doit,
4778 .policy = devlink_nl_policy,
4779 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
4780 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4781 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46 4782 },
bf797471
JP
4783 {
4784 .cmd = DEVLINK_CMD_SB_GET,
4785 .doit = devlink_nl_cmd_sb_get_doit,
4786 .dumpit = devlink_nl_cmd_sb_get_dumpit,
4787 .policy = devlink_nl_policy,
4788 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4789 DEVLINK_NL_FLAG_NEED_SB,
4790 /* can be retrieved by unprivileged users */
4791 },
4792 {
4793 .cmd = DEVLINK_CMD_SB_POOL_GET,
4794 .doit = devlink_nl_cmd_sb_pool_get_doit,
4795 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
4796 .policy = devlink_nl_policy,
4797 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4798 DEVLINK_NL_FLAG_NEED_SB,
4799 /* can be retrieved by unprivileged users */
4800 },
4801 {
4802 .cmd = DEVLINK_CMD_SB_POOL_SET,
4803 .doit = devlink_nl_cmd_sb_pool_set_doit,
4804 .policy = devlink_nl_policy,
4805 .flags = GENL_ADMIN_PERM,
4806 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4807 DEVLINK_NL_FLAG_NEED_SB,
4808 },
4809 {
4810 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
4811 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
4812 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
4813 .policy = devlink_nl_policy,
4814 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4815 DEVLINK_NL_FLAG_NEED_SB,
4816 /* can be retrieved by unprivileged users */
4817 },
4818 {
4819 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
4820 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
4821 .policy = devlink_nl_policy,
4822 .flags = GENL_ADMIN_PERM,
4823 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4824 DEVLINK_NL_FLAG_NEED_SB,
4825 },
4826 {
4827 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
4828 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
4829 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
4830 .policy = devlink_nl_policy,
4831 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4832 DEVLINK_NL_FLAG_NEED_SB,
4833 /* can be retrieved by unprivileged users */
4834 },
4835 {
4836 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
4837 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
4838 .policy = devlink_nl_policy,
4839 .flags = GENL_ADMIN_PERM,
4840 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4841 DEVLINK_NL_FLAG_NEED_SB,
4842 },
df38dafd
JP
4843 {
4844 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
4845 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
4846 .policy = devlink_nl_policy,
4847 .flags = GENL_ADMIN_PERM,
4848 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 4849 DEVLINK_NL_FLAG_NEED_SB,
df38dafd
JP
4850 },
4851 {
4852 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
4853 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
4854 .policy = devlink_nl_policy,
4855 .flags = GENL_ADMIN_PERM,
4856 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 4857 DEVLINK_NL_FLAG_NEED_SB,
df38dafd 4858 },
08f4b591 4859 {
adf200f3
JP
4860 .cmd = DEVLINK_CMD_ESWITCH_GET,
4861 .doit = devlink_nl_cmd_eswitch_get_doit,
08f4b591
OG
4862 .policy = devlink_nl_policy,
4863 .flags = GENL_ADMIN_PERM,
4864 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4865 },
4866 {
adf200f3
JP
4867 .cmd = DEVLINK_CMD_ESWITCH_SET,
4868 .doit = devlink_nl_cmd_eswitch_set_doit,
08f4b591
OG
4869 .policy = devlink_nl_policy,
4870 .flags = GENL_ADMIN_PERM,
7ac1cc9a
JK
4871 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4872 DEVLINK_NL_FLAG_NO_LOCK,
08f4b591 4873 },
1555d204
AS
4874 {
4875 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
4876 .doit = devlink_nl_cmd_dpipe_table_get,
4877 .policy = devlink_nl_policy,
1555d204 4878 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 4879 /* can be retrieved by unprivileged users */
1555d204
AS
4880 },
4881 {
4882 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
4883 .doit = devlink_nl_cmd_dpipe_entries_get,
4884 .policy = devlink_nl_policy,
1555d204 4885 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 4886 /* can be retrieved by unprivileged users */
1555d204
AS
4887 },
4888 {
4889 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
4890 .doit = devlink_nl_cmd_dpipe_headers_get,
4891 .policy = devlink_nl_policy,
1555d204 4892 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 4893 /* can be retrieved by unprivileged users */
1555d204
AS
4894 },
4895 {
4896 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
4897 .doit = devlink_nl_cmd_dpipe_table_counters_set,
4898 .policy = devlink_nl_policy,
4899 .flags = GENL_ADMIN_PERM,
4900 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4901 },
d9f9b9a4
AS
4902 {
4903 .cmd = DEVLINK_CMD_RESOURCE_SET,
4904 .doit = devlink_nl_cmd_resource_set,
4905 .policy = devlink_nl_policy,
4906 .flags = GENL_ADMIN_PERM,
4907 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4908 },
4909 {
4910 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
4911 .doit = devlink_nl_cmd_resource_dump,
4912 .policy = devlink_nl_policy,
d9f9b9a4 4913 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 4914 /* can be retrieved by unprivileged users */
d9f9b9a4 4915 },
2d8dc5bb
AS
4916 {
4917 .cmd = DEVLINK_CMD_RELOAD,
4918 .doit = devlink_nl_cmd_reload,
4919 .policy = devlink_nl_policy,
4920 .flags = GENL_ADMIN_PERM,
4921 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4922 DEVLINK_NL_FLAG_NO_LOCK,
4923 },
45f05def
MS
4924 {
4925 .cmd = DEVLINK_CMD_PARAM_GET,
4926 .doit = devlink_nl_cmd_param_get_doit,
4927 .dumpit = devlink_nl_cmd_param_get_dumpit,
4928 .policy = devlink_nl_policy,
4929 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4930 /* can be retrieved by unprivileged users */
4931 },
e3b7ca18
MS
4932 {
4933 .cmd = DEVLINK_CMD_PARAM_SET,
4934 .doit = devlink_nl_cmd_param_set_doit,
4935 .policy = devlink_nl_policy,
4936 .flags = GENL_ADMIN_PERM,
4937 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4938 },
f4601dee
VV
4939 {
4940 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
4941 .doit = devlink_nl_cmd_port_param_get_doit,
4942 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
4943 .policy = devlink_nl_policy,
4944 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4945 /* can be retrieved by unprivileged users */
4946 },
9c54873b
VV
4947 {
4948 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
4949 .doit = devlink_nl_cmd_port_param_set_doit,
4950 .policy = devlink_nl_policy,
4951 .flags = GENL_ADMIN_PERM,
4952 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4953 },
d8db7ea5
AV
4954 {
4955 .cmd = DEVLINK_CMD_REGION_GET,
4956 .doit = devlink_nl_cmd_region_get_doit,
4957 .dumpit = devlink_nl_cmd_region_get_dumpit,
4958 .policy = devlink_nl_policy,
4959 .flags = GENL_ADMIN_PERM,
4960 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4961 },
866319bb
AV
4962 {
4963 .cmd = DEVLINK_CMD_REGION_DEL,
4964 .doit = devlink_nl_cmd_region_del,
4965 .policy = devlink_nl_policy,
4966 .flags = GENL_ADMIN_PERM,
4967 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4968 },
4e54795a
AV
4969 {
4970 .cmd = DEVLINK_CMD_REGION_READ,
4971 .dumpit = devlink_nl_cmd_region_read_dumpit,
4972 .policy = devlink_nl_policy,
4973 .flags = GENL_ADMIN_PERM,
4974 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4975 },
f9cf2288
JK
4976 {
4977 .cmd = DEVLINK_CMD_INFO_GET,
4978 .doit = devlink_nl_cmd_info_get_doit,
4979 .dumpit = devlink_nl_cmd_info_get_dumpit,
4980 .policy = devlink_nl_policy,
4981 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4982 /* can be retrieved by unprivileged users */
4983 },
7afe335a
EBE
4984 {
4985 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
4986 .doit = devlink_nl_cmd_health_reporter_get_doit,
4987 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
4988 .policy = devlink_nl_policy,
4989 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4990 /* can be retrieved by unprivileged users */
4991 },
bfcd3a46
JP
4992};
4993
56989f6d 4994static struct genl_family devlink_nl_family __ro_after_init = {
489111e5
JB
4995 .name = DEVLINK_GENL_NAME,
4996 .version = DEVLINK_GENL_VERSION,
4997 .maxattr = DEVLINK_ATTR_MAX,
4998 .netnsok = true,
4999 .pre_doit = devlink_nl_pre_doit,
5000 .post_doit = devlink_nl_post_doit,
5001 .module = THIS_MODULE,
5002 .ops = devlink_nl_ops,
5003 .n_ops = ARRAY_SIZE(devlink_nl_ops),
5004 .mcgrps = devlink_nl_mcgrps,
5005 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
5006};
5007
bfcd3a46
JP
5008/**
5009 * devlink_alloc - Allocate new devlink instance resources
5010 *
5011 * @ops: ops
5012 * @priv_size: size of user private data
5013 *
5014 * Allocate new devlink instance resources, including devlink index
5015 * and name.
5016 */
5017struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
5018{
5019 struct devlink *devlink;
5020
5021 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
5022 if (!devlink)
5023 return NULL;
5024 devlink->ops = ops;
5025 devlink_net_set(devlink, &init_net);
5026 INIT_LIST_HEAD(&devlink->port_list);
bf797471 5027 INIT_LIST_HEAD(&devlink->sb_list);
1555d204 5028 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
d9f9b9a4 5029 INIT_LIST_HEAD(&devlink->resource_list);
eabaef18 5030 INIT_LIST_HEAD(&devlink->param_list);
b16ebe92 5031 INIT_LIST_HEAD(&devlink->region_list);
a0bdcc59 5032 INIT_LIST_HEAD(&devlink->reporter_list);
2406e7e5 5033 mutex_init(&devlink->lock);
bfcd3a46
JP
5034 return devlink;
5035}
5036EXPORT_SYMBOL_GPL(devlink_alloc);
5037
5038/**
5039 * devlink_register - Register devlink instance
5040 *
5041 * @devlink: devlink
5042 */
5043int devlink_register(struct devlink *devlink, struct device *dev)
5044{
5045 mutex_lock(&devlink_mutex);
5046 devlink->dev = dev;
5047 list_add_tail(&devlink->list, &devlink_list);
5048 devlink_notify(devlink, DEVLINK_CMD_NEW);
5049 mutex_unlock(&devlink_mutex);
5050 return 0;
5051}
5052EXPORT_SYMBOL_GPL(devlink_register);
5053
5054/**
5055 * devlink_unregister - Unregister devlink instance
5056 *
5057 * @devlink: devlink
5058 */
5059void devlink_unregister(struct devlink *devlink)
5060{
5061 mutex_lock(&devlink_mutex);
5062 devlink_notify(devlink, DEVLINK_CMD_DEL);
5063 list_del(&devlink->list);
5064 mutex_unlock(&devlink_mutex);
5065}
5066EXPORT_SYMBOL_GPL(devlink_unregister);
5067
5068/**
5069 * devlink_free - Free devlink instance resources
5070 *
5071 * @devlink: devlink
5072 */
5073void devlink_free(struct devlink *devlink)
5074{
5075 kfree(devlink);
5076}
5077EXPORT_SYMBOL_GPL(devlink_free);
5078
5079/**
5080 * devlink_port_register - Register devlink port
5081 *
5082 * @devlink: devlink
5083 * @devlink_port: devlink port
5084 * @port_index
5085 *
5086 * Register devlink port with provided port index. User can use
5087 * any indexing, even hw-related one. devlink_port structure
5088 * is convenient to be embedded inside user driver private structure.
5089 * Note that the caller should take care of zeroing the devlink_port
5090 * structure.
5091 */
5092int devlink_port_register(struct devlink *devlink,
5093 struct devlink_port *devlink_port,
5094 unsigned int port_index)
5095{
2406e7e5 5096 mutex_lock(&devlink->lock);
bfcd3a46 5097 if (devlink_port_index_exists(devlink, port_index)) {
2406e7e5 5098 mutex_unlock(&devlink->lock);
bfcd3a46
JP
5099 return -EEXIST;
5100 }
5101 devlink_port->devlink = devlink;
5102 devlink_port->index = port_index;
bfcd3a46
JP
5103 devlink_port->registered = true;
5104 list_add_tail(&devlink_port->list, &devlink->port_list);
39e6160e 5105 INIT_LIST_HEAD(&devlink_port->param_list);
2406e7e5 5106 mutex_unlock(&devlink->lock);
bfcd3a46
JP
5107 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5108 return 0;
5109}
5110EXPORT_SYMBOL_GPL(devlink_port_register);
5111
5112/**
5113 * devlink_port_unregister - Unregister devlink port
5114 *
5115 * @devlink_port: devlink port
5116 */
5117void devlink_port_unregister(struct devlink_port *devlink_port)
5118{
2406e7e5
AS
5119 struct devlink *devlink = devlink_port->devlink;
5120
bfcd3a46 5121 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
2406e7e5 5122 mutex_lock(&devlink->lock);
bfcd3a46 5123 list_del(&devlink_port->list);
2406e7e5 5124 mutex_unlock(&devlink->lock);
bfcd3a46
JP
5125}
5126EXPORT_SYMBOL_GPL(devlink_port_unregister);
5127
5128static void __devlink_port_type_set(struct devlink_port *devlink_port,
5129 enum devlink_port_type type,
5130 void *type_dev)
5131{
5132 devlink_port->type = type;
5133 devlink_port->type_dev = type_dev;
5134 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5135}
5136
5137/**
5138 * devlink_port_type_eth_set - Set port type to Ethernet
5139 *
5140 * @devlink_port: devlink port
5141 * @netdev: related netdevice
5142 */
5143void devlink_port_type_eth_set(struct devlink_port *devlink_port,
5144 struct net_device *netdev)
5145{
5146 return __devlink_port_type_set(devlink_port,
5147 DEVLINK_PORT_TYPE_ETH, netdev);
5148}
5149EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
5150
5151/**
5152 * devlink_port_type_ib_set - Set port type to InfiniBand
5153 *
5154 * @devlink_port: devlink port
5155 * @ibdev: related IB device
5156 */
5157void devlink_port_type_ib_set(struct devlink_port *devlink_port,
5158 struct ib_device *ibdev)
5159{
5160 return __devlink_port_type_set(devlink_port,
5161 DEVLINK_PORT_TYPE_IB, ibdev);
5162}
5163EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
5164
5165/**
5166 * devlink_port_type_clear - Clear port type
5167 *
5168 * @devlink_port: devlink port
5169 */
5170void devlink_port_type_clear(struct devlink_port *devlink_port)
5171{
5172 return __devlink_port_type_set(devlink_port,
5173 DEVLINK_PORT_TYPE_NOTSET, NULL);
5174}
5175EXPORT_SYMBOL_GPL(devlink_port_type_clear);
5176
5177/**
b9ffcbaf 5178 * devlink_port_attrs_set - Set port attributes
bfcd3a46
JP
5179 *
5180 * @devlink_port: devlink port
5ec1380a 5181 * @flavour: flavour of the port
b9ffcbaf
JP
5182 * @port_number: number of the port that is facing user, for example
5183 * the front panel port number
5184 * @split: indicates if this is split port
5185 * @split_subport_number: if the port is split, this is the number
5186 * of subport.
bfcd3a46 5187 */
b9ffcbaf 5188void devlink_port_attrs_set(struct devlink_port *devlink_port,
5ec1380a 5189 enum devlink_port_flavour flavour,
b9ffcbaf
JP
5190 u32 port_number, bool split,
5191 u32 split_subport_number)
bfcd3a46 5192{
b9ffcbaf
JP
5193 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5194
5195 attrs->set = true;
5ec1380a 5196 attrs->flavour = flavour;
b9ffcbaf
JP
5197 attrs->port_number = port_number;
5198 attrs->split = split;
5199 attrs->split_subport_number = split_subport_number;
bfcd3a46
JP
5200 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5201}
b9ffcbaf 5202EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
bfcd3a46 5203
08474c1a
JP
5204int devlink_port_get_phys_port_name(struct devlink_port *devlink_port,
5205 char *name, size_t len)
5206{
5207 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5208 int n = 0;
5209
5210 if (!attrs->set)
5211 return -EOPNOTSUPP;
5212
5213 switch (attrs->flavour) {
5214 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
5215 if (!attrs->split)
5216 n = snprintf(name, len, "p%u", attrs->port_number);
5217 else
5218 n = snprintf(name, len, "p%us%u", attrs->port_number,
5219 attrs->split_subport_number);
5220 break;
5221 case DEVLINK_PORT_FLAVOUR_CPU:
5222 case DEVLINK_PORT_FLAVOUR_DSA:
5223 /* As CPU and DSA ports do not have a netdevice associated
5224 * case should not ever happen.
5225 */
5226 WARN_ON(1);
5227 return -EINVAL;
5228 }
5229
5230 if (n >= len)
5231 return -EINVAL;
5232
5233 return 0;
5234}
5235EXPORT_SYMBOL_GPL(devlink_port_get_phys_port_name);
5236
bf797471
JP
5237int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
5238 u32 size, u16 ingress_pools_count,
5239 u16 egress_pools_count, u16 ingress_tc_count,
5240 u16 egress_tc_count)
5241{
5242 struct devlink_sb *devlink_sb;
5243 int err = 0;
5244
2406e7e5 5245 mutex_lock(&devlink->lock);
bf797471
JP
5246 if (devlink_sb_index_exists(devlink, sb_index)) {
5247 err = -EEXIST;
5248 goto unlock;
5249 }
5250
5251 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
5252 if (!devlink_sb) {
5253 err = -ENOMEM;
5254 goto unlock;
5255 }
5256 devlink_sb->index = sb_index;
5257 devlink_sb->size = size;
5258 devlink_sb->ingress_pools_count = ingress_pools_count;
5259 devlink_sb->egress_pools_count = egress_pools_count;
5260 devlink_sb->ingress_tc_count = ingress_tc_count;
5261 devlink_sb->egress_tc_count = egress_tc_count;
5262 list_add_tail(&devlink_sb->list, &devlink->sb_list);
5263unlock:
2406e7e5 5264 mutex_unlock(&devlink->lock);
bf797471
JP
5265 return err;
5266}
5267EXPORT_SYMBOL_GPL(devlink_sb_register);
5268
5269void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
5270{
5271 struct devlink_sb *devlink_sb;
5272
2406e7e5 5273 mutex_lock(&devlink->lock);
bf797471
JP
5274 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
5275 WARN_ON(!devlink_sb);
5276 list_del(&devlink_sb->list);
2406e7e5 5277 mutex_unlock(&devlink->lock);
bf797471
JP
5278 kfree(devlink_sb);
5279}
5280EXPORT_SYMBOL_GPL(devlink_sb_unregister);
5281
1555d204
AS
5282/**
5283 * devlink_dpipe_headers_register - register dpipe headers
5284 *
5285 * @devlink: devlink
5286 * @dpipe_headers: dpipe header array
5287 *
5288 * Register the headers supported by hardware.
5289 */
5290int devlink_dpipe_headers_register(struct devlink *devlink,
5291 struct devlink_dpipe_headers *dpipe_headers)
5292{
2406e7e5 5293 mutex_lock(&devlink->lock);
1555d204 5294 devlink->dpipe_headers = dpipe_headers;
2406e7e5 5295 mutex_unlock(&devlink->lock);
1555d204
AS
5296 return 0;
5297}
5298EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
5299
5300/**
5301 * devlink_dpipe_headers_unregister - unregister dpipe headers
5302 *
5303 * @devlink: devlink
5304 *
5305 * Unregister the headers supported by hardware.
5306 */
5307void devlink_dpipe_headers_unregister(struct devlink *devlink)
5308{
2406e7e5 5309 mutex_lock(&devlink->lock);
1555d204 5310 devlink->dpipe_headers = NULL;
2406e7e5 5311 mutex_unlock(&devlink->lock);
1555d204
AS
5312}
5313EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
5314
5315/**
5316 * devlink_dpipe_table_counter_enabled - check if counter allocation
5317 * required
5318 * @devlink: devlink
5319 * @table_name: tables name
5320 *
5321 * Used by driver to check if counter allocation is required.
5322 * After counter allocation is turned on the table entries
5323 * are updated to include counter statistics.
5324 *
5325 * After that point on the driver must respect the counter
5326 * state so that each entry added to the table is added
5327 * with a counter.
5328 */
5329bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
5330 const char *table_name)
5331{
5332 struct devlink_dpipe_table *table;
5333 bool enabled;
5334
5335 rcu_read_lock();
5336 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5337 table_name);
5338 enabled = false;
5339 if (table)
5340 enabled = table->counters_enabled;
5341 rcu_read_unlock();
5342 return enabled;
5343}
5344EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
5345
5346/**
5347 * devlink_dpipe_table_register - register dpipe table
5348 *
5349 * @devlink: devlink
5350 * @table_name: table name
5351 * @table_ops: table ops
5352 * @priv: priv
1555d204
AS
5353 * @counter_control_extern: external control for counters
5354 */
5355int devlink_dpipe_table_register(struct devlink *devlink,
5356 const char *table_name,
5357 struct devlink_dpipe_table_ops *table_ops,
ffd3cdcc 5358 void *priv, bool counter_control_extern)
1555d204
AS
5359{
5360 struct devlink_dpipe_table *table;
5361
5362 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
5363 return -EEXIST;
5364
ffd3cdcc
AS
5365 if (WARN_ON(!table_ops->size_get))
5366 return -EINVAL;
5367
1555d204
AS
5368 table = kzalloc(sizeof(*table), GFP_KERNEL);
5369 if (!table)
5370 return -ENOMEM;
5371
5372 table->name = table_name;
5373 table->table_ops = table_ops;
5374 table->priv = priv;
1555d204
AS
5375 table->counter_control_extern = counter_control_extern;
5376
2406e7e5 5377 mutex_lock(&devlink->lock);
1555d204 5378 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
2406e7e5 5379 mutex_unlock(&devlink->lock);
1555d204
AS
5380 return 0;
5381}
5382EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
5383
5384/**
5385 * devlink_dpipe_table_unregister - unregister dpipe table
5386 *
5387 * @devlink: devlink
5388 * @table_name: table name
5389 */
5390void devlink_dpipe_table_unregister(struct devlink *devlink,
5391 const char *table_name)
5392{
5393 struct devlink_dpipe_table *table;
5394
2406e7e5 5395 mutex_lock(&devlink->lock);
1555d204
AS
5396 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5397 table_name);
5398 if (!table)
5399 goto unlock;
5400 list_del_rcu(&table->list);
2406e7e5 5401 mutex_unlock(&devlink->lock);
1555d204
AS
5402 kfree_rcu(table, rcu);
5403 return;
5404unlock:
2406e7e5 5405 mutex_unlock(&devlink->lock);
1555d204
AS
5406}
5407EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
5408
d9f9b9a4
AS
5409/**
5410 * devlink_resource_register - devlink resource register
5411 *
5412 * @devlink: devlink
5413 * @resource_name: resource's name
5414 * @top_hierarchy: top hierarchy
5415 * @reload_required: reload is required for new configuration to
5416 * apply
5417 * @resource_size: resource's size
5418 * @resource_id: resource's id
5419 * @parent_reosurce_id: resource's parent id
5420 * @size params: size parameters
d9f9b9a4
AS
5421 */
5422int devlink_resource_register(struct devlink *devlink,
5423 const char *resource_name,
d9f9b9a4
AS
5424 u64 resource_size,
5425 u64 resource_id,
5426 u64 parent_resource_id,
fc56be47 5427 const struct devlink_resource_size_params *size_params)
d9f9b9a4
AS
5428{
5429 struct devlink_resource *resource;
5430 struct list_head *resource_list;
14530746 5431 bool top_hierarchy;
d9f9b9a4
AS
5432 int err = 0;
5433
14530746
DA
5434 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
5435
d9f9b9a4
AS
5436 mutex_lock(&devlink->lock);
5437 resource = devlink_resource_find(devlink, NULL, resource_id);
5438 if (resource) {
5439 err = -EINVAL;
5440 goto out;
5441 }
5442
5443 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
5444 if (!resource) {
5445 err = -ENOMEM;
5446 goto out;
5447 }
5448
5449 if (top_hierarchy) {
5450 resource_list = &devlink->resource_list;
5451 } else {
5452 struct devlink_resource *parent_resource;
5453
5454 parent_resource = devlink_resource_find(devlink, NULL,
5455 parent_resource_id);
5456 if (parent_resource) {
5457 resource_list = &parent_resource->resource_list;
5458 resource->parent = parent_resource;
5459 } else {
b75703de 5460 kfree(resource);
d9f9b9a4
AS
5461 err = -EINVAL;
5462 goto out;
5463 }
5464 }
5465
5466 resource->name = resource_name;
5467 resource->size = resource_size;
5468 resource->size_new = resource_size;
5469 resource->id = resource_id;
d9f9b9a4 5470 resource->size_valid = true;
77d27096
JP
5471 memcpy(&resource->size_params, size_params,
5472 sizeof(resource->size_params));
d9f9b9a4
AS
5473 INIT_LIST_HEAD(&resource->resource_list);
5474 list_add_tail(&resource->list, resource_list);
5475out:
5476 mutex_unlock(&devlink->lock);
5477 return err;
5478}
5479EXPORT_SYMBOL_GPL(devlink_resource_register);
5480
5481/**
5482 * devlink_resources_unregister - free all resources
5483 *
5484 * @devlink: devlink
5485 * @resource: resource
5486 */
5487void devlink_resources_unregister(struct devlink *devlink,
5488 struct devlink_resource *resource)
5489{
5490 struct devlink_resource *tmp, *child_resource;
5491 struct list_head *resource_list;
5492
5493 if (resource)
5494 resource_list = &resource->resource_list;
5495 else
5496 resource_list = &devlink->resource_list;
5497
5498 if (!resource)
5499 mutex_lock(&devlink->lock);
5500
5501 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
5502 devlink_resources_unregister(devlink, child_resource);
5503 list_del(&child_resource->list);
5504 kfree(child_resource);
5505 }
5506
5507 if (!resource)
5508 mutex_unlock(&devlink->lock);
5509}
5510EXPORT_SYMBOL_GPL(devlink_resources_unregister);
5511
5512/**
5513 * devlink_resource_size_get - get and update size
5514 *
5515 * @devlink: devlink
5516 * @resource_id: the requested resource id
5517 * @p_resource_size: ptr to update
5518 */
5519int devlink_resource_size_get(struct devlink *devlink,
5520 u64 resource_id,
5521 u64 *p_resource_size)
5522{
5523 struct devlink_resource *resource;
5524 int err = 0;
5525
5526 mutex_lock(&devlink->lock);
5527 resource = devlink_resource_find(devlink, NULL, resource_id);
5528 if (!resource) {
5529 err = -EINVAL;
5530 goto out;
5531 }
5532 *p_resource_size = resource->size_new;
5533 resource->size = resource->size_new;
5534out:
5535 mutex_unlock(&devlink->lock);
5536 return err;
5537}
5538EXPORT_SYMBOL_GPL(devlink_resource_size_get);
5539
56dc7cd0
AS
5540/**
5541 * devlink_dpipe_table_resource_set - set the resource id
5542 *
5543 * @devlink: devlink
5544 * @table_name: table name
5545 * @resource_id: resource id
5546 * @resource_units: number of resource's units consumed per table's entry
5547 */
5548int devlink_dpipe_table_resource_set(struct devlink *devlink,
5549 const char *table_name, u64 resource_id,
5550 u64 resource_units)
5551{
5552 struct devlink_dpipe_table *table;
5553 int err = 0;
5554
5555 mutex_lock(&devlink->lock);
5556 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5557 table_name);
5558 if (!table) {
5559 err = -EINVAL;
5560 goto out;
5561 }
5562 table->resource_id = resource_id;
5563 table->resource_units = resource_units;
5564 table->resource_valid = true;
5565out:
5566 mutex_unlock(&devlink->lock);
5567 return err;
5568}
5569EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
5570
fc56be47
JP
5571/**
5572 * devlink_resource_occ_get_register - register occupancy getter
5573 *
5574 * @devlink: devlink
5575 * @resource_id: resource id
5576 * @occ_get: occupancy getter callback
5577 * @occ_get_priv: occupancy getter callback priv
5578 */
5579void devlink_resource_occ_get_register(struct devlink *devlink,
5580 u64 resource_id,
5581 devlink_resource_occ_get_t *occ_get,
5582 void *occ_get_priv)
5583{
5584 struct devlink_resource *resource;
5585
5586 mutex_lock(&devlink->lock);
5587 resource = devlink_resource_find(devlink, NULL, resource_id);
5588 if (WARN_ON(!resource))
5589 goto out;
5590 WARN_ON(resource->occ_get);
5591
5592 resource->occ_get = occ_get;
5593 resource->occ_get_priv = occ_get_priv;
5594out:
5595 mutex_unlock(&devlink->lock);
5596}
5597EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
5598
5599/**
5600 * devlink_resource_occ_get_unregister - unregister occupancy getter
5601 *
5602 * @devlink: devlink
5603 * @resource_id: resource id
5604 */
5605void devlink_resource_occ_get_unregister(struct devlink *devlink,
5606 u64 resource_id)
5607{
5608 struct devlink_resource *resource;
5609
5610 mutex_lock(&devlink->lock);
5611 resource = devlink_resource_find(devlink, NULL, resource_id);
5612 if (WARN_ON(!resource))
5613 goto out;
5614 WARN_ON(!resource->occ_get);
5615
5616 resource->occ_get = NULL;
5617 resource->occ_get_priv = NULL;
5618out:
5619 mutex_unlock(&devlink->lock);
5620}
5621EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
5622
39e6160e
VV
5623static int devlink_param_verify(const struct devlink_param *param)
5624{
5625 if (!param || !param->name || !param->supported_cmodes)
5626 return -EINVAL;
5627 if (param->generic)
5628 return devlink_param_generic_verify(param);
5629 else
5630 return devlink_param_driver_verify(param);
5631}
5632
5633static int __devlink_params_register(struct devlink *devlink,
c1e5786d 5634 unsigned int port_index,
39e6160e
VV
5635 struct list_head *param_list,
5636 const struct devlink_param *params,
c1e5786d
VV
5637 size_t params_count,
5638 enum devlink_command reg_cmd,
5639 enum devlink_command unreg_cmd)
eabaef18
MS
5640{
5641 const struct devlink_param *param = params;
5642 int i;
5643 int err;
5644
5645 mutex_lock(&devlink->lock);
5646 for (i = 0; i < params_count; i++, param++) {
39e6160e
VV
5647 err = devlink_param_verify(param);
5648 if (err)
eabaef18 5649 goto rollback;
39e6160e 5650
c1e5786d
VV
5651 err = devlink_param_register_one(devlink, port_index,
5652 param_list, param, reg_cmd);
eabaef18
MS
5653 if (err)
5654 goto rollback;
5655 }
5656
5657 mutex_unlock(&devlink->lock);
5658 return 0;
5659
5660rollback:
5661 if (!i)
5662 goto unlock;
5663 for (param--; i > 0; i--, param--)
c1e5786d
VV
5664 devlink_param_unregister_one(devlink, port_index, param_list,
5665 param, unreg_cmd);
eabaef18
MS
5666unlock:
5667 mutex_unlock(&devlink->lock);
5668 return err;
5669}
39e6160e
VV
5670
5671static void __devlink_params_unregister(struct devlink *devlink,
c1e5786d 5672 unsigned int port_index,
39e6160e
VV
5673 struct list_head *param_list,
5674 const struct devlink_param *params,
c1e5786d
VV
5675 size_t params_count,
5676 enum devlink_command cmd)
39e6160e
VV
5677{
5678 const struct devlink_param *param = params;
5679 int i;
5680
5681 mutex_lock(&devlink->lock);
5682 for (i = 0; i < params_count; i++, param++)
c1e5786d
VV
5683 devlink_param_unregister_one(devlink, 0, param_list, param,
5684 cmd);
39e6160e
VV
5685 mutex_unlock(&devlink->lock);
5686}
5687
5688/**
5689 * devlink_params_register - register configuration parameters
5690 *
5691 * @devlink: devlink
5692 * @params: configuration parameters array
5693 * @params_count: number of parameters provided
5694 *
5695 * Register the configuration parameters supported by the driver.
5696 */
5697int devlink_params_register(struct devlink *devlink,
5698 const struct devlink_param *params,
5699 size_t params_count)
5700{
c1e5786d
VV
5701 return __devlink_params_register(devlink, 0, &devlink->param_list,
5702 params, params_count,
5703 DEVLINK_CMD_PARAM_NEW,
5704 DEVLINK_CMD_PARAM_DEL);
39e6160e 5705}
eabaef18
MS
5706EXPORT_SYMBOL_GPL(devlink_params_register);
5707
5708/**
5709 * devlink_params_unregister - unregister configuration parameters
5710 * @devlink: devlink
5711 * @params: configuration parameters to unregister
5712 * @params_count: number of parameters provided
5713 */
5714void devlink_params_unregister(struct devlink *devlink,
5715 const struct devlink_param *params,
5716 size_t params_count)
5717{
c1e5786d
VV
5718 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
5719 params, params_count,
5720 DEVLINK_CMD_PARAM_DEL);
eabaef18
MS
5721}
5722EXPORT_SYMBOL_GPL(devlink_params_unregister);
5723
39e6160e
VV
5724/**
5725 * devlink_port_params_register - register port configuration parameters
5726 *
5727 * @devlink_port: devlink port
5728 * @params: configuration parameters array
5729 * @params_count: number of parameters provided
5730 *
5731 * Register the configuration parameters supported by the port.
5732 */
5733int devlink_port_params_register(struct devlink_port *devlink_port,
5734 const struct devlink_param *params,
5735 size_t params_count)
5736{
5737 return __devlink_params_register(devlink_port->devlink,
c1e5786d 5738 devlink_port->index,
39e6160e 5739 &devlink_port->param_list, params,
c1e5786d
VV
5740 params_count,
5741 DEVLINK_CMD_PORT_PARAM_NEW,
5742 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
5743}
5744EXPORT_SYMBOL_GPL(devlink_port_params_register);
5745
5746/**
5747 * devlink_port_params_unregister - unregister port configuration
5748 * parameters
5749 *
5750 * @devlink_port: devlink port
5751 * @params: configuration parameters array
5752 * @params_count: number of parameters provided
5753 */
5754void devlink_port_params_unregister(struct devlink_port *devlink_port,
5755 const struct devlink_param *params,
5756 size_t params_count)
5757{
5758 return __devlink_params_unregister(devlink_port->devlink,
c1e5786d 5759 devlink_port->index,
39e6160e 5760 &devlink_port->param_list,
c1e5786d
VV
5761 params, params_count,
5762 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
5763}
5764EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
5765
ffd19b9a
VV
5766static int
5767__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
5768 union devlink_param_value *init_val)
ec01aeb1
MS
5769{
5770 struct devlink_param_item *param_item;
5771
ffd19b9a 5772 param_item = devlink_param_find_by_id(param_list, param_id);
ec01aeb1
MS
5773 if (!param_item)
5774 return -EINVAL;
5775
5776 if (!param_item->driverinit_value_valid ||
5777 !devlink_param_cmode_is_supported(param_item->param,
5778 DEVLINK_PARAM_CMODE_DRIVERINIT))
5779 return -EOPNOTSUPP;
5780
1276534c
MS
5781 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
5782 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
5783 else
5784 *init_val = param_item->driverinit_value;
ec01aeb1
MS
5785
5786 return 0;
5787}
ffd19b9a 5788
5473a7bd
VV
5789static int
5790__devlink_param_driverinit_value_set(struct devlink *devlink,
c1e5786d 5791 unsigned int port_index,
5473a7bd
VV
5792 struct list_head *param_list, u32 param_id,
5793 union devlink_param_value init_val,
5794 enum devlink_command cmd)
5795{
5796 struct devlink_param_item *param_item;
5797
5798 param_item = devlink_param_find_by_id(param_list, param_id);
5799 if (!param_item)
5800 return -EINVAL;
5801
5802 if (!devlink_param_cmode_is_supported(param_item->param,
5803 DEVLINK_PARAM_CMODE_DRIVERINIT))
5804 return -EOPNOTSUPP;
5805
5806 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
5807 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
5808 else
5809 param_item->driverinit_value = init_val;
5810 param_item->driverinit_value_valid = true;
5811
c1e5786d 5812 devlink_param_notify(devlink, port_index, param_item, cmd);
5473a7bd
VV
5813 return 0;
5814}
5815
ffd19b9a
VV
5816/**
5817 * devlink_param_driverinit_value_get - get configuration parameter
5818 * value for driver initializing
5819 *
5820 * @devlink: devlink
5821 * @param_id: parameter ID
5822 * @init_val: value of parameter in driverinit configuration mode
5823 *
5824 * This function should be used by the driver to get driverinit
5825 * configuration for initialization after reload command.
5826 */
5827int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
5828 union devlink_param_value *init_val)
5829{
5830 if (!devlink->ops || !devlink->ops->reload)
5831 return -EOPNOTSUPP;
5832
5833 return __devlink_param_driverinit_value_get(&devlink->param_list,
5834 param_id, init_val);
5835}
ec01aeb1
MS
5836EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
5837
5838/**
5839 * devlink_param_driverinit_value_set - set value of configuration
5840 * parameter for driverinit
5841 * configuration mode
5842 *
5843 * @devlink: devlink
5844 * @param_id: parameter ID
5845 * @init_val: value of parameter to set for driverinit configuration mode
5846 *
5847 * This function should be used by the driver to set driverinit
5848 * configuration mode default value.
5849 */
5850int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
5851 union devlink_param_value init_val)
5852{
c1e5786d 5853 return __devlink_param_driverinit_value_set(devlink, 0,
5473a7bd
VV
5854 &devlink->param_list,
5855 param_id, init_val,
5856 DEVLINK_CMD_PARAM_NEW);
ec01aeb1
MS
5857}
5858EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
5859
ffd19b9a
VV
5860/**
5861 * devlink_port_param_driverinit_value_get - get configuration parameter
5862 * value for driver initializing
5863 *
5864 * @devlink_port: devlink_port
5865 * @param_id: parameter ID
5866 * @init_val: value of parameter in driverinit configuration mode
5867 *
5868 * This function should be used by the driver to get driverinit
5869 * configuration for initialization after reload command.
5870 */
5871int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
5872 u32 param_id,
5873 union devlink_param_value *init_val)
5874{
5875 struct devlink *devlink = devlink_port->devlink;
5876
5877 if (!devlink->ops || !devlink->ops->reload)
5878 return -EOPNOTSUPP;
5879
5880 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
5881 param_id, init_val);
5882}
5883EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
5884
5473a7bd
VV
5885/**
5886 * devlink_port_param_driverinit_value_set - set value of configuration
5887 * parameter for driverinit
5888 * configuration mode
5889 *
5890 * @devlink_port: devlink_port
5891 * @param_id: parameter ID
5892 * @init_val: value of parameter to set for driverinit configuration mode
5893 *
5894 * This function should be used by the driver to set driverinit
5895 * configuration mode default value.
5896 */
5897int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
5898 u32 param_id,
5899 union devlink_param_value init_val)
5900{
5901 return __devlink_param_driverinit_value_set(devlink_port->devlink,
c1e5786d 5902 devlink_port->index,
5473a7bd 5903 &devlink_port->param_list,
c1e5786d
VV
5904 param_id, init_val,
5905 DEVLINK_CMD_PORT_PARAM_NEW);
5473a7bd
VV
5906}
5907EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
5908
ea601e17
MS
5909/**
5910 * devlink_param_value_changed - notify devlink on a parameter's value
5911 * change. Should be called by the driver
5912 * right after the change.
5913 *
5914 * @devlink: devlink
5915 * @param_id: parameter ID
5916 *
5917 * This function should be used by the driver to notify devlink on value
5918 * change, excluding driverinit configuration mode.
5919 * For driverinit configuration mode driver should use the function
ea601e17
MS
5920 */
5921void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
5922{
5923 struct devlink_param_item *param_item;
5924
5925 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
5926 WARN_ON(!param_item);
5927
c1e5786d 5928 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
ea601e17
MS
5929}
5930EXPORT_SYMBOL_GPL(devlink_param_value_changed);
5931
c1e5786d
VV
5932/**
5933 * devlink_port_param_value_changed - notify devlink on a parameter's value
5934 * change. Should be called by the driver
5935 * right after the change.
5936 *
5937 * @devlink_port: devlink_port
5938 * @param_id: parameter ID
5939 *
5940 * This function should be used by the driver to notify devlink on value
5941 * change, excluding driverinit configuration mode.
5942 * For driverinit configuration mode driver should use the function
5943 * devlink_port_param_driverinit_value_set() instead.
5944 */
5945void devlink_port_param_value_changed(struct devlink_port *devlink_port,
5946 u32 param_id)
5947{
5948 struct devlink_param_item *param_item;
5949
5950 param_item = devlink_param_find_by_id(&devlink_port->param_list,
5951 param_id);
5952 WARN_ON(!param_item);
5953
5954 devlink_param_notify(devlink_port->devlink, devlink_port->index,
5955 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
5956}
5957EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
5958
bde74ad1
MS
5959/**
5960 * devlink_param_value_str_fill - Safely fill-up the string preventing
5961 * from overflow of the preallocated buffer
5962 *
5963 * @dst_val: destination devlink_param_value
5964 * @src: source buffer
5965 */
5966void devlink_param_value_str_fill(union devlink_param_value *dst_val,
5967 const char *src)
5968{
5969 size_t len;
5970
5971 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
5972 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
5973}
5974EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
5975
b16ebe92
AV
5976/**
5977 * devlink_region_create - create a new address region
5978 *
5979 * @devlink: devlink
5980 * @region_name: region name
5981 * @region_max_snapshots: Maximum supported number of snapshots for region
5982 * @region_size: size of region
5983 */
5984struct devlink_region *devlink_region_create(struct devlink *devlink,
5985 const char *region_name,
5986 u32 region_max_snapshots,
5987 u64 region_size)
5988{
5989 struct devlink_region *region;
5990 int err = 0;
5991
5992 mutex_lock(&devlink->lock);
5993
5994 if (devlink_region_get_by_name(devlink, region_name)) {
5995 err = -EEXIST;
5996 goto unlock;
5997 }
5998
5999 region = kzalloc(sizeof(*region), GFP_KERNEL);
6000 if (!region) {
6001 err = -ENOMEM;
6002 goto unlock;
6003 }
6004
6005 region->devlink = devlink;
6006 region->max_snapshots = region_max_snapshots;
6007 region->name = region_name;
6008 region->size = region_size;
6009 INIT_LIST_HEAD(&region->snapshot_list);
6010 list_add_tail(&region->list, &devlink->region_list);
866319bb 6011 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
b16ebe92
AV
6012
6013 mutex_unlock(&devlink->lock);
6014 return region;
6015
6016unlock:
6017 mutex_unlock(&devlink->lock);
6018 return ERR_PTR(err);
6019}
6020EXPORT_SYMBOL_GPL(devlink_region_create);
6021
6022/**
6023 * devlink_region_destroy - destroy address region
6024 *
6025 * @region: devlink region to destroy
6026 */
6027void devlink_region_destroy(struct devlink_region *region)
6028{
6029 struct devlink *devlink = region->devlink;
d7e52722 6030 struct devlink_snapshot *snapshot, *ts;
b16ebe92
AV
6031
6032 mutex_lock(&devlink->lock);
d7e52722
AV
6033
6034 /* Free all snapshots of region */
6035 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
6036 devlink_region_snapshot_del(snapshot);
6037
b16ebe92 6038 list_del(&region->list);
866319bb
AV
6039
6040 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
b16ebe92
AV
6041 mutex_unlock(&devlink->lock);
6042 kfree(region);
6043}
6044EXPORT_SYMBOL_GPL(devlink_region_destroy);
6045
ccadfa44
AV
6046/**
6047 * devlink_region_shapshot_id_get - get snapshot ID
6048 *
6049 * This callback should be called when adding a new snapshot,
6050 * Driver should use the same id for multiple snapshots taken
6051 * on multiple regions at the same time/by the same trigger.
6052 *
6053 * @devlink: devlink
6054 */
6055u32 devlink_region_shapshot_id_get(struct devlink *devlink)
6056{
6057 u32 id;
6058
6059 mutex_lock(&devlink->lock);
6060 id = ++devlink->snapshot_id;
6061 mutex_unlock(&devlink->lock);
6062
6063 return id;
6064}
6065EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
6066
d7e52722
AV
6067/**
6068 * devlink_region_snapshot_create - create a new snapshot
6069 * This will add a new snapshot of a region. The snapshot
6070 * will be stored on the region struct and can be accessed
6071 * from devlink. This is useful for future analyses of snapshots.
6072 * Multiple snapshots can be created on a region.
6073 * The @snapshot_id should be obtained using the getter function.
6074 *
6075 * @devlink_region: devlink region of the snapshot
6076 * @data_len: size of snapshot data
6077 * @data: snapshot data
6078 * @snapshot_id: snapshot id to be created
6079 * @data_destructor: pointer to destructor function to free data
6080 */
6081int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
6082 u8 *data, u32 snapshot_id,
6083 devlink_snapshot_data_dest_t *data_destructor)
6084{
6085 struct devlink *devlink = region->devlink;
6086 struct devlink_snapshot *snapshot;
6087 int err;
6088
6089 mutex_lock(&devlink->lock);
6090
6091 /* check if region can hold one more snapshot */
6092 if (region->cur_snapshots == region->max_snapshots) {
6093 err = -ENOMEM;
6094 goto unlock;
6095 }
6096
6097 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
6098 err = -EEXIST;
6099 goto unlock;
6100 }
6101
6102 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
6103 if (!snapshot) {
6104 err = -ENOMEM;
6105 goto unlock;
6106 }
6107
6108 snapshot->id = snapshot_id;
6109 snapshot->region = region;
6110 snapshot->data = data;
6111 snapshot->data_len = data_len;
6112 snapshot->data_destructor = data_destructor;
6113
6114 list_add_tail(&snapshot->list, &region->snapshot_list);
6115
6116 region->cur_snapshots++;
6117
866319bb 6118 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
d7e52722
AV
6119 mutex_unlock(&devlink->lock);
6120 return 0;
6121
6122unlock:
6123 mutex_unlock(&devlink->lock);
6124 return err;
6125}
6126EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
6127
ddb6e99e
JK
6128static void __devlink_compat_running_version(struct devlink *devlink,
6129 char *buf, size_t len)
6130{
6131 const struct nlattr *nlattr;
6132 struct devlink_info_req req;
6133 struct sk_buff *msg;
6134 int rem, err;
6135
6136 if (!devlink->ops->info_get)
6137 return;
6138
6139 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6140 if (!msg)
6141 return;
6142
6143 req.msg = msg;
6144 err = devlink->ops->info_get(devlink, &req, NULL);
6145 if (err)
6146 goto free_msg;
6147
6148 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
6149 const struct nlattr *kv;
6150 int rem_kv;
6151
6152 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
6153 continue;
6154
6155 nla_for_each_nested(kv, nlattr, rem_kv) {
6156 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
6157 continue;
6158
6159 strlcat(buf, nla_data(kv), len);
6160 strlcat(buf, " ", len);
6161 }
6162 }
6163free_msg:
6164 nlmsg_free(msg);
6165}
6166
6167void devlink_compat_running_version(struct net_device *dev,
6168 char *buf, size_t len)
6169{
6170 struct devlink_port *devlink_port;
6171 struct devlink *devlink;
6172
6173 mutex_lock(&devlink_mutex);
6174 list_for_each_entry(devlink, &devlink_list, list) {
6175 mutex_lock(&devlink->lock);
6176 list_for_each_entry(devlink_port, &devlink->port_list, list) {
6177 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH ||
6178 devlink_port->type_dev == dev) {
6179 __devlink_compat_running_version(devlink,
6180 buf, len);
6181 mutex_unlock(&devlink->lock);
6182 goto out;
6183 }
6184 }
6185 mutex_unlock(&devlink->lock);
6186 }
6187out:
6188 mutex_unlock(&devlink_mutex);
6189}
6190
bfcd3a46
JP
6191static int __init devlink_module_init(void)
6192{
489111e5 6193 return genl_register_family(&devlink_nl_family);
bfcd3a46
JP
6194}
6195
6196static void __exit devlink_module_exit(void)
6197{
6198 genl_unregister_family(&devlink_nl_family);
6199}
6200
6201module_init(devlink_module_init);
6202module_exit(devlink_module_exit);
6203
6204MODULE_LICENSE("GPL v2");
6205MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
6206MODULE_DESCRIPTION("Network physical device Netlink interface");
6207MODULE_ALIAS_GENL_FAMILY(DEVLINK_GENL_NAME);