net: dsa: microchip: add switch offload forwarding support
[linux-2.6-block.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];
7c62cfb8 2861 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
45f05def
MS
2862 const struct devlink_param *param = param_item->param;
2863 struct devlink_param_gset_ctx ctx;
2864 struct nlattr *param_values_list;
2865 struct nlattr *param_attr;
2866 int nla_type;
2867 void *hdr;
2868 int err;
2869 int i;
2870
2871 /* Get value from driver part to driverinit configuration mode */
2872 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
2873 if (!devlink_param_cmode_is_supported(param, i))
2874 continue;
2875 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
2876 if (!param_item->driverinit_value_valid)
2877 return -EOPNOTSUPP;
2878 param_value[i] = param_item->driverinit_value;
2879 } else {
7c62cfb8
JP
2880 if (!param_item->published)
2881 continue;
45f05def
MS
2882 ctx.cmode = i;
2883 err = devlink_param_get(devlink, param, &ctx);
2884 if (err)
2885 return err;
2886 param_value[i] = ctx.val;
2887 }
7c62cfb8 2888 param_value_set[i] = true;
45f05def
MS
2889 }
2890
2891 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
2892 if (!hdr)
2893 return -EMSGSIZE;
2894
2895 if (devlink_nl_put_handle(msg, devlink))
2896 goto genlmsg_cancel;
f4601dee 2897
c1e5786d
VV
2898 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
2899 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
2900 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
f4601dee
VV
2901 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
2902 goto genlmsg_cancel;
2903
45f05def
MS
2904 param_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM);
2905 if (!param_attr)
2906 goto genlmsg_cancel;
2907 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
2908 goto param_nest_cancel;
2909 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
2910 goto param_nest_cancel;
2911
2912 nla_type = devlink_param_type_to_nla_type(param->type);
2913 if (nla_type < 0)
2914 goto param_nest_cancel;
2915 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
2916 goto param_nest_cancel;
2917
2918 param_values_list = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUES_LIST);
2919 if (!param_values_list)
2920 goto param_nest_cancel;
2921
2922 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
7c62cfb8 2923 if (!param_value_set[i])
45f05def
MS
2924 continue;
2925 err = devlink_nl_param_value_fill_one(msg, param->type,
2926 i, param_value[i]);
2927 if (err)
2928 goto values_list_nest_cancel;
2929 }
2930
2931 nla_nest_end(msg, param_values_list);
2932 nla_nest_end(msg, param_attr);
2933 genlmsg_end(msg, hdr);
2934 return 0;
2935
2936values_list_nest_cancel:
2937 nla_nest_end(msg, param_values_list);
2938param_nest_cancel:
2939 nla_nest_cancel(msg, param_attr);
2940genlmsg_cancel:
2941 genlmsg_cancel(msg, hdr);
2942 return -EMSGSIZE;
2943}
2944
ea601e17 2945static void devlink_param_notify(struct devlink *devlink,
c1e5786d 2946 unsigned int port_index,
ea601e17
MS
2947 struct devlink_param_item *param_item,
2948 enum devlink_command cmd)
2949{
2950 struct sk_buff *msg;
2951 int err;
2952
c1e5786d
VV
2953 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
2954 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
2955 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
ea601e17
MS
2956
2957 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2958 if (!msg)
2959 return;
c1e5786d
VV
2960 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
2961 0, 0, 0);
ea601e17
MS
2962 if (err) {
2963 nlmsg_free(msg);
2964 return;
2965 }
2966
2967 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
2968 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
2969}
2970
45f05def
MS
2971static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
2972 struct netlink_callback *cb)
2973{
2974 struct devlink_param_item *param_item;
2975 struct devlink *devlink;
2976 int start = cb->args[0];
2977 int idx = 0;
2978 int err;
2979
2980 mutex_lock(&devlink_mutex);
2981 list_for_each_entry(devlink, &devlink_list, list) {
2982 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
2983 continue;
2984 mutex_lock(&devlink->lock);
2985 list_for_each_entry(param_item, &devlink->param_list, list) {
2986 if (idx < start) {
2987 idx++;
2988 continue;
2989 }
f4601dee 2990 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
2991 DEVLINK_CMD_PARAM_GET,
2992 NETLINK_CB(cb->skb).portid,
2993 cb->nlh->nlmsg_seq,
2994 NLM_F_MULTI);
2995 if (err) {
2996 mutex_unlock(&devlink->lock);
2997 goto out;
2998 }
2999 idx++;
3000 }
3001 mutex_unlock(&devlink->lock);
3002 }
3003out:
3004 mutex_unlock(&devlink_mutex);
3005
3006 cb->args[0] = idx;
3007 return msg->len;
3008}
3009
e3b7ca18
MS
3010static int
3011devlink_param_type_get_from_info(struct genl_info *info,
3012 enum devlink_param_type *param_type)
3013{
3014 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3015 return -EINVAL;
3016
3017 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3018 case NLA_U8:
3019 *param_type = DEVLINK_PARAM_TYPE_U8;
3020 break;
3021 case NLA_U16:
3022 *param_type = DEVLINK_PARAM_TYPE_U16;
3023 break;
3024 case NLA_U32:
3025 *param_type = DEVLINK_PARAM_TYPE_U32;
3026 break;
3027 case NLA_STRING:
3028 *param_type = DEVLINK_PARAM_TYPE_STRING;
3029 break;
3030 case NLA_FLAG:
3031 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3032 break;
3033 default:
3034 return -EINVAL;
3035 }
3036
3037 return 0;
3038}
3039
3040static int
3041devlink_param_value_get_from_info(const struct devlink_param *param,
3042 struct genl_info *info,
3043 union devlink_param_value *value)
3044{
f355cfcd
MS
3045 int len;
3046
e3b7ca18
MS
3047 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3048 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3049 return -EINVAL;
3050
3051 switch (param->type) {
3052 case DEVLINK_PARAM_TYPE_U8:
3053 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3054 break;
3055 case DEVLINK_PARAM_TYPE_U16:
3056 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3057 break;
3058 case DEVLINK_PARAM_TYPE_U32:
3059 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3060 break;
3061 case DEVLINK_PARAM_TYPE_STRING:
f355cfcd
MS
3062 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3063 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3064 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
bde74ad1 3065 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
e3b7ca18 3066 return -EINVAL;
f355cfcd
MS
3067 strcpy(value->vstr,
3068 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
e3b7ca18
MS
3069 break;
3070 case DEVLINK_PARAM_TYPE_BOOL:
3071 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3072 true : false;
3073 break;
3074 }
3075 return 0;
3076}
3077
45f05def 3078static struct devlink_param_item *
f4601dee 3079devlink_param_get_from_info(struct list_head *param_list,
45f05def
MS
3080 struct genl_info *info)
3081{
3082 char *param_name;
3083
3084 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3085 return NULL;
3086
3087 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
f4601dee 3088 return devlink_param_find_by_name(param_list, param_name);
45f05def
MS
3089}
3090
3091static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3092 struct genl_info *info)
3093{
3094 struct devlink *devlink = info->user_ptr[0];
3095 struct devlink_param_item *param_item;
3096 struct sk_buff *msg;
3097 int err;
3098
f4601dee 3099 param_item = devlink_param_get_from_info(&devlink->param_list, info);
45f05def
MS
3100 if (!param_item)
3101 return -EINVAL;
3102
3103 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3104 if (!msg)
3105 return -ENOMEM;
3106
f4601dee 3107 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
3108 DEVLINK_CMD_PARAM_GET,
3109 info->snd_portid, info->snd_seq, 0);
3110 if (err) {
3111 nlmsg_free(msg);
3112 return err;
3113 }
3114
3115 return genlmsg_reply(msg, info);
3116}
3117
9c54873b 3118static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
c1e5786d 3119 unsigned int port_index,
9c54873b
VV
3120 struct list_head *param_list,
3121 struct genl_info *info,
3122 enum devlink_command cmd)
e3b7ca18 3123{
e3b7ca18
MS
3124 enum devlink_param_type param_type;
3125 struct devlink_param_gset_ctx ctx;
3126 enum devlink_param_cmode cmode;
3127 struct devlink_param_item *param_item;
3128 const struct devlink_param *param;
3129 union devlink_param_value value;
3130 int err = 0;
3131
9c54873b 3132 param_item = devlink_param_get_from_info(param_list, info);
e3b7ca18
MS
3133 if (!param_item)
3134 return -EINVAL;
3135 param = param_item->param;
3136 err = devlink_param_type_get_from_info(info, &param_type);
3137 if (err)
3138 return err;
3139 if (param_type != param->type)
3140 return -EINVAL;
3141 err = devlink_param_value_get_from_info(param, info, &value);
3142 if (err)
3143 return err;
3144 if (param->validate) {
3145 err = param->validate(devlink, param->id, value, info->extack);
3146 if (err)
3147 return err;
3148 }
3149
3150 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3151 return -EINVAL;
3152 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3153 if (!devlink_param_cmode_is_supported(param, cmode))
3154 return -EOPNOTSUPP;
3155
3156 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
1276534c
MS
3157 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3158 strcpy(param_item->driverinit_value.vstr, value.vstr);
3159 else
3160 param_item->driverinit_value = value;
e3b7ca18
MS
3161 param_item->driverinit_value_valid = true;
3162 } else {
3163 if (!param->set)
3164 return -EOPNOTSUPP;
3165 ctx.val = value;
3166 ctx.cmode = cmode;
3167 err = devlink_param_set(devlink, param, &ctx);
3168 if (err)
3169 return err;
3170 }
3171
c1e5786d 3172 devlink_param_notify(devlink, port_index, param_item, cmd);
e3b7ca18
MS
3173 return 0;
3174}
3175
9c54873b
VV
3176static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3177 struct genl_info *info)
3178{
3179 struct devlink *devlink = info->user_ptr[0];
3180
c1e5786d 3181 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
9c54873b
VV
3182 info, DEVLINK_CMD_PARAM_NEW);
3183}
3184
eabaef18 3185static int devlink_param_register_one(struct devlink *devlink,
c1e5786d 3186 unsigned int port_index,
39e6160e 3187 struct list_head *param_list,
c1e5786d
VV
3188 const struct devlink_param *param,
3189 enum devlink_command cmd)
eabaef18
MS
3190{
3191 struct devlink_param_item *param_item;
3192
39e6160e 3193 if (devlink_param_find_by_name(param_list, param->name))
eabaef18
MS
3194 return -EEXIST;
3195
3196 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3197 WARN_ON(param->get || param->set);
3198 else
3199 WARN_ON(!param->get || !param->set);
3200
3201 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3202 if (!param_item)
3203 return -ENOMEM;
3204 param_item->param = param;
3205
39e6160e 3206 list_add_tail(&param_item->list, param_list);
c1e5786d 3207 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3208 return 0;
3209}
3210
3211static void devlink_param_unregister_one(struct devlink *devlink,
c1e5786d 3212 unsigned int port_index,
39e6160e 3213 struct list_head *param_list,
c1e5786d
VV
3214 const struct devlink_param *param,
3215 enum devlink_command cmd)
eabaef18
MS
3216{
3217 struct devlink_param_item *param_item;
3218
39e6160e 3219 param_item = devlink_param_find_by_name(param_list, param->name);
eabaef18 3220 WARN_ON(!param_item);
c1e5786d 3221 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3222 list_del(&param_item->list);
3223 kfree(param_item);
3224}
3225
f4601dee
VV
3226static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3227 struct netlink_callback *cb)
3228{
3229 struct devlink_param_item *param_item;
3230 struct devlink_port *devlink_port;
3231 struct devlink *devlink;
3232 int start = cb->args[0];
3233 int idx = 0;
3234 int err;
3235
3236 mutex_lock(&devlink_mutex);
3237 list_for_each_entry(devlink, &devlink_list, list) {
3238 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3239 continue;
3240 mutex_lock(&devlink->lock);
3241 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3242 list_for_each_entry(param_item,
3243 &devlink_port->param_list, list) {
3244 if (idx < start) {
3245 idx++;
3246 continue;
3247 }
3248 err = devlink_nl_param_fill(msg,
3249 devlink_port->devlink,
3250 devlink_port->index, param_item,
3251 DEVLINK_CMD_PORT_PARAM_GET,
3252 NETLINK_CB(cb->skb).portid,
3253 cb->nlh->nlmsg_seq,
3254 NLM_F_MULTI);
3255 if (err) {
3256 mutex_unlock(&devlink->lock);
3257 goto out;
3258 }
3259 idx++;
3260 }
3261 }
3262 mutex_unlock(&devlink->lock);
3263 }
3264out:
3265 mutex_unlock(&devlink_mutex);
3266
3267 cb->args[0] = idx;
3268 return msg->len;
3269}
3270
3271static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3272 struct genl_info *info)
3273{
3274 struct devlink_port *devlink_port = info->user_ptr[0];
3275 struct devlink_param_item *param_item;
3276 struct sk_buff *msg;
3277 int err;
3278
3279 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3280 info);
3281 if (!param_item)
3282 return -EINVAL;
3283
3284 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3285 if (!msg)
3286 return -ENOMEM;
3287
3288 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3289 devlink_port->index, param_item,
3290 DEVLINK_CMD_PORT_PARAM_GET,
3291 info->snd_portid, info->snd_seq, 0);
3292 if (err) {
3293 nlmsg_free(msg);
3294 return err;
3295 }
3296
3297 return genlmsg_reply(msg, info);
3298}
3299
9c54873b
VV
3300static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3301 struct genl_info *info)
3302{
3303 struct devlink_port *devlink_port = info->user_ptr[0];
3304
3305 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
c1e5786d
VV
3306 devlink_port->index,
3307 &devlink_port->param_list, info,
3308 DEVLINK_CMD_PORT_PARAM_NEW);
9c54873b
VV
3309}
3310
a006d467
AV
3311static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3312 struct devlink *devlink,
3313 struct devlink_snapshot *snapshot)
3314{
3315 struct nlattr *snap_attr;
3316 int err;
3317
3318 snap_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
3319 if (!snap_attr)
3320 return -EINVAL;
3321
3322 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3323 if (err)
3324 goto nla_put_failure;
3325
3326 nla_nest_end(msg, snap_attr);
3327 return 0;
3328
3329nla_put_failure:
3330 nla_nest_cancel(msg, snap_attr);
3331 return err;
3332}
3333
3334static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3335 struct devlink *devlink,
3336 struct devlink_region *region)
3337{
3338 struct devlink_snapshot *snapshot;
3339 struct nlattr *snapshots_attr;
3340 int err;
3341
3342 snapshots_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOTS);
3343 if (!snapshots_attr)
3344 return -EINVAL;
3345
3346 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3347 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3348 if (err)
3349 goto nla_put_failure;
3350 }
3351
3352 nla_nest_end(msg, snapshots_attr);
3353 return 0;
3354
3355nla_put_failure:
3356 nla_nest_cancel(msg, snapshots_attr);
3357 return err;
3358}
3359
d8db7ea5
AV
3360static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3361 enum devlink_command cmd, u32 portid,
3362 u32 seq, int flags,
3363 struct devlink_region *region)
3364{
3365 void *hdr;
3366 int err;
3367
3368 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3369 if (!hdr)
3370 return -EMSGSIZE;
3371
3372 err = devlink_nl_put_handle(msg, devlink);
3373 if (err)
3374 goto nla_put_failure;
3375
3376 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3377 if (err)
3378 goto nla_put_failure;
3379
3380 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3381 region->size,
3382 DEVLINK_ATTR_PAD);
3383 if (err)
3384 goto nla_put_failure;
3385
a006d467
AV
3386 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3387 if (err)
3388 goto nla_put_failure;
3389
d8db7ea5
AV
3390 genlmsg_end(msg, hdr);
3391 return 0;
3392
3393nla_put_failure:
3394 genlmsg_cancel(msg, hdr);
3395 return err;
3396}
3397
866319bb
AV
3398static void devlink_nl_region_notify(struct devlink_region *region,
3399 struct devlink_snapshot *snapshot,
3400 enum devlink_command cmd)
3401{
3402 struct devlink *devlink = region->devlink;
3403 struct sk_buff *msg;
3404 void *hdr;
3405 int err;
3406
3407 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3408
3409 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3410 if (!msg)
3411 return;
3412
3413 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3414 if (!hdr)
3415 goto out_free_msg;
3416
3417 err = devlink_nl_put_handle(msg, devlink);
3418 if (err)
3419 goto out_cancel_msg;
3420
3421 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3422 region->name);
3423 if (err)
3424 goto out_cancel_msg;
3425
3426 if (snapshot) {
3427 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3428 snapshot->id);
3429 if (err)
3430 goto out_cancel_msg;
3431 } else {
3432 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3433 region->size, DEVLINK_ATTR_PAD);
3434 if (err)
3435 goto out_cancel_msg;
3436 }
3437 genlmsg_end(msg, hdr);
3438
3439 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3440 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3441
3442 return;
3443
3444out_cancel_msg:
3445 genlmsg_cancel(msg, hdr);
3446out_free_msg:
3447 nlmsg_free(msg);
3448}
3449
d8db7ea5
AV
3450static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3451 struct genl_info *info)
3452{
3453 struct devlink *devlink = info->user_ptr[0];
3454 struct devlink_region *region;
3455 const char *region_name;
3456 struct sk_buff *msg;
3457 int err;
3458
3459 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3460 return -EINVAL;
3461
3462 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3463 region = devlink_region_get_by_name(devlink, region_name);
3464 if (!region)
3465 return -EINVAL;
3466
3467 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3468 if (!msg)
3469 return -ENOMEM;
3470
3471 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3472 info->snd_portid, info->snd_seq, 0,
3473 region);
3474 if (err) {
3475 nlmsg_free(msg);
3476 return err;
3477 }
3478
3479 return genlmsg_reply(msg, info);
3480}
3481
3482static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3483 struct netlink_callback *cb)
3484{
3485 struct devlink_region *region;
3486 struct devlink *devlink;
3487 int start = cb->args[0];
3488 int idx = 0;
3489 int err;
3490
3491 mutex_lock(&devlink_mutex);
3492 list_for_each_entry(devlink, &devlink_list, list) {
3493 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3494 continue;
3495
3496 mutex_lock(&devlink->lock);
3497 list_for_each_entry(region, &devlink->region_list, list) {
3498 if (idx < start) {
3499 idx++;
3500 continue;
3501 }
3502 err = devlink_nl_region_fill(msg, devlink,
3503 DEVLINK_CMD_REGION_GET,
3504 NETLINK_CB(cb->skb).portid,
3505 cb->nlh->nlmsg_seq,
3506 NLM_F_MULTI, region);
3507 if (err) {
3508 mutex_unlock(&devlink->lock);
3509 goto out;
3510 }
3511 idx++;
3512 }
3513 mutex_unlock(&devlink->lock);
3514 }
3515out:
3516 mutex_unlock(&devlink_mutex);
3517 cb->args[0] = idx;
3518 return msg->len;
3519}
3520
866319bb
AV
3521static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3522 struct genl_info *info)
3523{
3524 struct devlink *devlink = info->user_ptr[0];
3525 struct devlink_snapshot *snapshot;
3526 struct devlink_region *region;
3527 const char *region_name;
3528 u32 snapshot_id;
3529
3530 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3531 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3532 return -EINVAL;
3533
3534 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3535 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3536
3537 region = devlink_region_get_by_name(devlink, region_name);
3538 if (!region)
3539 return -EINVAL;
3540
3541 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3542 if (!snapshot)
3543 return -EINVAL;
3544
3545 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3546 devlink_region_snapshot_del(snapshot);
3547 return 0;
3548}
3549
4e54795a
AV
3550static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3551 struct devlink *devlink,
3552 u8 *chunk, u32 chunk_size,
3553 u64 addr)
3554{
3555 struct nlattr *chunk_attr;
3556 int err;
3557
3558 chunk_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_CHUNK);
3559 if (!chunk_attr)
3560 return -EINVAL;
3561
3562 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3563 if (err)
3564 goto nla_put_failure;
3565
3566 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3567 DEVLINK_ATTR_PAD);
3568 if (err)
3569 goto nla_put_failure;
3570
3571 nla_nest_end(msg, chunk_attr);
3572 return 0;
3573
3574nla_put_failure:
3575 nla_nest_cancel(msg, chunk_attr);
3576 return err;
3577}
3578
3579#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3580
3581static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3582 struct devlink *devlink,
3583 struct devlink_region *region,
3584 struct nlattr **attrs,
3585 u64 start_offset,
3586 u64 end_offset,
3587 bool dump,
3588 u64 *new_offset)
3589{
3590 struct devlink_snapshot *snapshot;
3591 u64 curr_offset = start_offset;
3592 u32 snapshot_id;
3593 int err = 0;
3594
3595 *new_offset = start_offset;
3596
3597 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3598 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3599 if (!snapshot)
3600 return -EINVAL;
3601
3602 if (end_offset > snapshot->data_len || dump)
3603 end_offset = snapshot->data_len;
3604
3605 while (curr_offset < end_offset) {
3606 u32 data_size;
3607 u8 *data;
3608
3609 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3610 data_size = end_offset - curr_offset;
3611 else
3612 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3613
3614 data = &snapshot->data[curr_offset];
3615 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3616 data, data_size,
3617 curr_offset);
3618 if (err)
3619 break;
3620
3621 curr_offset += data_size;
3622 }
3623 *new_offset = curr_offset;
3624
3625 return err;
3626}
3627
3628static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3629 struct netlink_callback *cb)
3630{
3631 u64 ret_offset, start_offset, end_offset = 0;
3632 struct nlattr *attrs[DEVLINK_ATTR_MAX + 1];
3633 const struct genl_ops *ops = cb->data;
3634 struct devlink_region *region;
3635 struct nlattr *chunks_attr;
3636 const char *region_name;
3637 struct devlink *devlink;
3638 bool dump = true;
3639 void *hdr;
3640 int err;
3641
3642 start_offset = *((u64 *)&cb->args[0]);
3643
3644 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + devlink_nl_family.hdrsize,
dac9c979 3645 attrs, DEVLINK_ATTR_MAX, ops->policy, cb->extack);
4e54795a
AV
3646 if (err)
3647 goto out;
3648
3649 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
3650 if (IS_ERR(devlink))
3651 goto out;
3652
3653 mutex_lock(&devlink_mutex);
3654 mutex_lock(&devlink->lock);
3655
3656 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
3657 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3658 goto out_unlock;
3659
3660 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3661 region = devlink_region_get_by_name(devlink, region_name);
3662 if (!region)
3663 goto out_unlock;
3664
3665 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3666 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3667 DEVLINK_CMD_REGION_READ);
3668 if (!hdr)
3669 goto out_unlock;
3670
3671 err = devlink_nl_put_handle(skb, devlink);
3672 if (err)
3673 goto nla_put_failure;
3674
3675 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3676 if (err)
3677 goto nla_put_failure;
3678
3679 chunks_attr = nla_nest_start(skb, DEVLINK_ATTR_REGION_CHUNKS);
3680 if (!chunks_attr)
3681 goto nla_put_failure;
3682
3683 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3684 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3685 if (!start_offset)
3686 start_offset =
3687 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3688
3689 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3690 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3691 dump = false;
3692 }
3693
3694 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3695 region, attrs,
3696 start_offset,
3697 end_offset, dump,
3698 &ret_offset);
3699
3700 if (err && err != -EMSGSIZE)
3701 goto nla_put_failure;
3702
3703 /* Check if there was any progress done to prevent infinite loop */
3704 if (ret_offset == start_offset)
3705 goto nla_put_failure;
3706
3707 *((u64 *)&cb->args[0]) = ret_offset;
3708
3709 nla_nest_end(skb, chunks_attr);
3710 genlmsg_end(skb, hdr);
3711 mutex_unlock(&devlink->lock);
3712 mutex_unlock(&devlink_mutex);
3713
3714 return skb->len;
3715
3716nla_put_failure:
3717 genlmsg_cancel(skb, hdr);
3718out_unlock:
3719 mutex_unlock(&devlink->lock);
3720 mutex_unlock(&devlink_mutex);
3721out:
3722 return 0;
3723}
3724
f9cf2288
JK
3725struct devlink_info_req {
3726 struct sk_buff *msg;
3727};
3728
3729int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3730{
3731 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3732}
3733EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3734
3735int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3736{
3737 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3738}
3739EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3740
fc6fae7d
JK
3741static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3742 const char *version_name,
3743 const char *version_value)
3744{
3745 struct nlattr *nest;
3746 int err;
3747
3748 nest = nla_nest_start(req->msg, attr);
3749 if (!nest)
3750 return -EMSGSIZE;
3751
3752 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3753 version_name);
3754 if (err)
3755 goto nla_put_failure;
3756
3757 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3758 version_value);
3759 if (err)
3760 goto nla_put_failure;
3761
3762 nla_nest_end(req->msg, nest);
3763
3764 return 0;
3765
3766nla_put_failure:
3767 nla_nest_cancel(req->msg, nest);
3768 return err;
3769}
3770
3771int devlink_info_version_fixed_put(struct devlink_info_req *req,
3772 const char *version_name,
3773 const char *version_value)
3774{
3775 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3776 version_name, version_value);
3777}
3778EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3779
3780int devlink_info_version_stored_put(struct devlink_info_req *req,
3781 const char *version_name,
3782 const char *version_value)
3783{
3784 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3785 version_name, version_value);
3786}
3787EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3788
3789int devlink_info_version_running_put(struct devlink_info_req *req,
3790 const char *version_name,
3791 const char *version_value)
3792{
3793 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3794 version_name, version_value);
3795}
3796EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3797
f9cf2288
JK
3798static int
3799devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3800 enum devlink_command cmd, u32 portid,
3801 u32 seq, int flags, struct netlink_ext_ack *extack)
3802{
3803 struct devlink_info_req req;
3804 void *hdr;
3805 int err;
3806
3807 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3808 if (!hdr)
3809 return -EMSGSIZE;
3810
3811 err = -EMSGSIZE;
3812 if (devlink_nl_put_handle(msg, devlink))
3813 goto err_cancel_msg;
3814
3815 req.msg = msg;
3816 err = devlink->ops->info_get(devlink, &req, extack);
3817 if (err)
3818 goto err_cancel_msg;
3819
3820 genlmsg_end(msg, hdr);
3821 return 0;
3822
3823err_cancel_msg:
3824 genlmsg_cancel(msg, hdr);
3825 return err;
3826}
3827
3828static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
3829 struct genl_info *info)
3830{
3831 struct devlink *devlink = info->user_ptr[0];
3832 struct sk_buff *msg;
3833 int err;
3834
3835 if (!devlink->ops || !devlink->ops->info_get)
3836 return -EOPNOTSUPP;
3837
3838 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3839 if (!msg)
3840 return -ENOMEM;
3841
3842 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3843 info->snd_portid, info->snd_seq, 0,
3844 info->extack);
3845 if (err) {
3846 nlmsg_free(msg);
3847 return err;
3848 }
3849
3850 return genlmsg_reply(msg, info);
3851}
3852
3853static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
3854 struct netlink_callback *cb)
3855{
3856 struct devlink *devlink;
3857 int start = cb->args[0];
3858 int idx = 0;
3859 int err;
3860
3861 mutex_lock(&devlink_mutex);
3862 list_for_each_entry(devlink, &devlink_list, list) {
3863 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3864 continue;
3865 if (idx < start) {
3866 idx++;
3867 continue;
3868 }
3869
3870 mutex_lock(&devlink->lock);
3871 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3872 NETLINK_CB(cb->skb).portid,
3873 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3874 cb->extack);
3875 mutex_unlock(&devlink->lock);
3876 if (err)
3877 break;
3878 idx++;
3879 }
3880 mutex_unlock(&devlink_mutex);
3881
3882 cb->args[0] = idx;
3883 return msg->len;
3884}
3885
1db64e87
EBE
3886struct devlink_fmsg_item {
3887 struct list_head list;
3888 int attrtype;
3889 u8 nla_type;
3890 u16 len;
3891 int value[0];
3892};
3893
3894struct devlink_fmsg {
3895 struct list_head item_list;
3896};
3897
3898static struct devlink_fmsg *devlink_fmsg_alloc(void)
3899{
3900 struct devlink_fmsg *fmsg;
3901
3902 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
3903 if (!fmsg)
3904 return NULL;
3905
3906 INIT_LIST_HEAD(&fmsg->item_list);
3907
3908 return fmsg;
3909}
3910
3911static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
3912{
3913 struct devlink_fmsg_item *item, *tmp;
3914
3915 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
3916 list_del(&item->list);
3917 kfree(item);
3918 }
3919 kfree(fmsg);
3920}
3921
3922static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
3923 int attrtype)
3924{
3925 struct devlink_fmsg_item *item;
3926
3927 item = kzalloc(sizeof(*item), GFP_KERNEL);
3928 if (!item)
3929 return -ENOMEM;
3930
3931 item->attrtype = attrtype;
3932 list_add_tail(&item->list, &fmsg->item_list);
3933
3934 return 0;
3935}
3936
3937int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
3938{
3939 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
3940}
3941EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
3942
3943static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
3944{
3945 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
3946}
3947
3948int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
3949{
3950 return devlink_fmsg_nest_end(fmsg);
3951}
3952EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
3953
3954#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
3955
3956static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
3957{
3958 struct devlink_fmsg_item *item;
3959
3960 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
3961 return -EMSGSIZE;
3962
3963 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
3964 if (!item)
3965 return -ENOMEM;
3966
3967 item->nla_type = NLA_NUL_STRING;
3968 item->len = strlen(name) + 1;
3969 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
3970 memcpy(&item->value, name, item->len);
3971 list_add_tail(&item->list, &fmsg->item_list);
3972
3973 return 0;
3974}
3975
3976int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
3977{
3978 int err;
3979
3980 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
3981 if (err)
3982 return err;
3983
3984 err = devlink_fmsg_put_name(fmsg, name);
3985 if (err)
3986 return err;
3987
3988 return 0;
3989}
3990EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
3991
3992int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
3993{
3994 return devlink_fmsg_nest_end(fmsg);
3995}
3996EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
3997
3998int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
3999 const char *name)
4000{
4001 int err;
4002
4003 err = devlink_fmsg_pair_nest_start(fmsg, name);
4004 if (err)
4005 return err;
4006
4007 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4008 if (err)
4009 return err;
4010
4011 return 0;
4012}
4013EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4014
4015int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4016{
4017 int err;
4018
4019 err = devlink_fmsg_nest_end(fmsg);
4020 if (err)
4021 return err;
4022
4023 err = devlink_fmsg_nest_end(fmsg);
4024 if (err)
4025 return err;
4026
4027 return 0;
4028}
4029EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4030
4031static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4032 const void *value, u16 value_len,
4033 u8 value_nla_type)
4034{
4035 struct devlink_fmsg_item *item;
4036
4037 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4038 return -EMSGSIZE;
4039
4040 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4041 if (!item)
4042 return -ENOMEM;
4043
4044 item->nla_type = value_nla_type;
4045 item->len = value_len;
4046 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4047 memcpy(&item->value, value, item->len);
4048 list_add_tail(&item->list, &fmsg->item_list);
4049
4050 return 0;
4051}
4052
4053int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4054{
4055 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4056}
4057EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4058
4059int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4060{
4061 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4062}
4063EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4064
4065int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4066{
4067 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4068}
4069EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4070
4071int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4072{
4073 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4074}
4075EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4076
4077int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4078{
4079 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4080 NLA_NUL_STRING);
4081}
4082EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4083
4084int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4085 u16 value_len)
4086{
4087 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4088}
4089EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4090
4091int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4092 bool value)
4093{
4094 int err;
4095
4096 err = devlink_fmsg_pair_nest_start(fmsg, name);
4097 if (err)
4098 return err;
4099
4100 err = devlink_fmsg_bool_put(fmsg, value);
4101 if (err)
4102 return err;
4103
4104 err = devlink_fmsg_pair_nest_end(fmsg);
4105 if (err)
4106 return err;
4107
4108 return 0;
4109}
4110EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4111
4112int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4113 u8 value)
4114{
4115 int err;
4116
4117 err = devlink_fmsg_pair_nest_start(fmsg, name);
4118 if (err)
4119 return err;
4120
4121 err = devlink_fmsg_u8_put(fmsg, value);
4122 if (err)
4123 return err;
4124
4125 err = devlink_fmsg_pair_nest_end(fmsg);
4126 if (err)
4127 return err;
4128
4129 return 0;
4130}
4131EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4132
4133int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4134 u32 value)
4135{
4136 int err;
4137
4138 err = devlink_fmsg_pair_nest_start(fmsg, name);
4139 if (err)
4140 return err;
4141
4142 err = devlink_fmsg_u32_put(fmsg, value);
4143 if (err)
4144 return err;
4145
4146 err = devlink_fmsg_pair_nest_end(fmsg);
4147 if (err)
4148 return err;
4149
4150 return 0;
4151}
4152EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4153
4154int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4155 u64 value)
4156{
4157 int err;
4158
4159 err = devlink_fmsg_pair_nest_start(fmsg, name);
4160 if (err)
4161 return err;
4162
4163 err = devlink_fmsg_u64_put(fmsg, value);
4164 if (err)
4165 return err;
4166
4167 err = devlink_fmsg_pair_nest_end(fmsg);
4168 if (err)
4169 return err;
4170
4171 return 0;
4172}
4173EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4174
4175int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4176 const char *value)
4177{
4178 int err;
4179
4180 err = devlink_fmsg_pair_nest_start(fmsg, name);
4181 if (err)
4182 return err;
4183
4184 err = devlink_fmsg_string_put(fmsg, value);
4185 if (err)
4186 return err;
4187
4188 err = devlink_fmsg_pair_nest_end(fmsg);
4189 if (err)
4190 return err;
4191
4192 return 0;
4193}
4194EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4195
4196int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4197 const void *value, u16 value_len)
4198{
4199 int err;
4200
4201 err = devlink_fmsg_pair_nest_start(fmsg, name);
4202 if (err)
4203 return err;
4204
4205 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4206 if (err)
4207 return err;
4208
4209 err = devlink_fmsg_pair_nest_end(fmsg);
4210 if (err)
4211 return err;
4212
4213 return 0;
4214}
4215EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4216
4217static int
4218devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4219{
4220 switch (msg->nla_type) {
4221 case NLA_FLAG:
4222 case NLA_U8:
4223 case NLA_U32:
4224 case NLA_U64:
4225 case NLA_NUL_STRING:
4226 case NLA_BINARY:
4227 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4228 msg->nla_type);
4229 default:
4230 return -EINVAL;
4231 }
4232}
4233
4234static int
4235devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4236{
4237 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4238 u8 tmp;
4239
4240 switch (msg->nla_type) {
4241 case NLA_FLAG:
4242 /* Always provide flag data, regardless of its value */
4243 tmp = *(bool *) msg->value;
4244
4245 return nla_put_u8(skb, attrtype, tmp);
4246 case NLA_U8:
4247 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4248 case NLA_U32:
4249 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4250 case NLA_U64:
4251 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4252 DEVLINK_ATTR_PAD);
4253 case NLA_NUL_STRING:
4254 return nla_put_string(skb, attrtype, (char *) &msg->value);
4255 case NLA_BINARY:
4256 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4257 default:
4258 return -EINVAL;
4259 }
4260}
4261
4262static int
4263devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4264 int *start)
4265{
4266 struct devlink_fmsg_item *item;
4267 struct nlattr *fmsg_nlattr;
4268 int i = 0;
4269 int err;
4270
4271 fmsg_nlattr = nla_nest_start(skb, DEVLINK_ATTR_FMSG);
4272 if (!fmsg_nlattr)
4273 return -EMSGSIZE;
4274
4275 list_for_each_entry(item, &fmsg->item_list, list) {
4276 if (i < *start) {
4277 i++;
4278 continue;
4279 }
4280
4281 switch (item->attrtype) {
4282 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4283 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4284 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4285 case DEVLINK_ATTR_FMSG_NEST_END:
4286 err = nla_put_flag(skb, item->attrtype);
4287 break;
4288 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4289 err = devlink_fmsg_item_fill_type(item, skb);
4290 if (err)
4291 break;
4292 err = devlink_fmsg_item_fill_data(item, skb);
4293 break;
4294 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4295 err = nla_put_string(skb, item->attrtype,
4296 (char *) &item->value);
4297 break;
4298 default:
4299 err = -EINVAL;
4300 break;
4301 }
4302 if (!err)
4303 *start = ++i;
4304 else
4305 break;
4306 }
4307
4308 nla_nest_end(skb, fmsg_nlattr);
4309 return err;
4310}
4311
4312static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4313 struct genl_info *info,
4314 enum devlink_command cmd, int flags)
4315{
4316 struct nlmsghdr *nlh;
4317 struct sk_buff *skb;
4318 bool last = false;
4319 int index = 0;
4320 void *hdr;
4321 int err;
4322
4323 while (!last) {
4324 int tmp_index = index;
4325
4326 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4327 if (!skb)
4328 return -ENOMEM;
4329
4330 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4331 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4332 if (!hdr) {
4333 err = -EMSGSIZE;
4334 goto nla_put_failure;
4335 }
4336
4337 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4338 if (!err)
4339 last = true;
4340 else if (err != -EMSGSIZE || tmp_index == index)
4341 goto nla_put_failure;
4342
4343 genlmsg_end(skb, hdr);
4344 err = genlmsg_reply(skb, info);
4345 if (err)
4346 return err;
4347 }
4348
4349 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4350 if (!skb)
4351 return -ENOMEM;
4352 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4353 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4354 if (!nlh) {
4355 err = -EMSGSIZE;
4356 goto nla_put_failure;
4357 }
4358 err = genlmsg_reply(skb, info);
4359 if (err)
4360 return err;
4361
4362 return 0;
4363
4364nla_put_failure:
4365 nlmsg_free(skb);
4366 return err;
4367}
4368
a0bdcc59
EBE
4369struct devlink_health_reporter {
4370 struct list_head list;
4371 void *priv;
4372 const struct devlink_health_reporter_ops *ops;
4373 struct devlink *devlink;
c8e1da0b
EBE
4374 struct devlink_fmsg *dump_fmsg;
4375 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
a0bdcc59
EBE
4376 u64 graceful_period;
4377 bool auto_recover;
4378 u8 health_state;
c8e1da0b
EBE
4379 u64 dump_ts;
4380 u64 error_count;
4381 u64 recovery_count;
4382 u64 last_recovery_ts;
4383};
4384
4385enum devlink_health_reporter_state {
4386 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
4387 DEVLINK_HEALTH_REPORTER_STATE_ERROR,
a0bdcc59
EBE
4388};
4389
4390void *
4391devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4392{
4393 return reporter->priv;
4394}
4395EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4396
4397static struct devlink_health_reporter *
4398devlink_health_reporter_find_by_name(struct devlink *devlink,
4399 const char *reporter_name)
4400{
4401 struct devlink_health_reporter *reporter;
4402
4403 list_for_each_entry(reporter, &devlink->reporter_list, list)
4404 if (!strcmp(reporter->ops->name, reporter_name))
4405 return reporter;
4406 return NULL;
4407}
4408
4409/**
4410 * devlink_health_reporter_create - create devlink health reporter
4411 *
4412 * @devlink: devlink
4413 * @ops: ops
4414 * @graceful_period: to avoid recovery loops, in msecs
4415 * @auto_recover: auto recover when error occurs
4416 * @priv: priv
4417 */
4418struct devlink_health_reporter *
4419devlink_health_reporter_create(struct devlink *devlink,
4420 const struct devlink_health_reporter_ops *ops,
4421 u64 graceful_period, bool auto_recover,
4422 void *priv)
4423{
4424 struct devlink_health_reporter *reporter;
4425
4426 mutex_lock(&devlink->lock);
4427 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4428 reporter = ERR_PTR(-EEXIST);
4429 goto unlock;
4430 }
4431
4432 if (WARN_ON(auto_recover && !ops->recover) ||
4433 WARN_ON(graceful_period && !ops->recover)) {
4434 reporter = ERR_PTR(-EINVAL);
4435 goto unlock;
4436 }
4437
4438 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4439 if (!reporter) {
4440 reporter = ERR_PTR(-ENOMEM);
4441 goto unlock;
4442 }
4443
4444 reporter->priv = priv;
4445 reporter->ops = ops;
4446 reporter->devlink = devlink;
4447 reporter->graceful_period = graceful_period;
4448 reporter->auto_recover = auto_recover;
c8e1da0b 4449 mutex_init(&reporter->dump_lock);
a0bdcc59
EBE
4450 list_add_tail(&reporter->list, &devlink->reporter_list);
4451unlock:
4452 mutex_unlock(&devlink->lock);
4453 return reporter;
4454}
4455EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4456
4457/**
4458 * devlink_health_reporter_destroy - destroy devlink health reporter
4459 *
4460 * @reporter: devlink health reporter to destroy
4461 */
4462void
4463devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4464{
4465 mutex_lock(&reporter->devlink->lock);
4466 list_del(&reporter->list);
4467 mutex_unlock(&reporter->devlink->lock);
c8e1da0b
EBE
4468 if (reporter->dump_fmsg)
4469 devlink_fmsg_free(reporter->dump_fmsg);
a0bdcc59
EBE
4470 kfree(reporter);
4471}
4472EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4473
c8e1da0b
EBE
4474static int
4475devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4476 void *priv_ctx)
4477{
4478 int err;
4479
4480 if (!reporter->ops->recover)
4481 return -EOPNOTSUPP;
4482
4483 err = reporter->ops->recover(reporter, priv_ctx);
4484 if (err)
4485 return err;
4486
4487 reporter->recovery_count++;
4488 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4489 reporter->last_recovery_ts = jiffies;
4490
4491 return 0;
4492}
4493
4494static void
4495devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4496{
4497 if (!reporter->dump_fmsg)
4498 return;
4499 devlink_fmsg_free(reporter->dump_fmsg);
4500 reporter->dump_fmsg = NULL;
4501}
4502
4503static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4504 void *priv_ctx)
4505{
4506 int err;
4507
4508 if (!reporter->ops->dump)
4509 return 0;
4510
4511 if (reporter->dump_fmsg)
4512 return 0;
4513
4514 reporter->dump_fmsg = devlink_fmsg_alloc();
4515 if (!reporter->dump_fmsg) {
4516 err = -ENOMEM;
4517 return err;
4518 }
4519
4520 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4521 if (err)
4522 goto dump_err;
4523
4524 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4525 priv_ctx);
4526 if (err)
4527 goto dump_err;
4528
4529 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4530 if (err)
4531 goto dump_err;
4532
4533 reporter->dump_ts = jiffies;
4534
4535 return 0;
4536
4537dump_err:
4538 devlink_health_dump_clear(reporter);
4539 return err;
4540}
4541
4542int devlink_health_report(struct devlink_health_reporter *reporter,
4543 const char *msg, void *priv_ctx)
4544{
4545 struct devlink *devlink = reporter->devlink;
4546
4547 /* write a log message of the current error */
4548 WARN_ON(!msg);
4549 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4550 reporter->error_count++;
4551
4552 /* abort if the previous error wasn't recovered */
4553 if (reporter->auto_recover &&
4554 (reporter->health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
4555 jiffies - reporter->last_recovery_ts <
4556 msecs_to_jiffies(reporter->graceful_period))) {
4557 trace_devlink_health_recover_aborted(devlink,
4558 reporter->ops->name,
4559 reporter->health_state,
4560 jiffies -
4561 reporter->last_recovery_ts);
4562 return -ECANCELED;
4563 }
4564
4565 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4566
4567 mutex_lock(&reporter->dump_lock);
4568 /* store current dump of current error, for later analysis */
4569 devlink_health_do_dump(reporter, priv_ctx);
4570 mutex_unlock(&reporter->dump_lock);
4571
4572 if (reporter->auto_recover)
4573 return devlink_health_reporter_recover(reporter, priv_ctx);
4574
4575 return 0;
4576}
4577EXPORT_SYMBOL_GPL(devlink_health_report);
4578
7afe335a
EBE
4579static struct devlink_health_reporter *
4580devlink_health_reporter_get_from_info(struct devlink *devlink,
4581 struct genl_info *info)
4582{
4583 char *reporter_name;
4584
4585 if (!info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
4586 return NULL;
4587
4588 reporter_name =
4589 nla_data(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
4590 return devlink_health_reporter_find_by_name(devlink, reporter_name);
4591}
4592
4593static int
4594devlink_nl_health_reporter_fill(struct sk_buff *msg,
4595 struct devlink *devlink,
4596 struct devlink_health_reporter *reporter,
4597 enum devlink_command cmd, u32 portid,
4598 u32 seq, int flags)
4599{
4600 struct nlattr *reporter_attr;
4601 void *hdr;
4602
4603 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4604 if (!hdr)
4605 return -EMSGSIZE;
4606
4607 if (devlink_nl_put_handle(msg, devlink))
4608 goto genlmsg_cancel;
4609
4610 reporter_attr = nla_nest_start(msg, DEVLINK_ATTR_HEALTH_REPORTER);
4611 if (!reporter_attr)
4612 goto genlmsg_cancel;
4613 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4614 reporter->ops->name))
4615 goto reporter_nest_cancel;
4616 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4617 reporter->health_state))
4618 goto reporter_nest_cancel;
4619 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR,
4620 reporter->error_count, DEVLINK_ATTR_PAD))
4621 goto reporter_nest_cancel;
4622 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER,
4623 reporter->recovery_count, DEVLINK_ATTR_PAD))
4624 goto reporter_nest_cancel;
4625 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
4626 reporter->graceful_period,
4627 DEVLINK_ATTR_PAD))
4628 goto reporter_nest_cancel;
4629 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
4630 reporter->auto_recover))
4631 goto reporter_nest_cancel;
4632 if (reporter->dump_fmsg &&
4633 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4634 jiffies_to_msecs(reporter->dump_ts),
4635 DEVLINK_ATTR_PAD))
4636 goto reporter_nest_cancel;
4637
4638 nla_nest_end(msg, reporter_attr);
4639 genlmsg_end(msg, hdr);
4640 return 0;
4641
4642reporter_nest_cancel:
4643 nla_nest_end(msg, reporter_attr);
4644genlmsg_cancel:
4645 genlmsg_cancel(msg, hdr);
4646 return -EMSGSIZE;
4647}
4648
4649static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4650 struct genl_info *info)
4651{
4652 struct devlink *devlink = info->user_ptr[0];
4653 struct devlink_health_reporter *reporter;
4654 struct sk_buff *msg;
4655 int err;
4656
4657 reporter = devlink_health_reporter_get_from_info(devlink, info);
4658 if (!reporter)
4659 return -EINVAL;
4660
4661 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4662 if (!msg)
4663 return -ENOMEM;
4664
4665 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4666 DEVLINK_CMD_HEALTH_REPORTER_GET,
4667 info->snd_portid, info->snd_seq,
4668 0);
4669 if (err) {
4670 nlmsg_free(msg);
4671 return err;
4672 }
4673
4674 return genlmsg_reply(msg, info);
4675}
4676
4677static int
4678devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4679 struct netlink_callback *cb)
4680{
4681 struct devlink_health_reporter *reporter;
4682 struct devlink *devlink;
4683 int start = cb->args[0];
4684 int idx = 0;
4685 int err;
4686
4687 mutex_lock(&devlink_mutex);
4688 list_for_each_entry(devlink, &devlink_list, list) {
4689 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4690 continue;
4691 mutex_lock(&devlink->lock);
4692 list_for_each_entry(reporter, &devlink->reporter_list,
4693 list) {
4694 if (idx < start) {
4695 idx++;
4696 continue;
4697 }
4698 err = devlink_nl_health_reporter_fill(msg, devlink,
4699 reporter,
4700 DEVLINK_CMD_HEALTH_REPORTER_GET,
4701 NETLINK_CB(cb->skb).portid,
4702 cb->nlh->nlmsg_seq,
4703 NLM_F_MULTI);
4704 if (err) {
4705 mutex_unlock(&devlink->lock);
4706 goto out;
4707 }
4708 idx++;
4709 }
4710 mutex_unlock(&devlink->lock);
4711 }
4712out:
4713 mutex_unlock(&devlink_mutex);
4714
4715 cb->args[0] = idx;
4716 return msg->len;
4717}
4718
a1e55ec0
EBE
4719static int
4720devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
4721 struct genl_info *info)
4722{
4723 struct devlink *devlink = info->user_ptr[0];
4724 struct devlink_health_reporter *reporter;
4725
4726 reporter = devlink_health_reporter_get_from_info(devlink, info);
4727 if (!reporter)
4728 return -EINVAL;
4729
4730 if (!reporter->ops->recover &&
4731 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
4732 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]))
4733 return -EOPNOTSUPP;
4734
4735 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
4736 reporter->graceful_period =
4737 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
4738
4739 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
4740 reporter->auto_recover =
4741 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
4742
4743 return 0;
4744}
4745
20a0943a
EBE
4746static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
4747 struct genl_info *info)
4748{
4749 struct devlink *devlink = info->user_ptr[0];
4750 struct devlink_health_reporter *reporter;
4751
4752 reporter = devlink_health_reporter_get_from_info(devlink, info);
4753 if (!reporter)
4754 return -EINVAL;
4755
4756 return devlink_health_reporter_recover(reporter, NULL);
4757}
4758
fca42a27
EBE
4759static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
4760 struct genl_info *info)
4761{
4762 struct devlink *devlink = info->user_ptr[0];
4763 struct devlink_health_reporter *reporter;
4764 struct devlink_fmsg *fmsg;
4765 int err;
4766
4767 reporter = devlink_health_reporter_get_from_info(devlink, info);
4768 if (!reporter)
4769 return -EINVAL;
4770
4771 if (!reporter->ops->diagnose)
4772 return -EOPNOTSUPP;
4773
4774 fmsg = devlink_fmsg_alloc();
4775 if (!fmsg)
4776 return -ENOMEM;
4777
4778 err = devlink_fmsg_obj_nest_start(fmsg);
4779 if (err)
4780 goto out;
4781
4782 err = reporter->ops->diagnose(reporter, fmsg);
4783 if (err)
4784 goto out;
4785
4786 err = devlink_fmsg_obj_nest_end(fmsg);
4787 if (err)
4788 goto out;
4789
4790 err = devlink_fmsg_snd(fmsg, info,
4791 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
4792
4793out:
4794 devlink_fmsg_free(fmsg);
4795 return err;
4796}
4797
35455e23
EBE
4798static int devlink_nl_cmd_health_reporter_dump_get_doit(struct sk_buff *skb,
4799 struct genl_info *info)
4800{
4801 struct devlink *devlink = info->user_ptr[0];
4802 struct devlink_health_reporter *reporter;
4803 int err;
4804
4805 reporter = devlink_health_reporter_get_from_info(devlink, info);
4806 if (!reporter)
4807 return -EINVAL;
4808
4809 if (!reporter->ops->dump)
4810 return -EOPNOTSUPP;
4811
4812 mutex_lock(&reporter->dump_lock);
4813 err = devlink_health_do_dump(reporter, NULL);
4814 if (err)
4815 goto out;
4816
4817 err = devlink_fmsg_snd(reporter->dump_fmsg, info,
4818 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 0);
4819
4820out:
4821 mutex_unlock(&reporter->dump_lock);
4822 return err;
4823}
4824
4825static int
4826devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
4827 struct genl_info *info)
4828{
4829 struct devlink *devlink = info->user_ptr[0];
4830 struct devlink_health_reporter *reporter;
4831
4832 reporter = devlink_health_reporter_get_from_info(devlink, info);
4833 if (!reporter)
4834 return -EINVAL;
4835
4836 if (!reporter->ops->dump)
4837 return -EOPNOTSUPP;
4838
4839 mutex_lock(&reporter->dump_lock);
4840 devlink_health_dump_clear(reporter);
4841 mutex_unlock(&reporter->dump_lock);
4842 return 0;
4843}
4844
bfcd3a46
JP
4845static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
4846 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
4847 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
4848 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
4849 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
4850 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
bf797471
JP
4851 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
4852 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
4853 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
4854 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
4855 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
4856 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
4857 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
08f4b591 4858 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
59bfde01 4859 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
f43e9b06 4860 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
1555d204
AS
4861 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
4862 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
d9f9b9a4
AS
4863 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
4864 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
e3b7ca18
MS
4865 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
4866 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
4867 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
d8db7ea5 4868 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
866319bb 4869 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
7afe335a 4870 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
a1e55ec0
EBE
4871 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
4872 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
bfcd3a46
JP
4873};
4874
4875static const struct genl_ops devlink_nl_ops[] = {
4876 {
4877 .cmd = DEVLINK_CMD_GET,
4878 .doit = devlink_nl_cmd_get_doit,
4879 .dumpit = devlink_nl_cmd_get_dumpit,
4880 .policy = devlink_nl_policy,
1fc2257e 4881 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
bfcd3a46
JP
4882 /* can be retrieved by unprivileged users */
4883 },
4884 {
4885 .cmd = DEVLINK_CMD_PORT_GET,
4886 .doit = devlink_nl_cmd_port_get_doit,
4887 .dumpit = devlink_nl_cmd_port_get_dumpit,
4888 .policy = devlink_nl_policy,
4889 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4890 /* can be retrieved by unprivileged users */
4891 },
4892 {
4893 .cmd = DEVLINK_CMD_PORT_SET,
4894 .doit = devlink_nl_cmd_port_set_doit,
4895 .policy = devlink_nl_policy,
4896 .flags = GENL_ADMIN_PERM,
4897 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4898 },
4899 {
4900 .cmd = DEVLINK_CMD_PORT_SPLIT,
4901 .doit = devlink_nl_cmd_port_split_doit,
4902 .policy = devlink_nl_policy,
4903 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
4904 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4905 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46
JP
4906 },
4907 {
4908 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
4909 .doit = devlink_nl_cmd_port_unsplit_doit,
4910 .policy = devlink_nl_policy,
4911 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
4912 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4913 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46 4914 },
bf797471
JP
4915 {
4916 .cmd = DEVLINK_CMD_SB_GET,
4917 .doit = devlink_nl_cmd_sb_get_doit,
4918 .dumpit = devlink_nl_cmd_sb_get_dumpit,
4919 .policy = devlink_nl_policy,
4920 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4921 DEVLINK_NL_FLAG_NEED_SB,
4922 /* can be retrieved by unprivileged users */
4923 },
4924 {
4925 .cmd = DEVLINK_CMD_SB_POOL_GET,
4926 .doit = devlink_nl_cmd_sb_pool_get_doit,
4927 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
4928 .policy = devlink_nl_policy,
4929 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4930 DEVLINK_NL_FLAG_NEED_SB,
4931 /* can be retrieved by unprivileged users */
4932 },
4933 {
4934 .cmd = DEVLINK_CMD_SB_POOL_SET,
4935 .doit = devlink_nl_cmd_sb_pool_set_doit,
4936 .policy = devlink_nl_policy,
4937 .flags = GENL_ADMIN_PERM,
4938 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4939 DEVLINK_NL_FLAG_NEED_SB,
4940 },
4941 {
4942 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
4943 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
4944 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
4945 .policy = devlink_nl_policy,
4946 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4947 DEVLINK_NL_FLAG_NEED_SB,
4948 /* can be retrieved by unprivileged users */
4949 },
4950 {
4951 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
4952 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
4953 .policy = devlink_nl_policy,
4954 .flags = GENL_ADMIN_PERM,
4955 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4956 DEVLINK_NL_FLAG_NEED_SB,
4957 },
4958 {
4959 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
4960 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
4961 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
4962 .policy = devlink_nl_policy,
4963 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4964 DEVLINK_NL_FLAG_NEED_SB,
4965 /* can be retrieved by unprivileged users */
4966 },
4967 {
4968 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
4969 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
4970 .policy = devlink_nl_policy,
4971 .flags = GENL_ADMIN_PERM,
4972 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4973 DEVLINK_NL_FLAG_NEED_SB,
4974 },
df38dafd
JP
4975 {
4976 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
4977 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
4978 .policy = devlink_nl_policy,
4979 .flags = GENL_ADMIN_PERM,
4980 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 4981 DEVLINK_NL_FLAG_NEED_SB,
df38dafd
JP
4982 },
4983 {
4984 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
4985 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
4986 .policy = devlink_nl_policy,
4987 .flags = GENL_ADMIN_PERM,
4988 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 4989 DEVLINK_NL_FLAG_NEED_SB,
df38dafd 4990 },
08f4b591 4991 {
adf200f3
JP
4992 .cmd = DEVLINK_CMD_ESWITCH_GET,
4993 .doit = devlink_nl_cmd_eswitch_get_doit,
08f4b591
OG
4994 .policy = devlink_nl_policy,
4995 .flags = GENL_ADMIN_PERM,
4996 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4997 },
4998 {
adf200f3
JP
4999 .cmd = DEVLINK_CMD_ESWITCH_SET,
5000 .doit = devlink_nl_cmd_eswitch_set_doit,
08f4b591
OG
5001 .policy = devlink_nl_policy,
5002 .flags = GENL_ADMIN_PERM,
7ac1cc9a
JK
5003 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5004 DEVLINK_NL_FLAG_NO_LOCK,
08f4b591 5005 },
1555d204
AS
5006 {
5007 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
5008 .doit = devlink_nl_cmd_dpipe_table_get,
5009 .policy = devlink_nl_policy,
1555d204 5010 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5011 /* can be retrieved by unprivileged users */
1555d204
AS
5012 },
5013 {
5014 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
5015 .doit = devlink_nl_cmd_dpipe_entries_get,
5016 .policy = devlink_nl_policy,
1555d204 5017 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5018 /* can be retrieved by unprivileged users */
1555d204
AS
5019 },
5020 {
5021 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
5022 .doit = devlink_nl_cmd_dpipe_headers_get,
5023 .policy = devlink_nl_policy,
1555d204 5024 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5025 /* can be retrieved by unprivileged users */
1555d204
AS
5026 },
5027 {
5028 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
5029 .doit = devlink_nl_cmd_dpipe_table_counters_set,
5030 .policy = devlink_nl_policy,
5031 .flags = GENL_ADMIN_PERM,
5032 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5033 },
d9f9b9a4
AS
5034 {
5035 .cmd = DEVLINK_CMD_RESOURCE_SET,
5036 .doit = devlink_nl_cmd_resource_set,
5037 .policy = devlink_nl_policy,
5038 .flags = GENL_ADMIN_PERM,
5039 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5040 },
5041 {
5042 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
5043 .doit = devlink_nl_cmd_resource_dump,
5044 .policy = devlink_nl_policy,
d9f9b9a4 5045 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5046 /* can be retrieved by unprivileged users */
d9f9b9a4 5047 },
2d8dc5bb
AS
5048 {
5049 .cmd = DEVLINK_CMD_RELOAD,
5050 .doit = devlink_nl_cmd_reload,
5051 .policy = devlink_nl_policy,
5052 .flags = GENL_ADMIN_PERM,
5053 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5054 DEVLINK_NL_FLAG_NO_LOCK,
5055 },
45f05def
MS
5056 {
5057 .cmd = DEVLINK_CMD_PARAM_GET,
5058 .doit = devlink_nl_cmd_param_get_doit,
5059 .dumpit = devlink_nl_cmd_param_get_dumpit,
5060 .policy = devlink_nl_policy,
5061 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5062 /* can be retrieved by unprivileged users */
5063 },
e3b7ca18
MS
5064 {
5065 .cmd = DEVLINK_CMD_PARAM_SET,
5066 .doit = devlink_nl_cmd_param_set_doit,
5067 .policy = devlink_nl_policy,
5068 .flags = GENL_ADMIN_PERM,
5069 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5070 },
f4601dee
VV
5071 {
5072 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
5073 .doit = devlink_nl_cmd_port_param_get_doit,
5074 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
5075 .policy = devlink_nl_policy,
5076 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5077 /* can be retrieved by unprivileged users */
5078 },
9c54873b
VV
5079 {
5080 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
5081 .doit = devlink_nl_cmd_port_param_set_doit,
5082 .policy = devlink_nl_policy,
5083 .flags = GENL_ADMIN_PERM,
5084 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5085 },
d8db7ea5
AV
5086 {
5087 .cmd = DEVLINK_CMD_REGION_GET,
5088 .doit = devlink_nl_cmd_region_get_doit,
5089 .dumpit = devlink_nl_cmd_region_get_dumpit,
5090 .policy = devlink_nl_policy,
5091 .flags = GENL_ADMIN_PERM,
5092 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5093 },
866319bb
AV
5094 {
5095 .cmd = DEVLINK_CMD_REGION_DEL,
5096 .doit = devlink_nl_cmd_region_del,
5097 .policy = devlink_nl_policy,
5098 .flags = GENL_ADMIN_PERM,
5099 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5100 },
4e54795a
AV
5101 {
5102 .cmd = DEVLINK_CMD_REGION_READ,
5103 .dumpit = devlink_nl_cmd_region_read_dumpit,
5104 .policy = devlink_nl_policy,
5105 .flags = GENL_ADMIN_PERM,
5106 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5107 },
f9cf2288
JK
5108 {
5109 .cmd = DEVLINK_CMD_INFO_GET,
5110 .doit = devlink_nl_cmd_info_get_doit,
5111 .dumpit = devlink_nl_cmd_info_get_dumpit,
5112 .policy = devlink_nl_policy,
5113 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5114 /* can be retrieved by unprivileged users */
5115 },
7afe335a
EBE
5116 {
5117 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
5118 .doit = devlink_nl_cmd_health_reporter_get_doit,
5119 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
5120 .policy = devlink_nl_policy,
5121 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5122 /* can be retrieved by unprivileged users */
5123 },
a1e55ec0
EBE
5124 {
5125 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
5126 .doit = devlink_nl_cmd_health_reporter_set_doit,
5127 .policy = devlink_nl_policy,
5128 .flags = GENL_ADMIN_PERM,
5129 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5130 },
20a0943a
EBE
5131 {
5132 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
5133 .doit = devlink_nl_cmd_health_reporter_recover_doit,
5134 .policy = devlink_nl_policy,
5135 .flags = GENL_ADMIN_PERM,
5136 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5137 },
fca42a27
EBE
5138 {
5139 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
5140 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
5141 .policy = devlink_nl_policy,
5142 .flags = GENL_ADMIN_PERM,
5143 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5144 },
35455e23
EBE
5145 {
5146 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
5147 .doit = devlink_nl_cmd_health_reporter_dump_get_doit,
5148 .policy = devlink_nl_policy,
5149 .flags = GENL_ADMIN_PERM,
5150 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5151 DEVLINK_NL_FLAG_NO_LOCK,
5152 },
5153 {
5154 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
5155 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
5156 .policy = devlink_nl_policy,
5157 .flags = GENL_ADMIN_PERM,
5158 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5159 DEVLINK_NL_FLAG_NO_LOCK,
5160 },
bfcd3a46
JP
5161};
5162
56989f6d 5163static struct genl_family devlink_nl_family __ro_after_init = {
489111e5
JB
5164 .name = DEVLINK_GENL_NAME,
5165 .version = DEVLINK_GENL_VERSION,
5166 .maxattr = DEVLINK_ATTR_MAX,
5167 .netnsok = true,
5168 .pre_doit = devlink_nl_pre_doit,
5169 .post_doit = devlink_nl_post_doit,
5170 .module = THIS_MODULE,
5171 .ops = devlink_nl_ops,
5172 .n_ops = ARRAY_SIZE(devlink_nl_ops),
5173 .mcgrps = devlink_nl_mcgrps,
5174 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
5175};
5176
bfcd3a46
JP
5177/**
5178 * devlink_alloc - Allocate new devlink instance resources
5179 *
5180 * @ops: ops
5181 * @priv_size: size of user private data
5182 *
5183 * Allocate new devlink instance resources, including devlink index
5184 * and name.
5185 */
5186struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
5187{
5188 struct devlink *devlink;
5189
5190 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
5191 if (!devlink)
5192 return NULL;
5193 devlink->ops = ops;
5194 devlink_net_set(devlink, &init_net);
5195 INIT_LIST_HEAD(&devlink->port_list);
bf797471 5196 INIT_LIST_HEAD(&devlink->sb_list);
1555d204 5197 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
d9f9b9a4 5198 INIT_LIST_HEAD(&devlink->resource_list);
eabaef18 5199 INIT_LIST_HEAD(&devlink->param_list);
b16ebe92 5200 INIT_LIST_HEAD(&devlink->region_list);
a0bdcc59 5201 INIT_LIST_HEAD(&devlink->reporter_list);
2406e7e5 5202 mutex_init(&devlink->lock);
bfcd3a46
JP
5203 return devlink;
5204}
5205EXPORT_SYMBOL_GPL(devlink_alloc);
5206
5207/**
5208 * devlink_register - Register devlink instance
5209 *
5210 * @devlink: devlink
5211 */
5212int devlink_register(struct devlink *devlink, struct device *dev)
5213{
5214 mutex_lock(&devlink_mutex);
5215 devlink->dev = dev;
5216 list_add_tail(&devlink->list, &devlink_list);
5217 devlink_notify(devlink, DEVLINK_CMD_NEW);
5218 mutex_unlock(&devlink_mutex);
5219 return 0;
5220}
5221EXPORT_SYMBOL_GPL(devlink_register);
5222
5223/**
5224 * devlink_unregister - Unregister devlink instance
5225 *
5226 * @devlink: devlink
5227 */
5228void devlink_unregister(struct devlink *devlink)
5229{
5230 mutex_lock(&devlink_mutex);
5231 devlink_notify(devlink, DEVLINK_CMD_DEL);
5232 list_del(&devlink->list);
5233 mutex_unlock(&devlink_mutex);
5234}
5235EXPORT_SYMBOL_GPL(devlink_unregister);
5236
5237/**
5238 * devlink_free - Free devlink instance resources
5239 *
5240 * @devlink: devlink
5241 */
5242void devlink_free(struct devlink *devlink)
5243{
5244 kfree(devlink);
5245}
5246EXPORT_SYMBOL_GPL(devlink_free);
5247
5248/**
5249 * devlink_port_register - Register devlink port
5250 *
5251 * @devlink: devlink
5252 * @devlink_port: devlink port
5253 * @port_index
5254 *
5255 * Register devlink port with provided port index. User can use
5256 * any indexing, even hw-related one. devlink_port structure
5257 * is convenient to be embedded inside user driver private structure.
5258 * Note that the caller should take care of zeroing the devlink_port
5259 * structure.
5260 */
5261int devlink_port_register(struct devlink *devlink,
5262 struct devlink_port *devlink_port,
5263 unsigned int port_index)
5264{
2406e7e5 5265 mutex_lock(&devlink->lock);
bfcd3a46 5266 if (devlink_port_index_exists(devlink, port_index)) {
2406e7e5 5267 mutex_unlock(&devlink->lock);
bfcd3a46
JP
5268 return -EEXIST;
5269 }
5270 devlink_port->devlink = devlink;
5271 devlink_port->index = port_index;
bfcd3a46
JP
5272 devlink_port->registered = true;
5273 list_add_tail(&devlink_port->list, &devlink->port_list);
39e6160e 5274 INIT_LIST_HEAD(&devlink_port->param_list);
2406e7e5 5275 mutex_unlock(&devlink->lock);
bfcd3a46
JP
5276 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5277 return 0;
5278}
5279EXPORT_SYMBOL_GPL(devlink_port_register);
5280
5281/**
5282 * devlink_port_unregister - Unregister devlink port
5283 *
5284 * @devlink_port: devlink port
5285 */
5286void devlink_port_unregister(struct devlink_port *devlink_port)
5287{
2406e7e5
AS
5288 struct devlink *devlink = devlink_port->devlink;
5289
bfcd3a46 5290 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
2406e7e5 5291 mutex_lock(&devlink->lock);
bfcd3a46 5292 list_del(&devlink_port->list);
2406e7e5 5293 mutex_unlock(&devlink->lock);
bfcd3a46
JP
5294}
5295EXPORT_SYMBOL_GPL(devlink_port_unregister);
5296
5297static void __devlink_port_type_set(struct devlink_port *devlink_port,
5298 enum devlink_port_type type,
5299 void *type_dev)
5300{
5301 devlink_port->type = type;
5302 devlink_port->type_dev = type_dev;
5303 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5304}
5305
5306/**
5307 * devlink_port_type_eth_set - Set port type to Ethernet
5308 *
5309 * @devlink_port: devlink port
5310 * @netdev: related netdevice
5311 */
5312void devlink_port_type_eth_set(struct devlink_port *devlink_port,
5313 struct net_device *netdev)
5314{
5315 return __devlink_port_type_set(devlink_port,
5316 DEVLINK_PORT_TYPE_ETH, netdev);
5317}
5318EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
5319
5320/**
5321 * devlink_port_type_ib_set - Set port type to InfiniBand
5322 *
5323 * @devlink_port: devlink port
5324 * @ibdev: related IB device
5325 */
5326void devlink_port_type_ib_set(struct devlink_port *devlink_port,
5327 struct ib_device *ibdev)
5328{
5329 return __devlink_port_type_set(devlink_port,
5330 DEVLINK_PORT_TYPE_IB, ibdev);
5331}
5332EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
5333
5334/**
5335 * devlink_port_type_clear - Clear port type
5336 *
5337 * @devlink_port: devlink port
5338 */
5339void devlink_port_type_clear(struct devlink_port *devlink_port)
5340{
5341 return __devlink_port_type_set(devlink_port,
5342 DEVLINK_PORT_TYPE_NOTSET, NULL);
5343}
5344EXPORT_SYMBOL_GPL(devlink_port_type_clear);
5345
5346/**
b9ffcbaf 5347 * devlink_port_attrs_set - Set port attributes
bfcd3a46
JP
5348 *
5349 * @devlink_port: devlink port
5ec1380a 5350 * @flavour: flavour of the port
b9ffcbaf
JP
5351 * @port_number: number of the port that is facing user, for example
5352 * the front panel port number
5353 * @split: indicates if this is split port
5354 * @split_subport_number: if the port is split, this is the number
5355 * of subport.
bfcd3a46 5356 */
b9ffcbaf 5357void devlink_port_attrs_set(struct devlink_port *devlink_port,
5ec1380a 5358 enum devlink_port_flavour flavour,
b9ffcbaf
JP
5359 u32 port_number, bool split,
5360 u32 split_subport_number)
bfcd3a46 5361{
b9ffcbaf
JP
5362 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5363
5364 attrs->set = true;
5ec1380a 5365 attrs->flavour = flavour;
b9ffcbaf
JP
5366 attrs->port_number = port_number;
5367 attrs->split = split;
5368 attrs->split_subport_number = split_subport_number;
bfcd3a46
JP
5369 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5370}
b9ffcbaf 5371EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
bfcd3a46 5372
08474c1a
JP
5373int devlink_port_get_phys_port_name(struct devlink_port *devlink_port,
5374 char *name, size_t len)
5375{
5376 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5377 int n = 0;
5378
5379 if (!attrs->set)
5380 return -EOPNOTSUPP;
5381
5382 switch (attrs->flavour) {
5383 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
5384 if (!attrs->split)
5385 n = snprintf(name, len, "p%u", attrs->port_number);
5386 else
5387 n = snprintf(name, len, "p%us%u", attrs->port_number,
5388 attrs->split_subport_number);
5389 break;
5390 case DEVLINK_PORT_FLAVOUR_CPU:
5391 case DEVLINK_PORT_FLAVOUR_DSA:
5392 /* As CPU and DSA ports do not have a netdevice associated
5393 * case should not ever happen.
5394 */
5395 WARN_ON(1);
5396 return -EINVAL;
5397 }
5398
5399 if (n >= len)
5400 return -EINVAL;
5401
5402 return 0;
5403}
5404EXPORT_SYMBOL_GPL(devlink_port_get_phys_port_name);
5405
bf797471
JP
5406int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
5407 u32 size, u16 ingress_pools_count,
5408 u16 egress_pools_count, u16 ingress_tc_count,
5409 u16 egress_tc_count)
5410{
5411 struct devlink_sb *devlink_sb;
5412 int err = 0;
5413
2406e7e5 5414 mutex_lock(&devlink->lock);
bf797471
JP
5415 if (devlink_sb_index_exists(devlink, sb_index)) {
5416 err = -EEXIST;
5417 goto unlock;
5418 }
5419
5420 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
5421 if (!devlink_sb) {
5422 err = -ENOMEM;
5423 goto unlock;
5424 }
5425 devlink_sb->index = sb_index;
5426 devlink_sb->size = size;
5427 devlink_sb->ingress_pools_count = ingress_pools_count;
5428 devlink_sb->egress_pools_count = egress_pools_count;
5429 devlink_sb->ingress_tc_count = ingress_tc_count;
5430 devlink_sb->egress_tc_count = egress_tc_count;
5431 list_add_tail(&devlink_sb->list, &devlink->sb_list);
5432unlock:
2406e7e5 5433 mutex_unlock(&devlink->lock);
bf797471
JP
5434 return err;
5435}
5436EXPORT_SYMBOL_GPL(devlink_sb_register);
5437
5438void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
5439{
5440 struct devlink_sb *devlink_sb;
5441
2406e7e5 5442 mutex_lock(&devlink->lock);
bf797471
JP
5443 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
5444 WARN_ON(!devlink_sb);
5445 list_del(&devlink_sb->list);
2406e7e5 5446 mutex_unlock(&devlink->lock);
bf797471
JP
5447 kfree(devlink_sb);
5448}
5449EXPORT_SYMBOL_GPL(devlink_sb_unregister);
5450
1555d204
AS
5451/**
5452 * devlink_dpipe_headers_register - register dpipe headers
5453 *
5454 * @devlink: devlink
5455 * @dpipe_headers: dpipe header array
5456 *
5457 * Register the headers supported by hardware.
5458 */
5459int devlink_dpipe_headers_register(struct devlink *devlink,
5460 struct devlink_dpipe_headers *dpipe_headers)
5461{
2406e7e5 5462 mutex_lock(&devlink->lock);
1555d204 5463 devlink->dpipe_headers = dpipe_headers;
2406e7e5 5464 mutex_unlock(&devlink->lock);
1555d204
AS
5465 return 0;
5466}
5467EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
5468
5469/**
5470 * devlink_dpipe_headers_unregister - unregister dpipe headers
5471 *
5472 * @devlink: devlink
5473 *
5474 * Unregister the headers supported by hardware.
5475 */
5476void devlink_dpipe_headers_unregister(struct devlink *devlink)
5477{
2406e7e5 5478 mutex_lock(&devlink->lock);
1555d204 5479 devlink->dpipe_headers = NULL;
2406e7e5 5480 mutex_unlock(&devlink->lock);
1555d204
AS
5481}
5482EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
5483
5484/**
5485 * devlink_dpipe_table_counter_enabled - check if counter allocation
5486 * required
5487 * @devlink: devlink
5488 * @table_name: tables name
5489 *
5490 * Used by driver to check if counter allocation is required.
5491 * After counter allocation is turned on the table entries
5492 * are updated to include counter statistics.
5493 *
5494 * After that point on the driver must respect the counter
5495 * state so that each entry added to the table is added
5496 * with a counter.
5497 */
5498bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
5499 const char *table_name)
5500{
5501 struct devlink_dpipe_table *table;
5502 bool enabled;
5503
5504 rcu_read_lock();
5505 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5506 table_name);
5507 enabled = false;
5508 if (table)
5509 enabled = table->counters_enabled;
5510 rcu_read_unlock();
5511 return enabled;
5512}
5513EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
5514
5515/**
5516 * devlink_dpipe_table_register - register dpipe table
5517 *
5518 * @devlink: devlink
5519 * @table_name: table name
5520 * @table_ops: table ops
5521 * @priv: priv
1555d204
AS
5522 * @counter_control_extern: external control for counters
5523 */
5524int devlink_dpipe_table_register(struct devlink *devlink,
5525 const char *table_name,
5526 struct devlink_dpipe_table_ops *table_ops,
ffd3cdcc 5527 void *priv, bool counter_control_extern)
1555d204
AS
5528{
5529 struct devlink_dpipe_table *table;
5530
5531 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
5532 return -EEXIST;
5533
ffd3cdcc
AS
5534 if (WARN_ON(!table_ops->size_get))
5535 return -EINVAL;
5536
1555d204
AS
5537 table = kzalloc(sizeof(*table), GFP_KERNEL);
5538 if (!table)
5539 return -ENOMEM;
5540
5541 table->name = table_name;
5542 table->table_ops = table_ops;
5543 table->priv = priv;
1555d204
AS
5544 table->counter_control_extern = counter_control_extern;
5545
2406e7e5 5546 mutex_lock(&devlink->lock);
1555d204 5547 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
2406e7e5 5548 mutex_unlock(&devlink->lock);
1555d204
AS
5549 return 0;
5550}
5551EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
5552
5553/**
5554 * devlink_dpipe_table_unregister - unregister dpipe table
5555 *
5556 * @devlink: devlink
5557 * @table_name: table name
5558 */
5559void devlink_dpipe_table_unregister(struct devlink *devlink,
5560 const char *table_name)
5561{
5562 struct devlink_dpipe_table *table;
5563
2406e7e5 5564 mutex_lock(&devlink->lock);
1555d204
AS
5565 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5566 table_name);
5567 if (!table)
5568 goto unlock;
5569 list_del_rcu(&table->list);
2406e7e5 5570 mutex_unlock(&devlink->lock);
1555d204
AS
5571 kfree_rcu(table, rcu);
5572 return;
5573unlock:
2406e7e5 5574 mutex_unlock(&devlink->lock);
1555d204
AS
5575}
5576EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
5577
d9f9b9a4
AS
5578/**
5579 * devlink_resource_register - devlink resource register
5580 *
5581 * @devlink: devlink
5582 * @resource_name: resource's name
5583 * @top_hierarchy: top hierarchy
5584 * @reload_required: reload is required for new configuration to
5585 * apply
5586 * @resource_size: resource's size
5587 * @resource_id: resource's id
5588 * @parent_reosurce_id: resource's parent id
5589 * @size params: size parameters
d9f9b9a4
AS
5590 */
5591int devlink_resource_register(struct devlink *devlink,
5592 const char *resource_name,
d9f9b9a4
AS
5593 u64 resource_size,
5594 u64 resource_id,
5595 u64 parent_resource_id,
fc56be47 5596 const struct devlink_resource_size_params *size_params)
d9f9b9a4
AS
5597{
5598 struct devlink_resource *resource;
5599 struct list_head *resource_list;
14530746 5600 bool top_hierarchy;
d9f9b9a4
AS
5601 int err = 0;
5602
14530746
DA
5603 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
5604
d9f9b9a4
AS
5605 mutex_lock(&devlink->lock);
5606 resource = devlink_resource_find(devlink, NULL, resource_id);
5607 if (resource) {
5608 err = -EINVAL;
5609 goto out;
5610 }
5611
5612 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
5613 if (!resource) {
5614 err = -ENOMEM;
5615 goto out;
5616 }
5617
5618 if (top_hierarchy) {
5619 resource_list = &devlink->resource_list;
5620 } else {
5621 struct devlink_resource *parent_resource;
5622
5623 parent_resource = devlink_resource_find(devlink, NULL,
5624 parent_resource_id);
5625 if (parent_resource) {
5626 resource_list = &parent_resource->resource_list;
5627 resource->parent = parent_resource;
5628 } else {
b75703de 5629 kfree(resource);
d9f9b9a4
AS
5630 err = -EINVAL;
5631 goto out;
5632 }
5633 }
5634
5635 resource->name = resource_name;
5636 resource->size = resource_size;
5637 resource->size_new = resource_size;
5638 resource->id = resource_id;
d9f9b9a4 5639 resource->size_valid = true;
77d27096
JP
5640 memcpy(&resource->size_params, size_params,
5641 sizeof(resource->size_params));
d9f9b9a4
AS
5642 INIT_LIST_HEAD(&resource->resource_list);
5643 list_add_tail(&resource->list, resource_list);
5644out:
5645 mutex_unlock(&devlink->lock);
5646 return err;
5647}
5648EXPORT_SYMBOL_GPL(devlink_resource_register);
5649
5650/**
5651 * devlink_resources_unregister - free all resources
5652 *
5653 * @devlink: devlink
5654 * @resource: resource
5655 */
5656void devlink_resources_unregister(struct devlink *devlink,
5657 struct devlink_resource *resource)
5658{
5659 struct devlink_resource *tmp, *child_resource;
5660 struct list_head *resource_list;
5661
5662 if (resource)
5663 resource_list = &resource->resource_list;
5664 else
5665 resource_list = &devlink->resource_list;
5666
5667 if (!resource)
5668 mutex_lock(&devlink->lock);
5669
5670 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
5671 devlink_resources_unregister(devlink, child_resource);
5672 list_del(&child_resource->list);
5673 kfree(child_resource);
5674 }
5675
5676 if (!resource)
5677 mutex_unlock(&devlink->lock);
5678}
5679EXPORT_SYMBOL_GPL(devlink_resources_unregister);
5680
5681/**
5682 * devlink_resource_size_get - get and update size
5683 *
5684 * @devlink: devlink
5685 * @resource_id: the requested resource id
5686 * @p_resource_size: ptr to update
5687 */
5688int devlink_resource_size_get(struct devlink *devlink,
5689 u64 resource_id,
5690 u64 *p_resource_size)
5691{
5692 struct devlink_resource *resource;
5693 int err = 0;
5694
5695 mutex_lock(&devlink->lock);
5696 resource = devlink_resource_find(devlink, NULL, resource_id);
5697 if (!resource) {
5698 err = -EINVAL;
5699 goto out;
5700 }
5701 *p_resource_size = resource->size_new;
5702 resource->size = resource->size_new;
5703out:
5704 mutex_unlock(&devlink->lock);
5705 return err;
5706}
5707EXPORT_SYMBOL_GPL(devlink_resource_size_get);
5708
56dc7cd0
AS
5709/**
5710 * devlink_dpipe_table_resource_set - set the resource id
5711 *
5712 * @devlink: devlink
5713 * @table_name: table name
5714 * @resource_id: resource id
5715 * @resource_units: number of resource's units consumed per table's entry
5716 */
5717int devlink_dpipe_table_resource_set(struct devlink *devlink,
5718 const char *table_name, u64 resource_id,
5719 u64 resource_units)
5720{
5721 struct devlink_dpipe_table *table;
5722 int err = 0;
5723
5724 mutex_lock(&devlink->lock);
5725 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5726 table_name);
5727 if (!table) {
5728 err = -EINVAL;
5729 goto out;
5730 }
5731 table->resource_id = resource_id;
5732 table->resource_units = resource_units;
5733 table->resource_valid = true;
5734out:
5735 mutex_unlock(&devlink->lock);
5736 return err;
5737}
5738EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
5739
fc56be47
JP
5740/**
5741 * devlink_resource_occ_get_register - register occupancy getter
5742 *
5743 * @devlink: devlink
5744 * @resource_id: resource id
5745 * @occ_get: occupancy getter callback
5746 * @occ_get_priv: occupancy getter callback priv
5747 */
5748void devlink_resource_occ_get_register(struct devlink *devlink,
5749 u64 resource_id,
5750 devlink_resource_occ_get_t *occ_get,
5751 void *occ_get_priv)
5752{
5753 struct devlink_resource *resource;
5754
5755 mutex_lock(&devlink->lock);
5756 resource = devlink_resource_find(devlink, NULL, resource_id);
5757 if (WARN_ON(!resource))
5758 goto out;
5759 WARN_ON(resource->occ_get);
5760
5761 resource->occ_get = occ_get;
5762 resource->occ_get_priv = occ_get_priv;
5763out:
5764 mutex_unlock(&devlink->lock);
5765}
5766EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
5767
5768/**
5769 * devlink_resource_occ_get_unregister - unregister occupancy getter
5770 *
5771 * @devlink: devlink
5772 * @resource_id: resource id
5773 */
5774void devlink_resource_occ_get_unregister(struct devlink *devlink,
5775 u64 resource_id)
5776{
5777 struct devlink_resource *resource;
5778
5779 mutex_lock(&devlink->lock);
5780 resource = devlink_resource_find(devlink, NULL, resource_id);
5781 if (WARN_ON(!resource))
5782 goto out;
5783 WARN_ON(!resource->occ_get);
5784
5785 resource->occ_get = NULL;
5786 resource->occ_get_priv = NULL;
5787out:
5788 mutex_unlock(&devlink->lock);
5789}
5790EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
5791
39e6160e
VV
5792static int devlink_param_verify(const struct devlink_param *param)
5793{
5794 if (!param || !param->name || !param->supported_cmodes)
5795 return -EINVAL;
5796 if (param->generic)
5797 return devlink_param_generic_verify(param);
5798 else
5799 return devlink_param_driver_verify(param);
5800}
5801
5802static int __devlink_params_register(struct devlink *devlink,
c1e5786d 5803 unsigned int port_index,
39e6160e
VV
5804 struct list_head *param_list,
5805 const struct devlink_param *params,
c1e5786d
VV
5806 size_t params_count,
5807 enum devlink_command reg_cmd,
5808 enum devlink_command unreg_cmd)
eabaef18
MS
5809{
5810 const struct devlink_param *param = params;
5811 int i;
5812 int err;
5813
5814 mutex_lock(&devlink->lock);
5815 for (i = 0; i < params_count; i++, param++) {
39e6160e
VV
5816 err = devlink_param_verify(param);
5817 if (err)
eabaef18 5818 goto rollback;
39e6160e 5819
c1e5786d
VV
5820 err = devlink_param_register_one(devlink, port_index,
5821 param_list, param, reg_cmd);
eabaef18
MS
5822 if (err)
5823 goto rollback;
5824 }
5825
5826 mutex_unlock(&devlink->lock);
5827 return 0;
5828
5829rollback:
5830 if (!i)
5831 goto unlock;
5832 for (param--; i > 0; i--, param--)
c1e5786d
VV
5833 devlink_param_unregister_one(devlink, port_index, param_list,
5834 param, unreg_cmd);
eabaef18
MS
5835unlock:
5836 mutex_unlock(&devlink->lock);
5837 return err;
5838}
39e6160e
VV
5839
5840static void __devlink_params_unregister(struct devlink *devlink,
c1e5786d 5841 unsigned int port_index,
39e6160e
VV
5842 struct list_head *param_list,
5843 const struct devlink_param *params,
c1e5786d
VV
5844 size_t params_count,
5845 enum devlink_command cmd)
39e6160e
VV
5846{
5847 const struct devlink_param *param = params;
5848 int i;
5849
5850 mutex_lock(&devlink->lock);
5851 for (i = 0; i < params_count; i++, param++)
c1e5786d
VV
5852 devlink_param_unregister_one(devlink, 0, param_list, param,
5853 cmd);
39e6160e
VV
5854 mutex_unlock(&devlink->lock);
5855}
5856
5857/**
5858 * devlink_params_register - register configuration parameters
5859 *
5860 * @devlink: devlink
5861 * @params: configuration parameters array
5862 * @params_count: number of parameters provided
5863 *
5864 * Register the configuration parameters supported by the driver.
5865 */
5866int devlink_params_register(struct devlink *devlink,
5867 const struct devlink_param *params,
5868 size_t params_count)
5869{
c1e5786d
VV
5870 return __devlink_params_register(devlink, 0, &devlink->param_list,
5871 params, params_count,
5872 DEVLINK_CMD_PARAM_NEW,
5873 DEVLINK_CMD_PARAM_DEL);
39e6160e 5874}
eabaef18
MS
5875EXPORT_SYMBOL_GPL(devlink_params_register);
5876
5877/**
5878 * devlink_params_unregister - unregister configuration parameters
5879 * @devlink: devlink
5880 * @params: configuration parameters to unregister
5881 * @params_count: number of parameters provided
5882 */
5883void devlink_params_unregister(struct devlink *devlink,
5884 const struct devlink_param *params,
5885 size_t params_count)
5886{
c1e5786d
VV
5887 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
5888 params, params_count,
5889 DEVLINK_CMD_PARAM_DEL);
eabaef18
MS
5890}
5891EXPORT_SYMBOL_GPL(devlink_params_unregister);
5892
7c62cfb8
JP
5893/**
5894 * devlink_params_publish - publish configuration parameters
5895 *
5896 * @devlink: devlink
5897 *
5898 * Publish previously registered configuration parameters.
5899 */
5900void devlink_params_publish(struct devlink *devlink)
5901{
5902 struct devlink_param_item *param_item;
5903
5904 list_for_each_entry(param_item, &devlink->param_list, list) {
5905 if (param_item->published)
5906 continue;
5907 param_item->published = true;
5908 devlink_param_notify(devlink, 0, param_item,
5909 DEVLINK_CMD_PARAM_NEW);
5910 }
5911}
5912EXPORT_SYMBOL_GPL(devlink_params_publish);
5913
5914/**
5915 * devlink_params_unpublish - unpublish configuration parameters
5916 *
5917 * @devlink: devlink
5918 *
5919 * Unpublish previously registered configuration parameters.
5920 */
5921void devlink_params_unpublish(struct devlink *devlink)
5922{
5923 struct devlink_param_item *param_item;
5924
5925 list_for_each_entry(param_item, &devlink->param_list, list) {
5926 if (!param_item->published)
5927 continue;
5928 param_item->published = false;
5929 devlink_param_notify(devlink, 0, param_item,
5930 DEVLINK_CMD_PARAM_DEL);
5931 }
5932}
5933EXPORT_SYMBOL_GPL(devlink_params_unpublish);
5934
39e6160e
VV
5935/**
5936 * devlink_port_params_register - register port configuration parameters
5937 *
5938 * @devlink_port: devlink port
5939 * @params: configuration parameters array
5940 * @params_count: number of parameters provided
5941 *
5942 * Register the configuration parameters supported by the port.
5943 */
5944int devlink_port_params_register(struct devlink_port *devlink_port,
5945 const struct devlink_param *params,
5946 size_t params_count)
5947{
5948 return __devlink_params_register(devlink_port->devlink,
c1e5786d 5949 devlink_port->index,
39e6160e 5950 &devlink_port->param_list, params,
c1e5786d
VV
5951 params_count,
5952 DEVLINK_CMD_PORT_PARAM_NEW,
5953 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
5954}
5955EXPORT_SYMBOL_GPL(devlink_port_params_register);
5956
5957/**
5958 * devlink_port_params_unregister - unregister port configuration
5959 * parameters
5960 *
5961 * @devlink_port: devlink port
5962 * @params: configuration parameters array
5963 * @params_count: number of parameters provided
5964 */
5965void devlink_port_params_unregister(struct devlink_port *devlink_port,
5966 const struct devlink_param *params,
5967 size_t params_count)
5968{
5969 return __devlink_params_unregister(devlink_port->devlink,
c1e5786d 5970 devlink_port->index,
39e6160e 5971 &devlink_port->param_list,
c1e5786d
VV
5972 params, params_count,
5973 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
5974}
5975EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
5976
ffd19b9a
VV
5977static int
5978__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
5979 union devlink_param_value *init_val)
ec01aeb1
MS
5980{
5981 struct devlink_param_item *param_item;
5982
ffd19b9a 5983 param_item = devlink_param_find_by_id(param_list, param_id);
ec01aeb1
MS
5984 if (!param_item)
5985 return -EINVAL;
5986
5987 if (!param_item->driverinit_value_valid ||
5988 !devlink_param_cmode_is_supported(param_item->param,
5989 DEVLINK_PARAM_CMODE_DRIVERINIT))
5990 return -EOPNOTSUPP;
5991
1276534c
MS
5992 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
5993 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
5994 else
5995 *init_val = param_item->driverinit_value;
ec01aeb1
MS
5996
5997 return 0;
5998}
ffd19b9a 5999
5473a7bd
VV
6000static int
6001__devlink_param_driverinit_value_set(struct devlink *devlink,
c1e5786d 6002 unsigned int port_index,
5473a7bd
VV
6003 struct list_head *param_list, u32 param_id,
6004 union devlink_param_value init_val,
6005 enum devlink_command cmd)
6006{
6007 struct devlink_param_item *param_item;
6008
6009 param_item = devlink_param_find_by_id(param_list, param_id);
6010 if (!param_item)
6011 return -EINVAL;
6012
6013 if (!devlink_param_cmode_is_supported(param_item->param,
6014 DEVLINK_PARAM_CMODE_DRIVERINIT))
6015 return -EOPNOTSUPP;
6016
6017 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6018 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
6019 else
6020 param_item->driverinit_value = init_val;
6021 param_item->driverinit_value_valid = true;
6022
c1e5786d 6023 devlink_param_notify(devlink, port_index, param_item, cmd);
5473a7bd
VV
6024 return 0;
6025}
6026
ffd19b9a
VV
6027/**
6028 * devlink_param_driverinit_value_get - get configuration parameter
6029 * value for driver initializing
6030 *
6031 * @devlink: devlink
6032 * @param_id: parameter ID
6033 * @init_val: value of parameter in driverinit configuration mode
6034 *
6035 * This function should be used by the driver to get driverinit
6036 * configuration for initialization after reload command.
6037 */
6038int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
6039 union devlink_param_value *init_val)
6040{
6041 if (!devlink->ops || !devlink->ops->reload)
6042 return -EOPNOTSUPP;
6043
6044 return __devlink_param_driverinit_value_get(&devlink->param_list,
6045 param_id, init_val);
6046}
ec01aeb1
MS
6047EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
6048
6049/**
6050 * devlink_param_driverinit_value_set - set value of configuration
6051 * parameter for driverinit
6052 * configuration mode
6053 *
6054 * @devlink: devlink
6055 * @param_id: parameter ID
6056 * @init_val: value of parameter to set for driverinit configuration mode
6057 *
6058 * This function should be used by the driver to set driverinit
6059 * configuration mode default value.
6060 */
6061int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
6062 union devlink_param_value init_val)
6063{
c1e5786d 6064 return __devlink_param_driverinit_value_set(devlink, 0,
5473a7bd
VV
6065 &devlink->param_list,
6066 param_id, init_val,
6067 DEVLINK_CMD_PARAM_NEW);
ec01aeb1
MS
6068}
6069EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
6070
ffd19b9a
VV
6071/**
6072 * devlink_port_param_driverinit_value_get - get configuration parameter
6073 * value for driver initializing
6074 *
6075 * @devlink_port: devlink_port
6076 * @param_id: parameter ID
6077 * @init_val: value of parameter in driverinit configuration mode
6078 *
6079 * This function should be used by the driver to get driverinit
6080 * configuration for initialization after reload command.
6081 */
6082int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
6083 u32 param_id,
6084 union devlink_param_value *init_val)
6085{
6086 struct devlink *devlink = devlink_port->devlink;
6087
6088 if (!devlink->ops || !devlink->ops->reload)
6089 return -EOPNOTSUPP;
6090
6091 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
6092 param_id, init_val);
6093}
6094EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
6095
5473a7bd
VV
6096/**
6097 * devlink_port_param_driverinit_value_set - set value of configuration
6098 * parameter for driverinit
6099 * configuration mode
6100 *
6101 * @devlink_port: devlink_port
6102 * @param_id: parameter ID
6103 * @init_val: value of parameter to set for driverinit configuration mode
6104 *
6105 * This function should be used by the driver to set driverinit
6106 * configuration mode default value.
6107 */
6108int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
6109 u32 param_id,
6110 union devlink_param_value init_val)
6111{
6112 return __devlink_param_driverinit_value_set(devlink_port->devlink,
c1e5786d 6113 devlink_port->index,
5473a7bd 6114 &devlink_port->param_list,
c1e5786d
VV
6115 param_id, init_val,
6116 DEVLINK_CMD_PORT_PARAM_NEW);
5473a7bd
VV
6117}
6118EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
6119
ea601e17
MS
6120/**
6121 * devlink_param_value_changed - notify devlink on a parameter's value
6122 * change. Should be called by the driver
6123 * right after the change.
6124 *
6125 * @devlink: devlink
6126 * @param_id: parameter ID
6127 *
6128 * This function should be used by the driver to notify devlink on value
6129 * change, excluding driverinit configuration mode.
6130 * For driverinit configuration mode driver should use the function
ea601e17
MS
6131 */
6132void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
6133{
6134 struct devlink_param_item *param_item;
6135
6136 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
6137 WARN_ON(!param_item);
6138
c1e5786d 6139 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
ea601e17
MS
6140}
6141EXPORT_SYMBOL_GPL(devlink_param_value_changed);
6142
c1e5786d
VV
6143/**
6144 * devlink_port_param_value_changed - notify devlink on a parameter's value
6145 * change. Should be called by the driver
6146 * right after the change.
6147 *
6148 * @devlink_port: devlink_port
6149 * @param_id: parameter ID
6150 *
6151 * This function should be used by the driver to notify devlink on value
6152 * change, excluding driverinit configuration mode.
6153 * For driverinit configuration mode driver should use the function
6154 * devlink_port_param_driverinit_value_set() instead.
6155 */
6156void devlink_port_param_value_changed(struct devlink_port *devlink_port,
6157 u32 param_id)
6158{
6159 struct devlink_param_item *param_item;
6160
6161 param_item = devlink_param_find_by_id(&devlink_port->param_list,
6162 param_id);
6163 WARN_ON(!param_item);
6164
6165 devlink_param_notify(devlink_port->devlink, devlink_port->index,
6166 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
6167}
6168EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
6169
bde74ad1
MS
6170/**
6171 * devlink_param_value_str_fill - Safely fill-up the string preventing
6172 * from overflow of the preallocated buffer
6173 *
6174 * @dst_val: destination devlink_param_value
6175 * @src: source buffer
6176 */
6177void devlink_param_value_str_fill(union devlink_param_value *dst_val,
6178 const char *src)
6179{
6180 size_t len;
6181
6182 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
6183 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
6184}
6185EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
6186
b16ebe92
AV
6187/**
6188 * devlink_region_create - create a new address region
6189 *
6190 * @devlink: devlink
6191 * @region_name: region name
6192 * @region_max_snapshots: Maximum supported number of snapshots for region
6193 * @region_size: size of region
6194 */
6195struct devlink_region *devlink_region_create(struct devlink *devlink,
6196 const char *region_name,
6197 u32 region_max_snapshots,
6198 u64 region_size)
6199{
6200 struct devlink_region *region;
6201 int err = 0;
6202
6203 mutex_lock(&devlink->lock);
6204
6205 if (devlink_region_get_by_name(devlink, region_name)) {
6206 err = -EEXIST;
6207 goto unlock;
6208 }
6209
6210 region = kzalloc(sizeof(*region), GFP_KERNEL);
6211 if (!region) {
6212 err = -ENOMEM;
6213 goto unlock;
6214 }
6215
6216 region->devlink = devlink;
6217 region->max_snapshots = region_max_snapshots;
6218 region->name = region_name;
6219 region->size = region_size;
6220 INIT_LIST_HEAD(&region->snapshot_list);
6221 list_add_tail(&region->list, &devlink->region_list);
866319bb 6222 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
b16ebe92
AV
6223
6224 mutex_unlock(&devlink->lock);
6225 return region;
6226
6227unlock:
6228 mutex_unlock(&devlink->lock);
6229 return ERR_PTR(err);
6230}
6231EXPORT_SYMBOL_GPL(devlink_region_create);
6232
6233/**
6234 * devlink_region_destroy - destroy address region
6235 *
6236 * @region: devlink region to destroy
6237 */
6238void devlink_region_destroy(struct devlink_region *region)
6239{
6240 struct devlink *devlink = region->devlink;
d7e52722 6241 struct devlink_snapshot *snapshot, *ts;
b16ebe92
AV
6242
6243 mutex_lock(&devlink->lock);
d7e52722
AV
6244
6245 /* Free all snapshots of region */
6246 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
6247 devlink_region_snapshot_del(snapshot);
6248
b16ebe92 6249 list_del(&region->list);
866319bb
AV
6250
6251 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
b16ebe92
AV
6252 mutex_unlock(&devlink->lock);
6253 kfree(region);
6254}
6255EXPORT_SYMBOL_GPL(devlink_region_destroy);
6256
ccadfa44
AV
6257/**
6258 * devlink_region_shapshot_id_get - get snapshot ID
6259 *
6260 * This callback should be called when adding a new snapshot,
6261 * Driver should use the same id for multiple snapshots taken
6262 * on multiple regions at the same time/by the same trigger.
6263 *
6264 * @devlink: devlink
6265 */
6266u32 devlink_region_shapshot_id_get(struct devlink *devlink)
6267{
6268 u32 id;
6269
6270 mutex_lock(&devlink->lock);
6271 id = ++devlink->snapshot_id;
6272 mutex_unlock(&devlink->lock);
6273
6274 return id;
6275}
6276EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
6277
d7e52722
AV
6278/**
6279 * devlink_region_snapshot_create - create a new snapshot
6280 * This will add a new snapshot of a region. The snapshot
6281 * will be stored on the region struct and can be accessed
6282 * from devlink. This is useful for future analyses of snapshots.
6283 * Multiple snapshots can be created on a region.
6284 * The @snapshot_id should be obtained using the getter function.
6285 *
6286 * @devlink_region: devlink region of the snapshot
6287 * @data_len: size of snapshot data
6288 * @data: snapshot data
6289 * @snapshot_id: snapshot id to be created
6290 * @data_destructor: pointer to destructor function to free data
6291 */
6292int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
6293 u8 *data, u32 snapshot_id,
6294 devlink_snapshot_data_dest_t *data_destructor)
6295{
6296 struct devlink *devlink = region->devlink;
6297 struct devlink_snapshot *snapshot;
6298 int err;
6299
6300 mutex_lock(&devlink->lock);
6301
6302 /* check if region can hold one more snapshot */
6303 if (region->cur_snapshots == region->max_snapshots) {
6304 err = -ENOMEM;
6305 goto unlock;
6306 }
6307
6308 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
6309 err = -EEXIST;
6310 goto unlock;
6311 }
6312
6313 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
6314 if (!snapshot) {
6315 err = -ENOMEM;
6316 goto unlock;
6317 }
6318
6319 snapshot->id = snapshot_id;
6320 snapshot->region = region;
6321 snapshot->data = data;
6322 snapshot->data_len = data_len;
6323 snapshot->data_destructor = data_destructor;
6324
6325 list_add_tail(&snapshot->list, &region->snapshot_list);
6326
6327 region->cur_snapshots++;
6328
866319bb 6329 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
d7e52722
AV
6330 mutex_unlock(&devlink->lock);
6331 return 0;
6332
6333unlock:
6334 mutex_unlock(&devlink->lock);
6335 return err;
6336}
6337EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
6338
ddb6e99e
JK
6339static void __devlink_compat_running_version(struct devlink *devlink,
6340 char *buf, size_t len)
6341{
6342 const struct nlattr *nlattr;
6343 struct devlink_info_req req;
6344 struct sk_buff *msg;
6345 int rem, err;
6346
6347 if (!devlink->ops->info_get)
6348 return;
6349
6350 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6351 if (!msg)
6352 return;
6353
6354 req.msg = msg;
6355 err = devlink->ops->info_get(devlink, &req, NULL);
6356 if (err)
6357 goto free_msg;
6358
6359 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
6360 const struct nlattr *kv;
6361 int rem_kv;
6362
6363 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
6364 continue;
6365
6366 nla_for_each_nested(kv, nlattr, rem_kv) {
6367 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
6368 continue;
6369
6370 strlcat(buf, nla_data(kv), len);
6371 strlcat(buf, " ", len);
6372 }
6373 }
6374free_msg:
6375 nlmsg_free(msg);
6376}
6377
6378void devlink_compat_running_version(struct net_device *dev,
6379 char *buf, size_t len)
6380{
6381 struct devlink_port *devlink_port;
6382 struct devlink *devlink;
6383
6384 mutex_lock(&devlink_mutex);
6385 list_for_each_entry(devlink, &devlink_list, list) {
6386 mutex_lock(&devlink->lock);
6387 list_for_each_entry(devlink_port, &devlink->port_list, list) {
6388 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH ||
6389 devlink_port->type_dev == dev) {
6390 __devlink_compat_running_version(devlink,
6391 buf, len);
6392 mutex_unlock(&devlink->lock);
6393 goto out;
6394 }
6395 }
6396 mutex_unlock(&devlink->lock);
6397 }
6398out:
6399 mutex_unlock(&devlink_mutex);
6400}
6401
bfcd3a46
JP
6402static int __init devlink_module_init(void)
6403{
489111e5 6404 return genl_register_family(&devlink_nl_family);
bfcd3a46
JP
6405}
6406
6407static void __exit devlink_module_exit(void)
6408{
6409 genl_unregister_family(&devlink_nl_family);
6410}
6411
6412module_init(devlink_module_init);
6413module_exit(devlink_module_exit);
6414
6415MODULE_LICENSE("GPL v2");
6416MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
6417MODULE_DESCRIPTION("Network physical device Netlink interface");
6418MODULE_ALIAS_GENL_FAMILY(DEVLINK_GENL_NAME);