devlink: extend 'fw_load_policy' values
[linux-block.git] / net / core / devlink.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
bfcd3a46
JP
2/*
3 * net/core/devlink.c - Network physical/parent device Netlink interface
4 *
5 * Heavily inspired by net/wireless/
6 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
7 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
bfcd3a46
JP
8 */
9
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/slab.h>
14#include <linux/gfp.h>
15#include <linux/device.h>
16#include <linux/list.h>
17#include <linux/netdevice.h>
b8f97554 18#include <linux/spinlock.h>
b587bdaf 19#include <linux/refcount.h>
136bf27f 20#include <linux/workqueue.h>
0f420b6c
IS
21#include <linux/u64_stats_sync.h>
22#include <linux/timekeeping.h>
bfcd3a46
JP
23#include <rdma/ib_verbs.h>
24#include <net/netlink.h>
25#include <net/genetlink.h>
26#include <net/rtnetlink.h>
27#include <net/net_namespace.h>
28#include <net/sock.h>
29#include <net/devlink.h>
0f420b6c 30#include <net/drop_monitor.h>
e5224f0f
JP
31#define CREATE_TRACE_POINTS
32#include <trace/events/devlink.h>
33
11770091
AS
34static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
35 {
12bdc5e1 36 .name = "destination mac",
11770091
AS
37 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
38 .bitwidth = 48,
39 },
40};
41
42struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
43 .name = "ethernet",
44 .id = DEVLINK_DPIPE_HEADER_ETHERNET,
45 .fields = devlink_dpipe_fields_ethernet,
46 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
47 .global = true,
48};
49EXPORT_SYMBOL(devlink_dpipe_header_ethernet);
50
3fb886ec
AS
51static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
52 {
53 .name = "destination ip",
54 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
55 .bitwidth = 32,
56 },
57};
58
59struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
60 .name = "ipv4",
61 .id = DEVLINK_DPIPE_HEADER_IPV4,
62 .fields = devlink_dpipe_fields_ipv4,
63 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
64 .global = true,
65};
66EXPORT_SYMBOL(devlink_dpipe_header_ipv4);
67
1797f5b3
AS
68static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
69 {
70 .name = "destination ip",
71 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
72 .bitwidth = 128,
73 },
74};
75
76struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
77 .name = "ipv6",
78 .id = DEVLINK_DPIPE_HEADER_IPV6,
79 .fields = devlink_dpipe_fields_ipv6,
80 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
81 .global = true,
82};
83EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
84
e5224f0f 85EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
57186a5f 86EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
bfcd3a46
JP
87
88static LIST_HEAD(devlink_list);
89
90/* devlink_mutex
91 *
92 * An overall lock guarding every operation coming from userspace.
93 * It also guards devlink devices list and it is taken when
94 * driver registers/unregisters it.
95 */
96static DEFINE_MUTEX(devlink_mutex);
97
bfcd3a46
JP
98static struct net *devlink_net(const struct devlink *devlink)
99{
100 return read_pnet(&devlink->_net);
101}
102
103static void devlink_net_set(struct devlink *devlink, struct net *net)
104{
105 write_pnet(&devlink->_net, net);
106}
107
108static struct devlink *devlink_get_from_attrs(struct net *net,
109 struct nlattr **attrs)
110{
111 struct devlink *devlink;
112 char *busname;
113 char *devname;
114
115 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
116 return ERR_PTR(-EINVAL);
117
118 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
119 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
120
dac7c08f
PP
121 lockdep_assert_held(&devlink_mutex);
122
bfcd3a46
JP
123 list_for_each_entry(devlink, &devlink_list, list) {
124 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
125 strcmp(dev_name(devlink->dev), devname) == 0 &&
126 net_eq(devlink_net(devlink), net))
127 return devlink;
128 }
129
130 return ERR_PTR(-ENODEV);
131}
132
133static struct devlink *devlink_get_from_info(struct genl_info *info)
134{
135 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
136}
137
138static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
c7282b50 139 unsigned int port_index)
bfcd3a46
JP
140{
141 struct devlink_port *devlink_port;
142
143 list_for_each_entry(devlink_port, &devlink->port_list, list) {
144 if (devlink_port->index == port_index)
145 return devlink_port;
146 }
147 return NULL;
148}
149
c7282b50
PP
150static bool devlink_port_index_exists(struct devlink *devlink,
151 unsigned int port_index)
bfcd3a46
JP
152{
153 return devlink_port_get_by_index(devlink, port_index);
154}
155
156static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
157 struct nlattr **attrs)
158{
159 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
160 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
161 struct devlink_port *devlink_port;
162
163 devlink_port = devlink_port_get_by_index(devlink, port_index);
164 if (!devlink_port)
165 return ERR_PTR(-ENODEV);
166 return devlink_port;
167 }
168 return ERR_PTR(-EINVAL);
169}
170
171static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
172 struct genl_info *info)
173{
174 return devlink_port_get_from_attrs(devlink, info->attrs);
175}
176
bf797471
JP
177struct devlink_sb {
178 struct list_head list;
179 unsigned int index;
180 u32 size;
181 u16 ingress_pools_count;
182 u16 egress_pools_count;
183 u16 ingress_tc_count;
184 u16 egress_tc_count;
185};
186
187static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
188{
189 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
190}
191
192static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
193 unsigned int sb_index)
194{
195 struct devlink_sb *devlink_sb;
196
197 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
198 if (devlink_sb->index == sb_index)
199 return devlink_sb;
200 }
201 return NULL;
202}
203
204static bool devlink_sb_index_exists(struct devlink *devlink,
205 unsigned int sb_index)
206{
207 return devlink_sb_get_by_index(devlink, sb_index);
208}
209
210static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
211 struct nlattr **attrs)
212{
213 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
214 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
215 struct devlink_sb *devlink_sb;
216
217 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
218 if (!devlink_sb)
219 return ERR_PTR(-ENODEV);
220 return devlink_sb;
221 }
222 return ERR_PTR(-EINVAL);
223}
224
225static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
226 struct genl_info *info)
227{
228 return devlink_sb_get_from_attrs(devlink, info->attrs);
229}
230
231static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
232 struct nlattr **attrs,
233 u16 *p_pool_index)
234{
235 u16 val;
236
237 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
238 return -EINVAL;
239
240 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
241 if (val >= devlink_sb_pool_count(devlink_sb))
242 return -EINVAL;
243 *p_pool_index = val;
244 return 0;
245}
246
247static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
248 struct genl_info *info,
249 u16 *p_pool_index)
250{
251 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
252 p_pool_index);
253}
254
255static int
256devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
257 enum devlink_sb_pool_type *p_pool_type)
258{
259 u8 val;
260
261 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
262 return -EINVAL;
263
264 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
265 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
266 val != DEVLINK_SB_POOL_TYPE_EGRESS)
267 return -EINVAL;
268 *p_pool_type = val;
269 return 0;
270}
271
272static int
273devlink_sb_pool_type_get_from_info(struct genl_info *info,
274 enum devlink_sb_pool_type *p_pool_type)
275{
276 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
277}
278
279static int
280devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
281 enum devlink_sb_threshold_type *p_th_type)
282{
283 u8 val;
284
285 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
286 return -EINVAL;
287
288 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
289 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
290 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
291 return -EINVAL;
292 *p_th_type = val;
293 return 0;
294}
295
296static int
297devlink_sb_th_type_get_from_info(struct genl_info *info,
298 enum devlink_sb_threshold_type *p_th_type)
299{
300 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
301}
302
303static int
304devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
305 struct nlattr **attrs,
306 enum devlink_sb_pool_type pool_type,
307 u16 *p_tc_index)
308{
309 u16 val;
310
311 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
312 return -EINVAL;
313
314 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
315 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
316 val >= devlink_sb->ingress_tc_count)
317 return -EINVAL;
318 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
319 val >= devlink_sb->egress_tc_count)
320 return -EINVAL;
321 *p_tc_index = val;
322 return 0;
323}
324
325static int
326devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
327 struct genl_info *info,
328 enum devlink_sb_pool_type pool_type,
329 u16 *p_tc_index)
330{
331 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
332 pool_type, p_tc_index);
333}
334
b16ebe92
AV
335struct devlink_region {
336 struct devlink *devlink;
337 struct list_head list;
338 const char *name;
339 struct list_head snapshot_list;
340 u32 max_snapshots;
341 u32 cur_snapshots;
342 u64 size;
343};
344
d7e52722
AV
345struct devlink_snapshot {
346 struct list_head list;
347 struct devlink_region *region;
348 devlink_snapshot_data_dest_t *data_destructor;
d7e52722
AV
349 u8 *data;
350 u32 id;
351};
352
b16ebe92
AV
353static struct devlink_region *
354devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
355{
356 struct devlink_region *region;
357
358 list_for_each_entry(region, &devlink->region_list, list)
359 if (!strcmp(region->name, region_name))
360 return region;
361
362 return NULL;
363}
364
d7e52722
AV
365static struct devlink_snapshot *
366devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
367{
368 struct devlink_snapshot *snapshot;
369
370 list_for_each_entry(snapshot, &region->snapshot_list, list)
371 if (snapshot->id == id)
372 return snapshot;
373
374 return NULL;
375}
376
1fc2257e
JP
377#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
378#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
bf797471 379#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
2406e7e5
AS
380
381/* The per devlink instance lock is taken by default in the pre-doit
382 * operation, yet several commands do not require this. The global
383 * devlink lock is taken and protects from disruption by user-calls.
384 */
385#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
bfcd3a46
JP
386
387static int devlink_nl_pre_doit(const struct genl_ops *ops,
388 struct sk_buff *skb, struct genl_info *info)
389{
390 struct devlink *devlink;
2406e7e5 391 int err;
bfcd3a46
JP
392
393 mutex_lock(&devlink_mutex);
394 devlink = devlink_get_from_info(info);
395 if (IS_ERR(devlink)) {
396 mutex_unlock(&devlink_mutex);
397 return PTR_ERR(devlink);
398 }
2406e7e5
AS
399 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
400 mutex_lock(&devlink->lock);
1fc2257e
JP
401 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
402 info->user_ptr[0] = devlink;
403 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
bfcd3a46
JP
404 struct devlink_port *devlink_port;
405
bfcd3a46
JP
406 devlink_port = devlink_port_get_from_info(devlink, info);
407 if (IS_ERR(devlink_port)) {
2406e7e5
AS
408 err = PTR_ERR(devlink_port);
409 goto unlock;
bfcd3a46 410 }
1fc2257e 411 info->user_ptr[0] = devlink_port;
bfcd3a46 412 }
bf797471
JP
413 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
414 struct devlink_sb *devlink_sb;
415
416 devlink_sb = devlink_sb_get_from_info(devlink, info);
417 if (IS_ERR(devlink_sb)) {
2406e7e5
AS
418 err = PTR_ERR(devlink_sb);
419 goto unlock;
bf797471
JP
420 }
421 info->user_ptr[1] = devlink_sb;
422 }
bfcd3a46 423 return 0;
2406e7e5
AS
424
425unlock:
426 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
427 mutex_unlock(&devlink->lock);
428 mutex_unlock(&devlink_mutex);
429 return err;
bfcd3a46
JP
430}
431
432static void devlink_nl_post_doit(const struct genl_ops *ops,
433 struct sk_buff *skb, struct genl_info *info)
434{
2406e7e5
AS
435 struct devlink *devlink;
436
437 devlink = devlink_get_from_info(info);
438 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
439 mutex_unlock(&devlink->lock);
bfcd3a46
JP
440 mutex_unlock(&devlink_mutex);
441}
442
489111e5 443static struct genl_family devlink_nl_family;
bfcd3a46
JP
444
445enum devlink_multicast_groups {
446 DEVLINK_MCGRP_CONFIG,
447};
448
449static const struct genl_multicast_group devlink_nl_mcgrps[] = {
450 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
451};
452
453static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
454{
455 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
456 return -EMSGSIZE;
457 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
458 return -EMSGSIZE;
459 return 0;
460}
461
462static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
463 enum devlink_command cmd, u32 portid,
464 u32 seq, int flags)
465{
466 void *hdr;
467
468 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
469 if (!hdr)
470 return -EMSGSIZE;
471
472 if (devlink_nl_put_handle(msg, devlink))
473 goto nla_put_failure;
474
475 genlmsg_end(msg, hdr);
476 return 0;
477
478nla_put_failure:
479 genlmsg_cancel(msg, hdr);
480 return -EMSGSIZE;
481}
482
483static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
484{
485 struct sk_buff *msg;
486 int err;
487
488 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
489
490 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
491 if (!msg)
492 return;
493
494 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
495 if (err) {
496 nlmsg_free(msg);
497 return;
498 }
499
500 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
501 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
502}
503
b9ffcbaf
JP
504static int devlink_nl_port_attrs_put(struct sk_buff *msg,
505 struct devlink_port *devlink_port)
506{
507 struct devlink_port_attrs *attrs = &devlink_port->attrs;
508
509 if (!attrs->set)
510 return 0;
5ec1380a
JP
511 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
512 return -EMSGSIZE;
58b6be41
PP
513 switch (devlink_port->attrs.flavour) {
514 case DEVLINK_PORT_FLAVOUR_PCI_PF:
98fd2d65
PP
515 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
516 attrs->pci_pf.pf))
517 return -EMSGSIZE;
58b6be41
PP
518 break;
519 case DEVLINK_PORT_FLAVOUR_PCI_VF:
e41b6bf3
PP
520 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
521 attrs->pci_vf.pf) ||
522 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER,
523 attrs->pci_vf.vf))
524 return -EMSGSIZE;
58b6be41
PP
525 break;
526 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
527 case DEVLINK_PORT_FLAVOUR_CPU:
528 case DEVLINK_PORT_FLAVOUR_DSA:
529 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
530 attrs->phys.port_number))
531 return -EMSGSIZE;
532 if (!attrs->split)
533 return 0;
534 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
535 attrs->phys.port_number))
536 return -EMSGSIZE;
537 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
538 attrs->phys.split_subport_number))
539 return -EMSGSIZE;
540 break;
541 default:
542 break;
98fd2d65 543 }
b9ffcbaf
JP
544 return 0;
545}
546
bfcd3a46
JP
547static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
548 struct devlink_port *devlink_port,
549 enum devlink_command cmd, u32 portid,
550 u32 seq, int flags)
551{
552 void *hdr;
553
554 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
555 if (!hdr)
556 return -EMSGSIZE;
557
558 if (devlink_nl_put_handle(msg, devlink))
559 goto nla_put_failure;
560 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
561 goto nla_put_failure;
b8f97554 562
0f420b6c 563 spin_lock_bh(&devlink_port->type_lock);
bfcd3a46 564 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
b8f97554 565 goto nla_put_failure_type_locked;
bfcd3a46
JP
566 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
567 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
568 devlink_port->desired_type))
b8f97554 569 goto nla_put_failure_type_locked;
bfcd3a46
JP
570 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
571 struct net_device *netdev = devlink_port->type_dev;
572
573 if (netdev &&
574 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
575 netdev->ifindex) ||
576 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
577 netdev->name)))
b8f97554 578 goto nla_put_failure_type_locked;
bfcd3a46
JP
579 }
580 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
581 struct ib_device *ibdev = devlink_port->type_dev;
582
583 if (ibdev &&
584 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
585 ibdev->name))
b8f97554 586 goto nla_put_failure_type_locked;
bfcd3a46 587 }
0f420b6c 588 spin_unlock_bh(&devlink_port->type_lock);
b9ffcbaf 589 if (devlink_nl_port_attrs_put(msg, devlink_port))
bfcd3a46
JP
590 goto nla_put_failure;
591
592 genlmsg_end(msg, hdr);
593 return 0;
594
b8f97554 595nla_put_failure_type_locked:
0f420b6c 596 spin_unlock_bh(&devlink_port->type_lock);
bfcd3a46
JP
597nla_put_failure:
598 genlmsg_cancel(msg, hdr);
599 return -EMSGSIZE;
600}
601
602static void devlink_port_notify(struct devlink_port *devlink_port,
603 enum devlink_command cmd)
604{
605 struct devlink *devlink = devlink_port->devlink;
606 struct sk_buff *msg;
607 int err;
608
609 if (!devlink_port->registered)
610 return;
611
612 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
613
614 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
615 if (!msg)
616 return;
617
618 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
619 if (err) {
620 nlmsg_free(msg);
621 return;
622 }
623
624 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
625 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
626}
627
628static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
629{
630 struct devlink *devlink = info->user_ptr[0];
631 struct sk_buff *msg;
632 int err;
633
634 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
635 if (!msg)
636 return -ENOMEM;
637
638 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
639 info->snd_portid, info->snd_seq, 0);
640 if (err) {
641 nlmsg_free(msg);
642 return err;
643 }
644
645 return genlmsg_reply(msg, info);
646}
647
648static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
649 struct netlink_callback *cb)
650{
651 struct devlink *devlink;
652 int start = cb->args[0];
653 int idx = 0;
654 int err;
655
656 mutex_lock(&devlink_mutex);
657 list_for_each_entry(devlink, &devlink_list, list) {
658 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
659 continue;
660 if (idx < start) {
661 idx++;
662 continue;
663 }
664 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
665 NETLINK_CB(cb->skb).portid,
666 cb->nlh->nlmsg_seq, NLM_F_MULTI);
667 if (err)
668 goto out;
669 idx++;
670 }
671out:
672 mutex_unlock(&devlink_mutex);
673
674 cb->args[0] = idx;
675 return msg->len;
676}
677
678static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
679 struct genl_info *info)
680{
1fc2257e
JP
681 struct devlink_port *devlink_port = info->user_ptr[0];
682 struct devlink *devlink = devlink_port->devlink;
bfcd3a46
JP
683 struct sk_buff *msg;
684 int err;
685
686 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
687 if (!msg)
688 return -ENOMEM;
689
690 err = devlink_nl_port_fill(msg, devlink, devlink_port,
691 DEVLINK_CMD_PORT_NEW,
692 info->snd_portid, info->snd_seq, 0);
693 if (err) {
694 nlmsg_free(msg);
695 return err;
696 }
697
698 return genlmsg_reply(msg, info);
699}
700
701static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
702 struct netlink_callback *cb)
703{
704 struct devlink *devlink;
705 struct devlink_port *devlink_port;
706 int start = cb->args[0];
707 int idx = 0;
708 int err;
709
710 mutex_lock(&devlink_mutex);
bfcd3a46
JP
711 list_for_each_entry(devlink, &devlink_list, list) {
712 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
713 continue;
2406e7e5 714 mutex_lock(&devlink->lock);
bfcd3a46
JP
715 list_for_each_entry(devlink_port, &devlink->port_list, list) {
716 if (idx < start) {
717 idx++;
718 continue;
719 }
720 err = devlink_nl_port_fill(msg, devlink, devlink_port,
721 DEVLINK_CMD_NEW,
722 NETLINK_CB(cb->skb).portid,
723 cb->nlh->nlmsg_seq,
724 NLM_F_MULTI);
2406e7e5
AS
725 if (err) {
726 mutex_unlock(&devlink->lock);
bfcd3a46 727 goto out;
2406e7e5 728 }
bfcd3a46
JP
729 idx++;
730 }
2406e7e5 731 mutex_unlock(&devlink->lock);
bfcd3a46
JP
732 }
733out:
bfcd3a46
JP
734 mutex_unlock(&devlink_mutex);
735
736 cb->args[0] = idx;
737 return msg->len;
738}
739
740static int devlink_port_type_set(struct devlink *devlink,
741 struct devlink_port *devlink_port,
742 enum devlink_port_type port_type)
743
744{
745 int err;
746
be6fe1d8 747 if (devlink->ops->port_type_set) {
bfcd3a46
JP
748 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
749 return -EINVAL;
6edf1017
ER
750 if (port_type == devlink_port->type)
751 return 0;
bfcd3a46
JP
752 err = devlink->ops->port_type_set(devlink_port, port_type);
753 if (err)
754 return err;
755 devlink_port->desired_type = port_type;
756 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
757 return 0;
758 }
759 return -EOPNOTSUPP;
760}
761
762static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
763 struct genl_info *info)
764{
1fc2257e
JP
765 struct devlink_port *devlink_port = info->user_ptr[0];
766 struct devlink *devlink = devlink_port->devlink;
bfcd3a46
JP
767 int err;
768
769 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
770 enum devlink_port_type port_type;
771
772 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
773 err = devlink_port_type_set(devlink, devlink_port, port_type);
774 if (err)
775 return err;
776 }
777 return 0;
778}
779
ac0fc8a1
DA
780static int devlink_port_split(struct devlink *devlink, u32 port_index,
781 u32 count, struct netlink_ext_ack *extack)
bfcd3a46
JP
782
783{
be6fe1d8 784 if (devlink->ops->port_split)
ac0fc8a1
DA
785 return devlink->ops->port_split(devlink, port_index, count,
786 extack);
bfcd3a46
JP
787 return -EOPNOTSUPP;
788}
789
790static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
791 struct genl_info *info)
792{
793 struct devlink *devlink = info->user_ptr[0];
794 u32 port_index;
795 u32 count;
796
797 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
798 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
799 return -EINVAL;
800
801 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
802 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
ac0fc8a1 803 return devlink_port_split(devlink, port_index, count, info->extack);
bfcd3a46
JP
804}
805
ac0fc8a1
DA
806static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
807 struct netlink_ext_ack *extack)
bfcd3a46
JP
808
809{
be6fe1d8 810 if (devlink->ops->port_unsplit)
ac0fc8a1 811 return devlink->ops->port_unsplit(devlink, port_index, extack);
bfcd3a46
JP
812 return -EOPNOTSUPP;
813}
814
815static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
816 struct genl_info *info)
817{
818 struct devlink *devlink = info->user_ptr[0];
819 u32 port_index;
820
821 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
822 return -EINVAL;
823
824 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
ac0fc8a1 825 return devlink_port_unsplit(devlink, port_index, info->extack);
bfcd3a46
JP
826}
827
bf797471
JP
828static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
829 struct devlink_sb *devlink_sb,
830 enum devlink_command cmd, u32 portid,
831 u32 seq, int flags)
832{
833 void *hdr;
834
835 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
836 if (!hdr)
837 return -EMSGSIZE;
838
839 if (devlink_nl_put_handle(msg, devlink))
840 goto nla_put_failure;
841 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
842 goto nla_put_failure;
843 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
844 goto nla_put_failure;
845 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
846 devlink_sb->ingress_pools_count))
847 goto nla_put_failure;
848 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
849 devlink_sb->egress_pools_count))
850 goto nla_put_failure;
851 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
852 devlink_sb->ingress_tc_count))
853 goto nla_put_failure;
854 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
855 devlink_sb->egress_tc_count))
856 goto nla_put_failure;
857
858 genlmsg_end(msg, hdr);
859 return 0;
860
861nla_put_failure:
862 genlmsg_cancel(msg, hdr);
863 return -EMSGSIZE;
864}
865
866static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
867 struct genl_info *info)
868{
869 struct devlink *devlink = info->user_ptr[0];
870 struct devlink_sb *devlink_sb = info->user_ptr[1];
871 struct sk_buff *msg;
872 int err;
873
874 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
875 if (!msg)
876 return -ENOMEM;
877
878 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
879 DEVLINK_CMD_SB_NEW,
880 info->snd_portid, info->snd_seq, 0);
881 if (err) {
882 nlmsg_free(msg);
883 return err;
884 }
885
886 return genlmsg_reply(msg, info);
887}
888
889static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
890 struct netlink_callback *cb)
891{
892 struct devlink *devlink;
893 struct devlink_sb *devlink_sb;
894 int start = cb->args[0];
895 int idx = 0;
896 int err;
897
898 mutex_lock(&devlink_mutex);
899 list_for_each_entry(devlink, &devlink_list, list) {
900 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
901 continue;
2406e7e5 902 mutex_lock(&devlink->lock);
bf797471
JP
903 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
904 if (idx < start) {
905 idx++;
906 continue;
907 }
908 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
909 DEVLINK_CMD_SB_NEW,
910 NETLINK_CB(cb->skb).portid,
911 cb->nlh->nlmsg_seq,
912 NLM_F_MULTI);
2406e7e5
AS
913 if (err) {
914 mutex_unlock(&devlink->lock);
bf797471 915 goto out;
2406e7e5 916 }
bf797471
JP
917 idx++;
918 }
2406e7e5 919 mutex_unlock(&devlink->lock);
bf797471
JP
920 }
921out:
922 mutex_unlock(&devlink_mutex);
923
924 cb->args[0] = idx;
925 return msg->len;
926}
927
928static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
929 struct devlink_sb *devlink_sb,
930 u16 pool_index, enum devlink_command cmd,
931 u32 portid, u32 seq, int flags)
932{
933 struct devlink_sb_pool_info pool_info;
934 void *hdr;
935 int err;
936
937 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
938 pool_index, &pool_info);
939 if (err)
940 return err;
941
942 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
943 if (!hdr)
944 return -EMSGSIZE;
945
946 if (devlink_nl_put_handle(msg, devlink))
947 goto nla_put_failure;
948 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
949 goto nla_put_failure;
950 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
951 goto nla_put_failure;
952 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
953 goto nla_put_failure;
954 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
955 goto nla_put_failure;
956 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
957 pool_info.threshold_type))
958 goto nla_put_failure;
bff5731d
JK
959 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
960 pool_info.cell_size))
961 goto nla_put_failure;
bf797471
JP
962
963 genlmsg_end(msg, hdr);
964 return 0;
965
966nla_put_failure:
967 genlmsg_cancel(msg, hdr);
968 return -EMSGSIZE;
969}
970
971static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
972 struct genl_info *info)
973{
974 struct devlink *devlink = info->user_ptr[0];
975 struct devlink_sb *devlink_sb = info->user_ptr[1];
976 struct sk_buff *msg;
977 u16 pool_index;
978 int err;
979
980 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
981 &pool_index);
982 if (err)
983 return err;
984
be6fe1d8 985 if (!devlink->ops->sb_pool_get)
bf797471
JP
986 return -EOPNOTSUPP;
987
988 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
989 if (!msg)
990 return -ENOMEM;
991
992 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
993 DEVLINK_CMD_SB_POOL_NEW,
994 info->snd_portid, info->snd_seq, 0);
995 if (err) {
996 nlmsg_free(msg);
997 return err;
998 }
999
1000 return genlmsg_reply(msg, info);
1001}
1002
1003static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1004 struct devlink *devlink,
1005 struct devlink_sb *devlink_sb,
1006 u32 portid, u32 seq)
1007{
1008 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1009 u16 pool_index;
1010 int err;
1011
1012 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1013 if (*p_idx < start) {
1014 (*p_idx)++;
1015 continue;
1016 }
1017 err = devlink_nl_sb_pool_fill(msg, devlink,
1018 devlink_sb,
1019 pool_index,
1020 DEVLINK_CMD_SB_POOL_NEW,
1021 portid, seq, NLM_F_MULTI);
1022 if (err)
1023 return err;
1024 (*p_idx)++;
1025 }
1026 return 0;
1027}
1028
1029static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1030 struct netlink_callback *cb)
1031{
1032 struct devlink *devlink;
1033 struct devlink_sb *devlink_sb;
1034 int start = cb->args[0];
1035 int idx = 0;
1036 int err;
1037
1038 mutex_lock(&devlink_mutex);
1039 list_for_each_entry(devlink, &devlink_list, list) {
1040 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
be6fe1d8 1041 !devlink->ops->sb_pool_get)
bf797471 1042 continue;
2406e7e5 1043 mutex_lock(&devlink->lock);
bf797471
JP
1044 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1045 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1046 devlink_sb,
1047 NETLINK_CB(cb->skb).portid,
1048 cb->nlh->nlmsg_seq);
2406e7e5
AS
1049 if (err && err != -EOPNOTSUPP) {
1050 mutex_unlock(&devlink->lock);
bf797471 1051 goto out;
2406e7e5 1052 }
bf797471 1053 }
2406e7e5 1054 mutex_unlock(&devlink->lock);
bf797471
JP
1055 }
1056out:
1057 mutex_unlock(&devlink_mutex);
1058
1059 cb->args[0] = idx;
1060 return msg->len;
1061}
1062
1063static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1064 u16 pool_index, u32 size,
f2ad1a52
IS
1065 enum devlink_sb_threshold_type threshold_type,
1066 struct netlink_ext_ack *extack)
bf797471
JP
1067
1068{
1069 const struct devlink_ops *ops = devlink->ops;
1070
be6fe1d8 1071 if (ops->sb_pool_set)
bf797471 1072 return ops->sb_pool_set(devlink, sb_index, pool_index,
f2ad1a52 1073 size, threshold_type, extack);
bf797471
JP
1074 return -EOPNOTSUPP;
1075}
1076
1077static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1078 struct genl_info *info)
1079{
1080 struct devlink *devlink = info->user_ptr[0];
1081 struct devlink_sb *devlink_sb = info->user_ptr[1];
1082 enum devlink_sb_threshold_type threshold_type;
1083 u16 pool_index;
1084 u32 size;
1085 int err;
1086
1087 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1088 &pool_index);
1089 if (err)
1090 return err;
1091
1092 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1093 if (err)
1094 return err;
1095
1096 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1097 return -EINVAL;
1098
1099 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1100 return devlink_sb_pool_set(devlink, devlink_sb->index,
f2ad1a52
IS
1101 pool_index, size, threshold_type,
1102 info->extack);
bf797471
JP
1103}
1104
1105static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1106 struct devlink *devlink,
1107 struct devlink_port *devlink_port,
1108 struct devlink_sb *devlink_sb,
1109 u16 pool_index,
1110 enum devlink_command cmd,
1111 u32 portid, u32 seq, int flags)
1112{
df38dafd 1113 const struct devlink_ops *ops = devlink->ops;
bf797471
JP
1114 u32 threshold;
1115 void *hdr;
1116 int err;
1117
df38dafd
JP
1118 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1119 pool_index, &threshold);
bf797471
JP
1120 if (err)
1121 return err;
1122
1123 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1124 if (!hdr)
1125 return -EMSGSIZE;
1126
1127 if (devlink_nl_put_handle(msg, devlink))
1128 goto nla_put_failure;
1129 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1130 goto nla_put_failure;
1131 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1132 goto nla_put_failure;
1133 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1134 goto nla_put_failure;
1135 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1136 goto nla_put_failure;
1137
df38dafd
JP
1138 if (ops->sb_occ_port_pool_get) {
1139 u32 cur;
1140 u32 max;
1141
1142 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1143 pool_index, &cur, &max);
1144 if (err && err != -EOPNOTSUPP)
1145 return err;
1146 if (!err) {
1147 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1148 goto nla_put_failure;
1149 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1150 goto nla_put_failure;
1151 }
1152 }
1153
bf797471
JP
1154 genlmsg_end(msg, hdr);
1155 return 0;
1156
1157nla_put_failure:
1158 genlmsg_cancel(msg, hdr);
1159 return -EMSGSIZE;
1160}
1161
1162static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1163 struct genl_info *info)
1164{
1165 struct devlink_port *devlink_port = info->user_ptr[0];
1166 struct devlink *devlink = devlink_port->devlink;
1167 struct devlink_sb *devlink_sb = info->user_ptr[1];
1168 struct sk_buff *msg;
1169 u16 pool_index;
1170 int err;
1171
1172 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1173 &pool_index);
1174 if (err)
1175 return err;
1176
be6fe1d8 1177 if (!devlink->ops->sb_port_pool_get)
bf797471
JP
1178 return -EOPNOTSUPP;
1179
1180 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1181 if (!msg)
1182 return -ENOMEM;
1183
1184 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1185 devlink_sb, pool_index,
1186 DEVLINK_CMD_SB_PORT_POOL_NEW,
1187 info->snd_portid, info->snd_seq, 0);
1188 if (err) {
1189 nlmsg_free(msg);
1190 return err;
1191 }
1192
1193 return genlmsg_reply(msg, info);
1194}
1195
1196static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1197 struct devlink *devlink,
1198 struct devlink_sb *devlink_sb,
1199 u32 portid, u32 seq)
1200{
1201 struct devlink_port *devlink_port;
1202 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1203 u16 pool_index;
1204 int err;
1205
1206 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1207 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1208 if (*p_idx < start) {
1209 (*p_idx)++;
1210 continue;
1211 }
1212 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1213 devlink_port,
1214 devlink_sb,
1215 pool_index,
1216 DEVLINK_CMD_SB_PORT_POOL_NEW,
1217 portid, seq,
1218 NLM_F_MULTI);
1219 if (err)
1220 return err;
1221 (*p_idx)++;
1222 }
1223 }
1224 return 0;
1225}
1226
1227static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1228 struct netlink_callback *cb)
1229{
1230 struct devlink *devlink;
1231 struct devlink_sb *devlink_sb;
1232 int start = cb->args[0];
1233 int idx = 0;
1234 int err;
1235
1236 mutex_lock(&devlink_mutex);
bf797471
JP
1237 list_for_each_entry(devlink, &devlink_list, list) {
1238 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
be6fe1d8 1239 !devlink->ops->sb_port_pool_get)
bf797471 1240 continue;
2406e7e5 1241 mutex_lock(&devlink->lock);
bf797471
JP
1242 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1243 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1244 devlink, devlink_sb,
1245 NETLINK_CB(cb->skb).portid,
1246 cb->nlh->nlmsg_seq);
2406e7e5
AS
1247 if (err && err != -EOPNOTSUPP) {
1248 mutex_unlock(&devlink->lock);
bf797471 1249 goto out;
2406e7e5 1250 }
bf797471 1251 }
2406e7e5 1252 mutex_unlock(&devlink->lock);
bf797471
JP
1253 }
1254out:
bf797471
JP
1255 mutex_unlock(&devlink_mutex);
1256
1257 cb->args[0] = idx;
1258 return msg->len;
1259}
1260
1261static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1262 unsigned int sb_index, u16 pool_index,
f2ad1a52
IS
1263 u32 threshold,
1264 struct netlink_ext_ack *extack)
bf797471
JP
1265
1266{
1267 const struct devlink_ops *ops = devlink_port->devlink->ops;
1268
be6fe1d8 1269 if (ops->sb_port_pool_set)
bf797471 1270 return ops->sb_port_pool_set(devlink_port, sb_index,
f2ad1a52 1271 pool_index, threshold, extack);
bf797471
JP
1272 return -EOPNOTSUPP;
1273}
1274
1275static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1276 struct genl_info *info)
1277{
1278 struct devlink_port *devlink_port = info->user_ptr[0];
1279 struct devlink_sb *devlink_sb = info->user_ptr[1];
1280 u16 pool_index;
1281 u32 threshold;
1282 int err;
1283
1284 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1285 &pool_index);
1286 if (err)
1287 return err;
1288
1289 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1290 return -EINVAL;
1291
1292 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1293 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
f2ad1a52 1294 pool_index, threshold, info->extack);
bf797471
JP
1295}
1296
1297static int
1298devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1299 struct devlink_port *devlink_port,
1300 struct devlink_sb *devlink_sb, u16 tc_index,
1301 enum devlink_sb_pool_type pool_type,
1302 enum devlink_command cmd,
1303 u32 portid, u32 seq, int flags)
1304{
df38dafd 1305 const struct devlink_ops *ops = devlink->ops;
bf797471
JP
1306 u16 pool_index;
1307 u32 threshold;
1308 void *hdr;
1309 int err;
1310
df38dafd
JP
1311 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1312 tc_index, pool_type,
1313 &pool_index, &threshold);
bf797471
JP
1314 if (err)
1315 return err;
1316
1317 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1318 if (!hdr)
1319 return -EMSGSIZE;
1320
1321 if (devlink_nl_put_handle(msg, devlink))
1322 goto nla_put_failure;
1323 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1324 goto nla_put_failure;
1325 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1326 goto nla_put_failure;
1327 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1328 goto nla_put_failure;
1329 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1330 goto nla_put_failure;
1331 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1332 goto nla_put_failure;
1333 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1334 goto nla_put_failure;
1335
df38dafd
JP
1336 if (ops->sb_occ_tc_port_bind_get) {
1337 u32 cur;
1338 u32 max;
1339
1340 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1341 devlink_sb->index,
1342 tc_index, pool_type,
1343 &cur, &max);
1344 if (err && err != -EOPNOTSUPP)
1345 return err;
1346 if (!err) {
1347 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1348 goto nla_put_failure;
1349 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1350 goto nla_put_failure;
1351 }
1352 }
1353
bf797471
JP
1354 genlmsg_end(msg, hdr);
1355 return 0;
1356
1357nla_put_failure:
1358 genlmsg_cancel(msg, hdr);
1359 return -EMSGSIZE;
1360}
1361
1362static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1363 struct genl_info *info)
1364{
1365 struct devlink_port *devlink_port = info->user_ptr[0];
1366 struct devlink *devlink = devlink_port->devlink;
1367 struct devlink_sb *devlink_sb = info->user_ptr[1];
1368 struct sk_buff *msg;
1369 enum devlink_sb_pool_type pool_type;
1370 u16 tc_index;
1371 int err;
1372
1373 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1374 if (err)
1375 return err;
1376
1377 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1378 pool_type, &tc_index);
1379 if (err)
1380 return err;
1381
be6fe1d8 1382 if (!devlink->ops->sb_tc_pool_bind_get)
bf797471
JP
1383 return -EOPNOTSUPP;
1384
1385 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1386 if (!msg)
1387 return -ENOMEM;
1388
1389 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1390 devlink_sb, tc_index, pool_type,
1391 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1392 info->snd_portid,
1393 info->snd_seq, 0);
1394 if (err) {
1395 nlmsg_free(msg);
1396 return err;
1397 }
1398
1399 return genlmsg_reply(msg, info);
1400}
1401
1402static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1403 int start, int *p_idx,
1404 struct devlink *devlink,
1405 struct devlink_sb *devlink_sb,
1406 u32 portid, u32 seq)
1407{
1408 struct devlink_port *devlink_port;
1409 u16 tc_index;
1410 int err;
1411
1412 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1413 for (tc_index = 0;
1414 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1415 if (*p_idx < start) {
1416 (*p_idx)++;
1417 continue;
1418 }
1419 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1420 devlink_port,
1421 devlink_sb,
1422 tc_index,
1423 DEVLINK_SB_POOL_TYPE_INGRESS,
1424 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1425 portid, seq,
1426 NLM_F_MULTI);
1427 if (err)
1428 return err;
1429 (*p_idx)++;
1430 }
1431 for (tc_index = 0;
1432 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1433 if (*p_idx < start) {
1434 (*p_idx)++;
1435 continue;
1436 }
1437 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1438 devlink_port,
1439 devlink_sb,
1440 tc_index,
1441 DEVLINK_SB_POOL_TYPE_EGRESS,
1442 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1443 portid, seq,
1444 NLM_F_MULTI);
1445 if (err)
1446 return err;
1447 (*p_idx)++;
1448 }
1449 }
1450 return 0;
1451}
1452
1453static int
1454devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1455 struct netlink_callback *cb)
1456{
1457 struct devlink *devlink;
1458 struct devlink_sb *devlink_sb;
1459 int start = cb->args[0];
1460 int idx = 0;
1461 int err;
1462
1463 mutex_lock(&devlink_mutex);
bf797471
JP
1464 list_for_each_entry(devlink, &devlink_list, list) {
1465 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
be6fe1d8 1466 !devlink->ops->sb_tc_pool_bind_get)
bf797471 1467 continue;
2406e7e5
AS
1468
1469 mutex_lock(&devlink->lock);
bf797471
JP
1470 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1471 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1472 devlink,
1473 devlink_sb,
1474 NETLINK_CB(cb->skb).portid,
1475 cb->nlh->nlmsg_seq);
2406e7e5
AS
1476 if (err && err != -EOPNOTSUPP) {
1477 mutex_unlock(&devlink->lock);
bf797471 1478 goto out;
2406e7e5 1479 }
bf797471 1480 }
2406e7e5 1481 mutex_unlock(&devlink->lock);
bf797471
JP
1482 }
1483out:
bf797471
JP
1484 mutex_unlock(&devlink_mutex);
1485
1486 cb->args[0] = idx;
1487 return msg->len;
1488}
1489
1490static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1491 unsigned int sb_index, u16 tc_index,
1492 enum devlink_sb_pool_type pool_type,
f2ad1a52
IS
1493 u16 pool_index, u32 threshold,
1494 struct netlink_ext_ack *extack)
bf797471
JP
1495
1496{
1497 const struct devlink_ops *ops = devlink_port->devlink->ops;
1498
be6fe1d8 1499 if (ops->sb_tc_pool_bind_set)
bf797471
JP
1500 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1501 tc_index, pool_type,
f2ad1a52 1502 pool_index, threshold, extack);
bf797471
JP
1503 return -EOPNOTSUPP;
1504}
1505
1506static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1507 struct genl_info *info)
1508{
1509 struct devlink_port *devlink_port = info->user_ptr[0];
1510 struct devlink_sb *devlink_sb = info->user_ptr[1];
1511 enum devlink_sb_pool_type pool_type;
1512 u16 tc_index;
1513 u16 pool_index;
1514 u32 threshold;
1515 int err;
1516
1517 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1518 if (err)
1519 return err;
1520
1521 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1522 pool_type, &tc_index);
1523 if (err)
1524 return err;
1525
1526 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1527 &pool_index);
1528 if (err)
1529 return err;
1530
1531 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1532 return -EINVAL;
1533
1534 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1535 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1536 tc_index, pool_type,
f2ad1a52 1537 pool_index, threshold, info->extack);
bf797471
JP
1538}
1539
df38dafd
JP
1540static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1541 struct genl_info *info)
1542{
1543 struct devlink *devlink = info->user_ptr[0];
1544 struct devlink_sb *devlink_sb = info->user_ptr[1];
1545 const struct devlink_ops *ops = devlink->ops;
1546
be6fe1d8 1547 if (ops->sb_occ_snapshot)
df38dafd
JP
1548 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1549 return -EOPNOTSUPP;
1550}
1551
1552static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1553 struct genl_info *info)
1554{
1555 struct devlink *devlink = info->user_ptr[0];
1556 struct devlink_sb *devlink_sb = info->user_ptr[1];
1557 const struct devlink_ops *ops = devlink->ops;
1558
be6fe1d8 1559 if (ops->sb_occ_max_clear)
df38dafd
JP
1560 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1561 return -EOPNOTSUPP;
1562}
1563
21e3d2dd
JP
1564static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1565 enum devlink_command cmd, u32 portid,
1566 u32 seq, int flags)
08f4b591 1567{
59bfde01 1568 const struct devlink_ops *ops = devlink->ops;
98fdbea5
LR
1569 enum devlink_eswitch_encap_mode encap_mode;
1570 u8 inline_mode;
08f4b591 1571 void *hdr;
59bfde01
RD
1572 int err = 0;
1573 u16 mode;
08f4b591
OG
1574
1575 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1576 if (!hdr)
1577 return -EMSGSIZE;
1578
59bfde01
RD
1579 err = devlink_nl_put_handle(msg, devlink);
1580 if (err)
1a6aa36b 1581 goto nla_put_failure;
08f4b591 1582
4456f61c
JP
1583 if (ops->eswitch_mode_get) {
1584 err = ops->eswitch_mode_get(devlink, &mode);
1585 if (err)
1586 goto nla_put_failure;
1587 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1588 if (err)
1589 goto nla_put_failure;
1590 }
59bfde01
RD
1591
1592 if (ops->eswitch_inline_mode_get) {
1593 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1594 if (err)
1a6aa36b 1595 goto nla_put_failure;
59bfde01
RD
1596 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1597 inline_mode);
1598 if (err)
1a6aa36b 1599 goto nla_put_failure;
59bfde01 1600 }
08f4b591 1601
f43e9b06
RD
1602 if (ops->eswitch_encap_mode_get) {
1603 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1604 if (err)
1605 goto nla_put_failure;
1606 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1607 if (err)
1608 goto nla_put_failure;
1609 }
1610
08f4b591
OG
1611 genlmsg_end(msg, hdr);
1612 return 0;
1613
1a6aa36b 1614nla_put_failure:
08f4b591 1615 genlmsg_cancel(msg, hdr);
59bfde01 1616 return err;
08f4b591
OG
1617}
1618
adf200f3
JP
1619static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1620 struct genl_info *info)
08f4b591
OG
1621{
1622 struct devlink *devlink = info->user_ptr[0];
08f4b591 1623 struct sk_buff *msg;
08f4b591
OG
1624 int err;
1625
08f4b591
OG
1626 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1627 if (!msg)
1628 return -ENOMEM;
1629
21e3d2dd
JP
1630 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1631 info->snd_portid, info->snd_seq, 0);
08f4b591
OG
1632
1633 if (err) {
1634 nlmsg_free(msg);
1635 return err;
1636 }
1637
1638 return genlmsg_reply(msg, info);
1639}
1640
adf200f3
JP
1641static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1642 struct genl_info *info)
08f4b591
OG
1643{
1644 struct devlink *devlink = info->user_ptr[0];
1645 const struct devlink_ops *ops = devlink->ops;
98fdbea5
LR
1646 enum devlink_eswitch_encap_mode encap_mode;
1647 u8 inline_mode;
59bfde01 1648 int err = 0;
f43e9b06 1649 u16 mode;
08f4b591 1650
59bfde01
RD
1651 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1652 if (!ops->eswitch_mode_set)
1653 return -EOPNOTSUPP;
1654 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
db7ff19e 1655 err = ops->eswitch_mode_set(devlink, mode, info->extack);
59bfde01
RD
1656 if (err)
1657 return err;
1658 }
08f4b591 1659
59bfde01
RD
1660 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1661 if (!ops->eswitch_inline_mode_set)
1662 return -EOPNOTSUPP;
1663 inline_mode = nla_get_u8(
1664 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
db7ff19e
EB
1665 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1666 info->extack);
59bfde01
RD
1667 if (err)
1668 return err;
1669 }
f43e9b06
RD
1670
1671 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1672 if (!ops->eswitch_encap_mode_set)
1673 return -EOPNOTSUPP;
1674 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
db7ff19e
EB
1675 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1676 info->extack);
f43e9b06
RD
1677 if (err)
1678 return err;
1679 }
1680
1555d204
AS
1681 return 0;
1682}
1683
1684int devlink_dpipe_match_put(struct sk_buff *skb,
1685 struct devlink_dpipe_match *match)
1686{
1687 struct devlink_dpipe_header *header = match->header;
1688 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1689 struct nlattr *match_attr;
1690
ae0be8de 1691 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
1555d204
AS
1692 if (!match_attr)
1693 return -EMSGSIZE;
1694
1695 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1696 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1697 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1698 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1699 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1700 goto nla_put_failure;
1701
1702 nla_nest_end(skb, match_attr);
1703 return 0;
1704
1705nla_put_failure:
1706 nla_nest_cancel(skb, match_attr);
1707 return -EMSGSIZE;
1708}
1709EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1710
1711static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1712 struct sk_buff *skb)
1713{
1714 struct nlattr *matches_attr;
1715
ae0be8de
MK
1716 matches_attr = nla_nest_start_noflag(skb,
1717 DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
1555d204
AS
1718 if (!matches_attr)
1719 return -EMSGSIZE;
1720
1721 if (table->table_ops->matches_dump(table->priv, skb))
1722 goto nla_put_failure;
1723
1724 nla_nest_end(skb, matches_attr);
1725 return 0;
1726
1727nla_put_failure:
1728 nla_nest_cancel(skb, matches_attr);
1729 return -EMSGSIZE;
1730}
1731
1732int devlink_dpipe_action_put(struct sk_buff *skb,
1733 struct devlink_dpipe_action *action)
1734{
1735 struct devlink_dpipe_header *header = action->header;
1736 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1737 struct nlattr *action_attr;
1738
ae0be8de 1739 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
1555d204
AS
1740 if (!action_attr)
1741 return -EMSGSIZE;
1742
1743 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1744 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1745 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1746 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1747 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1748 goto nla_put_failure;
1749
1750 nla_nest_end(skb, action_attr);
1751 return 0;
1752
1753nla_put_failure:
1754 nla_nest_cancel(skb, action_attr);
1755 return -EMSGSIZE;
1756}
1757EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1758
1759static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1760 struct sk_buff *skb)
1761{
1762 struct nlattr *actions_attr;
1763
ae0be8de
MK
1764 actions_attr = nla_nest_start_noflag(skb,
1765 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
1555d204
AS
1766 if (!actions_attr)
1767 return -EMSGSIZE;
1768
1769 if (table->table_ops->actions_dump(table->priv, skb))
1770 goto nla_put_failure;
1771
1772 nla_nest_end(skb, actions_attr);
1773 return 0;
1774
1775nla_put_failure:
1776 nla_nest_cancel(skb, actions_attr);
1777 return -EMSGSIZE;
1778}
1779
1780static int devlink_dpipe_table_put(struct sk_buff *skb,
1781 struct devlink_dpipe_table *table)
1782{
1783 struct nlattr *table_attr;
ffd3cdcc 1784 u64 table_size;
1555d204 1785
ffd3cdcc 1786 table_size = table->table_ops->size_get(table->priv);
ae0be8de 1787 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
1555d204
AS
1788 if (!table_attr)
1789 return -EMSGSIZE;
1790
1791 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
ffd3cdcc 1792 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
1555d204
AS
1793 DEVLINK_ATTR_PAD))
1794 goto nla_put_failure;
1795 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1796 table->counters_enabled))
1797 goto nla_put_failure;
1798
56dc7cd0 1799 if (table->resource_valid) {
3d18e4f1
AS
1800 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1801 table->resource_id, DEVLINK_ATTR_PAD) ||
1802 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1803 table->resource_units, DEVLINK_ATTR_PAD))
1804 goto nla_put_failure;
56dc7cd0 1805 }
1555d204
AS
1806 if (devlink_dpipe_matches_put(table, skb))
1807 goto nla_put_failure;
1808
1809 if (devlink_dpipe_actions_put(table, skb))
1810 goto nla_put_failure;
1811
1812 nla_nest_end(skb, table_attr);
1813 return 0;
1814
1815nla_put_failure:
1816 nla_nest_cancel(skb, table_attr);
1817 return -EMSGSIZE;
1818}
1819
1820static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1821 struct genl_info *info)
1822{
1823 int err;
1824
1825 if (*pskb) {
1826 err = genlmsg_reply(*pskb, info);
1827 if (err)
1828 return err;
1829 }
1830 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1831 if (!*pskb)
1832 return -ENOMEM;
1833 return 0;
1834}
1835
1836static int devlink_dpipe_tables_fill(struct genl_info *info,
1837 enum devlink_command cmd, int flags,
1838 struct list_head *dpipe_tables,
1839 const char *table_name)
1840{
1841 struct devlink *devlink = info->user_ptr[0];
1842 struct devlink_dpipe_table *table;
1843 struct nlattr *tables_attr;
1844 struct sk_buff *skb = NULL;
1845 struct nlmsghdr *nlh;
1846 bool incomplete;
1847 void *hdr;
1848 int i;
1849 int err;
1850
1851 table = list_first_entry(dpipe_tables,
1852 struct devlink_dpipe_table, list);
1853start_again:
1854 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1855 if (err)
1856 return err;
1857
1858 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1859 &devlink_nl_family, NLM_F_MULTI, cmd);
6044bd4a
HY
1860 if (!hdr) {
1861 nlmsg_free(skb);
1555d204 1862 return -EMSGSIZE;
6044bd4a 1863 }
1555d204
AS
1864
1865 if (devlink_nl_put_handle(skb, devlink))
1866 goto nla_put_failure;
ae0be8de 1867 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
1555d204
AS
1868 if (!tables_attr)
1869 goto nla_put_failure;
1870
1871 i = 0;
1872 incomplete = false;
1873 list_for_each_entry_from(table, dpipe_tables, list) {
1874 if (!table_name) {
1875 err = devlink_dpipe_table_put(skb, table);
1876 if (err) {
1877 if (!i)
1878 goto err_table_put;
1879 incomplete = true;
1880 break;
1881 }
1882 } else {
1883 if (!strcmp(table->name, table_name)) {
1884 err = devlink_dpipe_table_put(skb, table);
1885 if (err)
1886 break;
1887 }
1888 }
1889 i++;
1890 }
1891
1892 nla_nest_end(skb, tables_attr);
1893 genlmsg_end(skb, hdr);
1894 if (incomplete)
1895 goto start_again;
1896
1897send_done:
1898 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1899 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1900 if (!nlh) {
1901 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1902 if (err)
7fe4d6dc 1903 return err;
1555d204
AS
1904 goto send_done;
1905 }
1906
1907 return genlmsg_reply(skb, info);
1908
1909nla_put_failure:
1910 err = -EMSGSIZE;
1911err_table_put:
1555d204
AS
1912 nlmsg_free(skb);
1913 return err;
1914}
1915
1916static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
1917 struct genl_info *info)
1918{
1919 struct devlink *devlink = info->user_ptr[0];
1920 const char *table_name = NULL;
1921
1922 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
1923 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
1924
1925 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
1926 &devlink->dpipe_table_list,
1927 table_name);
1928}
1929
1930static int devlink_dpipe_value_put(struct sk_buff *skb,
1931 struct devlink_dpipe_value *value)
1932{
1933 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
1934 value->value_size, value->value))
1935 return -EMSGSIZE;
1936 if (value->mask)
1937 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
1938 value->value_size, value->mask))
1939 return -EMSGSIZE;
1940 if (value->mapping_valid)
1941 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
1942 value->mapping_value))
1943 return -EMSGSIZE;
1944 return 0;
1945}
1946
1947static int devlink_dpipe_action_value_put(struct sk_buff *skb,
1948 struct devlink_dpipe_value *value)
1949{
1950 if (!value->action)
1951 return -EINVAL;
1952 if (devlink_dpipe_action_put(skb, value->action))
1953 return -EMSGSIZE;
1954 if (devlink_dpipe_value_put(skb, value))
1955 return -EMSGSIZE;
1956 return 0;
1957}
1958
1959static int devlink_dpipe_action_values_put(struct sk_buff *skb,
1960 struct devlink_dpipe_value *values,
1961 unsigned int values_count)
1962{
1963 struct nlattr *action_attr;
1964 int i;
1965 int err;
1966
1967 for (i = 0; i < values_count; i++) {
ae0be8de
MK
1968 action_attr = nla_nest_start_noflag(skb,
1969 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
1555d204
AS
1970 if (!action_attr)
1971 return -EMSGSIZE;
1972 err = devlink_dpipe_action_value_put(skb, &values[i]);
1973 if (err)
1974 goto err_action_value_put;
1975 nla_nest_end(skb, action_attr);
1976 }
1977 return 0;
1978
1979err_action_value_put:
1980 nla_nest_cancel(skb, action_attr);
1981 return err;
1982}
1983
1984static int devlink_dpipe_match_value_put(struct sk_buff *skb,
1985 struct devlink_dpipe_value *value)
1986{
1987 if (!value->match)
1988 return -EINVAL;
1989 if (devlink_dpipe_match_put(skb, value->match))
1990 return -EMSGSIZE;
1991 if (devlink_dpipe_value_put(skb, value))
1992 return -EMSGSIZE;
1993 return 0;
1994}
1995
1996static int devlink_dpipe_match_values_put(struct sk_buff *skb,
1997 struct devlink_dpipe_value *values,
1998 unsigned int values_count)
1999{
2000 struct nlattr *match_attr;
2001 int i;
2002 int err;
2003
2004 for (i = 0; i < values_count; i++) {
ae0be8de
MK
2005 match_attr = nla_nest_start_noflag(skb,
2006 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
1555d204
AS
2007 if (!match_attr)
2008 return -EMSGSIZE;
2009 err = devlink_dpipe_match_value_put(skb, &values[i]);
2010 if (err)
2011 goto err_match_value_put;
2012 nla_nest_end(skb, match_attr);
2013 }
2014 return 0;
2015
2016err_match_value_put:
2017 nla_nest_cancel(skb, match_attr);
2018 return err;
2019}
2020
2021static int devlink_dpipe_entry_put(struct sk_buff *skb,
2022 struct devlink_dpipe_entry *entry)
2023{
2024 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2025 int err;
2026
ae0be8de 2027 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
1555d204
AS
2028 if (!entry_attr)
2029 return -EMSGSIZE;
2030
2031 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2032 DEVLINK_ATTR_PAD))
2033 goto nla_put_failure;
2034 if (entry->counter_valid)
2035 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2036 entry->counter, DEVLINK_ATTR_PAD))
2037 goto nla_put_failure;
2038
ae0be8de
MK
2039 matches_attr = nla_nest_start_noflag(skb,
2040 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
1555d204
AS
2041 if (!matches_attr)
2042 goto nla_put_failure;
2043
2044 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2045 entry->match_values_count);
2046 if (err) {
2047 nla_nest_cancel(skb, matches_attr);
2048 goto err_match_values_put;
2049 }
2050 nla_nest_end(skb, matches_attr);
2051
ae0be8de
MK
2052 actions_attr = nla_nest_start_noflag(skb,
2053 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
1555d204
AS
2054 if (!actions_attr)
2055 goto nla_put_failure;
2056
2057 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2058 entry->action_values_count);
2059 if (err) {
2060 nla_nest_cancel(skb, actions_attr);
2061 goto err_action_values_put;
2062 }
2063 nla_nest_end(skb, actions_attr);
59bfde01 2064
1555d204 2065 nla_nest_end(skb, entry_attr);
59bfde01 2066 return 0;
1555d204
AS
2067
2068nla_put_failure:
2069 err = -EMSGSIZE;
2070err_match_values_put:
2071err_action_values_put:
2072 nla_nest_cancel(skb, entry_attr);
2073 return err;
2074}
2075
2076static struct devlink_dpipe_table *
2077devlink_dpipe_table_find(struct list_head *dpipe_tables,
2078 const char *table_name)
2079{
2080 struct devlink_dpipe_table *table;
2081
2082 list_for_each_entry_rcu(table, dpipe_tables, list) {
2083 if (!strcmp(table->name, table_name))
2084 return table;
2085 }
2086 return NULL;
2087}
2088
2089int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2090{
2091 struct devlink *devlink;
2092 int err;
2093
2094 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2095 dump_ctx->info);
2096 if (err)
2097 return err;
2098
2099 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2100 dump_ctx->info->snd_portid,
2101 dump_ctx->info->snd_seq,
2102 &devlink_nl_family, NLM_F_MULTI,
2103 dump_ctx->cmd);
2104 if (!dump_ctx->hdr)
2105 goto nla_put_failure;
2106
2107 devlink = dump_ctx->info->user_ptr[0];
2108 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2109 goto nla_put_failure;
ae0be8de
MK
2110 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2111 DEVLINK_ATTR_DPIPE_ENTRIES);
1555d204
AS
2112 if (!dump_ctx->nest)
2113 goto nla_put_failure;
2114 return 0;
2115
2116nla_put_failure:
1555d204
AS
2117 nlmsg_free(dump_ctx->skb);
2118 return -EMSGSIZE;
2119}
2120EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2121
2122int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2123 struct devlink_dpipe_entry *entry)
2124{
2125 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2126}
2127EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2128
2129int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2130{
2131 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2132 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2133 return 0;
2134}
2135EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2136
35807324
AS
2137void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2138
2139{
2140 unsigned int value_count, value_index;
2141 struct devlink_dpipe_value *value;
2142
2143 value = entry->action_values;
2144 value_count = entry->action_values_count;
2145 for (value_index = 0; value_index < value_count; value_index++) {
2146 kfree(value[value_index].value);
2147 kfree(value[value_index].mask);
2148 }
2149
2150 value = entry->match_values;
2151 value_count = entry->match_values_count;
2152 for (value_index = 0; value_index < value_count; value_index++) {
2153 kfree(value[value_index].value);
2154 kfree(value[value_index].mask);
2155 }
2156}
2157EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2158
1555d204
AS
2159static int devlink_dpipe_entries_fill(struct genl_info *info,
2160 enum devlink_command cmd, int flags,
2161 struct devlink_dpipe_table *table)
2162{
2163 struct devlink_dpipe_dump_ctx dump_ctx;
2164 struct nlmsghdr *nlh;
2165 int err;
2166
2167 dump_ctx.skb = NULL;
2168 dump_ctx.cmd = cmd;
2169 dump_ctx.info = info;
2170
2171 err = table->table_ops->entries_dump(table->priv,
2172 table->counters_enabled,
2173 &dump_ctx);
2174 if (err)
7fe4d6dc 2175 return err;
1555d204
AS
2176
2177send_done:
2178 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2179 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2180 if (!nlh) {
2181 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2182 if (err)
7fe4d6dc 2183 return err;
1555d204
AS
2184 goto send_done;
2185 }
2186 return genlmsg_reply(dump_ctx.skb, info);
1555d204
AS
2187}
2188
2189static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2190 struct genl_info *info)
2191{
2192 struct devlink *devlink = info->user_ptr[0];
2193 struct devlink_dpipe_table *table;
2194 const char *table_name;
2195
2196 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2197 return -EINVAL;
2198
2199 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2200 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2201 table_name);
2202 if (!table)
2203 return -EINVAL;
2204
2205 if (!table->table_ops->entries_dump)
2206 return -EINVAL;
2207
2208 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2209 0, table);
2210}
2211
2212static int devlink_dpipe_fields_put(struct sk_buff *skb,
2213 const struct devlink_dpipe_header *header)
2214{
2215 struct devlink_dpipe_field *field;
2216 struct nlattr *field_attr;
2217 int i;
2218
2219 for (i = 0; i < header->fields_count; i++) {
2220 field = &header->fields[i];
ae0be8de
MK
2221 field_attr = nla_nest_start_noflag(skb,
2222 DEVLINK_ATTR_DPIPE_FIELD);
1555d204
AS
2223 if (!field_attr)
2224 return -EMSGSIZE;
2225 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2226 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2227 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2228 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2229 goto nla_put_failure;
2230 nla_nest_end(skb, field_attr);
2231 }
2232 return 0;
2233
2234nla_put_failure:
2235 nla_nest_cancel(skb, field_attr);
2236 return -EMSGSIZE;
2237}
2238
2239static int devlink_dpipe_header_put(struct sk_buff *skb,
2240 struct devlink_dpipe_header *header)
2241{
2242 struct nlattr *fields_attr, *header_attr;
2243 int err;
2244
ae0be8de 2245 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
cb6bf9cf 2246 if (!header_attr)
1555d204
AS
2247 return -EMSGSIZE;
2248
2249 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2250 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2251 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2252 goto nla_put_failure;
2253
ae0be8de
MK
2254 fields_attr = nla_nest_start_noflag(skb,
2255 DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
1555d204
AS
2256 if (!fields_attr)
2257 goto nla_put_failure;
2258
2259 err = devlink_dpipe_fields_put(skb, header);
2260 if (err) {
2261 nla_nest_cancel(skb, fields_attr);
2262 goto nla_put_failure;
2263 }
2264 nla_nest_end(skb, fields_attr);
2265 nla_nest_end(skb, header_attr);
2266 return 0;
2267
2268nla_put_failure:
2269 err = -EMSGSIZE;
2270 nla_nest_cancel(skb, header_attr);
2271 return err;
2272}
2273
2274static int devlink_dpipe_headers_fill(struct genl_info *info,
2275 enum devlink_command cmd, int flags,
2276 struct devlink_dpipe_headers *
2277 dpipe_headers)
2278{
2279 struct devlink *devlink = info->user_ptr[0];
2280 struct nlattr *headers_attr;
2281 struct sk_buff *skb = NULL;
2282 struct nlmsghdr *nlh;
2283 void *hdr;
2284 int i, j;
2285 int err;
2286
2287 i = 0;
2288start_again:
2289 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2290 if (err)
2291 return err;
2292
2293 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2294 &devlink_nl_family, NLM_F_MULTI, cmd);
6044bd4a
HY
2295 if (!hdr) {
2296 nlmsg_free(skb);
1555d204 2297 return -EMSGSIZE;
6044bd4a 2298 }
1555d204
AS
2299
2300 if (devlink_nl_put_handle(skb, devlink))
2301 goto nla_put_failure;
ae0be8de 2302 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
1555d204
AS
2303 if (!headers_attr)
2304 goto nla_put_failure;
2305
2306 j = 0;
2307 for (; i < dpipe_headers->headers_count; i++) {
2308 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2309 if (err) {
2310 if (!j)
2311 goto err_table_put;
2312 break;
2313 }
2314 j++;
2315 }
2316 nla_nest_end(skb, headers_attr);
2317 genlmsg_end(skb, hdr);
2318 if (i != dpipe_headers->headers_count)
2319 goto start_again;
2320
2321send_done:
2322 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2323 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2324 if (!nlh) {
2325 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2326 if (err)
7fe4d6dc 2327 return err;
1555d204
AS
2328 goto send_done;
2329 }
2330 return genlmsg_reply(skb, info);
2331
2332nla_put_failure:
2333 err = -EMSGSIZE;
2334err_table_put:
1555d204
AS
2335 nlmsg_free(skb);
2336 return err;
2337}
2338
2339static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2340 struct genl_info *info)
2341{
2342 struct devlink *devlink = info->user_ptr[0];
2343
2344 if (!devlink->dpipe_headers)
2345 return -EOPNOTSUPP;
2346 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2347 0, devlink->dpipe_headers);
2348}
2349
2350static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2351 const char *table_name,
2352 bool enable)
2353{
2354 struct devlink_dpipe_table *table;
2355
2356 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2357 table_name);
2358 if (!table)
2359 return -EINVAL;
2360
2361 if (table->counter_control_extern)
2362 return -EOPNOTSUPP;
2363
2364 if (!(table->counters_enabled ^ enable))
2365 return 0;
2366
2367 table->counters_enabled = enable;
2368 if (table->table_ops->counters_set_update)
2369 table->table_ops->counters_set_update(table->priv, enable);
2370 return 0;
2371}
2372
2373static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2374 struct genl_info *info)
2375{
2376 struct devlink *devlink = info->user_ptr[0];
2377 const char *table_name;
2378 bool counters_enable;
2379
2380 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2381 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2382 return -EINVAL;
2383
2384 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2385 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2386
2387 return devlink_dpipe_table_counters_set(devlink, table_name,
2388 counters_enable);
08f4b591
OG
2389}
2390
43dd7512 2391static struct devlink_resource *
d9f9b9a4
AS
2392devlink_resource_find(struct devlink *devlink,
2393 struct devlink_resource *resource, u64 resource_id)
2394{
2395 struct list_head *resource_list;
2396
2397 if (resource)
2398 resource_list = &resource->resource_list;
2399 else
2400 resource_list = &devlink->resource_list;
2401
2402 list_for_each_entry(resource, resource_list, list) {
2403 struct devlink_resource *child_resource;
2404
2405 if (resource->id == resource_id)
2406 return resource;
2407
2408 child_resource = devlink_resource_find(devlink, resource,
2409 resource_id);
2410 if (child_resource)
2411 return child_resource;
2412 }
2413 return NULL;
2414}
2415
43dd7512
WY
2416static void
2417devlink_resource_validate_children(struct devlink_resource *resource)
d9f9b9a4
AS
2418{
2419 struct devlink_resource *child_resource;
2420 bool size_valid = true;
2421 u64 parts_size = 0;
2422
2423 if (list_empty(&resource->resource_list))
2424 goto out;
2425
2426 list_for_each_entry(child_resource, &resource->resource_list, list)
2427 parts_size += child_resource->size_new;
2428
b9d17175 2429 if (parts_size > resource->size_new)
d9f9b9a4
AS
2430 size_valid = false;
2431out:
2432 resource->size_valid = size_valid;
2433}
2434
cc944ead
AS
2435static int
2436devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2437 struct netlink_ext_ack *extack)
2438{
2439 u64 reminder;
2440 int err = 0;
2441
0f3e9c97 2442 if (size > resource->size_params.size_max) {
cc944ead
AS
2443 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2444 err = -EINVAL;
2445 }
2446
0f3e9c97 2447 if (size < resource->size_params.size_min) {
cc944ead
AS
2448 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2449 err = -EINVAL;
2450 }
2451
0f3e9c97 2452 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
cc944ead
AS
2453 if (reminder) {
2454 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2455 err = -EINVAL;
2456 }
2457
2458 return err;
2459}
2460
d9f9b9a4
AS
2461static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2462 struct genl_info *info)
2463{
2464 struct devlink *devlink = info->user_ptr[0];
2465 struct devlink_resource *resource;
2466 u64 resource_id;
2467 u64 size;
2468 int err;
2469
2470 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2471 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2472 return -EINVAL;
2473 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2474
2475 resource = devlink_resource_find(devlink, NULL, resource_id);
2476 if (!resource)
2477 return -EINVAL;
2478
d9f9b9a4 2479 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
cc944ead 2480 err = devlink_resource_validate_size(resource, size, info->extack);
d9f9b9a4
AS
2481 if (err)
2482 return err;
2483
2484 resource->size_new = size;
2485 devlink_resource_validate_children(resource);
2486 if (resource->parent)
2487 devlink_resource_validate_children(resource->parent);
2488 return 0;
2489}
2490
3d18e4f1 2491static int
d9f9b9a4
AS
2492devlink_resource_size_params_put(struct devlink_resource *resource,
2493 struct sk_buff *skb)
2494{
2495 struct devlink_resource_size_params *size_params;
2496
77d27096 2497 size_params = &resource->size_params;
3d18e4f1
AS
2498 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2499 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2500 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2501 size_params->size_max, DEVLINK_ATTR_PAD) ||
2502 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2503 size_params->size_min, DEVLINK_ATTR_PAD) ||
2504 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2505 return -EMSGSIZE;
2506 return 0;
d9f9b9a4
AS
2507}
2508
fc56be47
JP
2509static int devlink_resource_occ_put(struct devlink_resource *resource,
2510 struct sk_buff *skb)
2511{
2512 if (!resource->occ_get)
2513 return 0;
2514 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2515 resource->occ_get(resource->occ_get_priv),
2516 DEVLINK_ATTR_PAD);
2517}
2518
d9f9b9a4
AS
2519static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2520 struct devlink_resource *resource)
2521{
2522 struct devlink_resource *child_resource;
2523 struct nlattr *child_resource_attr;
2524 struct nlattr *resource_attr;
2525
ae0be8de 2526 resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
d9f9b9a4
AS
2527 if (!resource_attr)
2528 return -EMSGSIZE;
2529
2530 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2531 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2532 DEVLINK_ATTR_PAD) ||
2533 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2534 DEVLINK_ATTR_PAD))
2535 goto nla_put_failure;
2536 if (resource->size != resource->size_new)
2537 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2538 resource->size_new, DEVLINK_ATTR_PAD);
fc56be47
JP
2539 if (devlink_resource_occ_put(resource, skb))
2540 goto nla_put_failure;
3d18e4f1
AS
2541 if (devlink_resource_size_params_put(resource, skb))
2542 goto nla_put_failure;
d9f9b9a4
AS
2543 if (list_empty(&resource->resource_list))
2544 goto out;
2545
2546 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2547 resource->size_valid))
2548 goto nla_put_failure;
2549
ae0be8de
MK
2550 child_resource_attr = nla_nest_start_noflag(skb,
2551 DEVLINK_ATTR_RESOURCE_LIST);
d9f9b9a4
AS
2552 if (!child_resource_attr)
2553 goto nla_put_failure;
2554
2555 list_for_each_entry(child_resource, &resource->resource_list, list) {
2556 if (devlink_resource_put(devlink, skb, child_resource))
2557 goto resource_put_failure;
2558 }
2559
2560 nla_nest_end(skb, child_resource_attr);
2561out:
2562 nla_nest_end(skb, resource_attr);
2563 return 0;
2564
2565resource_put_failure:
2566 nla_nest_cancel(skb, child_resource_attr);
2567nla_put_failure:
2568 nla_nest_cancel(skb, resource_attr);
2569 return -EMSGSIZE;
2570}
2571
2572static int devlink_resource_fill(struct genl_info *info,
2573 enum devlink_command cmd, int flags)
2574{
2575 struct devlink *devlink = info->user_ptr[0];
2576 struct devlink_resource *resource;
2577 struct nlattr *resources_attr;
2578 struct sk_buff *skb = NULL;
2579 struct nlmsghdr *nlh;
2580 bool incomplete;
2581 void *hdr;
2582 int i;
2583 int err;
2584
2585 resource = list_first_entry(&devlink->resource_list,
2586 struct devlink_resource, list);
2587start_again:
2588 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2589 if (err)
2590 return err;
2591
2592 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2593 &devlink_nl_family, NLM_F_MULTI, cmd);
2594 if (!hdr) {
2595 nlmsg_free(skb);
2596 return -EMSGSIZE;
2597 }
2598
2599 if (devlink_nl_put_handle(skb, devlink))
2600 goto nla_put_failure;
2601
ae0be8de
MK
2602 resources_attr = nla_nest_start_noflag(skb,
2603 DEVLINK_ATTR_RESOURCE_LIST);
d9f9b9a4
AS
2604 if (!resources_attr)
2605 goto nla_put_failure;
2606
2607 incomplete = false;
2608 i = 0;
2609 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2610 err = devlink_resource_put(devlink, skb, resource);
2611 if (err) {
2612 if (!i)
2613 goto err_resource_put;
2614 incomplete = true;
2615 break;
2616 }
2617 i++;
2618 }
2619 nla_nest_end(skb, resources_attr);
2620 genlmsg_end(skb, hdr);
2621 if (incomplete)
2622 goto start_again;
2623send_done:
2624 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2625 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2626 if (!nlh) {
2627 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2628 if (err)
83fe9a96 2629 return err;
d9f9b9a4
AS
2630 goto send_done;
2631 }
2632 return genlmsg_reply(skb, info);
2633
2634nla_put_failure:
2635 err = -EMSGSIZE;
2636err_resource_put:
d9f9b9a4
AS
2637 nlmsg_free(skb);
2638 return err;
2639}
2640
2641static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2642 struct genl_info *info)
2643{
2644 struct devlink *devlink = info->user_ptr[0];
2645
2646 if (list_empty(&devlink->resource_list))
2647 return -EOPNOTSUPP;
2648
2649 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2650}
2651
2d8dc5bb
AS
2652static int
2653devlink_resources_validate(struct devlink *devlink,
2654 struct devlink_resource *resource,
2655 struct genl_info *info)
2656{
2657 struct list_head *resource_list;
2658 int err = 0;
2659
2660 if (resource)
2661 resource_list = &resource->resource_list;
2662 else
2663 resource_list = &devlink->resource_list;
2664
2665 list_for_each_entry(resource, resource_list, list) {
2666 if (!resource->size_valid)
2667 return -EINVAL;
2668 err = devlink_resources_validate(devlink, resource, info);
2669 if (err)
2670 return err;
2671 }
2672 return err;
2673}
2674
2675static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2676{
2677 struct devlink *devlink = info->user_ptr[0];
2678 int err;
2679
2680 if (!devlink->ops->reload)
2681 return -EOPNOTSUPP;
2682
2683 err = devlink_resources_validate(devlink, NULL, info);
2684 if (err) {
2685 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2686 return err;
2687 }
ac0fc8a1 2688 return devlink->ops->reload(devlink, info->extack);
2d8dc5bb
AS
2689}
2690
191ed202
JP
2691static int devlink_nl_flash_update_fill(struct sk_buff *msg,
2692 struct devlink *devlink,
2693 enum devlink_command cmd,
2694 const char *status_msg,
2695 const char *component,
2696 unsigned long done, unsigned long total)
2697{
2698 void *hdr;
2699
2700 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
2701 if (!hdr)
2702 return -EMSGSIZE;
2703
2704 if (devlink_nl_put_handle(msg, devlink))
2705 goto nla_put_failure;
2706
2707 if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
2708 goto out;
2709
2710 if (status_msg &&
2711 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
2712 status_msg))
2713 goto nla_put_failure;
2714 if (component &&
2715 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
2716 component))
2717 goto nla_put_failure;
2718 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
2719 done, DEVLINK_ATTR_PAD))
2720 goto nla_put_failure;
2721 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
2722 total, DEVLINK_ATTR_PAD))
2723 goto nla_put_failure;
2724
2725out:
2726 genlmsg_end(msg, hdr);
2727 return 0;
2728
2729nla_put_failure:
2730 genlmsg_cancel(msg, hdr);
2731 return -EMSGSIZE;
2732}
2733
2734static void __devlink_flash_update_notify(struct devlink *devlink,
2735 enum devlink_command cmd,
2736 const char *status_msg,
2737 const char *component,
2738 unsigned long done,
2739 unsigned long total)
2740{
2741 struct sk_buff *msg;
2742 int err;
2743
2744 WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
2745 cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
2746 cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
2747
2748 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2749 if (!msg)
2750 return;
2751
2752 err = devlink_nl_flash_update_fill(msg, devlink, cmd, status_msg,
2753 component, done, total);
2754 if (err)
2755 goto out_free_msg;
2756
2757 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
2758 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
2759 return;
2760
2761out_free_msg:
2762 nlmsg_free(msg);
2763}
2764
2765void devlink_flash_update_begin_notify(struct devlink *devlink)
2766{
2767 __devlink_flash_update_notify(devlink,
2768 DEVLINK_CMD_FLASH_UPDATE,
2769 NULL, NULL, 0, 0);
2770}
2771EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
2772
2773void devlink_flash_update_end_notify(struct devlink *devlink)
2774{
2775 __devlink_flash_update_notify(devlink,
2776 DEVLINK_CMD_FLASH_UPDATE_END,
2777 NULL, NULL, 0, 0);
2778}
2779EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
2780
2781void devlink_flash_update_status_notify(struct devlink *devlink,
2782 const char *status_msg,
2783 const char *component,
2784 unsigned long done,
2785 unsigned long total)
2786{
2787 __devlink_flash_update_notify(devlink,
2788 DEVLINK_CMD_FLASH_UPDATE_STATUS,
2789 status_msg, component, done, total);
2790}
2791EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
2792
76726ccb
JK
2793static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
2794 struct genl_info *info)
2795{
2796 struct devlink *devlink = info->user_ptr[0];
2797 const char *file_name, *component;
2798 struct nlattr *nla_component;
2799
2800 if (!devlink->ops->flash_update)
2801 return -EOPNOTSUPP;
2802
2803 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
2804 return -EINVAL;
2805 file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
2806
2807 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
2808 component = nla_component ? nla_data(nla_component) : NULL;
2809
2810 return devlink->ops->flash_update(devlink, file_name, component,
2811 info->extack);
2812}
2813
036467c3
MS
2814static const struct devlink_param devlink_param_generic[] = {
2815 {
2816 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
2817 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
2818 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
2819 },
2820 {
2821 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
2822 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
2823 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
2824 },
f567bcda
VV
2825 {
2826 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
2827 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
2828 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
2829 },
f6a69885
AV
2830 {
2831 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
2832 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
2833 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
2834 },
e3b51061
VV
2835 {
2836 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
2837 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
2838 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
2839 },
f61cba42
VV
2840 {
2841 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
2842 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
2843 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
2844 },
16511789
VV
2845 {
2846 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
2847 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
2848 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
2849 },
846e980a
ST
2850 {
2851 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
2852 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
2853 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
2854 },
036467c3 2855};
eabaef18
MS
2856
2857static int devlink_param_generic_verify(const struct devlink_param *param)
2858{
2859 /* verify it match generic parameter by id and name */
2860 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
2861 return -EINVAL;
2862 if (strcmp(param->name, devlink_param_generic[param->id].name))
2863 return -ENOENT;
2864
2865 WARN_ON(param->type != devlink_param_generic[param->id].type);
2866
2867 return 0;
2868}
2869
2870static int devlink_param_driver_verify(const struct devlink_param *param)
2871{
2872 int i;
2873
2874 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
2875 return -EINVAL;
2876 /* verify no such name in generic params */
2877 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
2878 if (!strcmp(param->name, devlink_param_generic[i].name))
2879 return -EEXIST;
2880
2881 return 0;
2882}
2883
2884static struct devlink_param_item *
2885devlink_param_find_by_name(struct list_head *param_list,
2886 const char *param_name)
2887{
2888 struct devlink_param_item *param_item;
2889
2890 list_for_each_entry(param_item, param_list, list)
2891 if (!strcmp(param_item->param->name, param_name))
2892 return param_item;
2893 return NULL;
2894}
2895
ec01aeb1
MS
2896static struct devlink_param_item *
2897devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
2898{
2899 struct devlink_param_item *param_item;
2900
2901 list_for_each_entry(param_item, param_list, list)
2902 if (param_item->param->id == param_id)
2903 return param_item;
2904 return NULL;
2905}
2906
45f05def
MS
2907static bool
2908devlink_param_cmode_is_supported(const struct devlink_param *param,
2909 enum devlink_param_cmode cmode)
2910{
2911 return test_bit(cmode, &param->supported_cmodes);
2912}
2913
2914static int devlink_param_get(struct devlink *devlink,
2915 const struct devlink_param *param,
2916 struct devlink_param_gset_ctx *ctx)
2917{
2918 if (!param->get)
2919 return -EOPNOTSUPP;
2920 return param->get(devlink, param->id, ctx);
2921}
2922
e3b7ca18
MS
2923static int devlink_param_set(struct devlink *devlink,
2924 const struct devlink_param *param,
2925 struct devlink_param_gset_ctx *ctx)
2926{
2927 if (!param->set)
2928 return -EOPNOTSUPP;
2929 return param->set(devlink, param->id, ctx);
2930}
2931
45f05def
MS
2932static int
2933devlink_param_type_to_nla_type(enum devlink_param_type param_type)
2934{
2935 switch (param_type) {
2936 case DEVLINK_PARAM_TYPE_U8:
2937 return NLA_U8;
2938 case DEVLINK_PARAM_TYPE_U16:
2939 return NLA_U16;
2940 case DEVLINK_PARAM_TYPE_U32:
2941 return NLA_U32;
2942 case DEVLINK_PARAM_TYPE_STRING:
2943 return NLA_STRING;
2944 case DEVLINK_PARAM_TYPE_BOOL:
2945 return NLA_FLAG;
2946 default:
2947 return -EINVAL;
2948 }
2949}
2950
2951static int
2952devlink_nl_param_value_fill_one(struct sk_buff *msg,
2953 enum devlink_param_type type,
2954 enum devlink_param_cmode cmode,
2955 union devlink_param_value val)
2956{
2957 struct nlattr *param_value_attr;
2958
ae0be8de
MK
2959 param_value_attr = nla_nest_start_noflag(msg,
2960 DEVLINK_ATTR_PARAM_VALUE);
45f05def
MS
2961 if (!param_value_attr)
2962 goto nla_put_failure;
2963
2964 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
2965 goto value_nest_cancel;
2966
2967 switch (type) {
2968 case DEVLINK_PARAM_TYPE_U8:
2969 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
2970 goto value_nest_cancel;
2971 break;
2972 case DEVLINK_PARAM_TYPE_U16:
2973 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
2974 goto value_nest_cancel;
2975 break;
2976 case DEVLINK_PARAM_TYPE_U32:
2977 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
2978 goto value_nest_cancel;
2979 break;
2980 case DEVLINK_PARAM_TYPE_STRING:
2981 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
2982 val.vstr))
2983 goto value_nest_cancel;
2984 break;
2985 case DEVLINK_PARAM_TYPE_BOOL:
2986 if (val.vbool &&
2987 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
2988 goto value_nest_cancel;
2989 break;
2990 }
2991
2992 nla_nest_end(msg, param_value_attr);
2993 return 0;
2994
2995value_nest_cancel:
2996 nla_nest_cancel(msg, param_value_attr);
2997nla_put_failure:
2998 return -EMSGSIZE;
2999}
3000
3001static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
f4601dee 3002 unsigned int port_index,
45f05def
MS
3003 struct devlink_param_item *param_item,
3004 enum devlink_command cmd,
3005 u32 portid, u32 seq, int flags)
3006{
3007 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
7c62cfb8 3008 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
45f05def
MS
3009 const struct devlink_param *param = param_item->param;
3010 struct devlink_param_gset_ctx ctx;
3011 struct nlattr *param_values_list;
3012 struct nlattr *param_attr;
3013 int nla_type;
3014 void *hdr;
3015 int err;
3016 int i;
3017
3018 /* Get value from driver part to driverinit configuration mode */
3019 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3020 if (!devlink_param_cmode_is_supported(param, i))
3021 continue;
3022 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3023 if (!param_item->driverinit_value_valid)
3024 return -EOPNOTSUPP;
3025 param_value[i] = param_item->driverinit_value;
3026 } else {
7c62cfb8
JP
3027 if (!param_item->published)
3028 continue;
45f05def
MS
3029 ctx.cmode = i;
3030 err = devlink_param_get(devlink, param, &ctx);
3031 if (err)
3032 return err;
3033 param_value[i] = ctx.val;
3034 }
7c62cfb8 3035 param_value_set[i] = true;
45f05def
MS
3036 }
3037
3038 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3039 if (!hdr)
3040 return -EMSGSIZE;
3041
3042 if (devlink_nl_put_handle(msg, devlink))
3043 goto genlmsg_cancel;
f4601dee 3044
c1e5786d
VV
3045 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3046 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3047 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
f4601dee
VV
3048 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3049 goto genlmsg_cancel;
3050
ae0be8de 3051 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
45f05def
MS
3052 if (!param_attr)
3053 goto genlmsg_cancel;
3054 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3055 goto param_nest_cancel;
3056 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3057 goto param_nest_cancel;
3058
3059 nla_type = devlink_param_type_to_nla_type(param->type);
3060 if (nla_type < 0)
3061 goto param_nest_cancel;
3062 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3063 goto param_nest_cancel;
3064
ae0be8de
MK
3065 param_values_list = nla_nest_start_noflag(msg,
3066 DEVLINK_ATTR_PARAM_VALUES_LIST);
45f05def
MS
3067 if (!param_values_list)
3068 goto param_nest_cancel;
3069
3070 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
7c62cfb8 3071 if (!param_value_set[i])
45f05def
MS
3072 continue;
3073 err = devlink_nl_param_value_fill_one(msg, param->type,
3074 i, param_value[i]);
3075 if (err)
3076 goto values_list_nest_cancel;
3077 }
3078
3079 nla_nest_end(msg, param_values_list);
3080 nla_nest_end(msg, param_attr);
3081 genlmsg_end(msg, hdr);
3082 return 0;
3083
3084values_list_nest_cancel:
3085 nla_nest_end(msg, param_values_list);
3086param_nest_cancel:
3087 nla_nest_cancel(msg, param_attr);
3088genlmsg_cancel:
3089 genlmsg_cancel(msg, hdr);
3090 return -EMSGSIZE;
3091}
3092
ea601e17 3093static void devlink_param_notify(struct devlink *devlink,
c1e5786d 3094 unsigned int port_index,
ea601e17
MS
3095 struct devlink_param_item *param_item,
3096 enum devlink_command cmd)
3097{
3098 struct sk_buff *msg;
3099 int err;
3100
c1e5786d
VV
3101 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3102 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3103 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
ea601e17
MS
3104
3105 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3106 if (!msg)
3107 return;
c1e5786d
VV
3108 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3109 0, 0, 0);
ea601e17
MS
3110 if (err) {
3111 nlmsg_free(msg);
3112 return;
3113 }
3114
3115 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3116 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3117}
3118
45f05def
MS
3119static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3120 struct netlink_callback *cb)
3121{
3122 struct devlink_param_item *param_item;
3123 struct devlink *devlink;
3124 int start = cb->args[0];
3125 int idx = 0;
3126 int err;
3127
3128 mutex_lock(&devlink_mutex);
3129 list_for_each_entry(devlink, &devlink_list, list) {
3130 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3131 continue;
3132 mutex_lock(&devlink->lock);
3133 list_for_each_entry(param_item, &devlink->param_list, list) {
3134 if (idx < start) {
3135 idx++;
3136 continue;
3137 }
f4601dee 3138 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
3139 DEVLINK_CMD_PARAM_GET,
3140 NETLINK_CB(cb->skb).portid,
3141 cb->nlh->nlmsg_seq,
3142 NLM_F_MULTI);
3143 if (err) {
3144 mutex_unlock(&devlink->lock);
3145 goto out;
3146 }
3147 idx++;
3148 }
3149 mutex_unlock(&devlink->lock);
3150 }
3151out:
3152 mutex_unlock(&devlink_mutex);
3153
3154 cb->args[0] = idx;
3155 return msg->len;
3156}
3157
e3b7ca18
MS
3158static int
3159devlink_param_type_get_from_info(struct genl_info *info,
3160 enum devlink_param_type *param_type)
3161{
3162 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3163 return -EINVAL;
3164
3165 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3166 case NLA_U8:
3167 *param_type = DEVLINK_PARAM_TYPE_U8;
3168 break;
3169 case NLA_U16:
3170 *param_type = DEVLINK_PARAM_TYPE_U16;
3171 break;
3172 case NLA_U32:
3173 *param_type = DEVLINK_PARAM_TYPE_U32;
3174 break;
3175 case NLA_STRING:
3176 *param_type = DEVLINK_PARAM_TYPE_STRING;
3177 break;
3178 case NLA_FLAG:
3179 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3180 break;
3181 default:
3182 return -EINVAL;
3183 }
3184
3185 return 0;
3186}
3187
3188static int
3189devlink_param_value_get_from_info(const struct devlink_param *param,
3190 struct genl_info *info,
3191 union devlink_param_value *value)
3192{
f355cfcd
MS
3193 int len;
3194
e3b7ca18
MS
3195 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3196 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3197 return -EINVAL;
3198
3199 switch (param->type) {
3200 case DEVLINK_PARAM_TYPE_U8:
3201 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3202 break;
3203 case DEVLINK_PARAM_TYPE_U16:
3204 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3205 break;
3206 case DEVLINK_PARAM_TYPE_U32:
3207 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3208 break;
3209 case DEVLINK_PARAM_TYPE_STRING:
f355cfcd
MS
3210 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3211 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3212 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
bde74ad1 3213 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
e3b7ca18 3214 return -EINVAL;
f355cfcd
MS
3215 strcpy(value->vstr,
3216 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
e3b7ca18
MS
3217 break;
3218 case DEVLINK_PARAM_TYPE_BOOL:
3219 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3220 true : false;
3221 break;
3222 }
3223 return 0;
3224}
3225
45f05def 3226static struct devlink_param_item *
f4601dee 3227devlink_param_get_from_info(struct list_head *param_list,
45f05def
MS
3228 struct genl_info *info)
3229{
3230 char *param_name;
3231
3232 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3233 return NULL;
3234
3235 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
f4601dee 3236 return devlink_param_find_by_name(param_list, param_name);
45f05def
MS
3237}
3238
3239static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3240 struct genl_info *info)
3241{
3242 struct devlink *devlink = info->user_ptr[0];
3243 struct devlink_param_item *param_item;
3244 struct sk_buff *msg;
3245 int err;
3246
f4601dee 3247 param_item = devlink_param_get_from_info(&devlink->param_list, info);
45f05def
MS
3248 if (!param_item)
3249 return -EINVAL;
3250
3251 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3252 if (!msg)
3253 return -ENOMEM;
3254
f4601dee 3255 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
3256 DEVLINK_CMD_PARAM_GET,
3257 info->snd_portid, info->snd_seq, 0);
3258 if (err) {
3259 nlmsg_free(msg);
3260 return err;
3261 }
3262
3263 return genlmsg_reply(msg, info);
3264}
3265
9c54873b 3266static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
c1e5786d 3267 unsigned int port_index,
9c54873b
VV
3268 struct list_head *param_list,
3269 struct genl_info *info,
3270 enum devlink_command cmd)
e3b7ca18 3271{
e3b7ca18
MS
3272 enum devlink_param_type param_type;
3273 struct devlink_param_gset_ctx ctx;
3274 enum devlink_param_cmode cmode;
3275 struct devlink_param_item *param_item;
3276 const struct devlink_param *param;
3277 union devlink_param_value value;
3278 int err = 0;
3279
9c54873b 3280 param_item = devlink_param_get_from_info(param_list, info);
e3b7ca18
MS
3281 if (!param_item)
3282 return -EINVAL;
3283 param = param_item->param;
3284 err = devlink_param_type_get_from_info(info, &param_type);
3285 if (err)
3286 return err;
3287 if (param_type != param->type)
3288 return -EINVAL;
3289 err = devlink_param_value_get_from_info(param, info, &value);
3290 if (err)
3291 return err;
3292 if (param->validate) {
3293 err = param->validate(devlink, param->id, value, info->extack);
3294 if (err)
3295 return err;
3296 }
3297
3298 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3299 return -EINVAL;
3300 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3301 if (!devlink_param_cmode_is_supported(param, cmode))
3302 return -EOPNOTSUPP;
3303
3304 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
1276534c
MS
3305 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3306 strcpy(param_item->driverinit_value.vstr, value.vstr);
3307 else
3308 param_item->driverinit_value = value;
e3b7ca18
MS
3309 param_item->driverinit_value_valid = true;
3310 } else {
3311 if (!param->set)
3312 return -EOPNOTSUPP;
3313 ctx.val = value;
3314 ctx.cmode = cmode;
3315 err = devlink_param_set(devlink, param, &ctx);
3316 if (err)
3317 return err;
3318 }
3319
c1e5786d 3320 devlink_param_notify(devlink, port_index, param_item, cmd);
e3b7ca18
MS
3321 return 0;
3322}
3323
9c54873b
VV
3324static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3325 struct genl_info *info)
3326{
3327 struct devlink *devlink = info->user_ptr[0];
3328
c1e5786d 3329 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
9c54873b
VV
3330 info, DEVLINK_CMD_PARAM_NEW);
3331}
3332
eabaef18 3333static int devlink_param_register_one(struct devlink *devlink,
c1e5786d 3334 unsigned int port_index,
39e6160e 3335 struct list_head *param_list,
c1e5786d
VV
3336 const struct devlink_param *param,
3337 enum devlink_command cmd)
eabaef18
MS
3338{
3339 struct devlink_param_item *param_item;
3340
39e6160e 3341 if (devlink_param_find_by_name(param_list, param->name))
eabaef18
MS
3342 return -EEXIST;
3343
3344 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3345 WARN_ON(param->get || param->set);
3346 else
3347 WARN_ON(!param->get || !param->set);
3348
3349 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3350 if (!param_item)
3351 return -ENOMEM;
3352 param_item->param = param;
3353
39e6160e 3354 list_add_tail(&param_item->list, param_list);
c1e5786d 3355 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3356 return 0;
3357}
3358
3359static void devlink_param_unregister_one(struct devlink *devlink,
c1e5786d 3360 unsigned int port_index,
39e6160e 3361 struct list_head *param_list,
c1e5786d
VV
3362 const struct devlink_param *param,
3363 enum devlink_command cmd)
eabaef18
MS
3364{
3365 struct devlink_param_item *param_item;
3366
39e6160e 3367 param_item = devlink_param_find_by_name(param_list, param->name);
eabaef18 3368 WARN_ON(!param_item);
c1e5786d 3369 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3370 list_del(&param_item->list);
3371 kfree(param_item);
3372}
3373
f4601dee
VV
3374static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3375 struct netlink_callback *cb)
3376{
3377 struct devlink_param_item *param_item;
3378 struct devlink_port *devlink_port;
3379 struct devlink *devlink;
3380 int start = cb->args[0];
3381 int idx = 0;
3382 int err;
3383
3384 mutex_lock(&devlink_mutex);
3385 list_for_each_entry(devlink, &devlink_list, list) {
3386 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3387 continue;
3388 mutex_lock(&devlink->lock);
3389 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3390 list_for_each_entry(param_item,
3391 &devlink_port->param_list, list) {
3392 if (idx < start) {
3393 idx++;
3394 continue;
3395 }
3396 err = devlink_nl_param_fill(msg,
3397 devlink_port->devlink,
3398 devlink_port->index, param_item,
3399 DEVLINK_CMD_PORT_PARAM_GET,
3400 NETLINK_CB(cb->skb).portid,
3401 cb->nlh->nlmsg_seq,
3402 NLM_F_MULTI);
3403 if (err) {
3404 mutex_unlock(&devlink->lock);
3405 goto out;
3406 }
3407 idx++;
3408 }
3409 }
3410 mutex_unlock(&devlink->lock);
3411 }
3412out:
3413 mutex_unlock(&devlink_mutex);
3414
3415 cb->args[0] = idx;
3416 return msg->len;
3417}
3418
3419static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3420 struct genl_info *info)
3421{
3422 struct devlink_port *devlink_port = info->user_ptr[0];
3423 struct devlink_param_item *param_item;
3424 struct sk_buff *msg;
3425 int err;
3426
3427 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3428 info);
3429 if (!param_item)
3430 return -EINVAL;
3431
3432 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3433 if (!msg)
3434 return -ENOMEM;
3435
3436 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3437 devlink_port->index, param_item,
3438 DEVLINK_CMD_PORT_PARAM_GET,
3439 info->snd_portid, info->snd_seq, 0);
3440 if (err) {
3441 nlmsg_free(msg);
3442 return err;
3443 }
3444
3445 return genlmsg_reply(msg, info);
3446}
3447
9c54873b
VV
3448static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3449 struct genl_info *info)
3450{
3451 struct devlink_port *devlink_port = info->user_ptr[0];
3452
3453 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
c1e5786d
VV
3454 devlink_port->index,
3455 &devlink_port->param_list, info,
3456 DEVLINK_CMD_PORT_PARAM_NEW);
9c54873b
VV
3457}
3458
a006d467
AV
3459static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3460 struct devlink *devlink,
3461 struct devlink_snapshot *snapshot)
3462{
3463 struct nlattr *snap_attr;
3464 int err;
3465
ae0be8de 3466 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
a006d467
AV
3467 if (!snap_attr)
3468 return -EINVAL;
3469
3470 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3471 if (err)
3472 goto nla_put_failure;
3473
3474 nla_nest_end(msg, snap_attr);
3475 return 0;
3476
3477nla_put_failure:
3478 nla_nest_cancel(msg, snap_attr);
3479 return err;
3480}
3481
3482static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3483 struct devlink *devlink,
3484 struct devlink_region *region)
3485{
3486 struct devlink_snapshot *snapshot;
3487 struct nlattr *snapshots_attr;
3488 int err;
3489
ae0be8de
MK
3490 snapshots_attr = nla_nest_start_noflag(msg,
3491 DEVLINK_ATTR_REGION_SNAPSHOTS);
a006d467
AV
3492 if (!snapshots_attr)
3493 return -EINVAL;
3494
3495 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3496 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3497 if (err)
3498 goto nla_put_failure;
3499 }
3500
3501 nla_nest_end(msg, snapshots_attr);
3502 return 0;
3503
3504nla_put_failure:
3505 nla_nest_cancel(msg, snapshots_attr);
3506 return err;
3507}
3508
d8db7ea5
AV
3509static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3510 enum devlink_command cmd, u32 portid,
3511 u32 seq, int flags,
3512 struct devlink_region *region)
3513{
3514 void *hdr;
3515 int err;
3516
3517 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3518 if (!hdr)
3519 return -EMSGSIZE;
3520
3521 err = devlink_nl_put_handle(msg, devlink);
3522 if (err)
3523 goto nla_put_failure;
3524
3525 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3526 if (err)
3527 goto nla_put_failure;
3528
3529 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3530 region->size,
3531 DEVLINK_ATTR_PAD);
3532 if (err)
3533 goto nla_put_failure;
3534
a006d467
AV
3535 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3536 if (err)
3537 goto nla_put_failure;
3538
d8db7ea5
AV
3539 genlmsg_end(msg, hdr);
3540 return 0;
3541
3542nla_put_failure:
3543 genlmsg_cancel(msg, hdr);
3544 return err;
3545}
3546
866319bb
AV
3547static void devlink_nl_region_notify(struct devlink_region *region,
3548 struct devlink_snapshot *snapshot,
3549 enum devlink_command cmd)
3550{
3551 struct devlink *devlink = region->devlink;
3552 struct sk_buff *msg;
3553 void *hdr;
3554 int err;
3555
3556 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3557
3558 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3559 if (!msg)
3560 return;
3561
3562 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3563 if (!hdr)
3564 goto out_free_msg;
3565
3566 err = devlink_nl_put_handle(msg, devlink);
3567 if (err)
3568 goto out_cancel_msg;
3569
3570 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3571 region->name);
3572 if (err)
3573 goto out_cancel_msg;
3574
3575 if (snapshot) {
3576 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3577 snapshot->id);
3578 if (err)
3579 goto out_cancel_msg;
3580 } else {
3581 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3582 region->size, DEVLINK_ATTR_PAD);
3583 if (err)
3584 goto out_cancel_msg;
3585 }
3586 genlmsg_end(msg, hdr);
3587
3588 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3589 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3590
3591 return;
3592
3593out_cancel_msg:
3594 genlmsg_cancel(msg, hdr);
3595out_free_msg:
3596 nlmsg_free(msg);
3597}
3598
92b49822
JP
3599static void devlink_region_snapshot_del(struct devlink_region *region,
3600 struct devlink_snapshot *snapshot)
3601{
3602 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3603 region->cur_snapshots--;
3604 list_del(&snapshot->list);
3605 (*snapshot->data_destructor)(snapshot->data);
3606 kfree(snapshot);
3607}
3608
d8db7ea5
AV
3609static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3610 struct genl_info *info)
3611{
3612 struct devlink *devlink = info->user_ptr[0];
3613 struct devlink_region *region;
3614 const char *region_name;
3615 struct sk_buff *msg;
3616 int err;
3617
3618 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3619 return -EINVAL;
3620
3621 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3622 region = devlink_region_get_by_name(devlink, region_name);
3623 if (!region)
3624 return -EINVAL;
3625
3626 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3627 if (!msg)
3628 return -ENOMEM;
3629
3630 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3631 info->snd_portid, info->snd_seq, 0,
3632 region);
3633 if (err) {
3634 nlmsg_free(msg);
3635 return err;
3636 }
3637
3638 return genlmsg_reply(msg, info);
3639}
3640
3641static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3642 struct netlink_callback *cb)
3643{
3644 struct devlink_region *region;
3645 struct devlink *devlink;
3646 int start = cb->args[0];
3647 int idx = 0;
3648 int err;
3649
3650 mutex_lock(&devlink_mutex);
3651 list_for_each_entry(devlink, &devlink_list, list) {
3652 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3653 continue;
3654
3655 mutex_lock(&devlink->lock);
3656 list_for_each_entry(region, &devlink->region_list, list) {
3657 if (idx < start) {
3658 idx++;
3659 continue;
3660 }
3661 err = devlink_nl_region_fill(msg, devlink,
3662 DEVLINK_CMD_REGION_GET,
3663 NETLINK_CB(cb->skb).portid,
3664 cb->nlh->nlmsg_seq,
3665 NLM_F_MULTI, region);
3666 if (err) {
3667 mutex_unlock(&devlink->lock);
3668 goto out;
3669 }
3670 idx++;
3671 }
3672 mutex_unlock(&devlink->lock);
3673 }
3674out:
3675 mutex_unlock(&devlink_mutex);
3676 cb->args[0] = idx;
3677 return msg->len;
3678}
3679
866319bb
AV
3680static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3681 struct genl_info *info)
3682{
3683 struct devlink *devlink = info->user_ptr[0];
3684 struct devlink_snapshot *snapshot;
3685 struct devlink_region *region;
3686 const char *region_name;
3687 u32 snapshot_id;
3688
3689 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3690 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3691 return -EINVAL;
3692
3693 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3694 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3695
3696 region = devlink_region_get_by_name(devlink, region_name);
3697 if (!region)
3698 return -EINVAL;
3699
3700 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3701 if (!snapshot)
3702 return -EINVAL;
3703
92b49822 3704 devlink_region_snapshot_del(region, snapshot);
866319bb
AV
3705 return 0;
3706}
3707
4e54795a
AV
3708static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3709 struct devlink *devlink,
3710 u8 *chunk, u32 chunk_size,
3711 u64 addr)
3712{
3713 struct nlattr *chunk_attr;
3714 int err;
3715
ae0be8de 3716 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
4e54795a
AV
3717 if (!chunk_attr)
3718 return -EINVAL;
3719
3720 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3721 if (err)
3722 goto nla_put_failure;
3723
3724 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3725 DEVLINK_ATTR_PAD);
3726 if (err)
3727 goto nla_put_failure;
3728
3729 nla_nest_end(msg, chunk_attr);
3730 return 0;
3731
3732nla_put_failure:
3733 nla_nest_cancel(msg, chunk_attr);
3734 return err;
3735}
3736
3737#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3738
3739static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3740 struct devlink *devlink,
3741 struct devlink_region *region,
3742 struct nlattr **attrs,
3743 u64 start_offset,
3744 u64 end_offset,
3745 bool dump,
3746 u64 *new_offset)
3747{
3748 struct devlink_snapshot *snapshot;
3749 u64 curr_offset = start_offset;
3750 u32 snapshot_id;
3751 int err = 0;
3752
3753 *new_offset = start_offset;
3754
3755 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3756 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3757 if (!snapshot)
3758 return -EINVAL;
3759
3a5e5234
JP
3760 if (end_offset > region->size || dump)
3761 end_offset = region->size;
4e54795a
AV
3762
3763 while (curr_offset < end_offset) {
3764 u32 data_size;
3765 u8 *data;
3766
3767 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3768 data_size = end_offset - curr_offset;
3769 else
3770 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3771
3772 data = &snapshot->data[curr_offset];
3773 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3774 data, data_size,
3775 curr_offset);
3776 if (err)
3777 break;
3778
3779 curr_offset += data_size;
3780 }
3781 *new_offset = curr_offset;
3782
3783 return err;
3784}
3785
3786static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3787 struct netlink_callback *cb)
3788{
3789 u64 ret_offset, start_offset, end_offset = 0;
4e54795a
AV
3790 struct devlink_region *region;
3791 struct nlattr *chunks_attr;
3792 const char *region_name;
3793 struct devlink *devlink;
68750561 3794 struct nlattr **attrs;
4e54795a
AV
3795 bool dump = true;
3796 void *hdr;
3797 int err;
3798
3799 start_offset = *((u64 *)&cb->args[0]);
3800
68750561
JK
3801 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
3802 if (!attrs)
3803 return -ENOMEM;
3804
8cb08174
JB
3805 err = nlmsg_parse_deprecated(cb->nlh,
3806 GENL_HDRLEN + devlink_nl_family.hdrsize,
3807 attrs, DEVLINK_ATTR_MAX,
3808 devlink_nl_family.policy, cb->extack);
4e54795a 3809 if (err)
68750561 3810 goto out_free;
4e54795a 3811
dac7c08f 3812 mutex_lock(&devlink_mutex);
4e54795a 3813 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
fdd41ec2
PP
3814 if (IS_ERR(devlink)) {
3815 err = PTR_ERR(devlink);
dac7c08f 3816 goto out_dev;
fdd41ec2 3817 }
4e54795a 3818
4e54795a
AV
3819 mutex_lock(&devlink->lock);
3820
3821 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
fdd41ec2
PP
3822 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
3823 err = -EINVAL;
4e54795a 3824 goto out_unlock;
fdd41ec2 3825 }
4e54795a
AV
3826
3827 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3828 region = devlink_region_get_by_name(devlink, region_name);
fdd41ec2
PP
3829 if (!region) {
3830 err = -EINVAL;
4e54795a 3831 goto out_unlock;
fdd41ec2 3832 }
4e54795a
AV
3833
3834 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3835 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3836 DEVLINK_CMD_REGION_READ);
fdd41ec2
PP
3837 if (!hdr) {
3838 err = -EMSGSIZE;
4e54795a 3839 goto out_unlock;
fdd41ec2 3840 }
4e54795a
AV
3841
3842 err = devlink_nl_put_handle(skb, devlink);
3843 if (err)
3844 goto nla_put_failure;
3845
3846 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3847 if (err)
3848 goto nla_put_failure;
3849
ae0be8de 3850 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
fdd41ec2
PP
3851 if (!chunks_attr) {
3852 err = -EMSGSIZE;
4e54795a 3853 goto nla_put_failure;
fdd41ec2 3854 }
4e54795a
AV
3855
3856 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3857 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3858 if (!start_offset)
3859 start_offset =
3860 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3861
3862 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3863 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3864 dump = false;
3865 }
3866
3867 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3868 region, attrs,
3869 start_offset,
3870 end_offset, dump,
3871 &ret_offset);
3872
3873 if (err && err != -EMSGSIZE)
3874 goto nla_put_failure;
3875
3876 /* Check if there was any progress done to prevent infinite loop */
fdd41ec2
PP
3877 if (ret_offset == start_offset) {
3878 err = -EINVAL;
4e54795a 3879 goto nla_put_failure;
fdd41ec2 3880 }
4e54795a
AV
3881
3882 *((u64 *)&cb->args[0]) = ret_offset;
3883
3884 nla_nest_end(skb, chunks_attr);
3885 genlmsg_end(skb, hdr);
3886 mutex_unlock(&devlink->lock);
3887 mutex_unlock(&devlink_mutex);
68750561 3888 kfree(attrs);
4e54795a
AV
3889
3890 return skb->len;
3891
3892nla_put_failure:
3893 genlmsg_cancel(skb, hdr);
3894out_unlock:
3895 mutex_unlock(&devlink->lock);
dac7c08f 3896out_dev:
4e54795a 3897 mutex_unlock(&devlink_mutex);
68750561
JK
3898out_free:
3899 kfree(attrs);
fdd41ec2 3900 return err;
4e54795a
AV
3901}
3902
f9cf2288
JK
3903struct devlink_info_req {
3904 struct sk_buff *msg;
3905};
3906
3907int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3908{
3909 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3910}
3911EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3912
3913int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3914{
3915 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3916}
3917EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3918
fc6fae7d
JK
3919static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3920 const char *version_name,
3921 const char *version_value)
3922{
3923 struct nlattr *nest;
3924 int err;
3925
ae0be8de 3926 nest = nla_nest_start_noflag(req->msg, attr);
fc6fae7d
JK
3927 if (!nest)
3928 return -EMSGSIZE;
3929
3930 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3931 version_name);
3932 if (err)
3933 goto nla_put_failure;
3934
3935 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3936 version_value);
3937 if (err)
3938 goto nla_put_failure;
3939
3940 nla_nest_end(req->msg, nest);
3941
3942 return 0;
3943
3944nla_put_failure:
3945 nla_nest_cancel(req->msg, nest);
3946 return err;
3947}
3948
3949int devlink_info_version_fixed_put(struct devlink_info_req *req,
3950 const char *version_name,
3951 const char *version_value)
3952{
3953 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3954 version_name, version_value);
3955}
3956EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3957
3958int devlink_info_version_stored_put(struct devlink_info_req *req,
3959 const char *version_name,
3960 const char *version_value)
3961{
3962 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3963 version_name, version_value);
3964}
3965EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3966
3967int devlink_info_version_running_put(struct devlink_info_req *req,
3968 const char *version_name,
3969 const char *version_value)
3970{
3971 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3972 version_name, version_value);
3973}
3974EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3975
f9cf2288
JK
3976static int
3977devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3978 enum devlink_command cmd, u32 portid,
3979 u32 seq, int flags, struct netlink_ext_ack *extack)
3980{
3981 struct devlink_info_req req;
3982 void *hdr;
3983 int err;
3984
3985 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3986 if (!hdr)
3987 return -EMSGSIZE;
3988
3989 err = -EMSGSIZE;
3990 if (devlink_nl_put_handle(msg, devlink))
3991 goto err_cancel_msg;
3992
3993 req.msg = msg;
3994 err = devlink->ops->info_get(devlink, &req, extack);
3995 if (err)
3996 goto err_cancel_msg;
3997
3998 genlmsg_end(msg, hdr);
3999 return 0;
4000
4001err_cancel_msg:
4002 genlmsg_cancel(msg, hdr);
4003 return err;
4004}
4005
4006static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
4007 struct genl_info *info)
4008{
4009 struct devlink *devlink = info->user_ptr[0];
4010 struct sk_buff *msg;
4011 int err;
4012
be6fe1d8 4013 if (!devlink->ops->info_get)
f9cf2288
JK
4014 return -EOPNOTSUPP;
4015
4016 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4017 if (!msg)
4018 return -ENOMEM;
4019
4020 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4021 info->snd_portid, info->snd_seq, 0,
4022 info->extack);
4023 if (err) {
4024 nlmsg_free(msg);
4025 return err;
4026 }
4027
4028 return genlmsg_reply(msg, info);
4029}
4030
4031static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
4032 struct netlink_callback *cb)
4033{
4034 struct devlink *devlink;
4035 int start = cb->args[0];
4036 int idx = 0;
4037 int err;
4038
4039 mutex_lock(&devlink_mutex);
4040 list_for_each_entry(devlink, &devlink_list, list) {
4041 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4042 continue;
4043 if (idx < start) {
4044 idx++;
4045 continue;
4046 }
4047
c493b09b
JP
4048 if (!devlink->ops->info_get) {
4049 idx++;
4050 continue;
4051 }
4052
f9cf2288
JK
4053 mutex_lock(&devlink->lock);
4054 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4055 NETLINK_CB(cb->skb).portid,
4056 cb->nlh->nlmsg_seq, NLM_F_MULTI,
4057 cb->extack);
4058 mutex_unlock(&devlink->lock);
4059 if (err)
4060 break;
4061 idx++;
4062 }
4063 mutex_unlock(&devlink_mutex);
4064
4065 cb->args[0] = idx;
4066 return msg->len;
4067}
4068
1db64e87
EBE
4069struct devlink_fmsg_item {
4070 struct list_head list;
4071 int attrtype;
4072 u8 nla_type;
4073 u16 len;
4074 int value[0];
4075};
4076
4077struct devlink_fmsg {
4078 struct list_head item_list;
4079};
4080
4081static struct devlink_fmsg *devlink_fmsg_alloc(void)
4082{
4083 struct devlink_fmsg *fmsg;
4084
4085 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
4086 if (!fmsg)
4087 return NULL;
4088
4089 INIT_LIST_HEAD(&fmsg->item_list);
4090
4091 return fmsg;
4092}
4093
4094static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
4095{
4096 struct devlink_fmsg_item *item, *tmp;
4097
4098 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
4099 list_del(&item->list);
4100 kfree(item);
4101 }
4102 kfree(fmsg);
4103}
4104
4105static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
4106 int attrtype)
4107{
4108 struct devlink_fmsg_item *item;
4109
4110 item = kzalloc(sizeof(*item), GFP_KERNEL);
4111 if (!item)
4112 return -ENOMEM;
4113
4114 item->attrtype = attrtype;
4115 list_add_tail(&item->list, &fmsg->item_list);
4116
4117 return 0;
4118}
4119
4120int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
4121{
4122 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
4123}
4124EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
4125
4126static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
4127{
4128 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
4129}
4130
4131int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
4132{
4133 return devlink_fmsg_nest_end(fmsg);
4134}
4135EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
4136
4137#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
4138
4139static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
4140{
4141 struct devlink_fmsg_item *item;
4142
4143 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4144 return -EMSGSIZE;
4145
4146 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4147 if (!item)
4148 return -ENOMEM;
4149
4150 item->nla_type = NLA_NUL_STRING;
4151 item->len = strlen(name) + 1;
4152 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4153 memcpy(&item->value, name, item->len);
4154 list_add_tail(&item->list, &fmsg->item_list);
4155
4156 return 0;
4157}
4158
4159int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4160{
4161 int err;
4162
4163 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4164 if (err)
4165 return err;
4166
4167 err = devlink_fmsg_put_name(fmsg, name);
4168 if (err)
4169 return err;
4170
4171 return 0;
4172}
4173EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4174
4175int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4176{
4177 return devlink_fmsg_nest_end(fmsg);
4178}
4179EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4180
4181int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4182 const char *name)
4183{
4184 int err;
4185
4186 err = devlink_fmsg_pair_nest_start(fmsg, name);
4187 if (err)
4188 return err;
4189
4190 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4191 if (err)
4192 return err;
4193
4194 return 0;
4195}
4196EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4197
4198int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4199{
4200 int err;
4201
4202 err = devlink_fmsg_nest_end(fmsg);
4203 if (err)
4204 return err;
4205
4206 err = devlink_fmsg_nest_end(fmsg);
4207 if (err)
4208 return err;
4209
4210 return 0;
4211}
4212EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4213
4214static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4215 const void *value, u16 value_len,
4216 u8 value_nla_type)
4217{
4218 struct devlink_fmsg_item *item;
4219
4220 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4221 return -EMSGSIZE;
4222
4223 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4224 if (!item)
4225 return -ENOMEM;
4226
4227 item->nla_type = value_nla_type;
4228 item->len = value_len;
4229 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4230 memcpy(&item->value, value, item->len);
4231 list_add_tail(&item->list, &fmsg->item_list);
4232
4233 return 0;
4234}
4235
4236int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4237{
4238 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4239}
4240EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4241
4242int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4243{
4244 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4245}
4246EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4247
4248int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4249{
4250 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4251}
4252EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4253
4254int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4255{
4256 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4257}
4258EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4259
4260int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4261{
4262 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4263 NLA_NUL_STRING);
4264}
4265EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4266
4267int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4268 u16 value_len)
4269{
4270 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4271}
4272EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4273
4274int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4275 bool value)
4276{
4277 int err;
4278
4279 err = devlink_fmsg_pair_nest_start(fmsg, name);
4280 if (err)
4281 return err;
4282
4283 err = devlink_fmsg_bool_put(fmsg, value);
4284 if (err)
4285 return err;
4286
4287 err = devlink_fmsg_pair_nest_end(fmsg);
4288 if (err)
4289 return err;
4290
4291 return 0;
4292}
4293EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4294
4295int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4296 u8 value)
4297{
4298 int err;
4299
4300 err = devlink_fmsg_pair_nest_start(fmsg, name);
4301 if (err)
4302 return err;
4303
4304 err = devlink_fmsg_u8_put(fmsg, value);
4305 if (err)
4306 return err;
4307
4308 err = devlink_fmsg_pair_nest_end(fmsg);
4309 if (err)
4310 return err;
4311
4312 return 0;
4313}
4314EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4315
4316int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4317 u32 value)
4318{
4319 int err;
4320
4321 err = devlink_fmsg_pair_nest_start(fmsg, name);
4322 if (err)
4323 return err;
4324
4325 err = devlink_fmsg_u32_put(fmsg, value);
4326 if (err)
4327 return err;
4328
4329 err = devlink_fmsg_pair_nest_end(fmsg);
4330 if (err)
4331 return err;
4332
4333 return 0;
4334}
4335EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4336
4337int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4338 u64 value)
4339{
4340 int err;
4341
4342 err = devlink_fmsg_pair_nest_start(fmsg, name);
4343 if (err)
4344 return err;
4345
4346 err = devlink_fmsg_u64_put(fmsg, value);
4347 if (err)
4348 return err;
4349
4350 err = devlink_fmsg_pair_nest_end(fmsg);
4351 if (err)
4352 return err;
4353
4354 return 0;
4355}
4356EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4357
4358int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4359 const char *value)
4360{
4361 int err;
4362
4363 err = devlink_fmsg_pair_nest_start(fmsg, name);
4364 if (err)
4365 return err;
4366
4367 err = devlink_fmsg_string_put(fmsg, value);
4368 if (err)
4369 return err;
4370
4371 err = devlink_fmsg_pair_nest_end(fmsg);
4372 if (err)
4373 return err;
4374
4375 return 0;
4376}
4377EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4378
4379int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4380 const void *value, u16 value_len)
4381{
4382 int err;
4383
4384 err = devlink_fmsg_pair_nest_start(fmsg, name);
4385 if (err)
4386 return err;
4387
4388 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4389 if (err)
4390 return err;
4391
4392 err = devlink_fmsg_pair_nest_end(fmsg);
4393 if (err)
4394 return err;
4395
4396 return 0;
4397}
4398EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4399
4400static int
4401devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4402{
4403 switch (msg->nla_type) {
4404 case NLA_FLAG:
4405 case NLA_U8:
4406 case NLA_U32:
4407 case NLA_U64:
4408 case NLA_NUL_STRING:
4409 case NLA_BINARY:
4410 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4411 msg->nla_type);
4412 default:
4413 return -EINVAL;
4414 }
4415}
4416
4417static int
4418devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4419{
4420 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4421 u8 tmp;
4422
4423 switch (msg->nla_type) {
4424 case NLA_FLAG:
4425 /* Always provide flag data, regardless of its value */
4426 tmp = *(bool *) msg->value;
4427
4428 return nla_put_u8(skb, attrtype, tmp);
4429 case NLA_U8:
4430 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4431 case NLA_U32:
4432 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4433 case NLA_U64:
4434 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4435 DEVLINK_ATTR_PAD);
4436 case NLA_NUL_STRING:
4437 return nla_put_string(skb, attrtype, (char *) &msg->value);
4438 case NLA_BINARY:
4439 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4440 default:
4441 return -EINVAL;
4442 }
4443}
4444
4445static int
4446devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4447 int *start)
4448{
4449 struct devlink_fmsg_item *item;
4450 struct nlattr *fmsg_nlattr;
4451 int i = 0;
4452 int err;
4453
ae0be8de 4454 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
1db64e87
EBE
4455 if (!fmsg_nlattr)
4456 return -EMSGSIZE;
4457
4458 list_for_each_entry(item, &fmsg->item_list, list) {
4459 if (i < *start) {
4460 i++;
4461 continue;
4462 }
4463
4464 switch (item->attrtype) {
4465 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4466 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4467 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4468 case DEVLINK_ATTR_FMSG_NEST_END:
4469 err = nla_put_flag(skb, item->attrtype);
4470 break;
4471 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4472 err = devlink_fmsg_item_fill_type(item, skb);
4473 if (err)
4474 break;
4475 err = devlink_fmsg_item_fill_data(item, skb);
4476 break;
4477 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4478 err = nla_put_string(skb, item->attrtype,
4479 (char *) &item->value);
4480 break;
4481 default:
4482 err = -EINVAL;
4483 break;
4484 }
4485 if (!err)
4486 *start = ++i;
4487 else
4488 break;
4489 }
4490
4491 nla_nest_end(skb, fmsg_nlattr);
4492 return err;
4493}
4494
4495static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4496 struct genl_info *info,
4497 enum devlink_command cmd, int flags)
4498{
4499 struct nlmsghdr *nlh;
4500 struct sk_buff *skb;
4501 bool last = false;
4502 int index = 0;
4503 void *hdr;
4504 int err;
4505
4506 while (!last) {
4507 int tmp_index = index;
4508
4509 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4510 if (!skb)
4511 return -ENOMEM;
4512
4513 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4514 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4515 if (!hdr) {
4516 err = -EMSGSIZE;
4517 goto nla_put_failure;
4518 }
4519
4520 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4521 if (!err)
4522 last = true;
4523 else if (err != -EMSGSIZE || tmp_index == index)
4524 goto nla_put_failure;
4525
4526 genlmsg_end(skb, hdr);
4527 err = genlmsg_reply(skb, info);
4528 if (err)
4529 return err;
4530 }
4531
4532 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4533 if (!skb)
4534 return -ENOMEM;
4535 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4536 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4537 if (!nlh) {
4538 err = -EMSGSIZE;
4539 goto nla_put_failure;
4540 }
1db64e87 4541
fde55ea7 4542 return genlmsg_reply(skb, info);
1db64e87
EBE
4543
4544nla_put_failure:
4545 nlmsg_free(skb);
4546 return err;
4547}
4548
e44ef4e4
AL
4549static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4550 struct netlink_callback *cb,
4551 enum devlink_command cmd)
4552{
4553 int index = cb->args[0];
4554 int tmp_index = index;
4555 void *hdr;
4556 int err;
4557
4558 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4559 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
4560 if (!hdr) {
4561 err = -EMSGSIZE;
4562 goto nla_put_failure;
4563 }
4564
4565 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4566 if ((err && err != -EMSGSIZE) || tmp_index == index)
4567 goto nla_put_failure;
4568
4569 cb->args[0] = index;
4570 genlmsg_end(skb, hdr);
4571 return skb->len;
4572
4573nla_put_failure:
4574 genlmsg_cancel(skb, hdr);
4575 return err;
4576}
4577
a0bdcc59
EBE
4578struct devlink_health_reporter {
4579 struct list_head list;
4580 void *priv;
4581 const struct devlink_health_reporter_ops *ops;
4582 struct devlink *devlink;
c8e1da0b
EBE
4583 struct devlink_fmsg *dump_fmsg;
4584 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
a0bdcc59
EBE
4585 u64 graceful_period;
4586 bool auto_recover;
4587 u8 health_state;
c8e1da0b
EBE
4588 u64 dump_ts;
4589 u64 error_count;
4590 u64 recovery_count;
4591 u64 last_recovery_ts;
b587bdaf 4592 refcount_t refcount;
c8e1da0b
EBE
4593};
4594
a0bdcc59
EBE
4595void *
4596devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4597{
4598 return reporter->priv;
4599}
4600EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4601
4602static struct devlink_health_reporter *
4603devlink_health_reporter_find_by_name(struct devlink *devlink,
4604 const char *reporter_name)
4605{
4606 struct devlink_health_reporter *reporter;
4607
b587bdaf 4608 lockdep_assert_held(&devlink->reporters_lock);
a0bdcc59
EBE
4609 list_for_each_entry(reporter, &devlink->reporter_list, list)
4610 if (!strcmp(reporter->ops->name, reporter_name))
4611 return reporter;
4612 return NULL;
4613}
4614
4615/**
4616 * devlink_health_reporter_create - create devlink health reporter
4617 *
4618 * @devlink: devlink
4619 * @ops: ops
4620 * @graceful_period: to avoid recovery loops, in msecs
4621 * @auto_recover: auto recover when error occurs
4622 * @priv: priv
4623 */
4624struct devlink_health_reporter *
4625devlink_health_reporter_create(struct devlink *devlink,
4626 const struct devlink_health_reporter_ops *ops,
4627 u64 graceful_period, bool auto_recover,
4628 void *priv)
4629{
4630 struct devlink_health_reporter *reporter;
4631
b587bdaf 4632 mutex_lock(&devlink->reporters_lock);
a0bdcc59
EBE
4633 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4634 reporter = ERR_PTR(-EEXIST);
4635 goto unlock;
4636 }
4637
4638 if (WARN_ON(auto_recover && !ops->recover) ||
4639 WARN_ON(graceful_period && !ops->recover)) {
4640 reporter = ERR_PTR(-EINVAL);
4641 goto unlock;
4642 }
4643
4644 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4645 if (!reporter) {
4646 reporter = ERR_PTR(-ENOMEM);
4647 goto unlock;
4648 }
4649
4650 reporter->priv = priv;
4651 reporter->ops = ops;
4652 reporter->devlink = devlink;
4653 reporter->graceful_period = graceful_period;
4654 reporter->auto_recover = auto_recover;
c8e1da0b 4655 mutex_init(&reporter->dump_lock);
b587bdaf 4656 refcount_set(&reporter->refcount, 1);
a0bdcc59
EBE
4657 list_add_tail(&reporter->list, &devlink->reporter_list);
4658unlock:
b587bdaf 4659 mutex_unlock(&devlink->reporters_lock);
a0bdcc59
EBE
4660 return reporter;
4661}
4662EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4663
4664/**
4665 * devlink_health_reporter_destroy - destroy devlink health reporter
4666 *
4667 * @reporter: devlink health reporter to destroy
4668 */
4669void
4670devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4671{
b587bdaf 4672 mutex_lock(&reporter->devlink->reporters_lock);
a0bdcc59 4673 list_del(&reporter->list);
b587bdaf
MS
4674 mutex_unlock(&reporter->devlink->reporters_lock);
4675 while (refcount_read(&reporter->refcount) > 1)
4676 msleep(100);
375cf8c6 4677 mutex_destroy(&reporter->dump_lock);
c8e1da0b
EBE
4678 if (reporter->dump_fmsg)
4679 devlink_fmsg_free(reporter->dump_fmsg);
a0bdcc59
EBE
4680 kfree(reporter);
4681}
4682EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4683
3167b27a
EBE
4684void
4685devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
4686 enum devlink_health_reporter_state state)
4687{
4688 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
4689 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
4690 return;
4691
4692 if (reporter->health_state == state)
4693 return;
4694
4695 reporter->health_state = state;
4696 trace_devlink_health_reporter_state_update(reporter->devlink,
4697 reporter->ops->name, state);
4698}
4699EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
4700
c8e1da0b
EBE
4701static int
4702devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4703 void *priv_ctx)
4704{
4705 int err;
4706
4707 if (!reporter->ops->recover)
4708 return -EOPNOTSUPP;
4709
4710 err = reporter->ops->recover(reporter, priv_ctx);
4711 if (err)
4712 return err;
4713
4714 reporter->recovery_count++;
4715 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4716 reporter->last_recovery_ts = jiffies;
4717
4718 return 0;
4719}
4720
4721static void
4722devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4723{
4724 if (!reporter->dump_fmsg)
4725 return;
4726 devlink_fmsg_free(reporter->dump_fmsg);
4727 reporter->dump_fmsg = NULL;
4728}
4729
4730static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4731 void *priv_ctx)
4732{
4733 int err;
4734
4735 if (!reporter->ops->dump)
4736 return 0;
4737
4738 if (reporter->dump_fmsg)
4739 return 0;
4740
4741 reporter->dump_fmsg = devlink_fmsg_alloc();
4742 if (!reporter->dump_fmsg) {
4743 err = -ENOMEM;
4744 return err;
4745 }
4746
4747 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4748 if (err)
4749 goto dump_err;
4750
4751 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4752 priv_ctx);
4753 if (err)
4754 goto dump_err;
4755
4756 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4757 if (err)
4758 goto dump_err;
4759
4760 reporter->dump_ts = jiffies;
4761
4762 return 0;
4763
4764dump_err:
4765 devlink_health_dump_clear(reporter);
4766 return err;
4767}
4768
4769int devlink_health_report(struct devlink_health_reporter *reporter,
4770 const char *msg, void *priv_ctx)
4771{
a0a21adb 4772 enum devlink_health_reporter_state prev_health_state;
c8e1da0b
EBE
4773 struct devlink *devlink = reporter->devlink;
4774
4775 /* write a log message of the current error */
4776 WARN_ON(!msg);
4777 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4778 reporter->error_count++;
a0a21adb
EBE
4779 prev_health_state = reporter->health_state;
4780 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
c8e1da0b
EBE
4781
4782 /* abort if the previous error wasn't recovered */
4783 if (reporter->auto_recover &&
a0a21adb 4784 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
c8e1da0b
EBE
4785 jiffies - reporter->last_recovery_ts <
4786 msecs_to_jiffies(reporter->graceful_period))) {
4787 trace_devlink_health_recover_aborted(devlink,
4788 reporter->ops->name,
4789 reporter->health_state,
4790 jiffies -
4791 reporter->last_recovery_ts);
4792 return -ECANCELED;
4793 }
4794
4795 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4796
4797 mutex_lock(&reporter->dump_lock);
4798 /* store current dump of current error, for later analysis */
4799 devlink_health_do_dump(reporter, priv_ctx);
4800 mutex_unlock(&reporter->dump_lock);
4801
4802 if (reporter->auto_recover)
4803 return devlink_health_reporter_recover(reporter, priv_ctx);
4804
4805 return 0;
4806}
4807EXPORT_SYMBOL_GPL(devlink_health_report);
4808
7afe335a 4809static struct devlink_health_reporter *
e44ef4e4
AL
4810devlink_health_reporter_get_from_attrs(struct devlink *devlink,
4811 struct nlattr **attrs)
7afe335a 4812{
b587bdaf 4813 struct devlink_health_reporter *reporter;
7afe335a
EBE
4814 char *reporter_name;
4815
e44ef4e4 4816 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
7afe335a
EBE
4817 return NULL;
4818
e44ef4e4 4819 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
b587bdaf
MS
4820 mutex_lock(&devlink->reporters_lock);
4821 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
4822 if (reporter)
4823 refcount_inc(&reporter->refcount);
4824 mutex_unlock(&devlink->reporters_lock);
4825 return reporter;
4826}
4827
e44ef4e4
AL
4828static struct devlink_health_reporter *
4829devlink_health_reporter_get_from_info(struct devlink *devlink,
4830 struct genl_info *info)
4831{
4832 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
4833}
4834
4835static struct devlink_health_reporter *
4836devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
4837{
4838 struct devlink_health_reporter *reporter;
4839 struct devlink *devlink;
4840 struct nlattr **attrs;
4841 int err;
4842
4843 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
4844 if (!attrs)
4845 return NULL;
4846
4847 err = nlmsg_parse_deprecated(cb->nlh,
4848 GENL_HDRLEN + devlink_nl_family.hdrsize,
4849 attrs, DEVLINK_ATTR_MAX,
4850 devlink_nl_family.policy, cb->extack);
4851 if (err)
4852 goto free;
4853
4854 mutex_lock(&devlink_mutex);
4855 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
4856 if (IS_ERR(devlink))
4857 goto unlock;
4858
4859 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
4860 mutex_unlock(&devlink_mutex);
4861 kfree(attrs);
4862 return reporter;
4863unlock:
4864 mutex_unlock(&devlink_mutex);
4865free:
4866 kfree(attrs);
4867 return NULL;
4868}
4869
b587bdaf
MS
4870static void
4871devlink_health_reporter_put(struct devlink_health_reporter *reporter)
4872{
4873 refcount_dec(&reporter->refcount);
7afe335a
EBE
4874}
4875
4876static int
4877devlink_nl_health_reporter_fill(struct sk_buff *msg,
4878 struct devlink *devlink,
4879 struct devlink_health_reporter *reporter,
4880 enum devlink_command cmd, u32 portid,
4881 u32 seq, int flags)
4882{
4883 struct nlattr *reporter_attr;
4884 void *hdr;
4885
4886 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4887 if (!hdr)
4888 return -EMSGSIZE;
4889
4890 if (devlink_nl_put_handle(msg, devlink))
4891 goto genlmsg_cancel;
4892
ae0be8de
MK
4893 reporter_attr = nla_nest_start_noflag(msg,
4894 DEVLINK_ATTR_HEALTH_REPORTER);
7afe335a
EBE
4895 if (!reporter_attr)
4896 goto genlmsg_cancel;
4897 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4898 reporter->ops->name))
4899 goto reporter_nest_cancel;
4900 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4901 reporter->health_state))
4902 goto reporter_nest_cancel;
54719527 4903 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
7afe335a
EBE
4904 reporter->error_count, DEVLINK_ATTR_PAD))
4905 goto reporter_nest_cancel;
54719527 4906 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
7afe335a
EBE
4907 reporter->recovery_count, DEVLINK_ATTR_PAD))
4908 goto reporter_nest_cancel;
574b1e1f
AL
4909 if (reporter->ops->recover &&
4910 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
7afe335a
EBE
4911 reporter->graceful_period,
4912 DEVLINK_ATTR_PAD))
4913 goto reporter_nest_cancel;
574b1e1f
AL
4914 if (reporter->ops->recover &&
4915 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
7afe335a
EBE
4916 reporter->auto_recover))
4917 goto reporter_nest_cancel;
4918 if (reporter->dump_fmsg &&
4919 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4920 jiffies_to_msecs(reporter->dump_ts),
4921 DEVLINK_ATTR_PAD))
4922 goto reporter_nest_cancel;
4923
4924 nla_nest_end(msg, reporter_attr);
4925 genlmsg_end(msg, hdr);
4926 return 0;
4927
4928reporter_nest_cancel:
4929 nla_nest_end(msg, reporter_attr);
4930genlmsg_cancel:
4931 genlmsg_cancel(msg, hdr);
4932 return -EMSGSIZE;
4933}
4934
4935static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4936 struct genl_info *info)
4937{
4938 struct devlink *devlink = info->user_ptr[0];
4939 struct devlink_health_reporter *reporter;
4940 struct sk_buff *msg;
4941 int err;
4942
4943 reporter = devlink_health_reporter_get_from_info(devlink, info);
4944 if (!reporter)
4945 return -EINVAL;
4946
4947 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
b587bdaf
MS
4948 if (!msg) {
4949 err = -ENOMEM;
4950 goto out;
4951 }
7afe335a
EBE
4952
4953 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4954 DEVLINK_CMD_HEALTH_REPORTER_GET,
4955 info->snd_portid, info->snd_seq,
4956 0);
4957 if (err) {
4958 nlmsg_free(msg);
b587bdaf 4959 goto out;
7afe335a
EBE
4960 }
4961
b587bdaf
MS
4962 err = genlmsg_reply(msg, info);
4963out:
4964 devlink_health_reporter_put(reporter);
4965 return err;
7afe335a
EBE
4966}
4967
4968static int
4969devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4970 struct netlink_callback *cb)
4971{
4972 struct devlink_health_reporter *reporter;
4973 struct devlink *devlink;
4974 int start = cb->args[0];
4975 int idx = 0;
4976 int err;
4977
4978 mutex_lock(&devlink_mutex);
4979 list_for_each_entry(devlink, &devlink_list, list) {
4980 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4981 continue;
b587bdaf 4982 mutex_lock(&devlink->reporters_lock);
7afe335a
EBE
4983 list_for_each_entry(reporter, &devlink->reporter_list,
4984 list) {
4985 if (idx < start) {
4986 idx++;
4987 continue;
4988 }
4989 err = devlink_nl_health_reporter_fill(msg, devlink,
4990 reporter,
4991 DEVLINK_CMD_HEALTH_REPORTER_GET,
4992 NETLINK_CB(cb->skb).portid,
4993 cb->nlh->nlmsg_seq,
4994 NLM_F_MULTI);
4995 if (err) {
b587bdaf 4996 mutex_unlock(&devlink->reporters_lock);
7afe335a
EBE
4997 goto out;
4998 }
4999 idx++;
5000 }
b587bdaf 5001 mutex_unlock(&devlink->reporters_lock);
7afe335a
EBE
5002 }
5003out:
5004 mutex_unlock(&devlink_mutex);
5005
5006 cb->args[0] = idx;
5007 return msg->len;
5008}
5009
a1e55ec0
EBE
5010static int
5011devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
5012 struct genl_info *info)
5013{
5014 struct devlink *devlink = info->user_ptr[0];
5015 struct devlink_health_reporter *reporter;
b587bdaf 5016 int err;
a1e55ec0
EBE
5017
5018 reporter = devlink_health_reporter_get_from_info(devlink, info);
5019 if (!reporter)
5020 return -EINVAL;
5021
5022 if (!reporter->ops->recover &&
5023 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
b587bdaf
MS
5024 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
5025 err = -EOPNOTSUPP;
5026 goto out;
5027 }
a1e55ec0
EBE
5028
5029 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
5030 reporter->graceful_period =
5031 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
5032
5033 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
5034 reporter->auto_recover =
5035 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
5036
b587bdaf 5037 devlink_health_reporter_put(reporter);
a1e55ec0 5038 return 0;
b587bdaf
MS
5039out:
5040 devlink_health_reporter_put(reporter);
5041 return err;
a1e55ec0
EBE
5042}
5043
20a0943a
EBE
5044static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
5045 struct genl_info *info)
5046{
5047 struct devlink *devlink = info->user_ptr[0];
5048 struct devlink_health_reporter *reporter;
b587bdaf 5049 int err;
20a0943a
EBE
5050
5051 reporter = devlink_health_reporter_get_from_info(devlink, info);
5052 if (!reporter)
5053 return -EINVAL;
5054
b587bdaf
MS
5055 err = devlink_health_reporter_recover(reporter, NULL);
5056
5057 devlink_health_reporter_put(reporter);
5058 return err;
20a0943a
EBE
5059}
5060
fca42a27
EBE
5061static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
5062 struct genl_info *info)
5063{
5064 struct devlink *devlink = info->user_ptr[0];
5065 struct devlink_health_reporter *reporter;
5066 struct devlink_fmsg *fmsg;
5067 int err;
5068
5069 reporter = devlink_health_reporter_get_from_info(devlink, info);
5070 if (!reporter)
5071 return -EINVAL;
5072
b587bdaf
MS
5073 if (!reporter->ops->diagnose) {
5074 devlink_health_reporter_put(reporter);
fca42a27 5075 return -EOPNOTSUPP;
b587bdaf 5076 }
fca42a27
EBE
5077
5078 fmsg = devlink_fmsg_alloc();
b587bdaf
MS
5079 if (!fmsg) {
5080 devlink_health_reporter_put(reporter);
fca42a27 5081 return -ENOMEM;
b587bdaf 5082 }
fca42a27
EBE
5083
5084 err = devlink_fmsg_obj_nest_start(fmsg);
5085 if (err)
5086 goto out;
5087
5088 err = reporter->ops->diagnose(reporter, fmsg);
5089 if (err)
5090 goto out;
5091
5092 err = devlink_fmsg_obj_nest_end(fmsg);
5093 if (err)
5094 goto out;
5095
5096 err = devlink_fmsg_snd(fmsg, info,
5097 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
5098
5099out:
5100 devlink_fmsg_free(fmsg);
b587bdaf 5101 devlink_health_reporter_put(reporter);
fca42a27
EBE
5102 return err;
5103}
5104
e44ef4e4
AL
5105static int
5106devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
5107 struct netlink_callback *cb)
35455e23 5108{
35455e23 5109 struct devlink_health_reporter *reporter;
e44ef4e4 5110 u64 start = cb->args[0];
35455e23
EBE
5111 int err;
5112
e44ef4e4 5113 reporter = devlink_health_reporter_get_from_cb(cb);
35455e23
EBE
5114 if (!reporter)
5115 return -EINVAL;
5116
b587bdaf 5117 if (!reporter->ops->dump) {
e44ef4e4
AL
5118 err = -EOPNOTSUPP;
5119 goto out;
b587bdaf 5120 }
35455e23 5121 mutex_lock(&reporter->dump_lock);
e44ef4e4
AL
5122 if (!start) {
5123 err = devlink_health_do_dump(reporter, NULL);
5124 if (err)
5125 goto unlock;
5126 cb->args[1] = reporter->dump_ts;
5127 }
5128 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
5129 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
5130 err = -EAGAIN;
5131 goto unlock;
5132 }
35455e23 5133
e44ef4e4
AL
5134 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
5135 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
5136unlock:
35455e23 5137 mutex_unlock(&reporter->dump_lock);
e44ef4e4 5138out:
b587bdaf 5139 devlink_health_reporter_put(reporter);
35455e23
EBE
5140 return err;
5141}
5142
5143static int
5144devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
5145 struct genl_info *info)
5146{
5147 struct devlink *devlink = info->user_ptr[0];
5148 struct devlink_health_reporter *reporter;
5149
5150 reporter = devlink_health_reporter_get_from_info(devlink, info);
5151 if (!reporter)
5152 return -EINVAL;
5153
b587bdaf
MS
5154 if (!reporter->ops->dump) {
5155 devlink_health_reporter_put(reporter);
35455e23 5156 return -EOPNOTSUPP;
b587bdaf 5157 }
35455e23
EBE
5158
5159 mutex_lock(&reporter->dump_lock);
5160 devlink_health_dump_clear(reporter);
5161 mutex_unlock(&reporter->dump_lock);
b587bdaf 5162 devlink_health_reporter_put(reporter);
35455e23
EBE
5163 return 0;
5164}
5165
0f420b6c
IS
5166struct devlink_stats {
5167 u64 rx_bytes;
5168 u64 rx_packets;
5169 struct u64_stats_sync syncp;
5170};
5171
5172/**
5173 * struct devlink_trap_group_item - Packet trap group attributes.
5174 * @group: Immutable packet trap group attributes.
5175 * @refcount: Number of trap items using the group.
5176 * @list: trap_group_list member.
5177 * @stats: Trap group statistics.
5178 *
5179 * Describes packet trap group attributes. Created by devlink during trap
5180 * registration.
5181 */
5182struct devlink_trap_group_item {
5183 const struct devlink_trap_group *group;
5184 refcount_t refcount;
5185 struct list_head list;
5186 struct devlink_stats __percpu *stats;
5187};
5188
5189/**
5190 * struct devlink_trap_item - Packet trap attributes.
5191 * @trap: Immutable packet trap attributes.
5192 * @group_item: Associated group item.
5193 * @list: trap_list member.
5194 * @action: Trap action.
5195 * @stats: Trap statistics.
5196 * @priv: Driver private information.
5197 *
5198 * Describes both mutable and immutable packet trap attributes. Created by
5199 * devlink during trap registration and used for all trap related operations.
5200 */
5201struct devlink_trap_item {
5202 const struct devlink_trap *trap;
5203 struct devlink_trap_group_item *group_item;
5204 struct list_head list;
5205 enum devlink_trap_action action;
5206 struct devlink_stats __percpu *stats;
5207 void *priv;
5208};
5209
5210static struct devlink_trap_item *
5211devlink_trap_item_lookup(struct devlink *devlink, const char *name)
5212{
5213 struct devlink_trap_item *trap_item;
5214
5215 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5216 if (!strcmp(trap_item->trap->name, name))
5217 return trap_item;
5218 }
5219
5220 return NULL;
5221}
5222
5223static struct devlink_trap_item *
5224devlink_trap_item_get_from_info(struct devlink *devlink,
5225 struct genl_info *info)
5226{
5227 struct nlattr *attr;
5228
5229 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
5230 return NULL;
5231 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
5232
5233 return devlink_trap_item_lookup(devlink, nla_data(attr));
5234}
5235
5236static int
5237devlink_trap_action_get_from_info(struct genl_info *info,
5238 enum devlink_trap_action *p_trap_action)
5239{
5240 u8 val;
5241
5242 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
5243 switch (val) {
5244 case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
5245 case DEVLINK_TRAP_ACTION_TRAP:
5246 *p_trap_action = val;
5247 break;
5248 default:
5249 return -EINVAL;
5250 }
5251
5252 return 0;
5253}
5254
5255static int devlink_trap_metadata_put(struct sk_buff *msg,
5256 const struct devlink_trap *trap)
5257{
5258 struct nlattr *attr;
5259
5260 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
5261 if (!attr)
5262 return -EMSGSIZE;
5263
5264 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
5265 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
5266 goto nla_put_failure;
5267
5268 nla_nest_end(msg, attr);
5269
5270 return 0;
5271
5272nla_put_failure:
5273 nla_nest_cancel(msg, attr);
5274 return -EMSGSIZE;
5275}
5276
5277static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
5278 struct devlink_stats *stats)
5279{
5280 int i;
5281
5282 memset(stats, 0, sizeof(*stats));
5283 for_each_possible_cpu(i) {
5284 struct devlink_stats *cpu_stats;
5285 u64 rx_packets, rx_bytes;
5286 unsigned int start;
5287
5288 cpu_stats = per_cpu_ptr(trap_stats, i);
5289 do {
5290 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
5291 rx_packets = cpu_stats->rx_packets;
5292 rx_bytes = cpu_stats->rx_bytes;
5293 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
5294
5295 stats->rx_packets += rx_packets;
5296 stats->rx_bytes += rx_bytes;
5297 }
5298}
5299
5300static int devlink_trap_stats_put(struct sk_buff *msg,
5301 struct devlink_stats __percpu *trap_stats)
5302{
5303 struct devlink_stats stats;
5304 struct nlattr *attr;
5305
5306 devlink_trap_stats_read(trap_stats, &stats);
5307
5308 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
5309 if (!attr)
5310 return -EMSGSIZE;
5311
5312 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
5313 stats.rx_packets, DEVLINK_ATTR_PAD))
5314 goto nla_put_failure;
5315
5316 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
5317 stats.rx_bytes, DEVLINK_ATTR_PAD))
5318 goto nla_put_failure;
5319
5320 nla_nest_end(msg, attr);
5321
5322 return 0;
5323
5324nla_put_failure:
5325 nla_nest_cancel(msg, attr);
5326 return -EMSGSIZE;
5327}
5328
5329static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
5330 const struct devlink_trap_item *trap_item,
5331 enum devlink_command cmd, u32 portid, u32 seq,
5332 int flags)
5333{
5334 struct devlink_trap_group_item *group_item = trap_item->group_item;
5335 void *hdr;
5336 int err;
5337
5338 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5339 if (!hdr)
5340 return -EMSGSIZE;
5341
5342 if (devlink_nl_put_handle(msg, devlink))
5343 goto nla_put_failure;
5344
5345 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
5346 group_item->group->name))
5347 goto nla_put_failure;
5348
5349 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
5350 goto nla_put_failure;
5351
5352 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
5353 goto nla_put_failure;
5354
5355 if (trap_item->trap->generic &&
5356 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
5357 goto nla_put_failure;
5358
5359 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
5360 goto nla_put_failure;
5361
5362 err = devlink_trap_metadata_put(msg, trap_item->trap);
5363 if (err)
5364 goto nla_put_failure;
5365
5366 err = devlink_trap_stats_put(msg, trap_item->stats);
5367 if (err)
5368 goto nla_put_failure;
5369
5370 genlmsg_end(msg, hdr);
5371
5372 return 0;
5373
5374nla_put_failure:
5375 genlmsg_cancel(msg, hdr);
5376 return -EMSGSIZE;
5377}
5378
5379static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
5380 struct genl_info *info)
5381{
5382 struct netlink_ext_ack *extack = info->extack;
5383 struct devlink *devlink = info->user_ptr[0];
5384 struct devlink_trap_item *trap_item;
5385 struct sk_buff *msg;
5386 int err;
5387
5388 if (list_empty(&devlink->trap_list))
5389 return -EOPNOTSUPP;
5390
5391 trap_item = devlink_trap_item_get_from_info(devlink, info);
5392 if (!trap_item) {
5393 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
5394 return -ENOENT;
5395 }
5396
5397 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5398 if (!msg)
5399 return -ENOMEM;
5400
5401 err = devlink_nl_trap_fill(msg, devlink, trap_item,
5402 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
5403 info->snd_seq, 0);
5404 if (err)
5405 goto err_trap_fill;
5406
5407 return genlmsg_reply(msg, info);
5408
5409err_trap_fill:
5410 nlmsg_free(msg);
5411 return err;
5412}
5413
5414static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
5415 struct netlink_callback *cb)
5416{
5417 struct devlink_trap_item *trap_item;
5418 struct devlink *devlink;
5419 int start = cb->args[0];
5420 int idx = 0;
5421 int err;
5422
5423 mutex_lock(&devlink_mutex);
5424 list_for_each_entry(devlink, &devlink_list, list) {
5425 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5426 continue;
5427 mutex_lock(&devlink->lock);
5428 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5429 if (idx < start) {
5430 idx++;
5431 continue;
5432 }
5433 err = devlink_nl_trap_fill(msg, devlink, trap_item,
5434 DEVLINK_CMD_TRAP_NEW,
5435 NETLINK_CB(cb->skb).portid,
5436 cb->nlh->nlmsg_seq,
5437 NLM_F_MULTI);
5438 if (err) {
5439 mutex_unlock(&devlink->lock);
5440 goto out;
5441 }
5442 idx++;
5443 }
5444 mutex_unlock(&devlink->lock);
5445 }
5446out:
5447 mutex_unlock(&devlink_mutex);
5448
5449 cb->args[0] = idx;
5450 return msg->len;
5451}
5452
5453static int __devlink_trap_action_set(struct devlink *devlink,
5454 struct devlink_trap_item *trap_item,
5455 enum devlink_trap_action trap_action,
5456 struct netlink_ext_ack *extack)
5457{
5458 int err;
5459
5460 if (trap_item->action != trap_action &&
5461 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
5462 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
5463 return 0;
5464 }
5465
5466 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
5467 trap_action);
5468 if (err)
5469 return err;
5470
5471 trap_item->action = trap_action;
5472
5473 return 0;
5474}
5475
5476static int devlink_trap_action_set(struct devlink *devlink,
5477 struct devlink_trap_item *trap_item,
5478 struct genl_info *info)
5479{
5480 enum devlink_trap_action trap_action;
5481 int err;
5482
5483 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
5484 return 0;
5485
5486 err = devlink_trap_action_get_from_info(info, &trap_action);
5487 if (err) {
5488 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
5489 return -EINVAL;
5490 }
5491
5492 return __devlink_trap_action_set(devlink, trap_item, trap_action,
5493 info->extack);
5494}
5495
5496static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
5497 struct genl_info *info)
5498{
5499 struct netlink_ext_ack *extack = info->extack;
5500 struct devlink *devlink = info->user_ptr[0];
5501 struct devlink_trap_item *trap_item;
5502 int err;
5503
5504 if (list_empty(&devlink->trap_list))
5505 return -EOPNOTSUPP;
5506
5507 trap_item = devlink_trap_item_get_from_info(devlink, info);
5508 if (!trap_item) {
5509 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
5510 return -ENOENT;
5511 }
5512
5513 err = devlink_trap_action_set(devlink, trap_item, info);
5514 if (err)
5515 return err;
5516
5517 return 0;
5518}
5519
5520static struct devlink_trap_group_item *
5521devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
5522{
5523 struct devlink_trap_group_item *group_item;
5524
5525 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
5526 if (!strcmp(group_item->group->name, name))
5527 return group_item;
5528 }
5529
5530 return NULL;
5531}
5532
5533static struct devlink_trap_group_item *
5534devlink_trap_group_item_get_from_info(struct devlink *devlink,
5535 struct genl_info *info)
5536{
5537 char *name;
5538
5539 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
5540 return NULL;
5541 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
5542
5543 return devlink_trap_group_item_lookup(devlink, name);
5544}
5545
5546static int
5547devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
5548 const struct devlink_trap_group_item *group_item,
5549 enum devlink_command cmd, u32 portid, u32 seq,
5550 int flags)
5551{
5552 void *hdr;
5553 int err;
5554
5555 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5556 if (!hdr)
5557 return -EMSGSIZE;
5558
5559 if (devlink_nl_put_handle(msg, devlink))
5560 goto nla_put_failure;
5561
5562 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
5563 group_item->group->name))
5564 goto nla_put_failure;
5565
5566 if (group_item->group->generic &&
5567 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
5568 goto nla_put_failure;
5569
5570 err = devlink_trap_stats_put(msg, group_item->stats);
5571 if (err)
5572 goto nla_put_failure;
5573
5574 genlmsg_end(msg, hdr);
5575
5576 return 0;
5577
5578nla_put_failure:
5579 genlmsg_cancel(msg, hdr);
5580 return -EMSGSIZE;
5581}
5582
5583static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
5584 struct genl_info *info)
5585{
5586 struct netlink_ext_ack *extack = info->extack;
5587 struct devlink *devlink = info->user_ptr[0];
5588 struct devlink_trap_group_item *group_item;
5589 struct sk_buff *msg;
5590 int err;
5591
5592 if (list_empty(&devlink->trap_group_list))
5593 return -EOPNOTSUPP;
5594
5595 group_item = devlink_trap_group_item_get_from_info(devlink, info);
5596 if (!group_item) {
5597 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
5598 return -ENOENT;
5599 }
5600
5601 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5602 if (!msg)
5603 return -ENOMEM;
5604
5605 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
5606 DEVLINK_CMD_TRAP_GROUP_NEW,
5607 info->snd_portid, info->snd_seq, 0);
5608 if (err)
5609 goto err_trap_group_fill;
5610
5611 return genlmsg_reply(msg, info);
5612
5613err_trap_group_fill:
5614 nlmsg_free(msg);
5615 return err;
5616}
5617
5618static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
5619 struct netlink_callback *cb)
5620{
5621 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
5622 struct devlink_trap_group_item *group_item;
5623 u32 portid = NETLINK_CB(cb->skb).portid;
5624 struct devlink *devlink;
5625 int start = cb->args[0];
5626 int idx = 0;
5627 int err;
5628
5629 mutex_lock(&devlink_mutex);
5630 list_for_each_entry(devlink, &devlink_list, list) {
5631 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5632 continue;
5633 mutex_lock(&devlink->lock);
5634 list_for_each_entry(group_item, &devlink->trap_group_list,
5635 list) {
5636 if (idx < start) {
5637 idx++;
5638 continue;
5639 }
5640 err = devlink_nl_trap_group_fill(msg, devlink,
5641 group_item, cmd,
5642 portid,
5643 cb->nlh->nlmsg_seq,
5644 NLM_F_MULTI);
5645 if (err) {
5646 mutex_unlock(&devlink->lock);
5647 goto out;
5648 }
5649 idx++;
5650 }
5651 mutex_unlock(&devlink->lock);
5652 }
5653out:
5654 mutex_unlock(&devlink_mutex);
5655
5656 cb->args[0] = idx;
5657 return msg->len;
5658}
5659
5660static int
5661__devlink_trap_group_action_set(struct devlink *devlink,
5662 struct devlink_trap_group_item *group_item,
5663 enum devlink_trap_action trap_action,
5664 struct netlink_ext_ack *extack)
5665{
5666 const char *group_name = group_item->group->name;
5667 struct devlink_trap_item *trap_item;
5668 int err;
5669
5670 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5671 if (strcmp(trap_item->trap->group.name, group_name))
5672 continue;
5673 err = __devlink_trap_action_set(devlink, trap_item,
5674 trap_action, extack);
5675 if (err)
5676 return err;
5677 }
5678
5679 return 0;
5680}
5681
5682static int
5683devlink_trap_group_action_set(struct devlink *devlink,
5684 struct devlink_trap_group_item *group_item,
5685 struct genl_info *info)
5686{
5687 enum devlink_trap_action trap_action;
5688 int err;
5689
5690 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
5691 return 0;
5692
5693 err = devlink_trap_action_get_from_info(info, &trap_action);
5694 if (err) {
5695 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
5696 return -EINVAL;
5697 }
5698
5699 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
5700 info->extack);
5701 if (err)
5702 return err;
5703
5704 return 0;
5705}
5706
5707static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
5708 struct genl_info *info)
5709{
5710 struct netlink_ext_ack *extack = info->extack;
5711 struct devlink *devlink = info->user_ptr[0];
5712 struct devlink_trap_group_item *group_item;
5713 int err;
5714
5715 if (list_empty(&devlink->trap_group_list))
5716 return -EOPNOTSUPP;
5717
5718 group_item = devlink_trap_group_item_get_from_info(devlink, info);
5719 if (!group_item) {
5720 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
5721 return -ENOENT;
5722 }
5723
5724 err = devlink_trap_group_action_set(devlink, group_item, info);
5725 if (err)
5726 return err;
5727
5728 return 0;
5729}
5730
bfcd3a46
JP
5731static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
5732 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
5733 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
5734 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
5735 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
5736 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
bf797471
JP
5737 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
5738 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
5739 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
5740 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
5741 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
5742 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
5743 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
08f4b591 5744 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
59bfde01 5745 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
f43e9b06 5746 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
1555d204
AS
5747 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
5748 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
d9f9b9a4
AS
5749 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
5750 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
e3b7ca18
MS
5751 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
5752 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
5753 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
d8db7ea5 5754 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
866319bb 5755 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
7afe335a 5756 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
a1e55ec0
EBE
5757 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
5758 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
76726ccb
JK
5759 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
5760 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
0f420b6c
IS
5761 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
5762 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
5763 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
bfcd3a46
JP
5764};
5765
5766static const struct genl_ops devlink_nl_ops[] = {
5767 {
5768 .cmd = DEVLINK_CMD_GET,
ef6243ac 5769 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46
JP
5770 .doit = devlink_nl_cmd_get_doit,
5771 .dumpit = devlink_nl_cmd_get_dumpit,
1fc2257e 5772 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
bfcd3a46
JP
5773 /* can be retrieved by unprivileged users */
5774 },
5775 {
5776 .cmd = DEVLINK_CMD_PORT_GET,
ef6243ac 5777 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46
JP
5778 .doit = devlink_nl_cmd_port_get_doit,
5779 .dumpit = devlink_nl_cmd_port_get_dumpit,
bfcd3a46
JP
5780 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5781 /* can be retrieved by unprivileged users */
5782 },
5783 {
5784 .cmd = DEVLINK_CMD_PORT_SET,
ef6243ac 5785 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46 5786 .doit = devlink_nl_cmd_port_set_doit,
bfcd3a46
JP
5787 .flags = GENL_ADMIN_PERM,
5788 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5789 },
5790 {
5791 .cmd = DEVLINK_CMD_PORT_SPLIT,
ef6243ac 5792 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46 5793 .doit = devlink_nl_cmd_port_split_doit,
bfcd3a46 5794 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
5795 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5796 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46
JP
5797 },
5798 {
5799 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
ef6243ac 5800 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46 5801 .doit = devlink_nl_cmd_port_unsplit_doit,
bfcd3a46 5802 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
5803 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5804 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46 5805 },
bf797471
JP
5806 {
5807 .cmd = DEVLINK_CMD_SB_GET,
ef6243ac 5808 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471
JP
5809 .doit = devlink_nl_cmd_sb_get_doit,
5810 .dumpit = devlink_nl_cmd_sb_get_dumpit,
bf797471
JP
5811 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5812 DEVLINK_NL_FLAG_NEED_SB,
5813 /* can be retrieved by unprivileged users */
5814 },
5815 {
5816 .cmd = DEVLINK_CMD_SB_POOL_GET,
ef6243ac 5817 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471
JP
5818 .doit = devlink_nl_cmd_sb_pool_get_doit,
5819 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
bf797471
JP
5820 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5821 DEVLINK_NL_FLAG_NEED_SB,
5822 /* can be retrieved by unprivileged users */
5823 },
5824 {
5825 .cmd = DEVLINK_CMD_SB_POOL_SET,
ef6243ac 5826 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471 5827 .doit = devlink_nl_cmd_sb_pool_set_doit,
bf797471
JP
5828 .flags = GENL_ADMIN_PERM,
5829 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5830 DEVLINK_NL_FLAG_NEED_SB,
5831 },
5832 {
5833 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
ef6243ac 5834 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471
JP
5835 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
5836 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
bf797471
JP
5837 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5838 DEVLINK_NL_FLAG_NEED_SB,
5839 /* can be retrieved by unprivileged users */
5840 },
5841 {
5842 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
ef6243ac 5843 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471 5844 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
bf797471
JP
5845 .flags = GENL_ADMIN_PERM,
5846 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5847 DEVLINK_NL_FLAG_NEED_SB,
5848 },
5849 {
5850 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
ef6243ac 5851 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471
JP
5852 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
5853 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
bf797471
JP
5854 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5855 DEVLINK_NL_FLAG_NEED_SB,
5856 /* can be retrieved by unprivileged users */
5857 },
5858 {
5859 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
ef6243ac 5860 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471 5861 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
bf797471
JP
5862 .flags = GENL_ADMIN_PERM,
5863 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5864 DEVLINK_NL_FLAG_NEED_SB,
5865 },
df38dafd
JP
5866 {
5867 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
ef6243ac 5868 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
df38dafd 5869 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
df38dafd
JP
5870 .flags = GENL_ADMIN_PERM,
5871 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 5872 DEVLINK_NL_FLAG_NEED_SB,
df38dafd
JP
5873 },
5874 {
5875 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
ef6243ac 5876 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
df38dafd 5877 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
df38dafd
JP
5878 .flags = GENL_ADMIN_PERM,
5879 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 5880 DEVLINK_NL_FLAG_NEED_SB,
df38dafd 5881 },
08f4b591 5882 {
adf200f3 5883 .cmd = DEVLINK_CMD_ESWITCH_GET,
ef6243ac 5884 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
adf200f3 5885 .doit = devlink_nl_cmd_eswitch_get_doit,
08f4b591
OG
5886 .flags = GENL_ADMIN_PERM,
5887 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5888 },
5889 {
adf200f3 5890 .cmd = DEVLINK_CMD_ESWITCH_SET,
ef6243ac 5891 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
adf200f3 5892 .doit = devlink_nl_cmd_eswitch_set_doit,
08f4b591 5893 .flags = GENL_ADMIN_PERM,
7ac1cc9a
JK
5894 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5895 DEVLINK_NL_FLAG_NO_LOCK,
08f4b591 5896 },
1555d204
AS
5897 {
5898 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
ef6243ac 5899 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1555d204 5900 .doit = devlink_nl_cmd_dpipe_table_get,
1555d204 5901 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5902 /* can be retrieved by unprivileged users */
1555d204
AS
5903 },
5904 {
5905 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
ef6243ac 5906 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1555d204 5907 .doit = devlink_nl_cmd_dpipe_entries_get,
1555d204 5908 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5909 /* can be retrieved by unprivileged users */
1555d204
AS
5910 },
5911 {
5912 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
ef6243ac 5913 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1555d204 5914 .doit = devlink_nl_cmd_dpipe_headers_get,
1555d204 5915 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5916 /* can be retrieved by unprivileged users */
1555d204
AS
5917 },
5918 {
5919 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
ef6243ac 5920 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1555d204 5921 .doit = devlink_nl_cmd_dpipe_table_counters_set,
1555d204
AS
5922 .flags = GENL_ADMIN_PERM,
5923 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5924 },
d9f9b9a4
AS
5925 {
5926 .cmd = DEVLINK_CMD_RESOURCE_SET,
ef6243ac 5927 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
d9f9b9a4 5928 .doit = devlink_nl_cmd_resource_set,
d9f9b9a4
AS
5929 .flags = GENL_ADMIN_PERM,
5930 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5931 },
5932 {
5933 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
ef6243ac 5934 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
d9f9b9a4 5935 .doit = devlink_nl_cmd_resource_dump,
d9f9b9a4 5936 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5937 /* can be retrieved by unprivileged users */
d9f9b9a4 5938 },
2d8dc5bb
AS
5939 {
5940 .cmd = DEVLINK_CMD_RELOAD,
ef6243ac 5941 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
2d8dc5bb 5942 .doit = devlink_nl_cmd_reload,
2d8dc5bb
AS
5943 .flags = GENL_ADMIN_PERM,
5944 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5945 DEVLINK_NL_FLAG_NO_LOCK,
5946 },
45f05def
MS
5947 {
5948 .cmd = DEVLINK_CMD_PARAM_GET,
ef6243ac 5949 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
45f05def
MS
5950 .doit = devlink_nl_cmd_param_get_doit,
5951 .dumpit = devlink_nl_cmd_param_get_dumpit,
45f05def
MS
5952 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5953 /* can be retrieved by unprivileged users */
5954 },
e3b7ca18
MS
5955 {
5956 .cmd = DEVLINK_CMD_PARAM_SET,
ef6243ac 5957 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
e3b7ca18 5958 .doit = devlink_nl_cmd_param_set_doit,
e3b7ca18
MS
5959 .flags = GENL_ADMIN_PERM,
5960 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5961 },
f4601dee
VV
5962 {
5963 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
ef6243ac 5964 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
f4601dee
VV
5965 .doit = devlink_nl_cmd_port_param_get_doit,
5966 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
f4601dee
VV
5967 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5968 /* can be retrieved by unprivileged users */
5969 },
9c54873b
VV
5970 {
5971 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
ef6243ac 5972 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
9c54873b 5973 .doit = devlink_nl_cmd_port_param_set_doit,
9c54873b
VV
5974 .flags = GENL_ADMIN_PERM,
5975 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5976 },
d8db7ea5
AV
5977 {
5978 .cmd = DEVLINK_CMD_REGION_GET,
ef6243ac 5979 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
d8db7ea5
AV
5980 .doit = devlink_nl_cmd_region_get_doit,
5981 .dumpit = devlink_nl_cmd_region_get_dumpit,
d8db7ea5
AV
5982 .flags = GENL_ADMIN_PERM,
5983 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5984 },
866319bb
AV
5985 {
5986 .cmd = DEVLINK_CMD_REGION_DEL,
ef6243ac 5987 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
866319bb 5988 .doit = devlink_nl_cmd_region_del,
866319bb
AV
5989 .flags = GENL_ADMIN_PERM,
5990 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5991 },
4e54795a
AV
5992 {
5993 .cmd = DEVLINK_CMD_REGION_READ,
ef6243ac 5994 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
4e54795a 5995 .dumpit = devlink_nl_cmd_region_read_dumpit,
4e54795a
AV
5996 .flags = GENL_ADMIN_PERM,
5997 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5998 },
f9cf2288
JK
5999 {
6000 .cmd = DEVLINK_CMD_INFO_GET,
ef6243ac 6001 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
f9cf2288
JK
6002 .doit = devlink_nl_cmd_info_get_doit,
6003 .dumpit = devlink_nl_cmd_info_get_dumpit,
f9cf2288
JK
6004 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6005 /* can be retrieved by unprivileged users */
6006 },
7afe335a
EBE
6007 {
6008 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
ef6243ac 6009 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7afe335a
EBE
6010 .doit = devlink_nl_cmd_health_reporter_get_doit,
6011 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
b587bdaf
MS
6012 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6013 DEVLINK_NL_FLAG_NO_LOCK,
7afe335a
EBE
6014 /* can be retrieved by unprivileged users */
6015 },
a1e55ec0
EBE
6016 {
6017 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
ef6243ac 6018 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
a1e55ec0 6019 .doit = devlink_nl_cmd_health_reporter_set_doit,
a1e55ec0 6020 .flags = GENL_ADMIN_PERM,
b587bdaf
MS
6021 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6022 DEVLINK_NL_FLAG_NO_LOCK,
a1e55ec0 6023 },
20a0943a
EBE
6024 {
6025 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
ef6243ac 6026 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
20a0943a 6027 .doit = devlink_nl_cmd_health_reporter_recover_doit,
20a0943a 6028 .flags = GENL_ADMIN_PERM,
b587bdaf
MS
6029 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6030 DEVLINK_NL_FLAG_NO_LOCK,
20a0943a 6031 },
fca42a27
EBE
6032 {
6033 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
ef6243ac 6034 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
fca42a27 6035 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
fca42a27 6036 .flags = GENL_ADMIN_PERM,
b587bdaf
MS
6037 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6038 DEVLINK_NL_FLAG_NO_LOCK,
fca42a27 6039 },
35455e23
EBE
6040 {
6041 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
ef6243ac 6042 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
e44ef4e4 6043 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
35455e23
EBE
6044 .flags = GENL_ADMIN_PERM,
6045 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6046 DEVLINK_NL_FLAG_NO_LOCK,
6047 },
6048 {
6049 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
ef6243ac 6050 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
35455e23 6051 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
35455e23
EBE
6052 .flags = GENL_ADMIN_PERM,
6053 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6054 DEVLINK_NL_FLAG_NO_LOCK,
6055 },
76726ccb
JK
6056 {
6057 .cmd = DEVLINK_CMD_FLASH_UPDATE,
ef6243ac 6058 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76726ccb 6059 .doit = devlink_nl_cmd_flash_update,
76726ccb
JK
6060 .flags = GENL_ADMIN_PERM,
6061 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6062 },
0f420b6c
IS
6063 {
6064 .cmd = DEVLINK_CMD_TRAP_GET,
6065 .doit = devlink_nl_cmd_trap_get_doit,
6066 .dumpit = devlink_nl_cmd_trap_get_dumpit,
6067 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6068 /* can be retrieved by unprivileged users */
6069 },
6070 {
6071 .cmd = DEVLINK_CMD_TRAP_SET,
6072 .doit = devlink_nl_cmd_trap_set_doit,
6073 .flags = GENL_ADMIN_PERM,
6074 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6075 },
6076 {
6077 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
6078 .doit = devlink_nl_cmd_trap_group_get_doit,
6079 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
6080 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6081 /* can be retrieved by unprivileged users */
6082 },
6083 {
6084 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
6085 .doit = devlink_nl_cmd_trap_group_set_doit,
6086 .flags = GENL_ADMIN_PERM,
6087 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6088 },
bfcd3a46
JP
6089};
6090
56989f6d 6091static struct genl_family devlink_nl_family __ro_after_init = {
489111e5
JB
6092 .name = DEVLINK_GENL_NAME,
6093 .version = DEVLINK_GENL_VERSION,
6094 .maxattr = DEVLINK_ATTR_MAX,
3b0f31f2 6095 .policy = devlink_nl_policy,
489111e5
JB
6096 .netnsok = true,
6097 .pre_doit = devlink_nl_pre_doit,
6098 .post_doit = devlink_nl_post_doit,
6099 .module = THIS_MODULE,
6100 .ops = devlink_nl_ops,
6101 .n_ops = ARRAY_SIZE(devlink_nl_ops),
6102 .mcgrps = devlink_nl_mcgrps,
6103 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
6104};
6105
bfcd3a46
JP
6106/**
6107 * devlink_alloc - Allocate new devlink instance resources
6108 *
6109 * @ops: ops
6110 * @priv_size: size of user private data
6111 *
6112 * Allocate new devlink instance resources, including devlink index
6113 * and name.
6114 */
6115struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
6116{
6117 struct devlink *devlink;
6118
be6fe1d8
JK
6119 if (WARN_ON(!ops))
6120 return NULL;
6121
bfcd3a46
JP
6122 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
6123 if (!devlink)
6124 return NULL;
6125 devlink->ops = ops;
6126 devlink_net_set(devlink, &init_net);
6127 INIT_LIST_HEAD(&devlink->port_list);
bf797471 6128 INIT_LIST_HEAD(&devlink->sb_list);
1555d204 6129 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
d9f9b9a4 6130 INIT_LIST_HEAD(&devlink->resource_list);
eabaef18 6131 INIT_LIST_HEAD(&devlink->param_list);
b16ebe92 6132 INIT_LIST_HEAD(&devlink->region_list);
a0bdcc59 6133 INIT_LIST_HEAD(&devlink->reporter_list);
0f420b6c
IS
6134 INIT_LIST_HEAD(&devlink->trap_list);
6135 INIT_LIST_HEAD(&devlink->trap_group_list);
2406e7e5 6136 mutex_init(&devlink->lock);
b587bdaf 6137 mutex_init(&devlink->reporters_lock);
bfcd3a46
JP
6138 return devlink;
6139}
6140EXPORT_SYMBOL_GPL(devlink_alloc);
6141
6142/**
6143 * devlink_register - Register devlink instance
6144 *
6145 * @devlink: devlink
eeaadd82 6146 * @dev: parent device
bfcd3a46
JP
6147 */
6148int devlink_register(struct devlink *devlink, struct device *dev)
6149{
6150 mutex_lock(&devlink_mutex);
6151 devlink->dev = dev;
6152 list_add_tail(&devlink->list, &devlink_list);
6153 devlink_notify(devlink, DEVLINK_CMD_NEW);
6154 mutex_unlock(&devlink_mutex);
6155 return 0;
6156}
6157EXPORT_SYMBOL_GPL(devlink_register);
6158
6159/**
6160 * devlink_unregister - Unregister devlink instance
6161 *
6162 * @devlink: devlink
6163 */
6164void devlink_unregister(struct devlink *devlink)
6165{
6166 mutex_lock(&devlink_mutex);
6167 devlink_notify(devlink, DEVLINK_CMD_DEL);
6168 list_del(&devlink->list);
6169 mutex_unlock(&devlink_mutex);
6170}
6171EXPORT_SYMBOL_GPL(devlink_unregister);
6172
6173/**
6174 * devlink_free - Free devlink instance resources
6175 *
6176 * @devlink: devlink
6177 */
6178void devlink_free(struct devlink *devlink)
6179{
b587bdaf 6180 mutex_destroy(&devlink->reporters_lock);
375cf8c6 6181 mutex_destroy(&devlink->lock);
0f420b6c
IS
6182 WARN_ON(!list_empty(&devlink->trap_group_list));
6183 WARN_ON(!list_empty(&devlink->trap_list));
b904aada
PP
6184 WARN_ON(!list_empty(&devlink->reporter_list));
6185 WARN_ON(!list_empty(&devlink->region_list));
6186 WARN_ON(!list_empty(&devlink->param_list));
6187 WARN_ON(!list_empty(&devlink->resource_list));
6188 WARN_ON(!list_empty(&devlink->dpipe_table_list));
6189 WARN_ON(!list_empty(&devlink->sb_list));
6190 WARN_ON(!list_empty(&devlink->port_list));
6191
bfcd3a46
JP
6192 kfree(devlink);
6193}
6194EXPORT_SYMBOL_GPL(devlink_free);
6195
136bf27f
JP
6196static void devlink_port_type_warn(struct work_struct *work)
6197{
6198 WARN(true, "Type was not set for devlink port.");
6199}
6200
6201static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
6202{
6203 /* Ignore CPU and DSA flavours. */
6204 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
6205 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
6206}
6207
6208#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 30)
6209
6210static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
6211{
6212 if (!devlink_port_type_should_warn(devlink_port))
6213 return;
6214 /* Schedule a work to WARN in case driver does not set port
6215 * type within timeout.
6216 */
6217 schedule_delayed_work(&devlink_port->type_warn_dw,
6218 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
6219}
6220
6221static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
6222{
6223 if (!devlink_port_type_should_warn(devlink_port))
6224 return;
6225 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
6226}
6227
bfcd3a46
JP
6228/**
6229 * devlink_port_register - Register devlink port
6230 *
6231 * @devlink: devlink
6232 * @devlink_port: devlink port
eeaadd82 6233 * @port_index: driver-specific numerical identifier of the port
bfcd3a46
JP
6234 *
6235 * Register devlink port with provided port index. User can use
6236 * any indexing, even hw-related one. devlink_port structure
6237 * is convenient to be embedded inside user driver private structure.
6238 * Note that the caller should take care of zeroing the devlink_port
6239 * structure.
6240 */
6241int devlink_port_register(struct devlink *devlink,
6242 struct devlink_port *devlink_port,
6243 unsigned int port_index)
6244{
2406e7e5 6245 mutex_lock(&devlink->lock);
bfcd3a46 6246 if (devlink_port_index_exists(devlink, port_index)) {
2406e7e5 6247 mutex_unlock(&devlink->lock);
bfcd3a46
JP
6248 return -EEXIST;
6249 }
6250 devlink_port->devlink = devlink;
6251 devlink_port->index = port_index;
bfcd3a46 6252 devlink_port->registered = true;
b8f97554 6253 spin_lock_init(&devlink_port->type_lock);
bfcd3a46 6254 list_add_tail(&devlink_port->list, &devlink->port_list);
39e6160e 6255 INIT_LIST_HEAD(&devlink_port->param_list);
2406e7e5 6256 mutex_unlock(&devlink->lock);
136bf27f
JP
6257 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
6258 devlink_port_type_warn_schedule(devlink_port);
bfcd3a46
JP
6259 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
6260 return 0;
6261}
6262EXPORT_SYMBOL_GPL(devlink_port_register);
6263
6264/**
6265 * devlink_port_unregister - Unregister devlink port
6266 *
6267 * @devlink_port: devlink port
6268 */
6269void devlink_port_unregister(struct devlink_port *devlink_port)
6270{
2406e7e5
AS
6271 struct devlink *devlink = devlink_port->devlink;
6272
136bf27f 6273 devlink_port_type_warn_cancel(devlink_port);
bfcd3a46 6274 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
2406e7e5 6275 mutex_lock(&devlink->lock);
bfcd3a46 6276 list_del(&devlink_port->list);
2406e7e5 6277 mutex_unlock(&devlink->lock);
bfcd3a46
JP
6278}
6279EXPORT_SYMBOL_GPL(devlink_port_unregister);
6280
6281static void __devlink_port_type_set(struct devlink_port *devlink_port,
6282 enum devlink_port_type type,
6283 void *type_dev)
6284{
2b239e70
JP
6285 if (WARN_ON(!devlink_port->registered))
6286 return;
136bf27f 6287 devlink_port_type_warn_cancel(devlink_port);
0f420b6c 6288 spin_lock_bh(&devlink_port->type_lock);
bfcd3a46
JP
6289 devlink_port->type = type;
6290 devlink_port->type_dev = type_dev;
0f420b6c 6291 spin_unlock_bh(&devlink_port->type_lock);
bfcd3a46
JP
6292 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
6293}
6294
6295/**
6296 * devlink_port_type_eth_set - Set port type to Ethernet
6297 *
6298 * @devlink_port: devlink port
6299 * @netdev: related netdevice
6300 */
6301void devlink_port_type_eth_set(struct devlink_port *devlink_port,
6302 struct net_device *netdev)
6303{
119c0b57
JP
6304 const struct net_device_ops *ops = netdev->netdev_ops;
6305
746364f2
JP
6306 /* If driver registers devlink port, it should set devlink port
6307 * attributes accordingly so the compat functions are called
6308 * and the original ops are not used.
6309 */
119c0b57 6310 if (ops->ndo_get_phys_port_name) {
746364f2
JP
6311 /* Some drivers use the same set of ndos for netdevs
6312 * that have devlink_port registered and also for
6313 * those who don't. Make sure that ndo_get_phys_port_name
6314 * returns -EOPNOTSUPP here in case it is defined.
6315 * Warn if not.
6316 */
746364f2
JP
6317 char name[IFNAMSIZ];
6318 int err;
6319
6320 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
6321 WARN_ON(err != -EOPNOTSUPP);
6322 }
119c0b57
JP
6323 if (ops->ndo_get_port_parent_id) {
6324 /* Some drivers use the same set of ndos for netdevs
6325 * that have devlink_port registered and also for
6326 * those who don't. Make sure that ndo_get_port_parent_id
6327 * returns -EOPNOTSUPP here in case it is defined.
6328 * Warn if not.
6329 */
6330 struct netdev_phys_item_id ppid;
6331 int err;
6332
6333 err = ops->ndo_get_port_parent_id(netdev, &ppid);
6334 WARN_ON(err != -EOPNOTSUPP);
6335 }
773b1f38 6336 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
bfcd3a46
JP
6337}
6338EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
6339
6340/**
6341 * devlink_port_type_ib_set - Set port type to InfiniBand
6342 *
6343 * @devlink_port: devlink port
6344 * @ibdev: related IB device
6345 */
6346void devlink_port_type_ib_set(struct devlink_port *devlink_port,
6347 struct ib_device *ibdev)
6348{
773b1f38 6349 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
bfcd3a46
JP
6350}
6351EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
6352
6353/**
6354 * devlink_port_type_clear - Clear port type
6355 *
6356 * @devlink_port: devlink port
6357 */
6358void devlink_port_type_clear(struct devlink_port *devlink_port)
6359{
773b1f38 6360 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
136bf27f 6361 devlink_port_type_warn_schedule(devlink_port);
bfcd3a46
JP
6362}
6363EXPORT_SYMBOL_GPL(devlink_port_type_clear);
6364
378ef01b
PP
6365static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
6366 enum devlink_port_flavour flavour,
6367 const unsigned char *switch_id,
6368 unsigned char switch_id_len)
6369{
6370 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6371
6372 if (WARN_ON(devlink_port->registered))
6373 return -EEXIST;
6374 attrs->set = true;
6375 attrs->flavour = flavour;
6376 if (switch_id) {
6377 attrs->switch_port = true;
6378 if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
6379 switch_id_len = MAX_PHYS_ITEM_ID_LEN;
6380 memcpy(attrs->switch_id.id, switch_id, switch_id_len);
6381 attrs->switch_id.id_len = switch_id_len;
6382 } else {
6383 attrs->switch_port = false;
6384 }
6385 return 0;
6386}
6387
bfcd3a46 6388/**
b9ffcbaf 6389 * devlink_port_attrs_set - Set port attributes
bfcd3a46
JP
6390 *
6391 * @devlink_port: devlink port
5ec1380a 6392 * @flavour: flavour of the port
b9ffcbaf
JP
6393 * @port_number: number of the port that is facing user, for example
6394 * the front panel port number
6395 * @split: indicates if this is split port
6396 * @split_subport_number: if the port is split, this is the number
6397 * of subport.
bec5267c
JP
6398 * @switch_id: if the port is part of switch, this is buffer with ID,
6399 * otwerwise this is NULL
6400 * @switch_id_len: length of the switch_id buffer
bfcd3a46 6401 */
b9ffcbaf 6402void devlink_port_attrs_set(struct devlink_port *devlink_port,
5ec1380a 6403 enum devlink_port_flavour flavour,
b9ffcbaf 6404 u32 port_number, bool split,
bec5267c
JP
6405 u32 split_subport_number,
6406 const unsigned char *switch_id,
6407 unsigned char switch_id_len)
bfcd3a46 6408{
b9ffcbaf 6409 struct devlink_port_attrs *attrs = &devlink_port->attrs;
378ef01b 6410 int ret;
b9ffcbaf 6411
378ef01b
PP
6412 ret = __devlink_port_attrs_set(devlink_port, flavour,
6413 switch_id, switch_id_len);
6414 if (ret)
45b86112 6415 return;
b9ffcbaf 6416 attrs->split = split;
378ef01b
PP
6417 attrs->phys.port_number = port_number;
6418 attrs->phys.split_subport_number = split_subport_number;
bfcd3a46 6419}
b9ffcbaf 6420EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
bfcd3a46 6421
98fd2d65
PP
6422/**
6423 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
6424 *
6425 * @devlink_port: devlink port
6426 * @pf: associated PF for the devlink port instance
6427 * @switch_id: if the port is part of switch, this is buffer with ID,
6428 * otherwise this is NULL
6429 * @switch_id_len: length of the switch_id buffer
6430 */
6431void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port,
6432 const unsigned char *switch_id,
6433 unsigned char switch_id_len, u16 pf)
6434{
6435 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6436 int ret;
6437
6438 ret = __devlink_port_attrs_set(devlink_port,
6439 DEVLINK_PORT_FLAVOUR_PCI_PF,
6440 switch_id, switch_id_len);
6441 if (ret)
6442 return;
6443
6444 attrs->pci_pf.pf = pf;
6445}
6446EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
6447
e41b6bf3
PP
6448/**
6449 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
6450 *
6451 * @devlink_port: devlink port
6452 * @pf: associated PF for the devlink port instance
6453 * @vf: associated VF of a PF for the devlink port instance
6454 * @switch_id: if the port is part of switch, this is buffer with ID,
6455 * otherwise this is NULL
6456 * @switch_id_len: length of the switch_id buffer
6457 */
6458void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
6459 const unsigned char *switch_id,
6460 unsigned char switch_id_len,
6461 u16 pf, u16 vf)
6462{
6463 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6464 int ret;
6465
6466 ret = __devlink_port_attrs_set(devlink_port,
6467 DEVLINK_PORT_FLAVOUR_PCI_VF,
6468 switch_id, switch_id_len);
6469 if (ret)
6470 return;
6471 attrs->pci_vf.pf = pf;
6472 attrs->pci_vf.vf = vf;
6473}
6474EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
6475
af3836df
JP
6476static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
6477 char *name, size_t len)
08474c1a
JP
6478{
6479 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6480 int n = 0;
6481
6482 if (!attrs->set)
6483 return -EOPNOTSUPP;
6484
6485 switch (attrs->flavour) {
6486 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
6487 if (!attrs->split)
378ef01b 6488 n = snprintf(name, len, "p%u", attrs->phys.port_number);
08474c1a 6489 else
378ef01b
PP
6490 n = snprintf(name, len, "p%us%u",
6491 attrs->phys.port_number,
6492 attrs->phys.split_subport_number);
08474c1a
JP
6493 break;
6494 case DEVLINK_PORT_FLAVOUR_CPU:
6495 case DEVLINK_PORT_FLAVOUR_DSA:
6496 /* As CPU and DSA ports do not have a netdevice associated
6497 * case should not ever happen.
6498 */
6499 WARN_ON(1);
6500 return -EINVAL;
98fd2d65
PP
6501 case DEVLINK_PORT_FLAVOUR_PCI_PF:
6502 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
6503 break;
e41b6bf3
PP
6504 case DEVLINK_PORT_FLAVOUR_PCI_VF:
6505 n = snprintf(name, len, "pf%uvf%u",
6506 attrs->pci_vf.pf, attrs->pci_vf.vf);
6507 break;
08474c1a
JP
6508 }
6509
6510 if (n >= len)
6511 return -EINVAL;
6512
6513 return 0;
6514}
af3836df 6515
bf797471
JP
6516int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
6517 u32 size, u16 ingress_pools_count,
6518 u16 egress_pools_count, u16 ingress_tc_count,
6519 u16 egress_tc_count)
6520{
6521 struct devlink_sb *devlink_sb;
6522 int err = 0;
6523
2406e7e5 6524 mutex_lock(&devlink->lock);
bf797471
JP
6525 if (devlink_sb_index_exists(devlink, sb_index)) {
6526 err = -EEXIST;
6527 goto unlock;
6528 }
6529
6530 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
6531 if (!devlink_sb) {
6532 err = -ENOMEM;
6533 goto unlock;
6534 }
6535 devlink_sb->index = sb_index;
6536 devlink_sb->size = size;
6537 devlink_sb->ingress_pools_count = ingress_pools_count;
6538 devlink_sb->egress_pools_count = egress_pools_count;
6539 devlink_sb->ingress_tc_count = ingress_tc_count;
6540 devlink_sb->egress_tc_count = egress_tc_count;
6541 list_add_tail(&devlink_sb->list, &devlink->sb_list);
6542unlock:
2406e7e5 6543 mutex_unlock(&devlink->lock);
bf797471
JP
6544 return err;
6545}
6546EXPORT_SYMBOL_GPL(devlink_sb_register);
6547
6548void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
6549{
6550 struct devlink_sb *devlink_sb;
6551
2406e7e5 6552 mutex_lock(&devlink->lock);
bf797471
JP
6553 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
6554 WARN_ON(!devlink_sb);
6555 list_del(&devlink_sb->list);
2406e7e5 6556 mutex_unlock(&devlink->lock);
bf797471
JP
6557 kfree(devlink_sb);
6558}
6559EXPORT_SYMBOL_GPL(devlink_sb_unregister);
6560
1555d204
AS
6561/**
6562 * devlink_dpipe_headers_register - register dpipe headers
6563 *
6564 * @devlink: devlink
6565 * @dpipe_headers: dpipe header array
6566 *
6567 * Register the headers supported by hardware.
6568 */
6569int devlink_dpipe_headers_register(struct devlink *devlink,
6570 struct devlink_dpipe_headers *dpipe_headers)
6571{
2406e7e5 6572 mutex_lock(&devlink->lock);
1555d204 6573 devlink->dpipe_headers = dpipe_headers;
2406e7e5 6574 mutex_unlock(&devlink->lock);
1555d204
AS
6575 return 0;
6576}
6577EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
6578
6579/**
6580 * devlink_dpipe_headers_unregister - unregister dpipe headers
6581 *
6582 * @devlink: devlink
6583 *
6584 * Unregister the headers supported by hardware.
6585 */
6586void devlink_dpipe_headers_unregister(struct devlink *devlink)
6587{
2406e7e5 6588 mutex_lock(&devlink->lock);
1555d204 6589 devlink->dpipe_headers = NULL;
2406e7e5 6590 mutex_unlock(&devlink->lock);
1555d204
AS
6591}
6592EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
6593
6594/**
6595 * devlink_dpipe_table_counter_enabled - check if counter allocation
6596 * required
6597 * @devlink: devlink
6598 * @table_name: tables name
6599 *
6600 * Used by driver to check if counter allocation is required.
6601 * After counter allocation is turned on the table entries
6602 * are updated to include counter statistics.
6603 *
6604 * After that point on the driver must respect the counter
6605 * state so that each entry added to the table is added
6606 * with a counter.
6607 */
6608bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
6609 const char *table_name)
6610{
6611 struct devlink_dpipe_table *table;
6612 bool enabled;
6613
6614 rcu_read_lock();
6615 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6616 table_name);
6617 enabled = false;
6618 if (table)
6619 enabled = table->counters_enabled;
6620 rcu_read_unlock();
6621 return enabled;
6622}
6623EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
6624
6625/**
6626 * devlink_dpipe_table_register - register dpipe table
6627 *
6628 * @devlink: devlink
6629 * @table_name: table name
6630 * @table_ops: table ops
6631 * @priv: priv
1555d204
AS
6632 * @counter_control_extern: external control for counters
6633 */
6634int devlink_dpipe_table_register(struct devlink *devlink,
6635 const char *table_name,
6636 struct devlink_dpipe_table_ops *table_ops,
ffd3cdcc 6637 void *priv, bool counter_control_extern)
1555d204
AS
6638{
6639 struct devlink_dpipe_table *table;
6640
6641 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
6642 return -EEXIST;
6643
ffd3cdcc
AS
6644 if (WARN_ON(!table_ops->size_get))
6645 return -EINVAL;
6646
1555d204
AS
6647 table = kzalloc(sizeof(*table), GFP_KERNEL);
6648 if (!table)
6649 return -ENOMEM;
6650
6651 table->name = table_name;
6652 table->table_ops = table_ops;
6653 table->priv = priv;
1555d204
AS
6654 table->counter_control_extern = counter_control_extern;
6655
2406e7e5 6656 mutex_lock(&devlink->lock);
1555d204 6657 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
2406e7e5 6658 mutex_unlock(&devlink->lock);
1555d204
AS
6659 return 0;
6660}
6661EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
6662
6663/**
6664 * devlink_dpipe_table_unregister - unregister dpipe table
6665 *
6666 * @devlink: devlink
6667 * @table_name: table name
6668 */
6669void devlink_dpipe_table_unregister(struct devlink *devlink,
6670 const char *table_name)
6671{
6672 struct devlink_dpipe_table *table;
6673
2406e7e5 6674 mutex_lock(&devlink->lock);
1555d204
AS
6675 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6676 table_name);
6677 if (!table)
6678 goto unlock;
6679 list_del_rcu(&table->list);
2406e7e5 6680 mutex_unlock(&devlink->lock);
1555d204
AS
6681 kfree_rcu(table, rcu);
6682 return;
6683unlock:
2406e7e5 6684 mutex_unlock(&devlink->lock);
1555d204
AS
6685}
6686EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
6687
d9f9b9a4
AS
6688/**
6689 * devlink_resource_register - devlink resource register
6690 *
6691 * @devlink: devlink
6692 * @resource_name: resource's name
d9f9b9a4
AS
6693 * @resource_size: resource's size
6694 * @resource_id: resource's id
eeaadd82
JK
6695 * @parent_resource_id: resource's parent id
6696 * @size_params: size parameters
d9f9b9a4
AS
6697 */
6698int devlink_resource_register(struct devlink *devlink,
6699 const char *resource_name,
d9f9b9a4
AS
6700 u64 resource_size,
6701 u64 resource_id,
6702 u64 parent_resource_id,
fc56be47 6703 const struct devlink_resource_size_params *size_params)
d9f9b9a4
AS
6704{
6705 struct devlink_resource *resource;
6706 struct list_head *resource_list;
14530746 6707 bool top_hierarchy;
d9f9b9a4
AS
6708 int err = 0;
6709
14530746
DA
6710 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
6711
d9f9b9a4
AS
6712 mutex_lock(&devlink->lock);
6713 resource = devlink_resource_find(devlink, NULL, resource_id);
6714 if (resource) {
6715 err = -EINVAL;
6716 goto out;
6717 }
6718
6719 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
6720 if (!resource) {
6721 err = -ENOMEM;
6722 goto out;
6723 }
6724
6725 if (top_hierarchy) {
6726 resource_list = &devlink->resource_list;
6727 } else {
6728 struct devlink_resource *parent_resource;
6729
6730 parent_resource = devlink_resource_find(devlink, NULL,
6731 parent_resource_id);
6732 if (parent_resource) {
6733 resource_list = &parent_resource->resource_list;
6734 resource->parent = parent_resource;
6735 } else {
b75703de 6736 kfree(resource);
d9f9b9a4
AS
6737 err = -EINVAL;
6738 goto out;
6739 }
6740 }
6741
6742 resource->name = resource_name;
6743 resource->size = resource_size;
6744 resource->size_new = resource_size;
6745 resource->id = resource_id;
d9f9b9a4 6746 resource->size_valid = true;
77d27096
JP
6747 memcpy(&resource->size_params, size_params,
6748 sizeof(resource->size_params));
d9f9b9a4
AS
6749 INIT_LIST_HEAD(&resource->resource_list);
6750 list_add_tail(&resource->list, resource_list);
6751out:
6752 mutex_unlock(&devlink->lock);
6753 return err;
6754}
6755EXPORT_SYMBOL_GPL(devlink_resource_register);
6756
6757/**
6758 * devlink_resources_unregister - free all resources
6759 *
6760 * @devlink: devlink
6761 * @resource: resource
6762 */
6763void devlink_resources_unregister(struct devlink *devlink,
6764 struct devlink_resource *resource)
6765{
6766 struct devlink_resource *tmp, *child_resource;
6767 struct list_head *resource_list;
6768
6769 if (resource)
6770 resource_list = &resource->resource_list;
6771 else
6772 resource_list = &devlink->resource_list;
6773
6774 if (!resource)
6775 mutex_lock(&devlink->lock);
6776
6777 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
6778 devlink_resources_unregister(devlink, child_resource);
6779 list_del(&child_resource->list);
6780 kfree(child_resource);
6781 }
6782
6783 if (!resource)
6784 mutex_unlock(&devlink->lock);
6785}
6786EXPORT_SYMBOL_GPL(devlink_resources_unregister);
6787
6788/**
6789 * devlink_resource_size_get - get and update size
6790 *
6791 * @devlink: devlink
6792 * @resource_id: the requested resource id
6793 * @p_resource_size: ptr to update
6794 */
6795int devlink_resource_size_get(struct devlink *devlink,
6796 u64 resource_id,
6797 u64 *p_resource_size)
6798{
6799 struct devlink_resource *resource;
6800 int err = 0;
6801
6802 mutex_lock(&devlink->lock);
6803 resource = devlink_resource_find(devlink, NULL, resource_id);
6804 if (!resource) {
6805 err = -EINVAL;
6806 goto out;
6807 }
6808 *p_resource_size = resource->size_new;
6809 resource->size = resource->size_new;
6810out:
6811 mutex_unlock(&devlink->lock);
6812 return err;
6813}
6814EXPORT_SYMBOL_GPL(devlink_resource_size_get);
6815
56dc7cd0
AS
6816/**
6817 * devlink_dpipe_table_resource_set - set the resource id
6818 *
6819 * @devlink: devlink
6820 * @table_name: table name
6821 * @resource_id: resource id
6822 * @resource_units: number of resource's units consumed per table's entry
6823 */
6824int devlink_dpipe_table_resource_set(struct devlink *devlink,
6825 const char *table_name, u64 resource_id,
6826 u64 resource_units)
6827{
6828 struct devlink_dpipe_table *table;
6829 int err = 0;
6830
6831 mutex_lock(&devlink->lock);
6832 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6833 table_name);
6834 if (!table) {
6835 err = -EINVAL;
6836 goto out;
6837 }
6838 table->resource_id = resource_id;
6839 table->resource_units = resource_units;
6840 table->resource_valid = true;
6841out:
6842 mutex_unlock(&devlink->lock);
6843 return err;
6844}
6845EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
6846
fc56be47
JP
6847/**
6848 * devlink_resource_occ_get_register - register occupancy getter
6849 *
6850 * @devlink: devlink
6851 * @resource_id: resource id
6852 * @occ_get: occupancy getter callback
6853 * @occ_get_priv: occupancy getter callback priv
6854 */
6855void devlink_resource_occ_get_register(struct devlink *devlink,
6856 u64 resource_id,
6857 devlink_resource_occ_get_t *occ_get,
6858 void *occ_get_priv)
6859{
6860 struct devlink_resource *resource;
6861
6862 mutex_lock(&devlink->lock);
6863 resource = devlink_resource_find(devlink, NULL, resource_id);
6864 if (WARN_ON(!resource))
6865 goto out;
6866 WARN_ON(resource->occ_get);
6867
6868 resource->occ_get = occ_get;
6869 resource->occ_get_priv = occ_get_priv;
6870out:
6871 mutex_unlock(&devlink->lock);
6872}
6873EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
6874
6875/**
6876 * devlink_resource_occ_get_unregister - unregister occupancy getter
6877 *
6878 * @devlink: devlink
6879 * @resource_id: resource id
6880 */
6881void devlink_resource_occ_get_unregister(struct devlink *devlink,
6882 u64 resource_id)
6883{
6884 struct devlink_resource *resource;
6885
6886 mutex_lock(&devlink->lock);
6887 resource = devlink_resource_find(devlink, NULL, resource_id);
6888 if (WARN_ON(!resource))
6889 goto out;
6890 WARN_ON(!resource->occ_get);
6891
6892 resource->occ_get = NULL;
6893 resource->occ_get_priv = NULL;
6894out:
6895 mutex_unlock(&devlink->lock);
6896}
6897EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
6898
39e6160e
VV
6899static int devlink_param_verify(const struct devlink_param *param)
6900{
6901 if (!param || !param->name || !param->supported_cmodes)
6902 return -EINVAL;
6903 if (param->generic)
6904 return devlink_param_generic_verify(param);
6905 else
6906 return devlink_param_driver_verify(param);
6907}
6908
6909static int __devlink_params_register(struct devlink *devlink,
c1e5786d 6910 unsigned int port_index,
39e6160e
VV
6911 struct list_head *param_list,
6912 const struct devlink_param *params,
c1e5786d
VV
6913 size_t params_count,
6914 enum devlink_command reg_cmd,
6915 enum devlink_command unreg_cmd)
eabaef18
MS
6916{
6917 const struct devlink_param *param = params;
6918 int i;
6919 int err;
6920
6921 mutex_lock(&devlink->lock);
6922 for (i = 0; i < params_count; i++, param++) {
39e6160e
VV
6923 err = devlink_param_verify(param);
6924 if (err)
eabaef18 6925 goto rollback;
39e6160e 6926
c1e5786d
VV
6927 err = devlink_param_register_one(devlink, port_index,
6928 param_list, param, reg_cmd);
eabaef18
MS
6929 if (err)
6930 goto rollback;
6931 }
6932
6933 mutex_unlock(&devlink->lock);
6934 return 0;
6935
6936rollback:
6937 if (!i)
6938 goto unlock;
6939 for (param--; i > 0; i--, param--)
c1e5786d
VV
6940 devlink_param_unregister_one(devlink, port_index, param_list,
6941 param, unreg_cmd);
eabaef18
MS
6942unlock:
6943 mutex_unlock(&devlink->lock);
6944 return err;
6945}
39e6160e
VV
6946
6947static void __devlink_params_unregister(struct devlink *devlink,
c1e5786d 6948 unsigned int port_index,
39e6160e
VV
6949 struct list_head *param_list,
6950 const struct devlink_param *params,
c1e5786d
VV
6951 size_t params_count,
6952 enum devlink_command cmd)
39e6160e
VV
6953{
6954 const struct devlink_param *param = params;
6955 int i;
6956
6957 mutex_lock(&devlink->lock);
6958 for (i = 0; i < params_count; i++, param++)
c1e5786d
VV
6959 devlink_param_unregister_one(devlink, 0, param_list, param,
6960 cmd);
39e6160e
VV
6961 mutex_unlock(&devlink->lock);
6962}
6963
6964/**
6965 * devlink_params_register - register configuration parameters
6966 *
6967 * @devlink: devlink
6968 * @params: configuration parameters array
6969 * @params_count: number of parameters provided
6970 *
6971 * Register the configuration parameters supported by the driver.
6972 */
6973int devlink_params_register(struct devlink *devlink,
6974 const struct devlink_param *params,
6975 size_t params_count)
6976{
c1e5786d
VV
6977 return __devlink_params_register(devlink, 0, &devlink->param_list,
6978 params, params_count,
6979 DEVLINK_CMD_PARAM_NEW,
6980 DEVLINK_CMD_PARAM_DEL);
39e6160e 6981}
eabaef18
MS
6982EXPORT_SYMBOL_GPL(devlink_params_register);
6983
6984/**
6985 * devlink_params_unregister - unregister configuration parameters
6986 * @devlink: devlink
6987 * @params: configuration parameters to unregister
6988 * @params_count: number of parameters provided
6989 */
6990void devlink_params_unregister(struct devlink *devlink,
6991 const struct devlink_param *params,
6992 size_t params_count)
6993{
c1e5786d
VV
6994 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
6995 params, params_count,
6996 DEVLINK_CMD_PARAM_DEL);
eabaef18
MS
6997}
6998EXPORT_SYMBOL_GPL(devlink_params_unregister);
6999
7c62cfb8
JP
7000/**
7001 * devlink_params_publish - publish configuration parameters
7002 *
7003 * @devlink: devlink
7004 *
7005 * Publish previously registered configuration parameters.
7006 */
7007void devlink_params_publish(struct devlink *devlink)
7008{
7009 struct devlink_param_item *param_item;
7010
7011 list_for_each_entry(param_item, &devlink->param_list, list) {
7012 if (param_item->published)
7013 continue;
7014 param_item->published = true;
7015 devlink_param_notify(devlink, 0, param_item,
7016 DEVLINK_CMD_PARAM_NEW);
7017 }
7018}
7019EXPORT_SYMBOL_GPL(devlink_params_publish);
7020
7021/**
7022 * devlink_params_unpublish - unpublish configuration parameters
7023 *
7024 * @devlink: devlink
7025 *
7026 * Unpublish previously registered configuration parameters.
7027 */
7028void devlink_params_unpublish(struct devlink *devlink)
7029{
7030 struct devlink_param_item *param_item;
7031
7032 list_for_each_entry(param_item, &devlink->param_list, list) {
7033 if (!param_item->published)
7034 continue;
7035 param_item->published = false;
7036 devlink_param_notify(devlink, 0, param_item,
7037 DEVLINK_CMD_PARAM_DEL);
7038 }
7039}
7040EXPORT_SYMBOL_GPL(devlink_params_unpublish);
7041
39e6160e
VV
7042/**
7043 * devlink_port_params_register - register port configuration parameters
7044 *
7045 * @devlink_port: devlink port
7046 * @params: configuration parameters array
7047 * @params_count: number of parameters provided
7048 *
7049 * Register the configuration parameters supported by the port.
7050 */
7051int devlink_port_params_register(struct devlink_port *devlink_port,
7052 const struct devlink_param *params,
7053 size_t params_count)
7054{
7055 return __devlink_params_register(devlink_port->devlink,
c1e5786d 7056 devlink_port->index,
39e6160e 7057 &devlink_port->param_list, params,
c1e5786d
VV
7058 params_count,
7059 DEVLINK_CMD_PORT_PARAM_NEW,
7060 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
7061}
7062EXPORT_SYMBOL_GPL(devlink_port_params_register);
7063
7064/**
7065 * devlink_port_params_unregister - unregister port configuration
7066 * parameters
7067 *
7068 * @devlink_port: devlink port
7069 * @params: configuration parameters array
7070 * @params_count: number of parameters provided
7071 */
7072void devlink_port_params_unregister(struct devlink_port *devlink_port,
7073 const struct devlink_param *params,
7074 size_t params_count)
7075{
7076 return __devlink_params_unregister(devlink_port->devlink,
c1e5786d 7077 devlink_port->index,
39e6160e 7078 &devlink_port->param_list,
c1e5786d
VV
7079 params, params_count,
7080 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
7081}
7082EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
7083
ffd19b9a
VV
7084static int
7085__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
7086 union devlink_param_value *init_val)
ec01aeb1
MS
7087{
7088 struct devlink_param_item *param_item;
7089
ffd19b9a 7090 param_item = devlink_param_find_by_id(param_list, param_id);
ec01aeb1
MS
7091 if (!param_item)
7092 return -EINVAL;
7093
7094 if (!param_item->driverinit_value_valid ||
7095 !devlink_param_cmode_is_supported(param_item->param,
7096 DEVLINK_PARAM_CMODE_DRIVERINIT))
7097 return -EOPNOTSUPP;
7098
1276534c
MS
7099 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
7100 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
7101 else
7102 *init_val = param_item->driverinit_value;
ec01aeb1
MS
7103
7104 return 0;
7105}
ffd19b9a 7106
5473a7bd
VV
7107static int
7108__devlink_param_driverinit_value_set(struct devlink *devlink,
c1e5786d 7109 unsigned int port_index,
5473a7bd
VV
7110 struct list_head *param_list, u32 param_id,
7111 union devlink_param_value init_val,
7112 enum devlink_command cmd)
7113{
7114 struct devlink_param_item *param_item;
7115
7116 param_item = devlink_param_find_by_id(param_list, param_id);
7117 if (!param_item)
7118 return -EINVAL;
7119
7120 if (!devlink_param_cmode_is_supported(param_item->param,
7121 DEVLINK_PARAM_CMODE_DRIVERINIT))
7122 return -EOPNOTSUPP;
7123
7124 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
7125 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
7126 else
7127 param_item->driverinit_value = init_val;
7128 param_item->driverinit_value_valid = true;
7129
c1e5786d 7130 devlink_param_notify(devlink, port_index, param_item, cmd);
5473a7bd
VV
7131 return 0;
7132}
7133
ffd19b9a
VV
7134/**
7135 * devlink_param_driverinit_value_get - get configuration parameter
7136 * value for driver initializing
7137 *
7138 * @devlink: devlink
7139 * @param_id: parameter ID
7140 * @init_val: value of parameter in driverinit configuration mode
7141 *
7142 * This function should be used by the driver to get driverinit
7143 * configuration for initialization after reload command.
7144 */
7145int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
7146 union devlink_param_value *init_val)
7147{
be6fe1d8 7148 if (!devlink->ops->reload)
ffd19b9a
VV
7149 return -EOPNOTSUPP;
7150
7151 return __devlink_param_driverinit_value_get(&devlink->param_list,
7152 param_id, init_val);
7153}
ec01aeb1
MS
7154EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
7155
7156/**
7157 * devlink_param_driverinit_value_set - set value of configuration
7158 * parameter for driverinit
7159 * configuration mode
7160 *
7161 * @devlink: devlink
7162 * @param_id: parameter ID
7163 * @init_val: value of parameter to set for driverinit configuration mode
7164 *
7165 * This function should be used by the driver to set driverinit
7166 * configuration mode default value.
7167 */
7168int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
7169 union devlink_param_value init_val)
7170{
c1e5786d 7171 return __devlink_param_driverinit_value_set(devlink, 0,
5473a7bd
VV
7172 &devlink->param_list,
7173 param_id, init_val,
7174 DEVLINK_CMD_PARAM_NEW);
ec01aeb1
MS
7175}
7176EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
7177
ffd19b9a
VV
7178/**
7179 * devlink_port_param_driverinit_value_get - get configuration parameter
7180 * value for driver initializing
7181 *
7182 * @devlink_port: devlink_port
7183 * @param_id: parameter ID
7184 * @init_val: value of parameter in driverinit configuration mode
7185 *
7186 * This function should be used by the driver to get driverinit
7187 * configuration for initialization after reload command.
7188 */
7189int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
7190 u32 param_id,
7191 union devlink_param_value *init_val)
7192{
7193 struct devlink *devlink = devlink_port->devlink;
7194
be6fe1d8 7195 if (!devlink->ops->reload)
ffd19b9a
VV
7196 return -EOPNOTSUPP;
7197
7198 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
7199 param_id, init_val);
7200}
7201EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
7202
5473a7bd
VV
7203/**
7204 * devlink_port_param_driverinit_value_set - set value of configuration
7205 * parameter for driverinit
7206 * configuration mode
7207 *
7208 * @devlink_port: devlink_port
7209 * @param_id: parameter ID
7210 * @init_val: value of parameter to set for driverinit configuration mode
7211 *
7212 * This function should be used by the driver to set driverinit
7213 * configuration mode default value.
7214 */
7215int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
7216 u32 param_id,
7217 union devlink_param_value init_val)
7218{
7219 return __devlink_param_driverinit_value_set(devlink_port->devlink,
c1e5786d 7220 devlink_port->index,
5473a7bd 7221 &devlink_port->param_list,
c1e5786d
VV
7222 param_id, init_val,
7223 DEVLINK_CMD_PORT_PARAM_NEW);
5473a7bd
VV
7224}
7225EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
7226
ea601e17
MS
7227/**
7228 * devlink_param_value_changed - notify devlink on a parameter's value
7229 * change. Should be called by the driver
7230 * right after the change.
7231 *
7232 * @devlink: devlink
7233 * @param_id: parameter ID
7234 *
7235 * This function should be used by the driver to notify devlink on value
7236 * change, excluding driverinit configuration mode.
7237 * For driverinit configuration mode driver should use the function
ea601e17
MS
7238 */
7239void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
7240{
7241 struct devlink_param_item *param_item;
7242
7243 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
7244 WARN_ON(!param_item);
7245
c1e5786d 7246 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
ea601e17
MS
7247}
7248EXPORT_SYMBOL_GPL(devlink_param_value_changed);
7249
c1e5786d
VV
7250/**
7251 * devlink_port_param_value_changed - notify devlink on a parameter's value
7252 * change. Should be called by the driver
7253 * right after the change.
7254 *
7255 * @devlink_port: devlink_port
7256 * @param_id: parameter ID
7257 *
7258 * This function should be used by the driver to notify devlink on value
7259 * change, excluding driverinit configuration mode.
7260 * For driverinit configuration mode driver should use the function
7261 * devlink_port_param_driverinit_value_set() instead.
7262 */
7263void devlink_port_param_value_changed(struct devlink_port *devlink_port,
7264 u32 param_id)
7265{
7266 struct devlink_param_item *param_item;
7267
7268 param_item = devlink_param_find_by_id(&devlink_port->param_list,
7269 param_id);
7270 WARN_ON(!param_item);
7271
7272 devlink_param_notify(devlink_port->devlink, devlink_port->index,
7273 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
7274}
7275EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
7276
bde74ad1
MS
7277/**
7278 * devlink_param_value_str_fill - Safely fill-up the string preventing
7279 * from overflow of the preallocated buffer
7280 *
7281 * @dst_val: destination devlink_param_value
7282 * @src: source buffer
7283 */
7284void devlink_param_value_str_fill(union devlink_param_value *dst_val,
7285 const char *src)
7286{
7287 size_t len;
7288
7289 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
7290 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
7291}
7292EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
7293
b16ebe92
AV
7294/**
7295 * devlink_region_create - create a new address region
7296 *
7297 * @devlink: devlink
7298 * @region_name: region name
7299 * @region_max_snapshots: Maximum supported number of snapshots for region
7300 * @region_size: size of region
7301 */
7302struct devlink_region *devlink_region_create(struct devlink *devlink,
7303 const char *region_name,
7304 u32 region_max_snapshots,
7305 u64 region_size)
7306{
7307 struct devlink_region *region;
7308 int err = 0;
7309
7310 mutex_lock(&devlink->lock);
7311
7312 if (devlink_region_get_by_name(devlink, region_name)) {
7313 err = -EEXIST;
7314 goto unlock;
7315 }
7316
7317 region = kzalloc(sizeof(*region), GFP_KERNEL);
7318 if (!region) {
7319 err = -ENOMEM;
7320 goto unlock;
7321 }
7322
7323 region->devlink = devlink;
7324 region->max_snapshots = region_max_snapshots;
7325 region->name = region_name;
7326 region->size = region_size;
7327 INIT_LIST_HEAD(&region->snapshot_list);
7328 list_add_tail(&region->list, &devlink->region_list);
866319bb 7329 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
b16ebe92
AV
7330
7331 mutex_unlock(&devlink->lock);
7332 return region;
7333
7334unlock:
7335 mutex_unlock(&devlink->lock);
7336 return ERR_PTR(err);
7337}
7338EXPORT_SYMBOL_GPL(devlink_region_create);
7339
7340/**
7341 * devlink_region_destroy - destroy address region
7342 *
7343 * @region: devlink region to destroy
7344 */
7345void devlink_region_destroy(struct devlink_region *region)
7346{
7347 struct devlink *devlink = region->devlink;
d7e52722 7348 struct devlink_snapshot *snapshot, *ts;
b16ebe92
AV
7349
7350 mutex_lock(&devlink->lock);
d7e52722
AV
7351
7352 /* Free all snapshots of region */
7353 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
92b49822 7354 devlink_region_snapshot_del(region, snapshot);
d7e52722 7355
b16ebe92 7356 list_del(&region->list);
866319bb
AV
7357
7358 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
b16ebe92
AV
7359 mutex_unlock(&devlink->lock);
7360 kfree(region);
7361}
7362EXPORT_SYMBOL_GPL(devlink_region_destroy);
7363
ccadfa44
AV
7364/**
7365 * devlink_region_shapshot_id_get - get snapshot ID
7366 *
7367 * This callback should be called when adding a new snapshot,
7368 * Driver should use the same id for multiple snapshots taken
7369 * on multiple regions at the same time/by the same trigger.
7370 *
7371 * @devlink: devlink
7372 */
7373u32 devlink_region_shapshot_id_get(struct devlink *devlink)
7374{
7375 u32 id;
7376
7377 mutex_lock(&devlink->lock);
7378 id = ++devlink->snapshot_id;
7379 mutex_unlock(&devlink->lock);
7380
7381 return id;
7382}
7383EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
7384
d7e52722
AV
7385/**
7386 * devlink_region_snapshot_create - create a new snapshot
7387 * This will add a new snapshot of a region. The snapshot
7388 * will be stored on the region struct and can be accessed
7389 * from devlink. This is useful for future analyses of snapshots.
7390 * Multiple snapshots can be created on a region.
7391 * The @snapshot_id should be obtained using the getter function.
7392 *
eeaadd82 7393 * @region: devlink region of the snapshot
d7e52722
AV
7394 * @data: snapshot data
7395 * @snapshot_id: snapshot id to be created
7396 * @data_destructor: pointer to destructor function to free data
7397 */
3a5e5234 7398int devlink_region_snapshot_create(struct devlink_region *region,
d7e52722
AV
7399 u8 *data, u32 snapshot_id,
7400 devlink_snapshot_data_dest_t *data_destructor)
7401{
7402 struct devlink *devlink = region->devlink;
7403 struct devlink_snapshot *snapshot;
7404 int err;
7405
7406 mutex_lock(&devlink->lock);
7407
7408 /* check if region can hold one more snapshot */
7409 if (region->cur_snapshots == region->max_snapshots) {
7410 err = -ENOMEM;
7411 goto unlock;
7412 }
7413
7414 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
7415 err = -EEXIST;
7416 goto unlock;
7417 }
7418
7419 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
7420 if (!snapshot) {
7421 err = -ENOMEM;
7422 goto unlock;
7423 }
7424
7425 snapshot->id = snapshot_id;
7426 snapshot->region = region;
7427 snapshot->data = data;
d7e52722
AV
7428 snapshot->data_destructor = data_destructor;
7429
7430 list_add_tail(&snapshot->list, &region->snapshot_list);
7431
7432 region->cur_snapshots++;
7433
866319bb 7434 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
d7e52722
AV
7435 mutex_unlock(&devlink->lock);
7436 return 0;
7437
7438unlock:
7439 mutex_unlock(&devlink->lock);
7440 return err;
7441}
7442EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
7443
0f420b6c
IS
7444#define DEVLINK_TRAP(_id, _type) \
7445 { \
7446 .type = DEVLINK_TRAP_TYPE_##_type, \
7447 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
7448 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
7449 }
7450
7451static const struct devlink_trap devlink_trap_generic[] = {
391203ab
IS
7452 DEVLINK_TRAP(SMAC_MC, DROP),
7453 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
7454 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
7455 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
7456 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
7457 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
7458 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
7459 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
7460 DEVLINK_TRAP(TAIL_DROP, DROP),
0f420b6c
IS
7461};
7462
7463#define DEVLINK_TRAP_GROUP(_id) \
7464 { \
7465 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
7466 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
7467 }
7468
7469static const struct devlink_trap_group devlink_trap_group_generic[] = {
391203ab
IS
7470 DEVLINK_TRAP_GROUP(L2_DROPS),
7471 DEVLINK_TRAP_GROUP(L3_DROPS),
7472 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
0f420b6c
IS
7473};
7474
7475static int devlink_trap_generic_verify(const struct devlink_trap *trap)
7476{
7477 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
7478 return -EINVAL;
7479
7480 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
7481 return -EINVAL;
7482
7483 if (trap->type != devlink_trap_generic[trap->id].type)
7484 return -EINVAL;
7485
7486 return 0;
7487}
7488
7489static int devlink_trap_driver_verify(const struct devlink_trap *trap)
7490{
7491 int i;
7492
7493 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
7494 return -EINVAL;
7495
7496 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
7497 if (!strcmp(trap->name, devlink_trap_generic[i].name))
7498 return -EEXIST;
7499 }
7500
7501 return 0;
7502}
7503
7504static int devlink_trap_verify(const struct devlink_trap *trap)
7505{
7506 if (!trap || !trap->name || !trap->group.name)
7507 return -EINVAL;
7508
7509 if (trap->generic)
7510 return devlink_trap_generic_verify(trap);
7511 else
7512 return devlink_trap_driver_verify(trap);
7513}
7514
7515static int
7516devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
7517{
7518 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
7519 return -EINVAL;
7520
7521 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
7522 return -EINVAL;
7523
7524 return 0;
7525}
7526
7527static int
7528devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
7529{
7530 int i;
7531
7532 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
7533 return -EINVAL;
7534
7535 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
7536 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
7537 return -EEXIST;
7538 }
7539
7540 return 0;
7541}
7542
7543static int devlink_trap_group_verify(const struct devlink_trap_group *group)
7544{
7545 if (group->generic)
7546 return devlink_trap_group_generic_verify(group);
7547 else
7548 return devlink_trap_group_driver_verify(group);
7549}
7550
7551static void
7552devlink_trap_group_notify(struct devlink *devlink,
7553 const struct devlink_trap_group_item *group_item,
7554 enum devlink_command cmd)
7555{
7556 struct sk_buff *msg;
7557 int err;
7558
7559 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
7560 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
7561
7562 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7563 if (!msg)
7564 return;
7565
7566 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
7567 0);
7568 if (err) {
7569 nlmsg_free(msg);
7570 return;
7571 }
7572
7573 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
7574 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
7575}
7576
7577static struct devlink_trap_group_item *
7578devlink_trap_group_item_create(struct devlink *devlink,
7579 const struct devlink_trap_group *group)
7580{
7581 struct devlink_trap_group_item *group_item;
7582 int err;
7583
7584 err = devlink_trap_group_verify(group);
7585 if (err)
7586 return ERR_PTR(err);
7587
7588 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
7589 if (!group_item)
7590 return ERR_PTR(-ENOMEM);
7591
7592 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
7593 if (!group_item->stats) {
7594 err = -ENOMEM;
7595 goto err_stats_alloc;
7596 }
7597
7598 group_item->group = group;
7599 refcount_set(&group_item->refcount, 1);
7600
7601 if (devlink->ops->trap_group_init) {
7602 err = devlink->ops->trap_group_init(devlink, group);
7603 if (err)
7604 goto err_group_init;
7605 }
7606
7607 list_add_tail(&group_item->list, &devlink->trap_group_list);
7608 devlink_trap_group_notify(devlink, group_item,
7609 DEVLINK_CMD_TRAP_GROUP_NEW);
7610
7611 return group_item;
7612
7613err_group_init:
7614 free_percpu(group_item->stats);
7615err_stats_alloc:
7616 kfree(group_item);
7617 return ERR_PTR(err);
7618}
7619
7620static void
7621devlink_trap_group_item_destroy(struct devlink *devlink,
7622 struct devlink_trap_group_item *group_item)
7623{
7624 devlink_trap_group_notify(devlink, group_item,
7625 DEVLINK_CMD_TRAP_GROUP_DEL);
7626 list_del(&group_item->list);
7627 free_percpu(group_item->stats);
7628 kfree(group_item);
7629}
7630
7631static struct devlink_trap_group_item *
7632devlink_trap_group_item_get(struct devlink *devlink,
7633 const struct devlink_trap_group *group)
7634{
7635 struct devlink_trap_group_item *group_item;
7636
7637 group_item = devlink_trap_group_item_lookup(devlink, group->name);
7638 if (group_item) {
7639 refcount_inc(&group_item->refcount);
7640 return group_item;
7641 }
7642
7643 return devlink_trap_group_item_create(devlink, group);
7644}
7645
7646static void
7647devlink_trap_group_item_put(struct devlink *devlink,
7648 struct devlink_trap_group_item *group_item)
7649{
7650 if (!refcount_dec_and_test(&group_item->refcount))
7651 return;
7652
7653 devlink_trap_group_item_destroy(devlink, group_item);
7654}
7655
7656static int
7657devlink_trap_item_group_link(struct devlink *devlink,
7658 struct devlink_trap_item *trap_item)
7659{
7660 struct devlink_trap_group_item *group_item;
7661
7662 group_item = devlink_trap_group_item_get(devlink,
7663 &trap_item->trap->group);
7664 if (IS_ERR(group_item))
7665 return PTR_ERR(group_item);
7666
7667 trap_item->group_item = group_item;
7668
7669 return 0;
7670}
7671
7672static void
7673devlink_trap_item_group_unlink(struct devlink *devlink,
7674 struct devlink_trap_item *trap_item)
7675{
7676 devlink_trap_group_item_put(devlink, trap_item->group_item);
7677}
7678
7679static void devlink_trap_notify(struct devlink *devlink,
7680 const struct devlink_trap_item *trap_item,
7681 enum devlink_command cmd)
7682{
7683 struct sk_buff *msg;
7684 int err;
7685
7686 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
7687 cmd != DEVLINK_CMD_TRAP_DEL);
7688
7689 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7690 if (!msg)
7691 return;
7692
7693 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
7694 if (err) {
7695 nlmsg_free(msg);
7696 return;
7697 }
7698
7699 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
7700 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
7701}
7702
7703static int
7704devlink_trap_register(struct devlink *devlink,
7705 const struct devlink_trap *trap, void *priv)
7706{
7707 struct devlink_trap_item *trap_item;
7708 int err;
7709
7710 if (devlink_trap_item_lookup(devlink, trap->name))
7711 return -EEXIST;
7712
7713 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
7714 if (!trap_item)
7715 return -ENOMEM;
7716
7717 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
7718 if (!trap_item->stats) {
7719 err = -ENOMEM;
7720 goto err_stats_alloc;
7721 }
7722
7723 trap_item->trap = trap;
7724 trap_item->action = trap->init_action;
7725 trap_item->priv = priv;
7726
7727 err = devlink_trap_item_group_link(devlink, trap_item);
7728 if (err)
7729 goto err_group_link;
7730
7731 err = devlink->ops->trap_init(devlink, trap, trap_item);
7732 if (err)
7733 goto err_trap_init;
7734
7735 list_add_tail(&trap_item->list, &devlink->trap_list);
7736 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
7737
7738 return 0;
7739
7740err_trap_init:
7741 devlink_trap_item_group_unlink(devlink, trap_item);
7742err_group_link:
7743 free_percpu(trap_item->stats);
7744err_stats_alloc:
7745 kfree(trap_item);
7746 return err;
7747}
7748
7749static void devlink_trap_unregister(struct devlink *devlink,
7750 const struct devlink_trap *trap)
7751{
7752 struct devlink_trap_item *trap_item;
7753
7754 trap_item = devlink_trap_item_lookup(devlink, trap->name);
7755 if (WARN_ON_ONCE(!trap_item))
7756 return;
7757
7758 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
7759 list_del(&trap_item->list);
7760 if (devlink->ops->trap_fini)
7761 devlink->ops->trap_fini(devlink, trap, trap_item);
7762 devlink_trap_item_group_unlink(devlink, trap_item);
7763 free_percpu(trap_item->stats);
7764 kfree(trap_item);
7765}
7766
7767static void devlink_trap_disable(struct devlink *devlink,
7768 const struct devlink_trap *trap)
7769{
7770 struct devlink_trap_item *trap_item;
7771
7772 trap_item = devlink_trap_item_lookup(devlink, trap->name);
7773 if (WARN_ON_ONCE(!trap_item))
7774 return;
7775
7776 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP);
7777 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
7778}
7779
7780/**
7781 * devlink_traps_register - Register packet traps with devlink.
7782 * @devlink: devlink.
7783 * @traps: Packet traps.
7784 * @traps_count: Count of provided packet traps.
7785 * @priv: Driver private information.
7786 *
7787 * Return: Non-zero value on failure.
7788 */
7789int devlink_traps_register(struct devlink *devlink,
7790 const struct devlink_trap *traps,
7791 size_t traps_count, void *priv)
7792{
7793 int i, err;
7794
7795 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
7796 return -EINVAL;
7797
7798 mutex_lock(&devlink->lock);
7799 for (i = 0; i < traps_count; i++) {
7800 const struct devlink_trap *trap = &traps[i];
7801
7802 err = devlink_trap_verify(trap);
7803 if (err)
7804 goto err_trap_verify;
7805
7806 err = devlink_trap_register(devlink, trap, priv);
7807 if (err)
7808 goto err_trap_register;
7809 }
7810 mutex_unlock(&devlink->lock);
7811
7812 return 0;
7813
7814err_trap_register:
7815err_trap_verify:
7816 for (i--; i >= 0; i--)
7817 devlink_trap_unregister(devlink, &traps[i]);
7818 mutex_unlock(&devlink->lock);
7819 return err;
7820}
7821EXPORT_SYMBOL_GPL(devlink_traps_register);
7822
7823/**
7824 * devlink_traps_unregister - Unregister packet traps from devlink.
7825 * @devlink: devlink.
7826 * @traps: Packet traps.
7827 * @traps_count: Count of provided packet traps.
7828 */
7829void devlink_traps_unregister(struct devlink *devlink,
7830 const struct devlink_trap *traps,
7831 size_t traps_count)
7832{
7833 int i;
7834
7835 mutex_lock(&devlink->lock);
7836 /* Make sure we do not have any packets in-flight while unregistering
7837 * traps by disabling all of them and waiting for a grace period.
7838 */
7839 for (i = traps_count - 1; i >= 0; i--)
7840 devlink_trap_disable(devlink, &traps[i]);
7841 synchronize_rcu();
7842 for (i = traps_count - 1; i >= 0; i--)
7843 devlink_trap_unregister(devlink, &traps[i]);
7844 mutex_unlock(&devlink->lock);
7845}
7846EXPORT_SYMBOL_GPL(devlink_traps_unregister);
7847
7848static void
7849devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
7850 size_t skb_len)
7851{
7852 struct devlink_stats *stats;
7853
7854 stats = this_cpu_ptr(trap_stats);
7855 u64_stats_update_begin(&stats->syncp);
7856 stats->rx_bytes += skb_len;
7857 stats->rx_packets++;
7858 u64_stats_update_end(&stats->syncp);
7859}
7860
7861static void
7862devlink_trap_report_metadata_fill(struct net_dm_hw_metadata *hw_metadata,
7863 const struct devlink_trap_item *trap_item,
7864 struct devlink_port *in_devlink_port)
7865{
7866 struct devlink_trap_group_item *group_item = trap_item->group_item;
7867
7868 hw_metadata->trap_group_name = group_item->group->name;
7869 hw_metadata->trap_name = trap_item->trap->name;
7870
7871 spin_lock(&in_devlink_port->type_lock);
7872 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
7873 hw_metadata->input_dev = in_devlink_port->type_dev;
7874 spin_unlock(&in_devlink_port->type_lock);
7875}
7876
7877/**
7878 * devlink_trap_report - Report trapped packet to drop monitor.
7879 * @devlink: devlink.
7880 * @skb: Trapped packet.
7881 * @trap_ctx: Trap context.
7882 * @in_devlink_port: Input devlink port.
7883 */
7884void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
7885 void *trap_ctx, struct devlink_port *in_devlink_port)
7886{
7887 struct devlink_trap_item *trap_item = trap_ctx;
7888 struct net_dm_hw_metadata hw_metadata = {};
7889
7890 devlink_trap_stats_update(trap_item->stats, skb->len);
7891 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
7892
7893 devlink_trap_report_metadata_fill(&hw_metadata, trap_item,
7894 in_devlink_port);
7895 net_dm_hw_report(skb, &hw_metadata);
7896}
7897EXPORT_SYMBOL_GPL(devlink_trap_report);
7898
7899/**
7900 * devlink_trap_ctx_priv - Trap context to driver private information.
7901 * @trap_ctx: Trap context.
7902 *
7903 * Return: Driver private information passed during registration.
7904 */
7905void *devlink_trap_ctx_priv(void *trap_ctx)
7906{
7907 struct devlink_trap_item *trap_item = trap_ctx;
7908
7909 return trap_item->priv;
7910}
7911EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
7912
ddb6e99e
JK
7913static void __devlink_compat_running_version(struct devlink *devlink,
7914 char *buf, size_t len)
7915{
7916 const struct nlattr *nlattr;
7917 struct devlink_info_req req;
7918 struct sk_buff *msg;
7919 int rem, err;
7920
ddb6e99e
JK
7921 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7922 if (!msg)
7923 return;
7924
7925 req.msg = msg;
7926 err = devlink->ops->info_get(devlink, &req, NULL);
7927 if (err)
7928 goto free_msg;
7929
7930 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
7931 const struct nlattr *kv;
7932 int rem_kv;
7933
7934 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
7935 continue;
7936
7937 nla_for_each_nested(kv, nlattr, rem_kv) {
7938 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
7939 continue;
7940
7941 strlcat(buf, nla_data(kv), len);
7942 strlcat(buf, " ", len);
7943 }
7944 }
7945free_msg:
7946 nlmsg_free(msg);
7947}
7948
7949void devlink_compat_running_version(struct net_device *dev,
7950 char *buf, size_t len)
7951{
ddb6e99e
JK
7952 struct devlink *devlink;
7953
1b45ff6c
JK
7954 dev_hold(dev);
7955 rtnl_unlock();
7956
b473b0d2 7957 devlink = netdev_to_devlink(dev);
be6fe1d8 7958 if (!devlink || !devlink->ops->info_get)
e0dcd386 7959 goto out;
b473b0d2
JK
7960
7961 mutex_lock(&devlink->lock);
7962 __devlink_compat_running_version(devlink, buf, len);
7963 mutex_unlock(&devlink->lock);
1b45ff6c 7964
e0dcd386 7965out:
1b45ff6c
JK
7966 rtnl_lock();
7967 dev_put(dev);
ddb6e99e
JK
7968}
7969
4eceba17
JK
7970int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
7971{
4eceba17 7972 struct devlink *devlink;
e0dcd386 7973 int ret;
4eceba17 7974
1b45ff6c
JK
7975 dev_hold(dev);
7976 rtnl_unlock();
7977
b473b0d2 7978 devlink = netdev_to_devlink(dev);
e0dcd386
JP
7979 if (!devlink || !devlink->ops->flash_update) {
7980 ret = -EOPNOTSUPP;
7981 goto out;
7982 }
4eceba17 7983
b473b0d2
JK
7984 mutex_lock(&devlink->lock);
7985 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
7986 mutex_unlock(&devlink->lock);
1b45ff6c 7987
e0dcd386 7988out:
1b45ff6c
JK
7989 rtnl_lock();
7990 dev_put(dev);
7991
b473b0d2 7992 return ret;
4eceba17
JK
7993}
7994
af3836df
JP
7995int devlink_compat_phys_port_name_get(struct net_device *dev,
7996 char *name, size_t len)
7997{
7998 struct devlink_port *devlink_port;
7999
8000 /* RTNL mutex is held here which ensures that devlink_port
8001 * instance cannot disappear in the middle. No need to take
8002 * any devlink lock as only permanent values are accessed.
8003 */
8004 ASSERT_RTNL();
8005
8006 devlink_port = netdev_to_devlink_port(dev);
8007 if (!devlink_port)
8008 return -EOPNOTSUPP;
8009
8010 return __devlink_port_phys_port_name_get(devlink_port, name, len);
8011}
8012
7e1146e8
JP
8013int devlink_compat_switch_id_get(struct net_device *dev,
8014 struct netdev_phys_item_id *ppid)
8015{
8016 struct devlink_port *devlink_port;
8017
043b8413
VB
8018 /* Caller must hold RTNL mutex or reference to dev, which ensures that
8019 * devlink_port instance cannot disappear in the middle. No need to take
7e1146e8
JP
8020 * any devlink lock as only permanent values are accessed.
8021 */
7e1146e8
JP
8022 devlink_port = netdev_to_devlink_port(dev);
8023 if (!devlink_port || !devlink_port->attrs.switch_port)
8024 return -EOPNOTSUPP;
8025
8026 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
8027
8028 return 0;
8029}
8030
f4b6bcc7 8031static int __init devlink_init(void)
bfcd3a46 8032{
489111e5 8033 return genl_register_family(&devlink_nl_family);
bfcd3a46
JP
8034}
8035
f4b6bcc7 8036subsys_initcall(devlink_init);