mlx4: Split restart_one into two functions
[linux-2.6-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 },
5bbd21df
DM
2855 {
2856 .id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
2857 .name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
2858 .type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
2859 },
036467c3 2860};
eabaef18
MS
2861
2862static int devlink_param_generic_verify(const struct devlink_param *param)
2863{
2864 /* verify it match generic parameter by id and name */
2865 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
2866 return -EINVAL;
2867 if (strcmp(param->name, devlink_param_generic[param->id].name))
2868 return -ENOENT;
2869
2870 WARN_ON(param->type != devlink_param_generic[param->id].type);
2871
2872 return 0;
2873}
2874
2875static int devlink_param_driver_verify(const struct devlink_param *param)
2876{
2877 int i;
2878
2879 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
2880 return -EINVAL;
2881 /* verify no such name in generic params */
2882 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
2883 if (!strcmp(param->name, devlink_param_generic[i].name))
2884 return -EEXIST;
2885
2886 return 0;
2887}
2888
2889static struct devlink_param_item *
2890devlink_param_find_by_name(struct list_head *param_list,
2891 const char *param_name)
2892{
2893 struct devlink_param_item *param_item;
2894
2895 list_for_each_entry(param_item, param_list, list)
2896 if (!strcmp(param_item->param->name, param_name))
2897 return param_item;
2898 return NULL;
2899}
2900
ec01aeb1
MS
2901static struct devlink_param_item *
2902devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
2903{
2904 struct devlink_param_item *param_item;
2905
2906 list_for_each_entry(param_item, param_list, list)
2907 if (param_item->param->id == param_id)
2908 return param_item;
2909 return NULL;
2910}
2911
45f05def
MS
2912static bool
2913devlink_param_cmode_is_supported(const struct devlink_param *param,
2914 enum devlink_param_cmode cmode)
2915{
2916 return test_bit(cmode, &param->supported_cmodes);
2917}
2918
2919static int devlink_param_get(struct devlink *devlink,
2920 const struct devlink_param *param,
2921 struct devlink_param_gset_ctx *ctx)
2922{
2923 if (!param->get)
2924 return -EOPNOTSUPP;
2925 return param->get(devlink, param->id, ctx);
2926}
2927
e3b7ca18
MS
2928static int devlink_param_set(struct devlink *devlink,
2929 const struct devlink_param *param,
2930 struct devlink_param_gset_ctx *ctx)
2931{
2932 if (!param->set)
2933 return -EOPNOTSUPP;
2934 return param->set(devlink, param->id, ctx);
2935}
2936
45f05def
MS
2937static int
2938devlink_param_type_to_nla_type(enum devlink_param_type param_type)
2939{
2940 switch (param_type) {
2941 case DEVLINK_PARAM_TYPE_U8:
2942 return NLA_U8;
2943 case DEVLINK_PARAM_TYPE_U16:
2944 return NLA_U16;
2945 case DEVLINK_PARAM_TYPE_U32:
2946 return NLA_U32;
2947 case DEVLINK_PARAM_TYPE_STRING:
2948 return NLA_STRING;
2949 case DEVLINK_PARAM_TYPE_BOOL:
2950 return NLA_FLAG;
2951 default:
2952 return -EINVAL;
2953 }
2954}
2955
2956static int
2957devlink_nl_param_value_fill_one(struct sk_buff *msg,
2958 enum devlink_param_type type,
2959 enum devlink_param_cmode cmode,
2960 union devlink_param_value val)
2961{
2962 struct nlattr *param_value_attr;
2963
ae0be8de
MK
2964 param_value_attr = nla_nest_start_noflag(msg,
2965 DEVLINK_ATTR_PARAM_VALUE);
45f05def
MS
2966 if (!param_value_attr)
2967 goto nla_put_failure;
2968
2969 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
2970 goto value_nest_cancel;
2971
2972 switch (type) {
2973 case DEVLINK_PARAM_TYPE_U8:
2974 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
2975 goto value_nest_cancel;
2976 break;
2977 case DEVLINK_PARAM_TYPE_U16:
2978 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
2979 goto value_nest_cancel;
2980 break;
2981 case DEVLINK_PARAM_TYPE_U32:
2982 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
2983 goto value_nest_cancel;
2984 break;
2985 case DEVLINK_PARAM_TYPE_STRING:
2986 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
2987 val.vstr))
2988 goto value_nest_cancel;
2989 break;
2990 case DEVLINK_PARAM_TYPE_BOOL:
2991 if (val.vbool &&
2992 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
2993 goto value_nest_cancel;
2994 break;
2995 }
2996
2997 nla_nest_end(msg, param_value_attr);
2998 return 0;
2999
3000value_nest_cancel:
3001 nla_nest_cancel(msg, param_value_attr);
3002nla_put_failure:
3003 return -EMSGSIZE;
3004}
3005
3006static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
f4601dee 3007 unsigned int port_index,
45f05def
MS
3008 struct devlink_param_item *param_item,
3009 enum devlink_command cmd,
3010 u32 portid, u32 seq, int flags)
3011{
3012 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
7c62cfb8 3013 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
45f05def
MS
3014 const struct devlink_param *param = param_item->param;
3015 struct devlink_param_gset_ctx ctx;
3016 struct nlattr *param_values_list;
3017 struct nlattr *param_attr;
3018 int nla_type;
3019 void *hdr;
3020 int err;
3021 int i;
3022
3023 /* Get value from driver part to driverinit configuration mode */
3024 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3025 if (!devlink_param_cmode_is_supported(param, i))
3026 continue;
3027 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3028 if (!param_item->driverinit_value_valid)
3029 return -EOPNOTSUPP;
3030 param_value[i] = param_item->driverinit_value;
3031 } else {
7c62cfb8
JP
3032 if (!param_item->published)
3033 continue;
45f05def
MS
3034 ctx.cmode = i;
3035 err = devlink_param_get(devlink, param, &ctx);
3036 if (err)
3037 return err;
3038 param_value[i] = ctx.val;
3039 }
7c62cfb8 3040 param_value_set[i] = true;
45f05def
MS
3041 }
3042
3043 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3044 if (!hdr)
3045 return -EMSGSIZE;
3046
3047 if (devlink_nl_put_handle(msg, devlink))
3048 goto genlmsg_cancel;
f4601dee 3049
c1e5786d
VV
3050 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3051 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3052 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
f4601dee
VV
3053 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3054 goto genlmsg_cancel;
3055
ae0be8de 3056 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
45f05def
MS
3057 if (!param_attr)
3058 goto genlmsg_cancel;
3059 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3060 goto param_nest_cancel;
3061 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3062 goto param_nest_cancel;
3063
3064 nla_type = devlink_param_type_to_nla_type(param->type);
3065 if (nla_type < 0)
3066 goto param_nest_cancel;
3067 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3068 goto param_nest_cancel;
3069
ae0be8de
MK
3070 param_values_list = nla_nest_start_noflag(msg,
3071 DEVLINK_ATTR_PARAM_VALUES_LIST);
45f05def
MS
3072 if (!param_values_list)
3073 goto param_nest_cancel;
3074
3075 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
7c62cfb8 3076 if (!param_value_set[i])
45f05def
MS
3077 continue;
3078 err = devlink_nl_param_value_fill_one(msg, param->type,
3079 i, param_value[i]);
3080 if (err)
3081 goto values_list_nest_cancel;
3082 }
3083
3084 nla_nest_end(msg, param_values_list);
3085 nla_nest_end(msg, param_attr);
3086 genlmsg_end(msg, hdr);
3087 return 0;
3088
3089values_list_nest_cancel:
3090 nla_nest_end(msg, param_values_list);
3091param_nest_cancel:
3092 nla_nest_cancel(msg, param_attr);
3093genlmsg_cancel:
3094 genlmsg_cancel(msg, hdr);
3095 return -EMSGSIZE;
3096}
3097
ea601e17 3098static void devlink_param_notify(struct devlink *devlink,
c1e5786d 3099 unsigned int port_index,
ea601e17
MS
3100 struct devlink_param_item *param_item,
3101 enum devlink_command cmd)
3102{
3103 struct sk_buff *msg;
3104 int err;
3105
c1e5786d
VV
3106 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3107 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3108 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
ea601e17
MS
3109
3110 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3111 if (!msg)
3112 return;
c1e5786d
VV
3113 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3114 0, 0, 0);
ea601e17
MS
3115 if (err) {
3116 nlmsg_free(msg);
3117 return;
3118 }
3119
3120 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3121 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3122}
3123
45f05def
MS
3124static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3125 struct netlink_callback *cb)
3126{
3127 struct devlink_param_item *param_item;
3128 struct devlink *devlink;
3129 int start = cb->args[0];
3130 int idx = 0;
3131 int err;
3132
3133 mutex_lock(&devlink_mutex);
3134 list_for_each_entry(devlink, &devlink_list, list) {
3135 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3136 continue;
3137 mutex_lock(&devlink->lock);
3138 list_for_each_entry(param_item, &devlink->param_list, list) {
3139 if (idx < start) {
3140 idx++;
3141 continue;
3142 }
f4601dee 3143 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
3144 DEVLINK_CMD_PARAM_GET,
3145 NETLINK_CB(cb->skb).portid,
3146 cb->nlh->nlmsg_seq,
3147 NLM_F_MULTI);
3148 if (err) {
3149 mutex_unlock(&devlink->lock);
3150 goto out;
3151 }
3152 idx++;
3153 }
3154 mutex_unlock(&devlink->lock);
3155 }
3156out:
3157 mutex_unlock(&devlink_mutex);
3158
3159 cb->args[0] = idx;
3160 return msg->len;
3161}
3162
e3b7ca18
MS
3163static int
3164devlink_param_type_get_from_info(struct genl_info *info,
3165 enum devlink_param_type *param_type)
3166{
3167 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3168 return -EINVAL;
3169
3170 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3171 case NLA_U8:
3172 *param_type = DEVLINK_PARAM_TYPE_U8;
3173 break;
3174 case NLA_U16:
3175 *param_type = DEVLINK_PARAM_TYPE_U16;
3176 break;
3177 case NLA_U32:
3178 *param_type = DEVLINK_PARAM_TYPE_U32;
3179 break;
3180 case NLA_STRING:
3181 *param_type = DEVLINK_PARAM_TYPE_STRING;
3182 break;
3183 case NLA_FLAG:
3184 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3185 break;
3186 default:
3187 return -EINVAL;
3188 }
3189
3190 return 0;
3191}
3192
3193static int
3194devlink_param_value_get_from_info(const struct devlink_param *param,
3195 struct genl_info *info,
3196 union devlink_param_value *value)
3197{
f355cfcd
MS
3198 int len;
3199
e3b7ca18
MS
3200 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3201 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3202 return -EINVAL;
3203
3204 switch (param->type) {
3205 case DEVLINK_PARAM_TYPE_U8:
3206 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3207 break;
3208 case DEVLINK_PARAM_TYPE_U16:
3209 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3210 break;
3211 case DEVLINK_PARAM_TYPE_U32:
3212 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3213 break;
3214 case DEVLINK_PARAM_TYPE_STRING:
f355cfcd
MS
3215 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3216 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3217 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
bde74ad1 3218 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
e3b7ca18 3219 return -EINVAL;
f355cfcd
MS
3220 strcpy(value->vstr,
3221 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
e3b7ca18
MS
3222 break;
3223 case DEVLINK_PARAM_TYPE_BOOL:
3224 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3225 true : false;
3226 break;
3227 }
3228 return 0;
3229}
3230
45f05def 3231static struct devlink_param_item *
f4601dee 3232devlink_param_get_from_info(struct list_head *param_list,
45f05def
MS
3233 struct genl_info *info)
3234{
3235 char *param_name;
3236
3237 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3238 return NULL;
3239
3240 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
f4601dee 3241 return devlink_param_find_by_name(param_list, param_name);
45f05def
MS
3242}
3243
3244static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3245 struct genl_info *info)
3246{
3247 struct devlink *devlink = info->user_ptr[0];
3248 struct devlink_param_item *param_item;
3249 struct sk_buff *msg;
3250 int err;
3251
f4601dee 3252 param_item = devlink_param_get_from_info(&devlink->param_list, info);
45f05def
MS
3253 if (!param_item)
3254 return -EINVAL;
3255
3256 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3257 if (!msg)
3258 return -ENOMEM;
3259
f4601dee 3260 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
3261 DEVLINK_CMD_PARAM_GET,
3262 info->snd_portid, info->snd_seq, 0);
3263 if (err) {
3264 nlmsg_free(msg);
3265 return err;
3266 }
3267
3268 return genlmsg_reply(msg, info);
3269}
3270
9c54873b 3271static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
c1e5786d 3272 unsigned int port_index,
9c54873b
VV
3273 struct list_head *param_list,
3274 struct genl_info *info,
3275 enum devlink_command cmd)
e3b7ca18 3276{
e3b7ca18
MS
3277 enum devlink_param_type param_type;
3278 struct devlink_param_gset_ctx ctx;
3279 enum devlink_param_cmode cmode;
3280 struct devlink_param_item *param_item;
3281 const struct devlink_param *param;
3282 union devlink_param_value value;
3283 int err = 0;
3284
9c54873b 3285 param_item = devlink_param_get_from_info(param_list, info);
e3b7ca18
MS
3286 if (!param_item)
3287 return -EINVAL;
3288 param = param_item->param;
3289 err = devlink_param_type_get_from_info(info, &param_type);
3290 if (err)
3291 return err;
3292 if (param_type != param->type)
3293 return -EINVAL;
3294 err = devlink_param_value_get_from_info(param, info, &value);
3295 if (err)
3296 return err;
3297 if (param->validate) {
3298 err = param->validate(devlink, param->id, value, info->extack);
3299 if (err)
3300 return err;
3301 }
3302
3303 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3304 return -EINVAL;
3305 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3306 if (!devlink_param_cmode_is_supported(param, cmode))
3307 return -EOPNOTSUPP;
3308
3309 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
1276534c
MS
3310 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3311 strcpy(param_item->driverinit_value.vstr, value.vstr);
3312 else
3313 param_item->driverinit_value = value;
e3b7ca18
MS
3314 param_item->driverinit_value_valid = true;
3315 } else {
3316 if (!param->set)
3317 return -EOPNOTSUPP;
3318 ctx.val = value;
3319 ctx.cmode = cmode;
3320 err = devlink_param_set(devlink, param, &ctx);
3321 if (err)
3322 return err;
3323 }
3324
c1e5786d 3325 devlink_param_notify(devlink, port_index, param_item, cmd);
e3b7ca18
MS
3326 return 0;
3327}
3328
9c54873b
VV
3329static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3330 struct genl_info *info)
3331{
3332 struct devlink *devlink = info->user_ptr[0];
3333
c1e5786d 3334 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
9c54873b
VV
3335 info, DEVLINK_CMD_PARAM_NEW);
3336}
3337
eabaef18 3338static int devlink_param_register_one(struct devlink *devlink,
c1e5786d 3339 unsigned int port_index,
39e6160e 3340 struct list_head *param_list,
c1e5786d
VV
3341 const struct devlink_param *param,
3342 enum devlink_command cmd)
eabaef18
MS
3343{
3344 struct devlink_param_item *param_item;
3345
39e6160e 3346 if (devlink_param_find_by_name(param_list, param->name))
eabaef18
MS
3347 return -EEXIST;
3348
3349 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3350 WARN_ON(param->get || param->set);
3351 else
3352 WARN_ON(!param->get || !param->set);
3353
3354 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3355 if (!param_item)
3356 return -ENOMEM;
3357 param_item->param = param;
3358
39e6160e 3359 list_add_tail(&param_item->list, param_list);
c1e5786d 3360 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3361 return 0;
3362}
3363
3364static void devlink_param_unregister_one(struct devlink *devlink,
c1e5786d 3365 unsigned int port_index,
39e6160e 3366 struct list_head *param_list,
c1e5786d
VV
3367 const struct devlink_param *param,
3368 enum devlink_command cmd)
eabaef18
MS
3369{
3370 struct devlink_param_item *param_item;
3371
39e6160e 3372 param_item = devlink_param_find_by_name(param_list, param->name);
eabaef18 3373 WARN_ON(!param_item);
c1e5786d 3374 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3375 list_del(&param_item->list);
3376 kfree(param_item);
3377}
3378
f4601dee
VV
3379static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3380 struct netlink_callback *cb)
3381{
3382 struct devlink_param_item *param_item;
3383 struct devlink_port *devlink_port;
3384 struct devlink *devlink;
3385 int start = cb->args[0];
3386 int idx = 0;
3387 int err;
3388
3389 mutex_lock(&devlink_mutex);
3390 list_for_each_entry(devlink, &devlink_list, list) {
3391 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3392 continue;
3393 mutex_lock(&devlink->lock);
3394 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3395 list_for_each_entry(param_item,
3396 &devlink_port->param_list, list) {
3397 if (idx < start) {
3398 idx++;
3399 continue;
3400 }
3401 err = devlink_nl_param_fill(msg,
3402 devlink_port->devlink,
3403 devlink_port->index, param_item,
3404 DEVLINK_CMD_PORT_PARAM_GET,
3405 NETLINK_CB(cb->skb).portid,
3406 cb->nlh->nlmsg_seq,
3407 NLM_F_MULTI);
3408 if (err) {
3409 mutex_unlock(&devlink->lock);
3410 goto out;
3411 }
3412 idx++;
3413 }
3414 }
3415 mutex_unlock(&devlink->lock);
3416 }
3417out:
3418 mutex_unlock(&devlink_mutex);
3419
3420 cb->args[0] = idx;
3421 return msg->len;
3422}
3423
3424static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3425 struct genl_info *info)
3426{
3427 struct devlink_port *devlink_port = info->user_ptr[0];
3428 struct devlink_param_item *param_item;
3429 struct sk_buff *msg;
3430 int err;
3431
3432 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3433 info);
3434 if (!param_item)
3435 return -EINVAL;
3436
3437 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3438 if (!msg)
3439 return -ENOMEM;
3440
3441 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3442 devlink_port->index, param_item,
3443 DEVLINK_CMD_PORT_PARAM_GET,
3444 info->snd_portid, info->snd_seq, 0);
3445 if (err) {
3446 nlmsg_free(msg);
3447 return err;
3448 }
3449
3450 return genlmsg_reply(msg, info);
3451}
3452
9c54873b
VV
3453static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3454 struct genl_info *info)
3455{
3456 struct devlink_port *devlink_port = info->user_ptr[0];
3457
3458 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
c1e5786d
VV
3459 devlink_port->index,
3460 &devlink_port->param_list, info,
3461 DEVLINK_CMD_PORT_PARAM_NEW);
9c54873b
VV
3462}
3463
a006d467
AV
3464static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3465 struct devlink *devlink,
3466 struct devlink_snapshot *snapshot)
3467{
3468 struct nlattr *snap_attr;
3469 int err;
3470
ae0be8de 3471 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
a006d467
AV
3472 if (!snap_attr)
3473 return -EINVAL;
3474
3475 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3476 if (err)
3477 goto nla_put_failure;
3478
3479 nla_nest_end(msg, snap_attr);
3480 return 0;
3481
3482nla_put_failure:
3483 nla_nest_cancel(msg, snap_attr);
3484 return err;
3485}
3486
3487static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3488 struct devlink *devlink,
3489 struct devlink_region *region)
3490{
3491 struct devlink_snapshot *snapshot;
3492 struct nlattr *snapshots_attr;
3493 int err;
3494
ae0be8de
MK
3495 snapshots_attr = nla_nest_start_noflag(msg,
3496 DEVLINK_ATTR_REGION_SNAPSHOTS);
a006d467
AV
3497 if (!snapshots_attr)
3498 return -EINVAL;
3499
3500 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3501 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3502 if (err)
3503 goto nla_put_failure;
3504 }
3505
3506 nla_nest_end(msg, snapshots_attr);
3507 return 0;
3508
3509nla_put_failure:
3510 nla_nest_cancel(msg, snapshots_attr);
3511 return err;
3512}
3513
d8db7ea5
AV
3514static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3515 enum devlink_command cmd, u32 portid,
3516 u32 seq, int flags,
3517 struct devlink_region *region)
3518{
3519 void *hdr;
3520 int err;
3521
3522 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3523 if (!hdr)
3524 return -EMSGSIZE;
3525
3526 err = devlink_nl_put_handle(msg, devlink);
3527 if (err)
3528 goto nla_put_failure;
3529
3530 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3531 if (err)
3532 goto nla_put_failure;
3533
3534 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3535 region->size,
3536 DEVLINK_ATTR_PAD);
3537 if (err)
3538 goto nla_put_failure;
3539
a006d467
AV
3540 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3541 if (err)
3542 goto nla_put_failure;
3543
d8db7ea5
AV
3544 genlmsg_end(msg, hdr);
3545 return 0;
3546
3547nla_put_failure:
3548 genlmsg_cancel(msg, hdr);
3549 return err;
3550}
3551
866319bb
AV
3552static void devlink_nl_region_notify(struct devlink_region *region,
3553 struct devlink_snapshot *snapshot,
3554 enum devlink_command cmd)
3555{
3556 struct devlink *devlink = region->devlink;
3557 struct sk_buff *msg;
3558 void *hdr;
3559 int err;
3560
3561 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3562
3563 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3564 if (!msg)
3565 return;
3566
3567 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3568 if (!hdr)
3569 goto out_free_msg;
3570
3571 err = devlink_nl_put_handle(msg, devlink);
3572 if (err)
3573 goto out_cancel_msg;
3574
3575 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3576 region->name);
3577 if (err)
3578 goto out_cancel_msg;
3579
3580 if (snapshot) {
3581 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3582 snapshot->id);
3583 if (err)
3584 goto out_cancel_msg;
3585 } else {
3586 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3587 region->size, DEVLINK_ATTR_PAD);
3588 if (err)
3589 goto out_cancel_msg;
3590 }
3591 genlmsg_end(msg, hdr);
3592
3593 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3594 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3595
3596 return;
3597
3598out_cancel_msg:
3599 genlmsg_cancel(msg, hdr);
3600out_free_msg:
3601 nlmsg_free(msg);
3602}
3603
92b49822
JP
3604static void devlink_region_snapshot_del(struct devlink_region *region,
3605 struct devlink_snapshot *snapshot)
3606{
3607 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3608 region->cur_snapshots--;
3609 list_del(&snapshot->list);
3610 (*snapshot->data_destructor)(snapshot->data);
3611 kfree(snapshot);
3612}
3613
d8db7ea5
AV
3614static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3615 struct genl_info *info)
3616{
3617 struct devlink *devlink = info->user_ptr[0];
3618 struct devlink_region *region;
3619 const char *region_name;
3620 struct sk_buff *msg;
3621 int err;
3622
3623 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3624 return -EINVAL;
3625
3626 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3627 region = devlink_region_get_by_name(devlink, region_name);
3628 if (!region)
3629 return -EINVAL;
3630
3631 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3632 if (!msg)
3633 return -ENOMEM;
3634
3635 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3636 info->snd_portid, info->snd_seq, 0,
3637 region);
3638 if (err) {
3639 nlmsg_free(msg);
3640 return err;
3641 }
3642
3643 return genlmsg_reply(msg, info);
3644}
3645
3646static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3647 struct netlink_callback *cb)
3648{
3649 struct devlink_region *region;
3650 struct devlink *devlink;
3651 int start = cb->args[0];
3652 int idx = 0;
3653 int err;
3654
3655 mutex_lock(&devlink_mutex);
3656 list_for_each_entry(devlink, &devlink_list, list) {
3657 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3658 continue;
3659
3660 mutex_lock(&devlink->lock);
3661 list_for_each_entry(region, &devlink->region_list, list) {
3662 if (idx < start) {
3663 idx++;
3664 continue;
3665 }
3666 err = devlink_nl_region_fill(msg, devlink,
3667 DEVLINK_CMD_REGION_GET,
3668 NETLINK_CB(cb->skb).portid,
3669 cb->nlh->nlmsg_seq,
3670 NLM_F_MULTI, region);
3671 if (err) {
3672 mutex_unlock(&devlink->lock);
3673 goto out;
3674 }
3675 idx++;
3676 }
3677 mutex_unlock(&devlink->lock);
3678 }
3679out:
3680 mutex_unlock(&devlink_mutex);
3681 cb->args[0] = idx;
3682 return msg->len;
3683}
3684
866319bb
AV
3685static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3686 struct genl_info *info)
3687{
3688 struct devlink *devlink = info->user_ptr[0];
3689 struct devlink_snapshot *snapshot;
3690 struct devlink_region *region;
3691 const char *region_name;
3692 u32 snapshot_id;
3693
3694 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3695 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3696 return -EINVAL;
3697
3698 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3699 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3700
3701 region = devlink_region_get_by_name(devlink, region_name);
3702 if (!region)
3703 return -EINVAL;
3704
3705 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3706 if (!snapshot)
3707 return -EINVAL;
3708
92b49822 3709 devlink_region_snapshot_del(region, snapshot);
866319bb
AV
3710 return 0;
3711}
3712
4e54795a
AV
3713static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3714 struct devlink *devlink,
3715 u8 *chunk, u32 chunk_size,
3716 u64 addr)
3717{
3718 struct nlattr *chunk_attr;
3719 int err;
3720
ae0be8de 3721 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
4e54795a
AV
3722 if (!chunk_attr)
3723 return -EINVAL;
3724
3725 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3726 if (err)
3727 goto nla_put_failure;
3728
3729 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3730 DEVLINK_ATTR_PAD);
3731 if (err)
3732 goto nla_put_failure;
3733
3734 nla_nest_end(msg, chunk_attr);
3735 return 0;
3736
3737nla_put_failure:
3738 nla_nest_cancel(msg, chunk_attr);
3739 return err;
3740}
3741
3742#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3743
3744static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3745 struct devlink *devlink,
3746 struct devlink_region *region,
3747 struct nlattr **attrs,
3748 u64 start_offset,
3749 u64 end_offset,
3750 bool dump,
3751 u64 *new_offset)
3752{
3753 struct devlink_snapshot *snapshot;
3754 u64 curr_offset = start_offset;
3755 u32 snapshot_id;
3756 int err = 0;
3757
3758 *new_offset = start_offset;
3759
3760 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3761 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3762 if (!snapshot)
3763 return -EINVAL;
3764
3a5e5234
JP
3765 if (end_offset > region->size || dump)
3766 end_offset = region->size;
4e54795a
AV
3767
3768 while (curr_offset < end_offset) {
3769 u32 data_size;
3770 u8 *data;
3771
3772 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3773 data_size = end_offset - curr_offset;
3774 else
3775 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3776
3777 data = &snapshot->data[curr_offset];
3778 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3779 data, data_size,
3780 curr_offset);
3781 if (err)
3782 break;
3783
3784 curr_offset += data_size;
3785 }
3786 *new_offset = curr_offset;
3787
3788 return err;
3789}
3790
3791static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3792 struct netlink_callback *cb)
3793{
3794 u64 ret_offset, start_offset, end_offset = 0;
4e54795a
AV
3795 struct devlink_region *region;
3796 struct nlattr *chunks_attr;
3797 const char *region_name;
3798 struct devlink *devlink;
68750561 3799 struct nlattr **attrs;
4e54795a
AV
3800 bool dump = true;
3801 void *hdr;
3802 int err;
3803
3804 start_offset = *((u64 *)&cb->args[0]);
3805
68750561
JK
3806 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
3807 if (!attrs)
3808 return -ENOMEM;
3809
8cb08174
JB
3810 err = nlmsg_parse_deprecated(cb->nlh,
3811 GENL_HDRLEN + devlink_nl_family.hdrsize,
3812 attrs, DEVLINK_ATTR_MAX,
3813 devlink_nl_family.policy, cb->extack);
4e54795a 3814 if (err)
68750561 3815 goto out_free;
4e54795a 3816
dac7c08f 3817 mutex_lock(&devlink_mutex);
4e54795a 3818 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
fdd41ec2
PP
3819 if (IS_ERR(devlink)) {
3820 err = PTR_ERR(devlink);
dac7c08f 3821 goto out_dev;
fdd41ec2 3822 }
4e54795a 3823
4e54795a
AV
3824 mutex_lock(&devlink->lock);
3825
3826 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
fdd41ec2
PP
3827 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
3828 err = -EINVAL;
4e54795a 3829 goto out_unlock;
fdd41ec2 3830 }
4e54795a
AV
3831
3832 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3833 region = devlink_region_get_by_name(devlink, region_name);
fdd41ec2
PP
3834 if (!region) {
3835 err = -EINVAL;
4e54795a 3836 goto out_unlock;
fdd41ec2 3837 }
4e54795a
AV
3838
3839 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3840 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3841 DEVLINK_CMD_REGION_READ);
fdd41ec2
PP
3842 if (!hdr) {
3843 err = -EMSGSIZE;
4e54795a 3844 goto out_unlock;
fdd41ec2 3845 }
4e54795a
AV
3846
3847 err = devlink_nl_put_handle(skb, devlink);
3848 if (err)
3849 goto nla_put_failure;
3850
3851 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3852 if (err)
3853 goto nla_put_failure;
3854
ae0be8de 3855 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
fdd41ec2
PP
3856 if (!chunks_attr) {
3857 err = -EMSGSIZE;
4e54795a 3858 goto nla_put_failure;
fdd41ec2 3859 }
4e54795a
AV
3860
3861 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3862 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3863 if (!start_offset)
3864 start_offset =
3865 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3866
3867 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3868 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3869 dump = false;
3870 }
3871
3872 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3873 region, attrs,
3874 start_offset,
3875 end_offset, dump,
3876 &ret_offset);
3877
3878 if (err && err != -EMSGSIZE)
3879 goto nla_put_failure;
3880
3881 /* Check if there was any progress done to prevent infinite loop */
fdd41ec2
PP
3882 if (ret_offset == start_offset) {
3883 err = -EINVAL;
4e54795a 3884 goto nla_put_failure;
fdd41ec2 3885 }
4e54795a
AV
3886
3887 *((u64 *)&cb->args[0]) = ret_offset;
3888
3889 nla_nest_end(skb, chunks_attr);
3890 genlmsg_end(skb, hdr);
3891 mutex_unlock(&devlink->lock);
3892 mutex_unlock(&devlink_mutex);
68750561 3893 kfree(attrs);
4e54795a
AV
3894
3895 return skb->len;
3896
3897nla_put_failure:
3898 genlmsg_cancel(skb, hdr);
3899out_unlock:
3900 mutex_unlock(&devlink->lock);
dac7c08f 3901out_dev:
4e54795a 3902 mutex_unlock(&devlink_mutex);
68750561
JK
3903out_free:
3904 kfree(attrs);
fdd41ec2 3905 return err;
4e54795a
AV
3906}
3907
f9cf2288
JK
3908struct devlink_info_req {
3909 struct sk_buff *msg;
3910};
3911
3912int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3913{
3914 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3915}
3916EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3917
3918int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3919{
3920 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3921}
3922EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3923
fc6fae7d
JK
3924static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3925 const char *version_name,
3926 const char *version_value)
3927{
3928 struct nlattr *nest;
3929 int err;
3930
ae0be8de 3931 nest = nla_nest_start_noflag(req->msg, attr);
fc6fae7d
JK
3932 if (!nest)
3933 return -EMSGSIZE;
3934
3935 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3936 version_name);
3937 if (err)
3938 goto nla_put_failure;
3939
3940 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3941 version_value);
3942 if (err)
3943 goto nla_put_failure;
3944
3945 nla_nest_end(req->msg, nest);
3946
3947 return 0;
3948
3949nla_put_failure:
3950 nla_nest_cancel(req->msg, nest);
3951 return err;
3952}
3953
3954int devlink_info_version_fixed_put(struct devlink_info_req *req,
3955 const char *version_name,
3956 const char *version_value)
3957{
3958 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3959 version_name, version_value);
3960}
3961EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3962
3963int devlink_info_version_stored_put(struct devlink_info_req *req,
3964 const char *version_name,
3965 const char *version_value)
3966{
3967 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3968 version_name, version_value);
3969}
3970EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3971
3972int devlink_info_version_running_put(struct devlink_info_req *req,
3973 const char *version_name,
3974 const char *version_value)
3975{
3976 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3977 version_name, version_value);
3978}
3979EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3980
f9cf2288
JK
3981static int
3982devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3983 enum devlink_command cmd, u32 portid,
3984 u32 seq, int flags, struct netlink_ext_ack *extack)
3985{
3986 struct devlink_info_req req;
3987 void *hdr;
3988 int err;
3989
3990 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3991 if (!hdr)
3992 return -EMSGSIZE;
3993
3994 err = -EMSGSIZE;
3995 if (devlink_nl_put_handle(msg, devlink))
3996 goto err_cancel_msg;
3997
3998 req.msg = msg;
3999 err = devlink->ops->info_get(devlink, &req, extack);
4000 if (err)
4001 goto err_cancel_msg;
4002
4003 genlmsg_end(msg, hdr);
4004 return 0;
4005
4006err_cancel_msg:
4007 genlmsg_cancel(msg, hdr);
4008 return err;
4009}
4010
4011static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
4012 struct genl_info *info)
4013{
4014 struct devlink *devlink = info->user_ptr[0];
4015 struct sk_buff *msg;
4016 int err;
4017
be6fe1d8 4018 if (!devlink->ops->info_get)
f9cf2288
JK
4019 return -EOPNOTSUPP;
4020
4021 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4022 if (!msg)
4023 return -ENOMEM;
4024
4025 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4026 info->snd_portid, info->snd_seq, 0,
4027 info->extack);
4028 if (err) {
4029 nlmsg_free(msg);
4030 return err;
4031 }
4032
4033 return genlmsg_reply(msg, info);
4034}
4035
4036static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
4037 struct netlink_callback *cb)
4038{
4039 struct devlink *devlink;
4040 int start = cb->args[0];
4041 int idx = 0;
4042 int err;
4043
4044 mutex_lock(&devlink_mutex);
4045 list_for_each_entry(devlink, &devlink_list, list) {
4046 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4047 continue;
4048 if (idx < start) {
4049 idx++;
4050 continue;
4051 }
4052
c493b09b
JP
4053 if (!devlink->ops->info_get) {
4054 idx++;
4055 continue;
4056 }
4057
f9cf2288
JK
4058 mutex_lock(&devlink->lock);
4059 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4060 NETLINK_CB(cb->skb).portid,
4061 cb->nlh->nlmsg_seq, NLM_F_MULTI,
4062 cb->extack);
4063 mutex_unlock(&devlink->lock);
4064 if (err)
4065 break;
4066 idx++;
4067 }
4068 mutex_unlock(&devlink_mutex);
4069
4070 cb->args[0] = idx;
4071 return msg->len;
4072}
4073
1db64e87
EBE
4074struct devlink_fmsg_item {
4075 struct list_head list;
4076 int attrtype;
4077 u8 nla_type;
4078 u16 len;
4079 int value[0];
4080};
4081
4082struct devlink_fmsg {
4083 struct list_head item_list;
4084};
4085
4086static struct devlink_fmsg *devlink_fmsg_alloc(void)
4087{
4088 struct devlink_fmsg *fmsg;
4089
4090 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
4091 if (!fmsg)
4092 return NULL;
4093
4094 INIT_LIST_HEAD(&fmsg->item_list);
4095
4096 return fmsg;
4097}
4098
4099static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
4100{
4101 struct devlink_fmsg_item *item, *tmp;
4102
4103 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
4104 list_del(&item->list);
4105 kfree(item);
4106 }
4107 kfree(fmsg);
4108}
4109
4110static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
4111 int attrtype)
4112{
4113 struct devlink_fmsg_item *item;
4114
4115 item = kzalloc(sizeof(*item), GFP_KERNEL);
4116 if (!item)
4117 return -ENOMEM;
4118
4119 item->attrtype = attrtype;
4120 list_add_tail(&item->list, &fmsg->item_list);
4121
4122 return 0;
4123}
4124
4125int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
4126{
4127 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
4128}
4129EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
4130
4131static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
4132{
4133 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
4134}
4135
4136int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
4137{
4138 return devlink_fmsg_nest_end(fmsg);
4139}
4140EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
4141
4142#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
4143
4144static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
4145{
4146 struct devlink_fmsg_item *item;
4147
4148 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4149 return -EMSGSIZE;
4150
4151 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4152 if (!item)
4153 return -ENOMEM;
4154
4155 item->nla_type = NLA_NUL_STRING;
4156 item->len = strlen(name) + 1;
4157 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4158 memcpy(&item->value, name, item->len);
4159 list_add_tail(&item->list, &fmsg->item_list);
4160
4161 return 0;
4162}
4163
4164int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4165{
4166 int err;
4167
4168 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4169 if (err)
4170 return err;
4171
4172 err = devlink_fmsg_put_name(fmsg, name);
4173 if (err)
4174 return err;
4175
4176 return 0;
4177}
4178EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4179
4180int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4181{
4182 return devlink_fmsg_nest_end(fmsg);
4183}
4184EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4185
4186int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4187 const char *name)
4188{
4189 int err;
4190
4191 err = devlink_fmsg_pair_nest_start(fmsg, name);
4192 if (err)
4193 return err;
4194
4195 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4196 if (err)
4197 return err;
4198
4199 return 0;
4200}
4201EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4202
4203int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4204{
4205 int err;
4206
4207 err = devlink_fmsg_nest_end(fmsg);
4208 if (err)
4209 return err;
4210
4211 err = devlink_fmsg_nest_end(fmsg);
4212 if (err)
4213 return err;
4214
4215 return 0;
4216}
4217EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4218
4219static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4220 const void *value, u16 value_len,
4221 u8 value_nla_type)
4222{
4223 struct devlink_fmsg_item *item;
4224
4225 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4226 return -EMSGSIZE;
4227
4228 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4229 if (!item)
4230 return -ENOMEM;
4231
4232 item->nla_type = value_nla_type;
4233 item->len = value_len;
4234 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4235 memcpy(&item->value, value, item->len);
4236 list_add_tail(&item->list, &fmsg->item_list);
4237
4238 return 0;
4239}
4240
4241int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4242{
4243 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4244}
4245EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4246
4247int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4248{
4249 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4250}
4251EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4252
4253int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4254{
4255 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4256}
4257EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4258
4259int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4260{
4261 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4262}
4263EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4264
4265int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4266{
4267 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4268 NLA_NUL_STRING);
4269}
4270EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4271
4272int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4273 u16 value_len)
4274{
4275 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4276}
4277EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4278
4279int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4280 bool value)
4281{
4282 int err;
4283
4284 err = devlink_fmsg_pair_nest_start(fmsg, name);
4285 if (err)
4286 return err;
4287
4288 err = devlink_fmsg_bool_put(fmsg, value);
4289 if (err)
4290 return err;
4291
4292 err = devlink_fmsg_pair_nest_end(fmsg);
4293 if (err)
4294 return err;
4295
4296 return 0;
4297}
4298EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4299
4300int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4301 u8 value)
4302{
4303 int err;
4304
4305 err = devlink_fmsg_pair_nest_start(fmsg, name);
4306 if (err)
4307 return err;
4308
4309 err = devlink_fmsg_u8_put(fmsg, value);
4310 if (err)
4311 return err;
4312
4313 err = devlink_fmsg_pair_nest_end(fmsg);
4314 if (err)
4315 return err;
4316
4317 return 0;
4318}
4319EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4320
4321int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4322 u32 value)
4323{
4324 int err;
4325
4326 err = devlink_fmsg_pair_nest_start(fmsg, name);
4327 if (err)
4328 return err;
4329
4330 err = devlink_fmsg_u32_put(fmsg, value);
4331 if (err)
4332 return err;
4333
4334 err = devlink_fmsg_pair_nest_end(fmsg);
4335 if (err)
4336 return err;
4337
4338 return 0;
4339}
4340EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4341
4342int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4343 u64 value)
4344{
4345 int err;
4346
4347 err = devlink_fmsg_pair_nest_start(fmsg, name);
4348 if (err)
4349 return err;
4350
4351 err = devlink_fmsg_u64_put(fmsg, value);
4352 if (err)
4353 return err;
4354
4355 err = devlink_fmsg_pair_nest_end(fmsg);
4356 if (err)
4357 return err;
4358
4359 return 0;
4360}
4361EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4362
4363int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4364 const char *value)
4365{
4366 int err;
4367
4368 err = devlink_fmsg_pair_nest_start(fmsg, name);
4369 if (err)
4370 return err;
4371
4372 err = devlink_fmsg_string_put(fmsg, value);
4373 if (err)
4374 return err;
4375
4376 err = devlink_fmsg_pair_nest_end(fmsg);
4377 if (err)
4378 return err;
4379
4380 return 0;
4381}
4382EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4383
4384int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4385 const void *value, u16 value_len)
4386{
4387 int err;
4388
4389 err = devlink_fmsg_pair_nest_start(fmsg, name);
4390 if (err)
4391 return err;
4392
4393 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4394 if (err)
4395 return err;
4396
4397 err = devlink_fmsg_pair_nest_end(fmsg);
4398 if (err)
4399 return err;
4400
4401 return 0;
4402}
4403EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4404
4405static int
4406devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4407{
4408 switch (msg->nla_type) {
4409 case NLA_FLAG:
4410 case NLA_U8:
4411 case NLA_U32:
4412 case NLA_U64:
4413 case NLA_NUL_STRING:
4414 case NLA_BINARY:
4415 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4416 msg->nla_type);
4417 default:
4418 return -EINVAL;
4419 }
4420}
4421
4422static int
4423devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4424{
4425 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4426 u8 tmp;
4427
4428 switch (msg->nla_type) {
4429 case NLA_FLAG:
4430 /* Always provide flag data, regardless of its value */
4431 tmp = *(bool *) msg->value;
4432
4433 return nla_put_u8(skb, attrtype, tmp);
4434 case NLA_U8:
4435 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4436 case NLA_U32:
4437 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4438 case NLA_U64:
4439 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4440 DEVLINK_ATTR_PAD);
4441 case NLA_NUL_STRING:
4442 return nla_put_string(skb, attrtype, (char *) &msg->value);
4443 case NLA_BINARY:
4444 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4445 default:
4446 return -EINVAL;
4447 }
4448}
4449
4450static int
4451devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4452 int *start)
4453{
4454 struct devlink_fmsg_item *item;
4455 struct nlattr *fmsg_nlattr;
4456 int i = 0;
4457 int err;
4458
ae0be8de 4459 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
1db64e87
EBE
4460 if (!fmsg_nlattr)
4461 return -EMSGSIZE;
4462
4463 list_for_each_entry(item, &fmsg->item_list, list) {
4464 if (i < *start) {
4465 i++;
4466 continue;
4467 }
4468
4469 switch (item->attrtype) {
4470 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4471 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4472 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4473 case DEVLINK_ATTR_FMSG_NEST_END:
4474 err = nla_put_flag(skb, item->attrtype);
4475 break;
4476 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4477 err = devlink_fmsg_item_fill_type(item, skb);
4478 if (err)
4479 break;
4480 err = devlink_fmsg_item_fill_data(item, skb);
4481 break;
4482 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4483 err = nla_put_string(skb, item->attrtype,
4484 (char *) &item->value);
4485 break;
4486 default:
4487 err = -EINVAL;
4488 break;
4489 }
4490 if (!err)
4491 *start = ++i;
4492 else
4493 break;
4494 }
4495
4496 nla_nest_end(skb, fmsg_nlattr);
4497 return err;
4498}
4499
4500static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4501 struct genl_info *info,
4502 enum devlink_command cmd, int flags)
4503{
4504 struct nlmsghdr *nlh;
4505 struct sk_buff *skb;
4506 bool last = false;
4507 int index = 0;
4508 void *hdr;
4509 int err;
4510
4511 while (!last) {
4512 int tmp_index = index;
4513
4514 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4515 if (!skb)
4516 return -ENOMEM;
4517
4518 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4519 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4520 if (!hdr) {
4521 err = -EMSGSIZE;
4522 goto nla_put_failure;
4523 }
4524
4525 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4526 if (!err)
4527 last = true;
4528 else if (err != -EMSGSIZE || tmp_index == index)
4529 goto nla_put_failure;
4530
4531 genlmsg_end(skb, hdr);
4532 err = genlmsg_reply(skb, info);
4533 if (err)
4534 return err;
4535 }
4536
4537 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4538 if (!skb)
4539 return -ENOMEM;
4540 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4541 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4542 if (!nlh) {
4543 err = -EMSGSIZE;
4544 goto nla_put_failure;
4545 }
1db64e87 4546
fde55ea7 4547 return genlmsg_reply(skb, info);
1db64e87
EBE
4548
4549nla_put_failure:
4550 nlmsg_free(skb);
4551 return err;
4552}
4553
e44ef4e4
AL
4554static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4555 struct netlink_callback *cb,
4556 enum devlink_command cmd)
4557{
4558 int index = cb->args[0];
4559 int tmp_index = index;
4560 void *hdr;
4561 int err;
4562
4563 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4564 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
4565 if (!hdr) {
4566 err = -EMSGSIZE;
4567 goto nla_put_failure;
4568 }
4569
4570 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4571 if ((err && err != -EMSGSIZE) || tmp_index == index)
4572 goto nla_put_failure;
4573
4574 cb->args[0] = index;
4575 genlmsg_end(skb, hdr);
4576 return skb->len;
4577
4578nla_put_failure:
4579 genlmsg_cancel(skb, hdr);
4580 return err;
4581}
4582
a0bdcc59
EBE
4583struct devlink_health_reporter {
4584 struct list_head list;
4585 void *priv;
4586 const struct devlink_health_reporter_ops *ops;
4587 struct devlink *devlink;
c8e1da0b
EBE
4588 struct devlink_fmsg *dump_fmsg;
4589 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
a0bdcc59
EBE
4590 u64 graceful_period;
4591 bool auto_recover;
4592 u8 health_state;
c8e1da0b
EBE
4593 u64 dump_ts;
4594 u64 error_count;
4595 u64 recovery_count;
4596 u64 last_recovery_ts;
b587bdaf 4597 refcount_t refcount;
c8e1da0b
EBE
4598};
4599
a0bdcc59
EBE
4600void *
4601devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4602{
4603 return reporter->priv;
4604}
4605EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4606
4607static struct devlink_health_reporter *
4608devlink_health_reporter_find_by_name(struct devlink *devlink,
4609 const char *reporter_name)
4610{
4611 struct devlink_health_reporter *reporter;
4612
b587bdaf 4613 lockdep_assert_held(&devlink->reporters_lock);
a0bdcc59
EBE
4614 list_for_each_entry(reporter, &devlink->reporter_list, list)
4615 if (!strcmp(reporter->ops->name, reporter_name))
4616 return reporter;
4617 return NULL;
4618}
4619
4620/**
4621 * devlink_health_reporter_create - create devlink health reporter
4622 *
4623 * @devlink: devlink
4624 * @ops: ops
4625 * @graceful_period: to avoid recovery loops, in msecs
4626 * @auto_recover: auto recover when error occurs
4627 * @priv: priv
4628 */
4629struct devlink_health_reporter *
4630devlink_health_reporter_create(struct devlink *devlink,
4631 const struct devlink_health_reporter_ops *ops,
4632 u64 graceful_period, bool auto_recover,
4633 void *priv)
4634{
4635 struct devlink_health_reporter *reporter;
4636
b587bdaf 4637 mutex_lock(&devlink->reporters_lock);
a0bdcc59
EBE
4638 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4639 reporter = ERR_PTR(-EEXIST);
4640 goto unlock;
4641 }
4642
4643 if (WARN_ON(auto_recover && !ops->recover) ||
4644 WARN_ON(graceful_period && !ops->recover)) {
4645 reporter = ERR_PTR(-EINVAL);
4646 goto unlock;
4647 }
4648
4649 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4650 if (!reporter) {
4651 reporter = ERR_PTR(-ENOMEM);
4652 goto unlock;
4653 }
4654
4655 reporter->priv = priv;
4656 reporter->ops = ops;
4657 reporter->devlink = devlink;
4658 reporter->graceful_period = graceful_period;
4659 reporter->auto_recover = auto_recover;
c8e1da0b 4660 mutex_init(&reporter->dump_lock);
b587bdaf 4661 refcount_set(&reporter->refcount, 1);
a0bdcc59
EBE
4662 list_add_tail(&reporter->list, &devlink->reporter_list);
4663unlock:
b587bdaf 4664 mutex_unlock(&devlink->reporters_lock);
a0bdcc59
EBE
4665 return reporter;
4666}
4667EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4668
4669/**
4670 * devlink_health_reporter_destroy - destroy devlink health reporter
4671 *
4672 * @reporter: devlink health reporter to destroy
4673 */
4674void
4675devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4676{
b587bdaf 4677 mutex_lock(&reporter->devlink->reporters_lock);
a0bdcc59 4678 list_del(&reporter->list);
b587bdaf
MS
4679 mutex_unlock(&reporter->devlink->reporters_lock);
4680 while (refcount_read(&reporter->refcount) > 1)
4681 msleep(100);
375cf8c6 4682 mutex_destroy(&reporter->dump_lock);
c8e1da0b
EBE
4683 if (reporter->dump_fmsg)
4684 devlink_fmsg_free(reporter->dump_fmsg);
a0bdcc59
EBE
4685 kfree(reporter);
4686}
4687EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4688
3167b27a
EBE
4689void
4690devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
4691 enum devlink_health_reporter_state state)
4692{
4693 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
4694 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
4695 return;
4696
4697 if (reporter->health_state == state)
4698 return;
4699
4700 reporter->health_state = state;
4701 trace_devlink_health_reporter_state_update(reporter->devlink,
4702 reporter->ops->name, state);
4703}
4704EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
4705
c8e1da0b
EBE
4706static int
4707devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4708 void *priv_ctx)
4709{
4710 int err;
4711
4712 if (!reporter->ops->recover)
4713 return -EOPNOTSUPP;
4714
4715 err = reporter->ops->recover(reporter, priv_ctx);
4716 if (err)
4717 return err;
4718
4719 reporter->recovery_count++;
4720 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4721 reporter->last_recovery_ts = jiffies;
4722
4723 return 0;
4724}
4725
4726static void
4727devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4728{
4729 if (!reporter->dump_fmsg)
4730 return;
4731 devlink_fmsg_free(reporter->dump_fmsg);
4732 reporter->dump_fmsg = NULL;
4733}
4734
4735static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4736 void *priv_ctx)
4737{
4738 int err;
4739
4740 if (!reporter->ops->dump)
4741 return 0;
4742
4743 if (reporter->dump_fmsg)
4744 return 0;
4745
4746 reporter->dump_fmsg = devlink_fmsg_alloc();
4747 if (!reporter->dump_fmsg) {
4748 err = -ENOMEM;
4749 return err;
4750 }
4751
4752 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4753 if (err)
4754 goto dump_err;
4755
4756 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4757 priv_ctx);
4758 if (err)
4759 goto dump_err;
4760
4761 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4762 if (err)
4763 goto dump_err;
4764
4765 reporter->dump_ts = jiffies;
4766
4767 return 0;
4768
4769dump_err:
4770 devlink_health_dump_clear(reporter);
4771 return err;
4772}
4773
4774int devlink_health_report(struct devlink_health_reporter *reporter,
4775 const char *msg, void *priv_ctx)
4776{
a0a21adb 4777 enum devlink_health_reporter_state prev_health_state;
c8e1da0b
EBE
4778 struct devlink *devlink = reporter->devlink;
4779
4780 /* write a log message of the current error */
4781 WARN_ON(!msg);
4782 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4783 reporter->error_count++;
a0a21adb
EBE
4784 prev_health_state = reporter->health_state;
4785 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
c8e1da0b
EBE
4786
4787 /* abort if the previous error wasn't recovered */
4788 if (reporter->auto_recover &&
a0a21adb 4789 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
c8e1da0b
EBE
4790 jiffies - reporter->last_recovery_ts <
4791 msecs_to_jiffies(reporter->graceful_period))) {
4792 trace_devlink_health_recover_aborted(devlink,
4793 reporter->ops->name,
4794 reporter->health_state,
4795 jiffies -
4796 reporter->last_recovery_ts);
4797 return -ECANCELED;
4798 }
4799
4800 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4801
4802 mutex_lock(&reporter->dump_lock);
4803 /* store current dump of current error, for later analysis */
4804 devlink_health_do_dump(reporter, priv_ctx);
4805 mutex_unlock(&reporter->dump_lock);
4806
4807 if (reporter->auto_recover)
4808 return devlink_health_reporter_recover(reporter, priv_ctx);
4809
4810 return 0;
4811}
4812EXPORT_SYMBOL_GPL(devlink_health_report);
4813
7afe335a 4814static struct devlink_health_reporter *
e44ef4e4
AL
4815devlink_health_reporter_get_from_attrs(struct devlink *devlink,
4816 struct nlattr **attrs)
7afe335a 4817{
b587bdaf 4818 struct devlink_health_reporter *reporter;
7afe335a
EBE
4819 char *reporter_name;
4820
e44ef4e4 4821 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
7afe335a
EBE
4822 return NULL;
4823
e44ef4e4 4824 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
b587bdaf
MS
4825 mutex_lock(&devlink->reporters_lock);
4826 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
4827 if (reporter)
4828 refcount_inc(&reporter->refcount);
4829 mutex_unlock(&devlink->reporters_lock);
4830 return reporter;
4831}
4832
e44ef4e4
AL
4833static struct devlink_health_reporter *
4834devlink_health_reporter_get_from_info(struct devlink *devlink,
4835 struct genl_info *info)
4836{
4837 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
4838}
4839
4840static struct devlink_health_reporter *
4841devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
4842{
4843 struct devlink_health_reporter *reporter;
4844 struct devlink *devlink;
4845 struct nlattr **attrs;
4846 int err;
4847
4848 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
4849 if (!attrs)
4850 return NULL;
4851
4852 err = nlmsg_parse_deprecated(cb->nlh,
4853 GENL_HDRLEN + devlink_nl_family.hdrsize,
4854 attrs, DEVLINK_ATTR_MAX,
4855 devlink_nl_family.policy, cb->extack);
4856 if (err)
4857 goto free;
4858
4859 mutex_lock(&devlink_mutex);
4860 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
4861 if (IS_ERR(devlink))
4862 goto unlock;
4863
4864 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
4865 mutex_unlock(&devlink_mutex);
4866 kfree(attrs);
4867 return reporter;
4868unlock:
4869 mutex_unlock(&devlink_mutex);
4870free:
4871 kfree(attrs);
4872 return NULL;
4873}
4874
b587bdaf
MS
4875static void
4876devlink_health_reporter_put(struct devlink_health_reporter *reporter)
4877{
4878 refcount_dec(&reporter->refcount);
7afe335a
EBE
4879}
4880
4881static int
4882devlink_nl_health_reporter_fill(struct sk_buff *msg,
4883 struct devlink *devlink,
4884 struct devlink_health_reporter *reporter,
4885 enum devlink_command cmd, u32 portid,
4886 u32 seq, int flags)
4887{
4888 struct nlattr *reporter_attr;
4889 void *hdr;
4890
4891 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4892 if (!hdr)
4893 return -EMSGSIZE;
4894
4895 if (devlink_nl_put_handle(msg, devlink))
4896 goto genlmsg_cancel;
4897
ae0be8de
MK
4898 reporter_attr = nla_nest_start_noflag(msg,
4899 DEVLINK_ATTR_HEALTH_REPORTER);
7afe335a
EBE
4900 if (!reporter_attr)
4901 goto genlmsg_cancel;
4902 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4903 reporter->ops->name))
4904 goto reporter_nest_cancel;
4905 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4906 reporter->health_state))
4907 goto reporter_nest_cancel;
54719527 4908 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
7afe335a
EBE
4909 reporter->error_count, DEVLINK_ATTR_PAD))
4910 goto reporter_nest_cancel;
54719527 4911 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
7afe335a
EBE
4912 reporter->recovery_count, DEVLINK_ATTR_PAD))
4913 goto reporter_nest_cancel;
574b1e1f
AL
4914 if (reporter->ops->recover &&
4915 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
7afe335a
EBE
4916 reporter->graceful_period,
4917 DEVLINK_ATTR_PAD))
4918 goto reporter_nest_cancel;
574b1e1f
AL
4919 if (reporter->ops->recover &&
4920 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
7afe335a
EBE
4921 reporter->auto_recover))
4922 goto reporter_nest_cancel;
4923 if (reporter->dump_fmsg &&
4924 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4925 jiffies_to_msecs(reporter->dump_ts),
4926 DEVLINK_ATTR_PAD))
4927 goto reporter_nest_cancel;
4928
4929 nla_nest_end(msg, reporter_attr);
4930 genlmsg_end(msg, hdr);
4931 return 0;
4932
4933reporter_nest_cancel:
4934 nla_nest_end(msg, reporter_attr);
4935genlmsg_cancel:
4936 genlmsg_cancel(msg, hdr);
4937 return -EMSGSIZE;
4938}
4939
4940static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4941 struct genl_info *info)
4942{
4943 struct devlink *devlink = info->user_ptr[0];
4944 struct devlink_health_reporter *reporter;
4945 struct sk_buff *msg;
4946 int err;
4947
4948 reporter = devlink_health_reporter_get_from_info(devlink, info);
4949 if (!reporter)
4950 return -EINVAL;
4951
4952 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
b587bdaf
MS
4953 if (!msg) {
4954 err = -ENOMEM;
4955 goto out;
4956 }
7afe335a
EBE
4957
4958 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4959 DEVLINK_CMD_HEALTH_REPORTER_GET,
4960 info->snd_portid, info->snd_seq,
4961 0);
4962 if (err) {
4963 nlmsg_free(msg);
b587bdaf 4964 goto out;
7afe335a
EBE
4965 }
4966
b587bdaf
MS
4967 err = genlmsg_reply(msg, info);
4968out:
4969 devlink_health_reporter_put(reporter);
4970 return err;
7afe335a
EBE
4971}
4972
4973static int
4974devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4975 struct netlink_callback *cb)
4976{
4977 struct devlink_health_reporter *reporter;
4978 struct devlink *devlink;
4979 int start = cb->args[0];
4980 int idx = 0;
4981 int err;
4982
4983 mutex_lock(&devlink_mutex);
4984 list_for_each_entry(devlink, &devlink_list, list) {
4985 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4986 continue;
b587bdaf 4987 mutex_lock(&devlink->reporters_lock);
7afe335a
EBE
4988 list_for_each_entry(reporter, &devlink->reporter_list,
4989 list) {
4990 if (idx < start) {
4991 idx++;
4992 continue;
4993 }
4994 err = devlink_nl_health_reporter_fill(msg, devlink,
4995 reporter,
4996 DEVLINK_CMD_HEALTH_REPORTER_GET,
4997 NETLINK_CB(cb->skb).portid,
4998 cb->nlh->nlmsg_seq,
4999 NLM_F_MULTI);
5000 if (err) {
b587bdaf 5001 mutex_unlock(&devlink->reporters_lock);
7afe335a
EBE
5002 goto out;
5003 }
5004 idx++;
5005 }
b587bdaf 5006 mutex_unlock(&devlink->reporters_lock);
7afe335a
EBE
5007 }
5008out:
5009 mutex_unlock(&devlink_mutex);
5010
5011 cb->args[0] = idx;
5012 return msg->len;
5013}
5014
a1e55ec0
EBE
5015static int
5016devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
5017 struct genl_info *info)
5018{
5019 struct devlink *devlink = info->user_ptr[0];
5020 struct devlink_health_reporter *reporter;
b587bdaf 5021 int err;
a1e55ec0
EBE
5022
5023 reporter = devlink_health_reporter_get_from_info(devlink, info);
5024 if (!reporter)
5025 return -EINVAL;
5026
5027 if (!reporter->ops->recover &&
5028 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
b587bdaf
MS
5029 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
5030 err = -EOPNOTSUPP;
5031 goto out;
5032 }
a1e55ec0
EBE
5033
5034 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
5035 reporter->graceful_period =
5036 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
5037
5038 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
5039 reporter->auto_recover =
5040 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
5041
b587bdaf 5042 devlink_health_reporter_put(reporter);
a1e55ec0 5043 return 0;
b587bdaf
MS
5044out:
5045 devlink_health_reporter_put(reporter);
5046 return err;
a1e55ec0
EBE
5047}
5048
20a0943a
EBE
5049static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
5050 struct genl_info *info)
5051{
5052 struct devlink *devlink = info->user_ptr[0];
5053 struct devlink_health_reporter *reporter;
b587bdaf 5054 int err;
20a0943a
EBE
5055
5056 reporter = devlink_health_reporter_get_from_info(devlink, info);
5057 if (!reporter)
5058 return -EINVAL;
5059
b587bdaf
MS
5060 err = devlink_health_reporter_recover(reporter, NULL);
5061
5062 devlink_health_reporter_put(reporter);
5063 return err;
20a0943a
EBE
5064}
5065
fca42a27
EBE
5066static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
5067 struct genl_info *info)
5068{
5069 struct devlink *devlink = info->user_ptr[0];
5070 struct devlink_health_reporter *reporter;
5071 struct devlink_fmsg *fmsg;
5072 int err;
5073
5074 reporter = devlink_health_reporter_get_from_info(devlink, info);
5075 if (!reporter)
5076 return -EINVAL;
5077
b587bdaf
MS
5078 if (!reporter->ops->diagnose) {
5079 devlink_health_reporter_put(reporter);
fca42a27 5080 return -EOPNOTSUPP;
b587bdaf 5081 }
fca42a27
EBE
5082
5083 fmsg = devlink_fmsg_alloc();
b587bdaf
MS
5084 if (!fmsg) {
5085 devlink_health_reporter_put(reporter);
fca42a27 5086 return -ENOMEM;
b587bdaf 5087 }
fca42a27
EBE
5088
5089 err = devlink_fmsg_obj_nest_start(fmsg);
5090 if (err)
5091 goto out;
5092
5093 err = reporter->ops->diagnose(reporter, fmsg);
5094 if (err)
5095 goto out;
5096
5097 err = devlink_fmsg_obj_nest_end(fmsg);
5098 if (err)
5099 goto out;
5100
5101 err = devlink_fmsg_snd(fmsg, info,
5102 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
5103
5104out:
5105 devlink_fmsg_free(fmsg);
b587bdaf 5106 devlink_health_reporter_put(reporter);
fca42a27
EBE
5107 return err;
5108}
5109
e44ef4e4
AL
5110static int
5111devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
5112 struct netlink_callback *cb)
35455e23 5113{
35455e23 5114 struct devlink_health_reporter *reporter;
e44ef4e4 5115 u64 start = cb->args[0];
35455e23
EBE
5116 int err;
5117
e44ef4e4 5118 reporter = devlink_health_reporter_get_from_cb(cb);
35455e23
EBE
5119 if (!reporter)
5120 return -EINVAL;
5121
b587bdaf 5122 if (!reporter->ops->dump) {
e44ef4e4
AL
5123 err = -EOPNOTSUPP;
5124 goto out;
b587bdaf 5125 }
35455e23 5126 mutex_lock(&reporter->dump_lock);
e44ef4e4
AL
5127 if (!start) {
5128 err = devlink_health_do_dump(reporter, NULL);
5129 if (err)
5130 goto unlock;
5131 cb->args[1] = reporter->dump_ts;
5132 }
5133 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
5134 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
5135 err = -EAGAIN;
5136 goto unlock;
5137 }
35455e23 5138
e44ef4e4
AL
5139 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
5140 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
5141unlock:
35455e23 5142 mutex_unlock(&reporter->dump_lock);
e44ef4e4 5143out:
b587bdaf 5144 devlink_health_reporter_put(reporter);
35455e23
EBE
5145 return err;
5146}
5147
5148static int
5149devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
5150 struct genl_info *info)
5151{
5152 struct devlink *devlink = info->user_ptr[0];
5153 struct devlink_health_reporter *reporter;
5154
5155 reporter = devlink_health_reporter_get_from_info(devlink, info);
5156 if (!reporter)
5157 return -EINVAL;
5158
b587bdaf
MS
5159 if (!reporter->ops->dump) {
5160 devlink_health_reporter_put(reporter);
35455e23 5161 return -EOPNOTSUPP;
b587bdaf 5162 }
35455e23
EBE
5163
5164 mutex_lock(&reporter->dump_lock);
5165 devlink_health_dump_clear(reporter);
5166 mutex_unlock(&reporter->dump_lock);
b587bdaf 5167 devlink_health_reporter_put(reporter);
35455e23
EBE
5168 return 0;
5169}
5170
0f420b6c
IS
5171struct devlink_stats {
5172 u64 rx_bytes;
5173 u64 rx_packets;
5174 struct u64_stats_sync syncp;
5175};
5176
5177/**
5178 * struct devlink_trap_group_item - Packet trap group attributes.
5179 * @group: Immutable packet trap group attributes.
5180 * @refcount: Number of trap items using the group.
5181 * @list: trap_group_list member.
5182 * @stats: Trap group statistics.
5183 *
5184 * Describes packet trap group attributes. Created by devlink during trap
5185 * registration.
5186 */
5187struct devlink_trap_group_item {
5188 const struct devlink_trap_group *group;
5189 refcount_t refcount;
5190 struct list_head list;
5191 struct devlink_stats __percpu *stats;
5192};
5193
5194/**
5195 * struct devlink_trap_item - Packet trap attributes.
5196 * @trap: Immutable packet trap attributes.
5197 * @group_item: Associated group item.
5198 * @list: trap_list member.
5199 * @action: Trap action.
5200 * @stats: Trap statistics.
5201 * @priv: Driver private information.
5202 *
5203 * Describes both mutable and immutable packet trap attributes. Created by
5204 * devlink during trap registration and used for all trap related operations.
5205 */
5206struct devlink_trap_item {
5207 const struct devlink_trap *trap;
5208 struct devlink_trap_group_item *group_item;
5209 struct list_head list;
5210 enum devlink_trap_action action;
5211 struct devlink_stats __percpu *stats;
5212 void *priv;
5213};
5214
5215static struct devlink_trap_item *
5216devlink_trap_item_lookup(struct devlink *devlink, const char *name)
5217{
5218 struct devlink_trap_item *trap_item;
5219
5220 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5221 if (!strcmp(trap_item->trap->name, name))
5222 return trap_item;
5223 }
5224
5225 return NULL;
5226}
5227
5228static struct devlink_trap_item *
5229devlink_trap_item_get_from_info(struct devlink *devlink,
5230 struct genl_info *info)
5231{
5232 struct nlattr *attr;
5233
5234 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
5235 return NULL;
5236 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
5237
5238 return devlink_trap_item_lookup(devlink, nla_data(attr));
5239}
5240
5241static int
5242devlink_trap_action_get_from_info(struct genl_info *info,
5243 enum devlink_trap_action *p_trap_action)
5244{
5245 u8 val;
5246
5247 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
5248 switch (val) {
5249 case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
5250 case DEVLINK_TRAP_ACTION_TRAP:
5251 *p_trap_action = val;
5252 break;
5253 default:
5254 return -EINVAL;
5255 }
5256
5257 return 0;
5258}
5259
5260static int devlink_trap_metadata_put(struct sk_buff *msg,
5261 const struct devlink_trap *trap)
5262{
5263 struct nlattr *attr;
5264
5265 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
5266 if (!attr)
5267 return -EMSGSIZE;
5268
5269 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
5270 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
5271 goto nla_put_failure;
5272
5273 nla_nest_end(msg, attr);
5274
5275 return 0;
5276
5277nla_put_failure:
5278 nla_nest_cancel(msg, attr);
5279 return -EMSGSIZE;
5280}
5281
5282static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
5283 struct devlink_stats *stats)
5284{
5285 int i;
5286
5287 memset(stats, 0, sizeof(*stats));
5288 for_each_possible_cpu(i) {
5289 struct devlink_stats *cpu_stats;
5290 u64 rx_packets, rx_bytes;
5291 unsigned int start;
5292
5293 cpu_stats = per_cpu_ptr(trap_stats, i);
5294 do {
5295 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
5296 rx_packets = cpu_stats->rx_packets;
5297 rx_bytes = cpu_stats->rx_bytes;
5298 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
5299
5300 stats->rx_packets += rx_packets;
5301 stats->rx_bytes += rx_bytes;
5302 }
5303}
5304
5305static int devlink_trap_stats_put(struct sk_buff *msg,
5306 struct devlink_stats __percpu *trap_stats)
5307{
5308 struct devlink_stats stats;
5309 struct nlattr *attr;
5310
5311 devlink_trap_stats_read(trap_stats, &stats);
5312
5313 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
5314 if (!attr)
5315 return -EMSGSIZE;
5316
5317 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
5318 stats.rx_packets, DEVLINK_ATTR_PAD))
5319 goto nla_put_failure;
5320
5321 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
5322 stats.rx_bytes, DEVLINK_ATTR_PAD))
5323 goto nla_put_failure;
5324
5325 nla_nest_end(msg, attr);
5326
5327 return 0;
5328
5329nla_put_failure:
5330 nla_nest_cancel(msg, attr);
5331 return -EMSGSIZE;
5332}
5333
5334static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
5335 const struct devlink_trap_item *trap_item,
5336 enum devlink_command cmd, u32 portid, u32 seq,
5337 int flags)
5338{
5339 struct devlink_trap_group_item *group_item = trap_item->group_item;
5340 void *hdr;
5341 int err;
5342
5343 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5344 if (!hdr)
5345 return -EMSGSIZE;
5346
5347 if (devlink_nl_put_handle(msg, devlink))
5348 goto nla_put_failure;
5349
5350 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
5351 group_item->group->name))
5352 goto nla_put_failure;
5353
5354 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
5355 goto nla_put_failure;
5356
5357 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
5358 goto nla_put_failure;
5359
5360 if (trap_item->trap->generic &&
5361 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
5362 goto nla_put_failure;
5363
5364 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
5365 goto nla_put_failure;
5366
5367 err = devlink_trap_metadata_put(msg, trap_item->trap);
5368 if (err)
5369 goto nla_put_failure;
5370
5371 err = devlink_trap_stats_put(msg, trap_item->stats);
5372 if (err)
5373 goto nla_put_failure;
5374
5375 genlmsg_end(msg, hdr);
5376
5377 return 0;
5378
5379nla_put_failure:
5380 genlmsg_cancel(msg, hdr);
5381 return -EMSGSIZE;
5382}
5383
5384static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
5385 struct genl_info *info)
5386{
5387 struct netlink_ext_ack *extack = info->extack;
5388 struct devlink *devlink = info->user_ptr[0];
5389 struct devlink_trap_item *trap_item;
5390 struct sk_buff *msg;
5391 int err;
5392
5393 if (list_empty(&devlink->trap_list))
5394 return -EOPNOTSUPP;
5395
5396 trap_item = devlink_trap_item_get_from_info(devlink, info);
5397 if (!trap_item) {
5398 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
5399 return -ENOENT;
5400 }
5401
5402 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5403 if (!msg)
5404 return -ENOMEM;
5405
5406 err = devlink_nl_trap_fill(msg, devlink, trap_item,
5407 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
5408 info->snd_seq, 0);
5409 if (err)
5410 goto err_trap_fill;
5411
5412 return genlmsg_reply(msg, info);
5413
5414err_trap_fill:
5415 nlmsg_free(msg);
5416 return err;
5417}
5418
5419static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
5420 struct netlink_callback *cb)
5421{
5422 struct devlink_trap_item *trap_item;
5423 struct devlink *devlink;
5424 int start = cb->args[0];
5425 int idx = 0;
5426 int err;
5427
5428 mutex_lock(&devlink_mutex);
5429 list_for_each_entry(devlink, &devlink_list, list) {
5430 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5431 continue;
5432 mutex_lock(&devlink->lock);
5433 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5434 if (idx < start) {
5435 idx++;
5436 continue;
5437 }
5438 err = devlink_nl_trap_fill(msg, devlink, trap_item,
5439 DEVLINK_CMD_TRAP_NEW,
5440 NETLINK_CB(cb->skb).portid,
5441 cb->nlh->nlmsg_seq,
5442 NLM_F_MULTI);
5443 if (err) {
5444 mutex_unlock(&devlink->lock);
5445 goto out;
5446 }
5447 idx++;
5448 }
5449 mutex_unlock(&devlink->lock);
5450 }
5451out:
5452 mutex_unlock(&devlink_mutex);
5453
5454 cb->args[0] = idx;
5455 return msg->len;
5456}
5457
5458static int __devlink_trap_action_set(struct devlink *devlink,
5459 struct devlink_trap_item *trap_item,
5460 enum devlink_trap_action trap_action,
5461 struct netlink_ext_ack *extack)
5462{
5463 int err;
5464
5465 if (trap_item->action != trap_action &&
5466 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
5467 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
5468 return 0;
5469 }
5470
5471 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
5472 trap_action);
5473 if (err)
5474 return err;
5475
5476 trap_item->action = trap_action;
5477
5478 return 0;
5479}
5480
5481static int devlink_trap_action_set(struct devlink *devlink,
5482 struct devlink_trap_item *trap_item,
5483 struct genl_info *info)
5484{
5485 enum devlink_trap_action trap_action;
5486 int err;
5487
5488 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
5489 return 0;
5490
5491 err = devlink_trap_action_get_from_info(info, &trap_action);
5492 if (err) {
5493 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
5494 return -EINVAL;
5495 }
5496
5497 return __devlink_trap_action_set(devlink, trap_item, trap_action,
5498 info->extack);
5499}
5500
5501static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
5502 struct genl_info *info)
5503{
5504 struct netlink_ext_ack *extack = info->extack;
5505 struct devlink *devlink = info->user_ptr[0];
5506 struct devlink_trap_item *trap_item;
5507 int err;
5508
5509 if (list_empty(&devlink->trap_list))
5510 return -EOPNOTSUPP;
5511
5512 trap_item = devlink_trap_item_get_from_info(devlink, info);
5513 if (!trap_item) {
5514 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
5515 return -ENOENT;
5516 }
5517
5518 err = devlink_trap_action_set(devlink, trap_item, info);
5519 if (err)
5520 return err;
5521
5522 return 0;
5523}
5524
5525static struct devlink_trap_group_item *
5526devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
5527{
5528 struct devlink_trap_group_item *group_item;
5529
5530 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
5531 if (!strcmp(group_item->group->name, name))
5532 return group_item;
5533 }
5534
5535 return NULL;
5536}
5537
5538static struct devlink_trap_group_item *
5539devlink_trap_group_item_get_from_info(struct devlink *devlink,
5540 struct genl_info *info)
5541{
5542 char *name;
5543
5544 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
5545 return NULL;
5546 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
5547
5548 return devlink_trap_group_item_lookup(devlink, name);
5549}
5550
5551static int
5552devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
5553 const struct devlink_trap_group_item *group_item,
5554 enum devlink_command cmd, u32 portid, u32 seq,
5555 int flags)
5556{
5557 void *hdr;
5558 int err;
5559
5560 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5561 if (!hdr)
5562 return -EMSGSIZE;
5563
5564 if (devlink_nl_put_handle(msg, devlink))
5565 goto nla_put_failure;
5566
5567 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
5568 group_item->group->name))
5569 goto nla_put_failure;
5570
5571 if (group_item->group->generic &&
5572 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
5573 goto nla_put_failure;
5574
5575 err = devlink_trap_stats_put(msg, group_item->stats);
5576 if (err)
5577 goto nla_put_failure;
5578
5579 genlmsg_end(msg, hdr);
5580
5581 return 0;
5582
5583nla_put_failure:
5584 genlmsg_cancel(msg, hdr);
5585 return -EMSGSIZE;
5586}
5587
5588static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
5589 struct genl_info *info)
5590{
5591 struct netlink_ext_ack *extack = info->extack;
5592 struct devlink *devlink = info->user_ptr[0];
5593 struct devlink_trap_group_item *group_item;
5594 struct sk_buff *msg;
5595 int err;
5596
5597 if (list_empty(&devlink->trap_group_list))
5598 return -EOPNOTSUPP;
5599
5600 group_item = devlink_trap_group_item_get_from_info(devlink, info);
5601 if (!group_item) {
5602 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
5603 return -ENOENT;
5604 }
5605
5606 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5607 if (!msg)
5608 return -ENOMEM;
5609
5610 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
5611 DEVLINK_CMD_TRAP_GROUP_NEW,
5612 info->snd_portid, info->snd_seq, 0);
5613 if (err)
5614 goto err_trap_group_fill;
5615
5616 return genlmsg_reply(msg, info);
5617
5618err_trap_group_fill:
5619 nlmsg_free(msg);
5620 return err;
5621}
5622
5623static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
5624 struct netlink_callback *cb)
5625{
5626 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
5627 struct devlink_trap_group_item *group_item;
5628 u32 portid = NETLINK_CB(cb->skb).portid;
5629 struct devlink *devlink;
5630 int start = cb->args[0];
5631 int idx = 0;
5632 int err;
5633
5634 mutex_lock(&devlink_mutex);
5635 list_for_each_entry(devlink, &devlink_list, list) {
5636 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5637 continue;
5638 mutex_lock(&devlink->lock);
5639 list_for_each_entry(group_item, &devlink->trap_group_list,
5640 list) {
5641 if (idx < start) {
5642 idx++;
5643 continue;
5644 }
5645 err = devlink_nl_trap_group_fill(msg, devlink,
5646 group_item, cmd,
5647 portid,
5648 cb->nlh->nlmsg_seq,
5649 NLM_F_MULTI);
5650 if (err) {
5651 mutex_unlock(&devlink->lock);
5652 goto out;
5653 }
5654 idx++;
5655 }
5656 mutex_unlock(&devlink->lock);
5657 }
5658out:
5659 mutex_unlock(&devlink_mutex);
5660
5661 cb->args[0] = idx;
5662 return msg->len;
5663}
5664
5665static int
5666__devlink_trap_group_action_set(struct devlink *devlink,
5667 struct devlink_trap_group_item *group_item,
5668 enum devlink_trap_action trap_action,
5669 struct netlink_ext_ack *extack)
5670{
5671 const char *group_name = group_item->group->name;
5672 struct devlink_trap_item *trap_item;
5673 int err;
5674
5675 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5676 if (strcmp(trap_item->trap->group.name, group_name))
5677 continue;
5678 err = __devlink_trap_action_set(devlink, trap_item,
5679 trap_action, extack);
5680 if (err)
5681 return err;
5682 }
5683
5684 return 0;
5685}
5686
5687static int
5688devlink_trap_group_action_set(struct devlink *devlink,
5689 struct devlink_trap_group_item *group_item,
5690 struct genl_info *info)
5691{
5692 enum devlink_trap_action trap_action;
5693 int err;
5694
5695 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
5696 return 0;
5697
5698 err = devlink_trap_action_get_from_info(info, &trap_action);
5699 if (err) {
5700 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
5701 return -EINVAL;
5702 }
5703
5704 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
5705 info->extack);
5706 if (err)
5707 return err;
5708
5709 return 0;
5710}
5711
5712static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
5713 struct genl_info *info)
5714{
5715 struct netlink_ext_ack *extack = info->extack;
5716 struct devlink *devlink = info->user_ptr[0];
5717 struct devlink_trap_group_item *group_item;
5718 int err;
5719
5720 if (list_empty(&devlink->trap_group_list))
5721 return -EOPNOTSUPP;
5722
5723 group_item = devlink_trap_group_item_get_from_info(devlink, info);
5724 if (!group_item) {
5725 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
5726 return -ENOENT;
5727 }
5728
5729 err = devlink_trap_group_action_set(devlink, group_item, info);
5730 if (err)
5731 return err;
5732
5733 return 0;
5734}
5735
bfcd3a46
JP
5736static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
5737 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
5738 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
5739 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
5740 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
5741 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
bf797471
JP
5742 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
5743 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
5744 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
5745 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
5746 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
5747 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
5748 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
08f4b591 5749 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
59bfde01 5750 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
f43e9b06 5751 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
1555d204
AS
5752 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
5753 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
d9f9b9a4
AS
5754 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
5755 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
e3b7ca18
MS
5756 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
5757 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
5758 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
d8db7ea5 5759 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
866319bb 5760 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
7afe335a 5761 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
a1e55ec0
EBE
5762 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
5763 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
76726ccb
JK
5764 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
5765 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
0f420b6c
IS
5766 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
5767 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
5768 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
bfcd3a46
JP
5769};
5770
5771static const struct genl_ops devlink_nl_ops[] = {
5772 {
5773 .cmd = DEVLINK_CMD_GET,
ef6243ac 5774 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46
JP
5775 .doit = devlink_nl_cmd_get_doit,
5776 .dumpit = devlink_nl_cmd_get_dumpit,
1fc2257e 5777 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
bfcd3a46
JP
5778 /* can be retrieved by unprivileged users */
5779 },
5780 {
5781 .cmd = DEVLINK_CMD_PORT_GET,
ef6243ac 5782 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46
JP
5783 .doit = devlink_nl_cmd_port_get_doit,
5784 .dumpit = devlink_nl_cmd_port_get_dumpit,
bfcd3a46
JP
5785 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5786 /* can be retrieved by unprivileged users */
5787 },
5788 {
5789 .cmd = DEVLINK_CMD_PORT_SET,
ef6243ac 5790 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46 5791 .doit = devlink_nl_cmd_port_set_doit,
bfcd3a46
JP
5792 .flags = GENL_ADMIN_PERM,
5793 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5794 },
5795 {
5796 .cmd = DEVLINK_CMD_PORT_SPLIT,
ef6243ac 5797 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46 5798 .doit = devlink_nl_cmd_port_split_doit,
bfcd3a46 5799 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
5800 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5801 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46
JP
5802 },
5803 {
5804 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
ef6243ac 5805 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bfcd3a46 5806 .doit = devlink_nl_cmd_port_unsplit_doit,
bfcd3a46 5807 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
5808 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5809 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46 5810 },
bf797471
JP
5811 {
5812 .cmd = DEVLINK_CMD_SB_GET,
ef6243ac 5813 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471
JP
5814 .doit = devlink_nl_cmd_sb_get_doit,
5815 .dumpit = devlink_nl_cmd_sb_get_dumpit,
bf797471
JP
5816 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5817 DEVLINK_NL_FLAG_NEED_SB,
5818 /* can be retrieved by unprivileged users */
5819 },
5820 {
5821 .cmd = DEVLINK_CMD_SB_POOL_GET,
ef6243ac 5822 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471
JP
5823 .doit = devlink_nl_cmd_sb_pool_get_doit,
5824 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
bf797471
JP
5825 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5826 DEVLINK_NL_FLAG_NEED_SB,
5827 /* can be retrieved by unprivileged users */
5828 },
5829 {
5830 .cmd = DEVLINK_CMD_SB_POOL_SET,
ef6243ac 5831 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471 5832 .doit = devlink_nl_cmd_sb_pool_set_doit,
bf797471
JP
5833 .flags = GENL_ADMIN_PERM,
5834 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5835 DEVLINK_NL_FLAG_NEED_SB,
5836 },
5837 {
5838 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
ef6243ac 5839 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471
JP
5840 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
5841 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
bf797471
JP
5842 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5843 DEVLINK_NL_FLAG_NEED_SB,
5844 /* can be retrieved by unprivileged users */
5845 },
5846 {
5847 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
ef6243ac 5848 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471 5849 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
bf797471
JP
5850 .flags = GENL_ADMIN_PERM,
5851 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5852 DEVLINK_NL_FLAG_NEED_SB,
5853 },
5854 {
5855 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
ef6243ac 5856 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471
JP
5857 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
5858 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
bf797471
JP
5859 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5860 DEVLINK_NL_FLAG_NEED_SB,
5861 /* can be retrieved by unprivileged users */
5862 },
5863 {
5864 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
ef6243ac 5865 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
bf797471 5866 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
bf797471
JP
5867 .flags = GENL_ADMIN_PERM,
5868 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5869 DEVLINK_NL_FLAG_NEED_SB,
5870 },
df38dafd
JP
5871 {
5872 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
ef6243ac 5873 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
df38dafd 5874 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
df38dafd
JP
5875 .flags = GENL_ADMIN_PERM,
5876 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 5877 DEVLINK_NL_FLAG_NEED_SB,
df38dafd
JP
5878 },
5879 {
5880 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
ef6243ac 5881 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
df38dafd 5882 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
df38dafd
JP
5883 .flags = GENL_ADMIN_PERM,
5884 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 5885 DEVLINK_NL_FLAG_NEED_SB,
df38dafd 5886 },
08f4b591 5887 {
adf200f3 5888 .cmd = DEVLINK_CMD_ESWITCH_GET,
ef6243ac 5889 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
adf200f3 5890 .doit = devlink_nl_cmd_eswitch_get_doit,
08f4b591
OG
5891 .flags = GENL_ADMIN_PERM,
5892 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5893 },
5894 {
adf200f3 5895 .cmd = DEVLINK_CMD_ESWITCH_SET,
ef6243ac 5896 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
adf200f3 5897 .doit = devlink_nl_cmd_eswitch_set_doit,
08f4b591 5898 .flags = GENL_ADMIN_PERM,
7ac1cc9a
JK
5899 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5900 DEVLINK_NL_FLAG_NO_LOCK,
08f4b591 5901 },
1555d204
AS
5902 {
5903 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
ef6243ac 5904 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1555d204 5905 .doit = devlink_nl_cmd_dpipe_table_get,
1555d204 5906 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5907 /* can be retrieved by unprivileged users */
1555d204
AS
5908 },
5909 {
5910 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
ef6243ac 5911 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1555d204 5912 .doit = devlink_nl_cmd_dpipe_entries_get,
1555d204 5913 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5914 /* can be retrieved by unprivileged users */
1555d204
AS
5915 },
5916 {
5917 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
ef6243ac 5918 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1555d204 5919 .doit = devlink_nl_cmd_dpipe_headers_get,
1555d204 5920 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5921 /* can be retrieved by unprivileged users */
1555d204
AS
5922 },
5923 {
5924 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
ef6243ac 5925 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1555d204 5926 .doit = devlink_nl_cmd_dpipe_table_counters_set,
1555d204
AS
5927 .flags = GENL_ADMIN_PERM,
5928 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5929 },
d9f9b9a4
AS
5930 {
5931 .cmd = DEVLINK_CMD_RESOURCE_SET,
ef6243ac 5932 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
d9f9b9a4 5933 .doit = devlink_nl_cmd_resource_set,
d9f9b9a4
AS
5934 .flags = GENL_ADMIN_PERM,
5935 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5936 },
5937 {
5938 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
ef6243ac 5939 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
d9f9b9a4 5940 .doit = devlink_nl_cmd_resource_dump,
d9f9b9a4 5941 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5942 /* can be retrieved by unprivileged users */
d9f9b9a4 5943 },
2d8dc5bb
AS
5944 {
5945 .cmd = DEVLINK_CMD_RELOAD,
ef6243ac 5946 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
2d8dc5bb 5947 .doit = devlink_nl_cmd_reload,
2d8dc5bb
AS
5948 .flags = GENL_ADMIN_PERM,
5949 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5950 DEVLINK_NL_FLAG_NO_LOCK,
5951 },
45f05def
MS
5952 {
5953 .cmd = DEVLINK_CMD_PARAM_GET,
ef6243ac 5954 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
45f05def
MS
5955 .doit = devlink_nl_cmd_param_get_doit,
5956 .dumpit = devlink_nl_cmd_param_get_dumpit,
45f05def
MS
5957 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5958 /* can be retrieved by unprivileged users */
5959 },
e3b7ca18
MS
5960 {
5961 .cmd = DEVLINK_CMD_PARAM_SET,
ef6243ac 5962 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
e3b7ca18 5963 .doit = devlink_nl_cmd_param_set_doit,
e3b7ca18
MS
5964 .flags = GENL_ADMIN_PERM,
5965 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5966 },
f4601dee
VV
5967 {
5968 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
ef6243ac 5969 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
f4601dee
VV
5970 .doit = devlink_nl_cmd_port_param_get_doit,
5971 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
f4601dee
VV
5972 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5973 /* can be retrieved by unprivileged users */
5974 },
9c54873b
VV
5975 {
5976 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
ef6243ac 5977 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
9c54873b 5978 .doit = devlink_nl_cmd_port_param_set_doit,
9c54873b
VV
5979 .flags = GENL_ADMIN_PERM,
5980 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5981 },
d8db7ea5
AV
5982 {
5983 .cmd = DEVLINK_CMD_REGION_GET,
ef6243ac 5984 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
d8db7ea5
AV
5985 .doit = devlink_nl_cmd_region_get_doit,
5986 .dumpit = devlink_nl_cmd_region_get_dumpit,
d8db7ea5
AV
5987 .flags = GENL_ADMIN_PERM,
5988 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5989 },
866319bb
AV
5990 {
5991 .cmd = DEVLINK_CMD_REGION_DEL,
ef6243ac 5992 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
866319bb 5993 .doit = devlink_nl_cmd_region_del,
866319bb
AV
5994 .flags = GENL_ADMIN_PERM,
5995 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5996 },
4e54795a
AV
5997 {
5998 .cmd = DEVLINK_CMD_REGION_READ,
ef6243ac 5999 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
4e54795a 6000 .dumpit = devlink_nl_cmd_region_read_dumpit,
4e54795a
AV
6001 .flags = GENL_ADMIN_PERM,
6002 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6003 },
f9cf2288
JK
6004 {
6005 .cmd = DEVLINK_CMD_INFO_GET,
ef6243ac 6006 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
f9cf2288
JK
6007 .doit = devlink_nl_cmd_info_get_doit,
6008 .dumpit = devlink_nl_cmd_info_get_dumpit,
f9cf2288
JK
6009 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6010 /* can be retrieved by unprivileged users */
6011 },
7afe335a
EBE
6012 {
6013 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
ef6243ac 6014 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7afe335a
EBE
6015 .doit = devlink_nl_cmd_health_reporter_get_doit,
6016 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
b587bdaf
MS
6017 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6018 DEVLINK_NL_FLAG_NO_LOCK,
7afe335a
EBE
6019 /* can be retrieved by unprivileged users */
6020 },
a1e55ec0
EBE
6021 {
6022 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
ef6243ac 6023 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
a1e55ec0 6024 .doit = devlink_nl_cmd_health_reporter_set_doit,
a1e55ec0 6025 .flags = GENL_ADMIN_PERM,
b587bdaf
MS
6026 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6027 DEVLINK_NL_FLAG_NO_LOCK,
a1e55ec0 6028 },
20a0943a
EBE
6029 {
6030 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
ef6243ac 6031 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
20a0943a 6032 .doit = devlink_nl_cmd_health_reporter_recover_doit,
20a0943a 6033 .flags = GENL_ADMIN_PERM,
b587bdaf
MS
6034 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6035 DEVLINK_NL_FLAG_NO_LOCK,
20a0943a 6036 },
fca42a27
EBE
6037 {
6038 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
ef6243ac 6039 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
fca42a27 6040 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
fca42a27 6041 .flags = GENL_ADMIN_PERM,
b587bdaf
MS
6042 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6043 DEVLINK_NL_FLAG_NO_LOCK,
fca42a27 6044 },
35455e23
EBE
6045 {
6046 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
ef6243ac 6047 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
e44ef4e4 6048 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
35455e23
EBE
6049 .flags = GENL_ADMIN_PERM,
6050 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6051 DEVLINK_NL_FLAG_NO_LOCK,
6052 },
6053 {
6054 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
ef6243ac 6055 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
35455e23 6056 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
35455e23
EBE
6057 .flags = GENL_ADMIN_PERM,
6058 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6059 DEVLINK_NL_FLAG_NO_LOCK,
6060 },
76726ccb
JK
6061 {
6062 .cmd = DEVLINK_CMD_FLASH_UPDATE,
ef6243ac 6063 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76726ccb 6064 .doit = devlink_nl_cmd_flash_update,
76726ccb
JK
6065 .flags = GENL_ADMIN_PERM,
6066 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6067 },
0f420b6c
IS
6068 {
6069 .cmd = DEVLINK_CMD_TRAP_GET,
6070 .doit = devlink_nl_cmd_trap_get_doit,
6071 .dumpit = devlink_nl_cmd_trap_get_dumpit,
6072 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6073 /* can be retrieved by unprivileged users */
6074 },
6075 {
6076 .cmd = DEVLINK_CMD_TRAP_SET,
6077 .doit = devlink_nl_cmd_trap_set_doit,
6078 .flags = GENL_ADMIN_PERM,
6079 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6080 },
6081 {
6082 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
6083 .doit = devlink_nl_cmd_trap_group_get_doit,
6084 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
6085 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6086 /* can be retrieved by unprivileged users */
6087 },
6088 {
6089 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
6090 .doit = devlink_nl_cmd_trap_group_set_doit,
6091 .flags = GENL_ADMIN_PERM,
6092 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6093 },
bfcd3a46
JP
6094};
6095
56989f6d 6096static struct genl_family devlink_nl_family __ro_after_init = {
489111e5
JB
6097 .name = DEVLINK_GENL_NAME,
6098 .version = DEVLINK_GENL_VERSION,
6099 .maxattr = DEVLINK_ATTR_MAX,
3b0f31f2 6100 .policy = devlink_nl_policy,
489111e5
JB
6101 .netnsok = true,
6102 .pre_doit = devlink_nl_pre_doit,
6103 .post_doit = devlink_nl_post_doit,
6104 .module = THIS_MODULE,
6105 .ops = devlink_nl_ops,
6106 .n_ops = ARRAY_SIZE(devlink_nl_ops),
6107 .mcgrps = devlink_nl_mcgrps,
6108 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
6109};
6110
bfcd3a46
JP
6111/**
6112 * devlink_alloc - Allocate new devlink instance resources
6113 *
6114 * @ops: ops
6115 * @priv_size: size of user private data
6116 *
6117 * Allocate new devlink instance resources, including devlink index
6118 * and name.
6119 */
6120struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
6121{
6122 struct devlink *devlink;
6123
be6fe1d8
JK
6124 if (WARN_ON(!ops))
6125 return NULL;
6126
bfcd3a46
JP
6127 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
6128 if (!devlink)
6129 return NULL;
6130 devlink->ops = ops;
6131 devlink_net_set(devlink, &init_net);
6132 INIT_LIST_HEAD(&devlink->port_list);
bf797471 6133 INIT_LIST_HEAD(&devlink->sb_list);
1555d204 6134 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
d9f9b9a4 6135 INIT_LIST_HEAD(&devlink->resource_list);
eabaef18 6136 INIT_LIST_HEAD(&devlink->param_list);
b16ebe92 6137 INIT_LIST_HEAD(&devlink->region_list);
a0bdcc59 6138 INIT_LIST_HEAD(&devlink->reporter_list);
0f420b6c
IS
6139 INIT_LIST_HEAD(&devlink->trap_list);
6140 INIT_LIST_HEAD(&devlink->trap_group_list);
2406e7e5 6141 mutex_init(&devlink->lock);
b587bdaf 6142 mutex_init(&devlink->reporters_lock);
bfcd3a46
JP
6143 return devlink;
6144}
6145EXPORT_SYMBOL_GPL(devlink_alloc);
6146
6147/**
6148 * devlink_register - Register devlink instance
6149 *
6150 * @devlink: devlink
eeaadd82 6151 * @dev: parent device
bfcd3a46
JP
6152 */
6153int devlink_register(struct devlink *devlink, struct device *dev)
6154{
6155 mutex_lock(&devlink_mutex);
6156 devlink->dev = dev;
6157 list_add_tail(&devlink->list, &devlink_list);
6158 devlink_notify(devlink, DEVLINK_CMD_NEW);
6159 mutex_unlock(&devlink_mutex);
6160 return 0;
6161}
6162EXPORT_SYMBOL_GPL(devlink_register);
6163
6164/**
6165 * devlink_unregister - Unregister devlink instance
6166 *
6167 * @devlink: devlink
6168 */
6169void devlink_unregister(struct devlink *devlink)
6170{
6171 mutex_lock(&devlink_mutex);
6172 devlink_notify(devlink, DEVLINK_CMD_DEL);
6173 list_del(&devlink->list);
6174 mutex_unlock(&devlink_mutex);
6175}
6176EXPORT_SYMBOL_GPL(devlink_unregister);
6177
6178/**
6179 * devlink_free - Free devlink instance resources
6180 *
6181 * @devlink: devlink
6182 */
6183void devlink_free(struct devlink *devlink)
6184{
b587bdaf 6185 mutex_destroy(&devlink->reporters_lock);
375cf8c6 6186 mutex_destroy(&devlink->lock);
0f420b6c
IS
6187 WARN_ON(!list_empty(&devlink->trap_group_list));
6188 WARN_ON(!list_empty(&devlink->trap_list));
b904aada
PP
6189 WARN_ON(!list_empty(&devlink->reporter_list));
6190 WARN_ON(!list_empty(&devlink->region_list));
6191 WARN_ON(!list_empty(&devlink->param_list));
6192 WARN_ON(!list_empty(&devlink->resource_list));
6193 WARN_ON(!list_empty(&devlink->dpipe_table_list));
6194 WARN_ON(!list_empty(&devlink->sb_list));
6195 WARN_ON(!list_empty(&devlink->port_list));
6196
bfcd3a46
JP
6197 kfree(devlink);
6198}
6199EXPORT_SYMBOL_GPL(devlink_free);
6200
136bf27f
JP
6201static void devlink_port_type_warn(struct work_struct *work)
6202{
6203 WARN(true, "Type was not set for devlink port.");
6204}
6205
6206static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
6207{
6208 /* Ignore CPU and DSA flavours. */
6209 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
6210 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
6211}
6212
6213#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 30)
6214
6215static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
6216{
6217 if (!devlink_port_type_should_warn(devlink_port))
6218 return;
6219 /* Schedule a work to WARN in case driver does not set port
6220 * type within timeout.
6221 */
6222 schedule_delayed_work(&devlink_port->type_warn_dw,
6223 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
6224}
6225
6226static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
6227{
6228 if (!devlink_port_type_should_warn(devlink_port))
6229 return;
6230 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
6231}
6232
bfcd3a46
JP
6233/**
6234 * devlink_port_register - Register devlink port
6235 *
6236 * @devlink: devlink
6237 * @devlink_port: devlink port
eeaadd82 6238 * @port_index: driver-specific numerical identifier of the port
bfcd3a46
JP
6239 *
6240 * Register devlink port with provided port index. User can use
6241 * any indexing, even hw-related one. devlink_port structure
6242 * is convenient to be embedded inside user driver private structure.
6243 * Note that the caller should take care of zeroing the devlink_port
6244 * structure.
6245 */
6246int devlink_port_register(struct devlink *devlink,
6247 struct devlink_port *devlink_port,
6248 unsigned int port_index)
6249{
2406e7e5 6250 mutex_lock(&devlink->lock);
bfcd3a46 6251 if (devlink_port_index_exists(devlink, port_index)) {
2406e7e5 6252 mutex_unlock(&devlink->lock);
bfcd3a46
JP
6253 return -EEXIST;
6254 }
6255 devlink_port->devlink = devlink;
6256 devlink_port->index = port_index;
bfcd3a46 6257 devlink_port->registered = true;
b8f97554 6258 spin_lock_init(&devlink_port->type_lock);
bfcd3a46 6259 list_add_tail(&devlink_port->list, &devlink->port_list);
39e6160e 6260 INIT_LIST_HEAD(&devlink_port->param_list);
2406e7e5 6261 mutex_unlock(&devlink->lock);
136bf27f
JP
6262 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
6263 devlink_port_type_warn_schedule(devlink_port);
bfcd3a46
JP
6264 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
6265 return 0;
6266}
6267EXPORT_SYMBOL_GPL(devlink_port_register);
6268
6269/**
6270 * devlink_port_unregister - Unregister devlink port
6271 *
6272 * @devlink_port: devlink port
6273 */
6274void devlink_port_unregister(struct devlink_port *devlink_port)
6275{
2406e7e5
AS
6276 struct devlink *devlink = devlink_port->devlink;
6277
136bf27f 6278 devlink_port_type_warn_cancel(devlink_port);
bfcd3a46 6279 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
2406e7e5 6280 mutex_lock(&devlink->lock);
bfcd3a46 6281 list_del(&devlink_port->list);
2406e7e5 6282 mutex_unlock(&devlink->lock);
bfcd3a46
JP
6283}
6284EXPORT_SYMBOL_GPL(devlink_port_unregister);
6285
6286static void __devlink_port_type_set(struct devlink_port *devlink_port,
6287 enum devlink_port_type type,
6288 void *type_dev)
6289{
2b239e70
JP
6290 if (WARN_ON(!devlink_port->registered))
6291 return;
136bf27f 6292 devlink_port_type_warn_cancel(devlink_port);
0f420b6c 6293 spin_lock_bh(&devlink_port->type_lock);
bfcd3a46
JP
6294 devlink_port->type = type;
6295 devlink_port->type_dev = type_dev;
0f420b6c 6296 spin_unlock_bh(&devlink_port->type_lock);
bfcd3a46
JP
6297 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
6298}
6299
6300/**
6301 * devlink_port_type_eth_set - Set port type to Ethernet
6302 *
6303 * @devlink_port: devlink port
6304 * @netdev: related netdevice
6305 */
6306void devlink_port_type_eth_set(struct devlink_port *devlink_port,
6307 struct net_device *netdev)
6308{
119c0b57
JP
6309 const struct net_device_ops *ops = netdev->netdev_ops;
6310
746364f2
JP
6311 /* If driver registers devlink port, it should set devlink port
6312 * attributes accordingly so the compat functions are called
6313 * and the original ops are not used.
6314 */
119c0b57 6315 if (ops->ndo_get_phys_port_name) {
746364f2
JP
6316 /* Some drivers use the same set of ndos for netdevs
6317 * that have devlink_port registered and also for
6318 * those who don't. Make sure that ndo_get_phys_port_name
6319 * returns -EOPNOTSUPP here in case it is defined.
6320 * Warn if not.
6321 */
746364f2
JP
6322 char name[IFNAMSIZ];
6323 int err;
6324
6325 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
6326 WARN_ON(err != -EOPNOTSUPP);
6327 }
119c0b57
JP
6328 if (ops->ndo_get_port_parent_id) {
6329 /* Some drivers use the same set of ndos for netdevs
6330 * that have devlink_port registered and also for
6331 * those who don't. Make sure that ndo_get_port_parent_id
6332 * returns -EOPNOTSUPP here in case it is defined.
6333 * Warn if not.
6334 */
6335 struct netdev_phys_item_id ppid;
6336 int err;
6337
6338 err = ops->ndo_get_port_parent_id(netdev, &ppid);
6339 WARN_ON(err != -EOPNOTSUPP);
6340 }
773b1f38 6341 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
bfcd3a46
JP
6342}
6343EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
6344
6345/**
6346 * devlink_port_type_ib_set - Set port type to InfiniBand
6347 *
6348 * @devlink_port: devlink port
6349 * @ibdev: related IB device
6350 */
6351void devlink_port_type_ib_set(struct devlink_port *devlink_port,
6352 struct ib_device *ibdev)
6353{
773b1f38 6354 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
bfcd3a46
JP
6355}
6356EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
6357
6358/**
6359 * devlink_port_type_clear - Clear port type
6360 *
6361 * @devlink_port: devlink port
6362 */
6363void devlink_port_type_clear(struct devlink_port *devlink_port)
6364{
773b1f38 6365 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
136bf27f 6366 devlink_port_type_warn_schedule(devlink_port);
bfcd3a46
JP
6367}
6368EXPORT_SYMBOL_GPL(devlink_port_type_clear);
6369
378ef01b
PP
6370static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
6371 enum devlink_port_flavour flavour,
6372 const unsigned char *switch_id,
6373 unsigned char switch_id_len)
6374{
6375 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6376
6377 if (WARN_ON(devlink_port->registered))
6378 return -EEXIST;
6379 attrs->set = true;
6380 attrs->flavour = flavour;
6381 if (switch_id) {
6382 attrs->switch_port = true;
6383 if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
6384 switch_id_len = MAX_PHYS_ITEM_ID_LEN;
6385 memcpy(attrs->switch_id.id, switch_id, switch_id_len);
6386 attrs->switch_id.id_len = switch_id_len;
6387 } else {
6388 attrs->switch_port = false;
6389 }
6390 return 0;
6391}
6392
bfcd3a46 6393/**
b9ffcbaf 6394 * devlink_port_attrs_set - Set port attributes
bfcd3a46
JP
6395 *
6396 * @devlink_port: devlink port
5ec1380a 6397 * @flavour: flavour of the port
b9ffcbaf
JP
6398 * @port_number: number of the port that is facing user, for example
6399 * the front panel port number
6400 * @split: indicates if this is split port
6401 * @split_subport_number: if the port is split, this is the number
6402 * of subport.
bec5267c
JP
6403 * @switch_id: if the port is part of switch, this is buffer with ID,
6404 * otwerwise this is NULL
6405 * @switch_id_len: length of the switch_id buffer
bfcd3a46 6406 */
b9ffcbaf 6407void devlink_port_attrs_set(struct devlink_port *devlink_port,
5ec1380a 6408 enum devlink_port_flavour flavour,
b9ffcbaf 6409 u32 port_number, bool split,
bec5267c
JP
6410 u32 split_subport_number,
6411 const unsigned char *switch_id,
6412 unsigned char switch_id_len)
bfcd3a46 6413{
b9ffcbaf 6414 struct devlink_port_attrs *attrs = &devlink_port->attrs;
378ef01b 6415 int ret;
b9ffcbaf 6416
378ef01b
PP
6417 ret = __devlink_port_attrs_set(devlink_port, flavour,
6418 switch_id, switch_id_len);
6419 if (ret)
45b86112 6420 return;
b9ffcbaf 6421 attrs->split = split;
378ef01b
PP
6422 attrs->phys.port_number = port_number;
6423 attrs->phys.split_subport_number = split_subport_number;
bfcd3a46 6424}
b9ffcbaf 6425EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
bfcd3a46 6426
98fd2d65
PP
6427/**
6428 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
6429 *
6430 * @devlink_port: devlink port
6431 * @pf: associated PF for the devlink port instance
6432 * @switch_id: if the port is part of switch, this is buffer with ID,
6433 * otherwise this is NULL
6434 * @switch_id_len: length of the switch_id buffer
6435 */
6436void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port,
6437 const unsigned char *switch_id,
6438 unsigned char switch_id_len, u16 pf)
6439{
6440 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6441 int ret;
6442
6443 ret = __devlink_port_attrs_set(devlink_port,
6444 DEVLINK_PORT_FLAVOUR_PCI_PF,
6445 switch_id, switch_id_len);
6446 if (ret)
6447 return;
6448
6449 attrs->pci_pf.pf = pf;
6450}
6451EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
6452
e41b6bf3
PP
6453/**
6454 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
6455 *
6456 * @devlink_port: devlink port
6457 * @pf: associated PF for the devlink port instance
6458 * @vf: associated VF of a PF for the devlink port instance
6459 * @switch_id: if the port is part of switch, this is buffer with ID,
6460 * otherwise this is NULL
6461 * @switch_id_len: length of the switch_id buffer
6462 */
6463void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
6464 const unsigned char *switch_id,
6465 unsigned char switch_id_len,
6466 u16 pf, u16 vf)
6467{
6468 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6469 int ret;
6470
6471 ret = __devlink_port_attrs_set(devlink_port,
6472 DEVLINK_PORT_FLAVOUR_PCI_VF,
6473 switch_id, switch_id_len);
6474 if (ret)
6475 return;
6476 attrs->pci_vf.pf = pf;
6477 attrs->pci_vf.vf = vf;
6478}
6479EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
6480
af3836df
JP
6481static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
6482 char *name, size_t len)
08474c1a
JP
6483{
6484 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6485 int n = 0;
6486
6487 if (!attrs->set)
6488 return -EOPNOTSUPP;
6489
6490 switch (attrs->flavour) {
6491 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
6492 if (!attrs->split)
378ef01b 6493 n = snprintf(name, len, "p%u", attrs->phys.port_number);
08474c1a 6494 else
378ef01b
PP
6495 n = snprintf(name, len, "p%us%u",
6496 attrs->phys.port_number,
6497 attrs->phys.split_subport_number);
08474c1a
JP
6498 break;
6499 case DEVLINK_PORT_FLAVOUR_CPU:
6500 case DEVLINK_PORT_FLAVOUR_DSA:
6501 /* As CPU and DSA ports do not have a netdevice associated
6502 * case should not ever happen.
6503 */
6504 WARN_ON(1);
6505 return -EINVAL;
98fd2d65
PP
6506 case DEVLINK_PORT_FLAVOUR_PCI_PF:
6507 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
6508 break;
e41b6bf3
PP
6509 case DEVLINK_PORT_FLAVOUR_PCI_VF:
6510 n = snprintf(name, len, "pf%uvf%u",
6511 attrs->pci_vf.pf, attrs->pci_vf.vf);
6512 break;
08474c1a
JP
6513 }
6514
6515 if (n >= len)
6516 return -EINVAL;
6517
6518 return 0;
6519}
af3836df 6520
bf797471
JP
6521int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
6522 u32 size, u16 ingress_pools_count,
6523 u16 egress_pools_count, u16 ingress_tc_count,
6524 u16 egress_tc_count)
6525{
6526 struct devlink_sb *devlink_sb;
6527 int err = 0;
6528
2406e7e5 6529 mutex_lock(&devlink->lock);
bf797471
JP
6530 if (devlink_sb_index_exists(devlink, sb_index)) {
6531 err = -EEXIST;
6532 goto unlock;
6533 }
6534
6535 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
6536 if (!devlink_sb) {
6537 err = -ENOMEM;
6538 goto unlock;
6539 }
6540 devlink_sb->index = sb_index;
6541 devlink_sb->size = size;
6542 devlink_sb->ingress_pools_count = ingress_pools_count;
6543 devlink_sb->egress_pools_count = egress_pools_count;
6544 devlink_sb->ingress_tc_count = ingress_tc_count;
6545 devlink_sb->egress_tc_count = egress_tc_count;
6546 list_add_tail(&devlink_sb->list, &devlink->sb_list);
6547unlock:
2406e7e5 6548 mutex_unlock(&devlink->lock);
bf797471
JP
6549 return err;
6550}
6551EXPORT_SYMBOL_GPL(devlink_sb_register);
6552
6553void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
6554{
6555 struct devlink_sb *devlink_sb;
6556
2406e7e5 6557 mutex_lock(&devlink->lock);
bf797471
JP
6558 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
6559 WARN_ON(!devlink_sb);
6560 list_del(&devlink_sb->list);
2406e7e5 6561 mutex_unlock(&devlink->lock);
bf797471
JP
6562 kfree(devlink_sb);
6563}
6564EXPORT_SYMBOL_GPL(devlink_sb_unregister);
6565
1555d204
AS
6566/**
6567 * devlink_dpipe_headers_register - register dpipe headers
6568 *
6569 * @devlink: devlink
6570 * @dpipe_headers: dpipe header array
6571 *
6572 * Register the headers supported by hardware.
6573 */
6574int devlink_dpipe_headers_register(struct devlink *devlink,
6575 struct devlink_dpipe_headers *dpipe_headers)
6576{
2406e7e5 6577 mutex_lock(&devlink->lock);
1555d204 6578 devlink->dpipe_headers = dpipe_headers;
2406e7e5 6579 mutex_unlock(&devlink->lock);
1555d204
AS
6580 return 0;
6581}
6582EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
6583
6584/**
6585 * devlink_dpipe_headers_unregister - unregister dpipe headers
6586 *
6587 * @devlink: devlink
6588 *
6589 * Unregister the headers supported by hardware.
6590 */
6591void devlink_dpipe_headers_unregister(struct devlink *devlink)
6592{
2406e7e5 6593 mutex_lock(&devlink->lock);
1555d204 6594 devlink->dpipe_headers = NULL;
2406e7e5 6595 mutex_unlock(&devlink->lock);
1555d204
AS
6596}
6597EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
6598
6599/**
6600 * devlink_dpipe_table_counter_enabled - check if counter allocation
6601 * required
6602 * @devlink: devlink
6603 * @table_name: tables name
6604 *
6605 * Used by driver to check if counter allocation is required.
6606 * After counter allocation is turned on the table entries
6607 * are updated to include counter statistics.
6608 *
6609 * After that point on the driver must respect the counter
6610 * state so that each entry added to the table is added
6611 * with a counter.
6612 */
6613bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
6614 const char *table_name)
6615{
6616 struct devlink_dpipe_table *table;
6617 bool enabled;
6618
6619 rcu_read_lock();
6620 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6621 table_name);
6622 enabled = false;
6623 if (table)
6624 enabled = table->counters_enabled;
6625 rcu_read_unlock();
6626 return enabled;
6627}
6628EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
6629
6630/**
6631 * devlink_dpipe_table_register - register dpipe table
6632 *
6633 * @devlink: devlink
6634 * @table_name: table name
6635 * @table_ops: table ops
6636 * @priv: priv
1555d204
AS
6637 * @counter_control_extern: external control for counters
6638 */
6639int devlink_dpipe_table_register(struct devlink *devlink,
6640 const char *table_name,
6641 struct devlink_dpipe_table_ops *table_ops,
ffd3cdcc 6642 void *priv, bool counter_control_extern)
1555d204
AS
6643{
6644 struct devlink_dpipe_table *table;
6645
6646 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
6647 return -EEXIST;
6648
ffd3cdcc
AS
6649 if (WARN_ON(!table_ops->size_get))
6650 return -EINVAL;
6651
1555d204
AS
6652 table = kzalloc(sizeof(*table), GFP_KERNEL);
6653 if (!table)
6654 return -ENOMEM;
6655
6656 table->name = table_name;
6657 table->table_ops = table_ops;
6658 table->priv = priv;
1555d204
AS
6659 table->counter_control_extern = counter_control_extern;
6660
2406e7e5 6661 mutex_lock(&devlink->lock);
1555d204 6662 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
2406e7e5 6663 mutex_unlock(&devlink->lock);
1555d204
AS
6664 return 0;
6665}
6666EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
6667
6668/**
6669 * devlink_dpipe_table_unregister - unregister dpipe table
6670 *
6671 * @devlink: devlink
6672 * @table_name: table name
6673 */
6674void devlink_dpipe_table_unregister(struct devlink *devlink,
6675 const char *table_name)
6676{
6677 struct devlink_dpipe_table *table;
6678
2406e7e5 6679 mutex_lock(&devlink->lock);
1555d204
AS
6680 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6681 table_name);
6682 if (!table)
6683 goto unlock;
6684 list_del_rcu(&table->list);
2406e7e5 6685 mutex_unlock(&devlink->lock);
1555d204
AS
6686 kfree_rcu(table, rcu);
6687 return;
6688unlock:
2406e7e5 6689 mutex_unlock(&devlink->lock);
1555d204
AS
6690}
6691EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
6692
d9f9b9a4
AS
6693/**
6694 * devlink_resource_register - devlink resource register
6695 *
6696 * @devlink: devlink
6697 * @resource_name: resource's name
d9f9b9a4
AS
6698 * @resource_size: resource's size
6699 * @resource_id: resource's id
eeaadd82
JK
6700 * @parent_resource_id: resource's parent id
6701 * @size_params: size parameters
d9f9b9a4
AS
6702 */
6703int devlink_resource_register(struct devlink *devlink,
6704 const char *resource_name,
d9f9b9a4
AS
6705 u64 resource_size,
6706 u64 resource_id,
6707 u64 parent_resource_id,
fc56be47 6708 const struct devlink_resource_size_params *size_params)
d9f9b9a4
AS
6709{
6710 struct devlink_resource *resource;
6711 struct list_head *resource_list;
14530746 6712 bool top_hierarchy;
d9f9b9a4
AS
6713 int err = 0;
6714
14530746
DA
6715 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
6716
d9f9b9a4
AS
6717 mutex_lock(&devlink->lock);
6718 resource = devlink_resource_find(devlink, NULL, resource_id);
6719 if (resource) {
6720 err = -EINVAL;
6721 goto out;
6722 }
6723
6724 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
6725 if (!resource) {
6726 err = -ENOMEM;
6727 goto out;
6728 }
6729
6730 if (top_hierarchy) {
6731 resource_list = &devlink->resource_list;
6732 } else {
6733 struct devlink_resource *parent_resource;
6734
6735 parent_resource = devlink_resource_find(devlink, NULL,
6736 parent_resource_id);
6737 if (parent_resource) {
6738 resource_list = &parent_resource->resource_list;
6739 resource->parent = parent_resource;
6740 } else {
b75703de 6741 kfree(resource);
d9f9b9a4
AS
6742 err = -EINVAL;
6743 goto out;
6744 }
6745 }
6746
6747 resource->name = resource_name;
6748 resource->size = resource_size;
6749 resource->size_new = resource_size;
6750 resource->id = resource_id;
d9f9b9a4 6751 resource->size_valid = true;
77d27096
JP
6752 memcpy(&resource->size_params, size_params,
6753 sizeof(resource->size_params));
d9f9b9a4
AS
6754 INIT_LIST_HEAD(&resource->resource_list);
6755 list_add_tail(&resource->list, resource_list);
6756out:
6757 mutex_unlock(&devlink->lock);
6758 return err;
6759}
6760EXPORT_SYMBOL_GPL(devlink_resource_register);
6761
6762/**
6763 * devlink_resources_unregister - free all resources
6764 *
6765 * @devlink: devlink
6766 * @resource: resource
6767 */
6768void devlink_resources_unregister(struct devlink *devlink,
6769 struct devlink_resource *resource)
6770{
6771 struct devlink_resource *tmp, *child_resource;
6772 struct list_head *resource_list;
6773
6774 if (resource)
6775 resource_list = &resource->resource_list;
6776 else
6777 resource_list = &devlink->resource_list;
6778
6779 if (!resource)
6780 mutex_lock(&devlink->lock);
6781
6782 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
6783 devlink_resources_unregister(devlink, child_resource);
6784 list_del(&child_resource->list);
6785 kfree(child_resource);
6786 }
6787
6788 if (!resource)
6789 mutex_unlock(&devlink->lock);
6790}
6791EXPORT_SYMBOL_GPL(devlink_resources_unregister);
6792
6793/**
6794 * devlink_resource_size_get - get and update size
6795 *
6796 * @devlink: devlink
6797 * @resource_id: the requested resource id
6798 * @p_resource_size: ptr to update
6799 */
6800int devlink_resource_size_get(struct devlink *devlink,
6801 u64 resource_id,
6802 u64 *p_resource_size)
6803{
6804 struct devlink_resource *resource;
6805 int err = 0;
6806
6807 mutex_lock(&devlink->lock);
6808 resource = devlink_resource_find(devlink, NULL, resource_id);
6809 if (!resource) {
6810 err = -EINVAL;
6811 goto out;
6812 }
6813 *p_resource_size = resource->size_new;
6814 resource->size = resource->size_new;
6815out:
6816 mutex_unlock(&devlink->lock);
6817 return err;
6818}
6819EXPORT_SYMBOL_GPL(devlink_resource_size_get);
6820
56dc7cd0
AS
6821/**
6822 * devlink_dpipe_table_resource_set - set the resource id
6823 *
6824 * @devlink: devlink
6825 * @table_name: table name
6826 * @resource_id: resource id
6827 * @resource_units: number of resource's units consumed per table's entry
6828 */
6829int devlink_dpipe_table_resource_set(struct devlink *devlink,
6830 const char *table_name, u64 resource_id,
6831 u64 resource_units)
6832{
6833 struct devlink_dpipe_table *table;
6834 int err = 0;
6835
6836 mutex_lock(&devlink->lock);
6837 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6838 table_name);
6839 if (!table) {
6840 err = -EINVAL;
6841 goto out;
6842 }
6843 table->resource_id = resource_id;
6844 table->resource_units = resource_units;
6845 table->resource_valid = true;
6846out:
6847 mutex_unlock(&devlink->lock);
6848 return err;
6849}
6850EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
6851
fc56be47
JP
6852/**
6853 * devlink_resource_occ_get_register - register occupancy getter
6854 *
6855 * @devlink: devlink
6856 * @resource_id: resource id
6857 * @occ_get: occupancy getter callback
6858 * @occ_get_priv: occupancy getter callback priv
6859 */
6860void devlink_resource_occ_get_register(struct devlink *devlink,
6861 u64 resource_id,
6862 devlink_resource_occ_get_t *occ_get,
6863 void *occ_get_priv)
6864{
6865 struct devlink_resource *resource;
6866
6867 mutex_lock(&devlink->lock);
6868 resource = devlink_resource_find(devlink, NULL, resource_id);
6869 if (WARN_ON(!resource))
6870 goto out;
6871 WARN_ON(resource->occ_get);
6872
6873 resource->occ_get = occ_get;
6874 resource->occ_get_priv = occ_get_priv;
6875out:
6876 mutex_unlock(&devlink->lock);
6877}
6878EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
6879
6880/**
6881 * devlink_resource_occ_get_unregister - unregister occupancy getter
6882 *
6883 * @devlink: devlink
6884 * @resource_id: resource id
6885 */
6886void devlink_resource_occ_get_unregister(struct devlink *devlink,
6887 u64 resource_id)
6888{
6889 struct devlink_resource *resource;
6890
6891 mutex_lock(&devlink->lock);
6892 resource = devlink_resource_find(devlink, NULL, resource_id);
6893 if (WARN_ON(!resource))
6894 goto out;
6895 WARN_ON(!resource->occ_get);
6896
6897 resource->occ_get = NULL;
6898 resource->occ_get_priv = NULL;
6899out:
6900 mutex_unlock(&devlink->lock);
6901}
6902EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
6903
39e6160e
VV
6904static int devlink_param_verify(const struct devlink_param *param)
6905{
6906 if (!param || !param->name || !param->supported_cmodes)
6907 return -EINVAL;
6908 if (param->generic)
6909 return devlink_param_generic_verify(param);
6910 else
6911 return devlink_param_driver_verify(param);
6912}
6913
6914static int __devlink_params_register(struct devlink *devlink,
c1e5786d 6915 unsigned int port_index,
39e6160e
VV
6916 struct list_head *param_list,
6917 const struct devlink_param *params,
c1e5786d
VV
6918 size_t params_count,
6919 enum devlink_command reg_cmd,
6920 enum devlink_command unreg_cmd)
eabaef18
MS
6921{
6922 const struct devlink_param *param = params;
6923 int i;
6924 int err;
6925
6926 mutex_lock(&devlink->lock);
6927 for (i = 0; i < params_count; i++, param++) {
39e6160e
VV
6928 err = devlink_param_verify(param);
6929 if (err)
eabaef18 6930 goto rollback;
39e6160e 6931
c1e5786d
VV
6932 err = devlink_param_register_one(devlink, port_index,
6933 param_list, param, reg_cmd);
eabaef18
MS
6934 if (err)
6935 goto rollback;
6936 }
6937
6938 mutex_unlock(&devlink->lock);
6939 return 0;
6940
6941rollback:
6942 if (!i)
6943 goto unlock;
6944 for (param--; i > 0; i--, param--)
c1e5786d
VV
6945 devlink_param_unregister_one(devlink, port_index, param_list,
6946 param, unreg_cmd);
eabaef18
MS
6947unlock:
6948 mutex_unlock(&devlink->lock);
6949 return err;
6950}
39e6160e
VV
6951
6952static void __devlink_params_unregister(struct devlink *devlink,
c1e5786d 6953 unsigned int port_index,
39e6160e
VV
6954 struct list_head *param_list,
6955 const struct devlink_param *params,
c1e5786d
VV
6956 size_t params_count,
6957 enum devlink_command cmd)
39e6160e
VV
6958{
6959 const struct devlink_param *param = params;
6960 int i;
6961
6962 mutex_lock(&devlink->lock);
6963 for (i = 0; i < params_count; i++, param++)
c1e5786d
VV
6964 devlink_param_unregister_one(devlink, 0, param_list, param,
6965 cmd);
39e6160e
VV
6966 mutex_unlock(&devlink->lock);
6967}
6968
6969/**
6970 * devlink_params_register - register configuration parameters
6971 *
6972 * @devlink: devlink
6973 * @params: configuration parameters array
6974 * @params_count: number of parameters provided
6975 *
6976 * Register the configuration parameters supported by the driver.
6977 */
6978int devlink_params_register(struct devlink *devlink,
6979 const struct devlink_param *params,
6980 size_t params_count)
6981{
c1e5786d
VV
6982 return __devlink_params_register(devlink, 0, &devlink->param_list,
6983 params, params_count,
6984 DEVLINK_CMD_PARAM_NEW,
6985 DEVLINK_CMD_PARAM_DEL);
39e6160e 6986}
eabaef18
MS
6987EXPORT_SYMBOL_GPL(devlink_params_register);
6988
6989/**
6990 * devlink_params_unregister - unregister configuration parameters
6991 * @devlink: devlink
6992 * @params: configuration parameters to unregister
6993 * @params_count: number of parameters provided
6994 */
6995void devlink_params_unregister(struct devlink *devlink,
6996 const struct devlink_param *params,
6997 size_t params_count)
6998{
c1e5786d
VV
6999 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
7000 params, params_count,
7001 DEVLINK_CMD_PARAM_DEL);
eabaef18
MS
7002}
7003EXPORT_SYMBOL_GPL(devlink_params_unregister);
7004
7c62cfb8
JP
7005/**
7006 * devlink_params_publish - publish configuration parameters
7007 *
7008 * @devlink: devlink
7009 *
7010 * Publish previously registered configuration parameters.
7011 */
7012void devlink_params_publish(struct devlink *devlink)
7013{
7014 struct devlink_param_item *param_item;
7015
7016 list_for_each_entry(param_item, &devlink->param_list, list) {
7017 if (param_item->published)
7018 continue;
7019 param_item->published = true;
7020 devlink_param_notify(devlink, 0, param_item,
7021 DEVLINK_CMD_PARAM_NEW);
7022 }
7023}
7024EXPORT_SYMBOL_GPL(devlink_params_publish);
7025
7026/**
7027 * devlink_params_unpublish - unpublish configuration parameters
7028 *
7029 * @devlink: devlink
7030 *
7031 * Unpublish previously registered configuration parameters.
7032 */
7033void devlink_params_unpublish(struct devlink *devlink)
7034{
7035 struct devlink_param_item *param_item;
7036
7037 list_for_each_entry(param_item, &devlink->param_list, list) {
7038 if (!param_item->published)
7039 continue;
7040 param_item->published = false;
7041 devlink_param_notify(devlink, 0, param_item,
7042 DEVLINK_CMD_PARAM_DEL);
7043 }
7044}
7045EXPORT_SYMBOL_GPL(devlink_params_unpublish);
7046
39e6160e
VV
7047/**
7048 * devlink_port_params_register - register port configuration parameters
7049 *
7050 * @devlink_port: devlink port
7051 * @params: configuration parameters array
7052 * @params_count: number of parameters provided
7053 *
7054 * Register the configuration parameters supported by the port.
7055 */
7056int devlink_port_params_register(struct devlink_port *devlink_port,
7057 const struct devlink_param *params,
7058 size_t params_count)
7059{
7060 return __devlink_params_register(devlink_port->devlink,
c1e5786d 7061 devlink_port->index,
39e6160e 7062 &devlink_port->param_list, params,
c1e5786d
VV
7063 params_count,
7064 DEVLINK_CMD_PORT_PARAM_NEW,
7065 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
7066}
7067EXPORT_SYMBOL_GPL(devlink_port_params_register);
7068
7069/**
7070 * devlink_port_params_unregister - unregister port configuration
7071 * parameters
7072 *
7073 * @devlink_port: devlink port
7074 * @params: configuration parameters array
7075 * @params_count: number of parameters provided
7076 */
7077void devlink_port_params_unregister(struct devlink_port *devlink_port,
7078 const struct devlink_param *params,
7079 size_t params_count)
7080{
7081 return __devlink_params_unregister(devlink_port->devlink,
c1e5786d 7082 devlink_port->index,
39e6160e 7083 &devlink_port->param_list,
c1e5786d
VV
7084 params, params_count,
7085 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
7086}
7087EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
7088
ffd19b9a
VV
7089static int
7090__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
7091 union devlink_param_value *init_val)
ec01aeb1
MS
7092{
7093 struct devlink_param_item *param_item;
7094
ffd19b9a 7095 param_item = devlink_param_find_by_id(param_list, param_id);
ec01aeb1
MS
7096 if (!param_item)
7097 return -EINVAL;
7098
7099 if (!param_item->driverinit_value_valid ||
7100 !devlink_param_cmode_is_supported(param_item->param,
7101 DEVLINK_PARAM_CMODE_DRIVERINIT))
7102 return -EOPNOTSUPP;
7103
1276534c
MS
7104 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
7105 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
7106 else
7107 *init_val = param_item->driverinit_value;
ec01aeb1
MS
7108
7109 return 0;
7110}
ffd19b9a 7111
5473a7bd
VV
7112static int
7113__devlink_param_driverinit_value_set(struct devlink *devlink,
c1e5786d 7114 unsigned int port_index,
5473a7bd
VV
7115 struct list_head *param_list, u32 param_id,
7116 union devlink_param_value init_val,
7117 enum devlink_command cmd)
7118{
7119 struct devlink_param_item *param_item;
7120
7121 param_item = devlink_param_find_by_id(param_list, param_id);
7122 if (!param_item)
7123 return -EINVAL;
7124
7125 if (!devlink_param_cmode_is_supported(param_item->param,
7126 DEVLINK_PARAM_CMODE_DRIVERINIT))
7127 return -EOPNOTSUPP;
7128
7129 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
7130 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
7131 else
7132 param_item->driverinit_value = init_val;
7133 param_item->driverinit_value_valid = true;
7134
c1e5786d 7135 devlink_param_notify(devlink, port_index, param_item, cmd);
5473a7bd
VV
7136 return 0;
7137}
7138
ffd19b9a
VV
7139/**
7140 * devlink_param_driverinit_value_get - get configuration parameter
7141 * value for driver initializing
7142 *
7143 * @devlink: devlink
7144 * @param_id: parameter ID
7145 * @init_val: value of parameter in driverinit configuration mode
7146 *
7147 * This function should be used by the driver to get driverinit
7148 * configuration for initialization after reload command.
7149 */
7150int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
7151 union devlink_param_value *init_val)
7152{
be6fe1d8 7153 if (!devlink->ops->reload)
ffd19b9a
VV
7154 return -EOPNOTSUPP;
7155
7156 return __devlink_param_driverinit_value_get(&devlink->param_list,
7157 param_id, init_val);
7158}
ec01aeb1
MS
7159EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
7160
7161/**
7162 * devlink_param_driverinit_value_set - set value of configuration
7163 * parameter for driverinit
7164 * configuration mode
7165 *
7166 * @devlink: devlink
7167 * @param_id: parameter ID
7168 * @init_val: value of parameter to set for driverinit configuration mode
7169 *
7170 * This function should be used by the driver to set driverinit
7171 * configuration mode default value.
7172 */
7173int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
7174 union devlink_param_value init_val)
7175{
c1e5786d 7176 return __devlink_param_driverinit_value_set(devlink, 0,
5473a7bd
VV
7177 &devlink->param_list,
7178 param_id, init_val,
7179 DEVLINK_CMD_PARAM_NEW);
ec01aeb1
MS
7180}
7181EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
7182
ffd19b9a
VV
7183/**
7184 * devlink_port_param_driverinit_value_get - get configuration parameter
7185 * value for driver initializing
7186 *
7187 * @devlink_port: devlink_port
7188 * @param_id: parameter ID
7189 * @init_val: value of parameter in driverinit configuration mode
7190 *
7191 * This function should be used by the driver to get driverinit
7192 * configuration for initialization after reload command.
7193 */
7194int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
7195 u32 param_id,
7196 union devlink_param_value *init_val)
7197{
7198 struct devlink *devlink = devlink_port->devlink;
7199
be6fe1d8 7200 if (!devlink->ops->reload)
ffd19b9a
VV
7201 return -EOPNOTSUPP;
7202
7203 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
7204 param_id, init_val);
7205}
7206EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
7207
5473a7bd
VV
7208/**
7209 * devlink_port_param_driverinit_value_set - set value of configuration
7210 * parameter for driverinit
7211 * configuration mode
7212 *
7213 * @devlink_port: devlink_port
7214 * @param_id: parameter ID
7215 * @init_val: value of parameter to set for driverinit configuration mode
7216 *
7217 * This function should be used by the driver to set driverinit
7218 * configuration mode default value.
7219 */
7220int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
7221 u32 param_id,
7222 union devlink_param_value init_val)
7223{
7224 return __devlink_param_driverinit_value_set(devlink_port->devlink,
c1e5786d 7225 devlink_port->index,
5473a7bd 7226 &devlink_port->param_list,
c1e5786d
VV
7227 param_id, init_val,
7228 DEVLINK_CMD_PORT_PARAM_NEW);
5473a7bd
VV
7229}
7230EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
7231
ea601e17
MS
7232/**
7233 * devlink_param_value_changed - notify devlink on a parameter's value
7234 * change. Should be called by the driver
7235 * right after the change.
7236 *
7237 * @devlink: devlink
7238 * @param_id: parameter ID
7239 *
7240 * This function should be used by the driver to notify devlink on value
7241 * change, excluding driverinit configuration mode.
7242 * For driverinit configuration mode driver should use the function
ea601e17
MS
7243 */
7244void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
7245{
7246 struct devlink_param_item *param_item;
7247
7248 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
7249 WARN_ON(!param_item);
7250
c1e5786d 7251 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
ea601e17
MS
7252}
7253EXPORT_SYMBOL_GPL(devlink_param_value_changed);
7254
c1e5786d
VV
7255/**
7256 * devlink_port_param_value_changed - notify devlink on a parameter's value
7257 * change. Should be called by the driver
7258 * right after the change.
7259 *
7260 * @devlink_port: devlink_port
7261 * @param_id: parameter ID
7262 *
7263 * This function should be used by the driver to notify devlink on value
7264 * change, excluding driverinit configuration mode.
7265 * For driverinit configuration mode driver should use the function
7266 * devlink_port_param_driverinit_value_set() instead.
7267 */
7268void devlink_port_param_value_changed(struct devlink_port *devlink_port,
7269 u32 param_id)
7270{
7271 struct devlink_param_item *param_item;
7272
7273 param_item = devlink_param_find_by_id(&devlink_port->param_list,
7274 param_id);
7275 WARN_ON(!param_item);
7276
7277 devlink_param_notify(devlink_port->devlink, devlink_port->index,
7278 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
7279}
7280EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
7281
bde74ad1
MS
7282/**
7283 * devlink_param_value_str_fill - Safely fill-up the string preventing
7284 * from overflow of the preallocated buffer
7285 *
7286 * @dst_val: destination devlink_param_value
7287 * @src: source buffer
7288 */
7289void devlink_param_value_str_fill(union devlink_param_value *dst_val,
7290 const char *src)
7291{
7292 size_t len;
7293
7294 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
7295 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
7296}
7297EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
7298
b16ebe92
AV
7299/**
7300 * devlink_region_create - create a new address region
7301 *
7302 * @devlink: devlink
7303 * @region_name: region name
7304 * @region_max_snapshots: Maximum supported number of snapshots for region
7305 * @region_size: size of region
7306 */
7307struct devlink_region *devlink_region_create(struct devlink *devlink,
7308 const char *region_name,
7309 u32 region_max_snapshots,
7310 u64 region_size)
7311{
7312 struct devlink_region *region;
7313 int err = 0;
7314
7315 mutex_lock(&devlink->lock);
7316
7317 if (devlink_region_get_by_name(devlink, region_name)) {
7318 err = -EEXIST;
7319 goto unlock;
7320 }
7321
7322 region = kzalloc(sizeof(*region), GFP_KERNEL);
7323 if (!region) {
7324 err = -ENOMEM;
7325 goto unlock;
7326 }
7327
7328 region->devlink = devlink;
7329 region->max_snapshots = region_max_snapshots;
7330 region->name = region_name;
7331 region->size = region_size;
7332 INIT_LIST_HEAD(&region->snapshot_list);
7333 list_add_tail(&region->list, &devlink->region_list);
866319bb 7334 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
b16ebe92
AV
7335
7336 mutex_unlock(&devlink->lock);
7337 return region;
7338
7339unlock:
7340 mutex_unlock(&devlink->lock);
7341 return ERR_PTR(err);
7342}
7343EXPORT_SYMBOL_GPL(devlink_region_create);
7344
7345/**
7346 * devlink_region_destroy - destroy address region
7347 *
7348 * @region: devlink region to destroy
7349 */
7350void devlink_region_destroy(struct devlink_region *region)
7351{
7352 struct devlink *devlink = region->devlink;
d7e52722 7353 struct devlink_snapshot *snapshot, *ts;
b16ebe92
AV
7354
7355 mutex_lock(&devlink->lock);
d7e52722
AV
7356
7357 /* Free all snapshots of region */
7358 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
92b49822 7359 devlink_region_snapshot_del(region, snapshot);
d7e52722 7360
b16ebe92 7361 list_del(&region->list);
866319bb
AV
7362
7363 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
b16ebe92
AV
7364 mutex_unlock(&devlink->lock);
7365 kfree(region);
7366}
7367EXPORT_SYMBOL_GPL(devlink_region_destroy);
7368
ccadfa44
AV
7369/**
7370 * devlink_region_shapshot_id_get - get snapshot ID
7371 *
7372 * This callback should be called when adding a new snapshot,
7373 * Driver should use the same id for multiple snapshots taken
7374 * on multiple regions at the same time/by the same trigger.
7375 *
7376 * @devlink: devlink
7377 */
7378u32 devlink_region_shapshot_id_get(struct devlink *devlink)
7379{
7380 u32 id;
7381
7382 mutex_lock(&devlink->lock);
7383 id = ++devlink->snapshot_id;
7384 mutex_unlock(&devlink->lock);
7385
7386 return id;
7387}
7388EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
7389
d7e52722
AV
7390/**
7391 * devlink_region_snapshot_create - create a new snapshot
7392 * This will add a new snapshot of a region. The snapshot
7393 * will be stored on the region struct and can be accessed
7394 * from devlink. This is useful for future analyses of snapshots.
7395 * Multiple snapshots can be created on a region.
7396 * The @snapshot_id should be obtained using the getter function.
7397 *
eeaadd82 7398 * @region: devlink region of the snapshot
d7e52722
AV
7399 * @data: snapshot data
7400 * @snapshot_id: snapshot id to be created
7401 * @data_destructor: pointer to destructor function to free data
7402 */
3a5e5234 7403int devlink_region_snapshot_create(struct devlink_region *region,
d7e52722
AV
7404 u8 *data, u32 snapshot_id,
7405 devlink_snapshot_data_dest_t *data_destructor)
7406{
7407 struct devlink *devlink = region->devlink;
7408 struct devlink_snapshot *snapshot;
7409 int err;
7410
7411 mutex_lock(&devlink->lock);
7412
7413 /* check if region can hold one more snapshot */
7414 if (region->cur_snapshots == region->max_snapshots) {
7415 err = -ENOMEM;
7416 goto unlock;
7417 }
7418
7419 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
7420 err = -EEXIST;
7421 goto unlock;
7422 }
7423
7424 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
7425 if (!snapshot) {
7426 err = -ENOMEM;
7427 goto unlock;
7428 }
7429
7430 snapshot->id = snapshot_id;
7431 snapshot->region = region;
7432 snapshot->data = data;
d7e52722
AV
7433 snapshot->data_destructor = data_destructor;
7434
7435 list_add_tail(&snapshot->list, &region->snapshot_list);
7436
7437 region->cur_snapshots++;
7438
866319bb 7439 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
d7e52722
AV
7440 mutex_unlock(&devlink->lock);
7441 return 0;
7442
7443unlock:
7444 mutex_unlock(&devlink->lock);
7445 return err;
7446}
7447EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
7448
0f420b6c
IS
7449#define DEVLINK_TRAP(_id, _type) \
7450 { \
7451 .type = DEVLINK_TRAP_TYPE_##_type, \
7452 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
7453 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
7454 }
7455
7456static const struct devlink_trap devlink_trap_generic[] = {
391203ab
IS
7457 DEVLINK_TRAP(SMAC_MC, DROP),
7458 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
7459 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
7460 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
7461 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
7462 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
7463 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
7464 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
7465 DEVLINK_TRAP(TAIL_DROP, DROP),
0f420b6c
IS
7466};
7467
7468#define DEVLINK_TRAP_GROUP(_id) \
7469 { \
7470 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
7471 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
7472 }
7473
7474static const struct devlink_trap_group devlink_trap_group_generic[] = {
391203ab
IS
7475 DEVLINK_TRAP_GROUP(L2_DROPS),
7476 DEVLINK_TRAP_GROUP(L3_DROPS),
7477 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
0f420b6c
IS
7478};
7479
7480static int devlink_trap_generic_verify(const struct devlink_trap *trap)
7481{
7482 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
7483 return -EINVAL;
7484
7485 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
7486 return -EINVAL;
7487
7488 if (trap->type != devlink_trap_generic[trap->id].type)
7489 return -EINVAL;
7490
7491 return 0;
7492}
7493
7494static int devlink_trap_driver_verify(const struct devlink_trap *trap)
7495{
7496 int i;
7497
7498 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
7499 return -EINVAL;
7500
7501 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
7502 if (!strcmp(trap->name, devlink_trap_generic[i].name))
7503 return -EEXIST;
7504 }
7505
7506 return 0;
7507}
7508
7509static int devlink_trap_verify(const struct devlink_trap *trap)
7510{
7511 if (!trap || !trap->name || !trap->group.name)
7512 return -EINVAL;
7513
7514 if (trap->generic)
7515 return devlink_trap_generic_verify(trap);
7516 else
7517 return devlink_trap_driver_verify(trap);
7518}
7519
7520static int
7521devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
7522{
7523 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
7524 return -EINVAL;
7525
7526 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
7527 return -EINVAL;
7528
7529 return 0;
7530}
7531
7532static int
7533devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
7534{
7535 int i;
7536
7537 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
7538 return -EINVAL;
7539
7540 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
7541 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
7542 return -EEXIST;
7543 }
7544
7545 return 0;
7546}
7547
7548static int devlink_trap_group_verify(const struct devlink_trap_group *group)
7549{
7550 if (group->generic)
7551 return devlink_trap_group_generic_verify(group);
7552 else
7553 return devlink_trap_group_driver_verify(group);
7554}
7555
7556static void
7557devlink_trap_group_notify(struct devlink *devlink,
7558 const struct devlink_trap_group_item *group_item,
7559 enum devlink_command cmd)
7560{
7561 struct sk_buff *msg;
7562 int err;
7563
7564 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
7565 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
7566
7567 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7568 if (!msg)
7569 return;
7570
7571 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
7572 0);
7573 if (err) {
7574 nlmsg_free(msg);
7575 return;
7576 }
7577
7578 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
7579 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
7580}
7581
7582static struct devlink_trap_group_item *
7583devlink_trap_group_item_create(struct devlink *devlink,
7584 const struct devlink_trap_group *group)
7585{
7586 struct devlink_trap_group_item *group_item;
7587 int err;
7588
7589 err = devlink_trap_group_verify(group);
7590 if (err)
7591 return ERR_PTR(err);
7592
7593 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
7594 if (!group_item)
7595 return ERR_PTR(-ENOMEM);
7596
7597 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
7598 if (!group_item->stats) {
7599 err = -ENOMEM;
7600 goto err_stats_alloc;
7601 }
7602
7603 group_item->group = group;
7604 refcount_set(&group_item->refcount, 1);
7605
7606 if (devlink->ops->trap_group_init) {
7607 err = devlink->ops->trap_group_init(devlink, group);
7608 if (err)
7609 goto err_group_init;
7610 }
7611
7612 list_add_tail(&group_item->list, &devlink->trap_group_list);
7613 devlink_trap_group_notify(devlink, group_item,
7614 DEVLINK_CMD_TRAP_GROUP_NEW);
7615
7616 return group_item;
7617
7618err_group_init:
7619 free_percpu(group_item->stats);
7620err_stats_alloc:
7621 kfree(group_item);
7622 return ERR_PTR(err);
7623}
7624
7625static void
7626devlink_trap_group_item_destroy(struct devlink *devlink,
7627 struct devlink_trap_group_item *group_item)
7628{
7629 devlink_trap_group_notify(devlink, group_item,
7630 DEVLINK_CMD_TRAP_GROUP_DEL);
7631 list_del(&group_item->list);
7632 free_percpu(group_item->stats);
7633 kfree(group_item);
7634}
7635
7636static struct devlink_trap_group_item *
7637devlink_trap_group_item_get(struct devlink *devlink,
7638 const struct devlink_trap_group *group)
7639{
7640 struct devlink_trap_group_item *group_item;
7641
7642 group_item = devlink_trap_group_item_lookup(devlink, group->name);
7643 if (group_item) {
7644 refcount_inc(&group_item->refcount);
7645 return group_item;
7646 }
7647
7648 return devlink_trap_group_item_create(devlink, group);
7649}
7650
7651static void
7652devlink_trap_group_item_put(struct devlink *devlink,
7653 struct devlink_trap_group_item *group_item)
7654{
7655 if (!refcount_dec_and_test(&group_item->refcount))
7656 return;
7657
7658 devlink_trap_group_item_destroy(devlink, group_item);
7659}
7660
7661static int
7662devlink_trap_item_group_link(struct devlink *devlink,
7663 struct devlink_trap_item *trap_item)
7664{
7665 struct devlink_trap_group_item *group_item;
7666
7667 group_item = devlink_trap_group_item_get(devlink,
7668 &trap_item->trap->group);
7669 if (IS_ERR(group_item))
7670 return PTR_ERR(group_item);
7671
7672 trap_item->group_item = group_item;
7673
7674 return 0;
7675}
7676
7677static void
7678devlink_trap_item_group_unlink(struct devlink *devlink,
7679 struct devlink_trap_item *trap_item)
7680{
7681 devlink_trap_group_item_put(devlink, trap_item->group_item);
7682}
7683
7684static void devlink_trap_notify(struct devlink *devlink,
7685 const struct devlink_trap_item *trap_item,
7686 enum devlink_command cmd)
7687{
7688 struct sk_buff *msg;
7689 int err;
7690
7691 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
7692 cmd != DEVLINK_CMD_TRAP_DEL);
7693
7694 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7695 if (!msg)
7696 return;
7697
7698 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
7699 if (err) {
7700 nlmsg_free(msg);
7701 return;
7702 }
7703
7704 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
7705 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
7706}
7707
7708static int
7709devlink_trap_register(struct devlink *devlink,
7710 const struct devlink_trap *trap, void *priv)
7711{
7712 struct devlink_trap_item *trap_item;
7713 int err;
7714
7715 if (devlink_trap_item_lookup(devlink, trap->name))
7716 return -EEXIST;
7717
7718 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
7719 if (!trap_item)
7720 return -ENOMEM;
7721
7722 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
7723 if (!trap_item->stats) {
7724 err = -ENOMEM;
7725 goto err_stats_alloc;
7726 }
7727
7728 trap_item->trap = trap;
7729 trap_item->action = trap->init_action;
7730 trap_item->priv = priv;
7731
7732 err = devlink_trap_item_group_link(devlink, trap_item);
7733 if (err)
7734 goto err_group_link;
7735
7736 err = devlink->ops->trap_init(devlink, trap, trap_item);
7737 if (err)
7738 goto err_trap_init;
7739
7740 list_add_tail(&trap_item->list, &devlink->trap_list);
7741 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
7742
7743 return 0;
7744
7745err_trap_init:
7746 devlink_trap_item_group_unlink(devlink, trap_item);
7747err_group_link:
7748 free_percpu(trap_item->stats);
7749err_stats_alloc:
7750 kfree(trap_item);
7751 return err;
7752}
7753
7754static void devlink_trap_unregister(struct devlink *devlink,
7755 const struct devlink_trap *trap)
7756{
7757 struct devlink_trap_item *trap_item;
7758
7759 trap_item = devlink_trap_item_lookup(devlink, trap->name);
7760 if (WARN_ON_ONCE(!trap_item))
7761 return;
7762
7763 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
7764 list_del(&trap_item->list);
7765 if (devlink->ops->trap_fini)
7766 devlink->ops->trap_fini(devlink, trap, trap_item);
7767 devlink_trap_item_group_unlink(devlink, trap_item);
7768 free_percpu(trap_item->stats);
7769 kfree(trap_item);
7770}
7771
7772static void devlink_trap_disable(struct devlink *devlink,
7773 const struct devlink_trap *trap)
7774{
7775 struct devlink_trap_item *trap_item;
7776
7777 trap_item = devlink_trap_item_lookup(devlink, trap->name);
7778 if (WARN_ON_ONCE(!trap_item))
7779 return;
7780
7781 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP);
7782 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
7783}
7784
7785/**
7786 * devlink_traps_register - Register packet traps with devlink.
7787 * @devlink: devlink.
7788 * @traps: Packet traps.
7789 * @traps_count: Count of provided packet traps.
7790 * @priv: Driver private information.
7791 *
7792 * Return: Non-zero value on failure.
7793 */
7794int devlink_traps_register(struct devlink *devlink,
7795 const struct devlink_trap *traps,
7796 size_t traps_count, void *priv)
7797{
7798 int i, err;
7799
7800 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
7801 return -EINVAL;
7802
7803 mutex_lock(&devlink->lock);
7804 for (i = 0; i < traps_count; i++) {
7805 const struct devlink_trap *trap = &traps[i];
7806
7807 err = devlink_trap_verify(trap);
7808 if (err)
7809 goto err_trap_verify;
7810
7811 err = devlink_trap_register(devlink, trap, priv);
7812 if (err)
7813 goto err_trap_register;
7814 }
7815 mutex_unlock(&devlink->lock);
7816
7817 return 0;
7818
7819err_trap_register:
7820err_trap_verify:
7821 for (i--; i >= 0; i--)
7822 devlink_trap_unregister(devlink, &traps[i]);
7823 mutex_unlock(&devlink->lock);
7824 return err;
7825}
7826EXPORT_SYMBOL_GPL(devlink_traps_register);
7827
7828/**
7829 * devlink_traps_unregister - Unregister packet traps from devlink.
7830 * @devlink: devlink.
7831 * @traps: Packet traps.
7832 * @traps_count: Count of provided packet traps.
7833 */
7834void devlink_traps_unregister(struct devlink *devlink,
7835 const struct devlink_trap *traps,
7836 size_t traps_count)
7837{
7838 int i;
7839
7840 mutex_lock(&devlink->lock);
7841 /* Make sure we do not have any packets in-flight while unregistering
7842 * traps by disabling all of them and waiting for a grace period.
7843 */
7844 for (i = traps_count - 1; i >= 0; i--)
7845 devlink_trap_disable(devlink, &traps[i]);
7846 synchronize_rcu();
7847 for (i = traps_count - 1; i >= 0; i--)
7848 devlink_trap_unregister(devlink, &traps[i]);
7849 mutex_unlock(&devlink->lock);
7850}
7851EXPORT_SYMBOL_GPL(devlink_traps_unregister);
7852
7853static void
7854devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
7855 size_t skb_len)
7856{
7857 struct devlink_stats *stats;
7858
7859 stats = this_cpu_ptr(trap_stats);
7860 u64_stats_update_begin(&stats->syncp);
7861 stats->rx_bytes += skb_len;
7862 stats->rx_packets++;
7863 u64_stats_update_end(&stats->syncp);
7864}
7865
7866static void
7867devlink_trap_report_metadata_fill(struct net_dm_hw_metadata *hw_metadata,
7868 const struct devlink_trap_item *trap_item,
7869 struct devlink_port *in_devlink_port)
7870{
7871 struct devlink_trap_group_item *group_item = trap_item->group_item;
7872
7873 hw_metadata->trap_group_name = group_item->group->name;
7874 hw_metadata->trap_name = trap_item->trap->name;
7875
7876 spin_lock(&in_devlink_port->type_lock);
7877 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
7878 hw_metadata->input_dev = in_devlink_port->type_dev;
7879 spin_unlock(&in_devlink_port->type_lock);
7880}
7881
7882/**
7883 * devlink_trap_report - Report trapped packet to drop monitor.
7884 * @devlink: devlink.
7885 * @skb: Trapped packet.
7886 * @trap_ctx: Trap context.
7887 * @in_devlink_port: Input devlink port.
7888 */
7889void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
7890 void *trap_ctx, struct devlink_port *in_devlink_port)
7891{
7892 struct devlink_trap_item *trap_item = trap_ctx;
7893 struct net_dm_hw_metadata hw_metadata = {};
7894
7895 devlink_trap_stats_update(trap_item->stats, skb->len);
7896 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
7897
7898 devlink_trap_report_metadata_fill(&hw_metadata, trap_item,
7899 in_devlink_port);
7900 net_dm_hw_report(skb, &hw_metadata);
7901}
7902EXPORT_SYMBOL_GPL(devlink_trap_report);
7903
7904/**
7905 * devlink_trap_ctx_priv - Trap context to driver private information.
7906 * @trap_ctx: Trap context.
7907 *
7908 * Return: Driver private information passed during registration.
7909 */
7910void *devlink_trap_ctx_priv(void *trap_ctx)
7911{
7912 struct devlink_trap_item *trap_item = trap_ctx;
7913
7914 return trap_item->priv;
7915}
7916EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
7917
ddb6e99e
JK
7918static void __devlink_compat_running_version(struct devlink *devlink,
7919 char *buf, size_t len)
7920{
7921 const struct nlattr *nlattr;
7922 struct devlink_info_req req;
7923 struct sk_buff *msg;
7924 int rem, err;
7925
ddb6e99e
JK
7926 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7927 if (!msg)
7928 return;
7929
7930 req.msg = msg;
7931 err = devlink->ops->info_get(devlink, &req, NULL);
7932 if (err)
7933 goto free_msg;
7934
7935 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
7936 const struct nlattr *kv;
7937 int rem_kv;
7938
7939 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
7940 continue;
7941
7942 nla_for_each_nested(kv, nlattr, rem_kv) {
7943 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
7944 continue;
7945
7946 strlcat(buf, nla_data(kv), len);
7947 strlcat(buf, " ", len);
7948 }
7949 }
7950free_msg:
7951 nlmsg_free(msg);
7952}
7953
7954void devlink_compat_running_version(struct net_device *dev,
7955 char *buf, size_t len)
7956{
ddb6e99e
JK
7957 struct devlink *devlink;
7958
1b45ff6c
JK
7959 dev_hold(dev);
7960 rtnl_unlock();
7961
b473b0d2 7962 devlink = netdev_to_devlink(dev);
be6fe1d8 7963 if (!devlink || !devlink->ops->info_get)
e0dcd386 7964 goto out;
b473b0d2
JK
7965
7966 mutex_lock(&devlink->lock);
7967 __devlink_compat_running_version(devlink, buf, len);
7968 mutex_unlock(&devlink->lock);
1b45ff6c 7969
e0dcd386 7970out:
1b45ff6c
JK
7971 rtnl_lock();
7972 dev_put(dev);
ddb6e99e
JK
7973}
7974
4eceba17
JK
7975int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
7976{
4eceba17 7977 struct devlink *devlink;
e0dcd386 7978 int ret;
4eceba17 7979
1b45ff6c
JK
7980 dev_hold(dev);
7981 rtnl_unlock();
7982
b473b0d2 7983 devlink = netdev_to_devlink(dev);
e0dcd386
JP
7984 if (!devlink || !devlink->ops->flash_update) {
7985 ret = -EOPNOTSUPP;
7986 goto out;
7987 }
4eceba17 7988
b473b0d2
JK
7989 mutex_lock(&devlink->lock);
7990 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
7991 mutex_unlock(&devlink->lock);
1b45ff6c 7992
e0dcd386 7993out:
1b45ff6c
JK
7994 rtnl_lock();
7995 dev_put(dev);
7996
b473b0d2 7997 return ret;
4eceba17
JK
7998}
7999
af3836df
JP
8000int devlink_compat_phys_port_name_get(struct net_device *dev,
8001 char *name, size_t len)
8002{
8003 struct devlink_port *devlink_port;
8004
8005 /* RTNL mutex is held here which ensures that devlink_port
8006 * instance cannot disappear in the middle. No need to take
8007 * any devlink lock as only permanent values are accessed.
8008 */
8009 ASSERT_RTNL();
8010
8011 devlink_port = netdev_to_devlink_port(dev);
8012 if (!devlink_port)
8013 return -EOPNOTSUPP;
8014
8015 return __devlink_port_phys_port_name_get(devlink_port, name, len);
8016}
8017
7e1146e8
JP
8018int devlink_compat_switch_id_get(struct net_device *dev,
8019 struct netdev_phys_item_id *ppid)
8020{
8021 struct devlink_port *devlink_port;
8022
043b8413
VB
8023 /* Caller must hold RTNL mutex or reference to dev, which ensures that
8024 * devlink_port instance cannot disappear in the middle. No need to take
7e1146e8
JP
8025 * any devlink lock as only permanent values are accessed.
8026 */
7e1146e8
JP
8027 devlink_port = netdev_to_devlink_port(dev);
8028 if (!devlink_port || !devlink_port->attrs.switch_port)
8029 return -EOPNOTSUPP;
8030
8031 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
8032
8033 return 0;
8034}
8035
f4b6bcc7 8036static int __init devlink_init(void)
bfcd3a46 8037{
489111e5 8038 return genl_register_family(&devlink_nl_family);
bfcd3a46
JP
8039}
8040
f4b6bcc7 8041subsys_initcall(devlink_init);