blob: a578634052a3c77366bee7922e8fd16eee564ec7 [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>
Jiri Pirkoe5224f02016-07-12 18:05:03 +020030#define CREATE_TRACE_POINTS
31#include <trace/events/devlink.h>
32
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020033static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
34 {
David Ahern12bdc5e2017-08-30 17:07:30 -070035 .name = "destination mac",
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020036 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
37 .bitwidth = 48,
38 },
39};
40
41struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
42 .name = "ethernet",
43 .id = DEVLINK_DPIPE_HEADER_ETHERNET,
44 .fields = devlink_dpipe_fields_ethernet,
45 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
46 .global = true,
47};
48EXPORT_SYMBOL(devlink_dpipe_header_ethernet);
49
Arkadi Sharshevsky3fb886e2017-08-24 08:40:00 +020050static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
51 {
52 .name = "destination ip",
53 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
54 .bitwidth = 32,
55 },
56};
57
58struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
59 .name = "ipv4",
60 .id = DEVLINK_DPIPE_HEADER_IPV4,
61 .fields = devlink_dpipe_fields_ipv4,
62 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
63 .global = true,
64};
65EXPORT_SYMBOL(devlink_dpipe_header_ipv4);
66
Arkadi Sharshevsky1797f5b2017-08-31 17:59:12 +020067static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
68 {
69 .name = "destination ip",
70 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
71 .bitwidth = 128,
72 },
73};
74
75struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
76 .name = "ipv6",
77 .id = DEVLINK_DPIPE_HEADER_IPV6,
78 .fields = devlink_dpipe_fields_ipv6,
79 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
80 .global = true,
81};
82EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
83
Jiri Pirkoe5224f02016-07-12 18:05:03 +020084EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
Nir Dotan57186a52019-02-04 18:47:45 +000085EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
Ido Schimmel5b888232020-09-29 11:15:50 +030086EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_trap_report);
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;
Andrew Lunn544e7c32020-10-04 18:12:54 +0200350 struct devlink_port *port;
Alex Veskerb16ebe92018-07-12 15:13:08 +0300351 struct list_head list;
Andrew Lunn544e7c32020-10-04 18:12:54 +0200352 union {
353 const struct devlink_region_ops *ops;
354 const struct devlink_port_region_ops *port_ops;
355 };
Alex Veskerb16ebe92018-07-12 15:13:08 +0300356 struct list_head snapshot_list;
357 u32 max_snapshots;
358 u32 cur_snapshots;
359 u64 size;
360};
361
Alex Veskerd7e52722018-07-12 15:13:10 +0300362struct devlink_snapshot {
363 struct list_head list;
364 struct devlink_region *region;
Alex Veskerd7e52722018-07-12 15:13:10 +0300365 u8 *data;
366 u32 id;
367};
368
Alex Veskerb16ebe92018-07-12 15:13:08 +0300369static struct devlink_region *
370devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
371{
372 struct devlink_region *region;
373
374 list_for_each_entry(region, &devlink->region_list, list)
Jacob Kellere8937682020-03-26 11:37:08 -0700375 if (!strcmp(region->ops->name, region_name))
Alex Veskerb16ebe92018-07-12 15:13:08 +0300376 return region;
377
378 return NULL;
379}
380
Andrew Lunn544e7c32020-10-04 18:12:54 +0200381static struct devlink_region *
382devlink_port_region_get_by_name(struct devlink_port *port,
383 const char *region_name)
384{
385 struct devlink_region *region;
386
387 list_for_each_entry(region, &port->region_list, list)
388 if (!strcmp(region->ops->name, region_name))
389 return region;
390
391 return NULL;
392}
393
Alex Veskerd7e52722018-07-12 15:13:10 +0300394static struct devlink_snapshot *
395devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
396{
397 struct devlink_snapshot *snapshot;
398
399 list_for_each_entry(snapshot, &region->snapshot_list, list)
400 if (snapshot->id == id)
401 return snapshot;
402
403 return NULL;
404}
405
Parav Pandit637989b2020-07-22 18:57:11 +0300406#define DEVLINK_NL_FLAG_NEED_PORT BIT(0)
407#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100408
409/* The per devlink instance lock is taken by default in the pre-doit
410 * operation, yet several commands do not require this. The global
411 * devlink lock is taken and protects from disruption by user-calls.
412 */
Parav Pandit637989b2020-07-22 18:57:11 +0300413#define DEVLINK_NL_FLAG_NO_LOCK BIT(2)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100414
415static int devlink_nl_pre_doit(const struct genl_ops *ops,
416 struct sk_buff *skb, struct genl_info *info)
417{
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300418 struct devlink_port *devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100419 struct devlink *devlink;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100420 int err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100421
422 mutex_lock(&devlink_mutex);
423 devlink = devlink_get_from_info(info);
424 if (IS_ERR(devlink)) {
425 mutex_unlock(&devlink_mutex);
426 return PTR_ERR(devlink);
427 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100428 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
429 mutex_lock(&devlink->lock);
Parav Pandit637989b2020-07-22 18:57:11 +0300430 info->user_ptr[0] = devlink;
431 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100432 devlink_port = devlink_port_get_from_info(devlink, info);
433 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100434 err = PTR_ERR(devlink_port);
435 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100436 }
Parav Pandit637989b2020-07-22 18:57:11 +0300437 info->user_ptr[1] = devlink_port;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300438 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300439 devlink_port = devlink_port_get_from_info(devlink, info);
440 if (!IS_ERR(devlink_port))
441 info->user_ptr[1] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100442 }
443 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100444
445unlock:
446 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
447 mutex_unlock(&devlink->lock);
448 mutex_unlock(&devlink_mutex);
449 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100450}
451
452static void devlink_nl_post_doit(const struct genl_ops *ops,
453 struct sk_buff *skb, struct genl_info *info)
454{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100455 struct devlink *devlink;
456
Parav Pandit637989b2020-07-22 18:57:11 +0300457 devlink = info->user_ptr[0];
458 if (~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
Moshe Shemeshdc64cc72020-10-07 09:00:44 +0300482struct devlink_reload_combination {
483 enum devlink_reload_action action;
484 enum devlink_reload_limit limit;
485};
486
487static const struct devlink_reload_combination devlink_reload_invalid_combinations[] = {
488 {
489 /* can't reinitialize driver with no down time */
490 .action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
491 .limit = DEVLINK_RELOAD_LIMIT_NO_RESET,
492 },
493};
494
495static bool
496devlink_reload_combination_is_invalid(enum devlink_reload_action action,
497 enum devlink_reload_limit limit)
498{
499 int i;
500
501 for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++)
502 if (devlink_reload_invalid_combinations[i].action == action &&
503 devlink_reload_invalid_combinations[i].limit == limit)
504 return true;
505 return false;
506}
507
Moshe Shemeshccdf0722020-10-07 09:00:43 +0300508static bool
509devlink_reload_action_is_supported(struct devlink *devlink, enum devlink_reload_action action)
510{
511 return test_bit(action, &devlink->ops->reload_actions);
512}
513
Moshe Shemeshdc64cc72020-10-07 09:00:44 +0300514static bool
515devlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_limit limit)
516{
517 return test_bit(limit, &devlink->ops->reload_limits);
518}
519
Moshe Shemesha254c262020-10-07 09:00:45 +0300520static int devlink_reload_stat_put(struct sk_buff *msg, enum devlink_reload_action action,
521 enum devlink_reload_limit limit, u32 value)
522{
523 struct nlattr *reload_stats_entry;
524
525 reload_stats_entry = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS_ENTRY);
526 if (!reload_stats_entry)
527 return -EMSGSIZE;
528
529 if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, action) ||
530 nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) ||
531 nla_put_u32(msg, DEVLINK_ATTR_RELOAD_STATS_VALUE, value))
532 goto nla_put_failure;
533 nla_nest_end(msg, reload_stats_entry);
534 return 0;
535
536nla_put_failure:
537 nla_nest_cancel(msg, reload_stats_entry);
538 return -EMSGSIZE;
539}
540
Moshe Shemesh77069ba2020-10-07 09:00:46 +0300541static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink, bool is_remote)
Moshe Shemesha254c262020-10-07 09:00:45 +0300542{
543 struct nlattr *reload_stats_attr;
544 int i, j, stat_idx;
545 u32 value;
546
Moshe Shemesh77069ba2020-10-07 09:00:46 +0300547 if (!is_remote)
548 reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS);
549 else
550 reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_REMOTE_RELOAD_STATS);
Moshe Shemesha254c262020-10-07 09:00:45 +0300551
552 if (!reload_stats_attr)
553 return -EMSGSIZE;
554
555 for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) {
Moshe Shemesh77069ba2020-10-07 09:00:46 +0300556 /* Remote stats are shown even if not locally supported. Stats
557 * of actions with unspecified limit are shown though drivers
558 * don't need to register unspecified limit.
559 */
560 if (!is_remote && j != DEVLINK_RELOAD_LIMIT_UNSPEC &&
Moshe Shemesha254c262020-10-07 09:00:45 +0300561 !devlink_reload_limit_is_supported(devlink, j))
562 continue;
563 for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) {
Moshe Shemesh77069ba2020-10-07 09:00:46 +0300564 if ((!is_remote && !devlink_reload_action_is_supported(devlink, i)) ||
565 i == DEVLINK_RELOAD_ACTION_UNSPEC ||
Moshe Shemesha254c262020-10-07 09:00:45 +0300566 devlink_reload_combination_is_invalid(i, j))
567 continue;
568
569 stat_idx = j * __DEVLINK_RELOAD_ACTION_MAX + i;
Moshe Shemesh77069ba2020-10-07 09:00:46 +0300570 if (!is_remote)
571 value = devlink->stats.reload_stats[stat_idx];
572 else
573 value = devlink->stats.remote_reload_stats[stat_idx];
Moshe Shemesha254c262020-10-07 09:00:45 +0300574 if (devlink_reload_stat_put(msg, i, j, value))
575 goto nla_put_failure;
576 }
577 }
578 nla_nest_end(msg, reload_stats_attr);
579 return 0;
580
581nla_put_failure:
582 nla_nest_cancel(msg, reload_stats_attr);
583 return -EMSGSIZE;
584}
585
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100586static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
587 enum devlink_command cmd, u32 portid,
588 u32 seq, int flags)
589{
Moshe Shemesha254c262020-10-07 09:00:45 +0300590 struct nlattr *dev_stats;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100591 void *hdr;
592
593 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
594 if (!hdr)
595 return -EMSGSIZE;
596
597 if (devlink_nl_put_handle(msg, devlink))
598 goto nla_put_failure;
Jiri Pirko2670ac22019-09-12 10:49:46 +0200599 if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed))
600 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100601
Moshe Shemesha254c262020-10-07 09:00:45 +0300602 dev_stats = nla_nest_start(msg, DEVLINK_ATTR_DEV_STATS);
603 if (!dev_stats)
604 goto nla_put_failure;
605
Moshe Shemesh77069ba2020-10-07 09:00:46 +0300606 if (devlink_reload_stats_put(msg, devlink, false))
607 goto dev_stats_nest_cancel;
608 if (devlink_reload_stats_put(msg, devlink, true))
Moshe Shemesha254c262020-10-07 09:00:45 +0300609 goto dev_stats_nest_cancel;
610
611 nla_nest_end(msg, dev_stats);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100612 genlmsg_end(msg, hdr);
613 return 0;
614
Moshe Shemesha254c262020-10-07 09:00:45 +0300615dev_stats_nest_cancel:
616 nla_nest_cancel(msg, dev_stats);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100617nla_put_failure:
618 genlmsg_cancel(msg, hdr);
619 return -EMSGSIZE;
620}
621
622static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
623{
624 struct sk_buff *msg;
625 int err;
626
627 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
628
629 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
630 if (!msg)
631 return;
632
633 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
634 if (err) {
635 nlmsg_free(msg);
636 return;
637 }
638
639 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
640 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
641}
642
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200643static int devlink_nl_port_attrs_put(struct sk_buff *msg,
644 struct devlink_port *devlink_port)
645{
646 struct devlink_port_attrs *attrs = &devlink_port->attrs;
647
Danielle Ratson10a429b2020-07-09 16:18:14 +0300648 if (!devlink_port->attrs_set)
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200649 return 0;
Danielle Ratsona21cf0a2020-07-09 16:18:18 +0300650 if (attrs->lanes) {
651 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
652 return -EMSGSIZE;
653 }
Danielle Ratsona0f49b52020-07-09 16:18:20 +0300654 if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
655 return -EMSGSIZE;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200656 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
657 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500658 switch (devlink_port->attrs.flavour) {
659 case DEVLINK_PORT_FLAVOUR_PCI_PF:
Parav Pandit3a2d9582020-09-09 07:50:37 +0300660 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
661 attrs->pci_pf.controller) ||
662 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_pf.pf))
Parav Pandit98fd2d62019-07-08 23:17:37 -0500663 return -EMSGSIZE;
Parav Pandit05b595e2020-09-09 07:50:36 +0300664 if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_pf.external))
665 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500666 break;
667 case DEVLINK_PORT_FLAVOUR_PCI_VF:
Parav Pandit3a2d9582020-09-09 07:50:37 +0300668 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
669 attrs->pci_vf.controller) ||
670 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_vf.pf) ||
671 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER, attrs->pci_vf.vf))
Parav Pandite41b6bf2019-07-08 23:17:38 -0500672 return -EMSGSIZE;
Parav Pandit05b595e2020-09-09 07:50:36 +0300673 if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_vf.external))
674 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500675 break;
676 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
677 case DEVLINK_PORT_FLAVOUR_CPU:
678 case DEVLINK_PORT_FLAVOUR_DSA:
Parav Panditacf1ee42020-03-03 08:12:42 -0600679 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Parav Pandit58b6be42019-08-30 05:39:45 -0500680 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
681 attrs->phys.port_number))
682 return -EMSGSIZE;
683 if (!attrs->split)
684 return 0;
685 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
686 attrs->phys.port_number))
687 return -EMSGSIZE;
688 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
689 attrs->phys.split_subport_number))
690 return -EMSGSIZE;
691 break;
692 default:
693 break;
Parav Pandit98fd2d62019-07-08 23:17:37 -0500694 }
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200695 return 0;
696}
697
Parav Pandit2a916ec2020-06-19 03:32:48 +0000698static int
699devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
700 struct netlink_ext_ack *extack)
701{
702 struct devlink *devlink = port->devlink;
703 const struct devlink_ops *ops;
704 struct nlattr *function_attr;
705 bool empty_nest = true;
706 int err = 0;
707
708 function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
709 if (!function_attr)
710 return -EMSGSIZE;
711
712 ops = devlink->ops;
713 if (ops->port_function_hw_addr_get) {
Stephen Rothwell29cb9862020-06-23 13:43:06 +1000714 int hw_addr_len;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000715 u8 hw_addr[MAX_ADDR_LEN];
716
717 err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack);
718 if (err == -EOPNOTSUPP) {
719 /* Port function attributes are optional for a port. If port doesn't
720 * support function attribute, returning -EOPNOTSUPP is not an error.
721 */
722 err = 0;
723 goto out;
724 } else if (err) {
725 goto out;
726 }
727 err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr);
728 if (err)
729 goto out;
730 empty_nest = false;
731 }
732
733out:
734 if (err || empty_nest)
735 nla_nest_cancel(msg, function_attr);
736 else
737 nla_nest_end(msg, function_attr);
738 return err;
739}
740
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100741static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
742 struct devlink_port *devlink_port,
743 enum devlink_command cmd, u32 portid,
Parav Pandita829eb02020-06-19 03:32:47 +0000744 u32 seq, int flags,
745 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100746{
747 void *hdr;
748
749 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
750 if (!hdr)
751 return -EMSGSIZE;
752
753 if (devlink_nl_put_handle(msg, devlink))
754 goto nla_put_failure;
755 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
756 goto nla_put_failure;
Jiri Pirkob8f97552019-03-24 11:14:37 +0100757
Ido Schimmel0f420b62019-08-17 16:28:17 +0300758 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100759 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100760 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100761 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
762 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
763 devlink_port->desired_type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100764 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100765 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
766 struct net_device *netdev = devlink_port->type_dev;
767
768 if (netdev &&
769 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
770 netdev->ifindex) ||
771 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
772 netdev->name)))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100773 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100774 }
775 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
776 struct ib_device *ibdev = devlink_port->type_dev;
777
778 if (ibdev &&
779 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
780 ibdev->name))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100781 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100782 }
Ido Schimmel0f420b62019-08-17 16:28:17 +0300783 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200784 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100785 goto nla_put_failure;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000786 if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
787 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100788
789 genlmsg_end(msg, hdr);
790 return 0;
791
Jiri Pirkob8f97552019-03-24 11:14:37 +0100792nla_put_failure_type_locked:
Ido Schimmel0f420b62019-08-17 16:28:17 +0300793 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100794nla_put_failure:
795 genlmsg_cancel(msg, hdr);
796 return -EMSGSIZE;
797}
798
799static void devlink_port_notify(struct devlink_port *devlink_port,
800 enum devlink_command cmd)
801{
802 struct devlink *devlink = devlink_port->devlink;
803 struct sk_buff *msg;
804 int err;
805
806 if (!devlink_port->registered)
807 return;
808
809 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
810
811 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
812 if (!msg)
813 return;
814
Parav Pandita829eb02020-06-19 03:32:47 +0000815 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0,
816 NULL);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100817 if (err) {
818 nlmsg_free(msg);
819 return;
820 }
821
822 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
823 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
824}
825
826static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
827{
828 struct devlink *devlink = info->user_ptr[0];
829 struct sk_buff *msg;
830 int err;
831
832 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
833 if (!msg)
834 return -ENOMEM;
835
836 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
837 info->snd_portid, info->snd_seq, 0);
838 if (err) {
839 nlmsg_free(msg);
840 return err;
841 }
842
843 return genlmsg_reply(msg, info);
844}
845
846static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
847 struct netlink_callback *cb)
848{
849 struct devlink *devlink;
850 int start = cb->args[0];
851 int idx = 0;
852 int err;
853
854 mutex_lock(&devlink_mutex);
855 list_for_each_entry(devlink, &devlink_list, list) {
856 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
857 continue;
858 if (idx < start) {
859 idx++;
860 continue;
861 }
862 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
863 NETLINK_CB(cb->skb).portid,
864 cb->nlh->nlmsg_seq, NLM_F_MULTI);
865 if (err)
866 goto out;
867 idx++;
868 }
869out:
870 mutex_unlock(&devlink_mutex);
871
872 cb->args[0] = idx;
873 return msg->len;
874}
875
876static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
877 struct genl_info *info)
878{
Parav Pandit637989b2020-07-22 18:57:11 +0300879 struct devlink_port *devlink_port = info->user_ptr[1];
Jiri Pirko1fc22572016-04-08 19:12:48 +0200880 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100881 struct sk_buff *msg;
882 int err;
883
884 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
885 if (!msg)
886 return -ENOMEM;
887
888 err = devlink_nl_port_fill(msg, devlink, devlink_port,
889 DEVLINK_CMD_PORT_NEW,
Parav Pandita829eb02020-06-19 03:32:47 +0000890 info->snd_portid, info->snd_seq, 0,
891 info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100892 if (err) {
893 nlmsg_free(msg);
894 return err;
895 }
896
897 return genlmsg_reply(msg, info);
898}
899
900static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
901 struct netlink_callback *cb)
902{
903 struct devlink *devlink;
904 struct devlink_port *devlink_port;
905 int start = cb->args[0];
906 int idx = 0;
907 int err;
908
909 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100910 list_for_each_entry(devlink, &devlink_list, list) {
911 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
912 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100913 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100914 list_for_each_entry(devlink_port, &devlink->port_list, list) {
915 if (idx < start) {
916 idx++;
917 continue;
918 }
919 err = devlink_nl_port_fill(msg, devlink, devlink_port,
920 DEVLINK_CMD_NEW,
921 NETLINK_CB(cb->skb).portid,
922 cb->nlh->nlmsg_seq,
Parav Pandita829eb02020-06-19 03:32:47 +0000923 NLM_F_MULTI,
924 cb->extack);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100925 if (err) {
926 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100927 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100928 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100929 idx++;
930 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100931 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100932 }
933out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100934 mutex_unlock(&devlink_mutex);
935
936 cb->args[0] = idx;
937 return msg->len;
938}
939
940static int devlink_port_type_set(struct devlink *devlink,
941 struct devlink_port *devlink_port,
942 enum devlink_port_type port_type)
943
944{
945 int err;
946
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800947 if (devlink->ops->port_type_set) {
Elad Raz6edf1012016-10-23 17:43:05 +0200948 if (port_type == devlink_port->type)
949 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100950 err = devlink->ops->port_type_set(devlink_port, port_type);
951 if (err)
952 return err;
953 devlink_port->desired_type = port_type;
954 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
955 return 0;
956 }
957 return -EOPNOTSUPP;
958}
959
Parav Pandita1e8ae92020-06-19 03:32:49 +0000960static int
961devlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port,
962 const struct nlattr *attr, struct netlink_ext_ack *extack)
963{
964 const struct devlink_ops *ops;
965 const u8 *hw_addr;
966 int hw_addr_len;
967 int err;
968
969 hw_addr = nla_data(attr);
970 hw_addr_len = nla_len(attr);
971 if (hw_addr_len > MAX_ADDR_LEN) {
972 NL_SET_ERR_MSG_MOD(extack, "Port function hardware address too long");
973 return -EINVAL;
974 }
975 if (port->type == DEVLINK_PORT_TYPE_ETH) {
976 if (hw_addr_len != ETH_ALEN) {
977 NL_SET_ERR_MSG_MOD(extack, "Address must be 6 bytes for Ethernet device");
978 return -EINVAL;
979 }
980 if (!is_unicast_ether_addr(hw_addr)) {
981 NL_SET_ERR_MSG_MOD(extack, "Non-unicast hardware address unsupported");
982 return -EINVAL;
983 }
984 }
985
986 ops = devlink->ops;
987 if (!ops->port_function_hw_addr_set) {
988 NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes");
989 return -EOPNOTSUPP;
990 }
991
992 err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack);
993 if (err)
994 return err;
995
996 devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
997 return 0;
998}
999
1000static int
1001devlink_port_function_set(struct devlink *devlink, struct devlink_port *port,
1002 const struct nlattr *attr, struct netlink_ext_ack *extack)
1003{
1004 struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];
1005 int err;
1006
1007 err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr,
1008 devlink_function_nl_policy, extack);
1009 if (err < 0) {
1010 NL_SET_ERR_MSG_MOD(extack, "Fail to parse port function attributes");
1011 return err;
1012 }
1013
1014 attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
1015 if (attr)
1016 err = devlink_port_function_hw_addr_set(devlink, port, attr, extack);
1017
1018 return err;
1019}
1020
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001021static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
1022 struct genl_info *info)
1023{
Parav Pandit637989b2020-07-22 18:57:11 +03001024 struct devlink_port *devlink_port = info->user_ptr[1];
Jiri Pirko1fc22572016-04-08 19:12:48 +02001025 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001026 int err;
1027
1028 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
1029 enum devlink_port_type port_type;
1030
1031 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
1032 err = devlink_port_type_set(devlink, devlink_port, port_type);
1033 if (err)
1034 return err;
1035 }
Parav Pandita1e8ae92020-06-19 03:32:49 +00001036
1037 if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
1038 struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
1039 struct netlink_ext_ack *extack = info->extack;
1040
1041 err = devlink_port_function_set(devlink, devlink_port, attr, extack);
1042 if (err)
1043 return err;
1044 }
1045
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001046 return 0;
1047}
1048
David Ahernac0fc8a2018-06-05 08:14:09 -07001049static int devlink_port_split(struct devlink *devlink, u32 port_index,
1050 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001051
1052{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001053 if (devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -07001054 return devlink->ops->port_split(devlink, port_index, count,
1055 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001056 return -EOPNOTSUPP;
1057}
1058
1059static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
1060 struct genl_info *info)
1061{
1062 struct devlink *devlink = info->user_ptr[0];
Danielle Ratson82901ad2020-07-09 16:18:21 +03001063 struct devlink_port *devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001064 u32 port_index;
1065 u32 count;
1066
1067 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
1068 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
1069 return -EINVAL;
1070
Danielle Ratson82901ad2020-07-09 16:18:21 +03001071 devlink_port = devlink_port_get_from_info(devlink, info);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001072 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
1073 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
Danielle Ratson82901ad2020-07-09 16:18:21 +03001074
1075 if (IS_ERR(devlink_port))
1076 return -EINVAL;
1077
1078 if (!devlink_port->attrs.splittable) {
1079 /* Split ports cannot be split. */
1080 if (devlink_port->attrs.split)
1081 NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split further");
1082 else
1083 NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split");
1084 return -EINVAL;
1085 }
1086
1087 if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
1088 NL_SET_ERR_MSG_MOD(info->extack, "Invalid split count");
1089 return -EINVAL;
1090 }
1091
David Ahernac0fc8a2018-06-05 08:14:09 -07001092 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001093}
1094
David Ahernac0fc8a2018-06-05 08:14:09 -07001095static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
1096 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001097
1098{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001099 if (devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -07001100 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001101 return -EOPNOTSUPP;
1102}
1103
1104static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
1105 struct genl_info *info)
1106{
1107 struct devlink *devlink = info->user_ptr[0];
1108 u32 port_index;
1109
1110 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
1111 return -EINVAL;
1112
1113 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -07001114 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001115}
1116
Jiri Pirkobf797472016-04-14 18:19:13 +02001117static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
1118 struct devlink_sb *devlink_sb,
1119 enum devlink_command cmd, u32 portid,
1120 u32 seq, int flags)
1121{
1122 void *hdr;
1123
1124 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1125 if (!hdr)
1126 return -EMSGSIZE;
1127
1128 if (devlink_nl_put_handle(msg, devlink))
1129 goto nla_put_failure;
1130 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1131 goto nla_put_failure;
1132 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
1133 goto nla_put_failure;
1134 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
1135 devlink_sb->ingress_pools_count))
1136 goto nla_put_failure;
1137 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
1138 devlink_sb->egress_pools_count))
1139 goto nla_put_failure;
1140 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
1141 devlink_sb->ingress_tc_count))
1142 goto nla_put_failure;
1143 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
1144 devlink_sb->egress_tc_count))
1145 goto nla_put_failure;
1146
1147 genlmsg_end(msg, hdr);
1148 return 0;
1149
1150nla_put_failure:
1151 genlmsg_cancel(msg, hdr);
1152 return -EMSGSIZE;
1153}
1154
1155static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
1156 struct genl_info *info)
1157{
1158 struct devlink *devlink = info->user_ptr[0];
Parav Pandit637989b2020-07-22 18:57:11 +03001159 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001160 struct sk_buff *msg;
1161 int err;
1162
Parav Pandit637989b2020-07-22 18:57:11 +03001163 devlink_sb = devlink_sb_get_from_info(devlink, info);
1164 if (IS_ERR(devlink_sb))
1165 return PTR_ERR(devlink_sb);
1166
Jiri Pirkobf797472016-04-14 18:19:13 +02001167 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1168 if (!msg)
1169 return -ENOMEM;
1170
1171 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1172 DEVLINK_CMD_SB_NEW,
1173 info->snd_portid, info->snd_seq, 0);
1174 if (err) {
1175 nlmsg_free(msg);
1176 return err;
1177 }
1178
1179 return genlmsg_reply(msg, info);
1180}
1181
1182static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
1183 struct netlink_callback *cb)
1184{
1185 struct devlink *devlink;
1186 struct devlink_sb *devlink_sb;
1187 int start = cb->args[0];
1188 int idx = 0;
1189 int err;
1190
1191 mutex_lock(&devlink_mutex);
1192 list_for_each_entry(devlink, &devlink_list, list) {
1193 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
1194 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001195 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001196 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1197 if (idx < start) {
1198 idx++;
1199 continue;
1200 }
1201 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1202 DEVLINK_CMD_SB_NEW,
1203 NETLINK_CB(cb->skb).portid,
1204 cb->nlh->nlmsg_seq,
1205 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001206 if (err) {
1207 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001208 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001209 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001210 idx++;
1211 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001212 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001213 }
1214out:
1215 mutex_unlock(&devlink_mutex);
1216
1217 cb->args[0] = idx;
1218 return msg->len;
1219}
1220
1221static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
1222 struct devlink_sb *devlink_sb,
1223 u16 pool_index, enum devlink_command cmd,
1224 u32 portid, u32 seq, int flags)
1225{
1226 struct devlink_sb_pool_info pool_info;
1227 void *hdr;
1228 int err;
1229
1230 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
1231 pool_index, &pool_info);
1232 if (err)
1233 return err;
1234
1235 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1236 if (!hdr)
1237 return -EMSGSIZE;
1238
1239 if (devlink_nl_put_handle(msg, devlink))
1240 goto nla_put_failure;
1241 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1242 goto nla_put_failure;
1243 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1244 goto nla_put_failure;
1245 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
1246 goto nla_put_failure;
1247 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
1248 goto nla_put_failure;
1249 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1250 pool_info.threshold_type))
1251 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -08001252 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
1253 pool_info.cell_size))
1254 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +02001255
1256 genlmsg_end(msg, hdr);
1257 return 0;
1258
1259nla_put_failure:
1260 genlmsg_cancel(msg, hdr);
1261 return -EMSGSIZE;
1262}
1263
1264static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
1265 struct genl_info *info)
1266{
1267 struct devlink *devlink = info->user_ptr[0];
Parav Pandit637989b2020-07-22 18:57:11 +03001268 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001269 struct sk_buff *msg;
1270 u16 pool_index;
1271 int err;
1272
Parav Pandit637989b2020-07-22 18:57:11 +03001273 devlink_sb = devlink_sb_get_from_info(devlink, info);
1274 if (IS_ERR(devlink_sb))
1275 return PTR_ERR(devlink_sb);
1276
Jiri Pirkobf797472016-04-14 18:19:13 +02001277 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1278 &pool_index);
1279 if (err)
1280 return err;
1281
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001282 if (!devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001283 return -EOPNOTSUPP;
1284
1285 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1286 if (!msg)
1287 return -ENOMEM;
1288
1289 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
1290 DEVLINK_CMD_SB_POOL_NEW,
1291 info->snd_portid, info->snd_seq, 0);
1292 if (err) {
1293 nlmsg_free(msg);
1294 return err;
1295 }
1296
1297 return genlmsg_reply(msg, info);
1298}
1299
1300static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1301 struct devlink *devlink,
1302 struct devlink_sb *devlink_sb,
1303 u32 portid, u32 seq)
1304{
1305 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1306 u16 pool_index;
1307 int err;
1308
1309 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1310 if (*p_idx < start) {
1311 (*p_idx)++;
1312 continue;
1313 }
1314 err = devlink_nl_sb_pool_fill(msg, devlink,
1315 devlink_sb,
1316 pool_index,
1317 DEVLINK_CMD_SB_POOL_NEW,
1318 portid, seq, NLM_F_MULTI);
1319 if (err)
1320 return err;
1321 (*p_idx)++;
1322 }
1323 return 0;
1324}
1325
1326static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1327 struct netlink_callback *cb)
1328{
1329 struct devlink *devlink;
1330 struct devlink_sb *devlink_sb;
1331 int start = cb->args[0];
1332 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001333 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001334
1335 mutex_lock(&devlink_mutex);
1336 list_for_each_entry(devlink, &devlink_list, list) {
1337 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001338 !devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001339 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001340 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001341 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1342 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1343 devlink_sb,
1344 NETLINK_CB(cb->skb).portid,
1345 cb->nlh->nlmsg_seq);
Jakub Kicinski82274d02020-07-28 16:15:07 -07001346 if (err == -EOPNOTSUPP) {
1347 err = 0;
1348 } else if (err) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001349 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001350 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001351 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001352 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001353 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001354 }
1355out:
1356 mutex_unlock(&devlink_mutex);
1357
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001358 if (err != -EMSGSIZE)
1359 return err;
1360
Jiri Pirkobf797472016-04-14 18:19:13 +02001361 cb->args[0] = idx;
1362 return msg->len;
1363}
1364
1365static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1366 u16 pool_index, u32 size,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001367 enum devlink_sb_threshold_type threshold_type,
1368 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001369
1370{
1371 const struct devlink_ops *ops = devlink->ops;
1372
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001373 if (ops->sb_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001374 return ops->sb_pool_set(devlink, sb_index, pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001375 size, threshold_type, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001376 return -EOPNOTSUPP;
1377}
1378
1379static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1380 struct genl_info *info)
1381{
1382 struct devlink *devlink = info->user_ptr[0];
Jiri Pirkobf797472016-04-14 18:19:13 +02001383 enum devlink_sb_threshold_type threshold_type;
Parav Pandit637989b2020-07-22 18:57:11 +03001384 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001385 u16 pool_index;
1386 u32 size;
1387 int err;
1388
Parav Pandit637989b2020-07-22 18:57:11 +03001389 devlink_sb = devlink_sb_get_from_info(devlink, info);
1390 if (IS_ERR(devlink_sb))
1391 return PTR_ERR(devlink_sb);
1392
Jiri Pirkobf797472016-04-14 18:19:13 +02001393 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1394 &pool_index);
1395 if (err)
1396 return err;
1397
1398 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1399 if (err)
1400 return err;
1401
1402 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1403 return -EINVAL;
1404
1405 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1406 return devlink_sb_pool_set(devlink, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001407 pool_index, size, threshold_type,
1408 info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001409}
1410
1411static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1412 struct devlink *devlink,
1413 struct devlink_port *devlink_port,
1414 struct devlink_sb *devlink_sb,
1415 u16 pool_index,
1416 enum devlink_command cmd,
1417 u32 portid, u32 seq, int flags)
1418{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001419 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001420 u32 threshold;
1421 void *hdr;
1422 int err;
1423
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001424 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1425 pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001426 if (err)
1427 return err;
1428
1429 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1430 if (!hdr)
1431 return -EMSGSIZE;
1432
1433 if (devlink_nl_put_handle(msg, devlink))
1434 goto nla_put_failure;
1435 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1436 goto nla_put_failure;
1437 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1438 goto nla_put_failure;
1439 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1440 goto nla_put_failure;
1441 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1442 goto nla_put_failure;
1443
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001444 if (ops->sb_occ_port_pool_get) {
1445 u32 cur;
1446 u32 max;
1447
1448 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1449 pool_index, &cur, &max);
1450 if (err && err != -EOPNOTSUPP)
1451 return err;
1452 if (!err) {
1453 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1454 goto nla_put_failure;
1455 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1456 goto nla_put_failure;
1457 }
1458 }
1459
Jiri Pirkobf797472016-04-14 18:19:13 +02001460 genlmsg_end(msg, hdr);
1461 return 0;
1462
1463nla_put_failure:
1464 genlmsg_cancel(msg, hdr);
1465 return -EMSGSIZE;
1466}
1467
1468static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1469 struct genl_info *info)
1470{
Parav Pandit637989b2020-07-22 18:57:11 +03001471 struct devlink_port *devlink_port = info->user_ptr[1];
Jiri Pirkobf797472016-04-14 18:19:13 +02001472 struct devlink *devlink = devlink_port->devlink;
Parav Pandit637989b2020-07-22 18:57:11 +03001473 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001474 struct sk_buff *msg;
1475 u16 pool_index;
1476 int err;
1477
Parav Pandit637989b2020-07-22 18:57:11 +03001478 devlink_sb = devlink_sb_get_from_info(devlink, info);
1479 if (IS_ERR(devlink_sb))
1480 return PTR_ERR(devlink_sb);
1481
Jiri Pirkobf797472016-04-14 18:19:13 +02001482 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1483 &pool_index);
1484 if (err)
1485 return err;
1486
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001487 if (!devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001488 return -EOPNOTSUPP;
1489
1490 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1491 if (!msg)
1492 return -ENOMEM;
1493
1494 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1495 devlink_sb, pool_index,
1496 DEVLINK_CMD_SB_PORT_POOL_NEW,
1497 info->snd_portid, info->snd_seq, 0);
1498 if (err) {
1499 nlmsg_free(msg);
1500 return err;
1501 }
1502
1503 return genlmsg_reply(msg, info);
1504}
1505
1506static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1507 struct devlink *devlink,
1508 struct devlink_sb *devlink_sb,
1509 u32 portid, u32 seq)
1510{
1511 struct devlink_port *devlink_port;
1512 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1513 u16 pool_index;
1514 int err;
1515
1516 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1517 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1518 if (*p_idx < start) {
1519 (*p_idx)++;
1520 continue;
1521 }
1522 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1523 devlink_port,
1524 devlink_sb,
1525 pool_index,
1526 DEVLINK_CMD_SB_PORT_POOL_NEW,
1527 portid, seq,
1528 NLM_F_MULTI);
1529 if (err)
1530 return err;
1531 (*p_idx)++;
1532 }
1533 }
1534 return 0;
1535}
1536
1537static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1538 struct netlink_callback *cb)
1539{
1540 struct devlink *devlink;
1541 struct devlink_sb *devlink_sb;
1542 int start = cb->args[0];
1543 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001544 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001545
1546 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001547 list_for_each_entry(devlink, &devlink_list, list) {
1548 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001549 !devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001550 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001551 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001552 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1553 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1554 devlink, devlink_sb,
1555 NETLINK_CB(cb->skb).portid,
1556 cb->nlh->nlmsg_seq);
Jakub Kicinski82274d02020-07-28 16:15:07 -07001557 if (err == -EOPNOTSUPP) {
1558 err = 0;
1559 } else if (err) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001560 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001561 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001562 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001563 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001564 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001565 }
1566out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001567 mutex_unlock(&devlink_mutex);
1568
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001569 if (err != -EMSGSIZE)
1570 return err;
1571
Jiri Pirkobf797472016-04-14 18:19:13 +02001572 cb->args[0] = idx;
1573 return msg->len;
1574}
1575
1576static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1577 unsigned int sb_index, u16 pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001578 u32 threshold,
1579 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001580
1581{
1582 const struct devlink_ops *ops = devlink_port->devlink->ops;
1583
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001584 if (ops->sb_port_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001585 return ops->sb_port_pool_set(devlink_port, sb_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001586 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001587 return -EOPNOTSUPP;
1588}
1589
1590static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1591 struct genl_info *info)
1592{
Parav Pandit637989b2020-07-22 18:57:11 +03001593 struct devlink_port *devlink_port = info->user_ptr[1];
1594 struct devlink *devlink = info->user_ptr[0];
1595 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001596 u16 pool_index;
1597 u32 threshold;
1598 int err;
1599
Parav Pandit637989b2020-07-22 18:57:11 +03001600 devlink_sb = devlink_sb_get_from_info(devlink, info);
1601 if (IS_ERR(devlink_sb))
1602 return PTR_ERR(devlink_sb);
1603
Jiri Pirkobf797472016-04-14 18:19:13 +02001604 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1605 &pool_index);
1606 if (err)
1607 return err;
1608
1609 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1610 return -EINVAL;
1611
1612 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1613 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001614 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001615}
1616
1617static int
1618devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1619 struct devlink_port *devlink_port,
1620 struct devlink_sb *devlink_sb, u16 tc_index,
1621 enum devlink_sb_pool_type pool_type,
1622 enum devlink_command cmd,
1623 u32 portid, u32 seq, int flags)
1624{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001625 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001626 u16 pool_index;
1627 u32 threshold;
1628 void *hdr;
1629 int err;
1630
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001631 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1632 tc_index, pool_type,
1633 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001634 if (err)
1635 return err;
1636
1637 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1638 if (!hdr)
1639 return -EMSGSIZE;
1640
1641 if (devlink_nl_put_handle(msg, devlink))
1642 goto nla_put_failure;
1643 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1644 goto nla_put_failure;
1645 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1646 goto nla_put_failure;
1647 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1648 goto nla_put_failure;
1649 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1650 goto nla_put_failure;
1651 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1652 goto nla_put_failure;
1653 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1654 goto nla_put_failure;
1655
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001656 if (ops->sb_occ_tc_port_bind_get) {
1657 u32 cur;
1658 u32 max;
1659
1660 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1661 devlink_sb->index,
1662 tc_index, pool_type,
1663 &cur, &max);
1664 if (err && err != -EOPNOTSUPP)
1665 return err;
1666 if (!err) {
1667 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1668 goto nla_put_failure;
1669 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1670 goto nla_put_failure;
1671 }
1672 }
1673
Jiri Pirkobf797472016-04-14 18:19:13 +02001674 genlmsg_end(msg, hdr);
1675 return 0;
1676
1677nla_put_failure:
1678 genlmsg_cancel(msg, hdr);
1679 return -EMSGSIZE;
1680}
1681
1682static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1683 struct genl_info *info)
1684{
Parav Pandit637989b2020-07-22 18:57:11 +03001685 struct devlink_port *devlink_port = info->user_ptr[1];
Jiri Pirkobf797472016-04-14 18:19:13 +02001686 struct devlink *devlink = devlink_port->devlink;
Parav Pandit637989b2020-07-22 18:57:11 +03001687 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001688 struct sk_buff *msg;
1689 enum devlink_sb_pool_type pool_type;
1690 u16 tc_index;
1691 int err;
1692
Parav Pandit637989b2020-07-22 18:57:11 +03001693 devlink_sb = devlink_sb_get_from_info(devlink, info);
1694 if (IS_ERR(devlink_sb))
1695 return PTR_ERR(devlink_sb);
1696
Jiri Pirkobf797472016-04-14 18:19:13 +02001697 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1698 if (err)
1699 return err;
1700
1701 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1702 pool_type, &tc_index);
1703 if (err)
1704 return err;
1705
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001706 if (!devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001707 return -EOPNOTSUPP;
1708
1709 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1710 if (!msg)
1711 return -ENOMEM;
1712
1713 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1714 devlink_sb, tc_index, pool_type,
1715 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1716 info->snd_portid,
1717 info->snd_seq, 0);
1718 if (err) {
1719 nlmsg_free(msg);
1720 return err;
1721 }
1722
1723 return genlmsg_reply(msg, info);
1724}
1725
1726static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1727 int start, int *p_idx,
1728 struct devlink *devlink,
1729 struct devlink_sb *devlink_sb,
1730 u32 portid, u32 seq)
1731{
1732 struct devlink_port *devlink_port;
1733 u16 tc_index;
1734 int err;
1735
1736 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1737 for (tc_index = 0;
1738 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1739 if (*p_idx < start) {
1740 (*p_idx)++;
1741 continue;
1742 }
1743 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1744 devlink_port,
1745 devlink_sb,
1746 tc_index,
1747 DEVLINK_SB_POOL_TYPE_INGRESS,
1748 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1749 portid, seq,
1750 NLM_F_MULTI);
1751 if (err)
1752 return err;
1753 (*p_idx)++;
1754 }
1755 for (tc_index = 0;
1756 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1757 if (*p_idx < start) {
1758 (*p_idx)++;
1759 continue;
1760 }
1761 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1762 devlink_port,
1763 devlink_sb,
1764 tc_index,
1765 DEVLINK_SB_POOL_TYPE_EGRESS,
1766 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1767 portid, seq,
1768 NLM_F_MULTI);
1769 if (err)
1770 return err;
1771 (*p_idx)++;
1772 }
1773 }
1774 return 0;
1775}
1776
1777static int
1778devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1779 struct netlink_callback *cb)
1780{
1781 struct devlink *devlink;
1782 struct devlink_sb *devlink_sb;
1783 int start = cb->args[0];
1784 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001785 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001786
1787 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001788 list_for_each_entry(devlink, &devlink_list, list) {
1789 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001790 !devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001791 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001792
1793 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001794 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1795 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1796 devlink,
1797 devlink_sb,
1798 NETLINK_CB(cb->skb).portid,
1799 cb->nlh->nlmsg_seq);
Jakub Kicinski82274d02020-07-28 16:15:07 -07001800 if (err == -EOPNOTSUPP) {
1801 err = 0;
1802 } else if (err) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001803 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001804 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001805 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001806 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001807 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001808 }
1809out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001810 mutex_unlock(&devlink_mutex);
1811
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001812 if (err != -EMSGSIZE)
1813 return err;
1814
Jiri Pirkobf797472016-04-14 18:19:13 +02001815 cb->args[0] = idx;
1816 return msg->len;
1817}
1818
1819static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1820 unsigned int sb_index, u16 tc_index,
1821 enum devlink_sb_pool_type pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001822 u16 pool_index, u32 threshold,
1823 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001824
1825{
1826 const struct devlink_ops *ops = devlink_port->devlink->ops;
1827
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001828 if (ops->sb_tc_pool_bind_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001829 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1830 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001831 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001832 return -EOPNOTSUPP;
1833}
1834
1835static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1836 struct genl_info *info)
1837{
Parav Pandit637989b2020-07-22 18:57:11 +03001838 struct devlink_port *devlink_port = info->user_ptr[1];
1839 struct devlink *devlink = info->user_ptr[0];
Jiri Pirkobf797472016-04-14 18:19:13 +02001840 enum devlink_sb_pool_type pool_type;
Parav Pandit637989b2020-07-22 18:57:11 +03001841 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001842 u16 tc_index;
1843 u16 pool_index;
1844 u32 threshold;
1845 int err;
1846
Parav Pandit637989b2020-07-22 18:57:11 +03001847 devlink_sb = devlink_sb_get_from_info(devlink, info);
1848 if (IS_ERR(devlink_sb))
1849 return PTR_ERR(devlink_sb);
1850
Jiri Pirkobf797472016-04-14 18:19:13 +02001851 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1852 if (err)
1853 return err;
1854
1855 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1856 pool_type, &tc_index);
1857 if (err)
1858 return err;
1859
1860 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1861 &pool_index);
1862 if (err)
1863 return err;
1864
1865 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1866 return -EINVAL;
1867
1868 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1869 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1870 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001871 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001872}
1873
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001874static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1875 struct genl_info *info)
1876{
1877 struct devlink *devlink = info->user_ptr[0];
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001878 const struct devlink_ops *ops = devlink->ops;
Parav Pandit637989b2020-07-22 18:57:11 +03001879 struct devlink_sb *devlink_sb;
1880
1881 devlink_sb = devlink_sb_get_from_info(devlink, info);
1882 if (IS_ERR(devlink_sb))
1883 return PTR_ERR(devlink_sb);
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001884
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001885 if (ops->sb_occ_snapshot)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001886 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1887 return -EOPNOTSUPP;
1888}
1889
1890static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1891 struct genl_info *info)
1892{
1893 struct devlink *devlink = info->user_ptr[0];
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001894 const struct devlink_ops *ops = devlink->ops;
Parav Pandit637989b2020-07-22 18:57:11 +03001895 struct devlink_sb *devlink_sb;
1896
1897 devlink_sb = devlink_sb_get_from_info(devlink, info);
1898 if (IS_ERR(devlink_sb))
1899 return PTR_ERR(devlink_sb);
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001900
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001901 if (ops->sb_occ_max_clear)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001902 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1903 return -EOPNOTSUPP;
1904}
1905
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001906static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1907 enum devlink_command cmd, u32 portid,
1908 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001909{
Roi Dayan59bfde02016-11-22 23:09:57 +02001910 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001911 enum devlink_eswitch_encap_mode encap_mode;
1912 u8 inline_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001913 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001914 int err = 0;
1915 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001916
1917 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1918 if (!hdr)
1919 return -EMSGSIZE;
1920
Roi Dayan59bfde02016-11-22 23:09:57 +02001921 err = devlink_nl_put_handle(msg, devlink);
1922 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001923 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001924
Jiri Pirko4456f612017-02-09 15:54:36 +01001925 if (ops->eswitch_mode_get) {
1926 err = ops->eswitch_mode_get(devlink, &mode);
1927 if (err)
1928 goto nla_put_failure;
1929 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1930 if (err)
1931 goto nla_put_failure;
1932 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001933
1934 if (ops->eswitch_inline_mode_get) {
1935 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1936 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001937 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001938 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1939 inline_mode);
1940 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001941 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001942 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001943
Roi Dayanf43e9b02016-09-25 13:52:44 +03001944 if (ops->eswitch_encap_mode_get) {
1945 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1946 if (err)
1947 goto nla_put_failure;
1948 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1949 if (err)
1950 goto nla_put_failure;
1951 }
1952
Or Gerlitz08f4b592016-07-01 14:51:01 +03001953 genlmsg_end(msg, hdr);
1954 return 0;
1955
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001956nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001957 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001958 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001959}
1960
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001961static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1962 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001963{
1964 struct devlink *devlink = info->user_ptr[0];
Or Gerlitz08f4b592016-07-01 14:51:01 +03001965 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001966 int err;
1967
Or Gerlitz08f4b592016-07-01 14:51:01 +03001968 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1969 if (!msg)
1970 return -ENOMEM;
1971
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001972 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1973 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001974
1975 if (err) {
1976 nlmsg_free(msg);
1977 return err;
1978 }
1979
1980 return genlmsg_reply(msg, info);
1981}
1982
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001983static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1984 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001985{
1986 struct devlink *devlink = info->user_ptr[0];
1987 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001988 enum devlink_eswitch_encap_mode encap_mode;
1989 u8 inline_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001990 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001991 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001992
Roi Dayan59bfde02016-11-22 23:09:57 +02001993 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1994 if (!ops->eswitch_mode_set)
1995 return -EOPNOTSUPP;
1996 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001997 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001998 if (err)
1999 return err;
2000 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03002001
Roi Dayan59bfde02016-11-22 23:09:57 +02002002 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
2003 if (!ops->eswitch_inline_mode_set)
2004 return -EOPNOTSUPP;
2005 inline_mode = nla_get_u8(
2006 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03002007 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
2008 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02002009 if (err)
2010 return err;
2011 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03002012
2013 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
2014 if (!ops->eswitch_encap_mode_set)
2015 return -EOPNOTSUPP;
2016 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03002017 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
2018 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03002019 if (err)
2020 return err;
2021 }
2022
Roi Dayan59bfde02016-11-22 23:09:57 +02002023 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03002024}
2025
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002026int devlink_dpipe_match_put(struct sk_buff *skb,
2027 struct devlink_dpipe_match *match)
2028{
2029 struct devlink_dpipe_header *header = match->header;
2030 struct devlink_dpipe_field *field = &header->fields[match->field_id];
2031 struct nlattr *match_attr;
2032
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002033 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002034 if (!match_attr)
2035 return -EMSGSIZE;
2036
2037 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
2038 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
2039 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2040 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2041 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2042 goto nla_put_failure;
2043
2044 nla_nest_end(skb, match_attr);
2045 return 0;
2046
2047nla_put_failure:
2048 nla_nest_cancel(skb, match_attr);
2049 return -EMSGSIZE;
2050}
2051EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
2052
2053static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
2054 struct sk_buff *skb)
2055{
2056 struct nlattr *matches_attr;
2057
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002058 matches_attr = nla_nest_start_noflag(skb,
2059 DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002060 if (!matches_attr)
2061 return -EMSGSIZE;
2062
2063 if (table->table_ops->matches_dump(table->priv, skb))
2064 goto nla_put_failure;
2065
2066 nla_nest_end(skb, matches_attr);
2067 return 0;
2068
2069nla_put_failure:
2070 nla_nest_cancel(skb, matches_attr);
2071 return -EMSGSIZE;
2072}
2073
2074int devlink_dpipe_action_put(struct sk_buff *skb,
2075 struct devlink_dpipe_action *action)
2076{
2077 struct devlink_dpipe_header *header = action->header;
2078 struct devlink_dpipe_field *field = &header->fields[action->field_id];
2079 struct nlattr *action_attr;
2080
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002081 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002082 if (!action_attr)
2083 return -EMSGSIZE;
2084
2085 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
2086 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
2087 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2088 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2089 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2090 goto nla_put_failure;
2091
2092 nla_nest_end(skb, action_attr);
2093 return 0;
2094
2095nla_put_failure:
2096 nla_nest_cancel(skb, action_attr);
2097 return -EMSGSIZE;
2098}
2099EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
2100
2101static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
2102 struct sk_buff *skb)
2103{
2104 struct nlattr *actions_attr;
2105
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002106 actions_attr = nla_nest_start_noflag(skb,
2107 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002108 if (!actions_attr)
2109 return -EMSGSIZE;
2110
2111 if (table->table_ops->actions_dump(table->priv, skb))
2112 goto nla_put_failure;
2113
2114 nla_nest_end(skb, actions_attr);
2115 return 0;
2116
2117nla_put_failure:
2118 nla_nest_cancel(skb, actions_attr);
2119 return -EMSGSIZE;
2120}
2121
2122static int devlink_dpipe_table_put(struct sk_buff *skb,
2123 struct devlink_dpipe_table *table)
2124{
2125 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02002126 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002127
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02002128 table_size = table->table_ops->size_get(table->priv);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002129 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002130 if (!table_attr)
2131 return -EMSGSIZE;
2132
2133 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02002134 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002135 DEVLINK_ATTR_PAD))
2136 goto nla_put_failure;
2137 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
2138 table->counters_enabled))
2139 goto nla_put_failure;
2140
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01002141 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002142 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
2143 table->resource_id, DEVLINK_ATTR_PAD) ||
2144 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
2145 table->resource_units, DEVLINK_ATTR_PAD))
2146 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01002147 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002148 if (devlink_dpipe_matches_put(table, skb))
2149 goto nla_put_failure;
2150
2151 if (devlink_dpipe_actions_put(table, skb))
2152 goto nla_put_failure;
2153
2154 nla_nest_end(skb, table_attr);
2155 return 0;
2156
2157nla_put_failure:
2158 nla_nest_cancel(skb, table_attr);
2159 return -EMSGSIZE;
2160}
2161
2162static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
2163 struct genl_info *info)
2164{
2165 int err;
2166
2167 if (*pskb) {
2168 err = genlmsg_reply(*pskb, info);
2169 if (err)
2170 return err;
2171 }
2172 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
2173 if (!*pskb)
2174 return -ENOMEM;
2175 return 0;
2176}
2177
2178static int devlink_dpipe_tables_fill(struct genl_info *info,
2179 enum devlink_command cmd, int flags,
2180 struct list_head *dpipe_tables,
2181 const char *table_name)
2182{
2183 struct devlink *devlink = info->user_ptr[0];
2184 struct devlink_dpipe_table *table;
2185 struct nlattr *tables_attr;
2186 struct sk_buff *skb = NULL;
2187 struct nlmsghdr *nlh;
2188 bool incomplete;
2189 void *hdr;
2190 int i;
2191 int err;
2192
2193 table = list_first_entry(dpipe_tables,
2194 struct devlink_dpipe_table, list);
2195start_again:
2196 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2197 if (err)
2198 return err;
2199
2200 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2201 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002202 if (!hdr) {
2203 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002204 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002205 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002206
2207 if (devlink_nl_put_handle(skb, devlink))
2208 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002209 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002210 if (!tables_attr)
2211 goto nla_put_failure;
2212
2213 i = 0;
2214 incomplete = false;
2215 list_for_each_entry_from(table, dpipe_tables, list) {
2216 if (!table_name) {
2217 err = devlink_dpipe_table_put(skb, table);
2218 if (err) {
2219 if (!i)
2220 goto err_table_put;
2221 incomplete = true;
2222 break;
2223 }
2224 } else {
2225 if (!strcmp(table->name, table_name)) {
2226 err = devlink_dpipe_table_put(skb, table);
2227 if (err)
2228 break;
2229 }
2230 }
2231 i++;
2232 }
2233
2234 nla_nest_end(skb, tables_attr);
2235 genlmsg_end(skb, hdr);
2236 if (incomplete)
2237 goto start_again;
2238
2239send_done:
2240 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2241 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2242 if (!nlh) {
2243 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2244 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002245 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002246 goto send_done;
2247 }
2248
2249 return genlmsg_reply(skb, info);
2250
2251nla_put_failure:
2252 err = -EMSGSIZE;
2253err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002254 nlmsg_free(skb);
2255 return err;
2256}
2257
2258static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
2259 struct genl_info *info)
2260{
2261 struct devlink *devlink = info->user_ptr[0];
2262 const char *table_name = NULL;
2263
2264 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2265 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2266
2267 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
2268 &devlink->dpipe_table_list,
2269 table_name);
2270}
2271
2272static int devlink_dpipe_value_put(struct sk_buff *skb,
2273 struct devlink_dpipe_value *value)
2274{
2275 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
2276 value->value_size, value->value))
2277 return -EMSGSIZE;
2278 if (value->mask)
2279 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
2280 value->value_size, value->mask))
2281 return -EMSGSIZE;
2282 if (value->mapping_valid)
2283 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
2284 value->mapping_value))
2285 return -EMSGSIZE;
2286 return 0;
2287}
2288
2289static int devlink_dpipe_action_value_put(struct sk_buff *skb,
2290 struct devlink_dpipe_value *value)
2291{
2292 if (!value->action)
2293 return -EINVAL;
2294 if (devlink_dpipe_action_put(skb, value->action))
2295 return -EMSGSIZE;
2296 if (devlink_dpipe_value_put(skb, value))
2297 return -EMSGSIZE;
2298 return 0;
2299}
2300
2301static int devlink_dpipe_action_values_put(struct sk_buff *skb,
2302 struct devlink_dpipe_value *values,
2303 unsigned int values_count)
2304{
2305 struct nlattr *action_attr;
2306 int i;
2307 int err;
2308
2309 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002310 action_attr = nla_nest_start_noflag(skb,
2311 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002312 if (!action_attr)
2313 return -EMSGSIZE;
2314 err = devlink_dpipe_action_value_put(skb, &values[i]);
2315 if (err)
2316 goto err_action_value_put;
2317 nla_nest_end(skb, action_attr);
2318 }
2319 return 0;
2320
2321err_action_value_put:
2322 nla_nest_cancel(skb, action_attr);
2323 return err;
2324}
2325
2326static int devlink_dpipe_match_value_put(struct sk_buff *skb,
2327 struct devlink_dpipe_value *value)
2328{
2329 if (!value->match)
2330 return -EINVAL;
2331 if (devlink_dpipe_match_put(skb, value->match))
2332 return -EMSGSIZE;
2333 if (devlink_dpipe_value_put(skb, value))
2334 return -EMSGSIZE;
2335 return 0;
2336}
2337
2338static int devlink_dpipe_match_values_put(struct sk_buff *skb,
2339 struct devlink_dpipe_value *values,
2340 unsigned int values_count)
2341{
2342 struct nlattr *match_attr;
2343 int i;
2344 int err;
2345
2346 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002347 match_attr = nla_nest_start_noflag(skb,
2348 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002349 if (!match_attr)
2350 return -EMSGSIZE;
2351 err = devlink_dpipe_match_value_put(skb, &values[i]);
2352 if (err)
2353 goto err_match_value_put;
2354 nla_nest_end(skb, match_attr);
2355 }
2356 return 0;
2357
2358err_match_value_put:
2359 nla_nest_cancel(skb, match_attr);
2360 return err;
2361}
2362
2363static int devlink_dpipe_entry_put(struct sk_buff *skb,
2364 struct devlink_dpipe_entry *entry)
2365{
2366 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2367 int err;
2368
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002369 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002370 if (!entry_attr)
2371 return -EMSGSIZE;
2372
2373 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2374 DEVLINK_ATTR_PAD))
2375 goto nla_put_failure;
2376 if (entry->counter_valid)
2377 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2378 entry->counter, DEVLINK_ATTR_PAD))
2379 goto nla_put_failure;
2380
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002381 matches_attr = nla_nest_start_noflag(skb,
2382 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002383 if (!matches_attr)
2384 goto nla_put_failure;
2385
2386 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2387 entry->match_values_count);
2388 if (err) {
2389 nla_nest_cancel(skb, matches_attr);
2390 goto err_match_values_put;
2391 }
2392 nla_nest_end(skb, matches_attr);
2393
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002394 actions_attr = nla_nest_start_noflag(skb,
2395 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002396 if (!actions_attr)
2397 goto nla_put_failure;
2398
2399 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2400 entry->action_values_count);
2401 if (err) {
2402 nla_nest_cancel(skb, actions_attr);
2403 goto err_action_values_put;
2404 }
2405 nla_nest_end(skb, actions_attr);
2406
2407 nla_nest_end(skb, entry_attr);
2408 return 0;
2409
2410nla_put_failure:
2411 err = -EMSGSIZE;
2412err_match_values_put:
2413err_action_values_put:
2414 nla_nest_cancel(skb, entry_attr);
2415 return err;
2416}
2417
2418static struct devlink_dpipe_table *
2419devlink_dpipe_table_find(struct list_head *dpipe_tables,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302420 const char *table_name, struct devlink *devlink)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002421{
2422 struct devlink_dpipe_table *table;
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302423 list_for_each_entry_rcu(table, dpipe_tables, list,
2424 lockdep_is_held(&devlink->lock)) {
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002425 if (!strcmp(table->name, table_name))
2426 return table;
2427 }
2428 return NULL;
2429}
2430
2431int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2432{
2433 struct devlink *devlink;
2434 int err;
2435
2436 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2437 dump_ctx->info);
2438 if (err)
2439 return err;
2440
2441 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2442 dump_ctx->info->snd_portid,
2443 dump_ctx->info->snd_seq,
2444 &devlink_nl_family, NLM_F_MULTI,
2445 dump_ctx->cmd);
2446 if (!dump_ctx->hdr)
2447 goto nla_put_failure;
2448
2449 devlink = dump_ctx->info->user_ptr[0];
2450 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2451 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002452 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2453 DEVLINK_ATTR_DPIPE_ENTRIES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002454 if (!dump_ctx->nest)
2455 goto nla_put_failure;
2456 return 0;
2457
2458nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002459 nlmsg_free(dump_ctx->skb);
2460 return -EMSGSIZE;
2461}
2462EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2463
2464int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2465 struct devlink_dpipe_entry *entry)
2466{
2467 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2468}
2469EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2470
2471int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2472{
2473 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2474 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2475 return 0;
2476}
2477EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2478
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002479void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2480
2481{
2482 unsigned int value_count, value_index;
2483 struct devlink_dpipe_value *value;
2484
2485 value = entry->action_values;
2486 value_count = entry->action_values_count;
2487 for (value_index = 0; value_index < value_count; value_index++) {
2488 kfree(value[value_index].value);
2489 kfree(value[value_index].mask);
2490 }
2491
2492 value = entry->match_values;
2493 value_count = entry->match_values_count;
2494 for (value_index = 0; value_index < value_count; value_index++) {
2495 kfree(value[value_index].value);
2496 kfree(value[value_index].mask);
2497 }
2498}
2499EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2500
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002501static int devlink_dpipe_entries_fill(struct genl_info *info,
2502 enum devlink_command cmd, int flags,
2503 struct devlink_dpipe_table *table)
2504{
2505 struct devlink_dpipe_dump_ctx dump_ctx;
2506 struct nlmsghdr *nlh;
2507 int err;
2508
2509 dump_ctx.skb = NULL;
2510 dump_ctx.cmd = cmd;
2511 dump_ctx.info = info;
2512
2513 err = table->table_ops->entries_dump(table->priv,
2514 table->counters_enabled,
2515 &dump_ctx);
2516 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002517 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002518
2519send_done:
2520 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2521 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2522 if (!nlh) {
2523 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2524 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002525 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002526 goto send_done;
2527 }
2528 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002529}
2530
2531static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2532 struct genl_info *info)
2533{
2534 struct devlink *devlink = info->user_ptr[0];
2535 struct devlink_dpipe_table *table;
2536 const char *table_name;
2537
2538 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2539 return -EINVAL;
2540
2541 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2542 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302543 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002544 if (!table)
2545 return -EINVAL;
2546
2547 if (!table->table_ops->entries_dump)
2548 return -EINVAL;
2549
2550 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2551 0, table);
2552}
2553
2554static int devlink_dpipe_fields_put(struct sk_buff *skb,
2555 const struct devlink_dpipe_header *header)
2556{
2557 struct devlink_dpipe_field *field;
2558 struct nlattr *field_attr;
2559 int i;
2560
2561 for (i = 0; i < header->fields_count; i++) {
2562 field = &header->fields[i];
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002563 field_attr = nla_nest_start_noflag(skb,
2564 DEVLINK_ATTR_DPIPE_FIELD);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002565 if (!field_attr)
2566 return -EMSGSIZE;
2567 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2568 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2569 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2570 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2571 goto nla_put_failure;
2572 nla_nest_end(skb, field_attr);
2573 }
2574 return 0;
2575
2576nla_put_failure:
2577 nla_nest_cancel(skb, field_attr);
2578 return -EMSGSIZE;
2579}
2580
2581static int devlink_dpipe_header_put(struct sk_buff *skb,
2582 struct devlink_dpipe_header *header)
2583{
2584 struct nlattr *fields_attr, *header_attr;
2585 int err;
2586
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002587 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002588 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002589 return -EMSGSIZE;
2590
2591 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2592 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2593 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2594 goto nla_put_failure;
2595
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002596 fields_attr = nla_nest_start_noflag(skb,
2597 DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002598 if (!fields_attr)
2599 goto nla_put_failure;
2600
2601 err = devlink_dpipe_fields_put(skb, header);
2602 if (err) {
2603 nla_nest_cancel(skb, fields_attr);
2604 goto nla_put_failure;
2605 }
2606 nla_nest_end(skb, fields_attr);
2607 nla_nest_end(skb, header_attr);
2608 return 0;
2609
2610nla_put_failure:
2611 err = -EMSGSIZE;
2612 nla_nest_cancel(skb, header_attr);
2613 return err;
2614}
2615
2616static int devlink_dpipe_headers_fill(struct genl_info *info,
2617 enum devlink_command cmd, int flags,
2618 struct devlink_dpipe_headers *
2619 dpipe_headers)
2620{
2621 struct devlink *devlink = info->user_ptr[0];
2622 struct nlattr *headers_attr;
2623 struct sk_buff *skb = NULL;
2624 struct nlmsghdr *nlh;
2625 void *hdr;
2626 int i, j;
2627 int err;
2628
2629 i = 0;
2630start_again:
2631 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2632 if (err)
2633 return err;
2634
2635 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2636 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002637 if (!hdr) {
2638 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002639 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002640 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002641
2642 if (devlink_nl_put_handle(skb, devlink))
2643 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002644 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002645 if (!headers_attr)
2646 goto nla_put_failure;
2647
2648 j = 0;
2649 for (; i < dpipe_headers->headers_count; i++) {
2650 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2651 if (err) {
2652 if (!j)
2653 goto err_table_put;
2654 break;
2655 }
2656 j++;
2657 }
2658 nla_nest_end(skb, headers_attr);
2659 genlmsg_end(skb, hdr);
2660 if (i != dpipe_headers->headers_count)
2661 goto start_again;
2662
2663send_done:
2664 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2665 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2666 if (!nlh) {
2667 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2668 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002669 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002670 goto send_done;
2671 }
2672 return genlmsg_reply(skb, info);
2673
2674nla_put_failure:
2675 err = -EMSGSIZE;
2676err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002677 nlmsg_free(skb);
2678 return err;
2679}
2680
2681static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2682 struct genl_info *info)
2683{
2684 struct devlink *devlink = info->user_ptr[0];
2685
2686 if (!devlink->dpipe_headers)
2687 return -EOPNOTSUPP;
2688 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2689 0, devlink->dpipe_headers);
2690}
2691
2692static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2693 const char *table_name,
2694 bool enable)
2695{
2696 struct devlink_dpipe_table *table;
2697
2698 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302699 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002700 if (!table)
2701 return -EINVAL;
2702
2703 if (table->counter_control_extern)
2704 return -EOPNOTSUPP;
2705
2706 if (!(table->counters_enabled ^ enable))
2707 return 0;
2708
2709 table->counters_enabled = enable;
2710 if (table->table_ops->counters_set_update)
2711 table->table_ops->counters_set_update(table->priv, enable);
2712 return 0;
2713}
2714
2715static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2716 struct genl_info *info)
2717{
2718 struct devlink *devlink = info->user_ptr[0];
2719 const char *table_name;
2720 bool counters_enable;
2721
2722 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2723 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2724 return -EINVAL;
2725
2726 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2727 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2728
2729 return devlink_dpipe_table_counters_set(devlink, table_name,
2730 counters_enable);
2731}
2732
Wei Yongjun43dd7512018-01-17 03:27:42 +00002733static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002734devlink_resource_find(struct devlink *devlink,
2735 struct devlink_resource *resource, u64 resource_id)
2736{
2737 struct list_head *resource_list;
2738
2739 if (resource)
2740 resource_list = &resource->resource_list;
2741 else
2742 resource_list = &devlink->resource_list;
2743
2744 list_for_each_entry(resource, resource_list, list) {
2745 struct devlink_resource *child_resource;
2746
2747 if (resource->id == resource_id)
2748 return resource;
2749
2750 child_resource = devlink_resource_find(devlink, resource,
2751 resource_id);
2752 if (child_resource)
2753 return child_resource;
2754 }
2755 return NULL;
2756}
2757
Wei Yongjun43dd7512018-01-17 03:27:42 +00002758static void
2759devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002760{
2761 struct devlink_resource *child_resource;
2762 bool size_valid = true;
2763 u64 parts_size = 0;
2764
2765 if (list_empty(&resource->resource_list))
2766 goto out;
2767
2768 list_for_each_entry(child_resource, &resource->resource_list, list)
2769 parts_size += child_resource->size_new;
2770
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002771 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002772 size_valid = false;
2773out:
2774 resource->size_valid = size_valid;
2775}
2776
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002777static int
2778devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2779 struct netlink_ext_ack *extack)
2780{
2781 u64 reminder;
2782 int err = 0;
2783
David S. Miller0f3e9c92018-03-06 00:53:44 -05002784 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002785 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2786 err = -EINVAL;
2787 }
2788
David S. Miller0f3e9c92018-03-06 00:53:44 -05002789 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002790 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2791 err = -EINVAL;
2792 }
2793
David S. Miller0f3e9c92018-03-06 00:53:44 -05002794 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002795 if (reminder) {
2796 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2797 err = -EINVAL;
2798 }
2799
2800 return err;
2801}
2802
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002803static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2804 struct genl_info *info)
2805{
2806 struct devlink *devlink = info->user_ptr[0];
2807 struct devlink_resource *resource;
2808 u64 resource_id;
2809 u64 size;
2810 int err;
2811
2812 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2813 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2814 return -EINVAL;
2815 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2816
2817 resource = devlink_resource_find(devlink, NULL, resource_id);
2818 if (!resource)
2819 return -EINVAL;
2820
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002821 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002822 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002823 if (err)
2824 return err;
2825
2826 resource->size_new = size;
2827 devlink_resource_validate_children(resource);
2828 if (resource->parent)
2829 devlink_resource_validate_children(resource->parent);
2830 return 0;
2831}
2832
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002833static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002834devlink_resource_size_params_put(struct devlink_resource *resource,
2835 struct sk_buff *skb)
2836{
2837 struct devlink_resource_size_params *size_params;
2838
Jiri Pirko77d27092018-02-28 13:12:09 +01002839 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002840 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2841 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2842 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2843 size_params->size_max, DEVLINK_ATTR_PAD) ||
2844 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2845 size_params->size_min, DEVLINK_ATTR_PAD) ||
2846 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2847 return -EMSGSIZE;
2848 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002849}
2850
Jiri Pirkofc56be42018-04-05 22:13:21 +02002851static int devlink_resource_occ_put(struct devlink_resource *resource,
2852 struct sk_buff *skb)
2853{
2854 if (!resource->occ_get)
2855 return 0;
2856 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2857 resource->occ_get(resource->occ_get_priv),
2858 DEVLINK_ATTR_PAD);
2859}
2860
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002861static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2862 struct devlink_resource *resource)
2863{
2864 struct devlink_resource *child_resource;
2865 struct nlattr *child_resource_attr;
2866 struct nlattr *resource_attr;
2867
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002868 resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002869 if (!resource_attr)
2870 return -EMSGSIZE;
2871
2872 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2873 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2874 DEVLINK_ATTR_PAD) ||
2875 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2876 DEVLINK_ATTR_PAD))
2877 goto nla_put_failure;
2878 if (resource->size != resource->size_new)
2879 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2880 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002881 if (devlink_resource_occ_put(resource, skb))
2882 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002883 if (devlink_resource_size_params_put(resource, skb))
2884 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002885 if (list_empty(&resource->resource_list))
2886 goto out;
2887
2888 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2889 resource->size_valid))
2890 goto nla_put_failure;
2891
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002892 child_resource_attr = nla_nest_start_noflag(skb,
2893 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002894 if (!child_resource_attr)
2895 goto nla_put_failure;
2896
2897 list_for_each_entry(child_resource, &resource->resource_list, list) {
2898 if (devlink_resource_put(devlink, skb, child_resource))
2899 goto resource_put_failure;
2900 }
2901
2902 nla_nest_end(skb, child_resource_attr);
2903out:
2904 nla_nest_end(skb, resource_attr);
2905 return 0;
2906
2907resource_put_failure:
2908 nla_nest_cancel(skb, child_resource_attr);
2909nla_put_failure:
2910 nla_nest_cancel(skb, resource_attr);
2911 return -EMSGSIZE;
2912}
2913
2914static int devlink_resource_fill(struct genl_info *info,
2915 enum devlink_command cmd, int flags)
2916{
2917 struct devlink *devlink = info->user_ptr[0];
2918 struct devlink_resource *resource;
2919 struct nlattr *resources_attr;
2920 struct sk_buff *skb = NULL;
2921 struct nlmsghdr *nlh;
2922 bool incomplete;
2923 void *hdr;
2924 int i;
2925 int err;
2926
2927 resource = list_first_entry(&devlink->resource_list,
2928 struct devlink_resource, list);
2929start_again:
2930 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2931 if (err)
2932 return err;
2933
2934 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2935 &devlink_nl_family, NLM_F_MULTI, cmd);
2936 if (!hdr) {
2937 nlmsg_free(skb);
2938 return -EMSGSIZE;
2939 }
2940
2941 if (devlink_nl_put_handle(skb, devlink))
2942 goto nla_put_failure;
2943
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002944 resources_attr = nla_nest_start_noflag(skb,
2945 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002946 if (!resources_attr)
2947 goto nla_put_failure;
2948
2949 incomplete = false;
2950 i = 0;
2951 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2952 err = devlink_resource_put(devlink, skb, resource);
2953 if (err) {
2954 if (!i)
2955 goto err_resource_put;
2956 incomplete = true;
2957 break;
2958 }
2959 i++;
2960 }
2961 nla_nest_end(skb, resources_attr);
2962 genlmsg_end(skb, hdr);
2963 if (incomplete)
2964 goto start_again;
2965send_done:
2966 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2967 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2968 if (!nlh) {
2969 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2970 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002971 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002972 goto send_done;
2973 }
2974 return genlmsg_reply(skb, info);
2975
2976nla_put_failure:
2977 err = -EMSGSIZE;
2978err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002979 nlmsg_free(skb);
2980 return err;
2981}
2982
2983static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2984 struct genl_info *info)
2985{
2986 struct devlink *devlink = info->user_ptr[0];
2987
2988 if (list_empty(&devlink->resource_list))
2989 return -EOPNOTSUPP;
2990
2991 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2992}
2993
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002994static int
2995devlink_resources_validate(struct devlink *devlink,
2996 struct devlink_resource *resource,
2997 struct genl_info *info)
2998{
2999 struct list_head *resource_list;
3000 int err = 0;
3001
3002 if (resource)
3003 resource_list = &resource->resource_list;
3004 else
3005 resource_list = &devlink->resource_list;
3006
3007 list_for_each_entry(resource, resource_list, list) {
3008 if (!resource->size_valid)
3009 return -EINVAL;
3010 err = devlink_resources_validate(devlink, resource, info);
3011 if (err)
3012 return err;
3013 }
3014 return err;
3015}
3016
Jiri Pirko070c63f2019-10-03 11:49:39 +02003017static struct net *devlink_netns_get(struct sk_buff *skb,
3018 struct genl_info *info)
3019{
3020 struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID];
3021 struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD];
3022 struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID];
3023 struct net *net;
3024
3025 if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) {
Jiri Pirko054eae82020-03-28 19:25:29 +01003026 NL_SET_ERR_MSG_MOD(info->extack, "multiple netns identifying attributes specified");
Jiri Pirko070c63f2019-10-03 11:49:39 +02003027 return ERR_PTR(-EINVAL);
3028 }
3029
3030 if (netns_pid_attr) {
3031 net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr));
3032 } else if (netns_fd_attr) {
3033 net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr));
3034 } else if (netns_id_attr) {
3035 net = get_net_ns_by_id(sock_net(skb->sk),
3036 nla_get_u32(netns_id_attr));
3037 if (!net)
3038 net = ERR_PTR(-EINVAL);
3039 } else {
3040 WARN_ON(1);
3041 net = ERR_PTR(-EINVAL);
3042 }
3043 if (IS_ERR(net)) {
Jiri Pirko054eae82020-03-28 19:25:29 +01003044 NL_SET_ERR_MSG_MOD(info->extack, "Unknown network namespace");
Jiri Pirko070c63f2019-10-03 11:49:39 +02003045 return ERR_PTR(-EINVAL);
3046 }
3047 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
3048 put_net(net);
3049 return ERR_PTR(-EPERM);
3050 }
3051 return net;
3052}
3053
3054static void devlink_param_notify(struct devlink *devlink,
3055 unsigned int port_index,
3056 struct devlink_param_item *param_item,
3057 enum devlink_command cmd);
3058
3059static void devlink_reload_netns_change(struct devlink *devlink,
3060 struct net *dest_net)
3061{
3062 struct devlink_param_item *param_item;
3063
3064 /* Userspace needs to be notified about devlink objects
3065 * removed from original and entering new network namespace.
3066 * The rest of the devlink objects are re-created during
3067 * reload process so the notifications are generated separatelly.
3068 */
3069
3070 list_for_each_entry(param_item, &devlink->param_list, list)
3071 devlink_param_notify(devlink, 0, param_item,
3072 DEVLINK_CMD_PARAM_DEL);
3073 devlink_notify(devlink, DEVLINK_CMD_DEL);
3074
Jiri Pirko8273fd82019-10-05 08:10:31 +02003075 __devlink_net_set(devlink, dest_net);
Jiri Pirko070c63f2019-10-03 11:49:39 +02003076
3077 devlink_notify(devlink, DEVLINK_CMD_NEW);
3078 list_for_each_entry(param_item, &devlink->param_list, list)
3079 devlink_param_notify(devlink, 0, param_item,
3080 DEVLINK_CMD_PARAM_NEW);
3081}
3082
Moshe Shemesh69d56e02020-10-07 09:00:42 +03003083static bool devlink_reload_supported(const struct devlink_ops *ops)
Jiri Pirko97691062019-09-12 10:49:45 +02003084{
Moshe Shemesh69d56e02020-10-07 09:00:42 +03003085 return ops->reload_down && ops->reload_up;
Jiri Pirko97691062019-09-12 10:49:45 +02003086}
3087
Jiri Pirko2670ac22019-09-12 10:49:46 +02003088static void devlink_reload_failed_set(struct devlink *devlink,
3089 bool reload_failed)
3090{
3091 if (devlink->reload_failed == reload_failed)
3092 return;
3093 devlink->reload_failed = reload_failed;
3094 devlink_notify(devlink, DEVLINK_CMD_NEW);
3095}
3096
3097bool devlink_is_reload_failed(const struct devlink *devlink)
3098{
3099 return devlink->reload_failed;
3100}
3101EXPORT_SYMBOL_GPL(devlink_is_reload_failed);
3102
Moshe Shemesha254c262020-10-07 09:00:45 +03003103static void
3104__devlink_reload_stats_update(struct devlink *devlink, u32 *reload_stats,
3105 enum devlink_reload_limit limit, u32 actions_performed)
3106{
3107 unsigned long actions = actions_performed;
3108 int stat_idx;
3109 int action;
3110
3111 for_each_set_bit(action, &actions, __DEVLINK_RELOAD_ACTION_MAX) {
3112 stat_idx = limit * __DEVLINK_RELOAD_ACTION_MAX + action;
3113 reload_stats[stat_idx]++;
3114 }
3115 devlink_notify(devlink, DEVLINK_CMD_NEW);
3116}
3117
3118static void
3119devlink_reload_stats_update(struct devlink *devlink, enum devlink_reload_limit limit,
3120 u32 actions_performed)
3121{
3122 __devlink_reload_stats_update(devlink, devlink->stats.reload_stats, limit,
3123 actions_performed);
3124}
3125
Moshe Shemesh77069ba2020-10-07 09:00:46 +03003126/**
3127 * devlink_remote_reload_actions_performed - Update devlink on reload actions
3128 * performed which are not a direct result of devlink reload call.
3129 *
3130 * This should be called by a driver after performing reload actions in case it was not
3131 * a result of devlink reload call. For example fw_activate was performed as a result
3132 * of devlink reload triggered fw_activate on another host.
3133 * The motivation for this function is to keep data on reload actions performed on this
3134 * function whether it was done due to direct devlink reload call or not.
3135 *
3136 * @devlink: devlink
3137 * @limit: reload limit
3138 * @actions_performed: bitmask of actions performed
3139 */
3140void devlink_remote_reload_actions_performed(struct devlink *devlink,
3141 enum devlink_reload_limit limit,
3142 u32 actions_performed)
3143{
3144 if (WARN_ON(!actions_performed ||
3145 actions_performed & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) ||
3146 actions_performed >= BIT(__DEVLINK_RELOAD_ACTION_MAX) ||
3147 limit > DEVLINK_RELOAD_LIMIT_MAX))
3148 return;
3149
3150 __devlink_reload_stats_update(devlink, devlink->stats.remote_reload_stats, limit,
3151 actions_performed);
3152}
3153EXPORT_SYMBOL_GPL(devlink_remote_reload_actions_performed);
3154
Jiri Pirko070c63f2019-10-03 11:49:39 +02003155static int devlink_reload(struct devlink *devlink, struct net *dest_net,
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03003156 enum devlink_reload_action action, enum devlink_reload_limit limit,
3157 u32 *actions_performed, struct netlink_ext_ack *extack)
Jiri Pirko070c63f2019-10-03 11:49:39 +02003158{
Moshe Shemesh77069ba2020-10-07 09:00:46 +03003159 u32 remote_reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE];
Jiri Pirko070c63f2019-10-03 11:49:39 +02003160 int err;
3161
Jiri Pirkoa0c76342019-11-08 21:42:43 +01003162 if (!devlink->reload_enabled)
3163 return -EOPNOTSUPP;
3164
Moshe Shemesh77069ba2020-10-07 09:00:46 +03003165 memcpy(remote_reload_stats, devlink->stats.remote_reload_stats,
3166 sizeof(remote_reload_stats));
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03003167 err = devlink->ops->reload_down(devlink, !!dest_net, action, limit, extack);
Jiri Pirko070c63f2019-10-03 11:49:39 +02003168 if (err)
3169 return err;
3170
3171 if (dest_net && !net_eq(dest_net, devlink_net(devlink)))
3172 devlink_reload_netns_change(devlink, dest_net);
3173
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03003174 err = devlink->ops->reload_up(devlink, action, limit, actions_performed, extack);
Jiri Pirko070c63f2019-10-03 11:49:39 +02003175 devlink_reload_failed_set(devlink, !!err);
Moshe Shemeshccdf0722020-10-07 09:00:43 +03003176 if (err)
3177 return err;
3178
3179 WARN_ON(!(*actions_performed & BIT(action)));
Moshe Shemesh77069ba2020-10-07 09:00:46 +03003180 /* Catch driver on updating the remote action within devlink reload */
3181 WARN_ON(memcmp(remote_reload_stats, devlink->stats.remote_reload_stats,
3182 sizeof(remote_reload_stats)));
Moshe Shemesha254c262020-10-07 09:00:45 +03003183 devlink_reload_stats_update(devlink, limit, *actions_performed);
Moshe Shemeshccdf0722020-10-07 09:00:43 +03003184 return 0;
3185}
3186
3187static int
3188devlink_nl_reload_actions_performed_snd(struct devlink *devlink, u32 actions_performed,
3189 enum devlink_command cmd, struct genl_info *info)
3190{
3191 struct sk_buff *msg;
3192 void *hdr;
3193
3194 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3195 if (!msg)
3196 return -ENOMEM;
3197
3198 hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &devlink_nl_family, 0, cmd);
3199 if (!hdr)
3200 goto free_msg;
3201
3202 if (devlink_nl_put_handle(msg, devlink))
3203 goto nla_put_failure;
3204
3205 if (nla_put_bitfield32(msg, DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED, actions_performed,
3206 actions_performed))
3207 goto nla_put_failure;
3208 genlmsg_end(msg, hdr);
3209
3210 return genlmsg_reply(msg, info);
3211
3212nla_put_failure:
3213 genlmsg_cancel(msg, hdr);
3214free_msg:
3215 nlmsg_free(msg);
3216 return -EMSGSIZE;
Jiri Pirko070c63f2019-10-03 11:49:39 +02003217}
3218
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01003219static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
3220{
3221 struct devlink *devlink = info->user_ptr[0];
Moshe Shemeshccdf0722020-10-07 09:00:43 +03003222 enum devlink_reload_action action;
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03003223 enum devlink_reload_limit limit;
Jiri Pirko070c63f2019-10-03 11:49:39 +02003224 struct net *dest_net = NULL;
Moshe Shemeshccdf0722020-10-07 09:00:43 +03003225 u32 actions_performed;
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01003226 int err;
3227
Moshe Shemesh69d56e02020-10-07 09:00:42 +03003228 if (!devlink_reload_supported(devlink->ops))
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01003229 return -EOPNOTSUPP;
3230
3231 err = devlink_resources_validate(devlink, NULL, info);
3232 if (err) {
3233 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
3234 return err;
3235 }
Jiri Pirko070c63f2019-10-03 11:49:39 +02003236
3237 if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
3238 info->attrs[DEVLINK_ATTR_NETNS_FD] ||
3239 info->attrs[DEVLINK_ATTR_NETNS_ID]) {
3240 dest_net = devlink_netns_get(skb, info);
3241 if (IS_ERR(dest_net))
3242 return PTR_ERR(dest_net);
3243 }
3244
Moshe Shemeshccdf0722020-10-07 09:00:43 +03003245 if (info->attrs[DEVLINK_ATTR_RELOAD_ACTION])
3246 action = nla_get_u8(info->attrs[DEVLINK_ATTR_RELOAD_ACTION]);
3247 else
3248 action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT;
3249
3250 if (!devlink_reload_action_is_supported(devlink, action)) {
3251 NL_SET_ERR_MSG_MOD(info->extack,
3252 "Requested reload action is not supported by the driver");
3253 return -EOPNOTSUPP;
3254 }
3255
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03003256 limit = DEVLINK_RELOAD_LIMIT_UNSPEC;
3257 if (info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) {
3258 struct nla_bitfield32 limits;
3259 u32 limits_selected;
3260
3261 limits = nla_get_bitfield32(info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]);
3262 limits_selected = limits.value & limits.selector;
3263 if (!limits_selected) {
3264 NL_SET_ERR_MSG_MOD(info->extack, "Invalid limit selected");
3265 return -EINVAL;
3266 }
3267 for (limit = 0 ; limit <= DEVLINK_RELOAD_LIMIT_MAX ; limit++)
3268 if (limits_selected & BIT(limit))
3269 break;
3270 /* UAPI enables multiselection, but currently it is not used */
3271 if (limits_selected != BIT(limit)) {
3272 NL_SET_ERR_MSG_MOD(info->extack,
3273 "Multiselection of limit is not supported");
3274 return -EOPNOTSUPP;
3275 }
3276 if (!devlink_reload_limit_is_supported(devlink, limit)) {
3277 NL_SET_ERR_MSG_MOD(info->extack,
3278 "Requested limit is not supported by the driver");
3279 return -EOPNOTSUPP;
3280 }
3281 if (devlink_reload_combination_is_invalid(action, limit)) {
3282 NL_SET_ERR_MSG_MOD(info->extack,
3283 "Requested limit is invalid for this action");
3284 return -EINVAL;
3285 }
3286 }
3287 err = devlink_reload(devlink, dest_net, action, limit, &actions_performed, info->extack);
Jiri Pirko070c63f2019-10-03 11:49:39 +02003288
3289 if (dest_net)
3290 put_net(dest_net);
3291
Moshe Shemeshccdf0722020-10-07 09:00:43 +03003292 if (err)
3293 return err;
3294 /* For backward compatibility generate reply only if attributes used by user */
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03003295 if (!info->attrs[DEVLINK_ATTR_RELOAD_ACTION] && !info->attrs[DEVLINK_ATTR_RELOAD_LIMITS])
Moshe Shemeshccdf0722020-10-07 09:00:43 +03003296 return 0;
3297
3298 return devlink_nl_reload_actions_performed_snd(devlink, actions_performed,
3299 DEVLINK_CMD_RELOAD, info);
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01003300}
3301
Jiri Pirko191ed202019-06-04 15:40:40 +02003302static int devlink_nl_flash_update_fill(struct sk_buff *msg,
3303 struct devlink *devlink,
3304 enum devlink_command cmd,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003305 struct devlink_flash_notify *params)
Jiri Pirko191ed202019-06-04 15:40:40 +02003306{
3307 void *hdr;
3308
3309 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3310 if (!hdr)
3311 return -EMSGSIZE;
3312
3313 if (devlink_nl_put_handle(msg, devlink))
3314 goto nla_put_failure;
3315
3316 if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
3317 goto out;
3318
Shannon Nelson6700acc2020-09-17 18:13:24 -07003319 if (params->status_msg &&
Jiri Pirko191ed202019-06-04 15:40:40 +02003320 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003321 params->status_msg))
Jiri Pirko191ed202019-06-04 15:40:40 +02003322 goto nla_put_failure;
Shannon Nelson6700acc2020-09-17 18:13:24 -07003323 if (params->component &&
Jiri Pirko191ed202019-06-04 15:40:40 +02003324 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003325 params->component))
Jiri Pirko191ed202019-06-04 15:40:40 +02003326 goto nla_put_failure;
3327 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003328 params->done, DEVLINK_ATTR_PAD))
Jiri Pirko191ed202019-06-04 15:40:40 +02003329 goto nla_put_failure;
3330 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003331 params->total, DEVLINK_ATTR_PAD))
Jiri Pirko191ed202019-06-04 15:40:40 +02003332 goto nla_put_failure;
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003333 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003334 params->timeout, DEVLINK_ATTR_PAD))
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003335 goto nla_put_failure;
Jiri Pirko191ed202019-06-04 15:40:40 +02003336
3337out:
3338 genlmsg_end(msg, hdr);
3339 return 0;
3340
3341nla_put_failure:
3342 genlmsg_cancel(msg, hdr);
3343 return -EMSGSIZE;
3344}
3345
3346static void __devlink_flash_update_notify(struct devlink *devlink,
3347 enum devlink_command cmd,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003348 struct devlink_flash_notify *params)
Jiri Pirko191ed202019-06-04 15:40:40 +02003349{
3350 struct sk_buff *msg;
3351 int err;
3352
3353 WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
3354 cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
3355 cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
3356
3357 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3358 if (!msg)
3359 return;
3360
Shannon Nelson6700acc2020-09-17 18:13:24 -07003361 err = devlink_nl_flash_update_fill(msg, devlink, cmd, params);
Jiri Pirko191ed202019-06-04 15:40:40 +02003362 if (err)
3363 goto out_free_msg;
3364
3365 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3366 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3367 return;
3368
3369out_free_msg:
3370 nlmsg_free(msg);
3371}
3372
3373void devlink_flash_update_begin_notify(struct devlink *devlink)
3374{
Shannon Nelson6700acc2020-09-17 18:13:24 -07003375 struct devlink_flash_notify params = { 0 };
3376
Jiri Pirko191ed202019-06-04 15:40:40 +02003377 __devlink_flash_update_notify(devlink,
3378 DEVLINK_CMD_FLASH_UPDATE,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003379 &params);
Jiri Pirko191ed202019-06-04 15:40:40 +02003380}
3381EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
3382
3383void devlink_flash_update_end_notify(struct devlink *devlink)
3384{
Shannon Nelson6700acc2020-09-17 18:13:24 -07003385 struct devlink_flash_notify params = { 0 };
3386
Jiri Pirko191ed202019-06-04 15:40:40 +02003387 __devlink_flash_update_notify(devlink,
3388 DEVLINK_CMD_FLASH_UPDATE_END,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003389 &params);
Jiri Pirko191ed202019-06-04 15:40:40 +02003390}
3391EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
3392
3393void devlink_flash_update_status_notify(struct devlink *devlink,
3394 const char *status_msg,
3395 const char *component,
3396 unsigned long done,
3397 unsigned long total)
3398{
Shannon Nelson6700acc2020-09-17 18:13:24 -07003399 struct devlink_flash_notify params = {
3400 .status_msg = status_msg,
3401 .component = component,
3402 .done = done,
3403 .total = total,
3404 };
3405
Jiri Pirko191ed202019-06-04 15:40:40 +02003406 __devlink_flash_update_notify(devlink,
3407 DEVLINK_CMD_FLASH_UPDATE_STATUS,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003408 &params);
Jiri Pirko191ed202019-06-04 15:40:40 +02003409}
3410EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
3411
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003412void devlink_flash_update_timeout_notify(struct devlink *devlink,
3413 const char *status_msg,
3414 const char *component,
3415 unsigned long timeout)
3416{
Shannon Nelson6700acc2020-09-17 18:13:24 -07003417 struct devlink_flash_notify params = {
3418 .status_msg = status_msg,
3419 .component = component,
3420 .timeout = timeout,
3421 };
3422
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003423 __devlink_flash_update_notify(devlink,
3424 DEVLINK_CMD_FLASH_UPDATE_STATUS,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003425 &params);
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003426}
3427EXPORT_SYMBOL_GPL(devlink_flash_update_timeout_notify);
3428
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003429static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
3430 struct genl_info *info)
3431{
Jacob Keller5d5b4122020-09-25 13:46:07 -07003432 struct nlattr *nla_component, *nla_overwrite_mask;
Jacob Kellerbc75c052020-09-25 13:46:06 -07003433 struct devlink_flash_update_params params = {};
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003434 struct devlink *devlink = info->user_ptr[0];
Jacob Keller22ec3d22020-09-25 13:46:05 -07003435 u32 supported_params;
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003436
3437 if (!devlink->ops->flash_update)
3438 return -EOPNOTSUPP;
3439
3440 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
3441 return -EINVAL;
Jacob Keller22ec3d22020-09-25 13:46:05 -07003442
3443 supported_params = devlink->ops->supported_flash_update_params;
3444
Jacob Kellerbc75c052020-09-25 13:46:06 -07003445 params.file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003446
3447 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
Jacob Keller22ec3d22020-09-25 13:46:05 -07003448 if (nla_component) {
3449 if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT)) {
3450 NL_SET_ERR_MSG_ATTR(info->extack, nla_component,
3451 "component update is not supported by this device");
3452 return -EOPNOTSUPP;
3453 }
Jacob Kellerbc75c052020-09-25 13:46:06 -07003454 params.component = nla_data(nla_component);
Jacob Keller22ec3d22020-09-25 13:46:05 -07003455 }
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003456
Jacob Keller5d5b4122020-09-25 13:46:07 -07003457 nla_overwrite_mask = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK];
3458 if (nla_overwrite_mask) {
3459 struct nla_bitfield32 sections;
3460
3461 if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK)) {
3462 NL_SET_ERR_MSG_ATTR(info->extack, nla_overwrite_mask,
3463 "overwrite settings are not supported by this device");
3464 return -EOPNOTSUPP;
3465 }
3466 sections = nla_get_bitfield32(nla_overwrite_mask);
3467 params.overwrite_mask = sections.value & sections.selector;
3468 }
3469
Jacob Kellerbc75c052020-09-25 13:46:06 -07003470 return devlink->ops->flash_update(devlink, &params, info->extack);
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003471}
3472
Moshe Shemesh036467c2018-07-04 14:30:33 +03003473static const struct devlink_param devlink_param_generic[] = {
3474 {
3475 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
3476 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
3477 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
3478 },
3479 {
3480 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
3481 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
3482 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
3483 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03003484 {
3485 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
3486 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
3487 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
3488 },
Alex Veskerf6a698852018-07-12 15:13:17 +03003489 {
3490 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
3491 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
3492 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
3493 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05303494 {
3495 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
3496 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
3497 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
3498 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05303499 {
3500 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
3501 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
3502 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
3503 },
Vasundhara Volam16511782018-10-04 11:13:46 +05303504 {
3505 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
3506 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
3507 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
3508 },
Shalom Toledo846e9802018-12-03 07:58:59 +00003509 {
3510 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
3511 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
3512 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
3513 },
Dirk van der Merwe5bbd21d2019-09-09 00:54:18 +01003514 {
3515 .id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
3516 .name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
3517 .type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
3518 },
Michael Guralnik6c7295e2019-11-08 23:45:20 +00003519 {
3520 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
3521 .name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
3522 .type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
3523 },
Moshe Shemesh195d9de2020-10-07 09:00:53 +03003524 {
3525 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET,
3526 .name = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_NAME,
3527 .type = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_TYPE,
3528 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03003529};
Moshe Shemesheabaef12018-07-04 14:30:28 +03003530
3531static int devlink_param_generic_verify(const struct devlink_param *param)
3532{
3533 /* verify it match generic parameter by id and name */
3534 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
3535 return -EINVAL;
3536 if (strcmp(param->name, devlink_param_generic[param->id].name))
3537 return -ENOENT;
3538
3539 WARN_ON(param->type != devlink_param_generic[param->id].type);
3540
3541 return 0;
3542}
3543
3544static int devlink_param_driver_verify(const struct devlink_param *param)
3545{
3546 int i;
3547
3548 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
3549 return -EINVAL;
3550 /* verify no such name in generic params */
3551 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
3552 if (!strcmp(param->name, devlink_param_generic[i].name))
3553 return -EEXIST;
3554
3555 return 0;
3556}
3557
3558static struct devlink_param_item *
3559devlink_param_find_by_name(struct list_head *param_list,
3560 const char *param_name)
3561{
3562 struct devlink_param_item *param_item;
3563
3564 list_for_each_entry(param_item, param_list, list)
3565 if (!strcmp(param_item->param->name, param_name))
3566 return param_item;
3567 return NULL;
3568}
3569
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03003570static struct devlink_param_item *
3571devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
3572{
3573 struct devlink_param_item *param_item;
3574
3575 list_for_each_entry(param_item, param_list, list)
3576 if (param_item->param->id == param_id)
3577 return param_item;
3578 return NULL;
3579}
3580
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003581static bool
3582devlink_param_cmode_is_supported(const struct devlink_param *param,
3583 enum devlink_param_cmode cmode)
3584{
3585 return test_bit(cmode, &param->supported_cmodes);
3586}
3587
3588static int devlink_param_get(struct devlink *devlink,
3589 const struct devlink_param *param,
3590 struct devlink_param_gset_ctx *ctx)
3591{
3592 if (!param->get)
3593 return -EOPNOTSUPP;
3594 return param->get(devlink, param->id, ctx);
3595}
3596
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003597static int devlink_param_set(struct devlink *devlink,
3598 const struct devlink_param *param,
3599 struct devlink_param_gset_ctx *ctx)
3600{
3601 if (!param->set)
3602 return -EOPNOTSUPP;
3603 return param->set(devlink, param->id, ctx);
3604}
3605
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003606static int
3607devlink_param_type_to_nla_type(enum devlink_param_type param_type)
3608{
3609 switch (param_type) {
3610 case DEVLINK_PARAM_TYPE_U8:
3611 return NLA_U8;
3612 case DEVLINK_PARAM_TYPE_U16:
3613 return NLA_U16;
3614 case DEVLINK_PARAM_TYPE_U32:
3615 return NLA_U32;
3616 case DEVLINK_PARAM_TYPE_STRING:
3617 return NLA_STRING;
3618 case DEVLINK_PARAM_TYPE_BOOL:
3619 return NLA_FLAG;
3620 default:
3621 return -EINVAL;
3622 }
3623}
3624
3625static int
3626devlink_nl_param_value_fill_one(struct sk_buff *msg,
3627 enum devlink_param_type type,
3628 enum devlink_param_cmode cmode,
3629 union devlink_param_value val)
3630{
3631 struct nlattr *param_value_attr;
3632
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003633 param_value_attr = nla_nest_start_noflag(msg,
3634 DEVLINK_ATTR_PARAM_VALUE);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003635 if (!param_value_attr)
3636 goto nla_put_failure;
3637
3638 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
3639 goto value_nest_cancel;
3640
3641 switch (type) {
3642 case DEVLINK_PARAM_TYPE_U8:
3643 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
3644 goto value_nest_cancel;
3645 break;
3646 case DEVLINK_PARAM_TYPE_U16:
3647 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
3648 goto value_nest_cancel;
3649 break;
3650 case DEVLINK_PARAM_TYPE_U32:
3651 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
3652 goto value_nest_cancel;
3653 break;
3654 case DEVLINK_PARAM_TYPE_STRING:
3655 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
3656 val.vstr))
3657 goto value_nest_cancel;
3658 break;
3659 case DEVLINK_PARAM_TYPE_BOOL:
3660 if (val.vbool &&
3661 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
3662 goto value_nest_cancel;
3663 break;
3664 }
3665
3666 nla_nest_end(msg, param_value_attr);
3667 return 0;
3668
3669value_nest_cancel:
3670 nla_nest_cancel(msg, param_value_attr);
3671nla_put_failure:
3672 return -EMSGSIZE;
3673}
3674
3675static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303676 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003677 struct devlink_param_item *param_item,
3678 enum devlink_command cmd,
3679 u32 portid, u32 seq, int flags)
3680{
3681 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003682 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003683 const struct devlink_param *param = param_item->param;
3684 struct devlink_param_gset_ctx ctx;
3685 struct nlattr *param_values_list;
3686 struct nlattr *param_attr;
3687 int nla_type;
3688 void *hdr;
3689 int err;
3690 int i;
3691
3692 /* Get value from driver part to driverinit configuration mode */
3693 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3694 if (!devlink_param_cmode_is_supported(param, i))
3695 continue;
3696 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3697 if (!param_item->driverinit_value_valid)
3698 return -EOPNOTSUPP;
3699 param_value[i] = param_item->driverinit_value;
3700 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003701 if (!param_item->published)
3702 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003703 ctx.cmode = i;
3704 err = devlink_param_get(devlink, param, &ctx);
3705 if (err)
3706 return err;
3707 param_value[i] = ctx.val;
3708 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003709 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003710 }
3711
3712 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3713 if (!hdr)
3714 return -EMSGSIZE;
3715
3716 if (devlink_nl_put_handle(msg, devlink))
3717 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303718
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303719 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3720 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3721 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303722 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3723 goto genlmsg_cancel;
3724
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003725 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003726 if (!param_attr)
3727 goto genlmsg_cancel;
3728 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3729 goto param_nest_cancel;
3730 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3731 goto param_nest_cancel;
3732
3733 nla_type = devlink_param_type_to_nla_type(param->type);
3734 if (nla_type < 0)
3735 goto param_nest_cancel;
3736 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3737 goto param_nest_cancel;
3738
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003739 param_values_list = nla_nest_start_noflag(msg,
3740 DEVLINK_ATTR_PARAM_VALUES_LIST);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003741 if (!param_values_list)
3742 goto param_nest_cancel;
3743
3744 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003745 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003746 continue;
3747 err = devlink_nl_param_value_fill_one(msg, param->type,
3748 i, param_value[i]);
3749 if (err)
3750 goto values_list_nest_cancel;
3751 }
3752
3753 nla_nest_end(msg, param_values_list);
3754 nla_nest_end(msg, param_attr);
3755 genlmsg_end(msg, hdr);
3756 return 0;
3757
3758values_list_nest_cancel:
3759 nla_nest_end(msg, param_values_list);
3760param_nest_cancel:
3761 nla_nest_cancel(msg, param_attr);
3762genlmsg_cancel:
3763 genlmsg_cancel(msg, hdr);
3764 return -EMSGSIZE;
3765}
3766
Moshe Shemeshea601e12018-07-04 14:30:32 +03003767static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303768 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03003769 struct devlink_param_item *param_item,
3770 enum devlink_command cmd)
3771{
3772 struct sk_buff *msg;
3773 int err;
3774
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303775 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3776 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3777 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003778
3779 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3780 if (!msg)
3781 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303782 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3783 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003784 if (err) {
3785 nlmsg_free(msg);
3786 return;
3787 }
3788
3789 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3790 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3791}
3792
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003793static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3794 struct netlink_callback *cb)
3795{
3796 struct devlink_param_item *param_item;
3797 struct devlink *devlink;
3798 int start = cb->args[0];
3799 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003800 int err = 0;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003801
3802 mutex_lock(&devlink_mutex);
3803 list_for_each_entry(devlink, &devlink_list, list) {
3804 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3805 continue;
3806 mutex_lock(&devlink->lock);
3807 list_for_each_entry(param_item, &devlink->param_list, list) {
3808 if (idx < start) {
3809 idx++;
3810 continue;
3811 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303812 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003813 DEVLINK_CMD_PARAM_GET,
3814 NETLINK_CB(cb->skb).portid,
3815 cb->nlh->nlmsg_seq,
3816 NLM_F_MULTI);
Jakub Kicinski82274d02020-07-28 16:15:07 -07003817 if (err == -EOPNOTSUPP) {
3818 err = 0;
3819 } else if (err) {
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003820 mutex_unlock(&devlink->lock);
3821 goto out;
3822 }
3823 idx++;
3824 }
3825 mutex_unlock(&devlink->lock);
3826 }
3827out:
3828 mutex_unlock(&devlink_mutex);
3829
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003830 if (err != -EMSGSIZE)
3831 return err;
3832
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003833 cb->args[0] = idx;
3834 return msg->len;
3835}
3836
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003837static int
3838devlink_param_type_get_from_info(struct genl_info *info,
3839 enum devlink_param_type *param_type)
3840{
3841 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3842 return -EINVAL;
3843
3844 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3845 case NLA_U8:
3846 *param_type = DEVLINK_PARAM_TYPE_U8;
3847 break;
3848 case NLA_U16:
3849 *param_type = DEVLINK_PARAM_TYPE_U16;
3850 break;
3851 case NLA_U32:
3852 *param_type = DEVLINK_PARAM_TYPE_U32;
3853 break;
3854 case NLA_STRING:
3855 *param_type = DEVLINK_PARAM_TYPE_STRING;
3856 break;
3857 case NLA_FLAG:
3858 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3859 break;
3860 default:
3861 return -EINVAL;
3862 }
3863
3864 return 0;
3865}
3866
3867static int
3868devlink_param_value_get_from_info(const struct devlink_param *param,
3869 struct genl_info *info,
3870 union devlink_param_value *value)
3871{
Jakub Kicinski87509392020-03-02 21:05:11 -08003872 struct nlattr *param_data;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003873 int len;
3874
Jakub Kicinski87509392020-03-02 21:05:11 -08003875 param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
3876
3877 if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003878 return -EINVAL;
3879
3880 switch (param->type) {
3881 case DEVLINK_PARAM_TYPE_U8:
Jakub Kicinski87509392020-03-02 21:05:11 -08003882 if (nla_len(param_data) != sizeof(u8))
3883 return -EINVAL;
3884 value->vu8 = nla_get_u8(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003885 break;
3886 case DEVLINK_PARAM_TYPE_U16:
Jakub Kicinski87509392020-03-02 21:05:11 -08003887 if (nla_len(param_data) != sizeof(u16))
3888 return -EINVAL;
3889 value->vu16 = nla_get_u16(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003890 break;
3891 case DEVLINK_PARAM_TYPE_U32:
Jakub Kicinski87509392020-03-02 21:05:11 -08003892 if (nla_len(param_data) != sizeof(u32))
3893 return -EINVAL;
3894 value->vu32 = nla_get_u32(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003895 break;
3896 case DEVLINK_PARAM_TYPE_STRING:
Jakub Kicinski87509392020-03-02 21:05:11 -08003897 len = strnlen(nla_data(param_data), nla_len(param_data));
3898 if (len == nla_len(param_data) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003899 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003900 return -EINVAL;
Jakub Kicinski87509392020-03-02 21:05:11 -08003901 strcpy(value->vstr, nla_data(param_data));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003902 break;
3903 case DEVLINK_PARAM_TYPE_BOOL:
Jakub Kicinski87509392020-03-02 21:05:11 -08003904 if (param_data && nla_len(param_data))
3905 return -EINVAL;
3906 value->vbool = nla_get_flag(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003907 break;
3908 }
3909 return 0;
3910}
3911
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003912static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303913devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003914 struct genl_info *info)
3915{
3916 char *param_name;
3917
3918 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3919 return NULL;
3920
3921 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303922 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003923}
3924
3925static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3926 struct genl_info *info)
3927{
3928 struct devlink *devlink = info->user_ptr[0];
3929 struct devlink_param_item *param_item;
3930 struct sk_buff *msg;
3931 int err;
3932
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303933 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003934 if (!param_item)
3935 return -EINVAL;
3936
3937 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3938 if (!msg)
3939 return -ENOMEM;
3940
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303941 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003942 DEVLINK_CMD_PARAM_GET,
3943 info->snd_portid, info->snd_seq, 0);
3944 if (err) {
3945 nlmsg_free(msg);
3946 return err;
3947 }
3948
3949 return genlmsg_reply(msg, info);
3950}
3951
Vasundhara Volam9c548732019-01-28 18:00:22 +05303952static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303953 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303954 struct list_head *param_list,
3955 struct genl_info *info,
3956 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003957{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003958 enum devlink_param_type param_type;
3959 struct devlink_param_gset_ctx ctx;
3960 enum devlink_param_cmode cmode;
3961 struct devlink_param_item *param_item;
3962 const struct devlink_param *param;
3963 union devlink_param_value value;
3964 int err = 0;
3965
Vasundhara Volam9c548732019-01-28 18:00:22 +05303966 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003967 if (!param_item)
3968 return -EINVAL;
3969 param = param_item->param;
3970 err = devlink_param_type_get_from_info(info, &param_type);
3971 if (err)
3972 return err;
3973 if (param_type != param->type)
3974 return -EINVAL;
3975 err = devlink_param_value_get_from_info(param, info, &value);
3976 if (err)
3977 return err;
3978 if (param->validate) {
3979 err = param->validate(devlink, param->id, value, info->extack);
3980 if (err)
3981 return err;
3982 }
3983
3984 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3985 return -EINVAL;
3986 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3987 if (!devlink_param_cmode_is_supported(param, cmode))
3988 return -EOPNOTSUPP;
3989
3990 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003991 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3992 strcpy(param_item->driverinit_value.vstr, value.vstr);
3993 else
3994 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003995 param_item->driverinit_value_valid = true;
3996 } else {
3997 if (!param->set)
3998 return -EOPNOTSUPP;
3999 ctx.val = value;
4000 ctx.cmode = cmode;
4001 err = devlink_param_set(devlink, param, &ctx);
4002 if (err)
4003 return err;
4004 }
4005
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304006 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03004007 return 0;
4008}
4009
Vasundhara Volam9c548732019-01-28 18:00:22 +05304010static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
4011 struct genl_info *info)
4012{
4013 struct devlink *devlink = info->user_ptr[0];
4014
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304015 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05304016 info, DEVLINK_CMD_PARAM_NEW);
4017}
4018
Moshe Shemesheabaef12018-07-04 14:30:28 +03004019static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304020 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05304021 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304022 const struct devlink_param *param,
4023 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03004024{
4025 struct devlink_param_item *param_item;
4026
Vasundhara Volam39e61602019-01-28 18:00:20 +05304027 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03004028 return -EEXIST;
4029
4030 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
4031 WARN_ON(param->get || param->set);
4032 else
4033 WARN_ON(!param->get || !param->set);
4034
4035 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
4036 if (!param_item)
4037 return -ENOMEM;
4038 param_item->param = param;
4039
Vasundhara Volam39e61602019-01-28 18:00:20 +05304040 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304041 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03004042 return 0;
4043}
4044
4045static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304046 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05304047 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304048 const struct devlink_param *param,
4049 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03004050{
4051 struct devlink_param_item *param_item;
4052
Vasundhara Volam39e61602019-01-28 18:00:20 +05304053 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03004054 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304055 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03004056 list_del(&param_item->list);
4057 kfree(param_item);
4058}
4059
Vasundhara Volamf4601de2019-01-28 18:00:21 +05304060static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
4061 struct netlink_callback *cb)
4062{
4063 struct devlink_param_item *param_item;
4064 struct devlink_port *devlink_port;
4065 struct devlink *devlink;
4066 int start = cb->args[0];
4067 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004068 int err = 0;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05304069
4070 mutex_lock(&devlink_mutex);
4071 list_for_each_entry(devlink, &devlink_list, list) {
4072 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4073 continue;
4074 mutex_lock(&devlink->lock);
4075 list_for_each_entry(devlink_port, &devlink->port_list, list) {
4076 list_for_each_entry(param_item,
4077 &devlink_port->param_list, list) {
4078 if (idx < start) {
4079 idx++;
4080 continue;
4081 }
4082 err = devlink_nl_param_fill(msg,
4083 devlink_port->devlink,
4084 devlink_port->index, param_item,
4085 DEVLINK_CMD_PORT_PARAM_GET,
4086 NETLINK_CB(cb->skb).portid,
4087 cb->nlh->nlmsg_seq,
4088 NLM_F_MULTI);
Jakub Kicinski82274d02020-07-28 16:15:07 -07004089 if (err == -EOPNOTSUPP) {
4090 err = 0;
4091 } else if (err) {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05304092 mutex_unlock(&devlink->lock);
4093 goto out;
4094 }
4095 idx++;
4096 }
4097 }
4098 mutex_unlock(&devlink->lock);
4099 }
4100out:
4101 mutex_unlock(&devlink_mutex);
4102
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004103 if (err != -EMSGSIZE)
4104 return err;
4105
Vasundhara Volamf4601de2019-01-28 18:00:21 +05304106 cb->args[0] = idx;
4107 return msg->len;
4108}
4109
4110static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
4111 struct genl_info *info)
4112{
4113 struct devlink_port *devlink_port = info->user_ptr[0];
4114 struct devlink_param_item *param_item;
4115 struct sk_buff *msg;
4116 int err;
4117
4118 param_item = devlink_param_get_from_info(&devlink_port->param_list,
4119 info);
4120 if (!param_item)
4121 return -EINVAL;
4122
4123 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4124 if (!msg)
4125 return -ENOMEM;
4126
4127 err = devlink_nl_param_fill(msg, devlink_port->devlink,
4128 devlink_port->index, param_item,
4129 DEVLINK_CMD_PORT_PARAM_GET,
4130 info->snd_portid, info->snd_seq, 0);
4131 if (err) {
4132 nlmsg_free(msg);
4133 return err;
4134 }
4135
4136 return genlmsg_reply(msg, info);
4137}
4138
Vasundhara Volam9c548732019-01-28 18:00:22 +05304139static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
4140 struct genl_info *info)
4141{
4142 struct devlink_port *devlink_port = info->user_ptr[0];
4143
4144 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304145 devlink_port->index,
4146 &devlink_port->param_list, info,
4147 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05304148}
4149
Alex Veskera006d462018-07-12 15:13:12 +03004150static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
4151 struct devlink *devlink,
4152 struct devlink_snapshot *snapshot)
4153{
4154 struct nlattr *snap_attr;
4155 int err;
4156
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004157 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
Alex Veskera006d462018-07-12 15:13:12 +03004158 if (!snap_attr)
4159 return -EINVAL;
4160
4161 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
4162 if (err)
4163 goto nla_put_failure;
4164
4165 nla_nest_end(msg, snap_attr);
4166 return 0;
4167
4168nla_put_failure:
4169 nla_nest_cancel(msg, snap_attr);
4170 return err;
4171}
4172
4173static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
4174 struct devlink *devlink,
4175 struct devlink_region *region)
4176{
4177 struct devlink_snapshot *snapshot;
4178 struct nlattr *snapshots_attr;
4179 int err;
4180
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004181 snapshots_attr = nla_nest_start_noflag(msg,
4182 DEVLINK_ATTR_REGION_SNAPSHOTS);
Alex Veskera006d462018-07-12 15:13:12 +03004183 if (!snapshots_attr)
4184 return -EINVAL;
4185
4186 list_for_each_entry(snapshot, &region->snapshot_list, list) {
4187 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
4188 if (err)
4189 goto nla_put_failure;
4190 }
4191
4192 nla_nest_end(msg, snapshots_attr);
4193 return 0;
4194
4195nla_put_failure:
4196 nla_nest_cancel(msg, snapshots_attr);
4197 return err;
4198}
4199
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004200static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
4201 enum devlink_command cmd, u32 portid,
4202 u32 seq, int flags,
4203 struct devlink_region *region)
4204{
4205 void *hdr;
4206 int err;
4207
4208 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4209 if (!hdr)
4210 return -EMSGSIZE;
4211
4212 err = devlink_nl_put_handle(msg, devlink);
4213 if (err)
4214 goto nla_put_failure;
4215
Andrew Lunn544e7c32020-10-04 18:12:54 +02004216 if (region->port)
4217 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
4218 region->port->index))
4219 goto nla_put_failure;
4220
Jacob Kellere8937682020-03-26 11:37:08 -07004221 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004222 if (err)
4223 goto nla_put_failure;
4224
4225 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
4226 region->size,
4227 DEVLINK_ATTR_PAD);
4228 if (err)
4229 goto nla_put_failure;
4230
Alex Veskera006d462018-07-12 15:13:12 +03004231 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
4232 if (err)
4233 goto nla_put_failure;
4234
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004235 genlmsg_end(msg, hdr);
4236 return 0;
4237
4238nla_put_failure:
4239 genlmsg_cancel(msg, hdr);
4240 return err;
4241}
4242
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004243static struct sk_buff *
4244devlink_nl_region_notify_build(struct devlink_region *region,
4245 struct devlink_snapshot *snapshot,
4246 enum devlink_command cmd, u32 portid, u32 seq)
Alex Vesker866319b2018-07-12 15:13:13 +03004247{
4248 struct devlink *devlink = region->devlink;
4249 struct sk_buff *msg;
4250 void *hdr;
4251 int err;
4252
Alex Vesker866319b2018-07-12 15:13:13 +03004253
4254 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4255 if (!msg)
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004256 return ERR_PTR(-ENOMEM);
Alex Vesker866319b2018-07-12 15:13:13 +03004257
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004258 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
4259 if (!hdr) {
4260 err = -EMSGSIZE;
Alex Vesker866319b2018-07-12 15:13:13 +03004261 goto out_free_msg;
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004262 }
Alex Vesker866319b2018-07-12 15:13:13 +03004263
4264 err = devlink_nl_put_handle(msg, devlink);
4265 if (err)
4266 goto out_cancel_msg;
4267
Andrew Lunn544e7c32020-10-04 18:12:54 +02004268 if (region->port)
4269 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
4270 region->port->index))
4271 goto out_cancel_msg;
4272
Alex Vesker866319b2018-07-12 15:13:13 +03004273 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
Jacob Kellere8937682020-03-26 11:37:08 -07004274 region->ops->name);
Alex Vesker866319b2018-07-12 15:13:13 +03004275 if (err)
4276 goto out_cancel_msg;
4277
4278 if (snapshot) {
4279 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
4280 snapshot->id);
4281 if (err)
4282 goto out_cancel_msg;
4283 } else {
4284 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
4285 region->size, DEVLINK_ATTR_PAD);
4286 if (err)
4287 goto out_cancel_msg;
4288 }
4289 genlmsg_end(msg, hdr);
4290
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004291 return msg;
Alex Vesker866319b2018-07-12 15:13:13 +03004292
4293out_cancel_msg:
4294 genlmsg_cancel(msg, hdr);
4295out_free_msg:
4296 nlmsg_free(msg);
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004297 return ERR_PTR(err);
4298}
4299
4300static void devlink_nl_region_notify(struct devlink_region *region,
4301 struct devlink_snapshot *snapshot,
4302 enum devlink_command cmd)
4303{
4304 struct devlink *devlink = region->devlink;
4305 struct sk_buff *msg;
4306
4307 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
4308
4309 msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
4310 if (IS_ERR(msg))
4311 return;
4312
4313 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
4314 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
Alex Vesker866319b2018-07-12 15:13:13 +03004315}
4316
Jacob Kellercf80fae2020-03-26 11:37:11 -07004317/**
Jacob Keller12102432020-03-26 11:37:15 -07004318 * __devlink_snapshot_id_increment - Increment number of snapshots using an id
4319 * @devlink: devlink instance
4320 * @id: the snapshot id
4321 *
4322 * Track when a new snapshot begins using an id. Load the count for the
4323 * given id from the snapshot xarray, increment it, and store it back.
4324 *
4325 * Called when a new snapshot is created with the given id.
4326 *
4327 * The id *must* have been previously allocated by
4328 * devlink_region_snapshot_id_get().
4329 *
4330 * Returns 0 on success, or an error on failure.
4331 */
4332static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
4333{
4334 unsigned long count;
4335 void *p;
4336
4337 lockdep_assert_held(&devlink->lock);
4338
4339 p = xa_load(&devlink->snapshot_ids, id);
4340 if (WARN_ON(!p))
4341 return -EINVAL;
4342
4343 if (WARN_ON(!xa_is_value(p)))
4344 return -EINVAL;
4345
4346 count = xa_to_value(p);
4347 count++;
4348
4349 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4350 GFP_KERNEL));
4351}
4352
4353/**
4354 * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
4355 * @devlink: devlink instance
4356 * @id: the snapshot id
4357 *
4358 * Track when a snapshot is deleted and stops using an id. Load the count
4359 * for the given id from the snapshot xarray, decrement it, and store it
4360 * back.
4361 *
4362 * If the count reaches zero, erase this id from the xarray, freeing it
4363 * up for future re-use by devlink_region_snapshot_id_get().
4364 *
4365 * Called when a snapshot using the given id is deleted, and when the
4366 * initial allocator of the id is finished using it.
4367 */
4368static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
4369{
4370 unsigned long count;
4371 void *p;
4372
4373 lockdep_assert_held(&devlink->lock);
4374
4375 p = xa_load(&devlink->snapshot_ids, id);
4376 if (WARN_ON(!p))
4377 return;
4378
4379 if (WARN_ON(!xa_is_value(p)))
4380 return;
4381
4382 count = xa_to_value(p);
4383
4384 if (count > 1) {
4385 count--;
4386 xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4387 GFP_KERNEL);
4388 } else {
4389 /* If this was the last user, we can erase this id */
4390 xa_erase(&devlink->snapshot_ids, id);
4391 }
4392}
4393
4394/**
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004395 * __devlink_snapshot_id_insert - Insert a specific snapshot ID
4396 * @devlink: devlink instance
4397 * @id: the snapshot id
4398 *
4399 * Mark the given snapshot id as used by inserting a zero value into the
4400 * snapshot xarray.
4401 *
4402 * This must be called while holding the devlink instance lock. Unlike
4403 * devlink_snapshot_id_get, the initial reference count is zero, not one.
4404 * It is expected that the id will immediately be used before
4405 * releasing the devlink instance lock.
4406 *
4407 * Returns zero on success, or an error code if the snapshot id could not
4408 * be inserted.
4409 */
4410static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
4411{
4412 lockdep_assert_held(&devlink->lock);
4413
Andrew Lunnbd71ea62020-08-16 21:26:38 +02004414 if (xa_load(&devlink->snapshot_ids, id))
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004415 return -EEXIST;
4416
4417 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
4418 GFP_KERNEL));
4419}
4420
4421/**
Jacob Keller70001082020-03-26 11:37:13 -07004422 * __devlink_region_snapshot_id_get - get snapshot ID
4423 * @devlink: devlink instance
Jacob Keller7ef19d32020-03-26 11:37:14 -07004424 * @id: storage to return snapshot id
Jacob Keller70001082020-03-26 11:37:13 -07004425 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07004426 * Allocates a new snapshot id. Returns zero on success, or a negative
4427 * error on failure. Must be called while holding the devlink instance
4428 * lock.
Jacob Keller12102432020-03-26 11:37:15 -07004429 *
4430 * Snapshot IDs are tracked using an xarray which stores the number of
4431 * users of the snapshot id.
4432 *
4433 * Note that the caller of this function counts as a 'user', in order to
4434 * avoid race conditions. The caller must release its hold on the
4435 * snapshot by using devlink_region_snapshot_id_put.
Jacob Keller70001082020-03-26 11:37:13 -07004436 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07004437static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Jacob Keller70001082020-03-26 11:37:13 -07004438{
4439 lockdep_assert_held(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07004440
Jacob Keller12102432020-03-26 11:37:15 -07004441 return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
4442 xa_limit_32b, GFP_KERNEL);
Jacob Keller70001082020-03-26 11:37:13 -07004443}
4444
4445/**
Jacob Kellercf80fae2020-03-26 11:37:11 -07004446 * __devlink_region_snapshot_create - create a new snapshot
4447 * This will add a new snapshot of a region. The snapshot
4448 * will be stored on the region struct and can be accessed
4449 * from devlink. This is useful for future analyses of snapshots.
4450 * Multiple snapshots can be created on a region.
4451 * The @snapshot_id should be obtained using the getter function.
4452 *
4453 * Must be called only while holding the devlink instance lock.
4454 *
4455 * @region: devlink region of the snapshot
4456 * @data: snapshot data
4457 * @snapshot_id: snapshot id to be created
4458 */
4459static int
4460__devlink_region_snapshot_create(struct devlink_region *region,
4461 u8 *data, u32 snapshot_id)
4462{
4463 struct devlink *devlink = region->devlink;
4464 struct devlink_snapshot *snapshot;
Jacob Keller12102432020-03-26 11:37:15 -07004465 int err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004466
4467 lockdep_assert_held(&devlink->lock);
4468
4469 /* check if region can hold one more snapshot */
4470 if (region->cur_snapshots == region->max_snapshots)
Jacob Keller47a39f62020-03-26 11:37:12 -07004471 return -ENOSPC;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004472
4473 if (devlink_region_snapshot_get_by_id(region, snapshot_id))
4474 return -EEXIST;
4475
4476 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
4477 if (!snapshot)
4478 return -ENOMEM;
4479
Jacob Keller12102432020-03-26 11:37:15 -07004480 err = __devlink_snapshot_id_increment(devlink, snapshot_id);
4481 if (err)
4482 goto err_snapshot_id_increment;
4483
Jacob Kellercf80fae2020-03-26 11:37:11 -07004484 snapshot->id = snapshot_id;
4485 snapshot->region = region;
4486 snapshot->data = data;
4487
4488 list_add_tail(&snapshot->list, &region->snapshot_list);
4489
4490 region->cur_snapshots++;
4491
4492 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
4493 return 0;
Jacob Keller12102432020-03-26 11:37:15 -07004494
4495err_snapshot_id_increment:
4496 kfree(snapshot);
4497 return err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004498}
4499
Jiri Pirko92b49822019-08-12 14:28:31 +02004500static void devlink_region_snapshot_del(struct devlink_region *region,
4501 struct devlink_snapshot *snapshot)
4502{
Jacob Keller12102432020-03-26 11:37:15 -07004503 struct devlink *devlink = region->devlink;
4504
4505 lockdep_assert_held(&devlink->lock);
4506
Jiri Pirko92b49822019-08-12 14:28:31 +02004507 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
4508 region->cur_snapshots--;
4509 list_del(&snapshot->list);
Jacob Kellera0a09f62020-03-26 11:37:09 -07004510 region->ops->destructor(snapshot->data);
Jacob Keller12102432020-03-26 11:37:15 -07004511 __devlink_snapshot_id_decrement(devlink, snapshot->id);
Jiri Pirko92b49822019-08-12 14:28:31 +02004512 kfree(snapshot);
4513}
4514
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004515static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
4516 struct genl_info *info)
4517{
4518 struct devlink *devlink = info->user_ptr[0];
Andrew Lunn544e7c32020-10-04 18:12:54 +02004519 struct devlink_port *port = NULL;
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004520 struct devlink_region *region;
4521 const char *region_name;
4522 struct sk_buff *msg;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004523 unsigned int index;
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004524 int err;
4525
4526 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
4527 return -EINVAL;
4528
Andrew Lunn544e7c32020-10-04 18:12:54 +02004529 if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4530 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4531
4532 port = devlink_port_get_by_index(devlink, index);
4533 if (!port)
4534 return -ENODEV;
4535 }
4536
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004537 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
Andrew Lunn544e7c32020-10-04 18:12:54 +02004538 if (port)
4539 region = devlink_port_region_get_by_name(port, region_name);
4540 else
4541 region = devlink_region_get_by_name(devlink, region_name);
4542
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004543 if (!region)
4544 return -EINVAL;
4545
4546 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4547 if (!msg)
4548 return -ENOMEM;
4549
4550 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
4551 info->snd_portid, info->snd_seq, 0,
4552 region);
4553 if (err) {
4554 nlmsg_free(msg);
4555 return err;
4556 }
4557
4558 return genlmsg_reply(msg, info);
4559}
4560
Andrew Lunn544e7c32020-10-04 18:12:54 +02004561static int devlink_nl_cmd_region_get_port_dumpit(struct sk_buff *msg,
4562 struct netlink_callback *cb,
4563 struct devlink_port *port,
4564 int *idx,
4565 int start)
4566{
4567 struct devlink_region *region;
4568 int err = 0;
4569
4570 list_for_each_entry(region, &port->region_list, list) {
4571 if (*idx < start) {
4572 (*idx)++;
4573 continue;
4574 }
4575 err = devlink_nl_region_fill(msg, port->devlink,
4576 DEVLINK_CMD_REGION_GET,
4577 NETLINK_CB(cb->skb).portid,
4578 cb->nlh->nlmsg_seq,
4579 NLM_F_MULTI, region);
4580 if (err)
4581 goto out;
4582 (*idx)++;
4583 }
4584
4585out:
4586 return err;
4587}
4588
4589static int devlink_nl_cmd_region_get_devlink_dumpit(struct sk_buff *msg,
4590 struct netlink_callback *cb,
4591 struct devlink *devlink,
4592 int *idx,
4593 int start)
4594{
4595 struct devlink_region *region;
4596 struct devlink_port *port;
4597 int err = 0;
4598
4599 mutex_lock(&devlink->lock);
4600 list_for_each_entry(region, &devlink->region_list, list) {
4601 if (*idx < start) {
4602 (*idx)++;
4603 continue;
4604 }
4605 err = devlink_nl_region_fill(msg, devlink,
4606 DEVLINK_CMD_REGION_GET,
4607 NETLINK_CB(cb->skb).portid,
4608 cb->nlh->nlmsg_seq,
4609 NLM_F_MULTI, region);
4610 if (err)
4611 goto out;
4612 (*idx)++;
4613 }
4614
4615 list_for_each_entry(port, &devlink->port_list, list) {
4616 err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, idx,
4617 start);
4618 if (err)
4619 goto out;
4620 }
4621
4622out:
4623 mutex_unlock(&devlink->lock);
4624 return err;
4625}
4626
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004627static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
4628 struct netlink_callback *cb)
4629{
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004630 struct devlink *devlink;
4631 int start = cb->args[0];
4632 int idx = 0;
4633 int err;
4634
4635 mutex_lock(&devlink_mutex);
4636 list_for_each_entry(devlink, &devlink_list, list) {
4637 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4638 continue;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004639 err = devlink_nl_cmd_region_get_devlink_dumpit(msg, cb, devlink,
4640 &idx, start);
4641 if (err)
4642 goto out;
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004643 }
4644out:
4645 mutex_unlock(&devlink_mutex);
4646 cb->args[0] = idx;
4647 return msg->len;
4648}
4649
Alex Vesker866319b2018-07-12 15:13:13 +03004650static int devlink_nl_cmd_region_del(struct sk_buff *skb,
4651 struct genl_info *info)
4652{
4653 struct devlink *devlink = info->user_ptr[0];
4654 struct devlink_snapshot *snapshot;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004655 struct devlink_port *port = NULL;
Alex Vesker866319b2018-07-12 15:13:13 +03004656 struct devlink_region *region;
4657 const char *region_name;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004658 unsigned int index;
Alex Vesker866319b2018-07-12 15:13:13 +03004659 u32 snapshot_id;
4660
4661 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
4662 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
4663 return -EINVAL;
4664
4665 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4666 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4667
Andrew Lunn544e7c32020-10-04 18:12:54 +02004668 if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4669 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4670
4671 port = devlink_port_get_by_index(devlink, index);
4672 if (!port)
4673 return -ENODEV;
4674 }
4675
4676 if (port)
4677 region = devlink_port_region_get_by_name(port, region_name);
4678 else
4679 region = devlink_region_get_by_name(devlink, region_name);
4680
Alex Vesker866319b2018-07-12 15:13:13 +03004681 if (!region)
4682 return -EINVAL;
4683
4684 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4685 if (!snapshot)
4686 return -EINVAL;
4687
Jiri Pirko92b49822019-08-12 14:28:31 +02004688 devlink_region_snapshot_del(region, snapshot);
Alex Vesker866319b2018-07-12 15:13:13 +03004689 return 0;
4690}
4691
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004692static int
4693devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
4694{
4695 struct devlink *devlink = info->user_ptr[0];
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004696 struct devlink_snapshot *snapshot;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004697 struct devlink_port *port = NULL;
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004698 struct nlattr *snapshot_id_attr;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004699 struct devlink_region *region;
4700 const char *region_name;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004701 unsigned int index;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004702 u32 snapshot_id;
4703 u8 *data;
4704 int err;
4705
4706 if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) {
4707 NL_SET_ERR_MSG_MOD(info->extack, "No region name provided");
4708 return -EINVAL;
4709 }
4710
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004711 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
Andrew Lunn544e7c32020-10-04 18:12:54 +02004712
4713 if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4714 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4715
4716 port = devlink_port_get_by_index(devlink, index);
4717 if (!port)
4718 return -ENODEV;
4719 }
4720
4721 if (port)
4722 region = devlink_port_region_get_by_name(port, region_name);
4723 else
4724 region = devlink_region_get_by_name(devlink, region_name);
4725
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004726 if (!region) {
4727 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist");
4728 return -EINVAL;
4729 }
4730
4731 if (!region->ops->snapshot) {
4732 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not support taking an immediate snapshot");
4733 return -EOPNOTSUPP;
4734 }
4735
4736 if (region->cur_snapshots == region->max_snapshots) {
4737 NL_SET_ERR_MSG_MOD(info->extack, "The region has reached the maximum number of stored snapshots");
4738 return -ENOSPC;
4739 }
4740
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004741 snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
4742 if (snapshot_id_attr) {
4743 snapshot_id = nla_get_u32(snapshot_id_attr);
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004744
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004745 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
4746 NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
4747 return -EEXIST;
4748 }
4749
4750 err = __devlink_snapshot_id_insert(devlink, snapshot_id);
4751 if (err)
4752 return err;
4753 } else {
4754 err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
4755 if (err) {
4756 NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
4757 return err;
4758 }
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004759 }
4760
Andrew Lunn544e7c32020-10-04 18:12:54 +02004761 if (port)
4762 err = region->port_ops->snapshot(port, region->port_ops,
4763 info->extack, &data);
4764 else
4765 err = region->ops->snapshot(devlink, region->ops,
4766 info->extack, &data);
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004767 if (err)
4768 goto err_snapshot_capture;
4769
4770 err = __devlink_region_snapshot_create(region, data, snapshot_id);
4771 if (err)
4772 goto err_snapshot_create;
4773
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004774 if (!snapshot_id_attr) {
4775 struct sk_buff *msg;
4776
4777 snapshot = devlink_region_snapshot_get_by_id(region,
4778 snapshot_id);
4779 if (WARN_ON(!snapshot))
4780 return -EINVAL;
4781
4782 msg = devlink_nl_region_notify_build(region, snapshot,
4783 DEVLINK_CMD_REGION_NEW,
4784 info->snd_portid,
4785 info->snd_seq);
4786 err = PTR_ERR_OR_ZERO(msg);
4787 if (err)
4788 goto err_notify;
4789
4790 err = genlmsg_reply(msg, info);
4791 if (err)
4792 goto err_notify;
4793 }
4794
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004795 return 0;
4796
4797err_snapshot_create:
4798 region->ops->destructor(data);
4799err_snapshot_capture:
4800 __devlink_snapshot_id_decrement(devlink, snapshot_id);
4801 return err;
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004802
4803err_notify:
4804 devlink_region_snapshot_del(region, snapshot);
4805 return err;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004806}
4807
Alex Vesker4e547952018-07-12 15:13:14 +03004808static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
4809 struct devlink *devlink,
4810 u8 *chunk, u32 chunk_size,
4811 u64 addr)
4812{
4813 struct nlattr *chunk_attr;
4814 int err;
4815
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004816 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
Alex Vesker4e547952018-07-12 15:13:14 +03004817 if (!chunk_attr)
4818 return -EINVAL;
4819
4820 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
4821 if (err)
4822 goto nla_put_failure;
4823
4824 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
4825 DEVLINK_ATTR_PAD);
4826 if (err)
4827 goto nla_put_failure;
4828
4829 nla_nest_end(msg, chunk_attr);
4830 return 0;
4831
4832nla_put_failure:
4833 nla_nest_cancel(msg, chunk_attr);
4834 return err;
4835}
4836
4837#define DEVLINK_REGION_READ_CHUNK_SIZE 256
4838
4839static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
4840 struct devlink *devlink,
4841 struct devlink_region *region,
4842 struct nlattr **attrs,
4843 u64 start_offset,
4844 u64 end_offset,
Alex Vesker4e547952018-07-12 15:13:14 +03004845 u64 *new_offset)
4846{
4847 struct devlink_snapshot *snapshot;
4848 u64 curr_offset = start_offset;
4849 u32 snapshot_id;
4850 int err = 0;
4851
4852 *new_offset = start_offset;
4853
4854 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4855 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4856 if (!snapshot)
4857 return -EINVAL;
4858
Alex Vesker4e547952018-07-12 15:13:14 +03004859 while (curr_offset < end_offset) {
4860 u32 data_size;
4861 u8 *data;
4862
4863 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
4864 data_size = end_offset - curr_offset;
4865 else
4866 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
4867
4868 data = &snapshot->data[curr_offset];
4869 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
4870 data, data_size,
4871 curr_offset);
4872 if (err)
4873 break;
4874
4875 curr_offset += data_size;
4876 }
4877 *new_offset = curr_offset;
4878
4879 return err;
4880}
4881
4882static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
4883 struct netlink_callback *cb)
4884{
Jiri Pirkoee85da52019-10-05 20:04:42 +02004885 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004886 u64 ret_offset, start_offset, end_offset = U64_MAX;
Jiri Pirkoee85da52019-10-05 20:04:42 +02004887 struct nlattr **attrs = info->attrs;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004888 struct devlink_port *port = NULL;
Alex Vesker4e547952018-07-12 15:13:14 +03004889 struct devlink_region *region;
4890 struct nlattr *chunks_attr;
4891 const char *region_name;
4892 struct devlink *devlink;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004893 unsigned int index;
Alex Vesker4e547952018-07-12 15:13:14 +03004894 void *hdr;
4895 int err;
4896
4897 start_offset = *((u64 *)&cb->args[0]);
4898
Parav Panditdac7c082019-02-12 14:24:08 -06004899 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03004900 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004901 if (IS_ERR(devlink)) {
4902 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06004903 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004904 }
Alex Vesker4e547952018-07-12 15:13:14 +03004905
Alex Vesker4e547952018-07-12 15:13:14 +03004906 mutex_lock(&devlink->lock);
4907
4908 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06004909 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
4910 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004911 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004912 }
Alex Vesker4e547952018-07-12 15:13:14 +03004913
Andrew Lunn544e7c32020-10-04 18:12:54 +02004914 if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4915 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4916
4917 port = devlink_port_get_by_index(devlink, index);
4918 if (!port)
4919 return -ENODEV;
4920 }
4921
Alex Vesker4e547952018-07-12 15:13:14 +03004922 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
Andrew Lunn544e7c32020-10-04 18:12:54 +02004923
4924 if (port)
4925 region = devlink_port_region_get_by_name(port, region_name);
4926 else
4927 region = devlink_region_get_by_name(devlink, region_name);
4928
Parav Panditfdd41ec2019-02-12 14:23:58 -06004929 if (!region) {
4930 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004931 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004932 }
Alex Vesker4e547952018-07-12 15:13:14 +03004933
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004934 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
4935 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
4936 if (!start_offset)
4937 start_offset =
4938 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4939
4940 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4941 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
4942 }
4943
4944 if (end_offset > region->size)
4945 end_offset = region->size;
4946
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004947 /* return 0 if there is no further data to read */
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004948 if (start_offset == end_offset) {
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004949 err = 0;
4950 goto out_unlock;
4951 }
4952
Alex Vesker4e547952018-07-12 15:13:14 +03004953 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4954 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
4955 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004956 if (!hdr) {
4957 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004958 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004959 }
Alex Vesker4e547952018-07-12 15:13:14 +03004960
4961 err = devlink_nl_put_handle(skb, devlink);
4962 if (err)
4963 goto nla_put_failure;
4964
Andrew Lunn544e7c32020-10-04 18:12:54 +02004965 if (region->port)
4966 if (nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX,
4967 region->port->index))
4968 goto nla_put_failure;
4969
Alex Vesker4e547952018-07-12 15:13:14 +03004970 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
4971 if (err)
4972 goto nla_put_failure;
4973
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004974 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004975 if (!chunks_attr) {
4976 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004977 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004978 }
Alex Vesker4e547952018-07-12 15:13:14 +03004979
Alex Vesker4e547952018-07-12 15:13:14 +03004980 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
4981 region, attrs,
4982 start_offset,
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004983 end_offset, &ret_offset);
Alex Vesker4e547952018-07-12 15:13:14 +03004984
4985 if (err && err != -EMSGSIZE)
4986 goto nla_put_failure;
4987
4988 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06004989 if (ret_offset == start_offset) {
4990 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004991 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004992 }
Alex Vesker4e547952018-07-12 15:13:14 +03004993
4994 *((u64 *)&cb->args[0]) = ret_offset;
4995
4996 nla_nest_end(skb, chunks_attr);
4997 genlmsg_end(skb, hdr);
4998 mutex_unlock(&devlink->lock);
4999 mutex_unlock(&devlink_mutex);
5000
5001 return skb->len;
5002
5003nla_put_failure:
5004 genlmsg_cancel(skb, hdr);
5005out_unlock:
5006 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06005007out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03005008 mutex_unlock(&devlink_mutex);
Parav Panditfdd41ec2019-02-12 14:23:58 -06005009 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03005010}
5011
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005012struct devlink_info_req {
5013 struct sk_buff *msg;
5014};
5015
5016int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
5017{
5018 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
5019}
5020EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
5021
5022int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
5023{
5024 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
5025}
5026EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
5027
Vasundhara Volamb5872cd2020-06-20 22:01:56 +05305028int devlink_info_board_serial_number_put(struct devlink_info_req *req,
5029 const char *bsn)
5030{
5031 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER,
5032 bsn);
5033}
5034EXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put);
5035
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08005036static int devlink_info_version_put(struct devlink_info_req *req, int attr,
5037 const char *version_name,
5038 const char *version_value)
5039{
5040 struct nlattr *nest;
5041 int err;
5042
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005043 nest = nla_nest_start_noflag(req->msg, attr);
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08005044 if (!nest)
5045 return -EMSGSIZE;
5046
5047 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
5048 version_name);
5049 if (err)
5050 goto nla_put_failure;
5051
5052 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
5053 version_value);
5054 if (err)
5055 goto nla_put_failure;
5056
5057 nla_nest_end(req->msg, nest);
5058
5059 return 0;
5060
5061nla_put_failure:
5062 nla_nest_cancel(req->msg, nest);
5063 return err;
5064}
5065
5066int devlink_info_version_fixed_put(struct devlink_info_req *req,
5067 const char *version_name,
5068 const char *version_value)
5069{
5070 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
5071 version_name, version_value);
5072}
5073EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
5074
5075int devlink_info_version_stored_put(struct devlink_info_req *req,
5076 const char *version_name,
5077 const char *version_value)
5078{
5079 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
5080 version_name, version_value);
5081}
5082EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
5083
5084int devlink_info_version_running_put(struct devlink_info_req *req,
5085 const char *version_name,
5086 const char *version_value)
5087{
5088 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
5089 version_name, version_value);
5090}
5091EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
5092
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005093static int
5094devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
5095 enum devlink_command cmd, u32 portid,
5096 u32 seq, int flags, struct netlink_ext_ack *extack)
5097{
5098 struct devlink_info_req req;
5099 void *hdr;
5100 int err;
5101
5102 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5103 if (!hdr)
5104 return -EMSGSIZE;
5105
5106 err = -EMSGSIZE;
5107 if (devlink_nl_put_handle(msg, devlink))
5108 goto err_cancel_msg;
5109
5110 req.msg = msg;
5111 err = devlink->ops->info_get(devlink, &req, extack);
5112 if (err)
5113 goto err_cancel_msg;
5114
5115 genlmsg_end(msg, hdr);
5116 return 0;
5117
5118err_cancel_msg:
5119 genlmsg_cancel(msg, hdr);
5120 return err;
5121}
5122
5123static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
5124 struct genl_info *info)
5125{
5126 struct devlink *devlink = info->user_ptr[0];
5127 struct sk_buff *msg;
5128 int err;
5129
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08005130 if (!devlink->ops->info_get)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005131 return -EOPNOTSUPP;
5132
5133 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5134 if (!msg)
5135 return -ENOMEM;
5136
5137 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
5138 info->snd_portid, info->snd_seq, 0,
5139 info->extack);
5140 if (err) {
5141 nlmsg_free(msg);
5142 return err;
5143 }
5144
5145 return genlmsg_reply(msg, info);
5146}
5147
5148static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
5149 struct netlink_callback *cb)
5150{
5151 struct devlink *devlink;
5152 int start = cb->args[0];
5153 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02005154 int err = 0;
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005155
5156 mutex_lock(&devlink_mutex);
5157 list_for_each_entry(devlink, &devlink_list, list) {
5158 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5159 continue;
5160 if (idx < start) {
5161 idx++;
5162 continue;
5163 }
5164
Jiri Pirkoc493b09b2019-03-24 00:21:03 +01005165 if (!devlink->ops->info_get) {
5166 idx++;
5167 continue;
5168 }
5169
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005170 mutex_lock(&devlink->lock);
5171 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
5172 NETLINK_CB(cb->skb).portid,
5173 cb->nlh->nlmsg_seq, NLM_F_MULTI,
5174 cb->extack);
5175 mutex_unlock(&devlink->lock);
Jakub Kicinski82274d02020-07-28 16:15:07 -07005176 if (err == -EOPNOTSUPP)
5177 err = 0;
5178 else if (err)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005179 break;
5180 idx++;
5181 }
5182 mutex_unlock(&devlink_mutex);
5183
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02005184 if (err != -EMSGSIZE)
5185 return err;
5186
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005187 cb->args[0] = idx;
5188 return msg->len;
5189}
5190
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005191struct devlink_fmsg_item {
5192 struct list_head list;
5193 int attrtype;
5194 u8 nla_type;
5195 u16 len;
Gustavo A. R. Silvad2afb412020-02-28 07:43:24 -06005196 int value[];
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005197};
5198
5199struct devlink_fmsg {
5200 struct list_head item_list;
Aya Levin573ed902020-02-11 14:32:42 -08005201 bool putting_binary; /* This flag forces enclosing of binary data
5202 * in an array brackets. It forces using
5203 * of designated API:
5204 * devlink_fmsg_binary_pair_nest_start()
5205 * devlink_fmsg_binary_pair_nest_end()
5206 */
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005207};
5208
5209static struct devlink_fmsg *devlink_fmsg_alloc(void)
5210{
5211 struct devlink_fmsg *fmsg;
5212
5213 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
5214 if (!fmsg)
5215 return NULL;
5216
5217 INIT_LIST_HEAD(&fmsg->item_list);
5218
5219 return fmsg;
5220}
5221
5222static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
5223{
5224 struct devlink_fmsg_item *item, *tmp;
5225
5226 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
5227 list_del(&item->list);
5228 kfree(item);
5229 }
5230 kfree(fmsg);
5231}
5232
5233static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
5234 int attrtype)
5235{
5236 struct devlink_fmsg_item *item;
5237
5238 item = kzalloc(sizeof(*item), GFP_KERNEL);
5239 if (!item)
5240 return -ENOMEM;
5241
5242 item->attrtype = attrtype;
5243 list_add_tail(&item->list, &fmsg->item_list);
5244
5245 return 0;
5246}
5247
5248int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
5249{
Aya Levin573ed902020-02-11 14:32:42 -08005250 if (fmsg->putting_binary)
5251 return -EINVAL;
5252
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005253 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
5254}
5255EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
5256
5257static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
5258{
Aya Levin573ed902020-02-11 14:32:42 -08005259 if (fmsg->putting_binary)
5260 return -EINVAL;
5261
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005262 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
5263}
5264
5265int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
5266{
Aya Levin573ed902020-02-11 14:32:42 -08005267 if (fmsg->putting_binary)
5268 return -EINVAL;
5269
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005270 return devlink_fmsg_nest_end(fmsg);
5271}
5272EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
5273
5274#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
5275
5276static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
5277{
5278 struct devlink_fmsg_item *item;
5279
Aya Levin573ed902020-02-11 14:32:42 -08005280 if (fmsg->putting_binary)
5281 return -EINVAL;
5282
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005283 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
5284 return -EMSGSIZE;
5285
5286 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
5287 if (!item)
5288 return -ENOMEM;
5289
5290 item->nla_type = NLA_NUL_STRING;
5291 item->len = strlen(name) + 1;
5292 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
5293 memcpy(&item->value, name, item->len);
5294 list_add_tail(&item->list, &fmsg->item_list);
5295
5296 return 0;
5297}
5298
5299int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
5300{
5301 int err;
5302
Aya Levin573ed902020-02-11 14:32:42 -08005303 if (fmsg->putting_binary)
5304 return -EINVAL;
5305
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005306 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
5307 if (err)
5308 return err;
5309
5310 err = devlink_fmsg_put_name(fmsg, name);
5311 if (err)
5312 return err;
5313
5314 return 0;
5315}
5316EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
5317
5318int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
5319{
Aya Levin573ed902020-02-11 14:32:42 -08005320 if (fmsg->putting_binary)
5321 return -EINVAL;
5322
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005323 return devlink_fmsg_nest_end(fmsg);
5324}
5325EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
5326
5327int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
5328 const char *name)
5329{
5330 int err;
5331
Aya Levin573ed902020-02-11 14:32:42 -08005332 if (fmsg->putting_binary)
5333 return -EINVAL;
5334
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005335 err = devlink_fmsg_pair_nest_start(fmsg, name);
5336 if (err)
5337 return err;
5338
5339 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
5340 if (err)
5341 return err;
5342
5343 return 0;
5344}
5345EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
5346
5347int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
5348{
5349 int err;
5350
Aya Levin573ed902020-02-11 14:32:42 -08005351 if (fmsg->putting_binary)
5352 return -EINVAL;
5353
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005354 err = devlink_fmsg_nest_end(fmsg);
5355 if (err)
5356 return err;
5357
5358 err = devlink_fmsg_nest_end(fmsg);
5359 if (err)
5360 return err;
5361
5362 return 0;
5363}
5364EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
5365
Aya Levin573ed902020-02-11 14:32:42 -08005366int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
5367 const char *name)
5368{
5369 int err;
5370
5371 err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
5372 if (err)
5373 return err;
5374
5375 fmsg->putting_binary = true;
5376 return err;
5377}
5378EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
5379
5380int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
5381{
5382 if (!fmsg->putting_binary)
5383 return -EINVAL;
5384
5385 fmsg->putting_binary = false;
5386 return devlink_fmsg_arr_pair_nest_end(fmsg);
5387}
5388EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
5389
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005390static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
5391 const void *value, u16 value_len,
5392 u8 value_nla_type)
5393{
5394 struct devlink_fmsg_item *item;
5395
5396 if (value_len > DEVLINK_FMSG_MAX_SIZE)
5397 return -EMSGSIZE;
5398
5399 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
5400 if (!item)
5401 return -ENOMEM;
5402
5403 item->nla_type = value_nla_type;
5404 item->len = value_len;
5405 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5406 memcpy(&item->value, value, item->len);
5407 list_add_tail(&item->list, &fmsg->item_list);
5408
5409 return 0;
5410}
5411
5412int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
5413{
Aya Levin573ed902020-02-11 14:32:42 -08005414 if (fmsg->putting_binary)
5415 return -EINVAL;
5416
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005417 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
5418}
5419EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
5420
5421int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
5422{
Aya Levin573ed902020-02-11 14:32:42 -08005423 if (fmsg->putting_binary)
5424 return -EINVAL;
5425
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005426 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
5427}
5428EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
5429
5430int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
5431{
Aya Levin573ed902020-02-11 14:32:42 -08005432 if (fmsg->putting_binary)
5433 return -EINVAL;
5434
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005435 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
5436}
5437EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
5438
5439int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
5440{
Aya Levin573ed902020-02-11 14:32:42 -08005441 if (fmsg->putting_binary)
5442 return -EINVAL;
5443
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005444 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
5445}
5446EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
5447
5448int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
5449{
Aya Levin573ed902020-02-11 14:32:42 -08005450 if (fmsg->putting_binary)
5451 return -EINVAL;
5452
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005453 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
5454 NLA_NUL_STRING);
5455}
5456EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
5457
Aya Levin573ed902020-02-11 14:32:42 -08005458int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
5459 u16 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005460{
Aya Levin573ed902020-02-11 14:32:42 -08005461 if (!fmsg->putting_binary)
5462 return -EINVAL;
5463
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005464 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
5465}
Aya Levin573ed902020-02-11 14:32:42 -08005466EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005467
5468int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
5469 bool value)
5470{
5471 int err;
5472
5473 err = devlink_fmsg_pair_nest_start(fmsg, name);
5474 if (err)
5475 return err;
5476
5477 err = devlink_fmsg_bool_put(fmsg, value);
5478 if (err)
5479 return err;
5480
5481 err = devlink_fmsg_pair_nest_end(fmsg);
5482 if (err)
5483 return err;
5484
5485 return 0;
5486}
5487EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
5488
5489int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
5490 u8 value)
5491{
5492 int err;
5493
5494 err = devlink_fmsg_pair_nest_start(fmsg, name);
5495 if (err)
5496 return err;
5497
5498 err = devlink_fmsg_u8_put(fmsg, value);
5499 if (err)
5500 return err;
5501
5502 err = devlink_fmsg_pair_nest_end(fmsg);
5503 if (err)
5504 return err;
5505
5506 return 0;
5507}
5508EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
5509
5510int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
5511 u32 value)
5512{
5513 int err;
5514
5515 err = devlink_fmsg_pair_nest_start(fmsg, name);
5516 if (err)
5517 return err;
5518
5519 err = devlink_fmsg_u32_put(fmsg, value);
5520 if (err)
5521 return err;
5522
5523 err = devlink_fmsg_pair_nest_end(fmsg);
5524 if (err)
5525 return err;
5526
5527 return 0;
5528}
5529EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
5530
5531int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
5532 u64 value)
5533{
5534 int err;
5535
5536 err = devlink_fmsg_pair_nest_start(fmsg, name);
5537 if (err)
5538 return err;
5539
5540 err = devlink_fmsg_u64_put(fmsg, value);
5541 if (err)
5542 return err;
5543
5544 err = devlink_fmsg_pair_nest_end(fmsg);
5545 if (err)
5546 return err;
5547
5548 return 0;
5549}
5550EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
5551
5552int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
5553 const char *value)
5554{
5555 int err;
5556
5557 err = devlink_fmsg_pair_nest_start(fmsg, name);
5558 if (err)
5559 return err;
5560
5561 err = devlink_fmsg_string_put(fmsg, value);
5562 if (err)
5563 return err;
5564
5565 err = devlink_fmsg_pair_nest_end(fmsg);
5566 if (err)
5567 return err;
5568
5569 return 0;
5570}
5571EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
5572
5573int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
Aya Levine2cde862019-11-12 14:07:49 +02005574 const void *value, u32 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005575{
Aya Levine2cde862019-11-12 14:07:49 +02005576 u32 data_size;
Aya Levin573ed902020-02-11 14:32:42 -08005577 int end_err;
Aya Levine2cde862019-11-12 14:07:49 +02005578 u32 offset;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005579 int err;
5580
Aya Levin573ed902020-02-11 14:32:42 -08005581 err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005582 if (err)
5583 return err;
5584
Aya Levine2cde862019-11-12 14:07:49 +02005585 for (offset = 0; offset < value_len; offset += data_size) {
5586 data_size = value_len - offset;
5587 if (data_size > DEVLINK_FMSG_MAX_SIZE)
5588 data_size = DEVLINK_FMSG_MAX_SIZE;
5589 err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
5590 if (err)
Aya Levin573ed902020-02-11 14:32:42 -08005591 break;
5592 /* Exit from loop with a break (instead of
5593 * return) to make sure putting_binary is turned off in
5594 * devlink_fmsg_binary_pair_nest_end
5595 */
Aya Levine2cde862019-11-12 14:07:49 +02005596 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005597
Aya Levin573ed902020-02-11 14:32:42 -08005598 end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
5599 if (end_err)
5600 err = end_err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005601
Aya Levin573ed902020-02-11 14:32:42 -08005602 return err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005603}
5604EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
5605
5606static int
5607devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5608{
5609 switch (msg->nla_type) {
5610 case NLA_FLAG:
5611 case NLA_U8:
5612 case NLA_U32:
5613 case NLA_U64:
5614 case NLA_NUL_STRING:
5615 case NLA_BINARY:
5616 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
5617 msg->nla_type);
5618 default:
5619 return -EINVAL;
5620 }
5621}
5622
5623static int
5624devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5625{
5626 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5627 u8 tmp;
5628
5629 switch (msg->nla_type) {
5630 case NLA_FLAG:
5631 /* Always provide flag data, regardless of its value */
5632 tmp = *(bool *) msg->value;
5633
5634 return nla_put_u8(skb, attrtype, tmp);
5635 case NLA_U8:
5636 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
5637 case NLA_U32:
5638 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
5639 case NLA_U64:
5640 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
5641 DEVLINK_ATTR_PAD);
5642 case NLA_NUL_STRING:
5643 return nla_put_string(skb, attrtype, (char *) &msg->value);
5644 case NLA_BINARY:
5645 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
5646 default:
5647 return -EINVAL;
5648 }
5649}
5650
5651static int
5652devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5653 int *start)
5654{
5655 struct devlink_fmsg_item *item;
5656 struct nlattr *fmsg_nlattr;
5657 int i = 0;
5658 int err;
5659
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005660 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005661 if (!fmsg_nlattr)
5662 return -EMSGSIZE;
5663
5664 list_for_each_entry(item, &fmsg->item_list, list) {
5665 if (i < *start) {
5666 i++;
5667 continue;
5668 }
5669
5670 switch (item->attrtype) {
5671 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
5672 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
5673 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
5674 case DEVLINK_ATTR_FMSG_NEST_END:
5675 err = nla_put_flag(skb, item->attrtype);
5676 break;
5677 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
5678 err = devlink_fmsg_item_fill_type(item, skb);
5679 if (err)
5680 break;
5681 err = devlink_fmsg_item_fill_data(item, skb);
5682 break;
5683 case DEVLINK_ATTR_FMSG_OBJ_NAME:
5684 err = nla_put_string(skb, item->attrtype,
5685 (char *) &item->value);
5686 break;
5687 default:
5688 err = -EINVAL;
5689 break;
5690 }
5691 if (!err)
5692 *start = ++i;
5693 else
5694 break;
5695 }
5696
5697 nla_nest_end(skb, fmsg_nlattr);
5698 return err;
5699}
5700
5701static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
5702 struct genl_info *info,
5703 enum devlink_command cmd, int flags)
5704{
5705 struct nlmsghdr *nlh;
5706 struct sk_buff *skb;
5707 bool last = false;
5708 int index = 0;
5709 void *hdr;
5710 int err;
5711
5712 while (!last) {
5713 int tmp_index = index;
5714
5715 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5716 if (!skb)
5717 return -ENOMEM;
5718
5719 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
5720 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
5721 if (!hdr) {
5722 err = -EMSGSIZE;
5723 goto nla_put_failure;
5724 }
5725
5726 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5727 if (!err)
5728 last = true;
5729 else if (err != -EMSGSIZE || tmp_index == index)
5730 goto nla_put_failure;
5731
5732 genlmsg_end(skb, hdr);
5733 err = genlmsg_reply(skb, info);
5734 if (err)
5735 return err;
5736 }
5737
5738 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5739 if (!skb)
5740 return -ENOMEM;
5741 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
5742 NLMSG_DONE, 0, flags | NLM_F_MULTI);
5743 if (!nlh) {
5744 err = -EMSGSIZE;
5745 goto nla_put_failure;
5746 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005747
Li RongQingfde55ea2019-02-11 19:09:07 +08005748 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005749
5750nla_put_failure:
5751 nlmsg_free(skb);
5752 return err;
5753}
5754
Aya Levine44ef4e2019-05-16 09:49:20 +03005755static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5756 struct netlink_callback *cb,
5757 enum devlink_command cmd)
5758{
5759 int index = cb->args[0];
5760 int tmp_index = index;
5761 void *hdr;
5762 int err;
5763
5764 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
5765 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
5766 if (!hdr) {
5767 err = -EMSGSIZE;
5768 goto nla_put_failure;
5769 }
5770
5771 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5772 if ((err && err != -EMSGSIZE) || tmp_index == index)
5773 goto nla_put_failure;
5774
5775 cb->args[0] = index;
5776 genlmsg_end(skb, hdr);
5777 return skb->len;
5778
5779nla_put_failure:
5780 genlmsg_cancel(skb, hdr);
5781 return err;
5782}
5783
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005784struct devlink_health_reporter {
5785 struct list_head list;
5786 void *priv;
5787 const struct devlink_health_reporter_ops *ops;
5788 struct devlink *devlink;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005789 struct devlink_port *devlink_port;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005790 struct devlink_fmsg *dump_fmsg;
5791 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005792 u64 graceful_period;
5793 bool auto_recover;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005794 bool auto_dump;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005795 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005796 u64 dump_ts;
Aya Levind2795052019-11-10 14:11:56 +02005797 u64 dump_real_ts;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005798 u64 error_count;
5799 u64 recovery_count;
5800 u64 last_recovery_ts;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005801 refcount_t refcount;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005802};
5803
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005804void *
5805devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
5806{
5807 return reporter->priv;
5808}
5809EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
5810
5811static struct devlink_health_reporter *
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005812__devlink_health_reporter_find_by_name(struct list_head *reporter_list,
5813 struct mutex *list_lock,
5814 const char *reporter_name)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005815{
5816 struct devlink_health_reporter *reporter;
5817
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005818 lockdep_assert_held(list_lock);
5819 list_for_each_entry(reporter, reporter_list, list)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005820 if (!strcmp(reporter->ops->name, reporter_name))
5821 return reporter;
5822 return NULL;
5823}
5824
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005825static struct devlink_health_reporter *
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005826devlink_health_reporter_find_by_name(struct devlink *devlink,
5827 const char *reporter_name)
5828{
5829 return __devlink_health_reporter_find_by_name(&devlink->reporter_list,
5830 &devlink->reporters_lock,
5831 reporter_name);
5832}
5833
5834static struct devlink_health_reporter *
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005835devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
5836 const char *reporter_name)
5837{
5838 return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
5839 &devlink_port->reporters_lock,
5840 reporter_name);
5841}
5842
5843static struct devlink_health_reporter *
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005844__devlink_health_reporter_create(struct devlink *devlink,
5845 const struct devlink_health_reporter_ops *ops,
5846 u64 graceful_period, void *priv)
5847{
5848 struct devlink_health_reporter *reporter;
5849
5850 if (WARN_ON(graceful_period && !ops->recover))
5851 return ERR_PTR(-EINVAL);
5852
5853 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
5854 if (!reporter)
5855 return ERR_PTR(-ENOMEM);
5856
5857 reporter->priv = priv;
5858 reporter->ops = ops;
5859 reporter->devlink = devlink;
5860 reporter->graceful_period = graceful_period;
5861 reporter->auto_recover = !!ops->recover;
5862 reporter->auto_dump = !!ops->dump;
5863 mutex_init(&reporter->dump_lock);
5864 refcount_set(&reporter->refcount, 1);
5865 return reporter;
5866}
5867
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005868/**
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005869 * devlink_port_health_reporter_create - create devlink health reporter for
5870 * specified port instance
5871 *
5872 * @port: devlink_port which should contain the new reporter
5873 * @ops: ops
5874 * @graceful_period: to avoid recovery loops, in msecs
5875 * @priv: priv
5876 */
5877struct devlink_health_reporter *
5878devlink_port_health_reporter_create(struct devlink_port *port,
5879 const struct devlink_health_reporter_ops *ops,
5880 u64 graceful_period, void *priv)
5881{
5882 struct devlink_health_reporter *reporter;
5883
5884 mutex_lock(&port->reporters_lock);
5885 if (__devlink_health_reporter_find_by_name(&port->reporter_list,
5886 &port->reporters_lock, ops->name)) {
5887 reporter = ERR_PTR(-EEXIST);
5888 goto unlock;
5889 }
5890
5891 reporter = __devlink_health_reporter_create(port->devlink, ops,
5892 graceful_period, priv);
5893 if (IS_ERR(reporter))
5894 goto unlock;
5895
5896 reporter->devlink_port = port;
5897 list_add_tail(&reporter->list, &port->reporter_list);
5898unlock:
5899 mutex_unlock(&port->reporters_lock);
5900 return reporter;
5901}
5902EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
5903
5904/**
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005905 * devlink_health_reporter_create - create devlink health reporter
5906 *
5907 * @devlink: devlink
5908 * @ops: ops
5909 * @graceful_period: to avoid recovery loops, in msecs
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005910 * @priv: priv
5911 */
5912struct devlink_health_reporter *
5913devlink_health_reporter_create(struct devlink *devlink,
5914 const struct devlink_health_reporter_ops *ops,
Eran Ben Elishaba7d16c2020-03-29 14:05:54 +03005915 u64 graceful_period, void *priv)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005916{
5917 struct devlink_health_reporter *reporter;
5918
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005919 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005920 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
5921 reporter = ERR_PTR(-EEXIST);
5922 goto unlock;
5923 }
5924
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005925 reporter = __devlink_health_reporter_create(devlink, ops,
5926 graceful_period, priv);
5927 if (IS_ERR(reporter))
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005928 goto unlock;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005929
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005930 list_add_tail(&reporter->list, &devlink->reporter_list);
5931unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005932 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005933 return reporter;
5934}
5935EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
5936
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005937static void
5938devlink_health_reporter_free(struct devlink_health_reporter *reporter)
5939{
5940 mutex_destroy(&reporter->dump_lock);
5941 if (reporter->dump_fmsg)
5942 devlink_fmsg_free(reporter->dump_fmsg);
5943 kfree(reporter);
5944}
5945
5946static void
5947devlink_health_reporter_put(struct devlink_health_reporter *reporter)
5948{
5949 if (refcount_dec_and_test(&reporter->refcount))
5950 devlink_health_reporter_free(reporter);
5951}
5952
5953static void
5954__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5955{
5956 list_del(&reporter->list);
5957 devlink_health_reporter_put(reporter);
5958}
5959
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005960/**
5961 * devlink_health_reporter_destroy - destroy devlink health reporter
5962 *
5963 * @reporter: devlink health reporter to destroy
5964 */
5965void
5966devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5967{
Ido Schimmel5d037b42020-07-13 18:20:14 +03005968 struct mutex *lock = &reporter->devlink->reporters_lock;
5969
5970 mutex_lock(lock);
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005971 __devlink_health_reporter_destroy(reporter);
Ido Schimmel5d037b42020-07-13 18:20:14 +03005972 mutex_unlock(lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005973}
5974EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
5975
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005976/**
5977 * devlink_port_health_reporter_destroy - destroy devlink port health reporter
5978 *
5979 * @reporter: devlink health reporter to destroy
5980 */
5981void
5982devlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter)
5983{
Ido Schimmel5d037b42020-07-13 18:20:14 +03005984 struct mutex *lock = &reporter->devlink_port->reporters_lock;
5985
5986 mutex_lock(lock);
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005987 __devlink_health_reporter_destroy(reporter);
Ido Schimmel5d037b42020-07-13 18:20:14 +03005988 mutex_unlock(lock);
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005989}
5990EXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy);
5991
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005992static int
5993devlink_nl_health_reporter_fill(struct sk_buff *msg,
5994 struct devlink *devlink,
5995 struct devlink_health_reporter *reporter,
5996 enum devlink_command cmd, u32 portid,
5997 u32 seq, int flags)
5998{
5999 struct nlattr *reporter_attr;
6000 void *hdr;
6001
6002 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6003 if (!hdr)
6004 return -EMSGSIZE;
6005
6006 if (devlink_nl_put_handle(msg, devlink))
6007 goto genlmsg_cancel;
6008
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006009 if (reporter->devlink_port) {
6010 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
6011 goto genlmsg_cancel;
6012 }
Michal Kubecekae0be8d2019-04-26 11:13:06 +02006013 reporter_attr = nla_nest_start_noflag(msg,
6014 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006015 if (!reporter_attr)
6016 goto genlmsg_cancel;
6017 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
6018 reporter->ops->name))
6019 goto reporter_nest_cancel;
6020 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
6021 reporter->health_state))
6022 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02006023 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006024 reporter->error_count, DEVLINK_ATTR_PAD))
6025 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02006026 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006027 reporter->recovery_count, DEVLINK_ATTR_PAD))
6028 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02006029 if (reporter->ops->recover &&
6030 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006031 reporter->graceful_period,
6032 DEVLINK_ATTR_PAD))
6033 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02006034 if (reporter->ops->recover &&
6035 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006036 reporter->auto_recover))
6037 goto reporter_nest_cancel;
6038 if (reporter->dump_fmsg &&
6039 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
6040 jiffies_to_msecs(reporter->dump_ts),
6041 DEVLINK_ATTR_PAD))
6042 goto reporter_nest_cancel;
Aya Levind2795052019-11-10 14:11:56 +02006043 if (reporter->dump_fmsg &&
6044 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
6045 reporter->dump_real_ts, DEVLINK_ATTR_PAD))
6046 goto reporter_nest_cancel;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006047 if (reporter->ops->dump &&
6048 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
6049 reporter->auto_dump))
6050 goto reporter_nest_cancel;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006051
6052 nla_nest_end(msg, reporter_attr);
6053 genlmsg_end(msg, hdr);
6054 return 0;
6055
6056reporter_nest_cancel:
6057 nla_nest_end(msg, reporter_attr);
6058genlmsg_cancel:
6059 genlmsg_cancel(msg, hdr);
6060 return -EMSGSIZE;
6061}
6062
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05306063static void devlink_recover_notify(struct devlink_health_reporter *reporter,
6064 enum devlink_command cmd)
6065{
6066 struct sk_buff *msg;
6067 int err;
6068
6069 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6070
6071 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6072 if (!msg)
6073 return;
6074
6075 err = devlink_nl_health_reporter_fill(msg, reporter->devlink,
6076 reporter, cmd, 0, 0, 0);
6077 if (err) {
6078 nlmsg_free(msg);
6079 return;
6080 }
6081
6082 genlmsg_multicast_netns(&devlink_nl_family,
6083 devlink_net(reporter->devlink),
6084 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
6085}
6086
6087void
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006088devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
6089{
6090 reporter->recovery_count++;
6091 reporter->last_recovery_ts = jiffies;
6092}
6093EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
6094
6095static int
6096devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
6097 void *priv_ctx, struct netlink_ext_ack *extack)
6098{
6099 int err;
6100
6101 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
6102 return 0;
6103
6104 if (!reporter->ops->recover)
6105 return -EOPNOTSUPP;
6106
6107 err = reporter->ops->recover(reporter, priv_ctx, extack);
6108 if (err)
6109 return err;
6110
6111 devlink_health_reporter_recovery_done(reporter);
6112 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
6113 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6114
6115 return 0;
6116}
6117
6118static void
6119devlink_health_dump_clear(struct devlink_health_reporter *reporter)
6120{
6121 if (!reporter->dump_fmsg)
6122 return;
6123 devlink_fmsg_free(reporter->dump_fmsg);
6124 reporter->dump_fmsg = NULL;
6125}
6126
6127static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
6128 void *priv_ctx,
6129 struct netlink_ext_ack *extack)
6130{
6131 int err;
6132
6133 if (!reporter->ops->dump)
6134 return 0;
6135
6136 if (reporter->dump_fmsg)
6137 return 0;
6138
6139 reporter->dump_fmsg = devlink_fmsg_alloc();
6140 if (!reporter->dump_fmsg) {
6141 err = -ENOMEM;
6142 return err;
6143 }
6144
6145 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
6146 if (err)
6147 goto dump_err;
6148
6149 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
6150 priv_ctx, extack);
6151 if (err)
6152 goto dump_err;
6153
6154 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
6155 if (err)
6156 goto dump_err;
6157
6158 reporter->dump_ts = jiffies;
6159 reporter->dump_real_ts = ktime_get_real_ns();
6160
6161 return 0;
6162
6163dump_err:
6164 devlink_health_dump_clear(reporter);
6165 return err;
6166}
6167
6168int devlink_health_report(struct devlink_health_reporter *reporter,
6169 const char *msg, void *priv_ctx)
6170{
6171 enum devlink_health_reporter_state prev_health_state;
6172 struct devlink *devlink = reporter->devlink;
Aya Levinbea0c5c2020-05-04 11:27:46 +03006173 unsigned long recover_ts_threshold;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006174
6175 /* write a log message of the current error */
6176 WARN_ON(!msg);
6177 trace_devlink_health_report(devlink, reporter->ops->name, msg);
6178 reporter->error_count++;
6179 prev_health_state = reporter->health_state;
6180 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
6181 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6182
6183 /* abort if the previous error wasn't recovered */
Aya Levinbea0c5c2020-05-04 11:27:46 +03006184 recover_ts_threshold = reporter->last_recovery_ts +
6185 msecs_to_jiffies(reporter->graceful_period);
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006186 if (reporter->auto_recover &&
6187 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Aya Levinbea0c5c2020-05-04 11:27:46 +03006188 (reporter->last_recovery_ts && reporter->recovery_count &&
6189 time_is_after_jiffies(recover_ts_threshold)))) {
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006190 trace_devlink_health_recover_aborted(devlink,
6191 reporter->ops->name,
6192 reporter->health_state,
6193 jiffies -
6194 reporter->last_recovery_ts);
6195 return -ECANCELED;
6196 }
6197
6198 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
6199
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006200 if (reporter->auto_dump) {
6201 mutex_lock(&reporter->dump_lock);
6202 /* store current dump of current error, for later analysis */
6203 devlink_health_do_dump(reporter, priv_ctx, NULL);
6204 mutex_unlock(&reporter->dump_lock);
6205 }
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006206
6207 if (reporter->auto_recover)
6208 return devlink_health_reporter_recover(reporter,
6209 priv_ctx, NULL);
6210
6211 return 0;
6212}
6213EXPORT_SYMBOL_GPL(devlink_health_report);
6214
6215static struct devlink_health_reporter *
6216devlink_health_reporter_get_from_attrs(struct devlink *devlink,
6217 struct nlattr **attrs)
6218{
6219 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006220 struct devlink_port *devlink_port;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006221 char *reporter_name;
6222
6223 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
6224 return NULL;
6225
6226 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006227 devlink_port = devlink_port_get_from_attrs(devlink, attrs);
6228 if (IS_ERR(devlink_port)) {
6229 mutex_lock(&devlink->reporters_lock);
6230 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
6231 if (reporter)
6232 refcount_inc(&reporter->refcount);
6233 mutex_unlock(&devlink->reporters_lock);
6234 } else {
6235 mutex_lock(&devlink_port->reporters_lock);
6236 reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name);
6237 if (reporter)
6238 refcount_inc(&reporter->refcount);
6239 mutex_unlock(&devlink_port->reporters_lock);
6240 }
6241
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006242 return reporter;
6243}
6244
6245static struct devlink_health_reporter *
6246devlink_health_reporter_get_from_info(struct devlink *devlink,
6247 struct genl_info *info)
6248{
6249 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
6250}
6251
6252static struct devlink_health_reporter *
6253devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
6254{
6255 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
6256 struct devlink_health_reporter *reporter;
6257 struct nlattr **attrs = info->attrs;
6258 struct devlink *devlink;
6259
6260 mutex_lock(&devlink_mutex);
6261 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
6262 if (IS_ERR(devlink))
6263 goto unlock;
6264
6265 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
6266 mutex_unlock(&devlink_mutex);
6267 return reporter;
6268unlock:
6269 mutex_unlock(&devlink_mutex);
6270 return NULL;
6271}
6272
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006273void
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05306274devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
6275 enum devlink_health_reporter_state state)
6276{
6277 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
6278 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
6279 return;
6280
6281 if (reporter->health_state == state)
6282 return;
6283
6284 reporter->health_state = state;
6285 trace_devlink_health_reporter_state_update(reporter->devlink,
6286 reporter->ops->name, state);
6287 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6288}
6289EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
6290
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006291static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
6292 struct genl_info *info)
6293{
6294 struct devlink *devlink = info->user_ptr[0];
6295 struct devlink_health_reporter *reporter;
6296 struct sk_buff *msg;
6297 int err;
6298
6299 reporter = devlink_health_reporter_get_from_info(devlink, info);
6300 if (!reporter)
6301 return -EINVAL;
6302
6303 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006304 if (!msg) {
6305 err = -ENOMEM;
6306 goto out;
6307 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006308
6309 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
6310 DEVLINK_CMD_HEALTH_REPORTER_GET,
6311 info->snd_portid, info->snd_seq,
6312 0);
6313 if (err) {
6314 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006315 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006316 }
6317
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006318 err = genlmsg_reply(msg, info);
6319out:
6320 devlink_health_reporter_put(reporter);
6321 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006322}
6323
6324static int
6325devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
6326 struct netlink_callback *cb)
6327{
6328 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006329 struct devlink_port *port;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006330 struct devlink *devlink;
6331 int start = cb->args[0];
6332 int idx = 0;
6333 int err;
6334
6335 mutex_lock(&devlink_mutex);
6336 list_for_each_entry(devlink, &devlink_list, list) {
6337 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6338 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006339 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006340 list_for_each_entry(reporter, &devlink->reporter_list,
6341 list) {
6342 if (idx < start) {
6343 idx++;
6344 continue;
6345 }
6346 err = devlink_nl_health_reporter_fill(msg, devlink,
6347 reporter,
6348 DEVLINK_CMD_HEALTH_REPORTER_GET,
6349 NETLINK_CB(cb->skb).portid,
6350 cb->nlh->nlmsg_seq,
6351 NLM_F_MULTI);
6352 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006353 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006354 goto out;
6355 }
6356 idx++;
6357 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006358 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006359 }
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006360
6361 list_for_each_entry(devlink, &devlink_list, list) {
6362 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6363 continue;
Parav Pandit5d080b52020-08-21 22:12:21 +03006364 mutex_lock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006365 list_for_each_entry(port, &devlink->port_list, list) {
6366 mutex_lock(&port->reporters_lock);
6367 list_for_each_entry(reporter, &port->reporter_list, list) {
6368 if (idx < start) {
6369 idx++;
6370 continue;
6371 }
6372 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
6373 DEVLINK_CMD_HEALTH_REPORTER_GET,
6374 NETLINK_CB(cb->skb).portid,
6375 cb->nlh->nlmsg_seq,
6376 NLM_F_MULTI);
6377 if (err) {
6378 mutex_unlock(&port->reporters_lock);
Parav Pandit5d080b52020-08-21 22:12:21 +03006379 mutex_unlock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006380 goto out;
6381 }
6382 idx++;
6383 }
6384 mutex_unlock(&port->reporters_lock);
6385 }
Parav Pandit5d080b52020-08-21 22:12:21 +03006386 mutex_unlock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006387 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006388out:
6389 mutex_unlock(&devlink_mutex);
6390
6391 cb->args[0] = idx;
6392 return msg->len;
6393}
6394
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006395static int
6396devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
6397 struct genl_info *info)
6398{
6399 struct devlink *devlink = info->user_ptr[0];
6400 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006401 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006402
6403 reporter = devlink_health_reporter_get_from_info(devlink, info);
6404 if (!reporter)
6405 return -EINVAL;
6406
6407 if (!reporter->ops->recover &&
6408 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006409 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
6410 err = -EOPNOTSUPP;
6411 goto out;
6412 }
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006413 if (!reporter->ops->dump &&
6414 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
6415 err = -EOPNOTSUPP;
6416 goto out;
6417 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006418
6419 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
6420 reporter->graceful_period =
6421 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
6422
6423 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
6424 reporter->auto_recover =
6425 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
6426
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006427 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
6428 reporter->auto_dump =
6429 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
6430
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006431 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006432 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006433out:
6434 devlink_health_reporter_put(reporter);
6435 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006436}
6437
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006438static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
6439 struct genl_info *info)
6440{
6441 struct devlink *devlink = info->user_ptr[0];
6442 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006443 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006444
6445 reporter = devlink_health_reporter_get_from_info(devlink, info);
6446 if (!reporter)
6447 return -EINVAL;
6448
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006449 err = devlink_health_reporter_recover(reporter, NULL, info->extack);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006450
6451 devlink_health_reporter_put(reporter);
6452 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006453}
6454
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006455static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
6456 struct genl_info *info)
6457{
6458 struct devlink *devlink = info->user_ptr[0];
6459 struct devlink_health_reporter *reporter;
6460 struct devlink_fmsg *fmsg;
6461 int err;
6462
6463 reporter = devlink_health_reporter_get_from_info(devlink, info);
6464 if (!reporter)
6465 return -EINVAL;
6466
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006467 if (!reporter->ops->diagnose) {
6468 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006469 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006470 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006471
6472 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006473 if (!fmsg) {
6474 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006475 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006476 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006477
6478 err = devlink_fmsg_obj_nest_start(fmsg);
6479 if (err)
6480 goto out;
6481
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006482 err = reporter->ops->diagnose(reporter, fmsg, info->extack);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006483 if (err)
6484 goto out;
6485
6486 err = devlink_fmsg_obj_nest_end(fmsg);
6487 if (err)
6488 goto out;
6489
6490 err = devlink_fmsg_snd(fmsg, info,
6491 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
6492
6493out:
6494 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006495 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006496 return err;
6497}
6498
Aya Levine44ef4e2019-05-16 09:49:20 +03006499static int
6500devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
6501 struct netlink_callback *cb)
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006502{
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006503 struct devlink_health_reporter *reporter;
Aya Levine44ef4e2019-05-16 09:49:20 +03006504 u64 start = cb->args[0];
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006505 int err;
6506
Aya Levine44ef4e2019-05-16 09:49:20 +03006507 reporter = devlink_health_reporter_get_from_cb(cb);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006508 if (!reporter)
6509 return -EINVAL;
6510
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006511 if (!reporter->ops->dump) {
Aya Levine44ef4e2019-05-16 09:49:20 +03006512 err = -EOPNOTSUPP;
6513 goto out;
6514 }
6515 mutex_lock(&reporter->dump_lock);
6516 if (!start) {
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006517 err = devlink_health_do_dump(reporter, NULL, cb->extack);
Aya Levine44ef4e2019-05-16 09:49:20 +03006518 if (err)
6519 goto unlock;
6520 cb->args[1] = reporter->dump_ts;
6521 }
6522 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
6523 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
6524 err = -EAGAIN;
6525 goto unlock;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006526 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006527
Aya Levine44ef4e2019-05-16 09:49:20 +03006528 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
6529 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
6530unlock:
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006531 mutex_unlock(&reporter->dump_lock);
Aya Levine44ef4e2019-05-16 09:49:20 +03006532out:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006533 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006534 return err;
6535}
6536
6537static int
6538devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
6539 struct genl_info *info)
6540{
6541 struct devlink *devlink = info->user_ptr[0];
6542 struct devlink_health_reporter *reporter;
6543
6544 reporter = devlink_health_reporter_get_from_info(devlink, info);
6545 if (!reporter)
6546 return -EINVAL;
6547
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006548 if (!reporter->ops->dump) {
6549 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006550 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006551 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006552
6553 mutex_lock(&reporter->dump_lock);
6554 devlink_health_dump_clear(reporter);
6555 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006556 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006557 return 0;
6558}
6559
Jiri Pirkoe2ce94d2020-09-15 11:40:57 +03006560static int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
6561 struct genl_info *info)
6562{
6563 struct devlink *devlink = info->user_ptr[0];
6564 struct devlink_health_reporter *reporter;
6565 int err;
6566
6567 reporter = devlink_health_reporter_get_from_info(devlink, info);
6568 if (!reporter)
6569 return -EINVAL;
6570
6571 if (!reporter->ops->test) {
6572 devlink_health_reporter_put(reporter);
6573 return -EOPNOTSUPP;
6574 }
6575
6576 err = reporter->ops->test(reporter, info->extack);
6577
6578 devlink_health_reporter_put(reporter);
6579 return err;
6580}
6581
Ido Schimmel0f420b62019-08-17 16:28:17 +03006582struct devlink_stats {
6583 u64 rx_bytes;
6584 u64 rx_packets;
6585 struct u64_stats_sync syncp;
6586};
6587
6588/**
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006589 * struct devlink_trap_policer_item - Packet trap policer attributes.
6590 * @policer: Immutable packet trap policer attributes.
6591 * @rate: Rate in packets / sec.
6592 * @burst: Burst size in packets.
6593 * @list: trap_policer_list member.
6594 *
6595 * Describes packet trap policer attributes. Created by devlink during trap
6596 * policer registration.
6597 */
6598struct devlink_trap_policer_item {
6599 const struct devlink_trap_policer *policer;
6600 u64 rate;
6601 u64 burst;
6602 struct list_head list;
6603};
6604
6605/**
Ido Schimmel0f420b62019-08-17 16:28:17 +03006606 * struct devlink_trap_group_item - Packet trap group attributes.
6607 * @group: Immutable packet trap group attributes.
Ido Schimmelf9f54392020-03-30 22:38:21 +03006608 * @policer_item: Associated policer item. Can be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006609 * @list: trap_group_list member.
6610 * @stats: Trap group statistics.
6611 *
6612 * Describes packet trap group attributes. Created by devlink during trap
Ido Schimmela09b37f2020-03-22 20:48:29 +02006613 * group registration.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006614 */
6615struct devlink_trap_group_item {
6616 const struct devlink_trap_group *group;
Ido Schimmelf9f54392020-03-30 22:38:21 +03006617 struct devlink_trap_policer_item *policer_item;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006618 struct list_head list;
6619 struct devlink_stats __percpu *stats;
6620};
6621
6622/**
6623 * struct devlink_trap_item - Packet trap attributes.
6624 * @trap: Immutable packet trap attributes.
6625 * @group_item: Associated group item.
6626 * @list: trap_list member.
6627 * @action: Trap action.
6628 * @stats: Trap statistics.
6629 * @priv: Driver private information.
6630 *
6631 * Describes both mutable and immutable packet trap attributes. Created by
6632 * devlink during trap registration and used for all trap related operations.
6633 */
6634struct devlink_trap_item {
6635 const struct devlink_trap *trap;
6636 struct devlink_trap_group_item *group_item;
6637 struct list_head list;
6638 enum devlink_trap_action action;
6639 struct devlink_stats __percpu *stats;
6640 void *priv;
6641};
6642
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006643static struct devlink_trap_policer_item *
6644devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
6645{
6646 struct devlink_trap_policer_item *policer_item;
6647
6648 list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
6649 if (policer_item->policer->id == id)
6650 return policer_item;
6651 }
6652
6653 return NULL;
6654}
6655
Ido Schimmel0f420b62019-08-17 16:28:17 +03006656static struct devlink_trap_item *
6657devlink_trap_item_lookup(struct devlink *devlink, const char *name)
6658{
6659 struct devlink_trap_item *trap_item;
6660
6661 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6662 if (!strcmp(trap_item->trap->name, name))
6663 return trap_item;
6664 }
6665
6666 return NULL;
6667}
6668
6669static struct devlink_trap_item *
6670devlink_trap_item_get_from_info(struct devlink *devlink,
6671 struct genl_info *info)
6672{
6673 struct nlattr *attr;
6674
6675 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
6676 return NULL;
6677 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
6678
6679 return devlink_trap_item_lookup(devlink, nla_data(attr));
6680}
6681
6682static int
6683devlink_trap_action_get_from_info(struct genl_info *info,
6684 enum devlink_trap_action *p_trap_action)
6685{
6686 u8 val;
6687
6688 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
6689 switch (val) {
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05006690 case DEVLINK_TRAP_ACTION_DROP:
6691 case DEVLINK_TRAP_ACTION_TRAP:
Ido Schimmel9eefeab2020-05-29 21:36:39 +03006692 case DEVLINK_TRAP_ACTION_MIRROR:
Ido Schimmel0f420b62019-08-17 16:28:17 +03006693 *p_trap_action = val;
6694 break;
6695 default:
6696 return -EINVAL;
6697 }
6698
6699 return 0;
6700}
6701
6702static int devlink_trap_metadata_put(struct sk_buff *msg,
6703 const struct devlink_trap *trap)
6704{
6705 struct nlattr *attr;
6706
6707 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
6708 if (!attr)
6709 return -EMSGSIZE;
6710
6711 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
6712 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
6713 goto nla_put_failure;
Jiri Pirko85b05892020-02-25 11:45:19 +01006714 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
6715 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
6716 goto nla_put_failure;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006717
6718 nla_nest_end(msg, attr);
6719
6720 return 0;
6721
6722nla_put_failure:
6723 nla_nest_cancel(msg, attr);
6724 return -EMSGSIZE;
6725}
6726
6727static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
6728 struct devlink_stats *stats)
6729{
6730 int i;
6731
6732 memset(stats, 0, sizeof(*stats));
6733 for_each_possible_cpu(i) {
6734 struct devlink_stats *cpu_stats;
6735 u64 rx_packets, rx_bytes;
6736 unsigned int start;
6737
6738 cpu_stats = per_cpu_ptr(trap_stats, i);
6739 do {
6740 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
6741 rx_packets = cpu_stats->rx_packets;
6742 rx_bytes = cpu_stats->rx_bytes;
6743 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
6744
6745 stats->rx_packets += rx_packets;
6746 stats->rx_bytes += rx_bytes;
6747 }
6748}
6749
6750static int devlink_trap_stats_put(struct sk_buff *msg,
6751 struct devlink_stats __percpu *trap_stats)
6752{
6753 struct devlink_stats stats;
6754 struct nlattr *attr;
6755
6756 devlink_trap_stats_read(trap_stats, &stats);
6757
6758 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6759 if (!attr)
6760 return -EMSGSIZE;
6761
6762 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
6763 stats.rx_packets, DEVLINK_ATTR_PAD))
6764 goto nla_put_failure;
6765
6766 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
6767 stats.rx_bytes, DEVLINK_ATTR_PAD))
6768 goto nla_put_failure;
6769
6770 nla_nest_end(msg, attr);
6771
6772 return 0;
6773
6774nla_put_failure:
6775 nla_nest_cancel(msg, attr);
6776 return -EMSGSIZE;
6777}
6778
6779static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
6780 const struct devlink_trap_item *trap_item,
6781 enum devlink_command cmd, u32 portid, u32 seq,
6782 int flags)
6783{
6784 struct devlink_trap_group_item *group_item = trap_item->group_item;
6785 void *hdr;
6786 int err;
6787
6788 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6789 if (!hdr)
6790 return -EMSGSIZE;
6791
6792 if (devlink_nl_put_handle(msg, devlink))
6793 goto nla_put_failure;
6794
6795 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6796 group_item->group->name))
6797 goto nla_put_failure;
6798
6799 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
6800 goto nla_put_failure;
6801
6802 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
6803 goto nla_put_failure;
6804
6805 if (trap_item->trap->generic &&
6806 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6807 goto nla_put_failure;
6808
6809 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
6810 goto nla_put_failure;
6811
6812 err = devlink_trap_metadata_put(msg, trap_item->trap);
6813 if (err)
6814 goto nla_put_failure;
6815
6816 err = devlink_trap_stats_put(msg, trap_item->stats);
6817 if (err)
6818 goto nla_put_failure;
6819
6820 genlmsg_end(msg, hdr);
6821
6822 return 0;
6823
6824nla_put_failure:
6825 genlmsg_cancel(msg, hdr);
6826 return -EMSGSIZE;
6827}
6828
6829static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
6830 struct genl_info *info)
6831{
6832 struct netlink_ext_ack *extack = info->extack;
6833 struct devlink *devlink = info->user_ptr[0];
6834 struct devlink_trap_item *trap_item;
6835 struct sk_buff *msg;
6836 int err;
6837
6838 if (list_empty(&devlink->trap_list))
6839 return -EOPNOTSUPP;
6840
6841 trap_item = devlink_trap_item_get_from_info(devlink, info);
6842 if (!trap_item) {
6843 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6844 return -ENOENT;
6845 }
6846
6847 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6848 if (!msg)
6849 return -ENOMEM;
6850
6851 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6852 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
6853 info->snd_seq, 0);
6854 if (err)
6855 goto err_trap_fill;
6856
6857 return genlmsg_reply(msg, info);
6858
6859err_trap_fill:
6860 nlmsg_free(msg);
6861 return err;
6862}
6863
6864static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
6865 struct netlink_callback *cb)
6866{
6867 struct devlink_trap_item *trap_item;
6868 struct devlink *devlink;
6869 int start = cb->args[0];
6870 int idx = 0;
6871 int err;
6872
6873 mutex_lock(&devlink_mutex);
6874 list_for_each_entry(devlink, &devlink_list, list) {
6875 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6876 continue;
6877 mutex_lock(&devlink->lock);
6878 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6879 if (idx < start) {
6880 idx++;
6881 continue;
6882 }
6883 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6884 DEVLINK_CMD_TRAP_NEW,
6885 NETLINK_CB(cb->skb).portid,
6886 cb->nlh->nlmsg_seq,
6887 NLM_F_MULTI);
6888 if (err) {
6889 mutex_unlock(&devlink->lock);
6890 goto out;
6891 }
6892 idx++;
6893 }
6894 mutex_unlock(&devlink->lock);
6895 }
6896out:
6897 mutex_unlock(&devlink_mutex);
6898
6899 cb->args[0] = idx;
6900 return msg->len;
6901}
6902
6903static int __devlink_trap_action_set(struct devlink *devlink,
6904 struct devlink_trap_item *trap_item,
6905 enum devlink_trap_action trap_action,
6906 struct netlink_ext_ack *extack)
6907{
6908 int err;
6909
6910 if (trap_item->action != trap_action &&
6911 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
6912 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
6913 return 0;
6914 }
6915
6916 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
Ido Schimmelc88e11e2020-08-03 19:11:34 +03006917 trap_action, extack);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006918 if (err)
6919 return err;
6920
6921 trap_item->action = trap_action;
6922
6923 return 0;
6924}
6925
6926static int devlink_trap_action_set(struct devlink *devlink,
6927 struct devlink_trap_item *trap_item,
6928 struct genl_info *info)
6929{
6930 enum devlink_trap_action trap_action;
6931 int err;
6932
6933 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6934 return 0;
6935
6936 err = devlink_trap_action_get_from_info(info, &trap_action);
6937 if (err) {
6938 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6939 return -EINVAL;
6940 }
6941
6942 return __devlink_trap_action_set(devlink, trap_item, trap_action,
6943 info->extack);
6944}
6945
6946static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
6947 struct genl_info *info)
6948{
6949 struct netlink_ext_ack *extack = info->extack;
6950 struct devlink *devlink = info->user_ptr[0];
6951 struct devlink_trap_item *trap_item;
6952 int err;
6953
6954 if (list_empty(&devlink->trap_list))
6955 return -EOPNOTSUPP;
6956
6957 trap_item = devlink_trap_item_get_from_info(devlink, info);
6958 if (!trap_item) {
6959 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6960 return -ENOENT;
6961 }
6962
6963 err = devlink_trap_action_set(devlink, trap_item, info);
6964 if (err)
6965 return err;
6966
6967 return 0;
6968}
6969
6970static struct devlink_trap_group_item *
6971devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
6972{
6973 struct devlink_trap_group_item *group_item;
6974
6975 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6976 if (!strcmp(group_item->group->name, name))
6977 return group_item;
6978 }
6979
6980 return NULL;
6981}
6982
6983static struct devlink_trap_group_item *
Ido Schimmel107f1672020-03-22 20:48:30 +02006984devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
6985{
6986 struct devlink_trap_group_item *group_item;
6987
6988 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6989 if (group_item->group->id == id)
6990 return group_item;
6991 }
6992
6993 return NULL;
6994}
6995
6996static struct devlink_trap_group_item *
Ido Schimmel0f420b62019-08-17 16:28:17 +03006997devlink_trap_group_item_get_from_info(struct devlink *devlink,
6998 struct genl_info *info)
6999{
7000 char *name;
7001
7002 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
7003 return NULL;
7004 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
7005
7006 return devlink_trap_group_item_lookup(devlink, name);
7007}
7008
7009static int
7010devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
7011 const struct devlink_trap_group_item *group_item,
7012 enum devlink_command cmd, u32 portid, u32 seq,
7013 int flags)
7014{
7015 void *hdr;
7016 int err;
7017
7018 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
7019 if (!hdr)
7020 return -EMSGSIZE;
7021
7022 if (devlink_nl_put_handle(msg, devlink))
7023 goto nla_put_failure;
7024
7025 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
7026 group_item->group->name))
7027 goto nla_put_failure;
7028
7029 if (group_item->group->generic &&
7030 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
7031 goto nla_put_failure;
7032
Ido Schimmelf9f54392020-03-30 22:38:21 +03007033 if (group_item->policer_item &&
7034 nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
7035 group_item->policer_item->policer->id))
7036 goto nla_put_failure;
7037
Ido Schimmel0f420b62019-08-17 16:28:17 +03007038 err = devlink_trap_stats_put(msg, group_item->stats);
7039 if (err)
7040 goto nla_put_failure;
7041
7042 genlmsg_end(msg, hdr);
7043
7044 return 0;
7045
7046nla_put_failure:
7047 genlmsg_cancel(msg, hdr);
7048 return -EMSGSIZE;
7049}
7050
7051static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
7052 struct genl_info *info)
7053{
7054 struct netlink_ext_ack *extack = info->extack;
7055 struct devlink *devlink = info->user_ptr[0];
7056 struct devlink_trap_group_item *group_item;
7057 struct sk_buff *msg;
7058 int err;
7059
7060 if (list_empty(&devlink->trap_group_list))
7061 return -EOPNOTSUPP;
7062
7063 group_item = devlink_trap_group_item_get_from_info(devlink, info);
7064 if (!group_item) {
7065 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
7066 return -ENOENT;
7067 }
7068
7069 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7070 if (!msg)
7071 return -ENOMEM;
7072
7073 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
7074 DEVLINK_CMD_TRAP_GROUP_NEW,
7075 info->snd_portid, info->snd_seq, 0);
7076 if (err)
7077 goto err_trap_group_fill;
7078
7079 return genlmsg_reply(msg, info);
7080
7081err_trap_group_fill:
7082 nlmsg_free(msg);
7083 return err;
7084}
7085
7086static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
7087 struct netlink_callback *cb)
7088{
7089 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
7090 struct devlink_trap_group_item *group_item;
7091 u32 portid = NETLINK_CB(cb->skb).portid;
7092 struct devlink *devlink;
7093 int start = cb->args[0];
7094 int idx = 0;
7095 int err;
7096
7097 mutex_lock(&devlink_mutex);
7098 list_for_each_entry(devlink, &devlink_list, list) {
7099 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
7100 continue;
7101 mutex_lock(&devlink->lock);
7102 list_for_each_entry(group_item, &devlink->trap_group_list,
7103 list) {
7104 if (idx < start) {
7105 idx++;
7106 continue;
7107 }
7108 err = devlink_nl_trap_group_fill(msg, devlink,
7109 group_item, cmd,
7110 portid,
7111 cb->nlh->nlmsg_seq,
7112 NLM_F_MULTI);
7113 if (err) {
7114 mutex_unlock(&devlink->lock);
7115 goto out;
7116 }
7117 idx++;
7118 }
7119 mutex_unlock(&devlink->lock);
7120 }
7121out:
7122 mutex_unlock(&devlink_mutex);
7123
7124 cb->args[0] = idx;
7125 return msg->len;
7126}
7127
7128static int
7129__devlink_trap_group_action_set(struct devlink *devlink,
7130 struct devlink_trap_group_item *group_item,
7131 enum devlink_trap_action trap_action,
7132 struct netlink_ext_ack *extack)
7133{
7134 const char *group_name = group_item->group->name;
7135 struct devlink_trap_item *trap_item;
7136 int err;
7137
Ioana Ciorneic50bf2b2020-10-01 18:11:46 +03007138 if (devlink->ops->trap_group_action_set) {
7139 err = devlink->ops->trap_group_action_set(devlink, group_item->group,
7140 trap_action, extack);
7141 if (err)
7142 return err;
7143
7144 list_for_each_entry(trap_item, &devlink->trap_list, list) {
7145 if (strcmp(trap_item->group_item->group->name, group_name))
7146 continue;
7147 if (trap_item->action != trap_action &&
7148 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP)
7149 continue;
7150 trap_item->action = trap_action;
7151 }
7152
7153 return 0;
7154 }
7155
Ido Schimmel0f420b62019-08-17 16:28:17 +03007156 list_for_each_entry(trap_item, &devlink->trap_list, list) {
Ido Schimmel107f1672020-03-22 20:48:30 +02007157 if (strcmp(trap_item->group_item->group->name, group_name))
Ido Schimmel0f420b62019-08-17 16:28:17 +03007158 continue;
7159 err = __devlink_trap_action_set(devlink, trap_item,
7160 trap_action, extack);
7161 if (err)
7162 return err;
7163 }
7164
7165 return 0;
7166}
7167
7168static int
7169devlink_trap_group_action_set(struct devlink *devlink,
7170 struct devlink_trap_group_item *group_item,
Ido Schimmelc0648752020-03-30 22:38:22 +03007171 struct genl_info *info, bool *p_modified)
Ido Schimmel0f420b62019-08-17 16:28:17 +03007172{
7173 enum devlink_trap_action trap_action;
7174 int err;
7175
7176 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
7177 return 0;
7178
7179 err = devlink_trap_action_get_from_info(info, &trap_action);
7180 if (err) {
7181 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
7182 return -EINVAL;
7183 }
7184
7185 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
7186 info->extack);
7187 if (err)
7188 return err;
7189
Ido Schimmelc0648752020-03-30 22:38:22 +03007190 *p_modified = true;
7191
7192 return 0;
7193}
7194
7195static int devlink_trap_group_set(struct devlink *devlink,
7196 struct devlink_trap_group_item *group_item,
7197 struct genl_info *info)
7198{
7199 struct devlink_trap_policer_item *policer_item;
7200 struct netlink_ext_ack *extack = info->extack;
7201 const struct devlink_trap_policer *policer;
7202 struct nlattr **attrs = info->attrs;
7203 int err;
7204
7205 if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
7206 return 0;
7207
7208 if (!devlink->ops->trap_group_set)
7209 return -EOPNOTSUPP;
7210
7211 policer_item = group_item->policer_item;
7212 if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) {
7213 u32 policer_id;
7214
7215 policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
7216 policer_item = devlink_trap_policer_item_lookup(devlink,
7217 policer_id);
7218 if (policer_id && !policer_item) {
7219 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7220 return -ENOENT;
7221 }
7222 }
7223 policer = policer_item ? policer_item->policer : NULL;
7224
Ido Schimmelc88e11e2020-08-03 19:11:34 +03007225 err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
7226 extack);
Ido Schimmelc0648752020-03-30 22:38:22 +03007227 if (err)
7228 return err;
7229
7230 group_item->policer_item = policer_item;
7231
Ido Schimmel0f420b62019-08-17 16:28:17 +03007232 return 0;
7233}
7234
7235static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
7236 struct genl_info *info)
7237{
7238 struct netlink_ext_ack *extack = info->extack;
7239 struct devlink *devlink = info->user_ptr[0];
7240 struct devlink_trap_group_item *group_item;
Ido Schimmelc0648752020-03-30 22:38:22 +03007241 bool modified = false;
Ido Schimmel0f420b62019-08-17 16:28:17 +03007242 int err;
7243
7244 if (list_empty(&devlink->trap_group_list))
7245 return -EOPNOTSUPP;
7246
7247 group_item = devlink_trap_group_item_get_from_info(devlink, info);
7248 if (!group_item) {
7249 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
7250 return -ENOENT;
7251 }
7252
Ido Schimmelc0648752020-03-30 22:38:22 +03007253 err = devlink_trap_group_action_set(devlink, group_item, info,
7254 &modified);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007255 if (err)
7256 return err;
7257
Ido Schimmelc0648752020-03-30 22:38:22 +03007258 err = devlink_trap_group_set(devlink, group_item, info);
7259 if (err)
7260 goto err_trap_group_set;
7261
Ido Schimmel0f420b62019-08-17 16:28:17 +03007262 return 0;
Ido Schimmelc0648752020-03-30 22:38:22 +03007263
7264err_trap_group_set:
7265 if (modified)
7266 NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already");
7267 return err;
Ido Schimmel0f420b62019-08-17 16:28:17 +03007268}
7269
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007270static struct devlink_trap_policer_item *
7271devlink_trap_policer_item_get_from_info(struct devlink *devlink,
7272 struct genl_info *info)
7273{
7274 u32 id;
7275
7276 if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
7277 return NULL;
7278 id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
7279
7280 return devlink_trap_policer_item_lookup(devlink, id);
7281}
7282
7283static int
7284devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
7285 const struct devlink_trap_policer *policer)
7286{
7287 struct nlattr *attr;
7288 u64 drops;
7289 int err;
7290
7291 if (!devlink->ops->trap_policer_counter_get)
7292 return 0;
7293
7294 err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
7295 if (err)
7296 return err;
7297
7298 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
7299 if (!attr)
7300 return -EMSGSIZE;
7301
7302 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
7303 DEVLINK_ATTR_PAD))
7304 goto nla_put_failure;
7305
7306 nla_nest_end(msg, attr);
7307
7308 return 0;
7309
7310nla_put_failure:
7311 nla_nest_cancel(msg, attr);
7312 return -EMSGSIZE;
7313}
7314
7315static int
7316devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
7317 const struct devlink_trap_policer_item *policer_item,
7318 enum devlink_command cmd, u32 portid, u32 seq,
7319 int flags)
7320{
7321 void *hdr;
7322 int err;
7323
7324 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
7325 if (!hdr)
7326 return -EMSGSIZE;
7327
7328 if (devlink_nl_put_handle(msg, devlink))
7329 goto nla_put_failure;
7330
7331 if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
7332 policer_item->policer->id))
7333 goto nla_put_failure;
7334
7335 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
7336 policer_item->rate, DEVLINK_ATTR_PAD))
7337 goto nla_put_failure;
7338
7339 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
7340 policer_item->burst, DEVLINK_ATTR_PAD))
7341 goto nla_put_failure;
7342
7343 err = devlink_trap_policer_stats_put(msg, devlink,
7344 policer_item->policer);
7345 if (err)
7346 goto nla_put_failure;
7347
7348 genlmsg_end(msg, hdr);
7349
7350 return 0;
7351
7352nla_put_failure:
7353 genlmsg_cancel(msg, hdr);
7354 return -EMSGSIZE;
7355}
7356
7357static int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
7358 struct genl_info *info)
7359{
7360 struct devlink_trap_policer_item *policer_item;
7361 struct netlink_ext_ack *extack = info->extack;
7362 struct devlink *devlink = info->user_ptr[0];
7363 struct sk_buff *msg;
7364 int err;
7365
7366 if (list_empty(&devlink->trap_policer_list))
7367 return -EOPNOTSUPP;
7368
7369 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
7370 if (!policer_item) {
7371 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7372 return -ENOENT;
7373 }
7374
7375 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7376 if (!msg)
7377 return -ENOMEM;
7378
7379 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
7380 DEVLINK_CMD_TRAP_POLICER_NEW,
7381 info->snd_portid, info->snd_seq, 0);
7382 if (err)
7383 goto err_trap_policer_fill;
7384
7385 return genlmsg_reply(msg, info);
7386
7387err_trap_policer_fill:
7388 nlmsg_free(msg);
7389 return err;
7390}
7391
7392static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,
7393 struct netlink_callback *cb)
7394{
7395 enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW;
7396 struct devlink_trap_policer_item *policer_item;
7397 u32 portid = NETLINK_CB(cb->skb).portid;
7398 struct devlink *devlink;
7399 int start = cb->args[0];
7400 int idx = 0;
7401 int err;
7402
7403 mutex_lock(&devlink_mutex);
7404 list_for_each_entry(devlink, &devlink_list, list) {
7405 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
7406 continue;
7407 mutex_lock(&devlink->lock);
7408 list_for_each_entry(policer_item, &devlink->trap_policer_list,
7409 list) {
7410 if (idx < start) {
7411 idx++;
7412 continue;
7413 }
7414 err = devlink_nl_trap_policer_fill(msg, devlink,
7415 policer_item, cmd,
7416 portid,
7417 cb->nlh->nlmsg_seq,
7418 NLM_F_MULTI);
7419 if (err) {
7420 mutex_unlock(&devlink->lock);
7421 goto out;
7422 }
7423 idx++;
7424 }
7425 mutex_unlock(&devlink->lock);
7426 }
7427out:
7428 mutex_unlock(&devlink_mutex);
7429
7430 cb->args[0] = idx;
7431 return msg->len;
7432}
7433
7434static int
7435devlink_trap_policer_set(struct devlink *devlink,
7436 struct devlink_trap_policer_item *policer_item,
7437 struct genl_info *info)
7438{
7439 struct netlink_ext_ack *extack = info->extack;
7440 struct nlattr **attrs = info->attrs;
7441 u64 rate, burst;
7442 int err;
7443
7444 rate = policer_item->rate;
7445 burst = policer_item->burst;
7446
7447 if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
7448 rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
7449
7450 if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
7451 burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
7452
7453 if (rate < policer_item->policer->min_rate) {
7454 NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
7455 return -EINVAL;
7456 }
7457
7458 if (rate > policer_item->policer->max_rate) {
7459 NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
7460 return -EINVAL;
7461 }
7462
7463 if (burst < policer_item->policer->min_burst) {
7464 NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
7465 return -EINVAL;
7466 }
7467
7468 if (burst > policer_item->policer->max_burst) {
7469 NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
7470 return -EINVAL;
7471 }
7472
7473 err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
7474 rate, burst, info->extack);
7475 if (err)
7476 return err;
7477
7478 policer_item->rate = rate;
7479 policer_item->burst = burst;
7480
7481 return 0;
7482}
7483
7484static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
7485 struct genl_info *info)
7486{
7487 struct devlink_trap_policer_item *policer_item;
7488 struct netlink_ext_ack *extack = info->extack;
7489 struct devlink *devlink = info->user_ptr[0];
7490
7491 if (list_empty(&devlink->trap_policer_list))
7492 return -EOPNOTSUPP;
7493
7494 if (!devlink->ops->trap_policer_set)
7495 return -EOPNOTSUPP;
7496
7497 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
7498 if (!policer_item) {
7499 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7500 return -ENOENT;
7501 }
7502
7503 return devlink_trap_policer_set(devlink, policer_item, info);
7504}
7505
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007506static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007507 [DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
7508 DEVLINK_ATTR_TRAP_POLICER_ID },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007509 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
7510 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
7511 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
Parav Panditc49a9442020-09-21 19:41:30 +03007512 [DEVLINK_ATTR_PORT_TYPE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_PORT_TYPE_AUTO,
7513 DEVLINK_PORT_TYPE_IB),
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007514 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02007515 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
7516 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
7517 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
7518 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
7519 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
7520 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
7521 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Parav Panditba356c92020-09-21 19:41:29 +03007522 [DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_ESWITCH_MODE_LEGACY,
7523 DEVLINK_ESWITCH_MODE_SWITCHDEV),
Roi Dayan59bfde02016-11-22 23:09:57 +02007524 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03007525 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007526 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
7527 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007528 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
7529 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007530 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
7531 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
7532 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007533 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03007534 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Jakub Kicinskiff3b63b2020-03-02 21:05:12 -08007535 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
7536 [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007537 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007538 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
7539 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007540 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
7541 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Jacob Keller5d5b4122020-09-25 13:46:07 -07007542 [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] =
7543 NLA_POLICY_BITFIELD32(DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS),
Ido Schimmel0f420b62019-08-17 16:28:17 +03007544 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
7545 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
7546 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
Jiri Pirko070c63f2019-10-03 11:49:39 +02007547 [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
7548 [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
7549 [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03007550 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007551 [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
7552 [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
7553 [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
Parav Pandita1e8ae92020-06-19 03:32:49 +00007554 [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007555 [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
7556 DEVLINK_RELOAD_ACTION_MAX),
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03007557 [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK),
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007558};
7559
Jakub Kicinski66a9b922020-10-02 14:49:54 -07007560static const struct genl_small_ops devlink_nl_ops[] = {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007561 {
7562 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007563 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007564 .doit = devlink_nl_cmd_get_doit,
7565 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007566 /* can be retrieved by unprivileged users */
7567 },
7568 {
7569 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007570 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007571 .doit = devlink_nl_cmd_port_get_doit,
7572 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007573 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7574 /* can be retrieved by unprivileged users */
7575 },
7576 {
7577 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007578 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007579 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007580 .flags = GENL_ADMIN_PERM,
7581 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7582 },
7583 {
7584 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007585 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007586 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007587 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007588 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007589 },
7590 {
7591 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007592 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007593 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007594 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007595 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007596 },
Jiri Pirkobf797472016-04-14 18:19:13 +02007597 {
7598 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007599 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007600 .doit = devlink_nl_cmd_sb_get_doit,
7601 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007602 /* can be retrieved by unprivileged users */
7603 },
7604 {
7605 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007606 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007607 .doit = devlink_nl_cmd_sb_pool_get_doit,
7608 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007609 /* can be retrieved by unprivileged users */
7610 },
7611 {
7612 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007613 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007614 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007615 .flags = GENL_ADMIN_PERM,
Jiri Pirkobf797472016-04-14 18:19:13 +02007616 },
7617 {
7618 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007619 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007620 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
7621 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Parav Pandit637989b2020-07-22 18:57:11 +03007622 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007623 /* can be retrieved by unprivileged users */
7624 },
7625 {
7626 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007627 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007628 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007629 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007630 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007631 },
7632 {
7633 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007634 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007635 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
7636 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Parav Pandit637989b2020-07-22 18:57:11 +03007637 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007638 /* can be retrieved by unprivileged users */
7639 },
7640 {
7641 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007642 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007643 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007644 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007645 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007646 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007647 {
7648 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007649 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007650 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007651 .flags = GENL_ADMIN_PERM,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007652 },
7653 {
7654 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007655 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007656 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007657 .flags = GENL_ADMIN_PERM,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007658 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03007659 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007660 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007661 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007662 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007663 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007664 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007665 },
7666 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007667 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007668 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007669 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007670 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007671 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007672 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007673 {
7674 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007675 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007676 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007677 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007678 },
7679 {
7680 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007681 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007682 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007683 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007684 },
7685 {
7686 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007687 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007688 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007689 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007690 },
7691 {
7692 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007693 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007694 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007695 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007696 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007697 {
7698 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007699 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007700 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007701 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007702 },
7703 {
7704 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02007705 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007706 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007707 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007708 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007709 {
7710 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02007711 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007712 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007713 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007714 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007715 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007716 {
7717 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007718 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007719 .doit = devlink_nl_cmd_param_get_doit,
7720 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007721 /* can be retrieved by unprivileged users */
7722 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007723 {
7724 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007725 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007726 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007727 .flags = GENL_ADMIN_PERM,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007728 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007729 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307730 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007731 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307732 .doit = devlink_nl_cmd_port_param_get_doit,
7733 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307734 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7735 /* can be retrieved by unprivileged users */
7736 },
7737 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05307738 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007739 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307740 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307741 .flags = GENL_ADMIN_PERM,
7742 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7743 },
7744 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007745 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007746 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007747 .doit = devlink_nl_cmd_region_get_doit,
7748 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007749 .flags = GENL_ADMIN_PERM,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007750 },
Alex Vesker866319b2018-07-12 15:13:13 +03007751 {
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07007752 .cmd = DEVLINK_CMD_REGION_NEW,
7753 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7754 .doit = devlink_nl_cmd_region_new,
7755 .flags = GENL_ADMIN_PERM,
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07007756 },
7757 {
Alex Vesker866319b2018-07-12 15:13:13 +03007758 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02007759 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03007760 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03007761 .flags = GENL_ADMIN_PERM,
Alex Vesker866319b2018-07-12 15:13:13 +03007762 },
Alex Vesker4e547952018-07-12 15:13:14 +03007763 {
7764 .cmd = DEVLINK_CMD_REGION_READ,
Jiri Pirkoee85da52019-10-05 20:04:42 +02007765 .validate = GENL_DONT_VALIDATE_STRICT |
7766 GENL_DONT_VALIDATE_DUMP_STRICT,
Alex Vesker4e547952018-07-12 15:13:14 +03007767 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03007768 .flags = GENL_ADMIN_PERM,
Alex Vesker4e547952018-07-12 15:13:14 +03007769 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007770 {
7771 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007772 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007773 .doit = devlink_nl_cmd_info_get_doit,
7774 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007775 /* can be retrieved by unprivileged users */
7776 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007777 {
7778 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007779 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007780 .doit = devlink_nl_cmd_health_reporter_get_doit,
7781 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007782 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007783 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007784 /* can be retrieved by unprivileged users */
7785 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007786 {
7787 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007788 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007789 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007790 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007791 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007792 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007793 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007794 {
7795 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02007796 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007797 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007798 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007799 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007800 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007801 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007802 {
7803 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007804 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007805 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007806 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007807 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007808 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007809 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007810 {
7811 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Jiri Pirko82a843d2019-10-07 09:28:31 +02007812 .validate = GENL_DONT_VALIDATE_STRICT |
7813 GENL_DONT_VALIDATE_DUMP_STRICT,
Aya Levine44ef4e2019-05-16 09:49:20 +03007814 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007815 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007816 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007817 DEVLINK_NL_FLAG_NO_LOCK,
7818 },
7819 {
7820 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007821 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007822 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007823 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007824 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007825 DEVLINK_NL_FLAG_NO_LOCK,
7826 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007827 {
Jiri Pirkoe2ce94d2020-09-15 11:40:57 +03007828 .cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST,
7829 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7830 .doit = devlink_nl_cmd_health_reporter_test_doit,
7831 .flags = GENL_ADMIN_PERM,
7832 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
7833 DEVLINK_NL_FLAG_NO_LOCK,
7834 },
7835 {
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007836 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007837 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007838 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007839 .flags = GENL_ADMIN_PERM,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007840 },
Ido Schimmel0f420b62019-08-17 16:28:17 +03007841 {
7842 .cmd = DEVLINK_CMD_TRAP_GET,
7843 .doit = devlink_nl_cmd_trap_get_doit,
7844 .dumpit = devlink_nl_cmd_trap_get_dumpit,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007845 /* can be retrieved by unprivileged users */
7846 },
7847 {
7848 .cmd = DEVLINK_CMD_TRAP_SET,
7849 .doit = devlink_nl_cmd_trap_set_doit,
7850 .flags = GENL_ADMIN_PERM,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007851 },
7852 {
7853 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
7854 .doit = devlink_nl_cmd_trap_group_get_doit,
7855 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007856 /* can be retrieved by unprivileged users */
7857 },
7858 {
7859 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
7860 .doit = devlink_nl_cmd_trap_group_set_doit,
7861 .flags = GENL_ADMIN_PERM,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007862 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007863 {
7864 .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
7865 .doit = devlink_nl_cmd_trap_policer_get_doit,
7866 .dumpit = devlink_nl_cmd_trap_policer_get_dumpit,
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007867 /* can be retrieved by unprivileged users */
7868 },
7869 {
7870 .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
7871 .doit = devlink_nl_cmd_trap_policer_set_doit,
7872 .flags = GENL_ADMIN_PERM,
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007873 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007874};
7875
Johannes Berg56989f62016-10-24 14:40:05 +02007876static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02007877 .name = DEVLINK_GENL_NAME,
7878 .version = DEVLINK_GENL_VERSION,
7879 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01007880 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02007881 .netnsok = true,
7882 .pre_doit = devlink_nl_pre_doit,
7883 .post_doit = devlink_nl_post_doit,
7884 .module = THIS_MODULE,
Jakub Kicinski66a9b922020-10-02 14:49:54 -07007885 .small_ops = devlink_nl_ops,
7886 .n_small_ops = ARRAY_SIZE(devlink_nl_ops),
Johannes Berg489111e2016-10-24 14:40:03 +02007887 .mcgrps = devlink_nl_mcgrps,
7888 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
7889};
7890
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007891static bool devlink_reload_actions_valid(const struct devlink_ops *ops)
7892{
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03007893 const struct devlink_reload_combination *comb;
7894 int i;
7895
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007896 if (!devlink_reload_supported(ops)) {
7897 if (WARN_ON(ops->reload_actions))
7898 return false;
7899 return true;
7900 }
7901
7902 if (WARN_ON(!ops->reload_actions ||
7903 ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) ||
7904 ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX)))
7905 return false;
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03007906
7907 if (WARN_ON(ops->reload_limits & BIT(DEVLINK_RELOAD_LIMIT_UNSPEC) ||
7908 ops->reload_limits >= BIT(__DEVLINK_RELOAD_LIMIT_MAX)))
7909 return false;
7910
7911 for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++) {
7912 comb = &devlink_reload_invalid_combinations[i];
7913 if (ops->reload_actions == BIT(comb->action) &&
7914 ops->reload_limits == BIT(comb->limit))
7915 return false;
7916 }
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007917 return true;
7918}
7919
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007920/**
7921 * devlink_alloc - Allocate new devlink instance resources
7922 *
7923 * @ops: ops
7924 * @priv_size: size of user private data
7925 *
7926 * Allocate new devlink instance resources, including devlink index
7927 * and name.
7928 */
7929struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
7930{
7931 struct devlink *devlink;
7932
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007933 if (WARN_ON(!ops))
7934 return NULL;
7935
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007936 if (!devlink_reload_actions_valid(ops))
7937 return NULL;
7938
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007939 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
7940 if (!devlink)
7941 return NULL;
7942 devlink->ops = ops;
Jacob Keller12102432020-03-26 11:37:15 -07007943 xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
Jiri Pirko8273fd82019-10-05 08:10:31 +02007944 __devlink_net_set(devlink, &init_net);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007945 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02007946 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007947 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007948 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03007949 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03007950 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02007951 INIT_LIST_HEAD(&devlink->reporter_list);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007952 INIT_LIST_HEAD(&devlink->trap_list);
7953 INIT_LIST_HEAD(&devlink->trap_group_list);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007954 INIT_LIST_HEAD(&devlink->trap_policer_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007955 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007956 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007957 return devlink;
7958}
7959EXPORT_SYMBOL_GPL(devlink_alloc);
7960
7961/**
7962 * devlink_register - Register devlink instance
7963 *
7964 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007965 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007966 */
7967int devlink_register(struct devlink *devlink, struct device *dev)
7968{
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007969 devlink->dev = dev;
Jiri Pirko8273fd82019-10-05 08:10:31 +02007970 devlink->registered = true;
Parav Pandit6553e562020-07-21 19:53:51 +03007971 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007972 list_add_tail(&devlink->list, &devlink_list);
7973 devlink_notify(devlink, DEVLINK_CMD_NEW);
7974 mutex_unlock(&devlink_mutex);
7975 return 0;
7976}
7977EXPORT_SYMBOL_GPL(devlink_register);
7978
7979/**
7980 * devlink_unregister - Unregister devlink instance
7981 *
7982 * @devlink: devlink
7983 */
7984void devlink_unregister(struct devlink *devlink)
7985{
7986 mutex_lock(&devlink_mutex);
Moshe Shemesh69d56e02020-10-07 09:00:42 +03007987 WARN_ON(devlink_reload_supported(devlink->ops) &&
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007988 devlink->reload_enabled);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007989 devlink_notify(devlink, DEVLINK_CMD_DEL);
7990 list_del(&devlink->list);
7991 mutex_unlock(&devlink_mutex);
7992}
7993EXPORT_SYMBOL_GPL(devlink_unregister);
7994
7995/**
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007996 * devlink_reload_enable - Enable reload of devlink instance
7997 *
7998 * @devlink: devlink
7999 *
8000 * Should be called at end of device initialization
8001 * process when reload operation is supported.
8002 */
8003void devlink_reload_enable(struct devlink *devlink)
8004{
8005 mutex_lock(&devlink_mutex);
8006 devlink->reload_enabled = true;
8007 mutex_unlock(&devlink_mutex);
8008}
8009EXPORT_SYMBOL_GPL(devlink_reload_enable);
8010
8011/**
8012 * devlink_reload_disable - Disable reload of devlink instance
8013 *
8014 * @devlink: devlink
8015 *
8016 * Should be called at the beginning of device cleanup
8017 * process when reload operation is supported.
8018 */
8019void devlink_reload_disable(struct devlink *devlink)
8020{
8021 mutex_lock(&devlink_mutex);
8022 /* Mutex is taken which ensures that no reload operation is in
8023 * progress while setting up forbidded flag.
8024 */
8025 devlink->reload_enabled = false;
8026 mutex_unlock(&devlink_mutex);
8027}
8028EXPORT_SYMBOL_GPL(devlink_reload_disable);
8029
8030/**
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008031 * devlink_free - Free devlink instance resources
8032 *
8033 * @devlink: devlink
8034 */
8035void devlink_free(struct devlink *devlink)
8036{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03008037 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01008038 mutex_destroy(&devlink->lock);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03008039 WARN_ON(!list_empty(&devlink->trap_policer_list));
Ido Schimmel0f420b62019-08-17 16:28:17 +03008040 WARN_ON(!list_empty(&devlink->trap_group_list));
8041 WARN_ON(!list_empty(&devlink->trap_list));
Parav Panditb904aad2019-02-08 15:15:00 -06008042 WARN_ON(!list_empty(&devlink->reporter_list));
8043 WARN_ON(!list_empty(&devlink->region_list));
8044 WARN_ON(!list_empty(&devlink->param_list));
8045 WARN_ON(!list_empty(&devlink->resource_list));
8046 WARN_ON(!list_empty(&devlink->dpipe_table_list));
8047 WARN_ON(!list_empty(&devlink->sb_list));
8048 WARN_ON(!list_empty(&devlink->port_list));
8049
Jacob Keller12102432020-03-26 11:37:15 -07008050 xa_destroy(&devlink->snapshot_ids);
8051
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008052 kfree(devlink);
8053}
8054EXPORT_SYMBOL_GPL(devlink_free);
8055
Jiri Pirko136bf272019-05-23 10:43:35 +02008056static void devlink_port_type_warn(struct work_struct *work)
8057{
8058 WARN(true, "Type was not set for devlink port.");
8059}
8060
8061static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
8062{
8063 /* Ignore CPU and DSA flavours. */
8064 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
Andrew Lunncf116632020-10-04 18:12:51 +02008065 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA &&
8066 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_UNUSED;
Jiri Pirko136bf272019-05-23 10:43:35 +02008067}
8068
Ido Schimmel4c582232020-01-09 19:57:41 +02008069#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
Jiri Pirko136bf272019-05-23 10:43:35 +02008070
8071static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
8072{
8073 if (!devlink_port_type_should_warn(devlink_port))
8074 return;
8075 /* Schedule a work to WARN in case driver does not set port
8076 * type within timeout.
8077 */
8078 schedule_delayed_work(&devlink_port->type_warn_dw,
8079 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
8080}
8081
8082static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
8083{
8084 if (!devlink_port_type_should_warn(devlink_port))
8085 return;
8086 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
8087}
8088
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008089/**
8090 * devlink_port_register - Register devlink port
8091 *
8092 * @devlink: devlink
8093 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008094 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008095 *
8096 * Register devlink port with provided port index. User can use
8097 * any indexing, even hw-related one. devlink_port structure
8098 * is convenient to be embedded inside user driver private structure.
8099 * Note that the caller should take care of zeroing the devlink_port
8100 * structure.
8101 */
8102int devlink_port_register(struct devlink *devlink,
8103 struct devlink_port *devlink_port,
8104 unsigned int port_index)
8105{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008106 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008107 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008108 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008109 return -EEXIST;
8110 }
8111 devlink_port->devlink = devlink;
8112 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008113 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01008114 spin_lock_init(&devlink_port->type_lock);
Parav Pandit79604c52020-08-21 22:12:20 +03008115 INIT_LIST_HEAD(&devlink_port->reporter_list);
8116 mutex_init(&devlink_port->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008117 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308118 INIT_LIST_HEAD(&devlink_port->param_list);
Andrew Lunn544e7c32020-10-04 18:12:54 +02008119 INIT_LIST_HEAD(&devlink_port->region_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008120 mutex_unlock(&devlink->lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02008121 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
8122 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008123 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
8124 return 0;
8125}
8126EXPORT_SYMBOL_GPL(devlink_port_register);
8127
8128/**
8129 * devlink_port_unregister - Unregister devlink port
8130 *
8131 * @devlink_port: devlink port
8132 */
8133void devlink_port_unregister(struct devlink_port *devlink_port)
8134{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008135 struct devlink *devlink = devlink_port->devlink;
8136
Jiri Pirko136bf272019-05-23 10:43:35 +02008137 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008138 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008139 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008140 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008141 mutex_unlock(&devlink->lock);
Parav Pandit79604c52020-08-21 22:12:20 +03008142 WARN_ON(!list_empty(&devlink_port->reporter_list));
Andrew Lunn544e7c32020-10-04 18:12:54 +02008143 WARN_ON(!list_empty(&devlink_port->region_list));
Parav Pandit79604c52020-08-21 22:12:20 +03008144 mutex_destroy(&devlink_port->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008145}
8146EXPORT_SYMBOL_GPL(devlink_port_unregister);
8147
8148static void __devlink_port_type_set(struct devlink_port *devlink_port,
8149 enum devlink_port_type type,
8150 void *type_dev)
8151{
Jiri Pirko2b239e72019-03-24 11:14:36 +01008152 if (WARN_ON(!devlink_port->registered))
8153 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02008154 devlink_port_type_warn_cancel(devlink_port);
Ido Schimmel0f420b62019-08-17 16:28:17 +03008155 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008156 devlink_port->type = type;
8157 devlink_port->type_dev = type_dev;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008158 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008159 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
8160}
8161
Jakub Kicinski3ea87ca2020-09-08 15:21:13 -07008162static void devlink_port_type_netdev_checks(struct devlink_port *devlink_port,
8163 struct net_device *netdev)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008164{
Jiri Pirko119c0b52019-04-03 14:24:27 +02008165 const struct net_device_ops *ops = netdev->netdev_ops;
8166
Jiri Pirko746364f2019-03-28 13:56:46 +01008167 /* If driver registers devlink port, it should set devlink port
8168 * attributes accordingly so the compat functions are called
8169 * and the original ops are not used.
8170 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02008171 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01008172 /* Some drivers use the same set of ndos for netdevs
8173 * that have devlink_port registered and also for
8174 * those who don't. Make sure that ndo_get_phys_port_name
8175 * returns -EOPNOTSUPP here in case it is defined.
8176 * Warn if not.
8177 */
Jiri Pirko746364f2019-03-28 13:56:46 +01008178 char name[IFNAMSIZ];
8179 int err;
8180
8181 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
8182 WARN_ON(err != -EOPNOTSUPP);
8183 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02008184 if (ops->ndo_get_port_parent_id) {
8185 /* Some drivers use the same set of ndos for netdevs
8186 * that have devlink_port registered and also for
8187 * those who don't. Make sure that ndo_get_port_parent_id
8188 * returns -EOPNOTSUPP here in case it is defined.
8189 * Warn if not.
8190 */
8191 struct netdev_phys_item_id ppid;
8192 int err;
8193
8194 err = ops->ndo_get_port_parent_id(netdev, &ppid);
8195 WARN_ON(err != -EOPNOTSUPP);
8196 }
Jakub Kicinski3ea87ca2020-09-08 15:21:13 -07008197}
8198
8199/**
8200 * devlink_port_type_eth_set - Set port type to Ethernet
8201 *
8202 * @devlink_port: devlink port
8203 * @netdev: related netdevice
8204 */
8205void devlink_port_type_eth_set(struct devlink_port *devlink_port,
8206 struct net_device *netdev)
8207{
8208 if (netdev)
8209 devlink_port_type_netdev_checks(devlink_port, netdev);
8210 else
8211 dev_warn(devlink_port->devlink->dev,
8212 "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
8213 devlink_port->index);
8214
Jiri Pirko773b1f32019-03-24 11:14:30 +01008215 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008216}
8217EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
8218
8219/**
8220 * devlink_port_type_ib_set - Set port type to InfiniBand
8221 *
8222 * @devlink_port: devlink port
8223 * @ibdev: related IB device
8224 */
8225void devlink_port_type_ib_set(struct devlink_port *devlink_port,
8226 struct ib_device *ibdev)
8227{
Jiri Pirko773b1f32019-03-24 11:14:30 +01008228 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008229}
8230EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
8231
8232/**
8233 * devlink_port_type_clear - Clear port type
8234 *
8235 * @devlink_port: devlink port
8236 */
8237void devlink_port_type_clear(struct devlink_port *devlink_port)
8238{
Jiri Pirko773b1f32019-03-24 11:14:30 +01008239 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02008240 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008241}
8242EXPORT_SYMBOL_GPL(devlink_port_type_clear);
8243
Parav Pandit378ef012019-07-08 23:17:35 -05008244static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008245 enum devlink_port_flavour flavour)
Parav Pandit378ef012019-07-08 23:17:35 -05008246{
8247 struct devlink_port_attrs *attrs = &devlink_port->attrs;
8248
8249 if (WARN_ON(devlink_port->registered))
8250 return -EEXIST;
Danielle Ratson10a429b2020-07-09 16:18:14 +03008251 devlink_port->attrs_set = true;
Parav Pandit378ef012019-07-08 23:17:35 -05008252 attrs->flavour = flavour;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008253 if (attrs->switch_id.id_len) {
Danielle Ratson46737a12020-07-09 16:18:15 +03008254 devlink_port->switch_port = true;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008255 if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
8256 attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
Parav Pandit378ef012019-07-08 23:17:35 -05008257 } else {
Danielle Ratson46737a12020-07-09 16:18:15 +03008258 devlink_port->switch_port = false;
Parav Pandit378ef012019-07-08 23:17:35 -05008259 }
8260 return 0;
8261}
8262
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008263/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02008264 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008265 *
8266 * @devlink_port: devlink port
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008267 * @attrs: devlink port attrs
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008268 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02008269void devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008270 struct devlink_port_attrs *attrs)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008271{
Parav Pandit378ef012019-07-08 23:17:35 -05008272 int ret;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02008273
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008274 devlink_port->attrs = *attrs;
8275 ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
Parav Pandit378ef012019-07-08 23:17:35 -05008276 if (ret)
Jiri Pirko45b86112019-03-24 11:14:33 +01008277 return;
Danielle Ratsona0f49b52020-07-09 16:18:20 +03008278 WARN_ON(attrs->splittable && attrs->split);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008279}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02008280EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008281
Parav Pandit98fd2d62019-07-08 23:17:37 -05008282/**
8283 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
8284 *
8285 * @devlink_port: devlink port
Parav Pandit3a2d9582020-09-09 07:50:37 +03008286 * @controller: associated controller number for the devlink port instance
Parav Pandit98fd2d62019-07-08 23:17:37 -05008287 * @pf: associated PF for the devlink port instance
Parav Pandit05b595e2020-09-09 07:50:36 +03008288 * @external: indicates if the port is for an external controller
Parav Pandit98fd2d62019-07-08 23:17:37 -05008289 */
Parav Pandit3a2d9582020-09-09 07:50:37 +03008290void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 controller,
8291 u16 pf, bool external)
Parav Pandit98fd2d62019-07-08 23:17:37 -05008292{
8293 struct devlink_port_attrs *attrs = &devlink_port->attrs;
8294 int ret;
8295
8296 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008297 DEVLINK_PORT_FLAVOUR_PCI_PF);
Parav Pandit98fd2d62019-07-08 23:17:37 -05008298 if (ret)
8299 return;
Parav Pandit3a2d9582020-09-09 07:50:37 +03008300 attrs->pci_pf.controller = controller;
Parav Pandit98fd2d62019-07-08 23:17:37 -05008301 attrs->pci_pf.pf = pf;
Parav Pandit05b595e2020-09-09 07:50:36 +03008302 attrs->pci_pf.external = external;
Parav Pandit98fd2d62019-07-08 23:17:37 -05008303}
8304EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
8305
Parav Pandite41b6bf2019-07-08 23:17:38 -05008306/**
8307 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
8308 *
8309 * @devlink_port: devlink port
Parav Pandit3a2d9582020-09-09 07:50:37 +03008310 * @controller: associated controller number for the devlink port instance
Parav Pandite41b6bf2019-07-08 23:17:38 -05008311 * @pf: associated PF for the devlink port instance
8312 * @vf: associated VF of a PF for the devlink port instance
Parav Pandit05b595e2020-09-09 07:50:36 +03008313 * @external: indicates if the port is for an external controller
Parav Pandite41b6bf2019-07-08 23:17:38 -05008314 */
Parav Pandit3a2d9582020-09-09 07:50:37 +03008315void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller,
Parav Pandit05b595e2020-09-09 07:50:36 +03008316 u16 pf, u16 vf, bool external)
Parav Pandite41b6bf2019-07-08 23:17:38 -05008317{
8318 struct devlink_port_attrs *attrs = &devlink_port->attrs;
8319 int ret;
8320
8321 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008322 DEVLINK_PORT_FLAVOUR_PCI_VF);
Parav Pandite41b6bf2019-07-08 23:17:38 -05008323 if (ret)
8324 return;
Parav Pandit3a2d9582020-09-09 07:50:37 +03008325 attrs->pci_vf.controller = controller;
Parav Pandite41b6bf2019-07-08 23:17:38 -05008326 attrs->pci_vf.pf = pf;
8327 attrs->pci_vf.vf = vf;
Parav Pandit05b595e2020-09-09 07:50:36 +03008328 attrs->pci_vf.external = external;
Parav Pandite41b6bf2019-07-08 23:17:38 -05008329}
8330EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
8331
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01008332static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
8333 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02008334{
8335 struct devlink_port_attrs *attrs = &devlink_port->attrs;
8336 int n = 0;
8337
Danielle Ratson10a429b2020-07-09 16:18:14 +03008338 if (!devlink_port->attrs_set)
Jiri Pirko08474c12018-05-18 09:29:02 +02008339 return -EOPNOTSUPP;
8340
8341 switch (attrs->flavour) {
8342 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
Parav Panditacf1ee42020-03-03 08:12:42 -06008343 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Jiri Pirko08474c12018-05-18 09:29:02 +02008344 if (!attrs->split)
Parav Pandit378ef012019-07-08 23:17:35 -05008345 n = snprintf(name, len, "p%u", attrs->phys.port_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02008346 else
Parav Pandit378ef012019-07-08 23:17:35 -05008347 n = snprintf(name, len, "p%us%u",
8348 attrs->phys.port_number,
8349 attrs->phys.split_subport_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02008350 break;
8351 case DEVLINK_PORT_FLAVOUR_CPU:
8352 case DEVLINK_PORT_FLAVOUR_DSA:
Andrew Lunncf116632020-10-04 18:12:51 +02008353 case DEVLINK_PORT_FLAVOUR_UNUSED:
Jiri Pirko08474c12018-05-18 09:29:02 +02008354 /* As CPU and DSA ports do not have a netdevice associated
8355 * case should not ever happen.
8356 */
8357 WARN_ON(1);
8358 return -EINVAL;
Parav Pandit98fd2d62019-07-08 23:17:37 -05008359 case DEVLINK_PORT_FLAVOUR_PCI_PF:
Parav Pandit66b17082020-09-09 07:50:38 +03008360 if (attrs->pci_pf.external) {
8361 n = snprintf(name, len, "c%u", attrs->pci_pf.controller);
8362 if (n >= len)
8363 return -EINVAL;
8364 len -= n;
8365 name += n;
8366 }
Parav Pandit98fd2d62019-07-08 23:17:37 -05008367 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
8368 break;
Parav Pandite41b6bf2019-07-08 23:17:38 -05008369 case DEVLINK_PORT_FLAVOUR_PCI_VF:
Parav Pandit66b17082020-09-09 07:50:38 +03008370 if (attrs->pci_vf.external) {
8371 n = snprintf(name, len, "c%u", attrs->pci_vf.controller);
8372 if (n >= len)
8373 return -EINVAL;
8374 len -= n;
8375 name += n;
8376 }
Parav Pandite41b6bf2019-07-08 23:17:38 -05008377 n = snprintf(name, len, "pf%uvf%u",
8378 attrs->pci_vf.pf, attrs->pci_vf.vf);
8379 break;
Jiri Pirko08474c12018-05-18 09:29:02 +02008380 }
8381
8382 if (n >= len)
8383 return -EINVAL;
8384
8385 return 0;
8386}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01008387
Jiri Pirkobf797472016-04-14 18:19:13 +02008388int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
8389 u32 size, u16 ingress_pools_count,
8390 u16 egress_pools_count, u16 ingress_tc_count,
8391 u16 egress_tc_count)
8392{
8393 struct devlink_sb *devlink_sb;
8394 int err = 0;
8395
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008396 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02008397 if (devlink_sb_index_exists(devlink, sb_index)) {
8398 err = -EEXIST;
8399 goto unlock;
8400 }
8401
8402 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
8403 if (!devlink_sb) {
8404 err = -ENOMEM;
8405 goto unlock;
8406 }
8407 devlink_sb->index = sb_index;
8408 devlink_sb->size = size;
8409 devlink_sb->ingress_pools_count = ingress_pools_count;
8410 devlink_sb->egress_pools_count = egress_pools_count;
8411 devlink_sb->ingress_tc_count = ingress_tc_count;
8412 devlink_sb->egress_tc_count = egress_tc_count;
8413 list_add_tail(&devlink_sb->list, &devlink->sb_list);
8414unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008415 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02008416 return err;
8417}
8418EXPORT_SYMBOL_GPL(devlink_sb_register);
8419
8420void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
8421{
8422 struct devlink_sb *devlink_sb;
8423
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008424 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02008425 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
8426 WARN_ON(!devlink_sb);
8427 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008428 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02008429 kfree(devlink_sb);
8430}
8431EXPORT_SYMBOL_GPL(devlink_sb_unregister);
8432
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008433/**
8434 * devlink_dpipe_headers_register - register dpipe headers
8435 *
8436 * @devlink: devlink
8437 * @dpipe_headers: dpipe header array
8438 *
8439 * Register the headers supported by hardware.
8440 */
8441int devlink_dpipe_headers_register(struct devlink *devlink,
8442 struct devlink_dpipe_headers *dpipe_headers)
8443{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008444 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008445 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008446 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008447 return 0;
8448}
8449EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
8450
8451/**
8452 * devlink_dpipe_headers_unregister - unregister dpipe headers
8453 *
8454 * @devlink: devlink
8455 *
8456 * Unregister the headers supported by hardware.
8457 */
8458void devlink_dpipe_headers_unregister(struct devlink *devlink)
8459{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008460 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008461 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008462 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008463}
8464EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
8465
8466/**
8467 * devlink_dpipe_table_counter_enabled - check if counter allocation
8468 * required
8469 * @devlink: devlink
8470 * @table_name: tables name
8471 *
8472 * Used by driver to check if counter allocation is required.
8473 * After counter allocation is turned on the table entries
8474 * are updated to include counter statistics.
8475 *
8476 * After that point on the driver must respect the counter
8477 * state so that each entry added to the table is added
8478 * with a counter.
8479 */
8480bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
8481 const char *table_name)
8482{
8483 struct devlink_dpipe_table *table;
8484 bool enabled;
8485
8486 rcu_read_lock();
8487 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308488 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008489 enabled = false;
8490 if (table)
8491 enabled = table->counters_enabled;
8492 rcu_read_unlock();
8493 return enabled;
8494}
8495EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
8496
8497/**
8498 * devlink_dpipe_table_register - register dpipe table
8499 *
8500 * @devlink: devlink
8501 * @table_name: table name
8502 * @table_ops: table ops
8503 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008504 * @counter_control_extern: external control for counters
8505 */
8506int devlink_dpipe_table_register(struct devlink *devlink,
8507 const char *table_name,
8508 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02008509 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008510{
8511 struct devlink_dpipe_table *table;
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308512 int err = 0;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008513
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02008514 if (WARN_ON(!table_ops->size_get))
8515 return -EINVAL;
8516
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308517 mutex_lock(&devlink->lock);
8518
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308519 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
8520 devlink)) {
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308521 err = -EEXIST;
8522 goto unlock;
8523 }
8524
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008525 table = kzalloc(sizeof(*table), GFP_KERNEL);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308526 if (!table) {
8527 err = -ENOMEM;
8528 goto unlock;
8529 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008530
8531 table->name = table_name;
8532 table->table_ops = table_ops;
8533 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008534 table->counter_control_extern = counter_control_extern;
8535
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008536 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308537unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008538 mutex_unlock(&devlink->lock);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308539 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008540}
8541EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
8542
8543/**
8544 * devlink_dpipe_table_unregister - unregister dpipe table
8545 *
8546 * @devlink: devlink
8547 * @table_name: table name
8548 */
8549void devlink_dpipe_table_unregister(struct devlink *devlink,
8550 const char *table_name)
8551{
8552 struct devlink_dpipe_table *table;
8553
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008554 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008555 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308556 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008557 if (!table)
8558 goto unlock;
8559 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008560 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008561 kfree_rcu(table, rcu);
8562 return;
8563unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008564 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008565}
8566EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
8567
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008568/**
8569 * devlink_resource_register - devlink resource register
8570 *
8571 * @devlink: devlink
8572 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008573 * @resource_size: resource's size
8574 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008575 * @parent_resource_id: resource's parent id
8576 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008577 */
8578int devlink_resource_register(struct devlink *devlink,
8579 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008580 u64 resource_size,
8581 u64 resource_id,
8582 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02008583 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008584{
8585 struct devlink_resource *resource;
8586 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07008587 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008588 int err = 0;
8589
David Ahern14530742018-03-20 19:31:14 -07008590 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
8591
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008592 mutex_lock(&devlink->lock);
8593 resource = devlink_resource_find(devlink, NULL, resource_id);
8594 if (resource) {
8595 err = -EINVAL;
8596 goto out;
8597 }
8598
8599 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
8600 if (!resource) {
8601 err = -ENOMEM;
8602 goto out;
8603 }
8604
8605 if (top_hierarchy) {
8606 resource_list = &devlink->resource_list;
8607 } else {
8608 struct devlink_resource *parent_resource;
8609
8610 parent_resource = devlink_resource_find(devlink, NULL,
8611 parent_resource_id);
8612 if (parent_resource) {
8613 resource_list = &parent_resource->resource_list;
8614 resource->parent = parent_resource;
8615 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00008616 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008617 err = -EINVAL;
8618 goto out;
8619 }
8620 }
8621
8622 resource->name = resource_name;
8623 resource->size = resource_size;
8624 resource->size_new = resource_size;
8625 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008626 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01008627 memcpy(&resource->size_params, size_params,
8628 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008629 INIT_LIST_HEAD(&resource->resource_list);
8630 list_add_tail(&resource->list, resource_list);
8631out:
8632 mutex_unlock(&devlink->lock);
8633 return err;
8634}
8635EXPORT_SYMBOL_GPL(devlink_resource_register);
8636
8637/**
8638 * devlink_resources_unregister - free all resources
8639 *
8640 * @devlink: devlink
8641 * @resource: resource
8642 */
8643void devlink_resources_unregister(struct devlink *devlink,
8644 struct devlink_resource *resource)
8645{
8646 struct devlink_resource *tmp, *child_resource;
8647 struct list_head *resource_list;
8648
8649 if (resource)
8650 resource_list = &resource->resource_list;
8651 else
8652 resource_list = &devlink->resource_list;
8653
8654 if (!resource)
8655 mutex_lock(&devlink->lock);
8656
8657 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
8658 devlink_resources_unregister(devlink, child_resource);
8659 list_del(&child_resource->list);
8660 kfree(child_resource);
8661 }
8662
8663 if (!resource)
8664 mutex_unlock(&devlink->lock);
8665}
8666EXPORT_SYMBOL_GPL(devlink_resources_unregister);
8667
8668/**
8669 * devlink_resource_size_get - get and update size
8670 *
8671 * @devlink: devlink
8672 * @resource_id: the requested resource id
8673 * @p_resource_size: ptr to update
8674 */
8675int devlink_resource_size_get(struct devlink *devlink,
8676 u64 resource_id,
8677 u64 *p_resource_size)
8678{
8679 struct devlink_resource *resource;
8680 int err = 0;
8681
8682 mutex_lock(&devlink->lock);
8683 resource = devlink_resource_find(devlink, NULL, resource_id);
8684 if (!resource) {
8685 err = -EINVAL;
8686 goto out;
8687 }
8688 *p_resource_size = resource->size_new;
8689 resource->size = resource->size_new;
8690out:
8691 mutex_unlock(&devlink->lock);
8692 return err;
8693}
8694EXPORT_SYMBOL_GPL(devlink_resource_size_get);
8695
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008696/**
8697 * devlink_dpipe_table_resource_set - set the resource id
8698 *
8699 * @devlink: devlink
8700 * @table_name: table name
8701 * @resource_id: resource id
8702 * @resource_units: number of resource's units consumed per table's entry
8703 */
8704int devlink_dpipe_table_resource_set(struct devlink *devlink,
8705 const char *table_name, u64 resource_id,
8706 u64 resource_units)
8707{
8708 struct devlink_dpipe_table *table;
8709 int err = 0;
8710
8711 mutex_lock(&devlink->lock);
8712 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308713 table_name, devlink);
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008714 if (!table) {
8715 err = -EINVAL;
8716 goto out;
8717 }
8718 table->resource_id = resource_id;
8719 table->resource_units = resource_units;
8720 table->resource_valid = true;
8721out:
8722 mutex_unlock(&devlink->lock);
8723 return err;
8724}
8725EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
8726
Jiri Pirkofc56be42018-04-05 22:13:21 +02008727/**
8728 * devlink_resource_occ_get_register - register occupancy getter
8729 *
8730 * @devlink: devlink
8731 * @resource_id: resource id
8732 * @occ_get: occupancy getter callback
8733 * @occ_get_priv: occupancy getter callback priv
8734 */
8735void devlink_resource_occ_get_register(struct devlink *devlink,
8736 u64 resource_id,
8737 devlink_resource_occ_get_t *occ_get,
8738 void *occ_get_priv)
8739{
8740 struct devlink_resource *resource;
8741
8742 mutex_lock(&devlink->lock);
8743 resource = devlink_resource_find(devlink, NULL, resource_id);
8744 if (WARN_ON(!resource))
8745 goto out;
8746 WARN_ON(resource->occ_get);
8747
8748 resource->occ_get = occ_get;
8749 resource->occ_get_priv = occ_get_priv;
8750out:
8751 mutex_unlock(&devlink->lock);
8752}
8753EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
8754
8755/**
8756 * devlink_resource_occ_get_unregister - unregister occupancy getter
8757 *
8758 * @devlink: devlink
8759 * @resource_id: resource id
8760 */
8761void devlink_resource_occ_get_unregister(struct devlink *devlink,
8762 u64 resource_id)
8763{
8764 struct devlink_resource *resource;
8765
8766 mutex_lock(&devlink->lock);
8767 resource = devlink_resource_find(devlink, NULL, resource_id);
8768 if (WARN_ON(!resource))
8769 goto out;
8770 WARN_ON(!resource->occ_get);
8771
8772 resource->occ_get = NULL;
8773 resource->occ_get_priv = NULL;
8774out:
8775 mutex_unlock(&devlink->lock);
8776}
8777EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
8778
Vasundhara Volam39e61602019-01-28 18:00:20 +05308779static int devlink_param_verify(const struct devlink_param *param)
8780{
8781 if (!param || !param->name || !param->supported_cmodes)
8782 return -EINVAL;
8783 if (param->generic)
8784 return devlink_param_generic_verify(param);
8785 else
8786 return devlink_param_driver_verify(param);
8787}
8788
8789static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308790 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308791 struct list_head *param_list,
8792 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308793 size_t params_count,
8794 enum devlink_command reg_cmd,
8795 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308796{
8797 const struct devlink_param *param = params;
8798 int i;
8799 int err;
8800
8801 mutex_lock(&devlink->lock);
8802 for (i = 0; i < params_count; i++, param++) {
8803 err = devlink_param_verify(param);
8804 if (err)
8805 goto rollback;
8806
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308807 err = devlink_param_register_one(devlink, port_index,
8808 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308809 if (err)
8810 goto rollback;
8811 }
8812
8813 mutex_unlock(&devlink->lock);
8814 return 0;
8815
8816rollback:
8817 if (!i)
8818 goto unlock;
8819 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308820 devlink_param_unregister_one(devlink, port_index, param_list,
8821 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308822unlock:
8823 mutex_unlock(&devlink->lock);
8824 return err;
8825}
8826
8827static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308828 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308829 struct list_head *param_list,
8830 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308831 size_t params_count,
8832 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308833{
8834 const struct devlink_param *param = params;
8835 int i;
8836
8837 mutex_lock(&devlink->lock);
8838 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308839 devlink_param_unregister_one(devlink, 0, param_list, param,
8840 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308841 mutex_unlock(&devlink->lock);
8842}
8843
Moshe Shemesheabaef12018-07-04 14:30:28 +03008844/**
8845 * devlink_params_register - register configuration parameters
8846 *
8847 * @devlink: devlink
8848 * @params: configuration parameters array
8849 * @params_count: number of parameters provided
8850 *
8851 * Register the configuration parameters supported by the driver.
8852 */
8853int devlink_params_register(struct devlink *devlink,
8854 const struct devlink_param *params,
8855 size_t params_count)
8856{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308857 return __devlink_params_register(devlink, 0, &devlink->param_list,
8858 params, params_count,
8859 DEVLINK_CMD_PARAM_NEW,
8860 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008861}
8862EXPORT_SYMBOL_GPL(devlink_params_register);
8863
8864/**
8865 * devlink_params_unregister - unregister configuration parameters
8866 * @devlink: devlink
8867 * @params: configuration parameters to unregister
8868 * @params_count: number of parameters provided
8869 */
8870void devlink_params_unregister(struct devlink *devlink,
8871 const struct devlink_param *params,
8872 size_t params_count)
8873{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308874 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
8875 params, params_count,
8876 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008877}
8878EXPORT_SYMBOL_GPL(devlink_params_unregister);
8879
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008880/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00008881 * devlink_params_publish - publish configuration parameters
8882 *
8883 * @devlink: devlink
8884 *
8885 * Publish previously registered configuration parameters.
8886 */
8887void devlink_params_publish(struct devlink *devlink)
8888{
8889 struct devlink_param_item *param_item;
8890
8891 list_for_each_entry(param_item, &devlink->param_list, list) {
8892 if (param_item->published)
8893 continue;
8894 param_item->published = true;
8895 devlink_param_notify(devlink, 0, param_item,
8896 DEVLINK_CMD_PARAM_NEW);
8897 }
8898}
8899EXPORT_SYMBOL_GPL(devlink_params_publish);
8900
8901/**
8902 * devlink_params_unpublish - unpublish configuration parameters
8903 *
8904 * @devlink: devlink
8905 *
8906 * Unpublish previously registered configuration parameters.
8907 */
8908void devlink_params_unpublish(struct devlink *devlink)
8909{
8910 struct devlink_param_item *param_item;
8911
8912 list_for_each_entry(param_item, &devlink->param_list, list) {
8913 if (!param_item->published)
8914 continue;
8915 param_item->published = false;
8916 devlink_param_notify(devlink, 0, param_item,
8917 DEVLINK_CMD_PARAM_DEL);
8918 }
8919}
8920EXPORT_SYMBOL_GPL(devlink_params_unpublish);
8921
8922/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05308923 * devlink_port_params_register - register port configuration parameters
8924 *
8925 * @devlink_port: devlink port
8926 * @params: configuration parameters array
8927 * @params_count: number of parameters provided
8928 *
8929 * Register the configuration parameters supported by the port.
8930 */
8931int devlink_port_params_register(struct devlink_port *devlink_port,
8932 const struct devlink_param *params,
8933 size_t params_count)
8934{
8935 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308936 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308937 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308938 params_count,
8939 DEVLINK_CMD_PORT_PARAM_NEW,
8940 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308941}
8942EXPORT_SYMBOL_GPL(devlink_port_params_register);
8943
8944/**
8945 * devlink_port_params_unregister - unregister port configuration
8946 * parameters
8947 *
8948 * @devlink_port: devlink port
8949 * @params: configuration parameters array
8950 * @params_count: number of parameters provided
8951 */
8952void devlink_port_params_unregister(struct devlink_port *devlink_port,
8953 const struct devlink_param *params,
8954 size_t params_count)
8955{
8956 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308957 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308958 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308959 params, params_count,
8960 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308961}
8962EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
8963
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308964static int
8965__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
8966 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008967{
8968 struct devlink_param_item *param_item;
8969
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308970 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008971 if (!param_item)
8972 return -EINVAL;
8973
8974 if (!param_item->driverinit_value_valid ||
8975 !devlink_param_cmode_is_supported(param_item->param,
8976 DEVLINK_PARAM_CMODE_DRIVERINIT))
8977 return -EOPNOTSUPP;
8978
Moshe Shemesh12765342018-10-10 16:09:26 +03008979 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8980 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
8981 else
8982 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008983
8984 return 0;
8985}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308986
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308987static int
8988__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308989 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308990 struct list_head *param_list, u32 param_id,
8991 union devlink_param_value init_val,
8992 enum devlink_command cmd)
8993{
8994 struct devlink_param_item *param_item;
8995
8996 param_item = devlink_param_find_by_id(param_list, param_id);
8997 if (!param_item)
8998 return -EINVAL;
8999
9000 if (!devlink_param_cmode_is_supported(param_item->param,
9001 DEVLINK_PARAM_CMODE_DRIVERINIT))
9002 return -EOPNOTSUPP;
9003
9004 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
9005 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
9006 else
9007 param_item->driverinit_value = init_val;
9008 param_item->driverinit_value_valid = true;
9009
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309010 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309011 return 0;
9012}
9013
Vasundhara Volamffd19b92019-01-28 18:00:23 +05309014/**
9015 * devlink_param_driverinit_value_get - get configuration parameter
9016 * value for driver initializing
9017 *
9018 * @devlink: devlink
9019 * @param_id: parameter ID
9020 * @init_val: value of parameter in driverinit configuration mode
9021 *
9022 * This function should be used by the driver to get driverinit
9023 * configuration for initialization after reload command.
9024 */
9025int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
9026 union devlink_param_value *init_val)
9027{
Moshe Shemesh69d56e02020-10-07 09:00:42 +03009028 if (!devlink_reload_supported(devlink->ops))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05309029 return -EOPNOTSUPP;
9030
9031 return __devlink_param_driverinit_value_get(&devlink->param_list,
9032 param_id, init_val);
9033}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03009034EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
9035
9036/**
9037 * devlink_param_driverinit_value_set - set value of configuration
9038 * parameter for driverinit
9039 * configuration mode
9040 *
9041 * @devlink: devlink
9042 * @param_id: parameter ID
9043 * @init_val: value of parameter to set for driverinit configuration mode
9044 *
9045 * This function should be used by the driver to set driverinit
9046 * configuration mode default value.
9047 */
9048int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
9049 union devlink_param_value init_val)
9050{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309051 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309052 &devlink->param_list,
9053 param_id, init_val,
9054 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03009055}
9056EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
9057
Moshe Shemeshea601e12018-07-04 14:30:32 +03009058/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05309059 * devlink_port_param_driverinit_value_get - get configuration parameter
9060 * value for driver initializing
9061 *
9062 * @devlink_port: devlink_port
9063 * @param_id: parameter ID
9064 * @init_val: value of parameter in driverinit configuration mode
9065 *
9066 * This function should be used by the driver to get driverinit
9067 * configuration for initialization after reload command.
9068 */
9069int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
9070 u32 param_id,
9071 union devlink_param_value *init_val)
9072{
9073 struct devlink *devlink = devlink_port->devlink;
9074
Moshe Shemesh69d56e02020-10-07 09:00:42 +03009075 if (!devlink_reload_supported(devlink->ops))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05309076 return -EOPNOTSUPP;
9077
9078 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
9079 param_id, init_val);
9080}
9081EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
9082
9083/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309084 * devlink_port_param_driverinit_value_set - set value of configuration
9085 * parameter for driverinit
9086 * configuration mode
9087 *
9088 * @devlink_port: devlink_port
9089 * @param_id: parameter ID
9090 * @init_val: value of parameter to set for driverinit configuration mode
9091 *
9092 * This function should be used by the driver to set driverinit
9093 * configuration mode default value.
9094 */
9095int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
9096 u32 param_id,
9097 union devlink_param_value init_val)
9098{
9099 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309100 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309101 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309102 param_id, init_val,
9103 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309104}
9105EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
9106
9107/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03009108 * devlink_param_value_changed - notify devlink on a parameter's value
9109 * change. Should be called by the driver
9110 * right after the change.
9111 *
9112 * @devlink: devlink
9113 * @param_id: parameter ID
9114 *
9115 * This function should be used by the driver to notify devlink on value
9116 * change, excluding driverinit configuration mode.
9117 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03009118 */
9119void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
9120{
9121 struct devlink_param_item *param_item;
9122
9123 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
9124 WARN_ON(!param_item);
9125
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309126 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03009127}
9128EXPORT_SYMBOL_GPL(devlink_param_value_changed);
9129
Alex Veskerb16ebe92018-07-12 15:13:08 +03009130/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309131 * devlink_port_param_value_changed - notify devlink on a parameter's value
9132 * change. Should be called by the driver
9133 * right after the change.
9134 *
9135 * @devlink_port: devlink_port
9136 * @param_id: parameter ID
9137 *
9138 * This function should be used by the driver to notify devlink on value
9139 * change, excluding driverinit configuration mode.
9140 * For driverinit configuration mode driver should use the function
9141 * devlink_port_param_driverinit_value_set() instead.
9142 */
9143void devlink_port_param_value_changed(struct devlink_port *devlink_port,
9144 u32 param_id)
9145{
9146 struct devlink_param_item *param_item;
9147
9148 param_item = devlink_param_find_by_id(&devlink_port->param_list,
9149 param_id);
9150 WARN_ON(!param_item);
9151
9152 devlink_param_notify(devlink_port->devlink, devlink_port->index,
9153 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
9154}
9155EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
9156
9157/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03009158 * devlink_param_value_str_fill - Safely fill-up the string preventing
9159 * from overflow of the preallocated buffer
9160 *
9161 * @dst_val: destination devlink_param_value
9162 * @src: source buffer
9163 */
9164void devlink_param_value_str_fill(union devlink_param_value *dst_val,
9165 const char *src)
9166{
9167 size_t len;
9168
9169 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
9170 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
9171}
9172EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
9173
9174/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03009175 * devlink_region_create - create a new address region
9176 *
9177 * @devlink: devlink
Jacob Kellere8937682020-03-26 11:37:08 -07009178 * @ops: region operations and name
Alex Veskerb16ebe92018-07-12 15:13:08 +03009179 * @region_max_snapshots: Maximum supported number of snapshots for region
9180 * @region_size: size of region
9181 */
Jacob Kellere8937682020-03-26 11:37:08 -07009182struct devlink_region *
9183devlink_region_create(struct devlink *devlink,
9184 const struct devlink_region_ops *ops,
9185 u32 region_max_snapshots, u64 region_size)
Alex Veskerb16ebe92018-07-12 15:13:08 +03009186{
9187 struct devlink_region *region;
9188 int err = 0;
9189
Jacob Kellera0a09f62020-03-26 11:37:09 -07009190 if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
9191 return ERR_PTR(-EINVAL);
9192
Alex Veskerb16ebe92018-07-12 15:13:08 +03009193 mutex_lock(&devlink->lock);
9194
Jacob Kellere8937682020-03-26 11:37:08 -07009195 if (devlink_region_get_by_name(devlink, ops->name)) {
Alex Veskerb16ebe92018-07-12 15:13:08 +03009196 err = -EEXIST;
9197 goto unlock;
9198 }
9199
9200 region = kzalloc(sizeof(*region), GFP_KERNEL);
9201 if (!region) {
9202 err = -ENOMEM;
9203 goto unlock;
9204 }
9205
9206 region->devlink = devlink;
9207 region->max_snapshots = region_max_snapshots;
Jacob Kellere8937682020-03-26 11:37:08 -07009208 region->ops = ops;
Alex Veskerb16ebe92018-07-12 15:13:08 +03009209 region->size = region_size;
9210 INIT_LIST_HEAD(&region->snapshot_list);
9211 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03009212 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03009213
9214 mutex_unlock(&devlink->lock);
9215 return region;
9216
9217unlock:
9218 mutex_unlock(&devlink->lock);
9219 return ERR_PTR(err);
9220}
9221EXPORT_SYMBOL_GPL(devlink_region_create);
9222
9223/**
Andrew Lunn544e7c32020-10-04 18:12:54 +02009224 * devlink_port_region_create - create a new address region for a port
9225 *
9226 * @port: devlink port
9227 * @ops: region operations and name
9228 * @region_max_snapshots: Maximum supported number of snapshots for region
9229 * @region_size: size of region
9230 */
9231struct devlink_region *
9232devlink_port_region_create(struct devlink_port *port,
9233 const struct devlink_port_region_ops *ops,
9234 u32 region_max_snapshots, u64 region_size)
9235{
9236 struct devlink *devlink = port->devlink;
9237 struct devlink_region *region;
9238 int err = 0;
9239
9240 if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
9241 return ERR_PTR(-EINVAL);
9242
9243 mutex_lock(&devlink->lock);
9244
9245 if (devlink_port_region_get_by_name(port, ops->name)) {
9246 err = -EEXIST;
9247 goto unlock;
9248 }
9249
9250 region = kzalloc(sizeof(*region), GFP_KERNEL);
9251 if (!region) {
9252 err = -ENOMEM;
9253 goto unlock;
9254 }
9255
9256 region->devlink = devlink;
9257 region->port = port;
9258 region->max_snapshots = region_max_snapshots;
9259 region->port_ops = ops;
9260 region->size = region_size;
9261 INIT_LIST_HEAD(&region->snapshot_list);
9262 list_add_tail(&region->list, &port->region_list);
9263 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
9264
9265 mutex_unlock(&devlink->lock);
9266 return region;
9267
9268unlock:
9269 mutex_unlock(&devlink->lock);
9270 return ERR_PTR(err);
9271}
9272EXPORT_SYMBOL_GPL(devlink_port_region_create);
9273
9274/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03009275 * devlink_region_destroy - destroy address region
9276 *
9277 * @region: devlink region to destroy
9278 */
9279void devlink_region_destroy(struct devlink_region *region)
9280{
9281 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03009282 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03009283
9284 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03009285
9286 /* Free all snapshots of region */
9287 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
Jiri Pirko92b49822019-08-12 14:28:31 +02009288 devlink_region_snapshot_del(region, snapshot);
Alex Veskerd7e52722018-07-12 15:13:10 +03009289
Alex Veskerb16ebe92018-07-12 15:13:08 +03009290 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03009291
9292 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03009293 mutex_unlock(&devlink->lock);
9294 kfree(region);
9295}
9296EXPORT_SYMBOL_GPL(devlink_region_destroy);
9297
Alex Veskerccadfa42018-07-12 15:13:09 +03009298/**
Jacob Kellerb0efcae2020-01-09 11:08:20 -08009299 * devlink_region_snapshot_id_get - get snapshot ID
Alex Veskerccadfa42018-07-12 15:13:09 +03009300 *
9301 * This callback should be called when adding a new snapshot,
9302 * Driver should use the same id for multiple snapshots taken
9303 * on multiple regions at the same time/by the same trigger.
9304 *
Jacob Keller12102432020-03-26 11:37:15 -07009305 * The caller of this function must use devlink_region_snapshot_id_put
9306 * when finished creating regions using this id.
9307 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07009308 * Returns zero on success, or a negative error code on failure.
9309 *
Alex Veskerccadfa42018-07-12 15:13:09 +03009310 * @devlink: devlink
Jacob Keller7ef19d32020-03-26 11:37:14 -07009311 * @id: storage to return id
Alex Veskerccadfa42018-07-12 15:13:09 +03009312 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07009313int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Alex Veskerccadfa42018-07-12 15:13:09 +03009314{
Jacob Keller7ef19d32020-03-26 11:37:14 -07009315 int err;
Alex Veskerccadfa42018-07-12 15:13:09 +03009316
9317 mutex_lock(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07009318 err = __devlink_region_snapshot_id_get(devlink, id);
Alex Veskerccadfa42018-07-12 15:13:09 +03009319 mutex_unlock(&devlink->lock);
9320
Jacob Keller7ef19d32020-03-26 11:37:14 -07009321 return err;
Alex Veskerccadfa42018-07-12 15:13:09 +03009322}
Jacob Kellerb0efcae2020-01-09 11:08:20 -08009323EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
Alex Veskerccadfa42018-07-12 15:13:09 +03009324
Alex Veskerd7e52722018-07-12 15:13:10 +03009325/**
Jacob Keller12102432020-03-26 11:37:15 -07009326 * devlink_region_snapshot_id_put - put snapshot ID reference
9327 *
9328 * This should be called by a driver after finishing creating snapshots
9329 * with an id. Doing so ensures that the ID can later be released in the
9330 * event that all snapshots using it have been destroyed.
9331 *
9332 * @devlink: devlink
9333 * @id: id to release reference on
9334 */
9335void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
9336{
9337 mutex_lock(&devlink->lock);
9338 __devlink_snapshot_id_decrement(devlink, id);
9339 mutex_unlock(&devlink->lock);
9340}
9341EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
9342
9343/**
Alex Veskerd7e52722018-07-12 15:13:10 +03009344 * devlink_region_snapshot_create - create a new snapshot
9345 * This will add a new snapshot of a region. The snapshot
9346 * will be stored on the region struct and can be accessed
Jacob Keller6d82f672020-03-26 11:37:10 -07009347 * from devlink. This is useful for future analyses of snapshots.
Alex Veskerd7e52722018-07-12 15:13:10 +03009348 * Multiple snapshots can be created on a region.
9349 * The @snapshot_id should be obtained using the getter function.
9350 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08009351 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03009352 * @data: snapshot data
9353 * @snapshot_id: snapshot id to be created
Alex Veskerd7e52722018-07-12 15:13:10 +03009354 */
Jiri Pirko3a5e5232019-08-09 15:27:15 +02009355int devlink_region_snapshot_create(struct devlink_region *region,
Jacob Kellera0a09f62020-03-26 11:37:09 -07009356 u8 *data, u32 snapshot_id)
Alex Veskerd7e52722018-07-12 15:13:10 +03009357{
9358 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03009359 int err;
9360
9361 mutex_lock(&devlink->lock);
Jacob Kellercf80fae2020-03-26 11:37:11 -07009362 err = __devlink_region_snapshot_create(region, data, snapshot_id);
Alex Veskerd7e52722018-07-12 15:13:10 +03009363 mutex_unlock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03009364
Alex Veskerd7e52722018-07-12 15:13:10 +03009365 return err;
9366}
9367EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
9368
Ido Schimmel0f420b62019-08-17 16:28:17 +03009369#define DEVLINK_TRAP(_id, _type) \
9370 { \
9371 .type = DEVLINK_TRAP_TYPE_##_type, \
9372 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
9373 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
9374 }
9375
9376static const struct devlink_trap devlink_trap_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03009377 DEVLINK_TRAP(SMAC_MC, DROP),
9378 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
9379 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
9380 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
9381 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
9382 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
9383 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
9384 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
9385 DEVLINK_TRAP(TAIL_DROP, DROP),
Amit Cohen6896cc42019-11-07 18:42:09 +02009386 DEVLINK_TRAP(NON_IP_PACKET, DROP),
9387 DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
9388 DEVLINK_TRAP(DIP_LB, DROP),
9389 DEVLINK_TRAP(SIP_MC, DROP),
9390 DEVLINK_TRAP(SIP_LB, DROP),
9391 DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
9392 DEVLINK_TRAP(IPV4_SIP_BC, DROP),
9393 DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
9394 DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
Amit Cohen3b063ae2019-11-07 18:42:14 +02009395 DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
9396 DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
9397 DEVLINK_TRAP(RPF, EXCEPTION),
9398 DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
9399 DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
9400 DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
Amit Cohen95f0ead2020-01-19 15:00:48 +02009401 DEVLINK_TRAP(NON_ROUTABLE, DROP),
Amit Cohen13c056e2020-01-19 15:00:54 +02009402 DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
Amit Cohenc3cae492020-01-19 15:00:58 +02009403 DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01009404 DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
9405 DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
Ido Schimmel515eac62020-05-29 21:36:41 +03009406 DEVLINK_TRAP(STP, CONTROL),
9407 DEVLINK_TRAP(LACP, CONTROL),
9408 DEVLINK_TRAP(LLDP, CONTROL),
9409 DEVLINK_TRAP(IGMP_QUERY, CONTROL),
9410 DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
9411 DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
9412 DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
9413 DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
9414 DEVLINK_TRAP(MLD_QUERY, CONTROL),
9415 DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
9416 DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
9417 DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03009418 DEVLINK_TRAP(IPV4_DHCP, CONTROL),
9419 DEVLINK_TRAP(IPV6_DHCP, CONTROL),
9420 DEVLINK_TRAP(ARP_REQUEST, CONTROL),
9421 DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
9422 DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
9423 DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
9424 DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
9425 DEVLINK_TRAP(IPV4_BFD, CONTROL),
9426 DEVLINK_TRAP(IPV6_BFD, CONTROL),
9427 DEVLINK_TRAP(IPV4_OSPF, CONTROL),
9428 DEVLINK_TRAP(IPV6_OSPF, CONTROL),
9429 DEVLINK_TRAP(IPV4_BGP, CONTROL),
9430 DEVLINK_TRAP(IPV6_BGP, CONTROL),
9431 DEVLINK_TRAP(IPV4_VRRP, CONTROL),
9432 DEVLINK_TRAP(IPV6_VRRP, CONTROL),
9433 DEVLINK_TRAP(IPV4_PIM, CONTROL),
9434 DEVLINK_TRAP(IPV6_PIM, CONTROL),
9435 DEVLINK_TRAP(UC_LB, CONTROL),
9436 DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
9437 DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
9438 DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
9439 DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
9440 DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
9441 DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
9442 DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
9443 DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
9444 DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
9445 DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
9446 DEVLINK_TRAP(PTP_EVENT, CONTROL),
9447 DEVLINK_TRAP(PTP_GENERAL, CONTROL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03009448 DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
9449 DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
Amit Cohen08e335f2020-08-03 19:11:33 +03009450 DEVLINK_TRAP(EARLY_DROP, DROP),
Ioana Ciornei10c24eb2020-10-01 18:11:45 +03009451 DEVLINK_TRAP(VXLAN_PARSING, DROP),
9452 DEVLINK_TRAP(LLC_SNAP_PARSING, DROP),
9453 DEVLINK_TRAP(VLAN_PARSING, DROP),
9454 DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP),
9455 DEVLINK_TRAP(MPLS_PARSING, DROP),
9456 DEVLINK_TRAP(ARP_PARSING, DROP),
9457 DEVLINK_TRAP(IP_1_PARSING, DROP),
9458 DEVLINK_TRAP(IP_N_PARSING, DROP),
9459 DEVLINK_TRAP(GRE_PARSING, DROP),
9460 DEVLINK_TRAP(UDP_PARSING, DROP),
9461 DEVLINK_TRAP(TCP_PARSING, DROP),
9462 DEVLINK_TRAP(IPSEC_PARSING, DROP),
9463 DEVLINK_TRAP(SCTP_PARSING, DROP),
9464 DEVLINK_TRAP(DCCP_PARSING, DROP),
9465 DEVLINK_TRAP(GTP_PARSING, DROP),
9466 DEVLINK_TRAP(ESP_PARSING, DROP),
Ido Schimmel0f420b62019-08-17 16:28:17 +03009467};
9468
9469#define DEVLINK_TRAP_GROUP(_id) \
9470 { \
9471 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
9472 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
9473 }
9474
9475static const struct devlink_trap_group devlink_trap_group_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03009476 DEVLINK_TRAP_GROUP(L2_DROPS),
9477 DEVLINK_TRAP_GROUP(L3_DROPS),
Ido Schimmel678eb192020-05-29 21:36:36 +03009478 DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
Ido Schimmel391203a2019-08-17 16:28:18 +03009479 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
Amit Cohen13c056e2020-01-19 15:00:54 +02009480 DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01009481 DEVLINK_TRAP_GROUP(ACL_DROPS),
Ido Schimmel515eac62020-05-29 21:36:41 +03009482 DEVLINK_TRAP_GROUP(STP),
9483 DEVLINK_TRAP_GROUP(LACP),
9484 DEVLINK_TRAP_GROUP(LLDP),
9485 DEVLINK_TRAP_GROUP(MC_SNOOPING),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03009486 DEVLINK_TRAP_GROUP(DHCP),
9487 DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
9488 DEVLINK_TRAP_GROUP(BFD),
9489 DEVLINK_TRAP_GROUP(OSPF),
9490 DEVLINK_TRAP_GROUP(BGP),
9491 DEVLINK_TRAP_GROUP(VRRP),
9492 DEVLINK_TRAP_GROUP(PIM),
9493 DEVLINK_TRAP_GROUP(UC_LB),
9494 DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
Ido Schimmelec4f5b32020-07-29 12:26:44 +03009495 DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03009496 DEVLINK_TRAP_GROUP(IPV6),
9497 DEVLINK_TRAP_GROUP(PTP_EVENT),
9498 DEVLINK_TRAP_GROUP(PTP_GENERAL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03009499 DEVLINK_TRAP_GROUP(ACL_SAMPLE),
9500 DEVLINK_TRAP_GROUP(ACL_TRAP),
Ioana Ciornei10c24eb2020-10-01 18:11:45 +03009501 DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS),
Ido Schimmel0f420b62019-08-17 16:28:17 +03009502};
9503
9504static int devlink_trap_generic_verify(const struct devlink_trap *trap)
9505{
9506 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
9507 return -EINVAL;
9508
9509 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
9510 return -EINVAL;
9511
9512 if (trap->type != devlink_trap_generic[trap->id].type)
9513 return -EINVAL;
9514
9515 return 0;
9516}
9517
9518static int devlink_trap_driver_verify(const struct devlink_trap *trap)
9519{
9520 int i;
9521
9522 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
9523 return -EINVAL;
9524
9525 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
9526 if (!strcmp(trap->name, devlink_trap_generic[i].name))
9527 return -EEXIST;
9528 }
9529
9530 return 0;
9531}
9532
9533static int devlink_trap_verify(const struct devlink_trap *trap)
9534{
Ido Schimmel107f1672020-03-22 20:48:30 +02009535 if (!trap || !trap->name)
Ido Schimmel0f420b62019-08-17 16:28:17 +03009536 return -EINVAL;
9537
9538 if (trap->generic)
9539 return devlink_trap_generic_verify(trap);
9540 else
9541 return devlink_trap_driver_verify(trap);
9542}
9543
9544static int
9545devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
9546{
9547 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
9548 return -EINVAL;
9549
9550 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
9551 return -EINVAL;
9552
9553 return 0;
9554}
9555
9556static int
9557devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
9558{
9559 int i;
9560
9561 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
9562 return -EINVAL;
9563
9564 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
9565 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
9566 return -EEXIST;
9567 }
9568
9569 return 0;
9570}
9571
9572static int devlink_trap_group_verify(const struct devlink_trap_group *group)
9573{
9574 if (group->generic)
9575 return devlink_trap_group_generic_verify(group);
9576 else
9577 return devlink_trap_group_driver_verify(group);
9578}
9579
9580static void
9581devlink_trap_group_notify(struct devlink *devlink,
9582 const struct devlink_trap_group_item *group_item,
9583 enum devlink_command cmd)
9584{
9585 struct sk_buff *msg;
9586 int err;
9587
9588 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
9589 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
9590
9591 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9592 if (!msg)
9593 return;
9594
9595 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
9596 0);
9597 if (err) {
9598 nlmsg_free(msg);
9599 return;
9600 }
9601
9602 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9603 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9604}
9605
Ido Schimmel0f420b62019-08-17 16:28:17 +03009606static int
9607devlink_trap_item_group_link(struct devlink *devlink,
9608 struct devlink_trap_item *trap_item)
9609{
Ido Schimmel107f1672020-03-22 20:48:30 +02009610 u16 group_id = trap_item->trap->init_group_id;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009611 struct devlink_trap_group_item *group_item;
9612
Ido Schimmel107f1672020-03-22 20:48:30 +02009613 group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
Ido Schimmela09b37f2020-03-22 20:48:29 +02009614 if (WARN_ON_ONCE(!group_item))
9615 return -EINVAL;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009616
9617 trap_item->group_item = group_item;
9618
9619 return 0;
9620}
9621
Ido Schimmel0f420b62019-08-17 16:28:17 +03009622static void devlink_trap_notify(struct devlink *devlink,
9623 const struct devlink_trap_item *trap_item,
9624 enum devlink_command cmd)
9625{
9626 struct sk_buff *msg;
9627 int err;
9628
9629 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
9630 cmd != DEVLINK_CMD_TRAP_DEL);
9631
9632 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9633 if (!msg)
9634 return;
9635
9636 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
9637 if (err) {
9638 nlmsg_free(msg);
9639 return;
9640 }
9641
9642 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9643 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9644}
9645
9646static int
9647devlink_trap_register(struct devlink *devlink,
9648 const struct devlink_trap *trap, void *priv)
9649{
9650 struct devlink_trap_item *trap_item;
9651 int err;
9652
9653 if (devlink_trap_item_lookup(devlink, trap->name))
9654 return -EEXIST;
9655
9656 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
9657 if (!trap_item)
9658 return -ENOMEM;
9659
9660 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9661 if (!trap_item->stats) {
9662 err = -ENOMEM;
9663 goto err_stats_alloc;
9664 }
9665
9666 trap_item->trap = trap;
9667 trap_item->action = trap->init_action;
9668 trap_item->priv = priv;
9669
9670 err = devlink_trap_item_group_link(devlink, trap_item);
9671 if (err)
9672 goto err_group_link;
9673
9674 err = devlink->ops->trap_init(devlink, trap, trap_item);
9675 if (err)
9676 goto err_trap_init;
9677
9678 list_add_tail(&trap_item->list, &devlink->trap_list);
9679 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
9680
9681 return 0;
9682
9683err_trap_init:
Ido Schimmel0f420b62019-08-17 16:28:17 +03009684err_group_link:
9685 free_percpu(trap_item->stats);
9686err_stats_alloc:
9687 kfree(trap_item);
9688 return err;
9689}
9690
9691static void devlink_trap_unregister(struct devlink *devlink,
9692 const struct devlink_trap *trap)
9693{
9694 struct devlink_trap_item *trap_item;
9695
9696 trap_item = devlink_trap_item_lookup(devlink, trap->name);
9697 if (WARN_ON_ONCE(!trap_item))
9698 return;
9699
9700 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
9701 list_del(&trap_item->list);
9702 if (devlink->ops->trap_fini)
9703 devlink->ops->trap_fini(devlink, trap, trap_item);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009704 free_percpu(trap_item->stats);
9705 kfree(trap_item);
9706}
9707
9708static void devlink_trap_disable(struct devlink *devlink,
9709 const struct devlink_trap *trap)
9710{
9711 struct devlink_trap_item *trap_item;
9712
9713 trap_item = devlink_trap_item_lookup(devlink, trap->name);
9714 if (WARN_ON_ONCE(!trap_item))
9715 return;
9716
Ido Schimmelc88e11e2020-08-03 19:11:34 +03009717 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
9718 NULL);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009719 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
9720}
9721
9722/**
9723 * devlink_traps_register - Register packet traps with devlink.
9724 * @devlink: devlink.
9725 * @traps: Packet traps.
9726 * @traps_count: Count of provided packet traps.
9727 * @priv: Driver private information.
9728 *
9729 * Return: Non-zero value on failure.
9730 */
9731int devlink_traps_register(struct devlink *devlink,
9732 const struct devlink_trap *traps,
9733 size_t traps_count, void *priv)
9734{
9735 int i, err;
9736
9737 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
9738 return -EINVAL;
9739
9740 mutex_lock(&devlink->lock);
9741 for (i = 0; i < traps_count; i++) {
9742 const struct devlink_trap *trap = &traps[i];
9743
9744 err = devlink_trap_verify(trap);
9745 if (err)
9746 goto err_trap_verify;
9747
9748 err = devlink_trap_register(devlink, trap, priv);
9749 if (err)
9750 goto err_trap_register;
9751 }
9752 mutex_unlock(&devlink->lock);
9753
9754 return 0;
9755
9756err_trap_register:
9757err_trap_verify:
9758 for (i--; i >= 0; i--)
9759 devlink_trap_unregister(devlink, &traps[i]);
9760 mutex_unlock(&devlink->lock);
9761 return err;
9762}
9763EXPORT_SYMBOL_GPL(devlink_traps_register);
9764
9765/**
9766 * devlink_traps_unregister - Unregister packet traps from devlink.
9767 * @devlink: devlink.
9768 * @traps: Packet traps.
9769 * @traps_count: Count of provided packet traps.
9770 */
9771void devlink_traps_unregister(struct devlink *devlink,
9772 const struct devlink_trap *traps,
9773 size_t traps_count)
9774{
9775 int i;
9776
9777 mutex_lock(&devlink->lock);
9778 /* Make sure we do not have any packets in-flight while unregistering
9779 * traps by disabling all of them and waiting for a grace period.
9780 */
9781 for (i = traps_count - 1; i >= 0; i--)
9782 devlink_trap_disable(devlink, &traps[i]);
9783 synchronize_rcu();
9784 for (i = traps_count - 1; i >= 0; i--)
9785 devlink_trap_unregister(devlink, &traps[i]);
9786 mutex_unlock(&devlink->lock);
9787}
9788EXPORT_SYMBOL_GPL(devlink_traps_unregister);
9789
9790static void
9791devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
9792 size_t skb_len)
9793{
9794 struct devlink_stats *stats;
9795
9796 stats = this_cpu_ptr(trap_stats);
9797 u64_stats_update_begin(&stats->syncp);
9798 stats->rx_bytes += skb_len;
9799 stats->rx_packets++;
9800 u64_stats_update_end(&stats->syncp);
9801}
9802
9803static void
Ido Schimmel5b888232020-09-29 11:15:50 +03009804devlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata,
9805 const struct devlink_trap_item *trap_item,
9806 struct devlink_port *in_devlink_port,
9807 const struct flow_action_cookie *fa_cookie)
9808{
9809 metadata->trap_name = trap_item->trap->name;
9810 metadata->trap_group_name = trap_item->group_item->group->name;
9811 metadata->fa_cookie = fa_cookie;
Ido Schimmel93e15592020-09-29 11:15:55 +03009812 metadata->trap_type = trap_item->trap->type;
Ido Schimmel5b888232020-09-29 11:15:50 +03009813
9814 spin_lock(&in_devlink_port->type_lock);
9815 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
9816 metadata->input_dev = in_devlink_port->type_dev;
9817 spin_unlock(&in_devlink_port->type_lock);
9818}
9819
Ido Schimmel0f420b62019-08-17 16:28:17 +03009820/**
9821 * devlink_trap_report - Report trapped packet to drop monitor.
9822 * @devlink: devlink.
9823 * @skb: Trapped packet.
9824 * @trap_ctx: Trap context.
9825 * @in_devlink_port: Input devlink port.
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009826 * @fa_cookie: Flow action cookie. Could be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03009827 */
9828void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009829 void *trap_ctx, struct devlink_port *in_devlink_port,
9830 const struct flow_action_cookie *fa_cookie)
9831
Ido Schimmel0f420b62019-08-17 16:28:17 +03009832{
9833 struct devlink_trap_item *trap_item = trap_ctx;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009834
9835 devlink_trap_stats_update(trap_item->stats, skb->len);
9836 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
9837
Ido Schimmel5b888232020-09-29 11:15:50 +03009838 if (trace_devlink_trap_report_enabled()) {
9839 struct devlink_trap_metadata metadata = {};
9840
9841 devlink_trap_report_metadata_set(&metadata, trap_item,
9842 in_devlink_port, fa_cookie);
9843 trace_devlink_trap_report(devlink, skb, &metadata);
9844 }
Ido Schimmel0f420b62019-08-17 16:28:17 +03009845}
9846EXPORT_SYMBOL_GPL(devlink_trap_report);
9847
9848/**
9849 * devlink_trap_ctx_priv - Trap context to driver private information.
9850 * @trap_ctx: Trap context.
9851 *
9852 * Return: Driver private information passed during registration.
9853 */
9854void *devlink_trap_ctx_priv(void *trap_ctx)
9855{
9856 struct devlink_trap_item *trap_item = trap_ctx;
9857
9858 return trap_item->priv;
9859}
9860EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
9861
Ido Schimmel95ad9552020-03-22 20:48:26 +02009862static int
Ido Schimmelf9f54392020-03-30 22:38:21 +03009863devlink_trap_group_item_policer_link(struct devlink *devlink,
9864 struct devlink_trap_group_item *group_item)
9865{
9866 u32 policer_id = group_item->group->init_policer_id;
9867 struct devlink_trap_policer_item *policer_item;
9868
9869 if (policer_id == 0)
9870 return 0;
9871
9872 policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
9873 if (WARN_ON_ONCE(!policer_item))
9874 return -EINVAL;
9875
9876 group_item->policer_item = policer_item;
9877
9878 return 0;
9879}
9880
9881static int
Ido Schimmel95ad9552020-03-22 20:48:26 +02009882devlink_trap_group_register(struct devlink *devlink,
9883 const struct devlink_trap_group *group)
9884{
9885 struct devlink_trap_group_item *group_item;
9886 int err;
9887
9888 if (devlink_trap_group_item_lookup(devlink, group->name))
9889 return -EEXIST;
9890
9891 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
9892 if (!group_item)
9893 return -ENOMEM;
9894
9895 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9896 if (!group_item->stats) {
9897 err = -ENOMEM;
9898 goto err_stats_alloc;
9899 }
9900
9901 group_item->group = group;
Ido Schimmel95ad9552020-03-22 20:48:26 +02009902
Ido Schimmelf9f54392020-03-30 22:38:21 +03009903 err = devlink_trap_group_item_policer_link(devlink, group_item);
9904 if (err)
9905 goto err_policer_link;
9906
Ido Schimmel95ad9552020-03-22 20:48:26 +02009907 if (devlink->ops->trap_group_init) {
9908 err = devlink->ops->trap_group_init(devlink, group);
9909 if (err)
9910 goto err_group_init;
9911 }
9912
9913 list_add_tail(&group_item->list, &devlink->trap_group_list);
9914 devlink_trap_group_notify(devlink, group_item,
9915 DEVLINK_CMD_TRAP_GROUP_NEW);
9916
9917 return 0;
9918
9919err_group_init:
Ido Schimmelf9f54392020-03-30 22:38:21 +03009920err_policer_link:
Ido Schimmel95ad9552020-03-22 20:48:26 +02009921 free_percpu(group_item->stats);
9922err_stats_alloc:
9923 kfree(group_item);
9924 return err;
9925}
9926
9927static void
9928devlink_trap_group_unregister(struct devlink *devlink,
9929 const struct devlink_trap_group *group)
9930{
9931 struct devlink_trap_group_item *group_item;
9932
9933 group_item = devlink_trap_group_item_lookup(devlink, group->name);
9934 if (WARN_ON_ONCE(!group_item))
9935 return;
9936
9937 devlink_trap_group_notify(devlink, group_item,
9938 DEVLINK_CMD_TRAP_GROUP_DEL);
9939 list_del(&group_item->list);
9940 free_percpu(group_item->stats);
9941 kfree(group_item);
9942}
9943
9944/**
9945 * devlink_trap_groups_register - Register packet trap groups with devlink.
9946 * @devlink: devlink.
9947 * @groups: Packet trap groups.
9948 * @groups_count: Count of provided packet trap groups.
9949 *
9950 * Return: Non-zero value on failure.
9951 */
9952int devlink_trap_groups_register(struct devlink *devlink,
9953 const struct devlink_trap_group *groups,
9954 size_t groups_count)
9955{
9956 int i, err;
9957
9958 mutex_lock(&devlink->lock);
9959 for (i = 0; i < groups_count; i++) {
9960 const struct devlink_trap_group *group = &groups[i];
9961
9962 err = devlink_trap_group_verify(group);
9963 if (err)
9964 goto err_trap_group_verify;
9965
9966 err = devlink_trap_group_register(devlink, group);
9967 if (err)
9968 goto err_trap_group_register;
9969 }
9970 mutex_unlock(&devlink->lock);
9971
9972 return 0;
9973
9974err_trap_group_register:
9975err_trap_group_verify:
9976 for (i--; i >= 0; i--)
9977 devlink_trap_group_unregister(devlink, &groups[i]);
9978 mutex_unlock(&devlink->lock);
9979 return err;
9980}
9981EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
9982
9983/**
9984 * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
9985 * @devlink: devlink.
9986 * @groups: Packet trap groups.
9987 * @groups_count: Count of provided packet trap groups.
9988 */
9989void devlink_trap_groups_unregister(struct devlink *devlink,
9990 const struct devlink_trap_group *groups,
9991 size_t groups_count)
9992{
9993 int i;
9994
9995 mutex_lock(&devlink->lock);
9996 for (i = groups_count - 1; i >= 0; i--)
9997 devlink_trap_group_unregister(devlink, &groups[i]);
9998 mutex_unlock(&devlink->lock);
9999}
10000EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
10001
Ido Schimmel1e8c6612020-03-30 22:38:18 +030010002static void
10003devlink_trap_policer_notify(struct devlink *devlink,
10004 const struct devlink_trap_policer_item *policer_item,
10005 enum devlink_command cmd)
10006{
10007 struct sk_buff *msg;
10008 int err;
10009
10010 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
10011 cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
10012
10013 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10014 if (!msg)
10015 return;
10016
10017 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
10018 0, 0);
10019 if (err) {
10020 nlmsg_free(msg);
10021 return;
10022 }
10023
10024 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
10025 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
10026}
10027
10028static int
10029devlink_trap_policer_register(struct devlink *devlink,
10030 const struct devlink_trap_policer *policer)
10031{
10032 struct devlink_trap_policer_item *policer_item;
10033 int err;
10034
10035 if (devlink_trap_policer_item_lookup(devlink, policer->id))
10036 return -EEXIST;
10037
10038 policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
10039 if (!policer_item)
10040 return -ENOMEM;
10041
10042 policer_item->policer = policer;
10043 policer_item->rate = policer->init_rate;
10044 policer_item->burst = policer->init_burst;
10045
10046 if (devlink->ops->trap_policer_init) {
10047 err = devlink->ops->trap_policer_init(devlink, policer);
10048 if (err)
10049 goto err_policer_init;
10050 }
10051
10052 list_add_tail(&policer_item->list, &devlink->trap_policer_list);
10053 devlink_trap_policer_notify(devlink, policer_item,
10054 DEVLINK_CMD_TRAP_POLICER_NEW);
10055
10056 return 0;
10057
10058err_policer_init:
10059 kfree(policer_item);
10060 return err;
10061}
10062
10063static void
10064devlink_trap_policer_unregister(struct devlink *devlink,
10065 const struct devlink_trap_policer *policer)
10066{
10067 struct devlink_trap_policer_item *policer_item;
10068
10069 policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
10070 if (WARN_ON_ONCE(!policer_item))
10071 return;
10072
10073 devlink_trap_policer_notify(devlink, policer_item,
10074 DEVLINK_CMD_TRAP_POLICER_DEL);
10075 list_del(&policer_item->list);
10076 if (devlink->ops->trap_policer_fini)
10077 devlink->ops->trap_policer_fini(devlink, policer);
10078 kfree(policer_item);
10079}
10080
10081/**
10082 * devlink_trap_policers_register - Register packet trap policers with devlink.
10083 * @devlink: devlink.
10084 * @policers: Packet trap policers.
10085 * @policers_count: Count of provided packet trap policers.
10086 *
10087 * Return: Non-zero value on failure.
10088 */
10089int
10090devlink_trap_policers_register(struct devlink *devlink,
10091 const struct devlink_trap_policer *policers,
10092 size_t policers_count)
10093{
10094 int i, err;
10095
10096 mutex_lock(&devlink->lock);
10097 for (i = 0; i < policers_count; i++) {
10098 const struct devlink_trap_policer *policer = &policers[i];
10099
10100 if (WARN_ON(policer->id == 0 ||
10101 policer->max_rate < policer->min_rate ||
10102 policer->max_burst < policer->min_burst)) {
10103 err = -EINVAL;
10104 goto err_trap_policer_verify;
10105 }
10106
10107 err = devlink_trap_policer_register(devlink, policer);
10108 if (err)
10109 goto err_trap_policer_register;
10110 }
10111 mutex_unlock(&devlink->lock);
10112
10113 return 0;
10114
10115err_trap_policer_register:
10116err_trap_policer_verify:
10117 for (i--; i >= 0; i--)
10118 devlink_trap_policer_unregister(devlink, &policers[i]);
10119 mutex_unlock(&devlink->lock);
10120 return err;
10121}
10122EXPORT_SYMBOL_GPL(devlink_trap_policers_register);
10123
10124/**
10125 * devlink_trap_policers_unregister - Unregister packet trap policers from devlink.
10126 * @devlink: devlink.
10127 * @policers: Packet trap policers.
10128 * @policers_count: Count of provided packet trap policers.
10129 */
10130void
10131devlink_trap_policers_unregister(struct devlink *devlink,
10132 const struct devlink_trap_policer *policers,
10133 size_t policers_count)
10134{
10135 int i;
10136
10137 mutex_lock(&devlink->lock);
10138 for (i = policers_count - 1; i >= 0; i--)
10139 devlink_trap_policer_unregister(devlink, &policers[i]);
10140 mutex_unlock(&devlink->lock);
10141}
10142EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister);
10143
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080010144static void __devlink_compat_running_version(struct devlink *devlink,
10145 char *buf, size_t len)
10146{
10147 const struct nlattr *nlattr;
10148 struct devlink_info_req req;
10149 struct sk_buff *msg;
10150 int rem, err;
10151
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080010152 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10153 if (!msg)
10154 return;
10155
10156 req.msg = msg;
10157 err = devlink->ops->info_get(devlink, &req, NULL);
10158 if (err)
10159 goto free_msg;
10160
10161 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
10162 const struct nlattr *kv;
10163 int rem_kv;
10164
10165 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
10166 continue;
10167
10168 nla_for_each_nested(kv, nlattr, rem_kv) {
10169 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
10170 continue;
10171
10172 strlcat(buf, nla_data(kv), len);
10173 strlcat(buf, " ", len);
10174 }
10175 }
10176free_msg:
10177 nlmsg_free(msg);
10178}
10179
10180void devlink_compat_running_version(struct net_device *dev,
10181 char *buf, size_t len)
10182{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080010183 struct devlink *devlink;
10184
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010185 dev_hold(dev);
10186 rtnl_unlock();
10187
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010188 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -080010189 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010190 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010191
10192 mutex_lock(&devlink->lock);
10193 __devlink_compat_running_version(devlink, buf, len);
10194 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010195
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010196out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010197 rtnl_lock();
10198 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080010199}
10200
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010201int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
10202{
Jacob Kellerbc75c052020-09-25 13:46:06 -070010203 struct devlink_flash_update_params params = {};
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010204 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010205 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010206
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010207 dev_hold(dev);
10208 rtnl_unlock();
10209
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010210 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010211 if (!devlink || !devlink->ops->flash_update) {
10212 ret = -EOPNOTSUPP;
10213 goto out;
10214 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010215
Jacob Kellerbc75c052020-09-25 13:46:06 -070010216 params.file_name = file_name;
10217
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010218 mutex_lock(&devlink->lock);
Jacob Kellerbc75c052020-09-25 13:46:06 -070010219 ret = devlink->ops->flash_update(devlink, &params, NULL);
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010220 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010221
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010222out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010223 rtnl_lock();
10224 dev_put(dev);
10225
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010226 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010227}
10228
Jiri Pirkoaf3836d2019-03-28 13:56:37 +010010229int devlink_compat_phys_port_name_get(struct net_device *dev,
10230 char *name, size_t len)
10231{
10232 struct devlink_port *devlink_port;
10233
10234 /* RTNL mutex is held here which ensures that devlink_port
10235 * instance cannot disappear in the middle. No need to take
10236 * any devlink lock as only permanent values are accessed.
10237 */
10238 ASSERT_RTNL();
10239
10240 devlink_port = netdev_to_devlink_port(dev);
10241 if (!devlink_port)
10242 return -EOPNOTSUPP;
10243
10244 return __devlink_port_phys_port_name_get(devlink_port, name, len);
10245}
10246
Jiri Pirko7e1146e2019-04-03 14:24:17 +020010247int devlink_compat_switch_id_get(struct net_device *dev,
10248 struct netdev_phys_item_id *ppid)
10249{
10250 struct devlink_port *devlink_port;
10251
Vlad Buslov043b8412019-08-12 20:02:02 +030010252 /* Caller must hold RTNL mutex or reference to dev, which ensures that
10253 * devlink_port instance cannot disappear in the middle. No need to take
Jiri Pirko7e1146e2019-04-03 14:24:17 +020010254 * any devlink lock as only permanent values are accessed.
10255 */
Jiri Pirko7e1146e2019-04-03 14:24:17 +020010256 devlink_port = netdev_to_devlink_port(dev);
Danielle Ratson46737a12020-07-09 16:18:15 +030010257 if (!devlink_port || !devlink_port->switch_port)
Jiri Pirko7e1146e2019-04-03 14:24:17 +020010258 return -EOPNOTSUPP;
10259
10260 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
10261
10262 return 0;
10263}
10264
Jiri Pirko070c63f2019-10-03 11:49:39 +020010265static void __net_exit devlink_pernet_pre_exit(struct net *net)
10266{
10267 struct devlink *devlink;
Moshe Shemeshccdf0722020-10-07 09:00:43 +030010268 u32 actions_performed;
Jiri Pirko070c63f2019-10-03 11:49:39 +020010269 int err;
10270
10271 /* In case network namespace is getting destroyed, reload
10272 * all devlink instances from this namespace into init_net.
10273 */
10274 mutex_lock(&devlink_mutex);
10275 list_for_each_entry(devlink, &devlink_list, list) {
10276 if (net_eq(devlink_net(devlink), net)) {
Moshe Shemesh69d56e02020-10-07 09:00:42 +030010277 if (WARN_ON(!devlink_reload_supported(devlink->ops)))
Jiri Pirko070c63f2019-10-03 11:49:39 +020010278 continue;
Moshe Shemeshccdf0722020-10-07 09:00:43 +030010279 err = devlink_reload(devlink, &init_net,
10280 DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
Moshe Shemeshdc64cc72020-10-07 09:00:44 +030010281 DEVLINK_RELOAD_LIMIT_UNSPEC,
Moshe Shemeshccdf0722020-10-07 09:00:43 +030010282 &actions_performed, NULL);
Jiri Pirkoa0c76342019-11-08 21:42:43 +010010283 if (err && err != -EOPNOTSUPP)
Jiri Pirko070c63f2019-10-03 11:49:39 +020010284 pr_warn("Failed to reload devlink instance into init_net\n");
10285 }
10286 }
10287 mutex_unlock(&devlink_mutex);
10288}
10289
10290static struct pernet_operations devlink_pernet_ops __net_initdata = {
10291 .pre_exit = devlink_pernet_pre_exit,
10292};
10293
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -080010294static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010010295{
Jiri Pirko070c63f2019-10-03 11:49:39 +020010296 int err;
10297
10298 err = genl_register_family(&devlink_nl_family);
10299 if (err)
10300 goto out;
10301 err = register_pernet_subsys(&devlink_pernet_ops);
10302
10303out:
10304 WARN_ON(err);
10305 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010010306}
10307
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -080010308subsys_initcall(devlink_init);