blob: 6ae36808c152133eddf69d73ed46fb1097c02470 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01002/*
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>
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008 */
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>
Jiri Pirkob8f97552019-03-24 11:14:37 +010018#include <linux/spinlock.h>
Moshe Shemeshb587bda2019-04-29 12:41:45 +030019#include <linux/refcount.h>
Jiri Pirko136bf272019-05-23 10:43:35 +020020#include <linux/workqueue.h>
Ido Schimmel0f420b62019-08-17 16:28:17 +030021#include <linux/u64_stats_sync.h>
22#include <linux/timekeeping.h>
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010023#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>
Ido Schimmel0f420b62019-08-17 16:28:17 +030030#include <net/drop_monitor.h>
Jiri Pirkoe5224f02016-07-12 18:05:03 +020031#define CREATE_TRACE_POINTS
32#include <trace/events/devlink.h>
33
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020034static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
35 {
David Ahern12bdc5e2017-08-30 17:07:30 -070036 .name = "destination mac",
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020037 .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
Arkadi Sharshevsky3fb886e2017-08-24 08:40:00 +020051static 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
Arkadi Sharshevsky1797f5b2017-08-31 17:59:12 +020068static 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
Jiri Pirkoe5224f02016-07-12 18:05:03 +020085EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
Nir Dotan57186a52019-02-04 18:47:45 +000086EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010087
Parav Pandita1e8ae92020-06-19 03:32:49 +000088static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
89 [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY },
90};
91
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010092static LIST_HEAD(devlink_list);
93
94/* devlink_mutex
95 *
96 * An overall lock guarding every operation coming from userspace.
97 * It also guards devlink devices list and it is taken when
98 * driver registers/unregisters it.
99 */
100static DEFINE_MUTEX(devlink_mutex);
101
Jiri Pirko471f8942019-10-03 11:49:31 +0200102struct net *devlink_net(const struct devlink *devlink)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100103{
104 return read_pnet(&devlink->_net);
105}
Jiri Pirko471f8942019-10-03 11:49:31 +0200106EXPORT_SYMBOL_GPL(devlink_net);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100107
Jiri Pirko8273fd82019-10-05 08:10:31 +0200108static void __devlink_net_set(struct devlink *devlink, struct net *net)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100109{
110 write_pnet(&devlink->_net, net);
111}
112
Jiri Pirko8273fd82019-10-05 08:10:31 +0200113void devlink_net_set(struct devlink *devlink, struct net *net)
114{
115 if (WARN_ON(devlink->registered))
116 return;
117 __devlink_net_set(devlink, net);
118}
119EXPORT_SYMBOL_GPL(devlink_net_set);
120
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100121static struct devlink *devlink_get_from_attrs(struct net *net,
122 struct nlattr **attrs)
123{
124 struct devlink *devlink;
125 char *busname;
126 char *devname;
127
128 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
129 return ERR_PTR(-EINVAL);
130
131 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
132 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
133
Parav Panditdac7c082019-02-12 14:24:08 -0600134 lockdep_assert_held(&devlink_mutex);
135
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100136 list_for_each_entry(devlink, &devlink_list, list) {
137 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
138 strcmp(dev_name(devlink->dev), devname) == 0 &&
139 net_eq(devlink_net(devlink), net))
140 return devlink;
141 }
142
143 return ERR_PTR(-ENODEV);
144}
145
146static struct devlink *devlink_get_from_info(struct genl_info *info)
147{
148 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
149}
150
151static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
Parav Panditc7282b52019-08-30 05:39:44 -0500152 unsigned int port_index)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100153{
154 struct devlink_port *devlink_port;
155
156 list_for_each_entry(devlink_port, &devlink->port_list, list) {
157 if (devlink_port->index == port_index)
158 return devlink_port;
159 }
160 return NULL;
161}
162
Parav Panditc7282b52019-08-30 05:39:44 -0500163static bool devlink_port_index_exists(struct devlink *devlink,
164 unsigned int port_index)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100165{
166 return devlink_port_get_by_index(devlink, port_index);
167}
168
169static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
170 struct nlattr **attrs)
171{
172 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
173 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
174 struct devlink_port *devlink_port;
175
176 devlink_port = devlink_port_get_by_index(devlink, port_index);
177 if (!devlink_port)
178 return ERR_PTR(-ENODEV);
179 return devlink_port;
180 }
181 return ERR_PTR(-EINVAL);
182}
183
184static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
185 struct genl_info *info)
186{
187 return devlink_port_get_from_attrs(devlink, info->attrs);
188}
189
Jiri Pirkobf797472016-04-14 18:19:13 +0200190struct devlink_sb {
191 struct list_head list;
192 unsigned int index;
193 u32 size;
194 u16 ingress_pools_count;
195 u16 egress_pools_count;
196 u16 ingress_tc_count;
197 u16 egress_tc_count;
198};
199
200static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
201{
202 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
203}
204
205static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
206 unsigned int sb_index)
207{
208 struct devlink_sb *devlink_sb;
209
210 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
211 if (devlink_sb->index == sb_index)
212 return devlink_sb;
213 }
214 return NULL;
215}
216
217static bool devlink_sb_index_exists(struct devlink *devlink,
218 unsigned int sb_index)
219{
220 return devlink_sb_get_by_index(devlink, sb_index);
221}
222
223static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
224 struct nlattr **attrs)
225{
226 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
227 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
228 struct devlink_sb *devlink_sb;
229
230 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
231 if (!devlink_sb)
232 return ERR_PTR(-ENODEV);
233 return devlink_sb;
234 }
235 return ERR_PTR(-EINVAL);
236}
237
238static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
239 struct genl_info *info)
240{
241 return devlink_sb_get_from_attrs(devlink, info->attrs);
242}
243
244static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
245 struct nlattr **attrs,
246 u16 *p_pool_index)
247{
248 u16 val;
249
250 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
251 return -EINVAL;
252
253 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
254 if (val >= devlink_sb_pool_count(devlink_sb))
255 return -EINVAL;
256 *p_pool_index = val;
257 return 0;
258}
259
260static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
261 struct genl_info *info,
262 u16 *p_pool_index)
263{
264 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
265 p_pool_index);
266}
267
268static int
269devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
270 enum devlink_sb_pool_type *p_pool_type)
271{
272 u8 val;
273
274 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
275 return -EINVAL;
276
277 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
278 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
279 val != DEVLINK_SB_POOL_TYPE_EGRESS)
280 return -EINVAL;
281 *p_pool_type = val;
282 return 0;
283}
284
285static int
286devlink_sb_pool_type_get_from_info(struct genl_info *info,
287 enum devlink_sb_pool_type *p_pool_type)
288{
289 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
290}
291
292static int
293devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
294 enum devlink_sb_threshold_type *p_th_type)
295{
296 u8 val;
297
298 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
299 return -EINVAL;
300
301 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
302 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
303 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
304 return -EINVAL;
305 *p_th_type = val;
306 return 0;
307}
308
309static int
310devlink_sb_th_type_get_from_info(struct genl_info *info,
311 enum devlink_sb_threshold_type *p_th_type)
312{
313 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
314}
315
316static int
317devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
318 struct nlattr **attrs,
319 enum devlink_sb_pool_type pool_type,
320 u16 *p_tc_index)
321{
322 u16 val;
323
324 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
325 return -EINVAL;
326
327 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
328 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
329 val >= devlink_sb->ingress_tc_count)
330 return -EINVAL;
331 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
332 val >= devlink_sb->egress_tc_count)
333 return -EINVAL;
334 *p_tc_index = val;
335 return 0;
336}
337
338static int
339devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
340 struct genl_info *info,
341 enum devlink_sb_pool_type pool_type,
342 u16 *p_tc_index)
343{
344 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
345 pool_type, p_tc_index);
346}
347
Alex Veskerb16ebe92018-07-12 15:13:08 +0300348struct devlink_region {
349 struct devlink *devlink;
350 struct list_head list;
Jacob Kellere8937682020-03-26 11:37:08 -0700351 const struct devlink_region_ops *ops;
Alex Veskerb16ebe92018-07-12 15:13:08 +0300352 struct list_head snapshot_list;
353 u32 max_snapshots;
354 u32 cur_snapshots;
355 u64 size;
356};
357
Alex Veskerd7e52722018-07-12 15:13:10 +0300358struct devlink_snapshot {
359 struct list_head list;
360 struct devlink_region *region;
Alex Veskerd7e52722018-07-12 15:13:10 +0300361 u8 *data;
362 u32 id;
363};
364
Alex Veskerb16ebe92018-07-12 15:13:08 +0300365static struct devlink_region *
366devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
367{
368 struct devlink_region *region;
369
370 list_for_each_entry(region, &devlink->region_list, list)
Jacob Kellere8937682020-03-26 11:37:08 -0700371 if (!strcmp(region->ops->name, region_name))
Alex Veskerb16ebe92018-07-12 15:13:08 +0300372 return region;
373
374 return NULL;
375}
376
Alex Veskerd7e52722018-07-12 15:13:10 +0300377static struct devlink_snapshot *
378devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
379{
380 struct devlink_snapshot *snapshot;
381
382 list_for_each_entry(snapshot, &region->snapshot_list, list)
383 if (snapshot->id == id)
384 return snapshot;
385
386 return NULL;
387}
388
Jiri Pirko1fc22572016-04-08 19:12:48 +0200389#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
390#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
Jiri Pirkobf797472016-04-14 18:19:13 +0200391#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100392
393/* The per devlink instance lock is taken by default in the pre-doit
394 * operation, yet several commands do not require this. The global
395 * devlink lock is taken and protects from disruption by user-calls.
396 */
397#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100398
399static int devlink_nl_pre_doit(const struct genl_ops *ops,
400 struct sk_buff *skb, struct genl_info *info)
401{
402 struct devlink *devlink;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100403 int err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100404
405 mutex_lock(&devlink_mutex);
406 devlink = devlink_get_from_info(info);
407 if (IS_ERR(devlink)) {
408 mutex_unlock(&devlink_mutex);
409 return PTR_ERR(devlink);
410 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100411 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
412 mutex_lock(&devlink->lock);
Jiri Pirko1fc22572016-04-08 19:12:48 +0200413 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
414 info->user_ptr[0] = devlink;
415 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100416 struct devlink_port *devlink_port;
417
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100418 devlink_port = devlink_port_get_from_info(devlink, info);
419 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100420 err = PTR_ERR(devlink_port);
421 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100422 }
Jiri Pirko1fc22572016-04-08 19:12:48 +0200423 info->user_ptr[0] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100424 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200425 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
426 struct devlink_sb *devlink_sb;
427
428 devlink_sb = devlink_sb_get_from_info(devlink, info);
429 if (IS_ERR(devlink_sb)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100430 err = PTR_ERR(devlink_sb);
431 goto unlock;
Jiri Pirkobf797472016-04-14 18:19:13 +0200432 }
433 info->user_ptr[1] = devlink_sb;
434 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100435 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100436
437unlock:
438 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
439 mutex_unlock(&devlink->lock);
440 mutex_unlock(&devlink_mutex);
441 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100442}
443
444static void devlink_nl_post_doit(const struct genl_ops *ops,
445 struct sk_buff *skb, struct genl_info *info)
446{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100447 struct devlink *devlink;
448
Jiri Pirko070c63f2019-10-03 11:49:39 +0200449 /* When devlink changes netns, it would not be found
450 * by devlink_get_from_info(). So try if it is stored first.
451 */
452 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
453 devlink = info->user_ptr[0];
454 } else {
455 devlink = devlink_get_from_info(info);
456 WARN_ON(IS_ERR(devlink));
457 }
458 if (!IS_ERR(devlink) && ~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100459 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100460 mutex_unlock(&devlink_mutex);
461}
462
Johannes Berg489111e2016-10-24 14:40:03 +0200463static struct genl_family devlink_nl_family;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100464
465enum devlink_multicast_groups {
466 DEVLINK_MCGRP_CONFIG,
467};
468
469static const struct genl_multicast_group devlink_nl_mcgrps[] = {
470 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
471};
472
473static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
474{
475 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
476 return -EMSGSIZE;
477 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
478 return -EMSGSIZE;
479 return 0;
480}
481
482static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
483 enum devlink_command cmd, u32 portid,
484 u32 seq, int flags)
485{
486 void *hdr;
487
488 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
489 if (!hdr)
490 return -EMSGSIZE;
491
492 if (devlink_nl_put_handle(msg, devlink))
493 goto nla_put_failure;
Jiri Pirko2670ac22019-09-12 10:49:46 +0200494 if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed))
495 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100496
497 genlmsg_end(msg, hdr);
498 return 0;
499
500nla_put_failure:
501 genlmsg_cancel(msg, hdr);
502 return -EMSGSIZE;
503}
504
505static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
506{
507 struct sk_buff *msg;
508 int err;
509
510 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
511
512 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
513 if (!msg)
514 return;
515
516 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
517 if (err) {
518 nlmsg_free(msg);
519 return;
520 }
521
522 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
523 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
524}
525
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200526static int devlink_nl_port_attrs_put(struct sk_buff *msg,
527 struct devlink_port *devlink_port)
528{
529 struct devlink_port_attrs *attrs = &devlink_port->attrs;
530
531 if (!attrs->set)
532 return 0;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200533 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
534 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500535 switch (devlink_port->attrs.flavour) {
536 case DEVLINK_PORT_FLAVOUR_PCI_PF:
Parav Pandit98fd2d62019-07-08 23:17:37 -0500537 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
538 attrs->pci_pf.pf))
539 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500540 break;
541 case DEVLINK_PORT_FLAVOUR_PCI_VF:
Parav Pandite41b6bf2019-07-08 23:17:38 -0500542 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
543 attrs->pci_vf.pf) ||
544 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER,
545 attrs->pci_vf.vf))
546 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500547 break;
548 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
549 case DEVLINK_PORT_FLAVOUR_CPU:
550 case DEVLINK_PORT_FLAVOUR_DSA:
Parav Panditacf1ee42020-03-03 08:12:42 -0600551 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Parav Pandit58b6be42019-08-30 05:39:45 -0500552 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
553 attrs->phys.port_number))
554 return -EMSGSIZE;
555 if (!attrs->split)
556 return 0;
557 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
558 attrs->phys.port_number))
559 return -EMSGSIZE;
560 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
561 attrs->phys.split_subport_number))
562 return -EMSGSIZE;
563 break;
564 default:
565 break;
Parav Pandit98fd2d62019-07-08 23:17:37 -0500566 }
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200567 return 0;
568}
569
Parav Pandit2a916ec2020-06-19 03:32:48 +0000570static int
571devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
572 struct netlink_ext_ack *extack)
573{
574 struct devlink *devlink = port->devlink;
575 const struct devlink_ops *ops;
576 struct nlattr *function_attr;
577 bool empty_nest = true;
578 int err = 0;
579
580 function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
581 if (!function_attr)
582 return -EMSGSIZE;
583
584 ops = devlink->ops;
585 if (ops->port_function_hw_addr_get) {
Stephen Rothwell29cb9862020-06-23 13:43:06 +1000586 int hw_addr_len;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000587 u8 hw_addr[MAX_ADDR_LEN];
588
589 err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack);
590 if (err == -EOPNOTSUPP) {
591 /* Port function attributes are optional for a port. If port doesn't
592 * support function attribute, returning -EOPNOTSUPP is not an error.
593 */
594 err = 0;
595 goto out;
596 } else if (err) {
597 goto out;
598 }
599 err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr);
600 if (err)
601 goto out;
602 empty_nest = false;
603 }
604
605out:
606 if (err || empty_nest)
607 nla_nest_cancel(msg, function_attr);
608 else
609 nla_nest_end(msg, function_attr);
610 return err;
611}
612
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100613static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
614 struct devlink_port *devlink_port,
615 enum devlink_command cmd, u32 portid,
Parav Pandita829eb02020-06-19 03:32:47 +0000616 u32 seq, int flags,
617 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100618{
619 void *hdr;
620
621 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
622 if (!hdr)
623 return -EMSGSIZE;
624
625 if (devlink_nl_put_handle(msg, devlink))
626 goto nla_put_failure;
627 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
628 goto nla_put_failure;
Jiri Pirkob8f97552019-03-24 11:14:37 +0100629
Ido Schimmel0f420b62019-08-17 16:28:17 +0300630 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100631 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100632 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100633 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
634 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
635 devlink_port->desired_type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100636 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100637 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
638 struct net_device *netdev = devlink_port->type_dev;
639
640 if (netdev &&
641 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
642 netdev->ifindex) ||
643 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
644 netdev->name)))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100645 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100646 }
647 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
648 struct ib_device *ibdev = devlink_port->type_dev;
649
650 if (ibdev &&
651 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
652 ibdev->name))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100653 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100654 }
Ido Schimmel0f420b62019-08-17 16:28:17 +0300655 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200656 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100657 goto nla_put_failure;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000658 if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
659 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100660
661 genlmsg_end(msg, hdr);
662 return 0;
663
Jiri Pirkob8f97552019-03-24 11:14:37 +0100664nla_put_failure_type_locked:
Ido Schimmel0f420b62019-08-17 16:28:17 +0300665 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100666nla_put_failure:
667 genlmsg_cancel(msg, hdr);
668 return -EMSGSIZE;
669}
670
671static void devlink_port_notify(struct devlink_port *devlink_port,
672 enum devlink_command cmd)
673{
674 struct devlink *devlink = devlink_port->devlink;
675 struct sk_buff *msg;
676 int err;
677
678 if (!devlink_port->registered)
679 return;
680
681 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
682
683 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
684 if (!msg)
685 return;
686
Parav Pandita829eb02020-06-19 03:32:47 +0000687 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0,
688 NULL);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100689 if (err) {
690 nlmsg_free(msg);
691 return;
692 }
693
694 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
695 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
696}
697
698static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
699{
700 struct devlink *devlink = info->user_ptr[0];
701 struct sk_buff *msg;
702 int err;
703
704 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
705 if (!msg)
706 return -ENOMEM;
707
708 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
709 info->snd_portid, info->snd_seq, 0);
710 if (err) {
711 nlmsg_free(msg);
712 return err;
713 }
714
715 return genlmsg_reply(msg, info);
716}
717
718static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
719 struct netlink_callback *cb)
720{
721 struct devlink *devlink;
722 int start = cb->args[0];
723 int idx = 0;
724 int err;
725
726 mutex_lock(&devlink_mutex);
727 list_for_each_entry(devlink, &devlink_list, list) {
728 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
729 continue;
730 if (idx < start) {
731 idx++;
732 continue;
733 }
734 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
735 NETLINK_CB(cb->skb).portid,
736 cb->nlh->nlmsg_seq, NLM_F_MULTI);
737 if (err)
738 goto out;
739 idx++;
740 }
741out:
742 mutex_unlock(&devlink_mutex);
743
744 cb->args[0] = idx;
745 return msg->len;
746}
747
748static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
749 struct genl_info *info)
750{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200751 struct devlink_port *devlink_port = info->user_ptr[0];
752 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100753 struct sk_buff *msg;
754 int err;
755
756 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
757 if (!msg)
758 return -ENOMEM;
759
760 err = devlink_nl_port_fill(msg, devlink, devlink_port,
761 DEVLINK_CMD_PORT_NEW,
Parav Pandita829eb02020-06-19 03:32:47 +0000762 info->snd_portid, info->snd_seq, 0,
763 info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100764 if (err) {
765 nlmsg_free(msg);
766 return err;
767 }
768
769 return genlmsg_reply(msg, info);
770}
771
772static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
773 struct netlink_callback *cb)
774{
775 struct devlink *devlink;
776 struct devlink_port *devlink_port;
777 int start = cb->args[0];
778 int idx = 0;
779 int err;
780
781 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100782 list_for_each_entry(devlink, &devlink_list, list) {
783 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
784 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100785 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100786 list_for_each_entry(devlink_port, &devlink->port_list, list) {
787 if (idx < start) {
788 idx++;
789 continue;
790 }
791 err = devlink_nl_port_fill(msg, devlink, devlink_port,
792 DEVLINK_CMD_NEW,
793 NETLINK_CB(cb->skb).portid,
794 cb->nlh->nlmsg_seq,
Parav Pandita829eb02020-06-19 03:32:47 +0000795 NLM_F_MULTI,
796 cb->extack);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100797 if (err) {
798 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100799 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100800 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100801 idx++;
802 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100803 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100804 }
805out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100806 mutex_unlock(&devlink_mutex);
807
808 cb->args[0] = idx;
809 return msg->len;
810}
811
812static int devlink_port_type_set(struct devlink *devlink,
813 struct devlink_port *devlink_port,
814 enum devlink_port_type port_type)
815
816{
817 int err;
818
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800819 if (devlink->ops->port_type_set) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100820 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
821 return -EINVAL;
Elad Raz6edf1012016-10-23 17:43:05 +0200822 if (port_type == devlink_port->type)
823 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100824 err = devlink->ops->port_type_set(devlink_port, port_type);
825 if (err)
826 return err;
827 devlink_port->desired_type = port_type;
828 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
829 return 0;
830 }
831 return -EOPNOTSUPP;
832}
833
Parav Pandita1e8ae92020-06-19 03:32:49 +0000834static int
835devlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port,
836 const struct nlattr *attr, struct netlink_ext_ack *extack)
837{
838 const struct devlink_ops *ops;
839 const u8 *hw_addr;
840 int hw_addr_len;
841 int err;
842
843 hw_addr = nla_data(attr);
844 hw_addr_len = nla_len(attr);
845 if (hw_addr_len > MAX_ADDR_LEN) {
846 NL_SET_ERR_MSG_MOD(extack, "Port function hardware address too long");
847 return -EINVAL;
848 }
849 if (port->type == DEVLINK_PORT_TYPE_ETH) {
850 if (hw_addr_len != ETH_ALEN) {
851 NL_SET_ERR_MSG_MOD(extack, "Address must be 6 bytes for Ethernet device");
852 return -EINVAL;
853 }
854 if (!is_unicast_ether_addr(hw_addr)) {
855 NL_SET_ERR_MSG_MOD(extack, "Non-unicast hardware address unsupported");
856 return -EINVAL;
857 }
858 }
859
860 ops = devlink->ops;
861 if (!ops->port_function_hw_addr_set) {
862 NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes");
863 return -EOPNOTSUPP;
864 }
865
866 err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack);
867 if (err)
868 return err;
869
870 devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
871 return 0;
872}
873
874static int
875devlink_port_function_set(struct devlink *devlink, struct devlink_port *port,
876 const struct nlattr *attr, struct netlink_ext_ack *extack)
877{
878 struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];
879 int err;
880
881 err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr,
882 devlink_function_nl_policy, extack);
883 if (err < 0) {
884 NL_SET_ERR_MSG_MOD(extack, "Fail to parse port function attributes");
885 return err;
886 }
887
888 attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
889 if (attr)
890 err = devlink_port_function_hw_addr_set(devlink, port, attr, extack);
891
892 return err;
893}
894
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100895static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
896 struct genl_info *info)
897{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200898 struct devlink_port *devlink_port = info->user_ptr[0];
899 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100900 int err;
901
902 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
903 enum devlink_port_type port_type;
904
905 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
906 err = devlink_port_type_set(devlink, devlink_port, port_type);
907 if (err)
908 return err;
909 }
Parav Pandita1e8ae92020-06-19 03:32:49 +0000910
911 if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
912 struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
913 struct netlink_ext_ack *extack = info->extack;
914
915 err = devlink_port_function_set(devlink, devlink_port, attr, extack);
916 if (err)
917 return err;
918 }
919
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100920 return 0;
921}
922
David Ahernac0fc8a2018-06-05 08:14:09 -0700923static int devlink_port_split(struct devlink *devlink, u32 port_index,
924 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100925
926{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800927 if (devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -0700928 return devlink->ops->port_split(devlink, port_index, count,
929 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100930 return -EOPNOTSUPP;
931}
932
933static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
934 struct genl_info *info)
935{
936 struct devlink *devlink = info->user_ptr[0];
937 u32 port_index;
938 u32 count;
939
940 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
941 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
942 return -EINVAL;
943
944 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
945 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700946 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100947}
948
David Ahernac0fc8a2018-06-05 08:14:09 -0700949static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
950 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100951
952{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800953 if (devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -0700954 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100955 return -EOPNOTSUPP;
956}
957
958static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
959 struct genl_info *info)
960{
961 struct devlink *devlink = info->user_ptr[0];
962 u32 port_index;
963
964 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
965 return -EINVAL;
966
967 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700968 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100969}
970
Jiri Pirkobf797472016-04-14 18:19:13 +0200971static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
972 struct devlink_sb *devlink_sb,
973 enum devlink_command cmd, u32 portid,
974 u32 seq, int flags)
975{
976 void *hdr;
977
978 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
979 if (!hdr)
980 return -EMSGSIZE;
981
982 if (devlink_nl_put_handle(msg, devlink))
983 goto nla_put_failure;
984 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
985 goto nla_put_failure;
986 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
987 goto nla_put_failure;
988 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
989 devlink_sb->ingress_pools_count))
990 goto nla_put_failure;
991 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
992 devlink_sb->egress_pools_count))
993 goto nla_put_failure;
994 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
995 devlink_sb->ingress_tc_count))
996 goto nla_put_failure;
997 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
998 devlink_sb->egress_tc_count))
999 goto nla_put_failure;
1000
1001 genlmsg_end(msg, hdr);
1002 return 0;
1003
1004nla_put_failure:
1005 genlmsg_cancel(msg, hdr);
1006 return -EMSGSIZE;
1007}
1008
1009static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
1010 struct genl_info *info)
1011{
1012 struct devlink *devlink = info->user_ptr[0];
1013 struct devlink_sb *devlink_sb = info->user_ptr[1];
1014 struct sk_buff *msg;
1015 int err;
1016
1017 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1018 if (!msg)
1019 return -ENOMEM;
1020
1021 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1022 DEVLINK_CMD_SB_NEW,
1023 info->snd_portid, info->snd_seq, 0);
1024 if (err) {
1025 nlmsg_free(msg);
1026 return err;
1027 }
1028
1029 return genlmsg_reply(msg, info);
1030}
1031
1032static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
1033 struct netlink_callback *cb)
1034{
1035 struct devlink *devlink;
1036 struct devlink_sb *devlink_sb;
1037 int start = cb->args[0];
1038 int idx = 0;
1039 int err;
1040
1041 mutex_lock(&devlink_mutex);
1042 list_for_each_entry(devlink, &devlink_list, list) {
1043 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
1044 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001045 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001046 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1047 if (idx < start) {
1048 idx++;
1049 continue;
1050 }
1051 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1052 DEVLINK_CMD_SB_NEW,
1053 NETLINK_CB(cb->skb).portid,
1054 cb->nlh->nlmsg_seq,
1055 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001056 if (err) {
1057 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001058 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001059 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001060 idx++;
1061 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001062 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001063 }
1064out:
1065 mutex_unlock(&devlink_mutex);
1066
1067 cb->args[0] = idx;
1068 return msg->len;
1069}
1070
1071static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
1072 struct devlink_sb *devlink_sb,
1073 u16 pool_index, enum devlink_command cmd,
1074 u32 portid, u32 seq, int flags)
1075{
1076 struct devlink_sb_pool_info pool_info;
1077 void *hdr;
1078 int err;
1079
1080 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
1081 pool_index, &pool_info);
1082 if (err)
1083 return err;
1084
1085 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1086 if (!hdr)
1087 return -EMSGSIZE;
1088
1089 if (devlink_nl_put_handle(msg, devlink))
1090 goto nla_put_failure;
1091 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1092 goto nla_put_failure;
1093 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1094 goto nla_put_failure;
1095 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
1096 goto nla_put_failure;
1097 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
1098 goto nla_put_failure;
1099 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1100 pool_info.threshold_type))
1101 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -08001102 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
1103 pool_info.cell_size))
1104 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +02001105
1106 genlmsg_end(msg, hdr);
1107 return 0;
1108
1109nla_put_failure:
1110 genlmsg_cancel(msg, hdr);
1111 return -EMSGSIZE;
1112}
1113
1114static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
1115 struct genl_info *info)
1116{
1117 struct devlink *devlink = info->user_ptr[0];
1118 struct devlink_sb *devlink_sb = info->user_ptr[1];
1119 struct sk_buff *msg;
1120 u16 pool_index;
1121 int err;
1122
1123 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1124 &pool_index);
1125 if (err)
1126 return err;
1127
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001128 if (!devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001129 return -EOPNOTSUPP;
1130
1131 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1132 if (!msg)
1133 return -ENOMEM;
1134
1135 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
1136 DEVLINK_CMD_SB_POOL_NEW,
1137 info->snd_portid, info->snd_seq, 0);
1138 if (err) {
1139 nlmsg_free(msg);
1140 return err;
1141 }
1142
1143 return genlmsg_reply(msg, info);
1144}
1145
1146static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1147 struct devlink *devlink,
1148 struct devlink_sb *devlink_sb,
1149 u32 portid, u32 seq)
1150{
1151 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1152 u16 pool_index;
1153 int err;
1154
1155 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1156 if (*p_idx < start) {
1157 (*p_idx)++;
1158 continue;
1159 }
1160 err = devlink_nl_sb_pool_fill(msg, devlink,
1161 devlink_sb,
1162 pool_index,
1163 DEVLINK_CMD_SB_POOL_NEW,
1164 portid, seq, NLM_F_MULTI);
1165 if (err)
1166 return err;
1167 (*p_idx)++;
1168 }
1169 return 0;
1170}
1171
1172static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1173 struct netlink_callback *cb)
1174{
1175 struct devlink *devlink;
1176 struct devlink_sb *devlink_sb;
1177 int start = cb->args[0];
1178 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001179 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001180
1181 mutex_lock(&devlink_mutex);
1182 list_for_each_entry(devlink, &devlink_list, list) {
1183 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001184 !devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001185 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001186 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001187 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1188 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1189 devlink_sb,
1190 NETLINK_CB(cb->skb).portid,
1191 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001192 if (err && err != -EOPNOTSUPP) {
1193 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001194 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001195 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001196 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001197 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001198 }
1199out:
1200 mutex_unlock(&devlink_mutex);
1201
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001202 if (err != -EMSGSIZE)
1203 return err;
1204
Jiri Pirkobf797472016-04-14 18:19:13 +02001205 cb->args[0] = idx;
1206 return msg->len;
1207}
1208
1209static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1210 u16 pool_index, u32 size,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001211 enum devlink_sb_threshold_type threshold_type,
1212 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001213
1214{
1215 const struct devlink_ops *ops = devlink->ops;
1216
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001217 if (ops->sb_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001218 return ops->sb_pool_set(devlink, sb_index, pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001219 size, threshold_type, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001220 return -EOPNOTSUPP;
1221}
1222
1223static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1224 struct genl_info *info)
1225{
1226 struct devlink *devlink = info->user_ptr[0];
1227 struct devlink_sb *devlink_sb = info->user_ptr[1];
1228 enum devlink_sb_threshold_type threshold_type;
1229 u16 pool_index;
1230 u32 size;
1231 int err;
1232
1233 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1234 &pool_index);
1235 if (err)
1236 return err;
1237
1238 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1239 if (err)
1240 return err;
1241
1242 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1243 return -EINVAL;
1244
1245 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1246 return devlink_sb_pool_set(devlink, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001247 pool_index, size, threshold_type,
1248 info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001249}
1250
1251static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1252 struct devlink *devlink,
1253 struct devlink_port *devlink_port,
1254 struct devlink_sb *devlink_sb,
1255 u16 pool_index,
1256 enum devlink_command cmd,
1257 u32 portid, u32 seq, int flags)
1258{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001259 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001260 u32 threshold;
1261 void *hdr;
1262 int err;
1263
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001264 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1265 pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001266 if (err)
1267 return err;
1268
1269 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1270 if (!hdr)
1271 return -EMSGSIZE;
1272
1273 if (devlink_nl_put_handle(msg, devlink))
1274 goto nla_put_failure;
1275 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1276 goto nla_put_failure;
1277 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1278 goto nla_put_failure;
1279 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1280 goto nla_put_failure;
1281 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1282 goto nla_put_failure;
1283
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001284 if (ops->sb_occ_port_pool_get) {
1285 u32 cur;
1286 u32 max;
1287
1288 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1289 pool_index, &cur, &max);
1290 if (err && err != -EOPNOTSUPP)
1291 return err;
1292 if (!err) {
1293 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1294 goto nla_put_failure;
1295 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1296 goto nla_put_failure;
1297 }
1298 }
1299
Jiri Pirkobf797472016-04-14 18:19:13 +02001300 genlmsg_end(msg, hdr);
1301 return 0;
1302
1303nla_put_failure:
1304 genlmsg_cancel(msg, hdr);
1305 return -EMSGSIZE;
1306}
1307
1308static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1309 struct genl_info *info)
1310{
1311 struct devlink_port *devlink_port = info->user_ptr[0];
1312 struct devlink *devlink = devlink_port->devlink;
1313 struct devlink_sb *devlink_sb = info->user_ptr[1];
1314 struct sk_buff *msg;
1315 u16 pool_index;
1316 int err;
1317
1318 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1319 &pool_index);
1320 if (err)
1321 return err;
1322
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001323 if (!devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001324 return -EOPNOTSUPP;
1325
1326 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1327 if (!msg)
1328 return -ENOMEM;
1329
1330 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1331 devlink_sb, pool_index,
1332 DEVLINK_CMD_SB_PORT_POOL_NEW,
1333 info->snd_portid, info->snd_seq, 0);
1334 if (err) {
1335 nlmsg_free(msg);
1336 return err;
1337 }
1338
1339 return genlmsg_reply(msg, info);
1340}
1341
1342static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1343 struct devlink *devlink,
1344 struct devlink_sb *devlink_sb,
1345 u32 portid, u32 seq)
1346{
1347 struct devlink_port *devlink_port;
1348 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1349 u16 pool_index;
1350 int err;
1351
1352 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1353 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1354 if (*p_idx < start) {
1355 (*p_idx)++;
1356 continue;
1357 }
1358 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1359 devlink_port,
1360 devlink_sb,
1361 pool_index,
1362 DEVLINK_CMD_SB_PORT_POOL_NEW,
1363 portid, seq,
1364 NLM_F_MULTI);
1365 if (err)
1366 return err;
1367 (*p_idx)++;
1368 }
1369 }
1370 return 0;
1371}
1372
1373static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1374 struct netlink_callback *cb)
1375{
1376 struct devlink *devlink;
1377 struct devlink_sb *devlink_sb;
1378 int start = cb->args[0];
1379 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001380 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001381
1382 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001383 list_for_each_entry(devlink, &devlink_list, list) {
1384 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001385 !devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001386 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001387 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001388 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1389 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1390 devlink, devlink_sb,
1391 NETLINK_CB(cb->skb).portid,
1392 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001393 if (err && err != -EOPNOTSUPP) {
1394 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001395 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001396 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001397 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001398 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001399 }
1400out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001401 mutex_unlock(&devlink_mutex);
1402
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001403 if (err != -EMSGSIZE)
1404 return err;
1405
Jiri Pirkobf797472016-04-14 18:19:13 +02001406 cb->args[0] = idx;
1407 return msg->len;
1408}
1409
1410static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1411 unsigned int sb_index, u16 pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001412 u32 threshold,
1413 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001414
1415{
1416 const struct devlink_ops *ops = devlink_port->devlink->ops;
1417
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001418 if (ops->sb_port_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001419 return ops->sb_port_pool_set(devlink_port, sb_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001420 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001421 return -EOPNOTSUPP;
1422}
1423
1424static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1425 struct genl_info *info)
1426{
1427 struct devlink_port *devlink_port = info->user_ptr[0];
1428 struct devlink_sb *devlink_sb = info->user_ptr[1];
1429 u16 pool_index;
1430 u32 threshold;
1431 int err;
1432
1433 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1434 &pool_index);
1435 if (err)
1436 return err;
1437
1438 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1439 return -EINVAL;
1440
1441 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1442 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001443 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001444}
1445
1446static int
1447devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1448 struct devlink_port *devlink_port,
1449 struct devlink_sb *devlink_sb, u16 tc_index,
1450 enum devlink_sb_pool_type pool_type,
1451 enum devlink_command cmd,
1452 u32 portid, u32 seq, int flags)
1453{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001454 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001455 u16 pool_index;
1456 u32 threshold;
1457 void *hdr;
1458 int err;
1459
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001460 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1461 tc_index, pool_type,
1462 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001463 if (err)
1464 return err;
1465
1466 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1467 if (!hdr)
1468 return -EMSGSIZE;
1469
1470 if (devlink_nl_put_handle(msg, devlink))
1471 goto nla_put_failure;
1472 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1473 goto nla_put_failure;
1474 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1475 goto nla_put_failure;
1476 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1477 goto nla_put_failure;
1478 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1479 goto nla_put_failure;
1480 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1481 goto nla_put_failure;
1482 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1483 goto nla_put_failure;
1484
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001485 if (ops->sb_occ_tc_port_bind_get) {
1486 u32 cur;
1487 u32 max;
1488
1489 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1490 devlink_sb->index,
1491 tc_index, pool_type,
1492 &cur, &max);
1493 if (err && err != -EOPNOTSUPP)
1494 return err;
1495 if (!err) {
1496 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1497 goto nla_put_failure;
1498 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1499 goto nla_put_failure;
1500 }
1501 }
1502
Jiri Pirkobf797472016-04-14 18:19:13 +02001503 genlmsg_end(msg, hdr);
1504 return 0;
1505
1506nla_put_failure:
1507 genlmsg_cancel(msg, hdr);
1508 return -EMSGSIZE;
1509}
1510
1511static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1512 struct genl_info *info)
1513{
1514 struct devlink_port *devlink_port = info->user_ptr[0];
1515 struct devlink *devlink = devlink_port->devlink;
1516 struct devlink_sb *devlink_sb = info->user_ptr[1];
1517 struct sk_buff *msg;
1518 enum devlink_sb_pool_type pool_type;
1519 u16 tc_index;
1520 int err;
1521
1522 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1523 if (err)
1524 return err;
1525
1526 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1527 pool_type, &tc_index);
1528 if (err)
1529 return err;
1530
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001531 if (!devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001532 return -EOPNOTSUPP;
1533
1534 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1535 if (!msg)
1536 return -ENOMEM;
1537
1538 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1539 devlink_sb, tc_index, pool_type,
1540 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1541 info->snd_portid,
1542 info->snd_seq, 0);
1543 if (err) {
1544 nlmsg_free(msg);
1545 return err;
1546 }
1547
1548 return genlmsg_reply(msg, info);
1549}
1550
1551static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1552 int start, int *p_idx,
1553 struct devlink *devlink,
1554 struct devlink_sb *devlink_sb,
1555 u32 portid, u32 seq)
1556{
1557 struct devlink_port *devlink_port;
1558 u16 tc_index;
1559 int err;
1560
1561 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1562 for (tc_index = 0;
1563 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1564 if (*p_idx < start) {
1565 (*p_idx)++;
1566 continue;
1567 }
1568 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1569 devlink_port,
1570 devlink_sb,
1571 tc_index,
1572 DEVLINK_SB_POOL_TYPE_INGRESS,
1573 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1574 portid, seq,
1575 NLM_F_MULTI);
1576 if (err)
1577 return err;
1578 (*p_idx)++;
1579 }
1580 for (tc_index = 0;
1581 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1582 if (*p_idx < start) {
1583 (*p_idx)++;
1584 continue;
1585 }
1586 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1587 devlink_port,
1588 devlink_sb,
1589 tc_index,
1590 DEVLINK_SB_POOL_TYPE_EGRESS,
1591 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1592 portid, seq,
1593 NLM_F_MULTI);
1594 if (err)
1595 return err;
1596 (*p_idx)++;
1597 }
1598 }
1599 return 0;
1600}
1601
1602static int
1603devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1604 struct netlink_callback *cb)
1605{
1606 struct devlink *devlink;
1607 struct devlink_sb *devlink_sb;
1608 int start = cb->args[0];
1609 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001610 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001611
1612 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001613 list_for_each_entry(devlink, &devlink_list, list) {
1614 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001615 !devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001616 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001617
1618 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001619 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1620 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1621 devlink,
1622 devlink_sb,
1623 NETLINK_CB(cb->skb).portid,
1624 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001625 if (err && err != -EOPNOTSUPP) {
1626 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001627 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001628 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001629 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001630 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001631 }
1632out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001633 mutex_unlock(&devlink_mutex);
1634
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001635 if (err != -EMSGSIZE)
1636 return err;
1637
Jiri Pirkobf797472016-04-14 18:19:13 +02001638 cb->args[0] = idx;
1639 return msg->len;
1640}
1641
1642static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1643 unsigned int sb_index, u16 tc_index,
1644 enum devlink_sb_pool_type pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001645 u16 pool_index, u32 threshold,
1646 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001647
1648{
1649 const struct devlink_ops *ops = devlink_port->devlink->ops;
1650
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001651 if (ops->sb_tc_pool_bind_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001652 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1653 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001654 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001655 return -EOPNOTSUPP;
1656}
1657
1658static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1659 struct genl_info *info)
1660{
1661 struct devlink_port *devlink_port = info->user_ptr[0];
1662 struct devlink_sb *devlink_sb = info->user_ptr[1];
1663 enum devlink_sb_pool_type pool_type;
1664 u16 tc_index;
1665 u16 pool_index;
1666 u32 threshold;
1667 int err;
1668
1669 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1670 if (err)
1671 return err;
1672
1673 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1674 pool_type, &tc_index);
1675 if (err)
1676 return err;
1677
1678 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1679 &pool_index);
1680 if (err)
1681 return err;
1682
1683 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1684 return -EINVAL;
1685
1686 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1687 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1688 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001689 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001690}
1691
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001692static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1693 struct genl_info *info)
1694{
1695 struct devlink *devlink = info->user_ptr[0];
1696 struct devlink_sb *devlink_sb = info->user_ptr[1];
1697 const struct devlink_ops *ops = devlink->ops;
1698
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001699 if (ops->sb_occ_snapshot)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001700 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1701 return -EOPNOTSUPP;
1702}
1703
1704static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1705 struct genl_info *info)
1706{
1707 struct devlink *devlink = info->user_ptr[0];
1708 struct devlink_sb *devlink_sb = info->user_ptr[1];
1709 const struct devlink_ops *ops = devlink->ops;
1710
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001711 if (ops->sb_occ_max_clear)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001712 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1713 return -EOPNOTSUPP;
1714}
1715
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001716static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1717 enum devlink_command cmd, u32 portid,
1718 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001719{
Roi Dayan59bfde02016-11-22 23:09:57 +02001720 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001721 enum devlink_eswitch_encap_mode encap_mode;
1722 u8 inline_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001723 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001724 int err = 0;
1725 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001726
1727 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1728 if (!hdr)
1729 return -EMSGSIZE;
1730
Roi Dayan59bfde02016-11-22 23:09:57 +02001731 err = devlink_nl_put_handle(msg, devlink);
1732 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001733 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001734
Jiri Pirko4456f612017-02-09 15:54:36 +01001735 if (ops->eswitch_mode_get) {
1736 err = ops->eswitch_mode_get(devlink, &mode);
1737 if (err)
1738 goto nla_put_failure;
1739 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1740 if (err)
1741 goto nla_put_failure;
1742 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001743
1744 if (ops->eswitch_inline_mode_get) {
1745 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1746 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001747 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001748 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1749 inline_mode);
1750 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001751 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001752 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001753
Roi Dayanf43e9b02016-09-25 13:52:44 +03001754 if (ops->eswitch_encap_mode_get) {
1755 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1756 if (err)
1757 goto nla_put_failure;
1758 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1759 if (err)
1760 goto nla_put_failure;
1761 }
1762
Or Gerlitz08f4b592016-07-01 14:51:01 +03001763 genlmsg_end(msg, hdr);
1764 return 0;
1765
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001766nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001767 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001768 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001769}
1770
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001771static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1772 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001773{
1774 struct devlink *devlink = info->user_ptr[0];
Or Gerlitz08f4b592016-07-01 14:51:01 +03001775 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001776 int err;
1777
Or Gerlitz08f4b592016-07-01 14:51:01 +03001778 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1779 if (!msg)
1780 return -ENOMEM;
1781
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001782 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1783 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001784
1785 if (err) {
1786 nlmsg_free(msg);
1787 return err;
1788 }
1789
1790 return genlmsg_reply(msg, info);
1791}
1792
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001793static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1794 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001795{
1796 struct devlink *devlink = info->user_ptr[0];
1797 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001798 enum devlink_eswitch_encap_mode encap_mode;
1799 u8 inline_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001800 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001801 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001802
Roi Dayan59bfde02016-11-22 23:09:57 +02001803 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1804 if (!ops->eswitch_mode_set)
1805 return -EOPNOTSUPP;
1806 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001807 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001808 if (err)
1809 return err;
1810 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001811
Roi Dayan59bfde02016-11-22 23:09:57 +02001812 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1813 if (!ops->eswitch_inline_mode_set)
1814 return -EOPNOTSUPP;
1815 inline_mode = nla_get_u8(
1816 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001817 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1818 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001819 if (err)
1820 return err;
1821 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03001822
1823 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1824 if (!ops->eswitch_encap_mode_set)
1825 return -EOPNOTSUPP;
1826 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001827 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1828 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03001829 if (err)
1830 return err;
1831 }
1832
Roi Dayan59bfde02016-11-22 23:09:57 +02001833 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001834}
1835
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001836int devlink_dpipe_match_put(struct sk_buff *skb,
1837 struct devlink_dpipe_match *match)
1838{
1839 struct devlink_dpipe_header *header = match->header;
1840 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1841 struct nlattr *match_attr;
1842
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001843 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001844 if (!match_attr)
1845 return -EMSGSIZE;
1846
1847 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1848 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1849 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1850 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1851 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1852 goto nla_put_failure;
1853
1854 nla_nest_end(skb, match_attr);
1855 return 0;
1856
1857nla_put_failure:
1858 nla_nest_cancel(skb, match_attr);
1859 return -EMSGSIZE;
1860}
1861EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1862
1863static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1864 struct sk_buff *skb)
1865{
1866 struct nlattr *matches_attr;
1867
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001868 matches_attr = nla_nest_start_noflag(skb,
1869 DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001870 if (!matches_attr)
1871 return -EMSGSIZE;
1872
1873 if (table->table_ops->matches_dump(table->priv, skb))
1874 goto nla_put_failure;
1875
1876 nla_nest_end(skb, matches_attr);
1877 return 0;
1878
1879nla_put_failure:
1880 nla_nest_cancel(skb, matches_attr);
1881 return -EMSGSIZE;
1882}
1883
1884int devlink_dpipe_action_put(struct sk_buff *skb,
1885 struct devlink_dpipe_action *action)
1886{
1887 struct devlink_dpipe_header *header = action->header;
1888 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1889 struct nlattr *action_attr;
1890
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001891 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001892 if (!action_attr)
1893 return -EMSGSIZE;
1894
1895 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1896 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1897 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1898 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1899 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1900 goto nla_put_failure;
1901
1902 nla_nest_end(skb, action_attr);
1903 return 0;
1904
1905nla_put_failure:
1906 nla_nest_cancel(skb, action_attr);
1907 return -EMSGSIZE;
1908}
1909EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1910
1911static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1912 struct sk_buff *skb)
1913{
1914 struct nlattr *actions_attr;
1915
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001916 actions_attr = nla_nest_start_noflag(skb,
1917 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001918 if (!actions_attr)
1919 return -EMSGSIZE;
1920
1921 if (table->table_ops->actions_dump(table->priv, skb))
1922 goto nla_put_failure;
1923
1924 nla_nest_end(skb, actions_attr);
1925 return 0;
1926
1927nla_put_failure:
1928 nla_nest_cancel(skb, actions_attr);
1929 return -EMSGSIZE;
1930}
1931
1932static int devlink_dpipe_table_put(struct sk_buff *skb,
1933 struct devlink_dpipe_table *table)
1934{
1935 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001936 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001937
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001938 table_size = table->table_ops->size_get(table->priv);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001939 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001940 if (!table_attr)
1941 return -EMSGSIZE;
1942
1943 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001944 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001945 DEVLINK_ATTR_PAD))
1946 goto nla_put_failure;
1947 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1948 table->counters_enabled))
1949 goto nla_put_failure;
1950
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001951 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02001952 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1953 table->resource_id, DEVLINK_ATTR_PAD) ||
1954 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1955 table->resource_units, DEVLINK_ATTR_PAD))
1956 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001957 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001958 if (devlink_dpipe_matches_put(table, skb))
1959 goto nla_put_failure;
1960
1961 if (devlink_dpipe_actions_put(table, skb))
1962 goto nla_put_failure;
1963
1964 nla_nest_end(skb, table_attr);
1965 return 0;
1966
1967nla_put_failure:
1968 nla_nest_cancel(skb, table_attr);
1969 return -EMSGSIZE;
1970}
1971
1972static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1973 struct genl_info *info)
1974{
1975 int err;
1976
1977 if (*pskb) {
1978 err = genlmsg_reply(*pskb, info);
1979 if (err)
1980 return err;
1981 }
1982 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1983 if (!*pskb)
1984 return -ENOMEM;
1985 return 0;
1986}
1987
1988static int devlink_dpipe_tables_fill(struct genl_info *info,
1989 enum devlink_command cmd, int flags,
1990 struct list_head *dpipe_tables,
1991 const char *table_name)
1992{
1993 struct devlink *devlink = info->user_ptr[0];
1994 struct devlink_dpipe_table *table;
1995 struct nlattr *tables_attr;
1996 struct sk_buff *skb = NULL;
1997 struct nlmsghdr *nlh;
1998 bool incomplete;
1999 void *hdr;
2000 int i;
2001 int err;
2002
2003 table = list_first_entry(dpipe_tables,
2004 struct devlink_dpipe_table, list);
2005start_again:
2006 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2007 if (err)
2008 return err;
2009
2010 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2011 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002012 if (!hdr) {
2013 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002014 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002015 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002016
2017 if (devlink_nl_put_handle(skb, devlink))
2018 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002019 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002020 if (!tables_attr)
2021 goto nla_put_failure;
2022
2023 i = 0;
2024 incomplete = false;
2025 list_for_each_entry_from(table, dpipe_tables, list) {
2026 if (!table_name) {
2027 err = devlink_dpipe_table_put(skb, table);
2028 if (err) {
2029 if (!i)
2030 goto err_table_put;
2031 incomplete = true;
2032 break;
2033 }
2034 } else {
2035 if (!strcmp(table->name, table_name)) {
2036 err = devlink_dpipe_table_put(skb, table);
2037 if (err)
2038 break;
2039 }
2040 }
2041 i++;
2042 }
2043
2044 nla_nest_end(skb, tables_attr);
2045 genlmsg_end(skb, hdr);
2046 if (incomplete)
2047 goto start_again;
2048
2049send_done:
2050 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2051 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2052 if (!nlh) {
2053 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2054 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002055 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002056 goto send_done;
2057 }
2058
2059 return genlmsg_reply(skb, info);
2060
2061nla_put_failure:
2062 err = -EMSGSIZE;
2063err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002064 nlmsg_free(skb);
2065 return err;
2066}
2067
2068static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
2069 struct genl_info *info)
2070{
2071 struct devlink *devlink = info->user_ptr[0];
2072 const char *table_name = NULL;
2073
2074 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2075 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2076
2077 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
2078 &devlink->dpipe_table_list,
2079 table_name);
2080}
2081
2082static int devlink_dpipe_value_put(struct sk_buff *skb,
2083 struct devlink_dpipe_value *value)
2084{
2085 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
2086 value->value_size, value->value))
2087 return -EMSGSIZE;
2088 if (value->mask)
2089 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
2090 value->value_size, value->mask))
2091 return -EMSGSIZE;
2092 if (value->mapping_valid)
2093 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
2094 value->mapping_value))
2095 return -EMSGSIZE;
2096 return 0;
2097}
2098
2099static int devlink_dpipe_action_value_put(struct sk_buff *skb,
2100 struct devlink_dpipe_value *value)
2101{
2102 if (!value->action)
2103 return -EINVAL;
2104 if (devlink_dpipe_action_put(skb, value->action))
2105 return -EMSGSIZE;
2106 if (devlink_dpipe_value_put(skb, value))
2107 return -EMSGSIZE;
2108 return 0;
2109}
2110
2111static int devlink_dpipe_action_values_put(struct sk_buff *skb,
2112 struct devlink_dpipe_value *values,
2113 unsigned int values_count)
2114{
2115 struct nlattr *action_attr;
2116 int i;
2117 int err;
2118
2119 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002120 action_attr = nla_nest_start_noflag(skb,
2121 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002122 if (!action_attr)
2123 return -EMSGSIZE;
2124 err = devlink_dpipe_action_value_put(skb, &values[i]);
2125 if (err)
2126 goto err_action_value_put;
2127 nla_nest_end(skb, action_attr);
2128 }
2129 return 0;
2130
2131err_action_value_put:
2132 nla_nest_cancel(skb, action_attr);
2133 return err;
2134}
2135
2136static int devlink_dpipe_match_value_put(struct sk_buff *skb,
2137 struct devlink_dpipe_value *value)
2138{
2139 if (!value->match)
2140 return -EINVAL;
2141 if (devlink_dpipe_match_put(skb, value->match))
2142 return -EMSGSIZE;
2143 if (devlink_dpipe_value_put(skb, value))
2144 return -EMSGSIZE;
2145 return 0;
2146}
2147
2148static int devlink_dpipe_match_values_put(struct sk_buff *skb,
2149 struct devlink_dpipe_value *values,
2150 unsigned int values_count)
2151{
2152 struct nlattr *match_attr;
2153 int i;
2154 int err;
2155
2156 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002157 match_attr = nla_nest_start_noflag(skb,
2158 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002159 if (!match_attr)
2160 return -EMSGSIZE;
2161 err = devlink_dpipe_match_value_put(skb, &values[i]);
2162 if (err)
2163 goto err_match_value_put;
2164 nla_nest_end(skb, match_attr);
2165 }
2166 return 0;
2167
2168err_match_value_put:
2169 nla_nest_cancel(skb, match_attr);
2170 return err;
2171}
2172
2173static int devlink_dpipe_entry_put(struct sk_buff *skb,
2174 struct devlink_dpipe_entry *entry)
2175{
2176 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2177 int err;
2178
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002179 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002180 if (!entry_attr)
2181 return -EMSGSIZE;
2182
2183 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2184 DEVLINK_ATTR_PAD))
2185 goto nla_put_failure;
2186 if (entry->counter_valid)
2187 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2188 entry->counter, DEVLINK_ATTR_PAD))
2189 goto nla_put_failure;
2190
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002191 matches_attr = nla_nest_start_noflag(skb,
2192 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002193 if (!matches_attr)
2194 goto nla_put_failure;
2195
2196 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2197 entry->match_values_count);
2198 if (err) {
2199 nla_nest_cancel(skb, matches_attr);
2200 goto err_match_values_put;
2201 }
2202 nla_nest_end(skb, matches_attr);
2203
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002204 actions_attr = nla_nest_start_noflag(skb,
2205 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002206 if (!actions_attr)
2207 goto nla_put_failure;
2208
2209 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2210 entry->action_values_count);
2211 if (err) {
2212 nla_nest_cancel(skb, actions_attr);
2213 goto err_action_values_put;
2214 }
2215 nla_nest_end(skb, actions_attr);
2216
2217 nla_nest_end(skb, entry_attr);
2218 return 0;
2219
2220nla_put_failure:
2221 err = -EMSGSIZE;
2222err_match_values_put:
2223err_action_values_put:
2224 nla_nest_cancel(skb, entry_attr);
2225 return err;
2226}
2227
2228static struct devlink_dpipe_table *
2229devlink_dpipe_table_find(struct list_head *dpipe_tables,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302230 const char *table_name, struct devlink *devlink)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002231{
2232 struct devlink_dpipe_table *table;
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302233 list_for_each_entry_rcu(table, dpipe_tables, list,
2234 lockdep_is_held(&devlink->lock)) {
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002235 if (!strcmp(table->name, table_name))
2236 return table;
2237 }
2238 return NULL;
2239}
2240
2241int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2242{
2243 struct devlink *devlink;
2244 int err;
2245
2246 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2247 dump_ctx->info);
2248 if (err)
2249 return err;
2250
2251 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2252 dump_ctx->info->snd_portid,
2253 dump_ctx->info->snd_seq,
2254 &devlink_nl_family, NLM_F_MULTI,
2255 dump_ctx->cmd);
2256 if (!dump_ctx->hdr)
2257 goto nla_put_failure;
2258
2259 devlink = dump_ctx->info->user_ptr[0];
2260 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2261 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002262 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2263 DEVLINK_ATTR_DPIPE_ENTRIES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002264 if (!dump_ctx->nest)
2265 goto nla_put_failure;
2266 return 0;
2267
2268nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002269 nlmsg_free(dump_ctx->skb);
2270 return -EMSGSIZE;
2271}
2272EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2273
2274int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2275 struct devlink_dpipe_entry *entry)
2276{
2277 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2278}
2279EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2280
2281int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2282{
2283 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2284 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2285 return 0;
2286}
2287EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2288
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002289void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2290
2291{
2292 unsigned int value_count, value_index;
2293 struct devlink_dpipe_value *value;
2294
2295 value = entry->action_values;
2296 value_count = entry->action_values_count;
2297 for (value_index = 0; value_index < value_count; value_index++) {
2298 kfree(value[value_index].value);
2299 kfree(value[value_index].mask);
2300 }
2301
2302 value = entry->match_values;
2303 value_count = entry->match_values_count;
2304 for (value_index = 0; value_index < value_count; value_index++) {
2305 kfree(value[value_index].value);
2306 kfree(value[value_index].mask);
2307 }
2308}
2309EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2310
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002311static int devlink_dpipe_entries_fill(struct genl_info *info,
2312 enum devlink_command cmd, int flags,
2313 struct devlink_dpipe_table *table)
2314{
2315 struct devlink_dpipe_dump_ctx dump_ctx;
2316 struct nlmsghdr *nlh;
2317 int err;
2318
2319 dump_ctx.skb = NULL;
2320 dump_ctx.cmd = cmd;
2321 dump_ctx.info = info;
2322
2323 err = table->table_ops->entries_dump(table->priv,
2324 table->counters_enabled,
2325 &dump_ctx);
2326 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002327 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002328
2329send_done:
2330 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2331 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2332 if (!nlh) {
2333 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2334 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002335 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002336 goto send_done;
2337 }
2338 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002339}
2340
2341static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2342 struct genl_info *info)
2343{
2344 struct devlink *devlink = info->user_ptr[0];
2345 struct devlink_dpipe_table *table;
2346 const char *table_name;
2347
2348 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2349 return -EINVAL;
2350
2351 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2352 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302353 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002354 if (!table)
2355 return -EINVAL;
2356
2357 if (!table->table_ops->entries_dump)
2358 return -EINVAL;
2359
2360 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2361 0, table);
2362}
2363
2364static int devlink_dpipe_fields_put(struct sk_buff *skb,
2365 const struct devlink_dpipe_header *header)
2366{
2367 struct devlink_dpipe_field *field;
2368 struct nlattr *field_attr;
2369 int i;
2370
2371 for (i = 0; i < header->fields_count; i++) {
2372 field = &header->fields[i];
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002373 field_attr = nla_nest_start_noflag(skb,
2374 DEVLINK_ATTR_DPIPE_FIELD);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002375 if (!field_attr)
2376 return -EMSGSIZE;
2377 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2378 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2379 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2380 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2381 goto nla_put_failure;
2382 nla_nest_end(skb, field_attr);
2383 }
2384 return 0;
2385
2386nla_put_failure:
2387 nla_nest_cancel(skb, field_attr);
2388 return -EMSGSIZE;
2389}
2390
2391static int devlink_dpipe_header_put(struct sk_buff *skb,
2392 struct devlink_dpipe_header *header)
2393{
2394 struct nlattr *fields_attr, *header_attr;
2395 int err;
2396
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002397 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002398 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002399 return -EMSGSIZE;
2400
2401 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2402 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2403 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2404 goto nla_put_failure;
2405
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002406 fields_attr = nla_nest_start_noflag(skb,
2407 DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002408 if (!fields_attr)
2409 goto nla_put_failure;
2410
2411 err = devlink_dpipe_fields_put(skb, header);
2412 if (err) {
2413 nla_nest_cancel(skb, fields_attr);
2414 goto nla_put_failure;
2415 }
2416 nla_nest_end(skb, fields_attr);
2417 nla_nest_end(skb, header_attr);
2418 return 0;
2419
2420nla_put_failure:
2421 err = -EMSGSIZE;
2422 nla_nest_cancel(skb, header_attr);
2423 return err;
2424}
2425
2426static int devlink_dpipe_headers_fill(struct genl_info *info,
2427 enum devlink_command cmd, int flags,
2428 struct devlink_dpipe_headers *
2429 dpipe_headers)
2430{
2431 struct devlink *devlink = info->user_ptr[0];
2432 struct nlattr *headers_attr;
2433 struct sk_buff *skb = NULL;
2434 struct nlmsghdr *nlh;
2435 void *hdr;
2436 int i, j;
2437 int err;
2438
2439 i = 0;
2440start_again:
2441 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2442 if (err)
2443 return err;
2444
2445 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2446 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002447 if (!hdr) {
2448 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002449 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002450 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002451
2452 if (devlink_nl_put_handle(skb, devlink))
2453 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002454 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002455 if (!headers_attr)
2456 goto nla_put_failure;
2457
2458 j = 0;
2459 for (; i < dpipe_headers->headers_count; i++) {
2460 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2461 if (err) {
2462 if (!j)
2463 goto err_table_put;
2464 break;
2465 }
2466 j++;
2467 }
2468 nla_nest_end(skb, headers_attr);
2469 genlmsg_end(skb, hdr);
2470 if (i != dpipe_headers->headers_count)
2471 goto start_again;
2472
2473send_done:
2474 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2475 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2476 if (!nlh) {
2477 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2478 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002479 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002480 goto send_done;
2481 }
2482 return genlmsg_reply(skb, info);
2483
2484nla_put_failure:
2485 err = -EMSGSIZE;
2486err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002487 nlmsg_free(skb);
2488 return err;
2489}
2490
2491static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2492 struct genl_info *info)
2493{
2494 struct devlink *devlink = info->user_ptr[0];
2495
2496 if (!devlink->dpipe_headers)
2497 return -EOPNOTSUPP;
2498 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2499 0, devlink->dpipe_headers);
2500}
2501
2502static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2503 const char *table_name,
2504 bool enable)
2505{
2506 struct devlink_dpipe_table *table;
2507
2508 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302509 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002510 if (!table)
2511 return -EINVAL;
2512
2513 if (table->counter_control_extern)
2514 return -EOPNOTSUPP;
2515
2516 if (!(table->counters_enabled ^ enable))
2517 return 0;
2518
2519 table->counters_enabled = enable;
2520 if (table->table_ops->counters_set_update)
2521 table->table_ops->counters_set_update(table->priv, enable);
2522 return 0;
2523}
2524
2525static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2526 struct genl_info *info)
2527{
2528 struct devlink *devlink = info->user_ptr[0];
2529 const char *table_name;
2530 bool counters_enable;
2531
2532 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2533 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2534 return -EINVAL;
2535
2536 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2537 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2538
2539 return devlink_dpipe_table_counters_set(devlink, table_name,
2540 counters_enable);
2541}
2542
Wei Yongjun43dd7512018-01-17 03:27:42 +00002543static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002544devlink_resource_find(struct devlink *devlink,
2545 struct devlink_resource *resource, u64 resource_id)
2546{
2547 struct list_head *resource_list;
2548
2549 if (resource)
2550 resource_list = &resource->resource_list;
2551 else
2552 resource_list = &devlink->resource_list;
2553
2554 list_for_each_entry(resource, resource_list, list) {
2555 struct devlink_resource *child_resource;
2556
2557 if (resource->id == resource_id)
2558 return resource;
2559
2560 child_resource = devlink_resource_find(devlink, resource,
2561 resource_id);
2562 if (child_resource)
2563 return child_resource;
2564 }
2565 return NULL;
2566}
2567
Wei Yongjun43dd7512018-01-17 03:27:42 +00002568static void
2569devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002570{
2571 struct devlink_resource *child_resource;
2572 bool size_valid = true;
2573 u64 parts_size = 0;
2574
2575 if (list_empty(&resource->resource_list))
2576 goto out;
2577
2578 list_for_each_entry(child_resource, &resource->resource_list, list)
2579 parts_size += child_resource->size_new;
2580
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002581 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002582 size_valid = false;
2583out:
2584 resource->size_valid = size_valid;
2585}
2586
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002587static int
2588devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2589 struct netlink_ext_ack *extack)
2590{
2591 u64 reminder;
2592 int err = 0;
2593
David S. Miller0f3e9c92018-03-06 00:53:44 -05002594 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002595 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2596 err = -EINVAL;
2597 }
2598
David S. Miller0f3e9c92018-03-06 00:53:44 -05002599 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002600 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2601 err = -EINVAL;
2602 }
2603
David S. Miller0f3e9c92018-03-06 00:53:44 -05002604 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002605 if (reminder) {
2606 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2607 err = -EINVAL;
2608 }
2609
2610 return err;
2611}
2612
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002613static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2614 struct genl_info *info)
2615{
2616 struct devlink *devlink = info->user_ptr[0];
2617 struct devlink_resource *resource;
2618 u64 resource_id;
2619 u64 size;
2620 int err;
2621
2622 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2623 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2624 return -EINVAL;
2625 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2626
2627 resource = devlink_resource_find(devlink, NULL, resource_id);
2628 if (!resource)
2629 return -EINVAL;
2630
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002631 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002632 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002633 if (err)
2634 return err;
2635
2636 resource->size_new = size;
2637 devlink_resource_validate_children(resource);
2638 if (resource->parent)
2639 devlink_resource_validate_children(resource->parent);
2640 return 0;
2641}
2642
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002643static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002644devlink_resource_size_params_put(struct devlink_resource *resource,
2645 struct sk_buff *skb)
2646{
2647 struct devlink_resource_size_params *size_params;
2648
Jiri Pirko77d27092018-02-28 13:12:09 +01002649 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002650 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2651 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2652 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2653 size_params->size_max, DEVLINK_ATTR_PAD) ||
2654 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2655 size_params->size_min, DEVLINK_ATTR_PAD) ||
2656 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2657 return -EMSGSIZE;
2658 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002659}
2660
Jiri Pirkofc56be42018-04-05 22:13:21 +02002661static int devlink_resource_occ_put(struct devlink_resource *resource,
2662 struct sk_buff *skb)
2663{
2664 if (!resource->occ_get)
2665 return 0;
2666 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2667 resource->occ_get(resource->occ_get_priv),
2668 DEVLINK_ATTR_PAD);
2669}
2670
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002671static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2672 struct devlink_resource *resource)
2673{
2674 struct devlink_resource *child_resource;
2675 struct nlattr *child_resource_attr;
2676 struct nlattr *resource_attr;
2677
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002678 resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002679 if (!resource_attr)
2680 return -EMSGSIZE;
2681
2682 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2683 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2684 DEVLINK_ATTR_PAD) ||
2685 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2686 DEVLINK_ATTR_PAD))
2687 goto nla_put_failure;
2688 if (resource->size != resource->size_new)
2689 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2690 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002691 if (devlink_resource_occ_put(resource, skb))
2692 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002693 if (devlink_resource_size_params_put(resource, skb))
2694 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002695 if (list_empty(&resource->resource_list))
2696 goto out;
2697
2698 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2699 resource->size_valid))
2700 goto nla_put_failure;
2701
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002702 child_resource_attr = nla_nest_start_noflag(skb,
2703 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002704 if (!child_resource_attr)
2705 goto nla_put_failure;
2706
2707 list_for_each_entry(child_resource, &resource->resource_list, list) {
2708 if (devlink_resource_put(devlink, skb, child_resource))
2709 goto resource_put_failure;
2710 }
2711
2712 nla_nest_end(skb, child_resource_attr);
2713out:
2714 nla_nest_end(skb, resource_attr);
2715 return 0;
2716
2717resource_put_failure:
2718 nla_nest_cancel(skb, child_resource_attr);
2719nla_put_failure:
2720 nla_nest_cancel(skb, resource_attr);
2721 return -EMSGSIZE;
2722}
2723
2724static int devlink_resource_fill(struct genl_info *info,
2725 enum devlink_command cmd, int flags)
2726{
2727 struct devlink *devlink = info->user_ptr[0];
2728 struct devlink_resource *resource;
2729 struct nlattr *resources_attr;
2730 struct sk_buff *skb = NULL;
2731 struct nlmsghdr *nlh;
2732 bool incomplete;
2733 void *hdr;
2734 int i;
2735 int err;
2736
2737 resource = list_first_entry(&devlink->resource_list,
2738 struct devlink_resource, list);
2739start_again:
2740 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2741 if (err)
2742 return err;
2743
2744 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2745 &devlink_nl_family, NLM_F_MULTI, cmd);
2746 if (!hdr) {
2747 nlmsg_free(skb);
2748 return -EMSGSIZE;
2749 }
2750
2751 if (devlink_nl_put_handle(skb, devlink))
2752 goto nla_put_failure;
2753
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002754 resources_attr = nla_nest_start_noflag(skb,
2755 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002756 if (!resources_attr)
2757 goto nla_put_failure;
2758
2759 incomplete = false;
2760 i = 0;
2761 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2762 err = devlink_resource_put(devlink, skb, resource);
2763 if (err) {
2764 if (!i)
2765 goto err_resource_put;
2766 incomplete = true;
2767 break;
2768 }
2769 i++;
2770 }
2771 nla_nest_end(skb, resources_attr);
2772 genlmsg_end(skb, hdr);
2773 if (incomplete)
2774 goto start_again;
2775send_done:
2776 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2777 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2778 if (!nlh) {
2779 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2780 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002781 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002782 goto send_done;
2783 }
2784 return genlmsg_reply(skb, info);
2785
2786nla_put_failure:
2787 err = -EMSGSIZE;
2788err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002789 nlmsg_free(skb);
2790 return err;
2791}
2792
2793static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2794 struct genl_info *info)
2795{
2796 struct devlink *devlink = info->user_ptr[0];
2797
2798 if (list_empty(&devlink->resource_list))
2799 return -EOPNOTSUPP;
2800
2801 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2802}
2803
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002804static int
2805devlink_resources_validate(struct devlink *devlink,
2806 struct devlink_resource *resource,
2807 struct genl_info *info)
2808{
2809 struct list_head *resource_list;
2810 int err = 0;
2811
2812 if (resource)
2813 resource_list = &resource->resource_list;
2814 else
2815 resource_list = &devlink->resource_list;
2816
2817 list_for_each_entry(resource, resource_list, list) {
2818 if (!resource->size_valid)
2819 return -EINVAL;
2820 err = devlink_resources_validate(devlink, resource, info);
2821 if (err)
2822 return err;
2823 }
2824 return err;
2825}
2826
Jiri Pirko070c63f2019-10-03 11:49:39 +02002827static struct net *devlink_netns_get(struct sk_buff *skb,
2828 struct genl_info *info)
2829{
2830 struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID];
2831 struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD];
2832 struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID];
2833 struct net *net;
2834
2835 if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) {
Jiri Pirko054eae82020-03-28 19:25:29 +01002836 NL_SET_ERR_MSG_MOD(info->extack, "multiple netns identifying attributes specified");
Jiri Pirko070c63f2019-10-03 11:49:39 +02002837 return ERR_PTR(-EINVAL);
2838 }
2839
2840 if (netns_pid_attr) {
2841 net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr));
2842 } else if (netns_fd_attr) {
2843 net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr));
2844 } else if (netns_id_attr) {
2845 net = get_net_ns_by_id(sock_net(skb->sk),
2846 nla_get_u32(netns_id_attr));
2847 if (!net)
2848 net = ERR_PTR(-EINVAL);
2849 } else {
2850 WARN_ON(1);
2851 net = ERR_PTR(-EINVAL);
2852 }
2853 if (IS_ERR(net)) {
Jiri Pirko054eae82020-03-28 19:25:29 +01002854 NL_SET_ERR_MSG_MOD(info->extack, "Unknown network namespace");
Jiri Pirko070c63f2019-10-03 11:49:39 +02002855 return ERR_PTR(-EINVAL);
2856 }
2857 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
2858 put_net(net);
2859 return ERR_PTR(-EPERM);
2860 }
2861 return net;
2862}
2863
2864static void devlink_param_notify(struct devlink *devlink,
2865 unsigned int port_index,
2866 struct devlink_param_item *param_item,
2867 enum devlink_command cmd);
2868
2869static void devlink_reload_netns_change(struct devlink *devlink,
2870 struct net *dest_net)
2871{
2872 struct devlink_param_item *param_item;
2873
2874 /* Userspace needs to be notified about devlink objects
2875 * removed from original and entering new network namespace.
2876 * The rest of the devlink objects are re-created during
2877 * reload process so the notifications are generated separatelly.
2878 */
2879
2880 list_for_each_entry(param_item, &devlink->param_list, list)
2881 devlink_param_notify(devlink, 0, param_item,
2882 DEVLINK_CMD_PARAM_DEL);
2883 devlink_notify(devlink, DEVLINK_CMD_DEL);
2884
Jiri Pirko8273fd82019-10-05 08:10:31 +02002885 __devlink_net_set(devlink, dest_net);
Jiri Pirko070c63f2019-10-03 11:49:39 +02002886
2887 devlink_notify(devlink, DEVLINK_CMD_NEW);
2888 list_for_each_entry(param_item, &devlink->param_list, list)
2889 devlink_param_notify(devlink, 0, param_item,
2890 DEVLINK_CMD_PARAM_NEW);
2891}
2892
Jiri Pirko97691062019-09-12 10:49:45 +02002893static bool devlink_reload_supported(struct devlink *devlink)
2894{
2895 return devlink->ops->reload_down && devlink->ops->reload_up;
2896}
2897
Jiri Pirko2670ac22019-09-12 10:49:46 +02002898static void devlink_reload_failed_set(struct devlink *devlink,
2899 bool reload_failed)
2900{
2901 if (devlink->reload_failed == reload_failed)
2902 return;
2903 devlink->reload_failed = reload_failed;
2904 devlink_notify(devlink, DEVLINK_CMD_NEW);
2905}
2906
2907bool devlink_is_reload_failed(const struct devlink *devlink)
2908{
2909 return devlink->reload_failed;
2910}
2911EXPORT_SYMBOL_GPL(devlink_is_reload_failed);
2912
Jiri Pirko070c63f2019-10-03 11:49:39 +02002913static int devlink_reload(struct devlink *devlink, struct net *dest_net,
2914 struct netlink_ext_ack *extack)
2915{
2916 int err;
2917
Jiri Pirkoa0c76342019-11-08 21:42:43 +01002918 if (!devlink->reload_enabled)
2919 return -EOPNOTSUPP;
2920
Jiri Pirko070c63f2019-10-03 11:49:39 +02002921 err = devlink->ops->reload_down(devlink, !!dest_net, extack);
2922 if (err)
2923 return err;
2924
2925 if (dest_net && !net_eq(dest_net, devlink_net(devlink)))
2926 devlink_reload_netns_change(devlink, dest_net);
2927
2928 err = devlink->ops->reload_up(devlink, extack);
2929 devlink_reload_failed_set(devlink, !!err);
2930 return err;
2931}
2932
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002933static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2934{
2935 struct devlink *devlink = info->user_ptr[0];
Jiri Pirko070c63f2019-10-03 11:49:39 +02002936 struct net *dest_net = NULL;
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002937 int err;
2938
Jiri Pirko5a508a22019-11-09 11:29:46 +01002939 if (!devlink_reload_supported(devlink) || !devlink->reload_enabled)
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002940 return -EOPNOTSUPP;
2941
2942 err = devlink_resources_validate(devlink, NULL, info);
2943 if (err) {
2944 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2945 return err;
2946 }
Jiri Pirko070c63f2019-10-03 11:49:39 +02002947
2948 if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
2949 info->attrs[DEVLINK_ATTR_NETNS_FD] ||
2950 info->attrs[DEVLINK_ATTR_NETNS_ID]) {
2951 dest_net = devlink_netns_get(skb, info);
2952 if (IS_ERR(dest_net))
2953 return PTR_ERR(dest_net);
2954 }
2955
2956 err = devlink_reload(devlink, dest_net, info->extack);
2957
2958 if (dest_net)
2959 put_net(dest_net);
2960
Jiri Pirko2670ac22019-09-12 10:49:46 +02002961 return err;
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002962}
2963
Jiri Pirko191ed202019-06-04 15:40:40 +02002964static int devlink_nl_flash_update_fill(struct sk_buff *msg,
2965 struct devlink *devlink,
2966 enum devlink_command cmd,
2967 const char *status_msg,
2968 const char *component,
2969 unsigned long done, unsigned long total)
2970{
2971 void *hdr;
2972
2973 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
2974 if (!hdr)
2975 return -EMSGSIZE;
2976
2977 if (devlink_nl_put_handle(msg, devlink))
2978 goto nla_put_failure;
2979
2980 if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
2981 goto out;
2982
2983 if (status_msg &&
2984 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
2985 status_msg))
2986 goto nla_put_failure;
2987 if (component &&
2988 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
2989 component))
2990 goto nla_put_failure;
2991 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
2992 done, DEVLINK_ATTR_PAD))
2993 goto nla_put_failure;
2994 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
2995 total, DEVLINK_ATTR_PAD))
2996 goto nla_put_failure;
2997
2998out:
2999 genlmsg_end(msg, hdr);
3000 return 0;
3001
3002nla_put_failure:
3003 genlmsg_cancel(msg, hdr);
3004 return -EMSGSIZE;
3005}
3006
3007static void __devlink_flash_update_notify(struct devlink *devlink,
3008 enum devlink_command cmd,
3009 const char *status_msg,
3010 const char *component,
3011 unsigned long done,
3012 unsigned long total)
3013{
3014 struct sk_buff *msg;
3015 int err;
3016
3017 WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
3018 cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
3019 cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
3020
3021 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3022 if (!msg)
3023 return;
3024
3025 err = devlink_nl_flash_update_fill(msg, devlink, cmd, status_msg,
3026 component, done, total);
3027 if (err)
3028 goto out_free_msg;
3029
3030 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3031 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3032 return;
3033
3034out_free_msg:
3035 nlmsg_free(msg);
3036}
3037
3038void devlink_flash_update_begin_notify(struct devlink *devlink)
3039{
3040 __devlink_flash_update_notify(devlink,
3041 DEVLINK_CMD_FLASH_UPDATE,
3042 NULL, NULL, 0, 0);
3043}
3044EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
3045
3046void devlink_flash_update_end_notify(struct devlink *devlink)
3047{
3048 __devlink_flash_update_notify(devlink,
3049 DEVLINK_CMD_FLASH_UPDATE_END,
3050 NULL, NULL, 0, 0);
3051}
3052EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
3053
3054void devlink_flash_update_status_notify(struct devlink *devlink,
3055 const char *status_msg,
3056 const char *component,
3057 unsigned long done,
3058 unsigned long total)
3059{
3060 __devlink_flash_update_notify(devlink,
3061 DEVLINK_CMD_FLASH_UPDATE_STATUS,
3062 status_msg, component, done, total);
3063}
3064EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
3065
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003066static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
3067 struct genl_info *info)
3068{
3069 struct devlink *devlink = info->user_ptr[0];
3070 const char *file_name, *component;
3071 struct nlattr *nla_component;
3072
3073 if (!devlink->ops->flash_update)
3074 return -EOPNOTSUPP;
3075
3076 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
3077 return -EINVAL;
3078 file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
3079
3080 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
3081 component = nla_component ? nla_data(nla_component) : NULL;
3082
3083 return devlink->ops->flash_update(devlink, file_name, component,
3084 info->extack);
3085}
3086
Moshe Shemesh036467c2018-07-04 14:30:33 +03003087static const struct devlink_param devlink_param_generic[] = {
3088 {
3089 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
3090 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
3091 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
3092 },
3093 {
3094 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
3095 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
3096 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
3097 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03003098 {
3099 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
3100 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
3101 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
3102 },
Alex Veskerf6a698852018-07-12 15:13:17 +03003103 {
3104 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
3105 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
3106 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
3107 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05303108 {
3109 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
3110 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
3111 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
3112 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05303113 {
3114 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
3115 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
3116 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
3117 },
Vasundhara Volam16511782018-10-04 11:13:46 +05303118 {
3119 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
3120 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
3121 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
3122 },
Shalom Toledo846e9802018-12-03 07:58:59 +00003123 {
3124 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
3125 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
3126 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
3127 },
Dirk van der Merwe5bbd21d2019-09-09 00:54:18 +01003128 {
3129 .id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
3130 .name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
3131 .type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
3132 },
Michael Guralnik6c7295e2019-11-08 23:45:20 +00003133 {
3134 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
3135 .name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
3136 .type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
3137 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03003138};
Moshe Shemesheabaef12018-07-04 14:30:28 +03003139
3140static int devlink_param_generic_verify(const struct devlink_param *param)
3141{
3142 /* verify it match generic parameter by id and name */
3143 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
3144 return -EINVAL;
3145 if (strcmp(param->name, devlink_param_generic[param->id].name))
3146 return -ENOENT;
3147
3148 WARN_ON(param->type != devlink_param_generic[param->id].type);
3149
3150 return 0;
3151}
3152
3153static int devlink_param_driver_verify(const struct devlink_param *param)
3154{
3155 int i;
3156
3157 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
3158 return -EINVAL;
3159 /* verify no such name in generic params */
3160 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
3161 if (!strcmp(param->name, devlink_param_generic[i].name))
3162 return -EEXIST;
3163
3164 return 0;
3165}
3166
3167static struct devlink_param_item *
3168devlink_param_find_by_name(struct list_head *param_list,
3169 const char *param_name)
3170{
3171 struct devlink_param_item *param_item;
3172
3173 list_for_each_entry(param_item, param_list, list)
3174 if (!strcmp(param_item->param->name, param_name))
3175 return param_item;
3176 return NULL;
3177}
3178
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03003179static struct devlink_param_item *
3180devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
3181{
3182 struct devlink_param_item *param_item;
3183
3184 list_for_each_entry(param_item, param_list, list)
3185 if (param_item->param->id == param_id)
3186 return param_item;
3187 return NULL;
3188}
3189
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003190static bool
3191devlink_param_cmode_is_supported(const struct devlink_param *param,
3192 enum devlink_param_cmode cmode)
3193{
3194 return test_bit(cmode, &param->supported_cmodes);
3195}
3196
3197static int devlink_param_get(struct devlink *devlink,
3198 const struct devlink_param *param,
3199 struct devlink_param_gset_ctx *ctx)
3200{
3201 if (!param->get)
3202 return -EOPNOTSUPP;
3203 return param->get(devlink, param->id, ctx);
3204}
3205
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003206static int devlink_param_set(struct devlink *devlink,
3207 const struct devlink_param *param,
3208 struct devlink_param_gset_ctx *ctx)
3209{
3210 if (!param->set)
3211 return -EOPNOTSUPP;
3212 return param->set(devlink, param->id, ctx);
3213}
3214
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003215static int
3216devlink_param_type_to_nla_type(enum devlink_param_type param_type)
3217{
3218 switch (param_type) {
3219 case DEVLINK_PARAM_TYPE_U8:
3220 return NLA_U8;
3221 case DEVLINK_PARAM_TYPE_U16:
3222 return NLA_U16;
3223 case DEVLINK_PARAM_TYPE_U32:
3224 return NLA_U32;
3225 case DEVLINK_PARAM_TYPE_STRING:
3226 return NLA_STRING;
3227 case DEVLINK_PARAM_TYPE_BOOL:
3228 return NLA_FLAG;
3229 default:
3230 return -EINVAL;
3231 }
3232}
3233
3234static int
3235devlink_nl_param_value_fill_one(struct sk_buff *msg,
3236 enum devlink_param_type type,
3237 enum devlink_param_cmode cmode,
3238 union devlink_param_value val)
3239{
3240 struct nlattr *param_value_attr;
3241
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003242 param_value_attr = nla_nest_start_noflag(msg,
3243 DEVLINK_ATTR_PARAM_VALUE);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003244 if (!param_value_attr)
3245 goto nla_put_failure;
3246
3247 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
3248 goto value_nest_cancel;
3249
3250 switch (type) {
3251 case DEVLINK_PARAM_TYPE_U8:
3252 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
3253 goto value_nest_cancel;
3254 break;
3255 case DEVLINK_PARAM_TYPE_U16:
3256 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
3257 goto value_nest_cancel;
3258 break;
3259 case DEVLINK_PARAM_TYPE_U32:
3260 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
3261 goto value_nest_cancel;
3262 break;
3263 case DEVLINK_PARAM_TYPE_STRING:
3264 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
3265 val.vstr))
3266 goto value_nest_cancel;
3267 break;
3268 case DEVLINK_PARAM_TYPE_BOOL:
3269 if (val.vbool &&
3270 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
3271 goto value_nest_cancel;
3272 break;
3273 }
3274
3275 nla_nest_end(msg, param_value_attr);
3276 return 0;
3277
3278value_nest_cancel:
3279 nla_nest_cancel(msg, param_value_attr);
3280nla_put_failure:
3281 return -EMSGSIZE;
3282}
3283
3284static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303285 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003286 struct devlink_param_item *param_item,
3287 enum devlink_command cmd,
3288 u32 portid, u32 seq, int flags)
3289{
3290 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003291 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003292 const struct devlink_param *param = param_item->param;
3293 struct devlink_param_gset_ctx ctx;
3294 struct nlattr *param_values_list;
3295 struct nlattr *param_attr;
3296 int nla_type;
3297 void *hdr;
3298 int err;
3299 int i;
3300
3301 /* Get value from driver part to driverinit configuration mode */
3302 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3303 if (!devlink_param_cmode_is_supported(param, i))
3304 continue;
3305 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3306 if (!param_item->driverinit_value_valid)
3307 return -EOPNOTSUPP;
3308 param_value[i] = param_item->driverinit_value;
3309 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003310 if (!param_item->published)
3311 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003312 ctx.cmode = i;
3313 err = devlink_param_get(devlink, param, &ctx);
3314 if (err)
3315 return err;
3316 param_value[i] = ctx.val;
3317 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003318 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003319 }
3320
3321 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3322 if (!hdr)
3323 return -EMSGSIZE;
3324
3325 if (devlink_nl_put_handle(msg, devlink))
3326 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303327
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303328 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3329 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3330 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303331 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3332 goto genlmsg_cancel;
3333
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003334 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003335 if (!param_attr)
3336 goto genlmsg_cancel;
3337 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3338 goto param_nest_cancel;
3339 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3340 goto param_nest_cancel;
3341
3342 nla_type = devlink_param_type_to_nla_type(param->type);
3343 if (nla_type < 0)
3344 goto param_nest_cancel;
3345 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3346 goto param_nest_cancel;
3347
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003348 param_values_list = nla_nest_start_noflag(msg,
3349 DEVLINK_ATTR_PARAM_VALUES_LIST);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003350 if (!param_values_list)
3351 goto param_nest_cancel;
3352
3353 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003354 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003355 continue;
3356 err = devlink_nl_param_value_fill_one(msg, param->type,
3357 i, param_value[i]);
3358 if (err)
3359 goto values_list_nest_cancel;
3360 }
3361
3362 nla_nest_end(msg, param_values_list);
3363 nla_nest_end(msg, param_attr);
3364 genlmsg_end(msg, hdr);
3365 return 0;
3366
3367values_list_nest_cancel:
3368 nla_nest_end(msg, param_values_list);
3369param_nest_cancel:
3370 nla_nest_cancel(msg, param_attr);
3371genlmsg_cancel:
3372 genlmsg_cancel(msg, hdr);
3373 return -EMSGSIZE;
3374}
3375
Moshe Shemeshea601e12018-07-04 14:30:32 +03003376static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303377 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03003378 struct devlink_param_item *param_item,
3379 enum devlink_command cmd)
3380{
3381 struct sk_buff *msg;
3382 int err;
3383
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303384 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3385 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3386 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003387
3388 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3389 if (!msg)
3390 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303391 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3392 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003393 if (err) {
3394 nlmsg_free(msg);
3395 return;
3396 }
3397
3398 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3399 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3400}
3401
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003402static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3403 struct netlink_callback *cb)
3404{
3405 struct devlink_param_item *param_item;
3406 struct devlink *devlink;
3407 int start = cb->args[0];
3408 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003409 int err = 0;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003410
3411 mutex_lock(&devlink_mutex);
3412 list_for_each_entry(devlink, &devlink_list, list) {
3413 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3414 continue;
3415 mutex_lock(&devlink->lock);
3416 list_for_each_entry(param_item, &devlink->param_list, list) {
3417 if (idx < start) {
3418 idx++;
3419 continue;
3420 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303421 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003422 DEVLINK_CMD_PARAM_GET,
3423 NETLINK_CB(cb->skb).portid,
3424 cb->nlh->nlmsg_seq,
3425 NLM_F_MULTI);
Vasundhara Volam93c2fcb2019-09-30 11:52:21 +05303426 if (err && err != -EOPNOTSUPP) {
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003427 mutex_unlock(&devlink->lock);
3428 goto out;
3429 }
3430 idx++;
3431 }
3432 mutex_unlock(&devlink->lock);
3433 }
3434out:
3435 mutex_unlock(&devlink_mutex);
3436
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003437 if (err != -EMSGSIZE)
3438 return err;
3439
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003440 cb->args[0] = idx;
3441 return msg->len;
3442}
3443
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003444static int
3445devlink_param_type_get_from_info(struct genl_info *info,
3446 enum devlink_param_type *param_type)
3447{
3448 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3449 return -EINVAL;
3450
3451 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3452 case NLA_U8:
3453 *param_type = DEVLINK_PARAM_TYPE_U8;
3454 break;
3455 case NLA_U16:
3456 *param_type = DEVLINK_PARAM_TYPE_U16;
3457 break;
3458 case NLA_U32:
3459 *param_type = DEVLINK_PARAM_TYPE_U32;
3460 break;
3461 case NLA_STRING:
3462 *param_type = DEVLINK_PARAM_TYPE_STRING;
3463 break;
3464 case NLA_FLAG:
3465 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3466 break;
3467 default:
3468 return -EINVAL;
3469 }
3470
3471 return 0;
3472}
3473
3474static int
3475devlink_param_value_get_from_info(const struct devlink_param *param,
3476 struct genl_info *info,
3477 union devlink_param_value *value)
3478{
Jakub Kicinski87509392020-03-02 21:05:11 -08003479 struct nlattr *param_data;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003480 int len;
3481
Jakub Kicinski87509392020-03-02 21:05:11 -08003482 param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
3483
3484 if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003485 return -EINVAL;
3486
3487 switch (param->type) {
3488 case DEVLINK_PARAM_TYPE_U8:
Jakub Kicinski87509392020-03-02 21:05:11 -08003489 if (nla_len(param_data) != sizeof(u8))
3490 return -EINVAL;
3491 value->vu8 = nla_get_u8(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003492 break;
3493 case DEVLINK_PARAM_TYPE_U16:
Jakub Kicinski87509392020-03-02 21:05:11 -08003494 if (nla_len(param_data) != sizeof(u16))
3495 return -EINVAL;
3496 value->vu16 = nla_get_u16(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003497 break;
3498 case DEVLINK_PARAM_TYPE_U32:
Jakub Kicinski87509392020-03-02 21:05:11 -08003499 if (nla_len(param_data) != sizeof(u32))
3500 return -EINVAL;
3501 value->vu32 = nla_get_u32(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003502 break;
3503 case DEVLINK_PARAM_TYPE_STRING:
Jakub Kicinski87509392020-03-02 21:05:11 -08003504 len = strnlen(nla_data(param_data), nla_len(param_data));
3505 if (len == nla_len(param_data) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003506 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003507 return -EINVAL;
Jakub Kicinski87509392020-03-02 21:05:11 -08003508 strcpy(value->vstr, nla_data(param_data));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003509 break;
3510 case DEVLINK_PARAM_TYPE_BOOL:
Jakub Kicinski87509392020-03-02 21:05:11 -08003511 if (param_data && nla_len(param_data))
3512 return -EINVAL;
3513 value->vbool = nla_get_flag(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003514 break;
3515 }
3516 return 0;
3517}
3518
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003519static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303520devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003521 struct genl_info *info)
3522{
3523 char *param_name;
3524
3525 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3526 return NULL;
3527
3528 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303529 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003530}
3531
3532static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3533 struct genl_info *info)
3534{
3535 struct devlink *devlink = info->user_ptr[0];
3536 struct devlink_param_item *param_item;
3537 struct sk_buff *msg;
3538 int err;
3539
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303540 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003541 if (!param_item)
3542 return -EINVAL;
3543
3544 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3545 if (!msg)
3546 return -ENOMEM;
3547
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303548 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003549 DEVLINK_CMD_PARAM_GET,
3550 info->snd_portid, info->snd_seq, 0);
3551 if (err) {
3552 nlmsg_free(msg);
3553 return err;
3554 }
3555
3556 return genlmsg_reply(msg, info);
3557}
3558
Vasundhara Volam9c548732019-01-28 18:00:22 +05303559static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303560 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303561 struct list_head *param_list,
3562 struct genl_info *info,
3563 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003564{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003565 enum devlink_param_type param_type;
3566 struct devlink_param_gset_ctx ctx;
3567 enum devlink_param_cmode cmode;
3568 struct devlink_param_item *param_item;
3569 const struct devlink_param *param;
3570 union devlink_param_value value;
3571 int err = 0;
3572
Vasundhara Volam9c548732019-01-28 18:00:22 +05303573 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003574 if (!param_item)
3575 return -EINVAL;
3576 param = param_item->param;
3577 err = devlink_param_type_get_from_info(info, &param_type);
3578 if (err)
3579 return err;
3580 if (param_type != param->type)
3581 return -EINVAL;
3582 err = devlink_param_value_get_from_info(param, info, &value);
3583 if (err)
3584 return err;
3585 if (param->validate) {
3586 err = param->validate(devlink, param->id, value, info->extack);
3587 if (err)
3588 return err;
3589 }
3590
3591 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3592 return -EINVAL;
3593 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3594 if (!devlink_param_cmode_is_supported(param, cmode))
3595 return -EOPNOTSUPP;
3596
3597 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003598 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3599 strcpy(param_item->driverinit_value.vstr, value.vstr);
3600 else
3601 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003602 param_item->driverinit_value_valid = true;
3603 } else {
3604 if (!param->set)
3605 return -EOPNOTSUPP;
3606 ctx.val = value;
3607 ctx.cmode = cmode;
3608 err = devlink_param_set(devlink, param, &ctx);
3609 if (err)
3610 return err;
3611 }
3612
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303613 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003614 return 0;
3615}
3616
Vasundhara Volam9c548732019-01-28 18:00:22 +05303617static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3618 struct genl_info *info)
3619{
3620 struct devlink *devlink = info->user_ptr[0];
3621
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303622 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303623 info, DEVLINK_CMD_PARAM_NEW);
3624}
3625
Moshe Shemesheabaef12018-07-04 14:30:28 +03003626static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303627 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303628 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303629 const struct devlink_param *param,
3630 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003631{
3632 struct devlink_param_item *param_item;
3633
Vasundhara Volam39e61602019-01-28 18:00:20 +05303634 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03003635 return -EEXIST;
3636
3637 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3638 WARN_ON(param->get || param->set);
3639 else
3640 WARN_ON(!param->get || !param->set);
3641
3642 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3643 if (!param_item)
3644 return -ENOMEM;
3645 param_item->param = param;
3646
Vasundhara Volam39e61602019-01-28 18:00:20 +05303647 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303648 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003649 return 0;
3650}
3651
3652static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303653 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303654 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303655 const struct devlink_param *param,
3656 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003657{
3658 struct devlink_param_item *param_item;
3659
Vasundhara Volam39e61602019-01-28 18:00:20 +05303660 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003661 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303662 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003663 list_del(&param_item->list);
3664 kfree(param_item);
3665}
3666
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303667static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3668 struct netlink_callback *cb)
3669{
3670 struct devlink_param_item *param_item;
3671 struct devlink_port *devlink_port;
3672 struct devlink *devlink;
3673 int start = cb->args[0];
3674 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003675 int err = 0;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303676
3677 mutex_lock(&devlink_mutex);
3678 list_for_each_entry(devlink, &devlink_list, list) {
3679 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3680 continue;
3681 mutex_lock(&devlink->lock);
3682 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3683 list_for_each_entry(param_item,
3684 &devlink_port->param_list, list) {
3685 if (idx < start) {
3686 idx++;
3687 continue;
3688 }
3689 err = devlink_nl_param_fill(msg,
3690 devlink_port->devlink,
3691 devlink_port->index, param_item,
3692 DEVLINK_CMD_PORT_PARAM_GET,
3693 NETLINK_CB(cb->skb).portid,
3694 cb->nlh->nlmsg_seq,
3695 NLM_F_MULTI);
Vasundhara Volam93c2fcb2019-09-30 11:52:21 +05303696 if (err && err != -EOPNOTSUPP) {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303697 mutex_unlock(&devlink->lock);
3698 goto out;
3699 }
3700 idx++;
3701 }
3702 }
3703 mutex_unlock(&devlink->lock);
3704 }
3705out:
3706 mutex_unlock(&devlink_mutex);
3707
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003708 if (err != -EMSGSIZE)
3709 return err;
3710
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303711 cb->args[0] = idx;
3712 return msg->len;
3713}
3714
3715static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3716 struct genl_info *info)
3717{
3718 struct devlink_port *devlink_port = info->user_ptr[0];
3719 struct devlink_param_item *param_item;
3720 struct sk_buff *msg;
3721 int err;
3722
3723 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3724 info);
3725 if (!param_item)
3726 return -EINVAL;
3727
3728 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3729 if (!msg)
3730 return -ENOMEM;
3731
3732 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3733 devlink_port->index, param_item,
3734 DEVLINK_CMD_PORT_PARAM_GET,
3735 info->snd_portid, info->snd_seq, 0);
3736 if (err) {
3737 nlmsg_free(msg);
3738 return err;
3739 }
3740
3741 return genlmsg_reply(msg, info);
3742}
3743
Vasundhara Volam9c548732019-01-28 18:00:22 +05303744static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3745 struct genl_info *info)
3746{
3747 struct devlink_port *devlink_port = info->user_ptr[0];
3748
3749 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303750 devlink_port->index,
3751 &devlink_port->param_list, info,
3752 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05303753}
3754
Alex Veskera006d462018-07-12 15:13:12 +03003755static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3756 struct devlink *devlink,
3757 struct devlink_snapshot *snapshot)
3758{
3759 struct nlattr *snap_attr;
3760 int err;
3761
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003762 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
Alex Veskera006d462018-07-12 15:13:12 +03003763 if (!snap_attr)
3764 return -EINVAL;
3765
3766 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3767 if (err)
3768 goto nla_put_failure;
3769
3770 nla_nest_end(msg, snap_attr);
3771 return 0;
3772
3773nla_put_failure:
3774 nla_nest_cancel(msg, snap_attr);
3775 return err;
3776}
3777
3778static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3779 struct devlink *devlink,
3780 struct devlink_region *region)
3781{
3782 struct devlink_snapshot *snapshot;
3783 struct nlattr *snapshots_attr;
3784 int err;
3785
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003786 snapshots_attr = nla_nest_start_noflag(msg,
3787 DEVLINK_ATTR_REGION_SNAPSHOTS);
Alex Veskera006d462018-07-12 15:13:12 +03003788 if (!snapshots_attr)
3789 return -EINVAL;
3790
3791 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3792 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3793 if (err)
3794 goto nla_put_failure;
3795 }
3796
3797 nla_nest_end(msg, snapshots_attr);
3798 return 0;
3799
3800nla_put_failure:
3801 nla_nest_cancel(msg, snapshots_attr);
3802 return err;
3803}
3804
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003805static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3806 enum devlink_command cmd, u32 portid,
3807 u32 seq, int flags,
3808 struct devlink_region *region)
3809{
3810 void *hdr;
3811 int err;
3812
3813 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3814 if (!hdr)
3815 return -EMSGSIZE;
3816
3817 err = devlink_nl_put_handle(msg, devlink);
3818 if (err)
3819 goto nla_put_failure;
3820
Jacob Kellere8937682020-03-26 11:37:08 -07003821 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003822 if (err)
3823 goto nla_put_failure;
3824
3825 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3826 region->size,
3827 DEVLINK_ATTR_PAD);
3828 if (err)
3829 goto nla_put_failure;
3830
Alex Veskera006d462018-07-12 15:13:12 +03003831 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3832 if (err)
3833 goto nla_put_failure;
3834
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003835 genlmsg_end(msg, hdr);
3836 return 0;
3837
3838nla_put_failure:
3839 genlmsg_cancel(msg, hdr);
3840 return err;
3841}
3842
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003843static struct sk_buff *
3844devlink_nl_region_notify_build(struct devlink_region *region,
3845 struct devlink_snapshot *snapshot,
3846 enum devlink_command cmd, u32 portid, u32 seq)
Alex Vesker866319b2018-07-12 15:13:13 +03003847{
3848 struct devlink *devlink = region->devlink;
3849 struct sk_buff *msg;
3850 void *hdr;
3851 int err;
3852
Alex Vesker866319b2018-07-12 15:13:13 +03003853
3854 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3855 if (!msg)
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003856 return ERR_PTR(-ENOMEM);
Alex Vesker866319b2018-07-12 15:13:13 +03003857
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003858 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
3859 if (!hdr) {
3860 err = -EMSGSIZE;
Alex Vesker866319b2018-07-12 15:13:13 +03003861 goto out_free_msg;
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003862 }
Alex Vesker866319b2018-07-12 15:13:13 +03003863
3864 err = devlink_nl_put_handle(msg, devlink);
3865 if (err)
3866 goto out_cancel_msg;
3867
3868 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
Jacob Kellere8937682020-03-26 11:37:08 -07003869 region->ops->name);
Alex Vesker866319b2018-07-12 15:13:13 +03003870 if (err)
3871 goto out_cancel_msg;
3872
3873 if (snapshot) {
3874 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3875 snapshot->id);
3876 if (err)
3877 goto out_cancel_msg;
3878 } else {
3879 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3880 region->size, DEVLINK_ATTR_PAD);
3881 if (err)
3882 goto out_cancel_msg;
3883 }
3884 genlmsg_end(msg, hdr);
3885
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003886 return msg;
Alex Vesker866319b2018-07-12 15:13:13 +03003887
3888out_cancel_msg:
3889 genlmsg_cancel(msg, hdr);
3890out_free_msg:
3891 nlmsg_free(msg);
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003892 return ERR_PTR(err);
3893}
3894
3895static void devlink_nl_region_notify(struct devlink_region *region,
3896 struct devlink_snapshot *snapshot,
3897 enum devlink_command cmd)
3898{
3899 struct devlink *devlink = region->devlink;
3900 struct sk_buff *msg;
3901
3902 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3903
3904 msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
3905 if (IS_ERR(msg))
3906 return;
3907
3908 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3909 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
Alex Vesker866319b2018-07-12 15:13:13 +03003910}
3911
Jacob Kellercf80fae2020-03-26 11:37:11 -07003912/**
Jacob Keller12102432020-03-26 11:37:15 -07003913 * __devlink_snapshot_id_increment - Increment number of snapshots using an id
3914 * @devlink: devlink instance
3915 * @id: the snapshot id
3916 *
3917 * Track when a new snapshot begins using an id. Load the count for the
3918 * given id from the snapshot xarray, increment it, and store it back.
3919 *
3920 * Called when a new snapshot is created with the given id.
3921 *
3922 * The id *must* have been previously allocated by
3923 * devlink_region_snapshot_id_get().
3924 *
3925 * Returns 0 on success, or an error on failure.
3926 */
3927static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
3928{
3929 unsigned long count;
3930 void *p;
3931
3932 lockdep_assert_held(&devlink->lock);
3933
3934 p = xa_load(&devlink->snapshot_ids, id);
3935 if (WARN_ON(!p))
3936 return -EINVAL;
3937
3938 if (WARN_ON(!xa_is_value(p)))
3939 return -EINVAL;
3940
3941 count = xa_to_value(p);
3942 count++;
3943
3944 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
3945 GFP_KERNEL));
3946}
3947
3948/**
3949 * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
3950 * @devlink: devlink instance
3951 * @id: the snapshot id
3952 *
3953 * Track when a snapshot is deleted and stops using an id. Load the count
3954 * for the given id from the snapshot xarray, decrement it, and store it
3955 * back.
3956 *
3957 * If the count reaches zero, erase this id from the xarray, freeing it
3958 * up for future re-use by devlink_region_snapshot_id_get().
3959 *
3960 * Called when a snapshot using the given id is deleted, and when the
3961 * initial allocator of the id is finished using it.
3962 */
3963static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
3964{
3965 unsigned long count;
3966 void *p;
3967
3968 lockdep_assert_held(&devlink->lock);
3969
3970 p = xa_load(&devlink->snapshot_ids, id);
3971 if (WARN_ON(!p))
3972 return;
3973
3974 if (WARN_ON(!xa_is_value(p)))
3975 return;
3976
3977 count = xa_to_value(p);
3978
3979 if (count > 1) {
3980 count--;
3981 xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
3982 GFP_KERNEL);
3983 } else {
3984 /* If this was the last user, we can erase this id */
3985 xa_erase(&devlink->snapshot_ids, id);
3986 }
3987}
3988
3989/**
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07003990 * __devlink_snapshot_id_insert - Insert a specific snapshot ID
3991 * @devlink: devlink instance
3992 * @id: the snapshot id
3993 *
3994 * Mark the given snapshot id as used by inserting a zero value into the
3995 * snapshot xarray.
3996 *
3997 * This must be called while holding the devlink instance lock. Unlike
3998 * devlink_snapshot_id_get, the initial reference count is zero, not one.
3999 * It is expected that the id will immediately be used before
4000 * releasing the devlink instance lock.
4001 *
4002 * Returns zero on success, or an error code if the snapshot id could not
4003 * be inserted.
4004 */
4005static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
4006{
4007 lockdep_assert_held(&devlink->lock);
4008
4009 if (WARN_ON(xa_load(&devlink->snapshot_ids, id)))
4010 return -EEXIST;
4011
4012 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
4013 GFP_KERNEL));
4014}
4015
4016/**
Jacob Keller70001082020-03-26 11:37:13 -07004017 * __devlink_region_snapshot_id_get - get snapshot ID
4018 * @devlink: devlink instance
Jacob Keller7ef19d32020-03-26 11:37:14 -07004019 * @id: storage to return snapshot id
Jacob Keller70001082020-03-26 11:37:13 -07004020 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07004021 * Allocates a new snapshot id. Returns zero on success, or a negative
4022 * error on failure. Must be called while holding the devlink instance
4023 * lock.
Jacob Keller12102432020-03-26 11:37:15 -07004024 *
4025 * Snapshot IDs are tracked using an xarray which stores the number of
4026 * users of the snapshot id.
4027 *
4028 * Note that the caller of this function counts as a 'user', in order to
4029 * avoid race conditions. The caller must release its hold on the
4030 * snapshot by using devlink_region_snapshot_id_put.
Jacob Keller70001082020-03-26 11:37:13 -07004031 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07004032static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Jacob Keller70001082020-03-26 11:37:13 -07004033{
4034 lockdep_assert_held(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07004035
Jacob Keller12102432020-03-26 11:37:15 -07004036 return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
4037 xa_limit_32b, GFP_KERNEL);
Jacob Keller70001082020-03-26 11:37:13 -07004038}
4039
4040/**
Jacob Kellercf80fae2020-03-26 11:37:11 -07004041 * __devlink_region_snapshot_create - create a new snapshot
4042 * This will add a new snapshot of a region. The snapshot
4043 * will be stored on the region struct and can be accessed
4044 * from devlink. This is useful for future analyses of snapshots.
4045 * Multiple snapshots can be created on a region.
4046 * The @snapshot_id should be obtained using the getter function.
4047 *
4048 * Must be called only while holding the devlink instance lock.
4049 *
4050 * @region: devlink region of the snapshot
4051 * @data: snapshot data
4052 * @snapshot_id: snapshot id to be created
4053 */
4054static int
4055__devlink_region_snapshot_create(struct devlink_region *region,
4056 u8 *data, u32 snapshot_id)
4057{
4058 struct devlink *devlink = region->devlink;
4059 struct devlink_snapshot *snapshot;
Jacob Keller12102432020-03-26 11:37:15 -07004060 int err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004061
4062 lockdep_assert_held(&devlink->lock);
4063
4064 /* check if region can hold one more snapshot */
4065 if (region->cur_snapshots == region->max_snapshots)
Jacob Keller47a39f62020-03-26 11:37:12 -07004066 return -ENOSPC;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004067
4068 if (devlink_region_snapshot_get_by_id(region, snapshot_id))
4069 return -EEXIST;
4070
4071 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
4072 if (!snapshot)
4073 return -ENOMEM;
4074
Jacob Keller12102432020-03-26 11:37:15 -07004075 err = __devlink_snapshot_id_increment(devlink, snapshot_id);
4076 if (err)
4077 goto err_snapshot_id_increment;
4078
Jacob Kellercf80fae2020-03-26 11:37:11 -07004079 snapshot->id = snapshot_id;
4080 snapshot->region = region;
4081 snapshot->data = data;
4082
4083 list_add_tail(&snapshot->list, &region->snapshot_list);
4084
4085 region->cur_snapshots++;
4086
4087 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
4088 return 0;
Jacob Keller12102432020-03-26 11:37:15 -07004089
4090err_snapshot_id_increment:
4091 kfree(snapshot);
4092 return err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004093}
4094
Jiri Pirko92b49822019-08-12 14:28:31 +02004095static void devlink_region_snapshot_del(struct devlink_region *region,
4096 struct devlink_snapshot *snapshot)
4097{
Jacob Keller12102432020-03-26 11:37:15 -07004098 struct devlink *devlink = region->devlink;
4099
4100 lockdep_assert_held(&devlink->lock);
4101
Jiri Pirko92b49822019-08-12 14:28:31 +02004102 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
4103 region->cur_snapshots--;
4104 list_del(&snapshot->list);
Jacob Kellera0a09f62020-03-26 11:37:09 -07004105 region->ops->destructor(snapshot->data);
Jacob Keller12102432020-03-26 11:37:15 -07004106 __devlink_snapshot_id_decrement(devlink, snapshot->id);
Jiri Pirko92b49822019-08-12 14:28:31 +02004107 kfree(snapshot);
4108}
4109
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004110static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
4111 struct genl_info *info)
4112{
4113 struct devlink *devlink = info->user_ptr[0];
4114 struct devlink_region *region;
4115 const char *region_name;
4116 struct sk_buff *msg;
4117 int err;
4118
4119 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
4120 return -EINVAL;
4121
4122 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4123 region = devlink_region_get_by_name(devlink, region_name);
4124 if (!region)
4125 return -EINVAL;
4126
4127 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4128 if (!msg)
4129 return -ENOMEM;
4130
4131 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
4132 info->snd_portid, info->snd_seq, 0,
4133 region);
4134 if (err) {
4135 nlmsg_free(msg);
4136 return err;
4137 }
4138
4139 return genlmsg_reply(msg, info);
4140}
4141
4142static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
4143 struct netlink_callback *cb)
4144{
4145 struct devlink_region *region;
4146 struct devlink *devlink;
4147 int start = cb->args[0];
4148 int idx = 0;
4149 int err;
4150
4151 mutex_lock(&devlink_mutex);
4152 list_for_each_entry(devlink, &devlink_list, list) {
4153 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4154 continue;
4155
4156 mutex_lock(&devlink->lock);
4157 list_for_each_entry(region, &devlink->region_list, list) {
4158 if (idx < start) {
4159 idx++;
4160 continue;
4161 }
4162 err = devlink_nl_region_fill(msg, devlink,
4163 DEVLINK_CMD_REGION_GET,
4164 NETLINK_CB(cb->skb).portid,
4165 cb->nlh->nlmsg_seq,
4166 NLM_F_MULTI, region);
4167 if (err) {
4168 mutex_unlock(&devlink->lock);
4169 goto out;
4170 }
4171 idx++;
4172 }
4173 mutex_unlock(&devlink->lock);
4174 }
4175out:
4176 mutex_unlock(&devlink_mutex);
4177 cb->args[0] = idx;
4178 return msg->len;
4179}
4180
Alex Vesker866319b2018-07-12 15:13:13 +03004181static int devlink_nl_cmd_region_del(struct sk_buff *skb,
4182 struct genl_info *info)
4183{
4184 struct devlink *devlink = info->user_ptr[0];
4185 struct devlink_snapshot *snapshot;
4186 struct devlink_region *region;
4187 const char *region_name;
4188 u32 snapshot_id;
4189
4190 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
4191 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
4192 return -EINVAL;
4193
4194 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4195 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4196
4197 region = devlink_region_get_by_name(devlink, region_name);
4198 if (!region)
4199 return -EINVAL;
4200
4201 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4202 if (!snapshot)
4203 return -EINVAL;
4204
Jiri Pirko92b49822019-08-12 14:28:31 +02004205 devlink_region_snapshot_del(region, snapshot);
Alex Vesker866319b2018-07-12 15:13:13 +03004206 return 0;
4207}
4208
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004209static int
4210devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
4211{
4212 struct devlink *devlink = info->user_ptr[0];
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004213 struct devlink_snapshot *snapshot;
4214 struct nlattr *snapshot_id_attr;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004215 struct devlink_region *region;
4216 const char *region_name;
4217 u32 snapshot_id;
4218 u8 *data;
4219 int err;
4220
4221 if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) {
4222 NL_SET_ERR_MSG_MOD(info->extack, "No region name provided");
4223 return -EINVAL;
4224 }
4225
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004226 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4227 region = devlink_region_get_by_name(devlink, region_name);
4228 if (!region) {
4229 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist");
4230 return -EINVAL;
4231 }
4232
4233 if (!region->ops->snapshot) {
4234 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not support taking an immediate snapshot");
4235 return -EOPNOTSUPP;
4236 }
4237
4238 if (region->cur_snapshots == region->max_snapshots) {
4239 NL_SET_ERR_MSG_MOD(info->extack, "The region has reached the maximum number of stored snapshots");
4240 return -ENOSPC;
4241 }
4242
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004243 snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
4244 if (snapshot_id_attr) {
4245 snapshot_id = nla_get_u32(snapshot_id_attr);
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004246
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004247 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
4248 NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
4249 return -EEXIST;
4250 }
4251
4252 err = __devlink_snapshot_id_insert(devlink, snapshot_id);
4253 if (err)
4254 return err;
4255 } else {
4256 err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
4257 if (err) {
4258 NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
4259 return err;
4260 }
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004261 }
4262
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004263 err = region->ops->snapshot(devlink, info->extack, &data);
4264 if (err)
4265 goto err_snapshot_capture;
4266
4267 err = __devlink_region_snapshot_create(region, data, snapshot_id);
4268 if (err)
4269 goto err_snapshot_create;
4270
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004271 if (!snapshot_id_attr) {
4272 struct sk_buff *msg;
4273
4274 snapshot = devlink_region_snapshot_get_by_id(region,
4275 snapshot_id);
4276 if (WARN_ON(!snapshot))
4277 return -EINVAL;
4278
4279 msg = devlink_nl_region_notify_build(region, snapshot,
4280 DEVLINK_CMD_REGION_NEW,
4281 info->snd_portid,
4282 info->snd_seq);
4283 err = PTR_ERR_OR_ZERO(msg);
4284 if (err)
4285 goto err_notify;
4286
4287 err = genlmsg_reply(msg, info);
4288 if (err)
4289 goto err_notify;
4290 }
4291
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004292 return 0;
4293
4294err_snapshot_create:
4295 region->ops->destructor(data);
4296err_snapshot_capture:
4297 __devlink_snapshot_id_decrement(devlink, snapshot_id);
4298 return err;
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004299
4300err_notify:
4301 devlink_region_snapshot_del(region, snapshot);
4302 return err;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004303}
4304
Alex Vesker4e547952018-07-12 15:13:14 +03004305static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
4306 struct devlink *devlink,
4307 u8 *chunk, u32 chunk_size,
4308 u64 addr)
4309{
4310 struct nlattr *chunk_attr;
4311 int err;
4312
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004313 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
Alex Vesker4e547952018-07-12 15:13:14 +03004314 if (!chunk_attr)
4315 return -EINVAL;
4316
4317 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
4318 if (err)
4319 goto nla_put_failure;
4320
4321 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
4322 DEVLINK_ATTR_PAD);
4323 if (err)
4324 goto nla_put_failure;
4325
4326 nla_nest_end(msg, chunk_attr);
4327 return 0;
4328
4329nla_put_failure:
4330 nla_nest_cancel(msg, chunk_attr);
4331 return err;
4332}
4333
4334#define DEVLINK_REGION_READ_CHUNK_SIZE 256
4335
4336static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
4337 struct devlink *devlink,
4338 struct devlink_region *region,
4339 struct nlattr **attrs,
4340 u64 start_offset,
4341 u64 end_offset,
Alex Vesker4e547952018-07-12 15:13:14 +03004342 u64 *new_offset)
4343{
4344 struct devlink_snapshot *snapshot;
4345 u64 curr_offset = start_offset;
4346 u32 snapshot_id;
4347 int err = 0;
4348
4349 *new_offset = start_offset;
4350
4351 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4352 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4353 if (!snapshot)
4354 return -EINVAL;
4355
Alex Vesker4e547952018-07-12 15:13:14 +03004356 while (curr_offset < end_offset) {
4357 u32 data_size;
4358 u8 *data;
4359
4360 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
4361 data_size = end_offset - curr_offset;
4362 else
4363 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
4364
4365 data = &snapshot->data[curr_offset];
4366 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
4367 data, data_size,
4368 curr_offset);
4369 if (err)
4370 break;
4371
4372 curr_offset += data_size;
4373 }
4374 *new_offset = curr_offset;
4375
4376 return err;
4377}
4378
4379static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
4380 struct netlink_callback *cb)
4381{
Jiri Pirkoee85da52019-10-05 20:04:42 +02004382 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004383 u64 ret_offset, start_offset, end_offset = U64_MAX;
Jiri Pirkoee85da52019-10-05 20:04:42 +02004384 struct nlattr **attrs = info->attrs;
Alex Vesker4e547952018-07-12 15:13:14 +03004385 struct devlink_region *region;
4386 struct nlattr *chunks_attr;
4387 const char *region_name;
4388 struct devlink *devlink;
Alex Vesker4e547952018-07-12 15:13:14 +03004389 void *hdr;
4390 int err;
4391
4392 start_offset = *((u64 *)&cb->args[0]);
4393
Parav Panditdac7c082019-02-12 14:24:08 -06004394 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03004395 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004396 if (IS_ERR(devlink)) {
4397 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06004398 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004399 }
Alex Vesker4e547952018-07-12 15:13:14 +03004400
Alex Vesker4e547952018-07-12 15:13:14 +03004401 mutex_lock(&devlink->lock);
4402
4403 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06004404 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
4405 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004406 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004407 }
Alex Vesker4e547952018-07-12 15:13:14 +03004408
4409 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
4410 region = devlink_region_get_by_name(devlink, region_name);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004411 if (!region) {
4412 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004413 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004414 }
Alex Vesker4e547952018-07-12 15:13:14 +03004415
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004416 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
4417 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
4418 if (!start_offset)
4419 start_offset =
4420 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4421
4422 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4423 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
4424 }
4425
4426 if (end_offset > region->size)
4427 end_offset = region->size;
4428
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004429 /* return 0 if there is no further data to read */
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004430 if (start_offset == end_offset) {
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004431 err = 0;
4432 goto out_unlock;
4433 }
4434
Alex Vesker4e547952018-07-12 15:13:14 +03004435 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4436 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
4437 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004438 if (!hdr) {
4439 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004440 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004441 }
Alex Vesker4e547952018-07-12 15:13:14 +03004442
4443 err = devlink_nl_put_handle(skb, devlink);
4444 if (err)
4445 goto nla_put_failure;
4446
4447 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
4448 if (err)
4449 goto nla_put_failure;
4450
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004451 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004452 if (!chunks_attr) {
4453 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004454 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004455 }
Alex Vesker4e547952018-07-12 15:13:14 +03004456
Alex Vesker4e547952018-07-12 15:13:14 +03004457 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
4458 region, attrs,
4459 start_offset,
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004460 end_offset, &ret_offset);
Alex Vesker4e547952018-07-12 15:13:14 +03004461
4462 if (err && err != -EMSGSIZE)
4463 goto nla_put_failure;
4464
4465 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06004466 if (ret_offset == start_offset) {
4467 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004468 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004469 }
Alex Vesker4e547952018-07-12 15:13:14 +03004470
4471 *((u64 *)&cb->args[0]) = ret_offset;
4472
4473 nla_nest_end(skb, chunks_attr);
4474 genlmsg_end(skb, hdr);
4475 mutex_unlock(&devlink->lock);
4476 mutex_unlock(&devlink_mutex);
4477
4478 return skb->len;
4479
4480nla_put_failure:
4481 genlmsg_cancel(skb, hdr);
4482out_unlock:
4483 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06004484out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03004485 mutex_unlock(&devlink_mutex);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004486 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03004487}
4488
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004489struct devlink_info_req {
4490 struct sk_buff *msg;
4491};
4492
4493int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
4494{
4495 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
4496}
4497EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
4498
4499int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
4500{
4501 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
4502}
4503EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
4504
Vasundhara Volamb5872cd2020-06-20 22:01:56 +05304505int devlink_info_board_serial_number_put(struct devlink_info_req *req,
4506 const char *bsn)
4507{
4508 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER,
4509 bsn);
4510}
4511EXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put);
4512
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08004513static int devlink_info_version_put(struct devlink_info_req *req, int attr,
4514 const char *version_name,
4515 const char *version_value)
4516{
4517 struct nlattr *nest;
4518 int err;
4519
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004520 nest = nla_nest_start_noflag(req->msg, attr);
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08004521 if (!nest)
4522 return -EMSGSIZE;
4523
4524 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
4525 version_name);
4526 if (err)
4527 goto nla_put_failure;
4528
4529 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
4530 version_value);
4531 if (err)
4532 goto nla_put_failure;
4533
4534 nla_nest_end(req->msg, nest);
4535
4536 return 0;
4537
4538nla_put_failure:
4539 nla_nest_cancel(req->msg, nest);
4540 return err;
4541}
4542
4543int devlink_info_version_fixed_put(struct devlink_info_req *req,
4544 const char *version_name,
4545 const char *version_value)
4546{
4547 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
4548 version_name, version_value);
4549}
4550EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
4551
4552int devlink_info_version_stored_put(struct devlink_info_req *req,
4553 const char *version_name,
4554 const char *version_value)
4555{
4556 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
4557 version_name, version_value);
4558}
4559EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
4560
4561int devlink_info_version_running_put(struct devlink_info_req *req,
4562 const char *version_name,
4563 const char *version_value)
4564{
4565 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
4566 version_name, version_value);
4567}
4568EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
4569
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004570static int
4571devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
4572 enum devlink_command cmd, u32 portid,
4573 u32 seq, int flags, struct netlink_ext_ack *extack)
4574{
4575 struct devlink_info_req req;
4576 void *hdr;
4577 int err;
4578
4579 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4580 if (!hdr)
4581 return -EMSGSIZE;
4582
4583 err = -EMSGSIZE;
4584 if (devlink_nl_put_handle(msg, devlink))
4585 goto err_cancel_msg;
4586
4587 req.msg = msg;
4588 err = devlink->ops->info_get(devlink, &req, extack);
4589 if (err)
4590 goto err_cancel_msg;
4591
4592 genlmsg_end(msg, hdr);
4593 return 0;
4594
4595err_cancel_msg:
4596 genlmsg_cancel(msg, hdr);
4597 return err;
4598}
4599
4600static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
4601 struct genl_info *info)
4602{
4603 struct devlink *devlink = info->user_ptr[0];
4604 struct sk_buff *msg;
4605 int err;
4606
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08004607 if (!devlink->ops->info_get)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004608 return -EOPNOTSUPP;
4609
4610 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4611 if (!msg)
4612 return -ENOMEM;
4613
4614 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4615 info->snd_portid, info->snd_seq, 0,
4616 info->extack);
4617 if (err) {
4618 nlmsg_free(msg);
4619 return err;
4620 }
4621
4622 return genlmsg_reply(msg, info);
4623}
4624
4625static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
4626 struct netlink_callback *cb)
4627{
4628 struct devlink *devlink;
4629 int start = cb->args[0];
4630 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004631 int err = 0;
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004632
4633 mutex_lock(&devlink_mutex);
4634 list_for_each_entry(devlink, &devlink_list, list) {
4635 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4636 continue;
4637 if (idx < start) {
4638 idx++;
4639 continue;
4640 }
4641
Jiri Pirkoc493b09b2019-03-24 00:21:03 +01004642 if (!devlink->ops->info_get) {
4643 idx++;
4644 continue;
4645 }
4646
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004647 mutex_lock(&devlink->lock);
4648 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4649 NETLINK_CB(cb->skb).portid,
4650 cb->nlh->nlmsg_seq, NLM_F_MULTI,
4651 cb->extack);
4652 mutex_unlock(&devlink->lock);
Vasundhara Volam93c2fcb2019-09-30 11:52:21 +05304653 if (err && err != -EOPNOTSUPP)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004654 break;
4655 idx++;
4656 }
4657 mutex_unlock(&devlink_mutex);
4658
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004659 if (err != -EMSGSIZE)
4660 return err;
4661
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004662 cb->args[0] = idx;
4663 return msg->len;
4664}
4665
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004666struct devlink_fmsg_item {
4667 struct list_head list;
4668 int attrtype;
4669 u8 nla_type;
4670 u16 len;
Gustavo A. R. Silvad2afb412020-02-28 07:43:24 -06004671 int value[];
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004672};
4673
4674struct devlink_fmsg {
4675 struct list_head item_list;
Aya Levin573ed902020-02-11 14:32:42 -08004676 bool putting_binary; /* This flag forces enclosing of binary data
4677 * in an array brackets. It forces using
4678 * of designated API:
4679 * devlink_fmsg_binary_pair_nest_start()
4680 * devlink_fmsg_binary_pair_nest_end()
4681 */
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004682};
4683
4684static struct devlink_fmsg *devlink_fmsg_alloc(void)
4685{
4686 struct devlink_fmsg *fmsg;
4687
4688 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
4689 if (!fmsg)
4690 return NULL;
4691
4692 INIT_LIST_HEAD(&fmsg->item_list);
4693
4694 return fmsg;
4695}
4696
4697static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
4698{
4699 struct devlink_fmsg_item *item, *tmp;
4700
4701 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
4702 list_del(&item->list);
4703 kfree(item);
4704 }
4705 kfree(fmsg);
4706}
4707
4708static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
4709 int attrtype)
4710{
4711 struct devlink_fmsg_item *item;
4712
4713 item = kzalloc(sizeof(*item), GFP_KERNEL);
4714 if (!item)
4715 return -ENOMEM;
4716
4717 item->attrtype = attrtype;
4718 list_add_tail(&item->list, &fmsg->item_list);
4719
4720 return 0;
4721}
4722
4723int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
4724{
Aya Levin573ed902020-02-11 14:32:42 -08004725 if (fmsg->putting_binary)
4726 return -EINVAL;
4727
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004728 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
4729}
4730EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
4731
4732static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
4733{
Aya Levin573ed902020-02-11 14:32:42 -08004734 if (fmsg->putting_binary)
4735 return -EINVAL;
4736
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004737 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
4738}
4739
4740int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
4741{
Aya Levin573ed902020-02-11 14:32:42 -08004742 if (fmsg->putting_binary)
4743 return -EINVAL;
4744
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004745 return devlink_fmsg_nest_end(fmsg);
4746}
4747EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
4748
4749#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
4750
4751static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
4752{
4753 struct devlink_fmsg_item *item;
4754
Aya Levin573ed902020-02-11 14:32:42 -08004755 if (fmsg->putting_binary)
4756 return -EINVAL;
4757
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004758 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4759 return -EMSGSIZE;
4760
4761 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4762 if (!item)
4763 return -ENOMEM;
4764
4765 item->nla_type = NLA_NUL_STRING;
4766 item->len = strlen(name) + 1;
4767 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4768 memcpy(&item->value, name, item->len);
4769 list_add_tail(&item->list, &fmsg->item_list);
4770
4771 return 0;
4772}
4773
4774int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4775{
4776 int err;
4777
Aya Levin573ed902020-02-11 14:32:42 -08004778 if (fmsg->putting_binary)
4779 return -EINVAL;
4780
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004781 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4782 if (err)
4783 return err;
4784
4785 err = devlink_fmsg_put_name(fmsg, name);
4786 if (err)
4787 return err;
4788
4789 return 0;
4790}
4791EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4792
4793int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4794{
Aya Levin573ed902020-02-11 14:32:42 -08004795 if (fmsg->putting_binary)
4796 return -EINVAL;
4797
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004798 return devlink_fmsg_nest_end(fmsg);
4799}
4800EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4801
4802int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4803 const char *name)
4804{
4805 int err;
4806
Aya Levin573ed902020-02-11 14:32:42 -08004807 if (fmsg->putting_binary)
4808 return -EINVAL;
4809
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004810 err = devlink_fmsg_pair_nest_start(fmsg, name);
4811 if (err)
4812 return err;
4813
4814 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4815 if (err)
4816 return err;
4817
4818 return 0;
4819}
4820EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4821
4822int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4823{
4824 int err;
4825
Aya Levin573ed902020-02-11 14:32:42 -08004826 if (fmsg->putting_binary)
4827 return -EINVAL;
4828
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004829 err = devlink_fmsg_nest_end(fmsg);
4830 if (err)
4831 return err;
4832
4833 err = devlink_fmsg_nest_end(fmsg);
4834 if (err)
4835 return err;
4836
4837 return 0;
4838}
4839EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4840
Aya Levin573ed902020-02-11 14:32:42 -08004841int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
4842 const char *name)
4843{
4844 int err;
4845
4846 err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
4847 if (err)
4848 return err;
4849
4850 fmsg->putting_binary = true;
4851 return err;
4852}
4853EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
4854
4855int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
4856{
4857 if (!fmsg->putting_binary)
4858 return -EINVAL;
4859
4860 fmsg->putting_binary = false;
4861 return devlink_fmsg_arr_pair_nest_end(fmsg);
4862}
4863EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
4864
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004865static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4866 const void *value, u16 value_len,
4867 u8 value_nla_type)
4868{
4869 struct devlink_fmsg_item *item;
4870
4871 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4872 return -EMSGSIZE;
4873
4874 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4875 if (!item)
4876 return -ENOMEM;
4877
4878 item->nla_type = value_nla_type;
4879 item->len = value_len;
4880 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4881 memcpy(&item->value, value, item->len);
4882 list_add_tail(&item->list, &fmsg->item_list);
4883
4884 return 0;
4885}
4886
4887int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4888{
Aya Levin573ed902020-02-11 14:32:42 -08004889 if (fmsg->putting_binary)
4890 return -EINVAL;
4891
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004892 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4893}
4894EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4895
4896int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4897{
Aya Levin573ed902020-02-11 14:32:42 -08004898 if (fmsg->putting_binary)
4899 return -EINVAL;
4900
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004901 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4902}
4903EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4904
4905int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4906{
Aya Levin573ed902020-02-11 14:32:42 -08004907 if (fmsg->putting_binary)
4908 return -EINVAL;
4909
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004910 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4911}
4912EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4913
4914int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4915{
Aya Levin573ed902020-02-11 14:32:42 -08004916 if (fmsg->putting_binary)
4917 return -EINVAL;
4918
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004919 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4920}
4921EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4922
4923int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4924{
Aya Levin573ed902020-02-11 14:32:42 -08004925 if (fmsg->putting_binary)
4926 return -EINVAL;
4927
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004928 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4929 NLA_NUL_STRING);
4930}
4931EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4932
Aya Levin573ed902020-02-11 14:32:42 -08004933int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4934 u16 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004935{
Aya Levin573ed902020-02-11 14:32:42 -08004936 if (!fmsg->putting_binary)
4937 return -EINVAL;
4938
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004939 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4940}
Aya Levin573ed902020-02-11 14:32:42 -08004941EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004942
4943int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4944 bool value)
4945{
4946 int err;
4947
4948 err = devlink_fmsg_pair_nest_start(fmsg, name);
4949 if (err)
4950 return err;
4951
4952 err = devlink_fmsg_bool_put(fmsg, value);
4953 if (err)
4954 return err;
4955
4956 err = devlink_fmsg_pair_nest_end(fmsg);
4957 if (err)
4958 return err;
4959
4960 return 0;
4961}
4962EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4963
4964int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4965 u8 value)
4966{
4967 int err;
4968
4969 err = devlink_fmsg_pair_nest_start(fmsg, name);
4970 if (err)
4971 return err;
4972
4973 err = devlink_fmsg_u8_put(fmsg, value);
4974 if (err)
4975 return err;
4976
4977 err = devlink_fmsg_pair_nest_end(fmsg);
4978 if (err)
4979 return err;
4980
4981 return 0;
4982}
4983EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4984
4985int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4986 u32 value)
4987{
4988 int err;
4989
4990 err = devlink_fmsg_pair_nest_start(fmsg, name);
4991 if (err)
4992 return err;
4993
4994 err = devlink_fmsg_u32_put(fmsg, value);
4995 if (err)
4996 return err;
4997
4998 err = devlink_fmsg_pair_nest_end(fmsg);
4999 if (err)
5000 return err;
5001
5002 return 0;
5003}
5004EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
5005
5006int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
5007 u64 value)
5008{
5009 int err;
5010
5011 err = devlink_fmsg_pair_nest_start(fmsg, name);
5012 if (err)
5013 return err;
5014
5015 err = devlink_fmsg_u64_put(fmsg, value);
5016 if (err)
5017 return err;
5018
5019 err = devlink_fmsg_pair_nest_end(fmsg);
5020 if (err)
5021 return err;
5022
5023 return 0;
5024}
5025EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
5026
5027int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
5028 const char *value)
5029{
5030 int err;
5031
5032 err = devlink_fmsg_pair_nest_start(fmsg, name);
5033 if (err)
5034 return err;
5035
5036 err = devlink_fmsg_string_put(fmsg, value);
5037 if (err)
5038 return err;
5039
5040 err = devlink_fmsg_pair_nest_end(fmsg);
5041 if (err)
5042 return err;
5043
5044 return 0;
5045}
5046EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
5047
5048int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
Aya Levine2cde862019-11-12 14:07:49 +02005049 const void *value, u32 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005050{
Aya Levine2cde862019-11-12 14:07:49 +02005051 u32 data_size;
Aya Levin573ed902020-02-11 14:32:42 -08005052 int end_err;
Aya Levine2cde862019-11-12 14:07:49 +02005053 u32 offset;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005054 int err;
5055
Aya Levin573ed902020-02-11 14:32:42 -08005056 err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005057 if (err)
5058 return err;
5059
Aya Levine2cde862019-11-12 14:07:49 +02005060 for (offset = 0; offset < value_len; offset += data_size) {
5061 data_size = value_len - offset;
5062 if (data_size > DEVLINK_FMSG_MAX_SIZE)
5063 data_size = DEVLINK_FMSG_MAX_SIZE;
5064 err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
5065 if (err)
Aya Levin573ed902020-02-11 14:32:42 -08005066 break;
5067 /* Exit from loop with a break (instead of
5068 * return) to make sure putting_binary is turned off in
5069 * devlink_fmsg_binary_pair_nest_end
5070 */
Aya Levine2cde862019-11-12 14:07:49 +02005071 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005072
Aya Levin573ed902020-02-11 14:32:42 -08005073 end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
5074 if (end_err)
5075 err = end_err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005076
Aya Levin573ed902020-02-11 14:32:42 -08005077 return err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005078}
5079EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
5080
5081static int
5082devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5083{
5084 switch (msg->nla_type) {
5085 case NLA_FLAG:
5086 case NLA_U8:
5087 case NLA_U32:
5088 case NLA_U64:
5089 case NLA_NUL_STRING:
5090 case NLA_BINARY:
5091 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
5092 msg->nla_type);
5093 default:
5094 return -EINVAL;
5095 }
5096}
5097
5098static int
5099devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5100{
5101 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5102 u8 tmp;
5103
5104 switch (msg->nla_type) {
5105 case NLA_FLAG:
5106 /* Always provide flag data, regardless of its value */
5107 tmp = *(bool *) msg->value;
5108
5109 return nla_put_u8(skb, attrtype, tmp);
5110 case NLA_U8:
5111 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
5112 case NLA_U32:
5113 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
5114 case NLA_U64:
5115 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
5116 DEVLINK_ATTR_PAD);
5117 case NLA_NUL_STRING:
5118 return nla_put_string(skb, attrtype, (char *) &msg->value);
5119 case NLA_BINARY:
5120 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
5121 default:
5122 return -EINVAL;
5123 }
5124}
5125
5126static int
5127devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5128 int *start)
5129{
5130 struct devlink_fmsg_item *item;
5131 struct nlattr *fmsg_nlattr;
5132 int i = 0;
5133 int err;
5134
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005135 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005136 if (!fmsg_nlattr)
5137 return -EMSGSIZE;
5138
5139 list_for_each_entry(item, &fmsg->item_list, list) {
5140 if (i < *start) {
5141 i++;
5142 continue;
5143 }
5144
5145 switch (item->attrtype) {
5146 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
5147 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
5148 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
5149 case DEVLINK_ATTR_FMSG_NEST_END:
5150 err = nla_put_flag(skb, item->attrtype);
5151 break;
5152 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
5153 err = devlink_fmsg_item_fill_type(item, skb);
5154 if (err)
5155 break;
5156 err = devlink_fmsg_item_fill_data(item, skb);
5157 break;
5158 case DEVLINK_ATTR_FMSG_OBJ_NAME:
5159 err = nla_put_string(skb, item->attrtype,
5160 (char *) &item->value);
5161 break;
5162 default:
5163 err = -EINVAL;
5164 break;
5165 }
5166 if (!err)
5167 *start = ++i;
5168 else
5169 break;
5170 }
5171
5172 nla_nest_end(skb, fmsg_nlattr);
5173 return err;
5174}
5175
5176static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
5177 struct genl_info *info,
5178 enum devlink_command cmd, int flags)
5179{
5180 struct nlmsghdr *nlh;
5181 struct sk_buff *skb;
5182 bool last = false;
5183 int index = 0;
5184 void *hdr;
5185 int err;
5186
5187 while (!last) {
5188 int tmp_index = index;
5189
5190 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5191 if (!skb)
5192 return -ENOMEM;
5193
5194 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
5195 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
5196 if (!hdr) {
5197 err = -EMSGSIZE;
5198 goto nla_put_failure;
5199 }
5200
5201 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5202 if (!err)
5203 last = true;
5204 else if (err != -EMSGSIZE || tmp_index == index)
5205 goto nla_put_failure;
5206
5207 genlmsg_end(skb, hdr);
5208 err = genlmsg_reply(skb, info);
5209 if (err)
5210 return err;
5211 }
5212
5213 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5214 if (!skb)
5215 return -ENOMEM;
5216 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
5217 NLMSG_DONE, 0, flags | NLM_F_MULTI);
5218 if (!nlh) {
5219 err = -EMSGSIZE;
5220 goto nla_put_failure;
5221 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005222
Li RongQingfde55ea2019-02-11 19:09:07 +08005223 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005224
5225nla_put_failure:
5226 nlmsg_free(skb);
5227 return err;
5228}
5229
Aya Levine44ef4e2019-05-16 09:49:20 +03005230static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5231 struct netlink_callback *cb,
5232 enum devlink_command cmd)
5233{
5234 int index = cb->args[0];
5235 int tmp_index = index;
5236 void *hdr;
5237 int err;
5238
5239 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
5240 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
5241 if (!hdr) {
5242 err = -EMSGSIZE;
5243 goto nla_put_failure;
5244 }
5245
5246 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5247 if ((err && err != -EMSGSIZE) || tmp_index == index)
5248 goto nla_put_failure;
5249
5250 cb->args[0] = index;
5251 genlmsg_end(skb, hdr);
5252 return skb->len;
5253
5254nla_put_failure:
5255 genlmsg_cancel(skb, hdr);
5256 return err;
5257}
5258
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005259struct devlink_health_reporter {
5260 struct list_head list;
5261 void *priv;
5262 const struct devlink_health_reporter_ops *ops;
5263 struct devlink *devlink;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005264 struct devlink_fmsg *dump_fmsg;
5265 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005266 u64 graceful_period;
5267 bool auto_recover;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005268 bool auto_dump;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005269 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005270 u64 dump_ts;
Aya Levind2795052019-11-10 14:11:56 +02005271 u64 dump_real_ts;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005272 u64 error_count;
5273 u64 recovery_count;
5274 u64 last_recovery_ts;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005275 refcount_t refcount;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005276};
5277
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005278void *
5279devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
5280{
5281 return reporter->priv;
5282}
5283EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
5284
5285static struct devlink_health_reporter *
5286devlink_health_reporter_find_by_name(struct devlink *devlink,
5287 const char *reporter_name)
5288{
5289 struct devlink_health_reporter *reporter;
5290
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005291 lockdep_assert_held(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005292 list_for_each_entry(reporter, &devlink->reporter_list, list)
5293 if (!strcmp(reporter->ops->name, reporter_name))
5294 return reporter;
5295 return NULL;
5296}
5297
5298/**
5299 * devlink_health_reporter_create - create devlink health reporter
5300 *
5301 * @devlink: devlink
5302 * @ops: ops
5303 * @graceful_period: to avoid recovery loops, in msecs
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005304 * @priv: priv
5305 */
5306struct devlink_health_reporter *
5307devlink_health_reporter_create(struct devlink *devlink,
5308 const struct devlink_health_reporter_ops *ops,
Eran Ben Elishaba7d16c2020-03-29 14:05:54 +03005309 u64 graceful_period, void *priv)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005310{
5311 struct devlink_health_reporter *reporter;
5312
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005313 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005314 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
5315 reporter = ERR_PTR(-EEXIST);
5316 goto unlock;
5317 }
5318
Eran Ben Elishaba7d16c2020-03-29 14:05:54 +03005319 if (WARN_ON(graceful_period && !ops->recover)) {
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005320 reporter = ERR_PTR(-EINVAL);
5321 goto unlock;
5322 }
5323
5324 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
5325 if (!reporter) {
5326 reporter = ERR_PTR(-ENOMEM);
5327 goto unlock;
5328 }
5329
5330 reporter->priv = priv;
5331 reporter->ops = ops;
5332 reporter->devlink = devlink;
5333 reporter->graceful_period = graceful_period;
Eran Ben Elishaba7d16c2020-03-29 14:05:54 +03005334 reporter->auto_recover = !!ops->recover;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005335 reporter->auto_dump = !!ops->dump;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005336 mutex_init(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005337 refcount_set(&reporter->refcount, 1);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005338 list_add_tail(&reporter->list, &devlink->reporter_list);
5339unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005340 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005341 return reporter;
5342}
5343EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
5344
5345/**
5346 * devlink_health_reporter_destroy - destroy devlink health reporter
5347 *
5348 * @reporter: devlink health reporter to destroy
5349 */
5350void
5351devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5352{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005353 mutex_lock(&reporter->devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005354 list_del(&reporter->list);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005355 mutex_unlock(&reporter->devlink->reporters_lock);
5356 while (refcount_read(&reporter->refcount) > 1)
5357 msleep(100);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01005358 mutex_destroy(&reporter->dump_lock);
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005359 if (reporter->dump_fmsg)
5360 devlink_fmsg_free(reporter->dump_fmsg);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005361 kfree(reporter);
5362}
5363EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
5364
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005365static int
5366devlink_nl_health_reporter_fill(struct sk_buff *msg,
5367 struct devlink *devlink,
5368 struct devlink_health_reporter *reporter,
5369 enum devlink_command cmd, u32 portid,
5370 u32 seq, int flags)
5371{
5372 struct nlattr *reporter_attr;
5373 void *hdr;
5374
5375 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5376 if (!hdr)
5377 return -EMSGSIZE;
5378
5379 if (devlink_nl_put_handle(msg, devlink))
5380 goto genlmsg_cancel;
5381
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005382 reporter_attr = nla_nest_start_noflag(msg,
5383 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005384 if (!reporter_attr)
5385 goto genlmsg_cancel;
5386 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
5387 reporter->ops->name))
5388 goto reporter_nest_cancel;
5389 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
5390 reporter->health_state))
5391 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005392 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005393 reporter->error_count, DEVLINK_ATTR_PAD))
5394 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005395 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005396 reporter->recovery_count, DEVLINK_ATTR_PAD))
5397 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005398 if (reporter->ops->recover &&
5399 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005400 reporter->graceful_period,
5401 DEVLINK_ATTR_PAD))
5402 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005403 if (reporter->ops->recover &&
5404 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005405 reporter->auto_recover))
5406 goto reporter_nest_cancel;
5407 if (reporter->dump_fmsg &&
5408 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
5409 jiffies_to_msecs(reporter->dump_ts),
5410 DEVLINK_ATTR_PAD))
5411 goto reporter_nest_cancel;
Aya Levind2795052019-11-10 14:11:56 +02005412 if (reporter->dump_fmsg &&
5413 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
5414 reporter->dump_real_ts, DEVLINK_ATTR_PAD))
5415 goto reporter_nest_cancel;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005416 if (reporter->ops->dump &&
5417 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
5418 reporter->auto_dump))
5419 goto reporter_nest_cancel;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005420
5421 nla_nest_end(msg, reporter_attr);
5422 genlmsg_end(msg, hdr);
5423 return 0;
5424
5425reporter_nest_cancel:
5426 nla_nest_end(msg, reporter_attr);
5427genlmsg_cancel:
5428 genlmsg_cancel(msg, hdr);
5429 return -EMSGSIZE;
5430}
5431
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305432static void devlink_recover_notify(struct devlink_health_reporter *reporter,
5433 enum devlink_command cmd)
5434{
5435 struct sk_buff *msg;
5436 int err;
5437
5438 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5439
5440 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5441 if (!msg)
5442 return;
5443
5444 err = devlink_nl_health_reporter_fill(msg, reporter->devlink,
5445 reporter, cmd, 0, 0, 0);
5446 if (err) {
5447 nlmsg_free(msg);
5448 return;
5449 }
5450
5451 genlmsg_multicast_netns(&devlink_nl_family,
5452 devlink_net(reporter->devlink),
5453 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
5454}
5455
5456void
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005457devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
5458{
5459 reporter->recovery_count++;
5460 reporter->last_recovery_ts = jiffies;
5461}
5462EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
5463
5464static int
5465devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
5466 void *priv_ctx, struct netlink_ext_ack *extack)
5467{
5468 int err;
5469
5470 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
5471 return 0;
5472
5473 if (!reporter->ops->recover)
5474 return -EOPNOTSUPP;
5475
5476 err = reporter->ops->recover(reporter, priv_ctx, extack);
5477 if (err)
5478 return err;
5479
5480 devlink_health_reporter_recovery_done(reporter);
5481 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
5482 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5483
5484 return 0;
5485}
5486
5487static void
5488devlink_health_dump_clear(struct devlink_health_reporter *reporter)
5489{
5490 if (!reporter->dump_fmsg)
5491 return;
5492 devlink_fmsg_free(reporter->dump_fmsg);
5493 reporter->dump_fmsg = NULL;
5494}
5495
5496static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
5497 void *priv_ctx,
5498 struct netlink_ext_ack *extack)
5499{
5500 int err;
5501
5502 if (!reporter->ops->dump)
5503 return 0;
5504
5505 if (reporter->dump_fmsg)
5506 return 0;
5507
5508 reporter->dump_fmsg = devlink_fmsg_alloc();
5509 if (!reporter->dump_fmsg) {
5510 err = -ENOMEM;
5511 return err;
5512 }
5513
5514 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
5515 if (err)
5516 goto dump_err;
5517
5518 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
5519 priv_ctx, extack);
5520 if (err)
5521 goto dump_err;
5522
5523 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
5524 if (err)
5525 goto dump_err;
5526
5527 reporter->dump_ts = jiffies;
5528 reporter->dump_real_ts = ktime_get_real_ns();
5529
5530 return 0;
5531
5532dump_err:
5533 devlink_health_dump_clear(reporter);
5534 return err;
5535}
5536
5537int devlink_health_report(struct devlink_health_reporter *reporter,
5538 const char *msg, void *priv_ctx)
5539{
5540 enum devlink_health_reporter_state prev_health_state;
5541 struct devlink *devlink = reporter->devlink;
Aya Levinbea0c5c2020-05-04 11:27:46 +03005542 unsigned long recover_ts_threshold;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005543
5544 /* write a log message of the current error */
5545 WARN_ON(!msg);
5546 trace_devlink_health_report(devlink, reporter->ops->name, msg);
5547 reporter->error_count++;
5548 prev_health_state = reporter->health_state;
5549 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5550 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5551
5552 /* abort if the previous error wasn't recovered */
Aya Levinbea0c5c2020-05-04 11:27:46 +03005553 recover_ts_threshold = reporter->last_recovery_ts +
5554 msecs_to_jiffies(reporter->graceful_period);
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005555 if (reporter->auto_recover &&
5556 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Aya Levinbea0c5c2020-05-04 11:27:46 +03005557 (reporter->last_recovery_ts && reporter->recovery_count &&
5558 time_is_after_jiffies(recover_ts_threshold)))) {
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005559 trace_devlink_health_recover_aborted(devlink,
5560 reporter->ops->name,
5561 reporter->health_state,
5562 jiffies -
5563 reporter->last_recovery_ts);
5564 return -ECANCELED;
5565 }
5566
5567 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5568
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005569 if (reporter->auto_dump) {
5570 mutex_lock(&reporter->dump_lock);
5571 /* store current dump of current error, for later analysis */
5572 devlink_health_do_dump(reporter, priv_ctx, NULL);
5573 mutex_unlock(&reporter->dump_lock);
5574 }
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005575
5576 if (reporter->auto_recover)
5577 return devlink_health_reporter_recover(reporter,
5578 priv_ctx, NULL);
5579
5580 return 0;
5581}
5582EXPORT_SYMBOL_GPL(devlink_health_report);
5583
5584static struct devlink_health_reporter *
5585devlink_health_reporter_get_from_attrs(struct devlink *devlink,
5586 struct nlattr **attrs)
5587{
5588 struct devlink_health_reporter *reporter;
5589 char *reporter_name;
5590
5591 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
5592 return NULL;
5593
5594 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
5595 mutex_lock(&devlink->reporters_lock);
5596 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
5597 if (reporter)
5598 refcount_inc(&reporter->refcount);
5599 mutex_unlock(&devlink->reporters_lock);
5600 return reporter;
5601}
5602
5603static struct devlink_health_reporter *
5604devlink_health_reporter_get_from_info(struct devlink *devlink,
5605 struct genl_info *info)
5606{
5607 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
5608}
5609
5610static struct devlink_health_reporter *
5611devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
5612{
5613 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
5614 struct devlink_health_reporter *reporter;
5615 struct nlattr **attrs = info->attrs;
5616 struct devlink *devlink;
5617
5618 mutex_lock(&devlink_mutex);
5619 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
5620 if (IS_ERR(devlink))
5621 goto unlock;
5622
5623 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
5624 mutex_unlock(&devlink_mutex);
5625 return reporter;
5626unlock:
5627 mutex_unlock(&devlink_mutex);
5628 return NULL;
5629}
5630
5631static void
5632devlink_health_reporter_put(struct devlink_health_reporter *reporter)
5633{
5634 refcount_dec(&reporter->refcount);
5635}
5636
5637void
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305638devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
5639 enum devlink_health_reporter_state state)
5640{
5641 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
5642 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
5643 return;
5644
5645 if (reporter->health_state == state)
5646 return;
5647
5648 reporter->health_state = state;
5649 trace_devlink_health_reporter_state_update(reporter->devlink,
5650 reporter->ops->name, state);
5651 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5652}
5653EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
5654
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005655static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
5656 struct genl_info *info)
5657{
5658 struct devlink *devlink = info->user_ptr[0];
5659 struct devlink_health_reporter *reporter;
5660 struct sk_buff *msg;
5661 int err;
5662
5663 reporter = devlink_health_reporter_get_from_info(devlink, info);
5664 if (!reporter)
5665 return -EINVAL;
5666
5667 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005668 if (!msg) {
5669 err = -ENOMEM;
5670 goto out;
5671 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005672
5673 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
5674 DEVLINK_CMD_HEALTH_REPORTER_GET,
5675 info->snd_portid, info->snd_seq,
5676 0);
5677 if (err) {
5678 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005679 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005680 }
5681
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005682 err = genlmsg_reply(msg, info);
5683out:
5684 devlink_health_reporter_put(reporter);
5685 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005686}
5687
5688static int
5689devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
5690 struct netlink_callback *cb)
5691{
5692 struct devlink_health_reporter *reporter;
5693 struct devlink *devlink;
5694 int start = cb->args[0];
5695 int idx = 0;
5696 int err;
5697
5698 mutex_lock(&devlink_mutex);
5699 list_for_each_entry(devlink, &devlink_list, list) {
5700 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5701 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005702 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005703 list_for_each_entry(reporter, &devlink->reporter_list,
5704 list) {
5705 if (idx < start) {
5706 idx++;
5707 continue;
5708 }
5709 err = devlink_nl_health_reporter_fill(msg, devlink,
5710 reporter,
5711 DEVLINK_CMD_HEALTH_REPORTER_GET,
5712 NETLINK_CB(cb->skb).portid,
5713 cb->nlh->nlmsg_seq,
5714 NLM_F_MULTI);
5715 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005716 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005717 goto out;
5718 }
5719 idx++;
5720 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005721 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005722 }
5723out:
5724 mutex_unlock(&devlink_mutex);
5725
5726 cb->args[0] = idx;
5727 return msg->len;
5728}
5729
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005730static int
5731devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
5732 struct genl_info *info)
5733{
5734 struct devlink *devlink = info->user_ptr[0];
5735 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005736 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005737
5738 reporter = devlink_health_reporter_get_from_info(devlink, info);
5739 if (!reporter)
5740 return -EINVAL;
5741
5742 if (!reporter->ops->recover &&
5743 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005744 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
5745 err = -EOPNOTSUPP;
5746 goto out;
5747 }
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005748 if (!reporter->ops->dump &&
5749 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
5750 err = -EOPNOTSUPP;
5751 goto out;
5752 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005753
5754 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
5755 reporter->graceful_period =
5756 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
5757
5758 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
5759 reporter->auto_recover =
5760 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
5761
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005762 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
5763 reporter->auto_dump =
5764 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
5765
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005766 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005767 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005768out:
5769 devlink_health_reporter_put(reporter);
5770 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005771}
5772
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005773static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
5774 struct genl_info *info)
5775{
5776 struct devlink *devlink = info->user_ptr[0];
5777 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005778 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005779
5780 reporter = devlink_health_reporter_get_from_info(devlink, info);
5781 if (!reporter)
5782 return -EINVAL;
5783
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005784 err = devlink_health_reporter_recover(reporter, NULL, info->extack);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005785
5786 devlink_health_reporter_put(reporter);
5787 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005788}
5789
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005790static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
5791 struct genl_info *info)
5792{
5793 struct devlink *devlink = info->user_ptr[0];
5794 struct devlink_health_reporter *reporter;
5795 struct devlink_fmsg *fmsg;
5796 int err;
5797
5798 reporter = devlink_health_reporter_get_from_info(devlink, info);
5799 if (!reporter)
5800 return -EINVAL;
5801
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005802 if (!reporter->ops->diagnose) {
5803 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005804 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005805 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005806
5807 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005808 if (!fmsg) {
5809 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005810 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005811 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005812
5813 err = devlink_fmsg_obj_nest_start(fmsg);
5814 if (err)
5815 goto out;
5816
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005817 err = reporter->ops->diagnose(reporter, fmsg, info->extack);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005818 if (err)
5819 goto out;
5820
5821 err = devlink_fmsg_obj_nest_end(fmsg);
5822 if (err)
5823 goto out;
5824
5825 err = devlink_fmsg_snd(fmsg, info,
5826 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
5827
5828out:
5829 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005830 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005831 return err;
5832}
5833
Aya Levine44ef4e2019-05-16 09:49:20 +03005834static int
5835devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
5836 struct netlink_callback *cb)
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005837{
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005838 struct devlink_health_reporter *reporter;
Aya Levine44ef4e2019-05-16 09:49:20 +03005839 u64 start = cb->args[0];
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005840 int err;
5841
Aya Levine44ef4e2019-05-16 09:49:20 +03005842 reporter = devlink_health_reporter_get_from_cb(cb);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005843 if (!reporter)
5844 return -EINVAL;
5845
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005846 if (!reporter->ops->dump) {
Aya Levine44ef4e2019-05-16 09:49:20 +03005847 err = -EOPNOTSUPP;
5848 goto out;
5849 }
5850 mutex_lock(&reporter->dump_lock);
5851 if (!start) {
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005852 err = devlink_health_do_dump(reporter, NULL, cb->extack);
Aya Levine44ef4e2019-05-16 09:49:20 +03005853 if (err)
5854 goto unlock;
5855 cb->args[1] = reporter->dump_ts;
5856 }
5857 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
5858 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
5859 err = -EAGAIN;
5860 goto unlock;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005861 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005862
Aya Levine44ef4e2019-05-16 09:49:20 +03005863 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
5864 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
5865unlock:
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005866 mutex_unlock(&reporter->dump_lock);
Aya Levine44ef4e2019-05-16 09:49:20 +03005867out:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005868 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005869 return err;
5870}
5871
5872static int
5873devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
5874 struct genl_info *info)
5875{
5876 struct devlink *devlink = info->user_ptr[0];
5877 struct devlink_health_reporter *reporter;
5878
5879 reporter = devlink_health_reporter_get_from_info(devlink, info);
5880 if (!reporter)
5881 return -EINVAL;
5882
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005883 if (!reporter->ops->dump) {
5884 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005885 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005886 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005887
5888 mutex_lock(&reporter->dump_lock);
5889 devlink_health_dump_clear(reporter);
5890 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005891 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005892 return 0;
5893}
5894
Ido Schimmel0f420b62019-08-17 16:28:17 +03005895struct devlink_stats {
5896 u64 rx_bytes;
5897 u64 rx_packets;
5898 struct u64_stats_sync syncp;
5899};
5900
5901/**
Ido Schimmel1e8c6612020-03-30 22:38:18 +03005902 * struct devlink_trap_policer_item - Packet trap policer attributes.
5903 * @policer: Immutable packet trap policer attributes.
5904 * @rate: Rate in packets / sec.
5905 * @burst: Burst size in packets.
5906 * @list: trap_policer_list member.
5907 *
5908 * Describes packet trap policer attributes. Created by devlink during trap
5909 * policer registration.
5910 */
5911struct devlink_trap_policer_item {
5912 const struct devlink_trap_policer *policer;
5913 u64 rate;
5914 u64 burst;
5915 struct list_head list;
5916};
5917
5918/**
Ido Schimmel0f420b62019-08-17 16:28:17 +03005919 * struct devlink_trap_group_item - Packet trap group attributes.
5920 * @group: Immutable packet trap group attributes.
Ido Schimmelf9f54392020-03-30 22:38:21 +03005921 * @policer_item: Associated policer item. Can be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03005922 * @list: trap_group_list member.
5923 * @stats: Trap group statistics.
5924 *
5925 * Describes packet trap group attributes. Created by devlink during trap
Ido Schimmela09b37f2020-03-22 20:48:29 +02005926 * group registration.
Ido Schimmel0f420b62019-08-17 16:28:17 +03005927 */
5928struct devlink_trap_group_item {
5929 const struct devlink_trap_group *group;
Ido Schimmelf9f54392020-03-30 22:38:21 +03005930 struct devlink_trap_policer_item *policer_item;
Ido Schimmel0f420b62019-08-17 16:28:17 +03005931 struct list_head list;
5932 struct devlink_stats __percpu *stats;
5933};
5934
5935/**
5936 * struct devlink_trap_item - Packet trap attributes.
5937 * @trap: Immutable packet trap attributes.
5938 * @group_item: Associated group item.
5939 * @list: trap_list member.
5940 * @action: Trap action.
5941 * @stats: Trap statistics.
5942 * @priv: Driver private information.
5943 *
5944 * Describes both mutable and immutable packet trap attributes. Created by
5945 * devlink during trap registration and used for all trap related operations.
5946 */
5947struct devlink_trap_item {
5948 const struct devlink_trap *trap;
5949 struct devlink_trap_group_item *group_item;
5950 struct list_head list;
5951 enum devlink_trap_action action;
5952 struct devlink_stats __percpu *stats;
5953 void *priv;
5954};
5955
Ido Schimmel1e8c6612020-03-30 22:38:18 +03005956static struct devlink_trap_policer_item *
5957devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
5958{
5959 struct devlink_trap_policer_item *policer_item;
5960
5961 list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
5962 if (policer_item->policer->id == id)
5963 return policer_item;
5964 }
5965
5966 return NULL;
5967}
5968
Ido Schimmel0f420b62019-08-17 16:28:17 +03005969static struct devlink_trap_item *
5970devlink_trap_item_lookup(struct devlink *devlink, const char *name)
5971{
5972 struct devlink_trap_item *trap_item;
5973
5974 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5975 if (!strcmp(trap_item->trap->name, name))
5976 return trap_item;
5977 }
5978
5979 return NULL;
5980}
5981
5982static struct devlink_trap_item *
5983devlink_trap_item_get_from_info(struct devlink *devlink,
5984 struct genl_info *info)
5985{
5986 struct nlattr *attr;
5987
5988 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
5989 return NULL;
5990 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
5991
5992 return devlink_trap_item_lookup(devlink, nla_data(attr));
5993}
5994
5995static int
5996devlink_trap_action_get_from_info(struct genl_info *info,
5997 enum devlink_trap_action *p_trap_action)
5998{
5999 u8 val;
6000
6001 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
6002 switch (val) {
6003 case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
Ido Schimmel9eefeab2020-05-29 21:36:39 +03006004 case DEVLINK_TRAP_ACTION_TRAP: /* fall-through */
6005 case DEVLINK_TRAP_ACTION_MIRROR:
Ido Schimmel0f420b62019-08-17 16:28:17 +03006006 *p_trap_action = val;
6007 break;
6008 default:
6009 return -EINVAL;
6010 }
6011
6012 return 0;
6013}
6014
6015static int devlink_trap_metadata_put(struct sk_buff *msg,
6016 const struct devlink_trap *trap)
6017{
6018 struct nlattr *attr;
6019
6020 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
6021 if (!attr)
6022 return -EMSGSIZE;
6023
6024 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
6025 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
6026 goto nla_put_failure;
Jiri Pirko85b05892020-02-25 11:45:19 +01006027 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
6028 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
6029 goto nla_put_failure;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006030
6031 nla_nest_end(msg, attr);
6032
6033 return 0;
6034
6035nla_put_failure:
6036 nla_nest_cancel(msg, attr);
6037 return -EMSGSIZE;
6038}
6039
6040static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
6041 struct devlink_stats *stats)
6042{
6043 int i;
6044
6045 memset(stats, 0, sizeof(*stats));
6046 for_each_possible_cpu(i) {
6047 struct devlink_stats *cpu_stats;
6048 u64 rx_packets, rx_bytes;
6049 unsigned int start;
6050
6051 cpu_stats = per_cpu_ptr(trap_stats, i);
6052 do {
6053 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
6054 rx_packets = cpu_stats->rx_packets;
6055 rx_bytes = cpu_stats->rx_bytes;
6056 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
6057
6058 stats->rx_packets += rx_packets;
6059 stats->rx_bytes += rx_bytes;
6060 }
6061}
6062
6063static int devlink_trap_stats_put(struct sk_buff *msg,
6064 struct devlink_stats __percpu *trap_stats)
6065{
6066 struct devlink_stats stats;
6067 struct nlattr *attr;
6068
6069 devlink_trap_stats_read(trap_stats, &stats);
6070
6071 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6072 if (!attr)
6073 return -EMSGSIZE;
6074
6075 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
6076 stats.rx_packets, DEVLINK_ATTR_PAD))
6077 goto nla_put_failure;
6078
6079 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
6080 stats.rx_bytes, DEVLINK_ATTR_PAD))
6081 goto nla_put_failure;
6082
6083 nla_nest_end(msg, attr);
6084
6085 return 0;
6086
6087nla_put_failure:
6088 nla_nest_cancel(msg, attr);
6089 return -EMSGSIZE;
6090}
6091
6092static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
6093 const struct devlink_trap_item *trap_item,
6094 enum devlink_command cmd, u32 portid, u32 seq,
6095 int flags)
6096{
6097 struct devlink_trap_group_item *group_item = trap_item->group_item;
6098 void *hdr;
6099 int err;
6100
6101 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6102 if (!hdr)
6103 return -EMSGSIZE;
6104
6105 if (devlink_nl_put_handle(msg, devlink))
6106 goto nla_put_failure;
6107
6108 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6109 group_item->group->name))
6110 goto nla_put_failure;
6111
6112 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
6113 goto nla_put_failure;
6114
6115 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
6116 goto nla_put_failure;
6117
6118 if (trap_item->trap->generic &&
6119 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6120 goto nla_put_failure;
6121
6122 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
6123 goto nla_put_failure;
6124
6125 err = devlink_trap_metadata_put(msg, trap_item->trap);
6126 if (err)
6127 goto nla_put_failure;
6128
6129 err = devlink_trap_stats_put(msg, trap_item->stats);
6130 if (err)
6131 goto nla_put_failure;
6132
6133 genlmsg_end(msg, hdr);
6134
6135 return 0;
6136
6137nla_put_failure:
6138 genlmsg_cancel(msg, hdr);
6139 return -EMSGSIZE;
6140}
6141
6142static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
6143 struct genl_info *info)
6144{
6145 struct netlink_ext_ack *extack = info->extack;
6146 struct devlink *devlink = info->user_ptr[0];
6147 struct devlink_trap_item *trap_item;
6148 struct sk_buff *msg;
6149 int err;
6150
6151 if (list_empty(&devlink->trap_list))
6152 return -EOPNOTSUPP;
6153
6154 trap_item = devlink_trap_item_get_from_info(devlink, info);
6155 if (!trap_item) {
6156 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6157 return -ENOENT;
6158 }
6159
6160 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6161 if (!msg)
6162 return -ENOMEM;
6163
6164 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6165 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
6166 info->snd_seq, 0);
6167 if (err)
6168 goto err_trap_fill;
6169
6170 return genlmsg_reply(msg, info);
6171
6172err_trap_fill:
6173 nlmsg_free(msg);
6174 return err;
6175}
6176
6177static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
6178 struct netlink_callback *cb)
6179{
6180 struct devlink_trap_item *trap_item;
6181 struct devlink *devlink;
6182 int start = cb->args[0];
6183 int idx = 0;
6184 int err;
6185
6186 mutex_lock(&devlink_mutex);
6187 list_for_each_entry(devlink, &devlink_list, list) {
6188 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6189 continue;
6190 mutex_lock(&devlink->lock);
6191 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6192 if (idx < start) {
6193 idx++;
6194 continue;
6195 }
6196 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6197 DEVLINK_CMD_TRAP_NEW,
6198 NETLINK_CB(cb->skb).portid,
6199 cb->nlh->nlmsg_seq,
6200 NLM_F_MULTI);
6201 if (err) {
6202 mutex_unlock(&devlink->lock);
6203 goto out;
6204 }
6205 idx++;
6206 }
6207 mutex_unlock(&devlink->lock);
6208 }
6209out:
6210 mutex_unlock(&devlink_mutex);
6211
6212 cb->args[0] = idx;
6213 return msg->len;
6214}
6215
6216static int __devlink_trap_action_set(struct devlink *devlink,
6217 struct devlink_trap_item *trap_item,
6218 enum devlink_trap_action trap_action,
6219 struct netlink_ext_ack *extack)
6220{
6221 int err;
6222
6223 if (trap_item->action != trap_action &&
6224 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
6225 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
6226 return 0;
6227 }
6228
6229 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
6230 trap_action);
6231 if (err)
6232 return err;
6233
6234 trap_item->action = trap_action;
6235
6236 return 0;
6237}
6238
6239static int devlink_trap_action_set(struct devlink *devlink,
6240 struct devlink_trap_item *trap_item,
6241 struct genl_info *info)
6242{
6243 enum devlink_trap_action trap_action;
6244 int err;
6245
6246 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6247 return 0;
6248
6249 err = devlink_trap_action_get_from_info(info, &trap_action);
6250 if (err) {
6251 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6252 return -EINVAL;
6253 }
6254
6255 return __devlink_trap_action_set(devlink, trap_item, trap_action,
6256 info->extack);
6257}
6258
6259static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
6260 struct genl_info *info)
6261{
6262 struct netlink_ext_ack *extack = info->extack;
6263 struct devlink *devlink = info->user_ptr[0];
6264 struct devlink_trap_item *trap_item;
6265 int err;
6266
6267 if (list_empty(&devlink->trap_list))
6268 return -EOPNOTSUPP;
6269
6270 trap_item = devlink_trap_item_get_from_info(devlink, info);
6271 if (!trap_item) {
6272 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6273 return -ENOENT;
6274 }
6275
6276 err = devlink_trap_action_set(devlink, trap_item, info);
6277 if (err)
6278 return err;
6279
6280 return 0;
6281}
6282
6283static struct devlink_trap_group_item *
6284devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
6285{
6286 struct devlink_trap_group_item *group_item;
6287
6288 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6289 if (!strcmp(group_item->group->name, name))
6290 return group_item;
6291 }
6292
6293 return NULL;
6294}
6295
6296static struct devlink_trap_group_item *
Ido Schimmel107f1672020-03-22 20:48:30 +02006297devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
6298{
6299 struct devlink_trap_group_item *group_item;
6300
6301 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6302 if (group_item->group->id == id)
6303 return group_item;
6304 }
6305
6306 return NULL;
6307}
6308
6309static struct devlink_trap_group_item *
Ido Schimmel0f420b62019-08-17 16:28:17 +03006310devlink_trap_group_item_get_from_info(struct devlink *devlink,
6311 struct genl_info *info)
6312{
6313 char *name;
6314
6315 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
6316 return NULL;
6317 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
6318
6319 return devlink_trap_group_item_lookup(devlink, name);
6320}
6321
6322static int
6323devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
6324 const struct devlink_trap_group_item *group_item,
6325 enum devlink_command cmd, u32 portid, u32 seq,
6326 int flags)
6327{
6328 void *hdr;
6329 int err;
6330
6331 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6332 if (!hdr)
6333 return -EMSGSIZE;
6334
6335 if (devlink_nl_put_handle(msg, devlink))
6336 goto nla_put_failure;
6337
6338 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6339 group_item->group->name))
6340 goto nla_put_failure;
6341
6342 if (group_item->group->generic &&
6343 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6344 goto nla_put_failure;
6345
Ido Schimmelf9f54392020-03-30 22:38:21 +03006346 if (group_item->policer_item &&
6347 nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6348 group_item->policer_item->policer->id))
6349 goto nla_put_failure;
6350
Ido Schimmel0f420b62019-08-17 16:28:17 +03006351 err = devlink_trap_stats_put(msg, group_item->stats);
6352 if (err)
6353 goto nla_put_failure;
6354
6355 genlmsg_end(msg, hdr);
6356
6357 return 0;
6358
6359nla_put_failure:
6360 genlmsg_cancel(msg, hdr);
6361 return -EMSGSIZE;
6362}
6363
6364static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
6365 struct genl_info *info)
6366{
6367 struct netlink_ext_ack *extack = info->extack;
6368 struct devlink *devlink = info->user_ptr[0];
6369 struct devlink_trap_group_item *group_item;
6370 struct sk_buff *msg;
6371 int err;
6372
6373 if (list_empty(&devlink->trap_group_list))
6374 return -EOPNOTSUPP;
6375
6376 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6377 if (!group_item) {
6378 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6379 return -ENOENT;
6380 }
6381
6382 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6383 if (!msg)
6384 return -ENOMEM;
6385
6386 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
6387 DEVLINK_CMD_TRAP_GROUP_NEW,
6388 info->snd_portid, info->snd_seq, 0);
6389 if (err)
6390 goto err_trap_group_fill;
6391
6392 return genlmsg_reply(msg, info);
6393
6394err_trap_group_fill:
6395 nlmsg_free(msg);
6396 return err;
6397}
6398
6399static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
6400 struct netlink_callback *cb)
6401{
6402 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
6403 struct devlink_trap_group_item *group_item;
6404 u32 portid = NETLINK_CB(cb->skb).portid;
6405 struct devlink *devlink;
6406 int start = cb->args[0];
6407 int idx = 0;
6408 int err;
6409
6410 mutex_lock(&devlink_mutex);
6411 list_for_each_entry(devlink, &devlink_list, list) {
6412 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6413 continue;
6414 mutex_lock(&devlink->lock);
6415 list_for_each_entry(group_item, &devlink->trap_group_list,
6416 list) {
6417 if (idx < start) {
6418 idx++;
6419 continue;
6420 }
6421 err = devlink_nl_trap_group_fill(msg, devlink,
6422 group_item, cmd,
6423 portid,
6424 cb->nlh->nlmsg_seq,
6425 NLM_F_MULTI);
6426 if (err) {
6427 mutex_unlock(&devlink->lock);
6428 goto out;
6429 }
6430 idx++;
6431 }
6432 mutex_unlock(&devlink->lock);
6433 }
6434out:
6435 mutex_unlock(&devlink_mutex);
6436
6437 cb->args[0] = idx;
6438 return msg->len;
6439}
6440
6441static int
6442__devlink_trap_group_action_set(struct devlink *devlink,
6443 struct devlink_trap_group_item *group_item,
6444 enum devlink_trap_action trap_action,
6445 struct netlink_ext_ack *extack)
6446{
6447 const char *group_name = group_item->group->name;
6448 struct devlink_trap_item *trap_item;
6449 int err;
6450
6451 list_for_each_entry(trap_item, &devlink->trap_list, list) {
Ido Schimmel107f1672020-03-22 20:48:30 +02006452 if (strcmp(trap_item->group_item->group->name, group_name))
Ido Schimmel0f420b62019-08-17 16:28:17 +03006453 continue;
6454 err = __devlink_trap_action_set(devlink, trap_item,
6455 trap_action, extack);
6456 if (err)
6457 return err;
6458 }
6459
6460 return 0;
6461}
6462
6463static int
6464devlink_trap_group_action_set(struct devlink *devlink,
6465 struct devlink_trap_group_item *group_item,
Ido Schimmelc0648752020-03-30 22:38:22 +03006466 struct genl_info *info, bool *p_modified)
Ido Schimmel0f420b62019-08-17 16:28:17 +03006467{
6468 enum devlink_trap_action trap_action;
6469 int err;
6470
6471 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6472 return 0;
6473
6474 err = devlink_trap_action_get_from_info(info, &trap_action);
6475 if (err) {
6476 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6477 return -EINVAL;
6478 }
6479
6480 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
6481 info->extack);
6482 if (err)
6483 return err;
6484
Ido Schimmelc0648752020-03-30 22:38:22 +03006485 *p_modified = true;
6486
6487 return 0;
6488}
6489
6490static int devlink_trap_group_set(struct devlink *devlink,
6491 struct devlink_trap_group_item *group_item,
6492 struct genl_info *info)
6493{
6494 struct devlink_trap_policer_item *policer_item;
6495 struct netlink_ext_ack *extack = info->extack;
6496 const struct devlink_trap_policer *policer;
6497 struct nlattr **attrs = info->attrs;
6498 int err;
6499
6500 if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6501 return 0;
6502
6503 if (!devlink->ops->trap_group_set)
6504 return -EOPNOTSUPP;
6505
6506 policer_item = group_item->policer_item;
6507 if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) {
6508 u32 policer_id;
6509
6510 policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6511 policer_item = devlink_trap_policer_item_lookup(devlink,
6512 policer_id);
6513 if (policer_id && !policer_item) {
6514 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6515 return -ENOENT;
6516 }
6517 }
6518 policer = policer_item ? policer_item->policer : NULL;
6519
6520 err = devlink->ops->trap_group_set(devlink, group_item->group, policer);
6521 if (err)
6522 return err;
6523
6524 group_item->policer_item = policer_item;
6525
Ido Schimmel0f420b62019-08-17 16:28:17 +03006526 return 0;
6527}
6528
6529static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
6530 struct genl_info *info)
6531{
6532 struct netlink_ext_ack *extack = info->extack;
6533 struct devlink *devlink = info->user_ptr[0];
6534 struct devlink_trap_group_item *group_item;
Ido Schimmelc0648752020-03-30 22:38:22 +03006535 bool modified = false;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006536 int err;
6537
6538 if (list_empty(&devlink->trap_group_list))
6539 return -EOPNOTSUPP;
6540
6541 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6542 if (!group_item) {
6543 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6544 return -ENOENT;
6545 }
6546
Ido Schimmelc0648752020-03-30 22:38:22 +03006547 err = devlink_trap_group_action_set(devlink, group_item, info,
6548 &modified);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006549 if (err)
6550 return err;
6551
Ido Schimmelc0648752020-03-30 22:38:22 +03006552 err = devlink_trap_group_set(devlink, group_item, info);
6553 if (err)
6554 goto err_trap_group_set;
6555
Ido Schimmel0f420b62019-08-17 16:28:17 +03006556 return 0;
Ido Schimmelc0648752020-03-30 22:38:22 +03006557
6558err_trap_group_set:
6559 if (modified)
6560 NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already");
6561 return err;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006562}
6563
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006564static struct devlink_trap_policer_item *
6565devlink_trap_policer_item_get_from_info(struct devlink *devlink,
6566 struct genl_info *info)
6567{
6568 u32 id;
6569
6570 if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6571 return NULL;
6572 id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6573
6574 return devlink_trap_policer_item_lookup(devlink, id);
6575}
6576
6577static int
6578devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
6579 const struct devlink_trap_policer *policer)
6580{
6581 struct nlattr *attr;
6582 u64 drops;
6583 int err;
6584
6585 if (!devlink->ops->trap_policer_counter_get)
6586 return 0;
6587
6588 err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
6589 if (err)
6590 return err;
6591
6592 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6593 if (!attr)
6594 return -EMSGSIZE;
6595
6596 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
6597 DEVLINK_ATTR_PAD))
6598 goto nla_put_failure;
6599
6600 nla_nest_end(msg, attr);
6601
6602 return 0;
6603
6604nla_put_failure:
6605 nla_nest_cancel(msg, attr);
6606 return -EMSGSIZE;
6607}
6608
6609static int
6610devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
6611 const struct devlink_trap_policer_item *policer_item,
6612 enum devlink_command cmd, u32 portid, u32 seq,
6613 int flags)
6614{
6615 void *hdr;
6616 int err;
6617
6618 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6619 if (!hdr)
6620 return -EMSGSIZE;
6621
6622 if (devlink_nl_put_handle(msg, devlink))
6623 goto nla_put_failure;
6624
6625 if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6626 policer_item->policer->id))
6627 goto nla_put_failure;
6628
6629 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
6630 policer_item->rate, DEVLINK_ATTR_PAD))
6631 goto nla_put_failure;
6632
6633 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
6634 policer_item->burst, DEVLINK_ATTR_PAD))
6635 goto nla_put_failure;
6636
6637 err = devlink_trap_policer_stats_put(msg, devlink,
6638 policer_item->policer);
6639 if (err)
6640 goto nla_put_failure;
6641
6642 genlmsg_end(msg, hdr);
6643
6644 return 0;
6645
6646nla_put_failure:
6647 genlmsg_cancel(msg, hdr);
6648 return -EMSGSIZE;
6649}
6650
6651static int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
6652 struct genl_info *info)
6653{
6654 struct devlink_trap_policer_item *policer_item;
6655 struct netlink_ext_ack *extack = info->extack;
6656 struct devlink *devlink = info->user_ptr[0];
6657 struct sk_buff *msg;
6658 int err;
6659
6660 if (list_empty(&devlink->trap_policer_list))
6661 return -EOPNOTSUPP;
6662
6663 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
6664 if (!policer_item) {
6665 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6666 return -ENOENT;
6667 }
6668
6669 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6670 if (!msg)
6671 return -ENOMEM;
6672
6673 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
6674 DEVLINK_CMD_TRAP_POLICER_NEW,
6675 info->snd_portid, info->snd_seq, 0);
6676 if (err)
6677 goto err_trap_policer_fill;
6678
6679 return genlmsg_reply(msg, info);
6680
6681err_trap_policer_fill:
6682 nlmsg_free(msg);
6683 return err;
6684}
6685
6686static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,
6687 struct netlink_callback *cb)
6688{
6689 enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW;
6690 struct devlink_trap_policer_item *policer_item;
6691 u32 portid = NETLINK_CB(cb->skb).portid;
6692 struct devlink *devlink;
6693 int start = cb->args[0];
6694 int idx = 0;
6695 int err;
6696
6697 mutex_lock(&devlink_mutex);
6698 list_for_each_entry(devlink, &devlink_list, list) {
6699 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6700 continue;
6701 mutex_lock(&devlink->lock);
6702 list_for_each_entry(policer_item, &devlink->trap_policer_list,
6703 list) {
6704 if (idx < start) {
6705 idx++;
6706 continue;
6707 }
6708 err = devlink_nl_trap_policer_fill(msg, devlink,
6709 policer_item, cmd,
6710 portid,
6711 cb->nlh->nlmsg_seq,
6712 NLM_F_MULTI);
6713 if (err) {
6714 mutex_unlock(&devlink->lock);
6715 goto out;
6716 }
6717 idx++;
6718 }
6719 mutex_unlock(&devlink->lock);
6720 }
6721out:
6722 mutex_unlock(&devlink_mutex);
6723
6724 cb->args[0] = idx;
6725 return msg->len;
6726}
6727
6728static int
6729devlink_trap_policer_set(struct devlink *devlink,
6730 struct devlink_trap_policer_item *policer_item,
6731 struct genl_info *info)
6732{
6733 struct netlink_ext_ack *extack = info->extack;
6734 struct nlattr **attrs = info->attrs;
6735 u64 rate, burst;
6736 int err;
6737
6738 rate = policer_item->rate;
6739 burst = policer_item->burst;
6740
6741 if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
6742 rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
6743
6744 if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
6745 burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
6746
6747 if (rate < policer_item->policer->min_rate) {
6748 NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
6749 return -EINVAL;
6750 }
6751
6752 if (rate > policer_item->policer->max_rate) {
6753 NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
6754 return -EINVAL;
6755 }
6756
6757 if (burst < policer_item->policer->min_burst) {
6758 NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
6759 return -EINVAL;
6760 }
6761
6762 if (burst > policer_item->policer->max_burst) {
6763 NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
6764 return -EINVAL;
6765 }
6766
6767 err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
6768 rate, burst, info->extack);
6769 if (err)
6770 return err;
6771
6772 policer_item->rate = rate;
6773 policer_item->burst = burst;
6774
6775 return 0;
6776}
6777
6778static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
6779 struct genl_info *info)
6780{
6781 struct devlink_trap_policer_item *policer_item;
6782 struct netlink_ext_ack *extack = info->extack;
6783 struct devlink *devlink = info->user_ptr[0];
6784
6785 if (list_empty(&devlink->trap_policer_list))
6786 return -EOPNOTSUPP;
6787
6788 if (!devlink->ops->trap_policer_set)
6789 return -EOPNOTSUPP;
6790
6791 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
6792 if (!policer_item) {
6793 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6794 return -ENOENT;
6795 }
6796
6797 return devlink_trap_policer_set(devlink, policer_item, info);
6798}
6799
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006800static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006801 [DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
6802 DEVLINK_ATTR_TRAP_POLICER_ID },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006803 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
6804 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
6805 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
6806 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
6807 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02006808 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
6809 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
6810 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
6811 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
6812 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
6813 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
6814 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03006815 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
Roi Dayan59bfde02016-11-22 23:09:57 +02006816 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03006817 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006818 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
6819 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006820 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
6821 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03006822 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
6823 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
6824 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03006825 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03006826 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Jakub Kicinskiff3b63b2020-03-02 21:05:12 -08006827 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
6828 [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006829 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006830 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
6831 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08006832 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
6833 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Ido Schimmel0f420b62019-08-17 16:28:17 +03006834 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
6835 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
6836 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
Jiri Pirko070c63f2019-10-03 11:49:39 +02006837 [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
6838 [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
6839 [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006840 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006841 [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
6842 [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
6843 [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
Parav Pandita1e8ae92020-06-19 03:32:49 +00006844 [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006845};
6846
6847static const struct genl_ops devlink_nl_ops[] = {
6848 {
6849 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006850 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006851 .doit = devlink_nl_cmd_get_doit,
6852 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirko1fc22572016-04-08 19:12:48 +02006853 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006854 /* can be retrieved by unprivileged users */
6855 },
6856 {
6857 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006858 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006859 .doit = devlink_nl_cmd_port_get_doit,
6860 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006861 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
6862 /* can be retrieved by unprivileged users */
6863 },
6864 {
6865 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006866 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006867 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006868 .flags = GENL_ADMIN_PERM,
6869 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
6870 },
6871 {
6872 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02006873 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006874 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006875 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006876 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6877 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006878 },
6879 {
6880 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02006881 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006882 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006883 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006884 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6885 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006886 },
Jiri Pirkobf797472016-04-14 18:19:13 +02006887 {
6888 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006889 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006890 .doit = devlink_nl_cmd_sb_get_doit,
6891 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006892 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6893 DEVLINK_NL_FLAG_NEED_SB,
6894 /* can be retrieved by unprivileged users */
6895 },
6896 {
6897 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006898 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006899 .doit = devlink_nl_cmd_sb_pool_get_doit,
6900 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006901 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6902 DEVLINK_NL_FLAG_NEED_SB,
6903 /* can be retrieved by unprivileged users */
6904 },
6905 {
6906 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006907 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006908 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006909 .flags = GENL_ADMIN_PERM,
6910 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6911 DEVLINK_NL_FLAG_NEED_SB,
6912 },
6913 {
6914 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006915 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006916 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
6917 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006918 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
6919 DEVLINK_NL_FLAG_NEED_SB,
6920 /* can be retrieved by unprivileged users */
6921 },
6922 {
6923 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006924 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006925 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006926 .flags = GENL_ADMIN_PERM,
6927 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
6928 DEVLINK_NL_FLAG_NEED_SB,
6929 },
6930 {
6931 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006932 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006933 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
6934 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006935 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
6936 DEVLINK_NL_FLAG_NEED_SB,
6937 /* can be retrieved by unprivileged users */
6938 },
6939 {
6940 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006941 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006942 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006943 .flags = GENL_ADMIN_PERM,
6944 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
6945 DEVLINK_NL_FLAG_NEED_SB,
6946 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006947 {
6948 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02006949 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006950 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006951 .flags = GENL_ADMIN_PERM,
6952 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006953 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006954 },
6955 {
6956 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02006957 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006958 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006959 .flags = GENL_ADMIN_PERM,
6960 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006961 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006962 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03006963 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01006964 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006965 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01006966 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03006967 .flags = GENL_ADMIN_PERM,
Parav Pandit98fed6e2020-02-23 19:06:56 -06006968 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6969 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03006970 },
6971 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01006972 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006973 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01006974 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03006975 .flags = GENL_ADMIN_PERM,
Jakub Kicinski7ac1cc92018-05-21 22:12:50 -07006976 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6977 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03006978 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006979 {
6980 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006981 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006982 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006983 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02006984 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006985 },
6986 {
6987 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006988 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006989 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006990 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02006991 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006992 },
6993 {
6994 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006995 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006996 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006997 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02006998 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006999 },
7000 {
7001 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007002 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007003 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007004 .flags = GENL_ADMIN_PERM,
7005 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7006 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007007 {
7008 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007009 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007010 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007011 .flags = GENL_ADMIN_PERM,
7012 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7013 },
7014 {
7015 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02007016 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007017 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007018 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007019 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007020 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007021 {
7022 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02007023 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007024 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007025 .flags = GENL_ADMIN_PERM,
7026 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7027 DEVLINK_NL_FLAG_NO_LOCK,
7028 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007029 {
7030 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007031 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007032 .doit = devlink_nl_cmd_param_get_doit,
7033 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007034 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7035 /* can be retrieved by unprivileged users */
7036 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007037 {
7038 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007039 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007040 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007041 .flags = GENL_ADMIN_PERM,
7042 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7043 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007044 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307045 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007046 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307047 .doit = devlink_nl_cmd_port_param_get_doit,
7048 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307049 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7050 /* can be retrieved by unprivileged users */
7051 },
7052 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05307053 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007054 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307055 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307056 .flags = GENL_ADMIN_PERM,
7057 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7058 },
7059 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007060 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007061 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007062 .doit = devlink_nl_cmd_region_get_doit,
7063 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007064 .flags = GENL_ADMIN_PERM,
7065 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7066 },
Alex Vesker866319b2018-07-12 15:13:13 +03007067 {
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07007068 .cmd = DEVLINK_CMD_REGION_NEW,
7069 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7070 .doit = devlink_nl_cmd_region_new,
7071 .flags = GENL_ADMIN_PERM,
7072 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7073 },
7074 {
Alex Vesker866319b2018-07-12 15:13:13 +03007075 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02007076 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03007077 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03007078 .flags = GENL_ADMIN_PERM,
7079 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7080 },
Alex Vesker4e547952018-07-12 15:13:14 +03007081 {
7082 .cmd = DEVLINK_CMD_REGION_READ,
Jiri Pirkoee85da52019-10-05 20:04:42 +02007083 .validate = GENL_DONT_VALIDATE_STRICT |
7084 GENL_DONT_VALIDATE_DUMP_STRICT,
Alex Vesker4e547952018-07-12 15:13:14 +03007085 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03007086 .flags = GENL_ADMIN_PERM,
7087 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7088 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007089 {
7090 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007091 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007092 .doit = devlink_nl_cmd_info_get_doit,
7093 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007094 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7095 /* can be retrieved by unprivileged users */
7096 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007097 {
7098 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007099 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007100 .doit = devlink_nl_cmd_health_reporter_get_doit,
7101 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007102 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7103 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007104 /* can be retrieved by unprivileged users */
7105 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007106 {
7107 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007108 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007109 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007110 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007111 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7112 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007113 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007114 {
7115 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02007116 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007117 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007118 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007119 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7120 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007121 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007122 {
7123 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007124 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007125 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007126 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007127 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7128 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007129 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007130 {
7131 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Jiri Pirko82a843d2019-10-07 09:28:31 +02007132 .validate = GENL_DONT_VALIDATE_STRICT |
7133 GENL_DONT_VALIDATE_DUMP_STRICT,
Aya Levine44ef4e2019-05-16 09:49:20 +03007134 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007135 .flags = GENL_ADMIN_PERM,
7136 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7137 DEVLINK_NL_FLAG_NO_LOCK,
7138 },
7139 {
7140 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007141 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007142 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007143 .flags = GENL_ADMIN_PERM,
7144 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7145 DEVLINK_NL_FLAG_NO_LOCK,
7146 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007147 {
7148 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007149 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007150 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007151 .flags = GENL_ADMIN_PERM,
7152 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7153 },
Ido Schimmel0f420b62019-08-17 16:28:17 +03007154 {
7155 .cmd = DEVLINK_CMD_TRAP_GET,
7156 .doit = devlink_nl_cmd_trap_get_doit,
7157 .dumpit = devlink_nl_cmd_trap_get_dumpit,
7158 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7159 /* can be retrieved by unprivileged users */
7160 },
7161 {
7162 .cmd = DEVLINK_CMD_TRAP_SET,
7163 .doit = devlink_nl_cmd_trap_set_doit,
7164 .flags = GENL_ADMIN_PERM,
7165 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7166 },
7167 {
7168 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
7169 .doit = devlink_nl_cmd_trap_group_get_doit,
7170 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
7171 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7172 /* can be retrieved by unprivileged users */
7173 },
7174 {
7175 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
7176 .doit = devlink_nl_cmd_trap_group_set_doit,
7177 .flags = GENL_ADMIN_PERM,
7178 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7179 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007180 {
7181 .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
7182 .doit = devlink_nl_cmd_trap_policer_get_doit,
7183 .dumpit = devlink_nl_cmd_trap_policer_get_dumpit,
7184 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7185 /* can be retrieved by unprivileged users */
7186 },
7187 {
7188 .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
7189 .doit = devlink_nl_cmd_trap_policer_set_doit,
7190 .flags = GENL_ADMIN_PERM,
7191 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7192 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007193};
7194
Johannes Berg56989f62016-10-24 14:40:05 +02007195static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02007196 .name = DEVLINK_GENL_NAME,
7197 .version = DEVLINK_GENL_VERSION,
7198 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01007199 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02007200 .netnsok = true,
7201 .pre_doit = devlink_nl_pre_doit,
7202 .post_doit = devlink_nl_post_doit,
7203 .module = THIS_MODULE,
7204 .ops = devlink_nl_ops,
7205 .n_ops = ARRAY_SIZE(devlink_nl_ops),
7206 .mcgrps = devlink_nl_mcgrps,
7207 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
7208};
7209
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007210/**
7211 * devlink_alloc - Allocate new devlink instance resources
7212 *
7213 * @ops: ops
7214 * @priv_size: size of user private data
7215 *
7216 * Allocate new devlink instance resources, including devlink index
7217 * and name.
7218 */
7219struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
7220{
7221 struct devlink *devlink;
7222
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007223 if (WARN_ON(!ops))
7224 return NULL;
7225
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007226 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
7227 if (!devlink)
7228 return NULL;
7229 devlink->ops = ops;
Jacob Keller12102432020-03-26 11:37:15 -07007230 xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
Jiri Pirko8273fd82019-10-05 08:10:31 +02007231 __devlink_net_set(devlink, &init_net);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007232 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02007233 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007234 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007235 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03007236 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03007237 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02007238 INIT_LIST_HEAD(&devlink->reporter_list);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007239 INIT_LIST_HEAD(&devlink->trap_list);
7240 INIT_LIST_HEAD(&devlink->trap_group_list);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007241 INIT_LIST_HEAD(&devlink->trap_policer_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007242 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007243 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007244 return devlink;
7245}
7246EXPORT_SYMBOL_GPL(devlink_alloc);
7247
7248/**
7249 * devlink_register - Register devlink instance
7250 *
7251 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007252 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007253 */
7254int devlink_register(struct devlink *devlink, struct device *dev)
7255{
7256 mutex_lock(&devlink_mutex);
7257 devlink->dev = dev;
Jiri Pirko8273fd82019-10-05 08:10:31 +02007258 devlink->registered = true;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007259 list_add_tail(&devlink->list, &devlink_list);
7260 devlink_notify(devlink, DEVLINK_CMD_NEW);
7261 mutex_unlock(&devlink_mutex);
7262 return 0;
7263}
7264EXPORT_SYMBOL_GPL(devlink_register);
7265
7266/**
7267 * devlink_unregister - Unregister devlink instance
7268 *
7269 * @devlink: devlink
7270 */
7271void devlink_unregister(struct devlink *devlink)
7272{
7273 mutex_lock(&devlink_mutex);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007274 WARN_ON(devlink_reload_supported(devlink) &&
7275 devlink->reload_enabled);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007276 devlink_notify(devlink, DEVLINK_CMD_DEL);
7277 list_del(&devlink->list);
7278 mutex_unlock(&devlink_mutex);
7279}
7280EXPORT_SYMBOL_GPL(devlink_unregister);
7281
7282/**
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007283 * devlink_reload_enable - Enable reload of devlink instance
7284 *
7285 * @devlink: devlink
7286 *
7287 * Should be called at end of device initialization
7288 * process when reload operation is supported.
7289 */
7290void devlink_reload_enable(struct devlink *devlink)
7291{
7292 mutex_lock(&devlink_mutex);
7293 devlink->reload_enabled = true;
7294 mutex_unlock(&devlink_mutex);
7295}
7296EXPORT_SYMBOL_GPL(devlink_reload_enable);
7297
7298/**
7299 * devlink_reload_disable - Disable reload of devlink instance
7300 *
7301 * @devlink: devlink
7302 *
7303 * Should be called at the beginning of device cleanup
7304 * process when reload operation is supported.
7305 */
7306void devlink_reload_disable(struct devlink *devlink)
7307{
7308 mutex_lock(&devlink_mutex);
7309 /* Mutex is taken which ensures that no reload operation is in
7310 * progress while setting up forbidded flag.
7311 */
7312 devlink->reload_enabled = false;
7313 mutex_unlock(&devlink_mutex);
7314}
7315EXPORT_SYMBOL_GPL(devlink_reload_disable);
7316
7317/**
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007318 * devlink_free - Free devlink instance resources
7319 *
7320 * @devlink: devlink
7321 */
7322void devlink_free(struct devlink *devlink)
7323{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007324 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01007325 mutex_destroy(&devlink->lock);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007326 WARN_ON(!list_empty(&devlink->trap_policer_list));
Ido Schimmel0f420b62019-08-17 16:28:17 +03007327 WARN_ON(!list_empty(&devlink->trap_group_list));
7328 WARN_ON(!list_empty(&devlink->trap_list));
Parav Panditb904aad2019-02-08 15:15:00 -06007329 WARN_ON(!list_empty(&devlink->reporter_list));
7330 WARN_ON(!list_empty(&devlink->region_list));
7331 WARN_ON(!list_empty(&devlink->param_list));
7332 WARN_ON(!list_empty(&devlink->resource_list));
7333 WARN_ON(!list_empty(&devlink->dpipe_table_list));
7334 WARN_ON(!list_empty(&devlink->sb_list));
7335 WARN_ON(!list_empty(&devlink->port_list));
7336
Jacob Keller12102432020-03-26 11:37:15 -07007337 xa_destroy(&devlink->snapshot_ids);
7338
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007339 kfree(devlink);
7340}
7341EXPORT_SYMBOL_GPL(devlink_free);
7342
Jiri Pirko136bf272019-05-23 10:43:35 +02007343static void devlink_port_type_warn(struct work_struct *work)
7344{
7345 WARN(true, "Type was not set for devlink port.");
7346}
7347
7348static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
7349{
7350 /* Ignore CPU and DSA flavours. */
7351 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
7352 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
7353}
7354
Ido Schimmel4c582232020-01-09 19:57:41 +02007355#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
Jiri Pirko136bf272019-05-23 10:43:35 +02007356
7357static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
7358{
7359 if (!devlink_port_type_should_warn(devlink_port))
7360 return;
7361 /* Schedule a work to WARN in case driver does not set port
7362 * type within timeout.
7363 */
7364 schedule_delayed_work(&devlink_port->type_warn_dw,
7365 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
7366}
7367
7368static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
7369{
7370 if (!devlink_port_type_should_warn(devlink_port))
7371 return;
7372 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
7373}
7374
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007375/**
7376 * devlink_port_register - Register devlink port
7377 *
7378 * @devlink: devlink
7379 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007380 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007381 *
7382 * Register devlink port with provided port index. User can use
7383 * any indexing, even hw-related one. devlink_port structure
7384 * is convenient to be embedded inside user driver private structure.
7385 * Note that the caller should take care of zeroing the devlink_port
7386 * structure.
7387 */
7388int devlink_port_register(struct devlink *devlink,
7389 struct devlink_port *devlink_port,
7390 unsigned int port_index)
7391{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007392 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007393 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007394 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007395 return -EEXIST;
7396 }
7397 devlink_port->devlink = devlink;
7398 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007399 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01007400 spin_lock_init(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007401 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05307402 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007403 mutex_unlock(&devlink->lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02007404 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
7405 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007406 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7407 return 0;
7408}
7409EXPORT_SYMBOL_GPL(devlink_port_register);
7410
7411/**
7412 * devlink_port_unregister - Unregister devlink port
7413 *
7414 * @devlink_port: devlink port
7415 */
7416void devlink_port_unregister(struct devlink_port *devlink_port)
7417{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007418 struct devlink *devlink = devlink_port->devlink;
7419
Jiri Pirko136bf272019-05-23 10:43:35 +02007420 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007421 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007422 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007423 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007424 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007425}
7426EXPORT_SYMBOL_GPL(devlink_port_unregister);
7427
7428static void __devlink_port_type_set(struct devlink_port *devlink_port,
7429 enum devlink_port_type type,
7430 void *type_dev)
7431{
Jiri Pirko2b239e72019-03-24 11:14:36 +01007432 if (WARN_ON(!devlink_port->registered))
7433 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02007434 devlink_port_type_warn_cancel(devlink_port);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007435 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007436 devlink_port->type = type;
7437 devlink_port->type_dev = type_dev;
Ido Schimmel0f420b62019-08-17 16:28:17 +03007438 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007439 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7440}
7441
7442/**
7443 * devlink_port_type_eth_set - Set port type to Ethernet
7444 *
7445 * @devlink_port: devlink port
7446 * @netdev: related netdevice
7447 */
7448void devlink_port_type_eth_set(struct devlink_port *devlink_port,
7449 struct net_device *netdev)
7450{
Jiri Pirko119c0b52019-04-03 14:24:27 +02007451 const struct net_device_ops *ops = netdev->netdev_ops;
7452
Jiri Pirko746364f2019-03-28 13:56:46 +01007453 /* If driver registers devlink port, it should set devlink port
7454 * attributes accordingly so the compat functions are called
7455 * and the original ops are not used.
7456 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02007457 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01007458 /* Some drivers use the same set of ndos for netdevs
7459 * that have devlink_port registered and also for
7460 * those who don't. Make sure that ndo_get_phys_port_name
7461 * returns -EOPNOTSUPP here in case it is defined.
7462 * Warn if not.
7463 */
Jiri Pirko746364f2019-03-28 13:56:46 +01007464 char name[IFNAMSIZ];
7465 int err;
7466
7467 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
7468 WARN_ON(err != -EOPNOTSUPP);
7469 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02007470 if (ops->ndo_get_port_parent_id) {
7471 /* Some drivers use the same set of ndos for netdevs
7472 * that have devlink_port registered and also for
7473 * those who don't. Make sure that ndo_get_port_parent_id
7474 * returns -EOPNOTSUPP here in case it is defined.
7475 * Warn if not.
7476 */
7477 struct netdev_phys_item_id ppid;
7478 int err;
7479
7480 err = ops->ndo_get_port_parent_id(netdev, &ppid);
7481 WARN_ON(err != -EOPNOTSUPP);
7482 }
Jiri Pirko773b1f32019-03-24 11:14:30 +01007483 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007484}
7485EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
7486
7487/**
7488 * devlink_port_type_ib_set - Set port type to InfiniBand
7489 *
7490 * @devlink_port: devlink port
7491 * @ibdev: related IB device
7492 */
7493void devlink_port_type_ib_set(struct devlink_port *devlink_port,
7494 struct ib_device *ibdev)
7495{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007496 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007497}
7498EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
7499
7500/**
7501 * devlink_port_type_clear - Clear port type
7502 *
7503 * @devlink_port: devlink port
7504 */
7505void devlink_port_type_clear(struct devlink_port *devlink_port)
7506{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007507 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02007508 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007509}
7510EXPORT_SYMBOL_GPL(devlink_port_type_clear);
7511
Parav Pandit378ef012019-07-08 23:17:35 -05007512static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
7513 enum devlink_port_flavour flavour,
7514 const unsigned char *switch_id,
7515 unsigned char switch_id_len)
7516{
7517 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7518
7519 if (WARN_ON(devlink_port->registered))
7520 return -EEXIST;
7521 attrs->set = true;
7522 attrs->flavour = flavour;
7523 if (switch_id) {
7524 attrs->switch_port = true;
7525 if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
7526 switch_id_len = MAX_PHYS_ITEM_ID_LEN;
7527 memcpy(attrs->switch_id.id, switch_id, switch_id_len);
7528 attrs->switch_id.id_len = switch_id_len;
7529 } else {
7530 attrs->switch_port = false;
7531 }
7532 return 0;
7533}
7534
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007535/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007536 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007537 *
7538 * @devlink_port: devlink port
Jiri Pirko5ec13802018-05-18 09:29:01 +02007539 * @flavour: flavour of the port
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007540 * @port_number: number of the port that is facing user, for example
7541 * the front panel port number
7542 * @split: indicates if this is split port
7543 * @split_subport_number: if the port is split, this is the number
7544 * of subport.
Jiri Pirkobec52672019-04-03 14:24:16 +02007545 * @switch_id: if the port is part of switch, this is buffer with ID,
7546 * otwerwise this is NULL
7547 * @switch_id_len: length of the switch_id buffer
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007548 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007549void devlink_port_attrs_set(struct devlink_port *devlink_port,
Jiri Pirko5ec13802018-05-18 09:29:01 +02007550 enum devlink_port_flavour flavour,
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007551 u32 port_number, bool split,
Jiri Pirkobec52672019-04-03 14:24:16 +02007552 u32 split_subport_number,
7553 const unsigned char *switch_id,
7554 unsigned char switch_id_len)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007555{
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007556 struct devlink_port_attrs *attrs = &devlink_port->attrs;
Parav Pandit378ef012019-07-08 23:17:35 -05007557 int ret;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007558
Parav Pandit378ef012019-07-08 23:17:35 -05007559 ret = __devlink_port_attrs_set(devlink_port, flavour,
7560 switch_id, switch_id_len);
7561 if (ret)
Jiri Pirko45b86112019-03-24 11:14:33 +01007562 return;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007563 attrs->split = split;
Parav Pandit378ef012019-07-08 23:17:35 -05007564 attrs->phys.port_number = port_number;
7565 attrs->phys.split_subport_number = split_subport_number;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007566}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007567EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007568
Parav Pandit98fd2d62019-07-08 23:17:37 -05007569/**
7570 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
7571 *
7572 * @devlink_port: devlink port
7573 * @pf: associated PF for the devlink port instance
7574 * @switch_id: if the port is part of switch, this is buffer with ID,
7575 * otherwise this is NULL
7576 * @switch_id_len: length of the switch_id buffer
7577 */
7578void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port,
7579 const unsigned char *switch_id,
7580 unsigned char switch_id_len, u16 pf)
7581{
7582 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7583 int ret;
7584
7585 ret = __devlink_port_attrs_set(devlink_port,
7586 DEVLINK_PORT_FLAVOUR_PCI_PF,
7587 switch_id, switch_id_len);
7588 if (ret)
7589 return;
7590
7591 attrs->pci_pf.pf = pf;
7592}
7593EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
7594
Parav Pandite41b6bf2019-07-08 23:17:38 -05007595/**
7596 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
7597 *
7598 * @devlink_port: devlink port
7599 * @pf: associated PF for the devlink port instance
7600 * @vf: associated VF of a PF for the devlink port instance
7601 * @switch_id: if the port is part of switch, this is buffer with ID,
7602 * otherwise this is NULL
7603 * @switch_id_len: length of the switch_id buffer
7604 */
7605void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
7606 const unsigned char *switch_id,
7607 unsigned char switch_id_len,
7608 u16 pf, u16 vf)
7609{
7610 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7611 int ret;
7612
7613 ret = __devlink_port_attrs_set(devlink_port,
7614 DEVLINK_PORT_FLAVOUR_PCI_VF,
7615 switch_id, switch_id_len);
7616 if (ret)
7617 return;
7618 attrs->pci_vf.pf = pf;
7619 attrs->pci_vf.vf = vf;
7620}
7621EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
7622
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007623static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
7624 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02007625{
7626 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7627 int n = 0;
7628
7629 if (!attrs->set)
7630 return -EOPNOTSUPP;
7631
7632 switch (attrs->flavour) {
7633 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
Parav Panditacf1ee42020-03-03 08:12:42 -06007634 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Jiri Pirko08474c12018-05-18 09:29:02 +02007635 if (!attrs->split)
Parav Pandit378ef012019-07-08 23:17:35 -05007636 n = snprintf(name, len, "p%u", attrs->phys.port_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007637 else
Parav Pandit378ef012019-07-08 23:17:35 -05007638 n = snprintf(name, len, "p%us%u",
7639 attrs->phys.port_number,
7640 attrs->phys.split_subport_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007641 break;
7642 case DEVLINK_PORT_FLAVOUR_CPU:
7643 case DEVLINK_PORT_FLAVOUR_DSA:
7644 /* As CPU and DSA ports do not have a netdevice associated
7645 * case should not ever happen.
7646 */
7647 WARN_ON(1);
7648 return -EINVAL;
Parav Pandit98fd2d62019-07-08 23:17:37 -05007649 case DEVLINK_PORT_FLAVOUR_PCI_PF:
7650 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
7651 break;
Parav Pandite41b6bf2019-07-08 23:17:38 -05007652 case DEVLINK_PORT_FLAVOUR_PCI_VF:
7653 n = snprintf(name, len, "pf%uvf%u",
7654 attrs->pci_vf.pf, attrs->pci_vf.vf);
7655 break;
Jiri Pirko08474c12018-05-18 09:29:02 +02007656 }
7657
7658 if (n >= len)
7659 return -EINVAL;
7660
7661 return 0;
7662}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007663
Jiri Pirkobf797472016-04-14 18:19:13 +02007664int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
7665 u32 size, u16 ingress_pools_count,
7666 u16 egress_pools_count, u16 ingress_tc_count,
7667 u16 egress_tc_count)
7668{
7669 struct devlink_sb *devlink_sb;
7670 int err = 0;
7671
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007672 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007673 if (devlink_sb_index_exists(devlink, sb_index)) {
7674 err = -EEXIST;
7675 goto unlock;
7676 }
7677
7678 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
7679 if (!devlink_sb) {
7680 err = -ENOMEM;
7681 goto unlock;
7682 }
7683 devlink_sb->index = sb_index;
7684 devlink_sb->size = size;
7685 devlink_sb->ingress_pools_count = ingress_pools_count;
7686 devlink_sb->egress_pools_count = egress_pools_count;
7687 devlink_sb->ingress_tc_count = ingress_tc_count;
7688 devlink_sb->egress_tc_count = egress_tc_count;
7689 list_add_tail(&devlink_sb->list, &devlink->sb_list);
7690unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007691 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007692 return err;
7693}
7694EXPORT_SYMBOL_GPL(devlink_sb_register);
7695
7696void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
7697{
7698 struct devlink_sb *devlink_sb;
7699
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007700 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007701 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
7702 WARN_ON(!devlink_sb);
7703 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007704 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007705 kfree(devlink_sb);
7706}
7707EXPORT_SYMBOL_GPL(devlink_sb_unregister);
7708
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007709/**
7710 * devlink_dpipe_headers_register - register dpipe headers
7711 *
7712 * @devlink: devlink
7713 * @dpipe_headers: dpipe header array
7714 *
7715 * Register the headers supported by hardware.
7716 */
7717int devlink_dpipe_headers_register(struct devlink *devlink,
7718 struct devlink_dpipe_headers *dpipe_headers)
7719{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007720 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007721 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007722 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007723 return 0;
7724}
7725EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
7726
7727/**
7728 * devlink_dpipe_headers_unregister - unregister dpipe headers
7729 *
7730 * @devlink: devlink
7731 *
7732 * Unregister the headers supported by hardware.
7733 */
7734void devlink_dpipe_headers_unregister(struct devlink *devlink)
7735{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007736 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007737 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007738 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007739}
7740EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
7741
7742/**
7743 * devlink_dpipe_table_counter_enabled - check if counter allocation
7744 * required
7745 * @devlink: devlink
7746 * @table_name: tables name
7747 *
7748 * Used by driver to check if counter allocation is required.
7749 * After counter allocation is turned on the table entries
7750 * are updated to include counter statistics.
7751 *
7752 * After that point on the driver must respect the counter
7753 * state so that each entry added to the table is added
7754 * with a counter.
7755 */
7756bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
7757 const char *table_name)
7758{
7759 struct devlink_dpipe_table *table;
7760 bool enabled;
7761
7762 rcu_read_lock();
7763 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307764 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007765 enabled = false;
7766 if (table)
7767 enabled = table->counters_enabled;
7768 rcu_read_unlock();
7769 return enabled;
7770}
7771EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
7772
7773/**
7774 * devlink_dpipe_table_register - register dpipe table
7775 *
7776 * @devlink: devlink
7777 * @table_name: table name
7778 * @table_ops: table ops
7779 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007780 * @counter_control_extern: external control for counters
7781 */
7782int devlink_dpipe_table_register(struct devlink *devlink,
7783 const char *table_name,
7784 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02007785 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007786{
7787 struct devlink_dpipe_table *table;
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307788 int err = 0;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007789
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02007790 if (WARN_ON(!table_ops->size_get))
7791 return -EINVAL;
7792
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307793 mutex_lock(&devlink->lock);
7794
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307795 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
7796 devlink)) {
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307797 err = -EEXIST;
7798 goto unlock;
7799 }
7800
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007801 table = kzalloc(sizeof(*table), GFP_KERNEL);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307802 if (!table) {
7803 err = -ENOMEM;
7804 goto unlock;
7805 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007806
7807 table->name = table_name;
7808 table->table_ops = table_ops;
7809 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007810 table->counter_control_extern = counter_control_extern;
7811
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007812 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307813unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007814 mutex_unlock(&devlink->lock);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307815 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007816}
7817EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
7818
7819/**
7820 * devlink_dpipe_table_unregister - unregister dpipe table
7821 *
7822 * @devlink: devlink
7823 * @table_name: table name
7824 */
7825void devlink_dpipe_table_unregister(struct devlink *devlink,
7826 const char *table_name)
7827{
7828 struct devlink_dpipe_table *table;
7829
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007830 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007831 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307832 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007833 if (!table)
7834 goto unlock;
7835 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007836 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007837 kfree_rcu(table, rcu);
7838 return;
7839unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007840 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007841}
7842EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
7843
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007844/**
7845 * devlink_resource_register - devlink resource register
7846 *
7847 * @devlink: devlink
7848 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007849 * @resource_size: resource's size
7850 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007851 * @parent_resource_id: resource's parent id
7852 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007853 */
7854int devlink_resource_register(struct devlink *devlink,
7855 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007856 u64 resource_size,
7857 u64 resource_id,
7858 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02007859 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007860{
7861 struct devlink_resource *resource;
7862 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07007863 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007864 int err = 0;
7865
David Ahern14530742018-03-20 19:31:14 -07007866 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
7867
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007868 mutex_lock(&devlink->lock);
7869 resource = devlink_resource_find(devlink, NULL, resource_id);
7870 if (resource) {
7871 err = -EINVAL;
7872 goto out;
7873 }
7874
7875 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
7876 if (!resource) {
7877 err = -ENOMEM;
7878 goto out;
7879 }
7880
7881 if (top_hierarchy) {
7882 resource_list = &devlink->resource_list;
7883 } else {
7884 struct devlink_resource *parent_resource;
7885
7886 parent_resource = devlink_resource_find(devlink, NULL,
7887 parent_resource_id);
7888 if (parent_resource) {
7889 resource_list = &parent_resource->resource_list;
7890 resource->parent = parent_resource;
7891 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00007892 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007893 err = -EINVAL;
7894 goto out;
7895 }
7896 }
7897
7898 resource->name = resource_name;
7899 resource->size = resource_size;
7900 resource->size_new = resource_size;
7901 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007902 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01007903 memcpy(&resource->size_params, size_params,
7904 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007905 INIT_LIST_HEAD(&resource->resource_list);
7906 list_add_tail(&resource->list, resource_list);
7907out:
7908 mutex_unlock(&devlink->lock);
7909 return err;
7910}
7911EXPORT_SYMBOL_GPL(devlink_resource_register);
7912
7913/**
7914 * devlink_resources_unregister - free all resources
7915 *
7916 * @devlink: devlink
7917 * @resource: resource
7918 */
7919void devlink_resources_unregister(struct devlink *devlink,
7920 struct devlink_resource *resource)
7921{
7922 struct devlink_resource *tmp, *child_resource;
7923 struct list_head *resource_list;
7924
7925 if (resource)
7926 resource_list = &resource->resource_list;
7927 else
7928 resource_list = &devlink->resource_list;
7929
7930 if (!resource)
7931 mutex_lock(&devlink->lock);
7932
7933 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
7934 devlink_resources_unregister(devlink, child_resource);
7935 list_del(&child_resource->list);
7936 kfree(child_resource);
7937 }
7938
7939 if (!resource)
7940 mutex_unlock(&devlink->lock);
7941}
7942EXPORT_SYMBOL_GPL(devlink_resources_unregister);
7943
7944/**
7945 * devlink_resource_size_get - get and update size
7946 *
7947 * @devlink: devlink
7948 * @resource_id: the requested resource id
7949 * @p_resource_size: ptr to update
7950 */
7951int devlink_resource_size_get(struct devlink *devlink,
7952 u64 resource_id,
7953 u64 *p_resource_size)
7954{
7955 struct devlink_resource *resource;
7956 int err = 0;
7957
7958 mutex_lock(&devlink->lock);
7959 resource = devlink_resource_find(devlink, NULL, resource_id);
7960 if (!resource) {
7961 err = -EINVAL;
7962 goto out;
7963 }
7964 *p_resource_size = resource->size_new;
7965 resource->size = resource->size_new;
7966out:
7967 mutex_unlock(&devlink->lock);
7968 return err;
7969}
7970EXPORT_SYMBOL_GPL(devlink_resource_size_get);
7971
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01007972/**
7973 * devlink_dpipe_table_resource_set - set the resource id
7974 *
7975 * @devlink: devlink
7976 * @table_name: table name
7977 * @resource_id: resource id
7978 * @resource_units: number of resource's units consumed per table's entry
7979 */
7980int devlink_dpipe_table_resource_set(struct devlink *devlink,
7981 const char *table_name, u64 resource_id,
7982 u64 resource_units)
7983{
7984 struct devlink_dpipe_table *table;
7985 int err = 0;
7986
7987 mutex_lock(&devlink->lock);
7988 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307989 table_name, devlink);
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01007990 if (!table) {
7991 err = -EINVAL;
7992 goto out;
7993 }
7994 table->resource_id = resource_id;
7995 table->resource_units = resource_units;
7996 table->resource_valid = true;
7997out:
7998 mutex_unlock(&devlink->lock);
7999 return err;
8000}
8001EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
8002
Jiri Pirkofc56be42018-04-05 22:13:21 +02008003/**
8004 * devlink_resource_occ_get_register - register occupancy getter
8005 *
8006 * @devlink: devlink
8007 * @resource_id: resource id
8008 * @occ_get: occupancy getter callback
8009 * @occ_get_priv: occupancy getter callback priv
8010 */
8011void devlink_resource_occ_get_register(struct devlink *devlink,
8012 u64 resource_id,
8013 devlink_resource_occ_get_t *occ_get,
8014 void *occ_get_priv)
8015{
8016 struct devlink_resource *resource;
8017
8018 mutex_lock(&devlink->lock);
8019 resource = devlink_resource_find(devlink, NULL, resource_id);
8020 if (WARN_ON(!resource))
8021 goto out;
8022 WARN_ON(resource->occ_get);
8023
8024 resource->occ_get = occ_get;
8025 resource->occ_get_priv = occ_get_priv;
8026out:
8027 mutex_unlock(&devlink->lock);
8028}
8029EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
8030
8031/**
8032 * devlink_resource_occ_get_unregister - unregister occupancy getter
8033 *
8034 * @devlink: devlink
8035 * @resource_id: resource id
8036 */
8037void devlink_resource_occ_get_unregister(struct devlink *devlink,
8038 u64 resource_id)
8039{
8040 struct devlink_resource *resource;
8041
8042 mutex_lock(&devlink->lock);
8043 resource = devlink_resource_find(devlink, NULL, resource_id);
8044 if (WARN_ON(!resource))
8045 goto out;
8046 WARN_ON(!resource->occ_get);
8047
8048 resource->occ_get = NULL;
8049 resource->occ_get_priv = NULL;
8050out:
8051 mutex_unlock(&devlink->lock);
8052}
8053EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
8054
Vasundhara Volam39e61602019-01-28 18:00:20 +05308055static int devlink_param_verify(const struct devlink_param *param)
8056{
8057 if (!param || !param->name || !param->supported_cmodes)
8058 return -EINVAL;
8059 if (param->generic)
8060 return devlink_param_generic_verify(param);
8061 else
8062 return devlink_param_driver_verify(param);
8063}
8064
8065static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308066 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308067 struct list_head *param_list,
8068 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308069 size_t params_count,
8070 enum devlink_command reg_cmd,
8071 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308072{
8073 const struct devlink_param *param = params;
8074 int i;
8075 int err;
8076
8077 mutex_lock(&devlink->lock);
8078 for (i = 0; i < params_count; i++, param++) {
8079 err = devlink_param_verify(param);
8080 if (err)
8081 goto rollback;
8082
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308083 err = devlink_param_register_one(devlink, port_index,
8084 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308085 if (err)
8086 goto rollback;
8087 }
8088
8089 mutex_unlock(&devlink->lock);
8090 return 0;
8091
8092rollback:
8093 if (!i)
8094 goto unlock;
8095 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308096 devlink_param_unregister_one(devlink, port_index, param_list,
8097 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308098unlock:
8099 mutex_unlock(&devlink->lock);
8100 return err;
8101}
8102
8103static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308104 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308105 struct list_head *param_list,
8106 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308107 size_t params_count,
8108 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308109{
8110 const struct devlink_param *param = params;
8111 int i;
8112
8113 mutex_lock(&devlink->lock);
8114 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308115 devlink_param_unregister_one(devlink, 0, param_list, param,
8116 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308117 mutex_unlock(&devlink->lock);
8118}
8119
Moshe Shemesheabaef12018-07-04 14:30:28 +03008120/**
8121 * devlink_params_register - register configuration parameters
8122 *
8123 * @devlink: devlink
8124 * @params: configuration parameters array
8125 * @params_count: number of parameters provided
8126 *
8127 * Register the configuration parameters supported by the driver.
8128 */
8129int devlink_params_register(struct devlink *devlink,
8130 const struct devlink_param *params,
8131 size_t params_count)
8132{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308133 return __devlink_params_register(devlink, 0, &devlink->param_list,
8134 params, params_count,
8135 DEVLINK_CMD_PARAM_NEW,
8136 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008137}
8138EXPORT_SYMBOL_GPL(devlink_params_register);
8139
8140/**
8141 * devlink_params_unregister - unregister configuration parameters
8142 * @devlink: devlink
8143 * @params: configuration parameters to unregister
8144 * @params_count: number of parameters provided
8145 */
8146void devlink_params_unregister(struct devlink *devlink,
8147 const struct devlink_param *params,
8148 size_t params_count)
8149{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308150 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
8151 params, params_count,
8152 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008153}
8154EXPORT_SYMBOL_GPL(devlink_params_unregister);
8155
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008156/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00008157 * devlink_params_publish - publish configuration parameters
8158 *
8159 * @devlink: devlink
8160 *
8161 * Publish previously registered configuration parameters.
8162 */
8163void devlink_params_publish(struct devlink *devlink)
8164{
8165 struct devlink_param_item *param_item;
8166
8167 list_for_each_entry(param_item, &devlink->param_list, list) {
8168 if (param_item->published)
8169 continue;
8170 param_item->published = true;
8171 devlink_param_notify(devlink, 0, param_item,
8172 DEVLINK_CMD_PARAM_NEW);
8173 }
8174}
8175EXPORT_SYMBOL_GPL(devlink_params_publish);
8176
8177/**
8178 * devlink_params_unpublish - unpublish configuration parameters
8179 *
8180 * @devlink: devlink
8181 *
8182 * Unpublish previously registered configuration parameters.
8183 */
8184void devlink_params_unpublish(struct devlink *devlink)
8185{
8186 struct devlink_param_item *param_item;
8187
8188 list_for_each_entry(param_item, &devlink->param_list, list) {
8189 if (!param_item->published)
8190 continue;
8191 param_item->published = false;
8192 devlink_param_notify(devlink, 0, param_item,
8193 DEVLINK_CMD_PARAM_DEL);
8194 }
8195}
8196EXPORT_SYMBOL_GPL(devlink_params_unpublish);
8197
8198/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05308199 * devlink_port_params_register - register port configuration parameters
8200 *
8201 * @devlink_port: devlink port
8202 * @params: configuration parameters array
8203 * @params_count: number of parameters provided
8204 *
8205 * Register the configuration parameters supported by the port.
8206 */
8207int devlink_port_params_register(struct devlink_port *devlink_port,
8208 const struct devlink_param *params,
8209 size_t params_count)
8210{
8211 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308212 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308213 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308214 params_count,
8215 DEVLINK_CMD_PORT_PARAM_NEW,
8216 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308217}
8218EXPORT_SYMBOL_GPL(devlink_port_params_register);
8219
8220/**
8221 * devlink_port_params_unregister - unregister port configuration
8222 * parameters
8223 *
8224 * @devlink_port: devlink port
8225 * @params: configuration parameters array
8226 * @params_count: number of parameters provided
8227 */
8228void devlink_port_params_unregister(struct devlink_port *devlink_port,
8229 const struct devlink_param *params,
8230 size_t params_count)
8231{
8232 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308233 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308234 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308235 params, params_count,
8236 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308237}
8238EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
8239
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308240static int
8241__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
8242 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008243{
8244 struct devlink_param_item *param_item;
8245
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308246 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008247 if (!param_item)
8248 return -EINVAL;
8249
8250 if (!param_item->driverinit_value_valid ||
8251 !devlink_param_cmode_is_supported(param_item->param,
8252 DEVLINK_PARAM_CMODE_DRIVERINIT))
8253 return -EOPNOTSUPP;
8254
Moshe Shemesh12765342018-10-10 16:09:26 +03008255 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8256 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
8257 else
8258 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008259
8260 return 0;
8261}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308262
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308263static int
8264__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308265 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308266 struct list_head *param_list, u32 param_id,
8267 union devlink_param_value init_val,
8268 enum devlink_command cmd)
8269{
8270 struct devlink_param_item *param_item;
8271
8272 param_item = devlink_param_find_by_id(param_list, param_id);
8273 if (!param_item)
8274 return -EINVAL;
8275
8276 if (!devlink_param_cmode_is_supported(param_item->param,
8277 DEVLINK_PARAM_CMODE_DRIVERINIT))
8278 return -EOPNOTSUPP;
8279
8280 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8281 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
8282 else
8283 param_item->driverinit_value = init_val;
8284 param_item->driverinit_value_valid = true;
8285
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308286 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308287 return 0;
8288}
8289
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308290/**
8291 * devlink_param_driverinit_value_get - get configuration parameter
8292 * value for driver initializing
8293 *
8294 * @devlink: devlink
8295 * @param_id: parameter ID
8296 * @init_val: value of parameter in driverinit configuration mode
8297 *
8298 * This function should be used by the driver to get driverinit
8299 * configuration for initialization after reload command.
8300 */
8301int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
8302 union devlink_param_value *init_val)
8303{
Jiri Pirko97691062019-09-12 10:49:45 +02008304 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308305 return -EOPNOTSUPP;
8306
8307 return __devlink_param_driverinit_value_get(&devlink->param_list,
8308 param_id, init_val);
8309}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008310EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
8311
8312/**
8313 * devlink_param_driverinit_value_set - set value of configuration
8314 * parameter for driverinit
8315 * configuration mode
8316 *
8317 * @devlink: devlink
8318 * @param_id: parameter ID
8319 * @init_val: value of parameter to set for driverinit configuration mode
8320 *
8321 * This function should be used by the driver to set driverinit
8322 * configuration mode default value.
8323 */
8324int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
8325 union devlink_param_value init_val)
8326{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308327 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308328 &devlink->param_list,
8329 param_id, init_val,
8330 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008331}
8332EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
8333
Moshe Shemeshea601e12018-07-04 14:30:32 +03008334/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308335 * devlink_port_param_driverinit_value_get - get configuration parameter
8336 * value for driver initializing
8337 *
8338 * @devlink_port: devlink_port
8339 * @param_id: parameter ID
8340 * @init_val: value of parameter in driverinit configuration mode
8341 *
8342 * This function should be used by the driver to get driverinit
8343 * configuration for initialization after reload command.
8344 */
8345int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
8346 u32 param_id,
8347 union devlink_param_value *init_val)
8348{
8349 struct devlink *devlink = devlink_port->devlink;
8350
Jiri Pirko97691062019-09-12 10:49:45 +02008351 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308352 return -EOPNOTSUPP;
8353
8354 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
8355 param_id, init_val);
8356}
8357EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
8358
8359/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308360 * devlink_port_param_driverinit_value_set - set value of configuration
8361 * parameter for driverinit
8362 * configuration mode
8363 *
8364 * @devlink_port: devlink_port
8365 * @param_id: parameter ID
8366 * @init_val: value of parameter to set for driverinit configuration mode
8367 *
8368 * This function should be used by the driver to set driverinit
8369 * configuration mode default value.
8370 */
8371int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
8372 u32 param_id,
8373 union devlink_param_value init_val)
8374{
8375 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308376 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308377 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308378 param_id, init_val,
8379 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308380}
8381EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
8382
8383/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03008384 * devlink_param_value_changed - notify devlink on a parameter's value
8385 * change. Should be called by the driver
8386 * right after the change.
8387 *
8388 * @devlink: devlink
8389 * @param_id: parameter ID
8390 *
8391 * This function should be used by the driver to notify devlink on value
8392 * change, excluding driverinit configuration mode.
8393 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03008394 */
8395void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
8396{
8397 struct devlink_param_item *param_item;
8398
8399 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
8400 WARN_ON(!param_item);
8401
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308402 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03008403}
8404EXPORT_SYMBOL_GPL(devlink_param_value_changed);
8405
Alex Veskerb16ebe92018-07-12 15:13:08 +03008406/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308407 * devlink_port_param_value_changed - notify devlink on a parameter's value
8408 * change. Should be called by the driver
8409 * right after the change.
8410 *
8411 * @devlink_port: devlink_port
8412 * @param_id: parameter ID
8413 *
8414 * This function should be used by the driver to notify devlink on value
8415 * change, excluding driverinit configuration mode.
8416 * For driverinit configuration mode driver should use the function
8417 * devlink_port_param_driverinit_value_set() instead.
8418 */
8419void devlink_port_param_value_changed(struct devlink_port *devlink_port,
8420 u32 param_id)
8421{
8422 struct devlink_param_item *param_item;
8423
8424 param_item = devlink_param_find_by_id(&devlink_port->param_list,
8425 param_id);
8426 WARN_ON(!param_item);
8427
8428 devlink_param_notify(devlink_port->devlink, devlink_port->index,
8429 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
8430}
8431EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
8432
8433/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03008434 * devlink_param_value_str_fill - Safely fill-up the string preventing
8435 * from overflow of the preallocated buffer
8436 *
8437 * @dst_val: destination devlink_param_value
8438 * @src: source buffer
8439 */
8440void devlink_param_value_str_fill(union devlink_param_value *dst_val,
8441 const char *src)
8442{
8443 size_t len;
8444
8445 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
8446 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
8447}
8448EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
8449
8450/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03008451 * devlink_region_create - create a new address region
8452 *
8453 * @devlink: devlink
Jacob Kellere8937682020-03-26 11:37:08 -07008454 * @ops: region operations and name
Alex Veskerb16ebe92018-07-12 15:13:08 +03008455 * @region_max_snapshots: Maximum supported number of snapshots for region
8456 * @region_size: size of region
8457 */
Jacob Kellere8937682020-03-26 11:37:08 -07008458struct devlink_region *
8459devlink_region_create(struct devlink *devlink,
8460 const struct devlink_region_ops *ops,
8461 u32 region_max_snapshots, u64 region_size)
Alex Veskerb16ebe92018-07-12 15:13:08 +03008462{
8463 struct devlink_region *region;
8464 int err = 0;
8465
Jacob Kellera0a09f62020-03-26 11:37:09 -07008466 if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
8467 return ERR_PTR(-EINVAL);
8468
Alex Veskerb16ebe92018-07-12 15:13:08 +03008469 mutex_lock(&devlink->lock);
8470
Jacob Kellere8937682020-03-26 11:37:08 -07008471 if (devlink_region_get_by_name(devlink, ops->name)) {
Alex Veskerb16ebe92018-07-12 15:13:08 +03008472 err = -EEXIST;
8473 goto unlock;
8474 }
8475
8476 region = kzalloc(sizeof(*region), GFP_KERNEL);
8477 if (!region) {
8478 err = -ENOMEM;
8479 goto unlock;
8480 }
8481
8482 region->devlink = devlink;
8483 region->max_snapshots = region_max_snapshots;
Jacob Kellere8937682020-03-26 11:37:08 -07008484 region->ops = ops;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008485 region->size = region_size;
8486 INIT_LIST_HEAD(&region->snapshot_list);
8487 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03008488 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008489
8490 mutex_unlock(&devlink->lock);
8491 return region;
8492
8493unlock:
8494 mutex_unlock(&devlink->lock);
8495 return ERR_PTR(err);
8496}
8497EXPORT_SYMBOL_GPL(devlink_region_create);
8498
8499/**
8500 * devlink_region_destroy - destroy address region
8501 *
8502 * @region: devlink region to destroy
8503 */
8504void devlink_region_destroy(struct devlink_region *region)
8505{
8506 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008507 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008508
8509 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008510
8511 /* Free all snapshots of region */
8512 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
Jiri Pirko92b49822019-08-12 14:28:31 +02008513 devlink_region_snapshot_del(region, snapshot);
Alex Veskerd7e52722018-07-12 15:13:10 +03008514
Alex Veskerb16ebe92018-07-12 15:13:08 +03008515 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03008516
8517 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008518 mutex_unlock(&devlink->lock);
8519 kfree(region);
8520}
8521EXPORT_SYMBOL_GPL(devlink_region_destroy);
8522
Alex Veskerccadfa42018-07-12 15:13:09 +03008523/**
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008524 * devlink_region_snapshot_id_get - get snapshot ID
Alex Veskerccadfa42018-07-12 15:13:09 +03008525 *
8526 * This callback should be called when adding a new snapshot,
8527 * Driver should use the same id for multiple snapshots taken
8528 * on multiple regions at the same time/by the same trigger.
8529 *
Jacob Keller12102432020-03-26 11:37:15 -07008530 * The caller of this function must use devlink_region_snapshot_id_put
8531 * when finished creating regions using this id.
8532 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07008533 * Returns zero on success, or a negative error code on failure.
8534 *
Alex Veskerccadfa42018-07-12 15:13:09 +03008535 * @devlink: devlink
Jacob Keller7ef19d32020-03-26 11:37:14 -07008536 * @id: storage to return id
Alex Veskerccadfa42018-07-12 15:13:09 +03008537 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07008538int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Alex Veskerccadfa42018-07-12 15:13:09 +03008539{
Jacob Keller7ef19d32020-03-26 11:37:14 -07008540 int err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008541
8542 mutex_lock(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07008543 err = __devlink_region_snapshot_id_get(devlink, id);
Alex Veskerccadfa42018-07-12 15:13:09 +03008544 mutex_unlock(&devlink->lock);
8545
Jacob Keller7ef19d32020-03-26 11:37:14 -07008546 return err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008547}
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008548EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
Alex Veskerccadfa42018-07-12 15:13:09 +03008549
Alex Veskerd7e52722018-07-12 15:13:10 +03008550/**
Jacob Keller12102432020-03-26 11:37:15 -07008551 * devlink_region_snapshot_id_put - put snapshot ID reference
8552 *
8553 * This should be called by a driver after finishing creating snapshots
8554 * with an id. Doing so ensures that the ID can later be released in the
8555 * event that all snapshots using it have been destroyed.
8556 *
8557 * @devlink: devlink
8558 * @id: id to release reference on
8559 */
8560void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
8561{
8562 mutex_lock(&devlink->lock);
8563 __devlink_snapshot_id_decrement(devlink, id);
8564 mutex_unlock(&devlink->lock);
8565}
8566EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
8567
8568/**
Alex Veskerd7e52722018-07-12 15:13:10 +03008569 * devlink_region_snapshot_create - create a new snapshot
8570 * This will add a new snapshot of a region. The snapshot
8571 * will be stored on the region struct and can be accessed
Jacob Keller6d82f672020-03-26 11:37:10 -07008572 * from devlink. This is useful for future analyses of snapshots.
Alex Veskerd7e52722018-07-12 15:13:10 +03008573 * Multiple snapshots can be created on a region.
8574 * The @snapshot_id should be obtained using the getter function.
8575 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008576 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03008577 * @data: snapshot data
8578 * @snapshot_id: snapshot id to be created
Alex Veskerd7e52722018-07-12 15:13:10 +03008579 */
Jiri Pirko3a5e5232019-08-09 15:27:15 +02008580int devlink_region_snapshot_create(struct devlink_region *region,
Jacob Kellera0a09f62020-03-26 11:37:09 -07008581 u8 *data, u32 snapshot_id)
Alex Veskerd7e52722018-07-12 15:13:10 +03008582{
8583 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008584 int err;
8585
8586 mutex_lock(&devlink->lock);
Jacob Kellercf80fae2020-03-26 11:37:11 -07008587 err = __devlink_region_snapshot_create(region, data, snapshot_id);
Alex Veskerd7e52722018-07-12 15:13:10 +03008588 mutex_unlock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008589
Alex Veskerd7e52722018-07-12 15:13:10 +03008590 return err;
8591}
8592EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
8593
Ido Schimmel0f420b62019-08-17 16:28:17 +03008594#define DEVLINK_TRAP(_id, _type) \
8595 { \
8596 .type = DEVLINK_TRAP_TYPE_##_type, \
8597 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
8598 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
8599 }
8600
8601static const struct devlink_trap devlink_trap_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008602 DEVLINK_TRAP(SMAC_MC, DROP),
8603 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
8604 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
8605 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
8606 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
8607 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
8608 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
8609 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
8610 DEVLINK_TRAP(TAIL_DROP, DROP),
Amit Cohen6896cc42019-11-07 18:42:09 +02008611 DEVLINK_TRAP(NON_IP_PACKET, DROP),
8612 DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
8613 DEVLINK_TRAP(DIP_LB, DROP),
8614 DEVLINK_TRAP(SIP_MC, DROP),
8615 DEVLINK_TRAP(SIP_LB, DROP),
8616 DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
8617 DEVLINK_TRAP(IPV4_SIP_BC, DROP),
8618 DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
8619 DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
Amit Cohen3b063ae2019-11-07 18:42:14 +02008620 DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
8621 DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
8622 DEVLINK_TRAP(RPF, EXCEPTION),
8623 DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
8624 DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
8625 DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
Amit Cohen95f0ead2020-01-19 15:00:48 +02008626 DEVLINK_TRAP(NON_ROUTABLE, DROP),
Amit Cohen13c056e2020-01-19 15:00:54 +02008627 DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
Amit Cohenc3cae492020-01-19 15:00:58 +02008628 DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008629 DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
8630 DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
Ido Schimmel515eac62020-05-29 21:36:41 +03008631 DEVLINK_TRAP(STP, CONTROL),
8632 DEVLINK_TRAP(LACP, CONTROL),
8633 DEVLINK_TRAP(LLDP, CONTROL),
8634 DEVLINK_TRAP(IGMP_QUERY, CONTROL),
8635 DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
8636 DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
8637 DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
8638 DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
8639 DEVLINK_TRAP(MLD_QUERY, CONTROL),
8640 DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
8641 DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
8642 DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008643 DEVLINK_TRAP(IPV4_DHCP, CONTROL),
8644 DEVLINK_TRAP(IPV6_DHCP, CONTROL),
8645 DEVLINK_TRAP(ARP_REQUEST, CONTROL),
8646 DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
8647 DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
8648 DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
8649 DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
8650 DEVLINK_TRAP(IPV4_BFD, CONTROL),
8651 DEVLINK_TRAP(IPV6_BFD, CONTROL),
8652 DEVLINK_TRAP(IPV4_OSPF, CONTROL),
8653 DEVLINK_TRAP(IPV6_OSPF, CONTROL),
8654 DEVLINK_TRAP(IPV4_BGP, CONTROL),
8655 DEVLINK_TRAP(IPV6_BGP, CONTROL),
8656 DEVLINK_TRAP(IPV4_VRRP, CONTROL),
8657 DEVLINK_TRAP(IPV6_VRRP, CONTROL),
8658 DEVLINK_TRAP(IPV4_PIM, CONTROL),
8659 DEVLINK_TRAP(IPV6_PIM, CONTROL),
8660 DEVLINK_TRAP(UC_LB, CONTROL),
8661 DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
8662 DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
8663 DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
8664 DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
8665 DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
8666 DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
8667 DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
8668 DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
8669 DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
8670 DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
8671 DEVLINK_TRAP(PTP_EVENT, CONTROL),
8672 DEVLINK_TRAP(PTP_GENERAL, CONTROL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008673 DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
8674 DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008675};
8676
8677#define DEVLINK_TRAP_GROUP(_id) \
8678 { \
8679 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
8680 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
8681 }
8682
8683static const struct devlink_trap_group devlink_trap_group_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008684 DEVLINK_TRAP_GROUP(L2_DROPS),
8685 DEVLINK_TRAP_GROUP(L3_DROPS),
Ido Schimmel678eb192020-05-29 21:36:36 +03008686 DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
Ido Schimmel391203a2019-08-17 16:28:18 +03008687 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
Amit Cohen13c056e2020-01-19 15:00:54 +02008688 DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008689 DEVLINK_TRAP_GROUP(ACL_DROPS),
Ido Schimmel515eac62020-05-29 21:36:41 +03008690 DEVLINK_TRAP_GROUP(STP),
8691 DEVLINK_TRAP_GROUP(LACP),
8692 DEVLINK_TRAP_GROUP(LLDP),
8693 DEVLINK_TRAP_GROUP(MC_SNOOPING),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008694 DEVLINK_TRAP_GROUP(DHCP),
8695 DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
8696 DEVLINK_TRAP_GROUP(BFD),
8697 DEVLINK_TRAP_GROUP(OSPF),
8698 DEVLINK_TRAP_GROUP(BGP),
8699 DEVLINK_TRAP_GROUP(VRRP),
8700 DEVLINK_TRAP_GROUP(PIM),
8701 DEVLINK_TRAP_GROUP(UC_LB),
8702 DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
8703 DEVLINK_TRAP_GROUP(IPV6),
8704 DEVLINK_TRAP_GROUP(PTP_EVENT),
8705 DEVLINK_TRAP_GROUP(PTP_GENERAL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008706 DEVLINK_TRAP_GROUP(ACL_SAMPLE),
8707 DEVLINK_TRAP_GROUP(ACL_TRAP),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008708};
8709
8710static int devlink_trap_generic_verify(const struct devlink_trap *trap)
8711{
8712 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
8713 return -EINVAL;
8714
8715 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
8716 return -EINVAL;
8717
8718 if (trap->type != devlink_trap_generic[trap->id].type)
8719 return -EINVAL;
8720
8721 return 0;
8722}
8723
8724static int devlink_trap_driver_verify(const struct devlink_trap *trap)
8725{
8726 int i;
8727
8728 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
8729 return -EINVAL;
8730
8731 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
8732 if (!strcmp(trap->name, devlink_trap_generic[i].name))
8733 return -EEXIST;
8734 }
8735
8736 return 0;
8737}
8738
8739static int devlink_trap_verify(const struct devlink_trap *trap)
8740{
Ido Schimmel107f1672020-03-22 20:48:30 +02008741 if (!trap || !trap->name)
Ido Schimmel0f420b62019-08-17 16:28:17 +03008742 return -EINVAL;
8743
8744 if (trap->generic)
8745 return devlink_trap_generic_verify(trap);
8746 else
8747 return devlink_trap_driver_verify(trap);
8748}
8749
8750static int
8751devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
8752{
8753 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
8754 return -EINVAL;
8755
8756 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
8757 return -EINVAL;
8758
8759 return 0;
8760}
8761
8762static int
8763devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
8764{
8765 int i;
8766
8767 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
8768 return -EINVAL;
8769
8770 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
8771 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
8772 return -EEXIST;
8773 }
8774
8775 return 0;
8776}
8777
8778static int devlink_trap_group_verify(const struct devlink_trap_group *group)
8779{
8780 if (group->generic)
8781 return devlink_trap_group_generic_verify(group);
8782 else
8783 return devlink_trap_group_driver_verify(group);
8784}
8785
8786static void
8787devlink_trap_group_notify(struct devlink *devlink,
8788 const struct devlink_trap_group_item *group_item,
8789 enum devlink_command cmd)
8790{
8791 struct sk_buff *msg;
8792 int err;
8793
8794 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
8795 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
8796
8797 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8798 if (!msg)
8799 return;
8800
8801 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
8802 0);
8803 if (err) {
8804 nlmsg_free(msg);
8805 return;
8806 }
8807
8808 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
8809 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
8810}
8811
Ido Schimmel0f420b62019-08-17 16:28:17 +03008812static int
8813devlink_trap_item_group_link(struct devlink *devlink,
8814 struct devlink_trap_item *trap_item)
8815{
Ido Schimmel107f1672020-03-22 20:48:30 +02008816 u16 group_id = trap_item->trap->init_group_id;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008817 struct devlink_trap_group_item *group_item;
8818
Ido Schimmel107f1672020-03-22 20:48:30 +02008819 group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
Ido Schimmela09b37f2020-03-22 20:48:29 +02008820 if (WARN_ON_ONCE(!group_item))
8821 return -EINVAL;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008822
8823 trap_item->group_item = group_item;
8824
8825 return 0;
8826}
8827
Ido Schimmel0f420b62019-08-17 16:28:17 +03008828static void devlink_trap_notify(struct devlink *devlink,
8829 const struct devlink_trap_item *trap_item,
8830 enum devlink_command cmd)
8831{
8832 struct sk_buff *msg;
8833 int err;
8834
8835 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
8836 cmd != DEVLINK_CMD_TRAP_DEL);
8837
8838 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8839 if (!msg)
8840 return;
8841
8842 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
8843 if (err) {
8844 nlmsg_free(msg);
8845 return;
8846 }
8847
8848 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
8849 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
8850}
8851
8852static int
8853devlink_trap_register(struct devlink *devlink,
8854 const struct devlink_trap *trap, void *priv)
8855{
8856 struct devlink_trap_item *trap_item;
8857 int err;
8858
8859 if (devlink_trap_item_lookup(devlink, trap->name))
8860 return -EEXIST;
8861
8862 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
8863 if (!trap_item)
8864 return -ENOMEM;
8865
8866 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
8867 if (!trap_item->stats) {
8868 err = -ENOMEM;
8869 goto err_stats_alloc;
8870 }
8871
8872 trap_item->trap = trap;
8873 trap_item->action = trap->init_action;
8874 trap_item->priv = priv;
8875
8876 err = devlink_trap_item_group_link(devlink, trap_item);
8877 if (err)
8878 goto err_group_link;
8879
8880 err = devlink->ops->trap_init(devlink, trap, trap_item);
8881 if (err)
8882 goto err_trap_init;
8883
8884 list_add_tail(&trap_item->list, &devlink->trap_list);
8885 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
8886
8887 return 0;
8888
8889err_trap_init:
Ido Schimmel0f420b62019-08-17 16:28:17 +03008890err_group_link:
8891 free_percpu(trap_item->stats);
8892err_stats_alloc:
8893 kfree(trap_item);
8894 return err;
8895}
8896
8897static void devlink_trap_unregister(struct devlink *devlink,
8898 const struct devlink_trap *trap)
8899{
8900 struct devlink_trap_item *trap_item;
8901
8902 trap_item = devlink_trap_item_lookup(devlink, trap->name);
8903 if (WARN_ON_ONCE(!trap_item))
8904 return;
8905
8906 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
8907 list_del(&trap_item->list);
8908 if (devlink->ops->trap_fini)
8909 devlink->ops->trap_fini(devlink, trap, trap_item);
Ido Schimmel0f420b62019-08-17 16:28:17 +03008910 free_percpu(trap_item->stats);
8911 kfree(trap_item);
8912}
8913
8914static void devlink_trap_disable(struct devlink *devlink,
8915 const struct devlink_trap *trap)
8916{
8917 struct devlink_trap_item *trap_item;
8918
8919 trap_item = devlink_trap_item_lookup(devlink, trap->name);
8920 if (WARN_ON_ONCE(!trap_item))
8921 return;
8922
8923 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP);
8924 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
8925}
8926
8927/**
8928 * devlink_traps_register - Register packet traps with devlink.
8929 * @devlink: devlink.
8930 * @traps: Packet traps.
8931 * @traps_count: Count of provided packet traps.
8932 * @priv: Driver private information.
8933 *
8934 * Return: Non-zero value on failure.
8935 */
8936int devlink_traps_register(struct devlink *devlink,
8937 const struct devlink_trap *traps,
8938 size_t traps_count, void *priv)
8939{
8940 int i, err;
8941
8942 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
8943 return -EINVAL;
8944
8945 mutex_lock(&devlink->lock);
8946 for (i = 0; i < traps_count; i++) {
8947 const struct devlink_trap *trap = &traps[i];
8948
8949 err = devlink_trap_verify(trap);
8950 if (err)
8951 goto err_trap_verify;
8952
8953 err = devlink_trap_register(devlink, trap, priv);
8954 if (err)
8955 goto err_trap_register;
8956 }
8957 mutex_unlock(&devlink->lock);
8958
8959 return 0;
8960
8961err_trap_register:
8962err_trap_verify:
8963 for (i--; i >= 0; i--)
8964 devlink_trap_unregister(devlink, &traps[i]);
8965 mutex_unlock(&devlink->lock);
8966 return err;
8967}
8968EXPORT_SYMBOL_GPL(devlink_traps_register);
8969
8970/**
8971 * devlink_traps_unregister - Unregister packet traps from devlink.
8972 * @devlink: devlink.
8973 * @traps: Packet traps.
8974 * @traps_count: Count of provided packet traps.
8975 */
8976void devlink_traps_unregister(struct devlink *devlink,
8977 const struct devlink_trap *traps,
8978 size_t traps_count)
8979{
8980 int i;
8981
8982 mutex_lock(&devlink->lock);
8983 /* Make sure we do not have any packets in-flight while unregistering
8984 * traps by disabling all of them and waiting for a grace period.
8985 */
8986 for (i = traps_count - 1; i >= 0; i--)
8987 devlink_trap_disable(devlink, &traps[i]);
8988 synchronize_rcu();
8989 for (i = traps_count - 1; i >= 0; i--)
8990 devlink_trap_unregister(devlink, &traps[i]);
8991 mutex_unlock(&devlink->lock);
8992}
8993EXPORT_SYMBOL_GPL(devlink_traps_unregister);
8994
8995static void
8996devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
8997 size_t skb_len)
8998{
8999 struct devlink_stats *stats;
9000
9001 stats = this_cpu_ptr(trap_stats);
9002 u64_stats_update_begin(&stats->syncp);
9003 stats->rx_bytes += skb_len;
9004 stats->rx_packets++;
9005 u64_stats_update_end(&stats->syncp);
9006}
9007
9008static void
9009devlink_trap_report_metadata_fill(struct net_dm_hw_metadata *hw_metadata,
9010 const struct devlink_trap_item *trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009011 struct devlink_port *in_devlink_port,
9012 const struct flow_action_cookie *fa_cookie)
Ido Schimmel0f420b62019-08-17 16:28:17 +03009013{
9014 struct devlink_trap_group_item *group_item = trap_item->group_item;
9015
9016 hw_metadata->trap_group_name = group_item->group->name;
9017 hw_metadata->trap_name = trap_item->trap->name;
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009018 hw_metadata->fa_cookie = fa_cookie;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009019
9020 spin_lock(&in_devlink_port->type_lock);
9021 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
9022 hw_metadata->input_dev = in_devlink_port->type_dev;
9023 spin_unlock(&in_devlink_port->type_lock);
9024}
9025
9026/**
9027 * devlink_trap_report - Report trapped packet to drop monitor.
9028 * @devlink: devlink.
9029 * @skb: Trapped packet.
9030 * @trap_ctx: Trap context.
9031 * @in_devlink_port: Input devlink port.
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009032 * @fa_cookie: Flow action cookie. Could be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03009033 */
9034void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009035 void *trap_ctx, struct devlink_port *in_devlink_port,
9036 const struct flow_action_cookie *fa_cookie)
9037
Ido Schimmel0f420b62019-08-17 16:28:17 +03009038{
9039 struct devlink_trap_item *trap_item = trap_ctx;
9040 struct net_dm_hw_metadata hw_metadata = {};
9041
9042 devlink_trap_stats_update(trap_item->stats, skb->len);
9043 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
9044
Ido Schimmel30a4e9a2020-05-29 21:36:40 +03009045 /* Control packets were not dropped by the device or encountered an
9046 * exception during forwarding and therefore should not be reported to
9047 * the kernel's drop monitor.
9048 */
9049 if (trap_item->trap->type == DEVLINK_TRAP_TYPE_CONTROL)
9050 return;
9051
Ido Schimmel0f420b62019-08-17 16:28:17 +03009052 devlink_trap_report_metadata_fill(&hw_metadata, trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009053 in_devlink_port, fa_cookie);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009054 net_dm_hw_report(skb, &hw_metadata);
9055}
9056EXPORT_SYMBOL_GPL(devlink_trap_report);
9057
9058/**
9059 * devlink_trap_ctx_priv - Trap context to driver private information.
9060 * @trap_ctx: Trap context.
9061 *
9062 * Return: Driver private information passed during registration.
9063 */
9064void *devlink_trap_ctx_priv(void *trap_ctx)
9065{
9066 struct devlink_trap_item *trap_item = trap_ctx;
9067
9068 return trap_item->priv;
9069}
9070EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
9071
Ido Schimmel95ad9552020-03-22 20:48:26 +02009072static int
Ido Schimmelf9f54392020-03-30 22:38:21 +03009073devlink_trap_group_item_policer_link(struct devlink *devlink,
9074 struct devlink_trap_group_item *group_item)
9075{
9076 u32 policer_id = group_item->group->init_policer_id;
9077 struct devlink_trap_policer_item *policer_item;
9078
9079 if (policer_id == 0)
9080 return 0;
9081
9082 policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
9083 if (WARN_ON_ONCE(!policer_item))
9084 return -EINVAL;
9085
9086 group_item->policer_item = policer_item;
9087
9088 return 0;
9089}
9090
9091static int
Ido Schimmel95ad9552020-03-22 20:48:26 +02009092devlink_trap_group_register(struct devlink *devlink,
9093 const struct devlink_trap_group *group)
9094{
9095 struct devlink_trap_group_item *group_item;
9096 int err;
9097
9098 if (devlink_trap_group_item_lookup(devlink, group->name))
9099 return -EEXIST;
9100
9101 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
9102 if (!group_item)
9103 return -ENOMEM;
9104
9105 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9106 if (!group_item->stats) {
9107 err = -ENOMEM;
9108 goto err_stats_alloc;
9109 }
9110
9111 group_item->group = group;
Ido Schimmel95ad9552020-03-22 20:48:26 +02009112
Ido Schimmelf9f54392020-03-30 22:38:21 +03009113 err = devlink_trap_group_item_policer_link(devlink, group_item);
9114 if (err)
9115 goto err_policer_link;
9116
Ido Schimmel95ad9552020-03-22 20:48:26 +02009117 if (devlink->ops->trap_group_init) {
9118 err = devlink->ops->trap_group_init(devlink, group);
9119 if (err)
9120 goto err_group_init;
9121 }
9122
9123 list_add_tail(&group_item->list, &devlink->trap_group_list);
9124 devlink_trap_group_notify(devlink, group_item,
9125 DEVLINK_CMD_TRAP_GROUP_NEW);
9126
9127 return 0;
9128
9129err_group_init:
Ido Schimmelf9f54392020-03-30 22:38:21 +03009130err_policer_link:
Ido Schimmel95ad9552020-03-22 20:48:26 +02009131 free_percpu(group_item->stats);
9132err_stats_alloc:
9133 kfree(group_item);
9134 return err;
9135}
9136
9137static void
9138devlink_trap_group_unregister(struct devlink *devlink,
9139 const struct devlink_trap_group *group)
9140{
9141 struct devlink_trap_group_item *group_item;
9142
9143 group_item = devlink_trap_group_item_lookup(devlink, group->name);
9144 if (WARN_ON_ONCE(!group_item))
9145 return;
9146
9147 devlink_trap_group_notify(devlink, group_item,
9148 DEVLINK_CMD_TRAP_GROUP_DEL);
9149 list_del(&group_item->list);
9150 free_percpu(group_item->stats);
9151 kfree(group_item);
9152}
9153
9154/**
9155 * devlink_trap_groups_register - Register packet trap groups with devlink.
9156 * @devlink: devlink.
9157 * @groups: Packet trap groups.
9158 * @groups_count: Count of provided packet trap groups.
9159 *
9160 * Return: Non-zero value on failure.
9161 */
9162int devlink_trap_groups_register(struct devlink *devlink,
9163 const struct devlink_trap_group *groups,
9164 size_t groups_count)
9165{
9166 int i, err;
9167
9168 mutex_lock(&devlink->lock);
9169 for (i = 0; i < groups_count; i++) {
9170 const struct devlink_trap_group *group = &groups[i];
9171
9172 err = devlink_trap_group_verify(group);
9173 if (err)
9174 goto err_trap_group_verify;
9175
9176 err = devlink_trap_group_register(devlink, group);
9177 if (err)
9178 goto err_trap_group_register;
9179 }
9180 mutex_unlock(&devlink->lock);
9181
9182 return 0;
9183
9184err_trap_group_register:
9185err_trap_group_verify:
9186 for (i--; i >= 0; i--)
9187 devlink_trap_group_unregister(devlink, &groups[i]);
9188 mutex_unlock(&devlink->lock);
9189 return err;
9190}
9191EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
9192
9193/**
9194 * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
9195 * @devlink: devlink.
9196 * @groups: Packet trap groups.
9197 * @groups_count: Count of provided packet trap groups.
9198 */
9199void devlink_trap_groups_unregister(struct devlink *devlink,
9200 const struct devlink_trap_group *groups,
9201 size_t groups_count)
9202{
9203 int i;
9204
9205 mutex_lock(&devlink->lock);
9206 for (i = groups_count - 1; i >= 0; i--)
9207 devlink_trap_group_unregister(devlink, &groups[i]);
9208 mutex_unlock(&devlink->lock);
9209}
9210EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
9211
Ido Schimmel1e8c6612020-03-30 22:38:18 +03009212static void
9213devlink_trap_policer_notify(struct devlink *devlink,
9214 const struct devlink_trap_policer_item *policer_item,
9215 enum devlink_command cmd)
9216{
9217 struct sk_buff *msg;
9218 int err;
9219
9220 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
9221 cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
9222
9223 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9224 if (!msg)
9225 return;
9226
9227 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
9228 0, 0);
9229 if (err) {
9230 nlmsg_free(msg);
9231 return;
9232 }
9233
9234 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9235 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9236}
9237
9238static int
9239devlink_trap_policer_register(struct devlink *devlink,
9240 const struct devlink_trap_policer *policer)
9241{
9242 struct devlink_trap_policer_item *policer_item;
9243 int err;
9244
9245 if (devlink_trap_policer_item_lookup(devlink, policer->id))
9246 return -EEXIST;
9247
9248 policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
9249 if (!policer_item)
9250 return -ENOMEM;
9251
9252 policer_item->policer = policer;
9253 policer_item->rate = policer->init_rate;
9254 policer_item->burst = policer->init_burst;
9255
9256 if (devlink->ops->trap_policer_init) {
9257 err = devlink->ops->trap_policer_init(devlink, policer);
9258 if (err)
9259 goto err_policer_init;
9260 }
9261
9262 list_add_tail(&policer_item->list, &devlink->trap_policer_list);
9263 devlink_trap_policer_notify(devlink, policer_item,
9264 DEVLINK_CMD_TRAP_POLICER_NEW);
9265
9266 return 0;
9267
9268err_policer_init:
9269 kfree(policer_item);
9270 return err;
9271}
9272
9273static void
9274devlink_trap_policer_unregister(struct devlink *devlink,
9275 const struct devlink_trap_policer *policer)
9276{
9277 struct devlink_trap_policer_item *policer_item;
9278
9279 policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
9280 if (WARN_ON_ONCE(!policer_item))
9281 return;
9282
9283 devlink_trap_policer_notify(devlink, policer_item,
9284 DEVLINK_CMD_TRAP_POLICER_DEL);
9285 list_del(&policer_item->list);
9286 if (devlink->ops->trap_policer_fini)
9287 devlink->ops->trap_policer_fini(devlink, policer);
9288 kfree(policer_item);
9289}
9290
9291/**
9292 * devlink_trap_policers_register - Register packet trap policers with devlink.
9293 * @devlink: devlink.
9294 * @policers: Packet trap policers.
9295 * @policers_count: Count of provided packet trap policers.
9296 *
9297 * Return: Non-zero value on failure.
9298 */
9299int
9300devlink_trap_policers_register(struct devlink *devlink,
9301 const struct devlink_trap_policer *policers,
9302 size_t policers_count)
9303{
9304 int i, err;
9305
9306 mutex_lock(&devlink->lock);
9307 for (i = 0; i < policers_count; i++) {
9308 const struct devlink_trap_policer *policer = &policers[i];
9309
9310 if (WARN_ON(policer->id == 0 ||
9311 policer->max_rate < policer->min_rate ||
9312 policer->max_burst < policer->min_burst)) {
9313 err = -EINVAL;
9314 goto err_trap_policer_verify;
9315 }
9316
9317 err = devlink_trap_policer_register(devlink, policer);
9318 if (err)
9319 goto err_trap_policer_register;
9320 }
9321 mutex_unlock(&devlink->lock);
9322
9323 return 0;
9324
9325err_trap_policer_register:
9326err_trap_policer_verify:
9327 for (i--; i >= 0; i--)
9328 devlink_trap_policer_unregister(devlink, &policers[i]);
9329 mutex_unlock(&devlink->lock);
9330 return err;
9331}
9332EXPORT_SYMBOL_GPL(devlink_trap_policers_register);
9333
9334/**
9335 * devlink_trap_policers_unregister - Unregister packet trap policers from devlink.
9336 * @devlink: devlink.
9337 * @policers: Packet trap policers.
9338 * @policers_count: Count of provided packet trap policers.
9339 */
9340void
9341devlink_trap_policers_unregister(struct devlink *devlink,
9342 const struct devlink_trap_policer *policers,
9343 size_t policers_count)
9344{
9345 int i;
9346
9347 mutex_lock(&devlink->lock);
9348 for (i = policers_count - 1; i >= 0; i--)
9349 devlink_trap_policer_unregister(devlink, &policers[i]);
9350 mutex_unlock(&devlink->lock);
9351}
9352EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister);
9353
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009354static void __devlink_compat_running_version(struct devlink *devlink,
9355 char *buf, size_t len)
9356{
9357 const struct nlattr *nlattr;
9358 struct devlink_info_req req;
9359 struct sk_buff *msg;
9360 int rem, err;
9361
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009362 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9363 if (!msg)
9364 return;
9365
9366 req.msg = msg;
9367 err = devlink->ops->info_get(devlink, &req, NULL);
9368 if (err)
9369 goto free_msg;
9370
9371 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
9372 const struct nlattr *kv;
9373 int rem_kv;
9374
9375 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
9376 continue;
9377
9378 nla_for_each_nested(kv, nlattr, rem_kv) {
9379 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
9380 continue;
9381
9382 strlcat(buf, nla_data(kv), len);
9383 strlcat(buf, " ", len);
9384 }
9385 }
9386free_msg:
9387 nlmsg_free(msg);
9388}
9389
9390void devlink_compat_running_version(struct net_device *dev,
9391 char *buf, size_t len)
9392{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009393 struct devlink *devlink;
9394
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009395 dev_hold(dev);
9396 rtnl_unlock();
9397
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009398 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08009399 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009400 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009401
9402 mutex_lock(&devlink->lock);
9403 __devlink_compat_running_version(devlink, buf, len);
9404 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009405
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009406out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009407 rtnl_lock();
9408 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009409}
9410
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009411int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
9412{
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009413 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009414 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009415
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009416 dev_hold(dev);
9417 rtnl_unlock();
9418
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009419 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009420 if (!devlink || !devlink->ops->flash_update) {
9421 ret = -EOPNOTSUPP;
9422 goto out;
9423 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009424
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009425 mutex_lock(&devlink->lock);
9426 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
9427 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009428
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009429out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009430 rtnl_lock();
9431 dev_put(dev);
9432
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009433 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009434}
9435
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01009436int devlink_compat_phys_port_name_get(struct net_device *dev,
9437 char *name, size_t len)
9438{
9439 struct devlink_port *devlink_port;
9440
9441 /* RTNL mutex is held here which ensures that devlink_port
9442 * instance cannot disappear in the middle. No need to take
9443 * any devlink lock as only permanent values are accessed.
9444 */
9445 ASSERT_RTNL();
9446
9447 devlink_port = netdev_to_devlink_port(dev);
9448 if (!devlink_port)
9449 return -EOPNOTSUPP;
9450
9451 return __devlink_port_phys_port_name_get(devlink_port, name, len);
9452}
9453
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009454int devlink_compat_switch_id_get(struct net_device *dev,
9455 struct netdev_phys_item_id *ppid)
9456{
9457 struct devlink_port *devlink_port;
9458
Vlad Buslov043b8412019-08-12 20:02:02 +03009459 /* Caller must hold RTNL mutex or reference to dev, which ensures that
9460 * devlink_port instance cannot disappear in the middle. No need to take
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009461 * any devlink lock as only permanent values are accessed.
9462 */
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009463 devlink_port = netdev_to_devlink_port(dev);
9464 if (!devlink_port || !devlink_port->attrs.switch_port)
9465 return -EOPNOTSUPP;
9466
9467 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
9468
9469 return 0;
9470}
9471
Jiri Pirko070c63f2019-10-03 11:49:39 +02009472static void __net_exit devlink_pernet_pre_exit(struct net *net)
9473{
9474 struct devlink *devlink;
9475 int err;
9476
9477 /* In case network namespace is getting destroyed, reload
9478 * all devlink instances from this namespace into init_net.
9479 */
9480 mutex_lock(&devlink_mutex);
9481 list_for_each_entry(devlink, &devlink_list, list) {
9482 if (net_eq(devlink_net(devlink), net)) {
9483 if (WARN_ON(!devlink_reload_supported(devlink)))
9484 continue;
9485 err = devlink_reload(devlink, &init_net, NULL);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01009486 if (err && err != -EOPNOTSUPP)
Jiri Pirko070c63f2019-10-03 11:49:39 +02009487 pr_warn("Failed to reload devlink instance into init_net\n");
9488 }
9489 }
9490 mutex_unlock(&devlink_mutex);
9491}
9492
9493static struct pernet_operations devlink_pernet_ops __net_initdata = {
9494 .pre_exit = devlink_pernet_pre_exit,
9495};
9496
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009497static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009498{
Jiri Pirko070c63f2019-10-03 11:49:39 +02009499 int err;
9500
9501 err = genl_register_family(&devlink_nl_family);
9502 if (err)
9503 goto out;
9504 err = register_pernet_subsys(&devlink_pernet_ops);
9505
9506out:
9507 WARN_ON(err);
9508 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009509}
9510
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009511subsys_initcall(devlink_init);