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