blob: dd889334fed9cae7e683471c6f955942a26946d0 [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 Shemesh036467c2018-07-04 14:30:33 +03003524};
Moshe Shemesheabaef12018-07-04 14:30:28 +03003525
3526static int devlink_param_generic_verify(const struct devlink_param *param)
3527{
3528 /* verify it match generic parameter by id and name */
3529 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
3530 return -EINVAL;
3531 if (strcmp(param->name, devlink_param_generic[param->id].name))
3532 return -ENOENT;
3533
3534 WARN_ON(param->type != devlink_param_generic[param->id].type);
3535
3536 return 0;
3537}
3538
3539static int devlink_param_driver_verify(const struct devlink_param *param)
3540{
3541 int i;
3542
3543 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
3544 return -EINVAL;
3545 /* verify no such name in generic params */
3546 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
3547 if (!strcmp(param->name, devlink_param_generic[i].name))
3548 return -EEXIST;
3549
3550 return 0;
3551}
3552
3553static struct devlink_param_item *
3554devlink_param_find_by_name(struct list_head *param_list,
3555 const char *param_name)
3556{
3557 struct devlink_param_item *param_item;
3558
3559 list_for_each_entry(param_item, param_list, list)
3560 if (!strcmp(param_item->param->name, param_name))
3561 return param_item;
3562 return NULL;
3563}
3564
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03003565static struct devlink_param_item *
3566devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
3567{
3568 struct devlink_param_item *param_item;
3569
3570 list_for_each_entry(param_item, param_list, list)
3571 if (param_item->param->id == param_id)
3572 return param_item;
3573 return NULL;
3574}
3575
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003576static bool
3577devlink_param_cmode_is_supported(const struct devlink_param *param,
3578 enum devlink_param_cmode cmode)
3579{
3580 return test_bit(cmode, &param->supported_cmodes);
3581}
3582
3583static int devlink_param_get(struct devlink *devlink,
3584 const struct devlink_param *param,
3585 struct devlink_param_gset_ctx *ctx)
3586{
3587 if (!param->get)
3588 return -EOPNOTSUPP;
3589 return param->get(devlink, param->id, ctx);
3590}
3591
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003592static int devlink_param_set(struct devlink *devlink,
3593 const struct devlink_param *param,
3594 struct devlink_param_gset_ctx *ctx)
3595{
3596 if (!param->set)
3597 return -EOPNOTSUPP;
3598 return param->set(devlink, param->id, ctx);
3599}
3600
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003601static int
3602devlink_param_type_to_nla_type(enum devlink_param_type param_type)
3603{
3604 switch (param_type) {
3605 case DEVLINK_PARAM_TYPE_U8:
3606 return NLA_U8;
3607 case DEVLINK_PARAM_TYPE_U16:
3608 return NLA_U16;
3609 case DEVLINK_PARAM_TYPE_U32:
3610 return NLA_U32;
3611 case DEVLINK_PARAM_TYPE_STRING:
3612 return NLA_STRING;
3613 case DEVLINK_PARAM_TYPE_BOOL:
3614 return NLA_FLAG;
3615 default:
3616 return -EINVAL;
3617 }
3618}
3619
3620static int
3621devlink_nl_param_value_fill_one(struct sk_buff *msg,
3622 enum devlink_param_type type,
3623 enum devlink_param_cmode cmode,
3624 union devlink_param_value val)
3625{
3626 struct nlattr *param_value_attr;
3627
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003628 param_value_attr = nla_nest_start_noflag(msg,
3629 DEVLINK_ATTR_PARAM_VALUE);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003630 if (!param_value_attr)
3631 goto nla_put_failure;
3632
3633 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
3634 goto value_nest_cancel;
3635
3636 switch (type) {
3637 case DEVLINK_PARAM_TYPE_U8:
3638 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
3639 goto value_nest_cancel;
3640 break;
3641 case DEVLINK_PARAM_TYPE_U16:
3642 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
3643 goto value_nest_cancel;
3644 break;
3645 case DEVLINK_PARAM_TYPE_U32:
3646 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
3647 goto value_nest_cancel;
3648 break;
3649 case DEVLINK_PARAM_TYPE_STRING:
3650 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
3651 val.vstr))
3652 goto value_nest_cancel;
3653 break;
3654 case DEVLINK_PARAM_TYPE_BOOL:
3655 if (val.vbool &&
3656 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
3657 goto value_nest_cancel;
3658 break;
3659 }
3660
3661 nla_nest_end(msg, param_value_attr);
3662 return 0;
3663
3664value_nest_cancel:
3665 nla_nest_cancel(msg, param_value_attr);
3666nla_put_failure:
3667 return -EMSGSIZE;
3668}
3669
3670static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303671 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003672 struct devlink_param_item *param_item,
3673 enum devlink_command cmd,
3674 u32 portid, u32 seq, int flags)
3675{
3676 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003677 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003678 const struct devlink_param *param = param_item->param;
3679 struct devlink_param_gset_ctx ctx;
3680 struct nlattr *param_values_list;
3681 struct nlattr *param_attr;
3682 int nla_type;
3683 void *hdr;
3684 int err;
3685 int i;
3686
3687 /* Get value from driver part to driverinit configuration mode */
3688 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3689 if (!devlink_param_cmode_is_supported(param, i))
3690 continue;
3691 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3692 if (!param_item->driverinit_value_valid)
3693 return -EOPNOTSUPP;
3694 param_value[i] = param_item->driverinit_value;
3695 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003696 if (!param_item->published)
3697 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003698 ctx.cmode = i;
3699 err = devlink_param_get(devlink, param, &ctx);
3700 if (err)
3701 return err;
3702 param_value[i] = ctx.val;
3703 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003704 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003705 }
3706
3707 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3708 if (!hdr)
3709 return -EMSGSIZE;
3710
3711 if (devlink_nl_put_handle(msg, devlink))
3712 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303713
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303714 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3715 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3716 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303717 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3718 goto genlmsg_cancel;
3719
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003720 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003721 if (!param_attr)
3722 goto genlmsg_cancel;
3723 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3724 goto param_nest_cancel;
3725 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3726 goto param_nest_cancel;
3727
3728 nla_type = devlink_param_type_to_nla_type(param->type);
3729 if (nla_type < 0)
3730 goto param_nest_cancel;
3731 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3732 goto param_nest_cancel;
3733
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003734 param_values_list = nla_nest_start_noflag(msg,
3735 DEVLINK_ATTR_PARAM_VALUES_LIST);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003736 if (!param_values_list)
3737 goto param_nest_cancel;
3738
3739 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003740 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003741 continue;
3742 err = devlink_nl_param_value_fill_one(msg, param->type,
3743 i, param_value[i]);
3744 if (err)
3745 goto values_list_nest_cancel;
3746 }
3747
3748 nla_nest_end(msg, param_values_list);
3749 nla_nest_end(msg, param_attr);
3750 genlmsg_end(msg, hdr);
3751 return 0;
3752
3753values_list_nest_cancel:
3754 nla_nest_end(msg, param_values_list);
3755param_nest_cancel:
3756 nla_nest_cancel(msg, param_attr);
3757genlmsg_cancel:
3758 genlmsg_cancel(msg, hdr);
3759 return -EMSGSIZE;
3760}
3761
Moshe Shemeshea601e12018-07-04 14:30:32 +03003762static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303763 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03003764 struct devlink_param_item *param_item,
3765 enum devlink_command cmd)
3766{
3767 struct sk_buff *msg;
3768 int err;
3769
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303770 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3771 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3772 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003773
3774 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3775 if (!msg)
3776 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303777 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3778 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003779 if (err) {
3780 nlmsg_free(msg);
3781 return;
3782 }
3783
3784 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3785 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3786}
3787
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003788static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3789 struct netlink_callback *cb)
3790{
3791 struct devlink_param_item *param_item;
3792 struct devlink *devlink;
3793 int start = cb->args[0];
3794 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003795 int err = 0;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003796
3797 mutex_lock(&devlink_mutex);
3798 list_for_each_entry(devlink, &devlink_list, list) {
3799 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3800 continue;
3801 mutex_lock(&devlink->lock);
3802 list_for_each_entry(param_item, &devlink->param_list, list) {
3803 if (idx < start) {
3804 idx++;
3805 continue;
3806 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303807 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003808 DEVLINK_CMD_PARAM_GET,
3809 NETLINK_CB(cb->skb).portid,
3810 cb->nlh->nlmsg_seq,
3811 NLM_F_MULTI);
Jakub Kicinski82274d02020-07-28 16:15:07 -07003812 if (err == -EOPNOTSUPP) {
3813 err = 0;
3814 } else if (err) {
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003815 mutex_unlock(&devlink->lock);
3816 goto out;
3817 }
3818 idx++;
3819 }
3820 mutex_unlock(&devlink->lock);
3821 }
3822out:
3823 mutex_unlock(&devlink_mutex);
3824
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003825 if (err != -EMSGSIZE)
3826 return err;
3827
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003828 cb->args[0] = idx;
3829 return msg->len;
3830}
3831
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003832static int
3833devlink_param_type_get_from_info(struct genl_info *info,
3834 enum devlink_param_type *param_type)
3835{
3836 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3837 return -EINVAL;
3838
3839 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3840 case NLA_U8:
3841 *param_type = DEVLINK_PARAM_TYPE_U8;
3842 break;
3843 case NLA_U16:
3844 *param_type = DEVLINK_PARAM_TYPE_U16;
3845 break;
3846 case NLA_U32:
3847 *param_type = DEVLINK_PARAM_TYPE_U32;
3848 break;
3849 case NLA_STRING:
3850 *param_type = DEVLINK_PARAM_TYPE_STRING;
3851 break;
3852 case NLA_FLAG:
3853 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3854 break;
3855 default:
3856 return -EINVAL;
3857 }
3858
3859 return 0;
3860}
3861
3862static int
3863devlink_param_value_get_from_info(const struct devlink_param *param,
3864 struct genl_info *info,
3865 union devlink_param_value *value)
3866{
Jakub Kicinski87509392020-03-02 21:05:11 -08003867 struct nlattr *param_data;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003868 int len;
3869
Jakub Kicinski87509392020-03-02 21:05:11 -08003870 param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
3871
3872 if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003873 return -EINVAL;
3874
3875 switch (param->type) {
3876 case DEVLINK_PARAM_TYPE_U8:
Jakub Kicinski87509392020-03-02 21:05:11 -08003877 if (nla_len(param_data) != sizeof(u8))
3878 return -EINVAL;
3879 value->vu8 = nla_get_u8(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003880 break;
3881 case DEVLINK_PARAM_TYPE_U16:
Jakub Kicinski87509392020-03-02 21:05:11 -08003882 if (nla_len(param_data) != sizeof(u16))
3883 return -EINVAL;
3884 value->vu16 = nla_get_u16(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003885 break;
3886 case DEVLINK_PARAM_TYPE_U32:
Jakub Kicinski87509392020-03-02 21:05:11 -08003887 if (nla_len(param_data) != sizeof(u32))
3888 return -EINVAL;
3889 value->vu32 = nla_get_u32(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003890 break;
3891 case DEVLINK_PARAM_TYPE_STRING:
Jakub Kicinski87509392020-03-02 21:05:11 -08003892 len = strnlen(nla_data(param_data), nla_len(param_data));
3893 if (len == nla_len(param_data) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003894 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003895 return -EINVAL;
Jakub Kicinski87509392020-03-02 21:05:11 -08003896 strcpy(value->vstr, nla_data(param_data));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003897 break;
3898 case DEVLINK_PARAM_TYPE_BOOL:
Jakub Kicinski87509392020-03-02 21:05:11 -08003899 if (param_data && nla_len(param_data))
3900 return -EINVAL;
3901 value->vbool = nla_get_flag(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003902 break;
3903 }
3904 return 0;
3905}
3906
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003907static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303908devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003909 struct genl_info *info)
3910{
3911 char *param_name;
3912
3913 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3914 return NULL;
3915
3916 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303917 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003918}
3919
3920static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3921 struct genl_info *info)
3922{
3923 struct devlink *devlink = info->user_ptr[0];
3924 struct devlink_param_item *param_item;
3925 struct sk_buff *msg;
3926 int err;
3927
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303928 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003929 if (!param_item)
3930 return -EINVAL;
3931
3932 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3933 if (!msg)
3934 return -ENOMEM;
3935
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303936 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003937 DEVLINK_CMD_PARAM_GET,
3938 info->snd_portid, info->snd_seq, 0);
3939 if (err) {
3940 nlmsg_free(msg);
3941 return err;
3942 }
3943
3944 return genlmsg_reply(msg, info);
3945}
3946
Vasundhara Volam9c548732019-01-28 18:00:22 +05303947static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303948 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303949 struct list_head *param_list,
3950 struct genl_info *info,
3951 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003952{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003953 enum devlink_param_type param_type;
3954 struct devlink_param_gset_ctx ctx;
3955 enum devlink_param_cmode cmode;
3956 struct devlink_param_item *param_item;
3957 const struct devlink_param *param;
3958 union devlink_param_value value;
3959 int err = 0;
3960
Vasundhara Volam9c548732019-01-28 18:00:22 +05303961 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003962 if (!param_item)
3963 return -EINVAL;
3964 param = param_item->param;
3965 err = devlink_param_type_get_from_info(info, &param_type);
3966 if (err)
3967 return err;
3968 if (param_type != param->type)
3969 return -EINVAL;
3970 err = devlink_param_value_get_from_info(param, info, &value);
3971 if (err)
3972 return err;
3973 if (param->validate) {
3974 err = param->validate(devlink, param->id, value, info->extack);
3975 if (err)
3976 return err;
3977 }
3978
3979 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3980 return -EINVAL;
3981 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3982 if (!devlink_param_cmode_is_supported(param, cmode))
3983 return -EOPNOTSUPP;
3984
3985 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003986 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3987 strcpy(param_item->driverinit_value.vstr, value.vstr);
3988 else
3989 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003990 param_item->driverinit_value_valid = true;
3991 } else {
3992 if (!param->set)
3993 return -EOPNOTSUPP;
3994 ctx.val = value;
3995 ctx.cmode = cmode;
3996 err = devlink_param_set(devlink, param, &ctx);
3997 if (err)
3998 return err;
3999 }
4000
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304001 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03004002 return 0;
4003}
4004
Vasundhara Volam9c548732019-01-28 18:00:22 +05304005static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
4006 struct genl_info *info)
4007{
4008 struct devlink *devlink = info->user_ptr[0];
4009
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304010 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05304011 info, DEVLINK_CMD_PARAM_NEW);
4012}
4013
Moshe Shemesheabaef12018-07-04 14:30:28 +03004014static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304015 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05304016 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304017 const struct devlink_param *param,
4018 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03004019{
4020 struct devlink_param_item *param_item;
4021
Vasundhara Volam39e61602019-01-28 18:00:20 +05304022 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03004023 return -EEXIST;
4024
4025 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
4026 WARN_ON(param->get || param->set);
4027 else
4028 WARN_ON(!param->get || !param->set);
4029
4030 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
4031 if (!param_item)
4032 return -ENOMEM;
4033 param_item->param = param;
4034
Vasundhara Volam39e61602019-01-28 18:00:20 +05304035 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304036 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03004037 return 0;
4038}
4039
4040static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304041 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05304042 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304043 const struct devlink_param *param,
4044 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03004045{
4046 struct devlink_param_item *param_item;
4047
Vasundhara Volam39e61602019-01-28 18:00:20 +05304048 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03004049 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304050 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03004051 list_del(&param_item->list);
4052 kfree(param_item);
4053}
4054
Vasundhara Volamf4601de2019-01-28 18:00:21 +05304055static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
4056 struct netlink_callback *cb)
4057{
4058 struct devlink_param_item *param_item;
4059 struct devlink_port *devlink_port;
4060 struct devlink *devlink;
4061 int start = cb->args[0];
4062 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004063 int err = 0;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05304064
4065 mutex_lock(&devlink_mutex);
4066 list_for_each_entry(devlink, &devlink_list, list) {
4067 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4068 continue;
4069 mutex_lock(&devlink->lock);
4070 list_for_each_entry(devlink_port, &devlink->port_list, list) {
4071 list_for_each_entry(param_item,
4072 &devlink_port->param_list, list) {
4073 if (idx < start) {
4074 idx++;
4075 continue;
4076 }
4077 err = devlink_nl_param_fill(msg,
4078 devlink_port->devlink,
4079 devlink_port->index, param_item,
4080 DEVLINK_CMD_PORT_PARAM_GET,
4081 NETLINK_CB(cb->skb).portid,
4082 cb->nlh->nlmsg_seq,
4083 NLM_F_MULTI);
Jakub Kicinski82274d02020-07-28 16:15:07 -07004084 if (err == -EOPNOTSUPP) {
4085 err = 0;
4086 } else if (err) {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05304087 mutex_unlock(&devlink->lock);
4088 goto out;
4089 }
4090 idx++;
4091 }
4092 }
4093 mutex_unlock(&devlink->lock);
4094 }
4095out:
4096 mutex_unlock(&devlink_mutex);
4097
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004098 if (err != -EMSGSIZE)
4099 return err;
4100
Vasundhara Volamf4601de2019-01-28 18:00:21 +05304101 cb->args[0] = idx;
4102 return msg->len;
4103}
4104
4105static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
4106 struct genl_info *info)
4107{
4108 struct devlink_port *devlink_port = info->user_ptr[0];
4109 struct devlink_param_item *param_item;
4110 struct sk_buff *msg;
4111 int err;
4112
4113 param_item = devlink_param_get_from_info(&devlink_port->param_list,
4114 info);
4115 if (!param_item)
4116 return -EINVAL;
4117
4118 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4119 if (!msg)
4120 return -ENOMEM;
4121
4122 err = devlink_nl_param_fill(msg, devlink_port->devlink,
4123 devlink_port->index, param_item,
4124 DEVLINK_CMD_PORT_PARAM_GET,
4125 info->snd_portid, info->snd_seq, 0);
4126 if (err) {
4127 nlmsg_free(msg);
4128 return err;
4129 }
4130
4131 return genlmsg_reply(msg, info);
4132}
4133
Vasundhara Volam9c548732019-01-28 18:00:22 +05304134static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
4135 struct genl_info *info)
4136{
4137 struct devlink_port *devlink_port = info->user_ptr[0];
4138
4139 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05304140 devlink_port->index,
4141 &devlink_port->param_list, info,
4142 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05304143}
4144
Alex Veskera006d462018-07-12 15:13:12 +03004145static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
4146 struct devlink *devlink,
4147 struct devlink_snapshot *snapshot)
4148{
4149 struct nlattr *snap_attr;
4150 int err;
4151
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004152 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
Alex Veskera006d462018-07-12 15:13:12 +03004153 if (!snap_attr)
4154 return -EINVAL;
4155
4156 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
4157 if (err)
4158 goto nla_put_failure;
4159
4160 nla_nest_end(msg, snap_attr);
4161 return 0;
4162
4163nla_put_failure:
4164 nla_nest_cancel(msg, snap_attr);
4165 return err;
4166}
4167
4168static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
4169 struct devlink *devlink,
4170 struct devlink_region *region)
4171{
4172 struct devlink_snapshot *snapshot;
4173 struct nlattr *snapshots_attr;
4174 int err;
4175
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004176 snapshots_attr = nla_nest_start_noflag(msg,
4177 DEVLINK_ATTR_REGION_SNAPSHOTS);
Alex Veskera006d462018-07-12 15:13:12 +03004178 if (!snapshots_attr)
4179 return -EINVAL;
4180
4181 list_for_each_entry(snapshot, &region->snapshot_list, list) {
4182 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
4183 if (err)
4184 goto nla_put_failure;
4185 }
4186
4187 nla_nest_end(msg, snapshots_attr);
4188 return 0;
4189
4190nla_put_failure:
4191 nla_nest_cancel(msg, snapshots_attr);
4192 return err;
4193}
4194
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004195static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
4196 enum devlink_command cmd, u32 portid,
4197 u32 seq, int flags,
4198 struct devlink_region *region)
4199{
4200 void *hdr;
4201 int err;
4202
4203 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4204 if (!hdr)
4205 return -EMSGSIZE;
4206
4207 err = devlink_nl_put_handle(msg, devlink);
4208 if (err)
4209 goto nla_put_failure;
4210
Andrew Lunn544e7c32020-10-04 18:12:54 +02004211 if (region->port)
4212 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
4213 region->port->index))
4214 goto nla_put_failure;
4215
Jacob Kellere8937682020-03-26 11:37:08 -07004216 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004217 if (err)
4218 goto nla_put_failure;
4219
4220 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
4221 region->size,
4222 DEVLINK_ATTR_PAD);
4223 if (err)
4224 goto nla_put_failure;
4225
Alex Veskera006d462018-07-12 15:13:12 +03004226 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
4227 if (err)
4228 goto nla_put_failure;
4229
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004230 genlmsg_end(msg, hdr);
4231 return 0;
4232
4233nla_put_failure:
4234 genlmsg_cancel(msg, hdr);
4235 return err;
4236}
4237
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004238static struct sk_buff *
4239devlink_nl_region_notify_build(struct devlink_region *region,
4240 struct devlink_snapshot *snapshot,
4241 enum devlink_command cmd, u32 portid, u32 seq)
Alex Vesker866319b2018-07-12 15:13:13 +03004242{
4243 struct devlink *devlink = region->devlink;
4244 struct sk_buff *msg;
4245 void *hdr;
4246 int err;
4247
Alex Vesker866319b2018-07-12 15:13:13 +03004248
4249 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4250 if (!msg)
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004251 return ERR_PTR(-ENOMEM);
Alex Vesker866319b2018-07-12 15:13:13 +03004252
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004253 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
4254 if (!hdr) {
4255 err = -EMSGSIZE;
Alex Vesker866319b2018-07-12 15:13:13 +03004256 goto out_free_msg;
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004257 }
Alex Vesker866319b2018-07-12 15:13:13 +03004258
4259 err = devlink_nl_put_handle(msg, devlink);
4260 if (err)
4261 goto out_cancel_msg;
4262
Andrew Lunn544e7c32020-10-04 18:12:54 +02004263 if (region->port)
4264 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
4265 region->port->index))
4266 goto out_cancel_msg;
4267
Alex Vesker866319b2018-07-12 15:13:13 +03004268 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
Jacob Kellere8937682020-03-26 11:37:08 -07004269 region->ops->name);
Alex Vesker866319b2018-07-12 15:13:13 +03004270 if (err)
4271 goto out_cancel_msg;
4272
4273 if (snapshot) {
4274 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
4275 snapshot->id);
4276 if (err)
4277 goto out_cancel_msg;
4278 } else {
4279 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
4280 region->size, DEVLINK_ATTR_PAD);
4281 if (err)
4282 goto out_cancel_msg;
4283 }
4284 genlmsg_end(msg, hdr);
4285
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004286 return msg;
Alex Vesker866319b2018-07-12 15:13:13 +03004287
4288out_cancel_msg:
4289 genlmsg_cancel(msg, hdr);
4290out_free_msg:
4291 nlmsg_free(msg);
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07004292 return ERR_PTR(err);
4293}
4294
4295static void devlink_nl_region_notify(struct devlink_region *region,
4296 struct devlink_snapshot *snapshot,
4297 enum devlink_command cmd)
4298{
4299 struct devlink *devlink = region->devlink;
4300 struct sk_buff *msg;
4301
4302 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
4303
4304 msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
4305 if (IS_ERR(msg))
4306 return;
4307
4308 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
4309 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
Alex Vesker866319b2018-07-12 15:13:13 +03004310}
4311
Jacob Kellercf80fae2020-03-26 11:37:11 -07004312/**
Jacob Keller12102432020-03-26 11:37:15 -07004313 * __devlink_snapshot_id_increment - Increment number of snapshots using an id
4314 * @devlink: devlink instance
4315 * @id: the snapshot id
4316 *
4317 * Track when a new snapshot begins using an id. Load the count for the
4318 * given id from the snapshot xarray, increment it, and store it back.
4319 *
4320 * Called when a new snapshot is created with the given id.
4321 *
4322 * The id *must* have been previously allocated by
4323 * devlink_region_snapshot_id_get().
4324 *
4325 * Returns 0 on success, or an error on failure.
4326 */
4327static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
4328{
4329 unsigned long count;
4330 void *p;
4331
4332 lockdep_assert_held(&devlink->lock);
4333
4334 p = xa_load(&devlink->snapshot_ids, id);
4335 if (WARN_ON(!p))
4336 return -EINVAL;
4337
4338 if (WARN_ON(!xa_is_value(p)))
4339 return -EINVAL;
4340
4341 count = xa_to_value(p);
4342 count++;
4343
4344 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4345 GFP_KERNEL));
4346}
4347
4348/**
4349 * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
4350 * @devlink: devlink instance
4351 * @id: the snapshot id
4352 *
4353 * Track when a snapshot is deleted and stops using an id. Load the count
4354 * for the given id from the snapshot xarray, decrement it, and store it
4355 * back.
4356 *
4357 * If the count reaches zero, erase this id from the xarray, freeing it
4358 * up for future re-use by devlink_region_snapshot_id_get().
4359 *
4360 * Called when a snapshot using the given id is deleted, and when the
4361 * initial allocator of the id is finished using it.
4362 */
4363static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
4364{
4365 unsigned long count;
4366 void *p;
4367
4368 lockdep_assert_held(&devlink->lock);
4369
4370 p = xa_load(&devlink->snapshot_ids, id);
4371 if (WARN_ON(!p))
4372 return;
4373
4374 if (WARN_ON(!xa_is_value(p)))
4375 return;
4376
4377 count = xa_to_value(p);
4378
4379 if (count > 1) {
4380 count--;
4381 xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4382 GFP_KERNEL);
4383 } else {
4384 /* If this was the last user, we can erase this id */
4385 xa_erase(&devlink->snapshot_ids, id);
4386 }
4387}
4388
4389/**
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004390 * __devlink_snapshot_id_insert - Insert a specific snapshot ID
4391 * @devlink: devlink instance
4392 * @id: the snapshot id
4393 *
4394 * Mark the given snapshot id as used by inserting a zero value into the
4395 * snapshot xarray.
4396 *
4397 * This must be called while holding the devlink instance lock. Unlike
4398 * devlink_snapshot_id_get, the initial reference count is zero, not one.
4399 * It is expected that the id will immediately be used before
4400 * releasing the devlink instance lock.
4401 *
4402 * Returns zero on success, or an error code if the snapshot id could not
4403 * be inserted.
4404 */
4405static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
4406{
4407 lockdep_assert_held(&devlink->lock);
4408
Andrew Lunnbd71ea62020-08-16 21:26:38 +02004409 if (xa_load(&devlink->snapshot_ids, id))
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004410 return -EEXIST;
4411
4412 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
4413 GFP_KERNEL));
4414}
4415
4416/**
Jacob Keller70001082020-03-26 11:37:13 -07004417 * __devlink_region_snapshot_id_get - get snapshot ID
4418 * @devlink: devlink instance
Jacob Keller7ef19d32020-03-26 11:37:14 -07004419 * @id: storage to return snapshot id
Jacob Keller70001082020-03-26 11:37:13 -07004420 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07004421 * Allocates a new snapshot id. Returns zero on success, or a negative
4422 * error on failure. Must be called while holding the devlink instance
4423 * lock.
Jacob Keller12102432020-03-26 11:37:15 -07004424 *
4425 * Snapshot IDs are tracked using an xarray which stores the number of
4426 * users of the snapshot id.
4427 *
4428 * Note that the caller of this function counts as a 'user', in order to
4429 * avoid race conditions. The caller must release its hold on the
4430 * snapshot by using devlink_region_snapshot_id_put.
Jacob Keller70001082020-03-26 11:37:13 -07004431 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07004432static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Jacob Keller70001082020-03-26 11:37:13 -07004433{
4434 lockdep_assert_held(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07004435
Jacob Keller12102432020-03-26 11:37:15 -07004436 return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
4437 xa_limit_32b, GFP_KERNEL);
Jacob Keller70001082020-03-26 11:37:13 -07004438}
4439
4440/**
Jacob Kellercf80fae2020-03-26 11:37:11 -07004441 * __devlink_region_snapshot_create - create a new snapshot
4442 * This will add a new snapshot of a region. The snapshot
4443 * will be stored on the region struct and can be accessed
4444 * from devlink. This is useful for future analyses of snapshots.
4445 * Multiple snapshots can be created on a region.
4446 * The @snapshot_id should be obtained using the getter function.
4447 *
4448 * Must be called only while holding the devlink instance lock.
4449 *
4450 * @region: devlink region of the snapshot
4451 * @data: snapshot data
4452 * @snapshot_id: snapshot id to be created
4453 */
4454static int
4455__devlink_region_snapshot_create(struct devlink_region *region,
4456 u8 *data, u32 snapshot_id)
4457{
4458 struct devlink *devlink = region->devlink;
4459 struct devlink_snapshot *snapshot;
Jacob Keller12102432020-03-26 11:37:15 -07004460 int err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004461
4462 lockdep_assert_held(&devlink->lock);
4463
4464 /* check if region can hold one more snapshot */
4465 if (region->cur_snapshots == region->max_snapshots)
Jacob Keller47a39f62020-03-26 11:37:12 -07004466 return -ENOSPC;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004467
4468 if (devlink_region_snapshot_get_by_id(region, snapshot_id))
4469 return -EEXIST;
4470
4471 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
4472 if (!snapshot)
4473 return -ENOMEM;
4474
Jacob Keller12102432020-03-26 11:37:15 -07004475 err = __devlink_snapshot_id_increment(devlink, snapshot_id);
4476 if (err)
4477 goto err_snapshot_id_increment;
4478
Jacob Kellercf80fae2020-03-26 11:37:11 -07004479 snapshot->id = snapshot_id;
4480 snapshot->region = region;
4481 snapshot->data = data;
4482
4483 list_add_tail(&snapshot->list, &region->snapshot_list);
4484
4485 region->cur_snapshots++;
4486
4487 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
4488 return 0;
Jacob Keller12102432020-03-26 11:37:15 -07004489
4490err_snapshot_id_increment:
4491 kfree(snapshot);
4492 return err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004493}
4494
Jiri Pirko92b49822019-08-12 14:28:31 +02004495static void devlink_region_snapshot_del(struct devlink_region *region,
4496 struct devlink_snapshot *snapshot)
4497{
Jacob Keller12102432020-03-26 11:37:15 -07004498 struct devlink *devlink = region->devlink;
4499
4500 lockdep_assert_held(&devlink->lock);
4501
Jiri Pirko92b49822019-08-12 14:28:31 +02004502 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
4503 region->cur_snapshots--;
4504 list_del(&snapshot->list);
Jacob Kellera0a09f62020-03-26 11:37:09 -07004505 region->ops->destructor(snapshot->data);
Jacob Keller12102432020-03-26 11:37:15 -07004506 __devlink_snapshot_id_decrement(devlink, snapshot->id);
Jiri Pirko92b49822019-08-12 14:28:31 +02004507 kfree(snapshot);
4508}
4509
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004510static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
4511 struct genl_info *info)
4512{
4513 struct devlink *devlink = info->user_ptr[0];
Andrew Lunn544e7c32020-10-04 18:12:54 +02004514 struct devlink_port *port = NULL;
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004515 struct devlink_region *region;
4516 const char *region_name;
4517 struct sk_buff *msg;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004518 unsigned int index;
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004519 int err;
4520
4521 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
4522 return -EINVAL;
4523
Andrew Lunn544e7c32020-10-04 18:12:54 +02004524 if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4525 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4526
4527 port = devlink_port_get_by_index(devlink, index);
4528 if (!port)
4529 return -ENODEV;
4530 }
4531
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004532 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
Andrew Lunn544e7c32020-10-04 18:12:54 +02004533 if (port)
4534 region = devlink_port_region_get_by_name(port, region_name);
4535 else
4536 region = devlink_region_get_by_name(devlink, region_name);
4537
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004538 if (!region)
4539 return -EINVAL;
4540
4541 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4542 if (!msg)
4543 return -ENOMEM;
4544
4545 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
4546 info->snd_portid, info->snd_seq, 0,
4547 region);
4548 if (err) {
4549 nlmsg_free(msg);
4550 return err;
4551 }
4552
4553 return genlmsg_reply(msg, info);
4554}
4555
Andrew Lunn544e7c32020-10-04 18:12:54 +02004556static int devlink_nl_cmd_region_get_port_dumpit(struct sk_buff *msg,
4557 struct netlink_callback *cb,
4558 struct devlink_port *port,
4559 int *idx,
4560 int start)
4561{
4562 struct devlink_region *region;
4563 int err = 0;
4564
4565 list_for_each_entry(region, &port->region_list, list) {
4566 if (*idx < start) {
4567 (*idx)++;
4568 continue;
4569 }
4570 err = devlink_nl_region_fill(msg, port->devlink,
4571 DEVLINK_CMD_REGION_GET,
4572 NETLINK_CB(cb->skb).portid,
4573 cb->nlh->nlmsg_seq,
4574 NLM_F_MULTI, region);
4575 if (err)
4576 goto out;
4577 (*idx)++;
4578 }
4579
4580out:
4581 return err;
4582}
4583
4584static int devlink_nl_cmd_region_get_devlink_dumpit(struct sk_buff *msg,
4585 struct netlink_callback *cb,
4586 struct devlink *devlink,
4587 int *idx,
4588 int start)
4589{
4590 struct devlink_region *region;
4591 struct devlink_port *port;
4592 int err = 0;
4593
4594 mutex_lock(&devlink->lock);
4595 list_for_each_entry(region, &devlink->region_list, list) {
4596 if (*idx < start) {
4597 (*idx)++;
4598 continue;
4599 }
4600 err = devlink_nl_region_fill(msg, devlink,
4601 DEVLINK_CMD_REGION_GET,
4602 NETLINK_CB(cb->skb).portid,
4603 cb->nlh->nlmsg_seq,
4604 NLM_F_MULTI, region);
4605 if (err)
4606 goto out;
4607 (*idx)++;
4608 }
4609
4610 list_for_each_entry(port, &devlink->port_list, list) {
4611 err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, idx,
4612 start);
4613 if (err)
4614 goto out;
4615 }
4616
4617out:
4618 mutex_unlock(&devlink->lock);
4619 return err;
4620}
4621
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004622static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
4623 struct netlink_callback *cb)
4624{
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004625 struct devlink *devlink;
4626 int start = cb->args[0];
4627 int idx = 0;
4628 int err;
4629
4630 mutex_lock(&devlink_mutex);
4631 list_for_each_entry(devlink, &devlink_list, list) {
4632 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4633 continue;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004634 err = devlink_nl_cmd_region_get_devlink_dumpit(msg, cb, devlink,
4635 &idx, start);
4636 if (err)
4637 goto out;
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004638 }
4639out:
4640 mutex_unlock(&devlink_mutex);
4641 cb->args[0] = idx;
4642 return msg->len;
4643}
4644
Alex Vesker866319b2018-07-12 15:13:13 +03004645static int devlink_nl_cmd_region_del(struct sk_buff *skb,
4646 struct genl_info *info)
4647{
4648 struct devlink *devlink = info->user_ptr[0];
4649 struct devlink_snapshot *snapshot;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004650 struct devlink_port *port = NULL;
Alex Vesker866319b2018-07-12 15:13:13 +03004651 struct devlink_region *region;
4652 const char *region_name;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004653 unsigned int index;
Alex Vesker866319b2018-07-12 15:13:13 +03004654 u32 snapshot_id;
4655
4656 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
4657 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
4658 return -EINVAL;
4659
4660 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4661 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4662
Andrew Lunn544e7c32020-10-04 18:12:54 +02004663 if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4664 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4665
4666 port = devlink_port_get_by_index(devlink, index);
4667 if (!port)
4668 return -ENODEV;
4669 }
4670
4671 if (port)
4672 region = devlink_port_region_get_by_name(port, region_name);
4673 else
4674 region = devlink_region_get_by_name(devlink, region_name);
4675
Alex Vesker866319b2018-07-12 15:13:13 +03004676 if (!region)
4677 return -EINVAL;
4678
4679 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4680 if (!snapshot)
4681 return -EINVAL;
4682
Jiri Pirko92b49822019-08-12 14:28:31 +02004683 devlink_region_snapshot_del(region, snapshot);
Alex Vesker866319b2018-07-12 15:13:13 +03004684 return 0;
4685}
4686
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004687static int
4688devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
4689{
4690 struct devlink *devlink = info->user_ptr[0];
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004691 struct devlink_snapshot *snapshot;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004692 struct devlink_port *port = NULL;
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004693 struct nlattr *snapshot_id_attr;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004694 struct devlink_region *region;
4695 const char *region_name;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004696 unsigned int index;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004697 u32 snapshot_id;
4698 u8 *data;
4699 int err;
4700
4701 if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) {
4702 NL_SET_ERR_MSG_MOD(info->extack, "No region name provided");
4703 return -EINVAL;
4704 }
4705
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004706 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
Andrew Lunn544e7c32020-10-04 18:12:54 +02004707
4708 if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4709 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4710
4711 port = devlink_port_get_by_index(devlink, index);
4712 if (!port)
4713 return -ENODEV;
4714 }
4715
4716 if (port)
4717 region = devlink_port_region_get_by_name(port, region_name);
4718 else
4719 region = devlink_region_get_by_name(devlink, region_name);
4720
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004721 if (!region) {
4722 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist");
4723 return -EINVAL;
4724 }
4725
4726 if (!region->ops->snapshot) {
4727 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not support taking an immediate snapshot");
4728 return -EOPNOTSUPP;
4729 }
4730
4731 if (region->cur_snapshots == region->max_snapshots) {
4732 NL_SET_ERR_MSG_MOD(info->extack, "The region has reached the maximum number of stored snapshots");
4733 return -ENOSPC;
4734 }
4735
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004736 snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
4737 if (snapshot_id_attr) {
4738 snapshot_id = nla_get_u32(snapshot_id_attr);
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004739
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004740 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
4741 NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
4742 return -EEXIST;
4743 }
4744
4745 err = __devlink_snapshot_id_insert(devlink, snapshot_id);
4746 if (err)
4747 return err;
4748 } else {
4749 err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
4750 if (err) {
4751 NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
4752 return err;
4753 }
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004754 }
4755
Andrew Lunn544e7c32020-10-04 18:12:54 +02004756 if (port)
4757 err = region->port_ops->snapshot(port, region->port_ops,
4758 info->extack, &data);
4759 else
4760 err = region->ops->snapshot(devlink, region->ops,
4761 info->extack, &data);
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004762 if (err)
4763 goto err_snapshot_capture;
4764
4765 err = __devlink_region_snapshot_create(region, data, snapshot_id);
4766 if (err)
4767 goto err_snapshot_create;
4768
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004769 if (!snapshot_id_attr) {
4770 struct sk_buff *msg;
4771
4772 snapshot = devlink_region_snapshot_get_by_id(region,
4773 snapshot_id);
4774 if (WARN_ON(!snapshot))
4775 return -EINVAL;
4776
4777 msg = devlink_nl_region_notify_build(region, snapshot,
4778 DEVLINK_CMD_REGION_NEW,
4779 info->snd_portid,
4780 info->snd_seq);
4781 err = PTR_ERR_OR_ZERO(msg);
4782 if (err)
4783 goto err_notify;
4784
4785 err = genlmsg_reply(msg, info);
4786 if (err)
4787 goto err_notify;
4788 }
4789
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004790 return 0;
4791
4792err_snapshot_create:
4793 region->ops->destructor(data);
4794err_snapshot_capture:
4795 __devlink_snapshot_id_decrement(devlink, snapshot_id);
4796 return err;
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004797
4798err_notify:
4799 devlink_region_snapshot_del(region, snapshot);
4800 return err;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004801}
4802
Alex Vesker4e547952018-07-12 15:13:14 +03004803static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
4804 struct devlink *devlink,
4805 u8 *chunk, u32 chunk_size,
4806 u64 addr)
4807{
4808 struct nlattr *chunk_attr;
4809 int err;
4810
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004811 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
Alex Vesker4e547952018-07-12 15:13:14 +03004812 if (!chunk_attr)
4813 return -EINVAL;
4814
4815 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
4816 if (err)
4817 goto nla_put_failure;
4818
4819 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
4820 DEVLINK_ATTR_PAD);
4821 if (err)
4822 goto nla_put_failure;
4823
4824 nla_nest_end(msg, chunk_attr);
4825 return 0;
4826
4827nla_put_failure:
4828 nla_nest_cancel(msg, chunk_attr);
4829 return err;
4830}
4831
4832#define DEVLINK_REGION_READ_CHUNK_SIZE 256
4833
4834static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
4835 struct devlink *devlink,
4836 struct devlink_region *region,
4837 struct nlattr **attrs,
4838 u64 start_offset,
4839 u64 end_offset,
Alex Vesker4e547952018-07-12 15:13:14 +03004840 u64 *new_offset)
4841{
4842 struct devlink_snapshot *snapshot;
4843 u64 curr_offset = start_offset;
4844 u32 snapshot_id;
4845 int err = 0;
4846
4847 *new_offset = start_offset;
4848
4849 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4850 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4851 if (!snapshot)
4852 return -EINVAL;
4853
Alex Vesker4e547952018-07-12 15:13:14 +03004854 while (curr_offset < end_offset) {
4855 u32 data_size;
4856 u8 *data;
4857
4858 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
4859 data_size = end_offset - curr_offset;
4860 else
4861 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
4862
4863 data = &snapshot->data[curr_offset];
4864 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
4865 data, data_size,
4866 curr_offset);
4867 if (err)
4868 break;
4869
4870 curr_offset += data_size;
4871 }
4872 *new_offset = curr_offset;
4873
4874 return err;
4875}
4876
4877static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
4878 struct netlink_callback *cb)
4879{
Jiri Pirkoee85da52019-10-05 20:04:42 +02004880 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004881 u64 ret_offset, start_offset, end_offset = U64_MAX;
Jiri Pirkoee85da52019-10-05 20:04:42 +02004882 struct nlattr **attrs = info->attrs;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004883 struct devlink_port *port = NULL;
Alex Vesker4e547952018-07-12 15:13:14 +03004884 struct devlink_region *region;
4885 struct nlattr *chunks_attr;
4886 const char *region_name;
4887 struct devlink *devlink;
Andrew Lunn544e7c32020-10-04 18:12:54 +02004888 unsigned int index;
Alex Vesker4e547952018-07-12 15:13:14 +03004889 void *hdr;
4890 int err;
4891
4892 start_offset = *((u64 *)&cb->args[0]);
4893
Parav Panditdac7c082019-02-12 14:24:08 -06004894 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03004895 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004896 if (IS_ERR(devlink)) {
4897 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06004898 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004899 }
Alex Vesker4e547952018-07-12 15:13:14 +03004900
Alex Vesker4e547952018-07-12 15:13:14 +03004901 mutex_lock(&devlink->lock);
4902
4903 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06004904 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
4905 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004906 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004907 }
Alex Vesker4e547952018-07-12 15:13:14 +03004908
Andrew Lunn544e7c32020-10-04 18:12:54 +02004909 if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
4910 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
4911
4912 port = devlink_port_get_by_index(devlink, index);
4913 if (!port)
4914 return -ENODEV;
4915 }
4916
Alex Vesker4e547952018-07-12 15:13:14 +03004917 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
Andrew Lunn544e7c32020-10-04 18:12:54 +02004918
4919 if (port)
4920 region = devlink_port_region_get_by_name(port, region_name);
4921 else
4922 region = devlink_region_get_by_name(devlink, region_name);
4923
Parav Panditfdd41ec2019-02-12 14:23:58 -06004924 if (!region) {
4925 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004926 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004927 }
Alex Vesker4e547952018-07-12 15:13:14 +03004928
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004929 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
4930 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
4931 if (!start_offset)
4932 start_offset =
4933 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4934
4935 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4936 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
4937 }
4938
4939 if (end_offset > region->size)
4940 end_offset = region->size;
4941
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004942 /* return 0 if there is no further data to read */
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004943 if (start_offset == end_offset) {
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004944 err = 0;
4945 goto out_unlock;
4946 }
4947
Alex Vesker4e547952018-07-12 15:13:14 +03004948 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4949 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
4950 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004951 if (!hdr) {
4952 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004953 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004954 }
Alex Vesker4e547952018-07-12 15:13:14 +03004955
4956 err = devlink_nl_put_handle(skb, devlink);
4957 if (err)
4958 goto nla_put_failure;
4959
Andrew Lunn544e7c32020-10-04 18:12:54 +02004960 if (region->port)
4961 if (nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX,
4962 region->port->index))
4963 goto nla_put_failure;
4964
Alex Vesker4e547952018-07-12 15:13:14 +03004965 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
4966 if (err)
4967 goto nla_put_failure;
4968
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004969 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004970 if (!chunks_attr) {
4971 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004972 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004973 }
Alex Vesker4e547952018-07-12 15:13:14 +03004974
Alex Vesker4e547952018-07-12 15:13:14 +03004975 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
4976 region, attrs,
4977 start_offset,
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004978 end_offset, &ret_offset);
Alex Vesker4e547952018-07-12 15:13:14 +03004979
4980 if (err && err != -EMSGSIZE)
4981 goto nla_put_failure;
4982
4983 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06004984 if (ret_offset == start_offset) {
4985 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004986 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004987 }
Alex Vesker4e547952018-07-12 15:13:14 +03004988
4989 *((u64 *)&cb->args[0]) = ret_offset;
4990
4991 nla_nest_end(skb, chunks_attr);
4992 genlmsg_end(skb, hdr);
4993 mutex_unlock(&devlink->lock);
4994 mutex_unlock(&devlink_mutex);
4995
4996 return skb->len;
4997
4998nla_put_failure:
4999 genlmsg_cancel(skb, hdr);
5000out_unlock:
5001 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06005002out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03005003 mutex_unlock(&devlink_mutex);
Parav Panditfdd41ec2019-02-12 14:23:58 -06005004 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03005005}
5006
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005007struct devlink_info_req {
5008 struct sk_buff *msg;
5009};
5010
5011int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
5012{
5013 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
5014}
5015EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
5016
5017int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
5018{
5019 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
5020}
5021EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
5022
Vasundhara Volamb5872cd2020-06-20 22:01:56 +05305023int devlink_info_board_serial_number_put(struct devlink_info_req *req,
5024 const char *bsn)
5025{
5026 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER,
5027 bsn);
5028}
5029EXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put);
5030
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08005031static int devlink_info_version_put(struct devlink_info_req *req, int attr,
5032 const char *version_name,
5033 const char *version_value)
5034{
5035 struct nlattr *nest;
5036 int err;
5037
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005038 nest = nla_nest_start_noflag(req->msg, attr);
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08005039 if (!nest)
5040 return -EMSGSIZE;
5041
5042 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
5043 version_name);
5044 if (err)
5045 goto nla_put_failure;
5046
5047 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
5048 version_value);
5049 if (err)
5050 goto nla_put_failure;
5051
5052 nla_nest_end(req->msg, nest);
5053
5054 return 0;
5055
5056nla_put_failure:
5057 nla_nest_cancel(req->msg, nest);
5058 return err;
5059}
5060
5061int devlink_info_version_fixed_put(struct devlink_info_req *req,
5062 const char *version_name,
5063 const char *version_value)
5064{
5065 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
5066 version_name, version_value);
5067}
5068EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
5069
5070int devlink_info_version_stored_put(struct devlink_info_req *req,
5071 const char *version_name,
5072 const char *version_value)
5073{
5074 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
5075 version_name, version_value);
5076}
5077EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
5078
5079int devlink_info_version_running_put(struct devlink_info_req *req,
5080 const char *version_name,
5081 const char *version_value)
5082{
5083 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
5084 version_name, version_value);
5085}
5086EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
5087
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005088static int
5089devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
5090 enum devlink_command cmd, u32 portid,
5091 u32 seq, int flags, struct netlink_ext_ack *extack)
5092{
5093 struct devlink_info_req req;
5094 void *hdr;
5095 int err;
5096
5097 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5098 if (!hdr)
5099 return -EMSGSIZE;
5100
5101 err = -EMSGSIZE;
5102 if (devlink_nl_put_handle(msg, devlink))
5103 goto err_cancel_msg;
5104
5105 req.msg = msg;
5106 err = devlink->ops->info_get(devlink, &req, extack);
5107 if (err)
5108 goto err_cancel_msg;
5109
5110 genlmsg_end(msg, hdr);
5111 return 0;
5112
5113err_cancel_msg:
5114 genlmsg_cancel(msg, hdr);
5115 return err;
5116}
5117
5118static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
5119 struct genl_info *info)
5120{
5121 struct devlink *devlink = info->user_ptr[0];
5122 struct sk_buff *msg;
5123 int err;
5124
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08005125 if (!devlink->ops->info_get)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005126 return -EOPNOTSUPP;
5127
5128 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5129 if (!msg)
5130 return -ENOMEM;
5131
5132 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
5133 info->snd_portid, info->snd_seq, 0,
5134 info->extack);
5135 if (err) {
5136 nlmsg_free(msg);
5137 return err;
5138 }
5139
5140 return genlmsg_reply(msg, info);
5141}
5142
5143static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
5144 struct netlink_callback *cb)
5145{
5146 struct devlink *devlink;
5147 int start = cb->args[0];
5148 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02005149 int err = 0;
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005150
5151 mutex_lock(&devlink_mutex);
5152 list_for_each_entry(devlink, &devlink_list, list) {
5153 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5154 continue;
5155 if (idx < start) {
5156 idx++;
5157 continue;
5158 }
5159
Jiri Pirkoc493b09b2019-03-24 00:21:03 +01005160 if (!devlink->ops->info_get) {
5161 idx++;
5162 continue;
5163 }
5164
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005165 mutex_lock(&devlink->lock);
5166 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
5167 NETLINK_CB(cb->skb).portid,
5168 cb->nlh->nlmsg_seq, NLM_F_MULTI,
5169 cb->extack);
5170 mutex_unlock(&devlink->lock);
Jakub Kicinski82274d02020-07-28 16:15:07 -07005171 if (err == -EOPNOTSUPP)
5172 err = 0;
5173 else if (err)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005174 break;
5175 idx++;
5176 }
5177 mutex_unlock(&devlink_mutex);
5178
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02005179 if (err != -EMSGSIZE)
5180 return err;
5181
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005182 cb->args[0] = idx;
5183 return msg->len;
5184}
5185
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005186struct devlink_fmsg_item {
5187 struct list_head list;
5188 int attrtype;
5189 u8 nla_type;
5190 u16 len;
Gustavo A. R. Silvad2afb412020-02-28 07:43:24 -06005191 int value[];
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005192};
5193
5194struct devlink_fmsg {
5195 struct list_head item_list;
Aya Levin573ed902020-02-11 14:32:42 -08005196 bool putting_binary; /* This flag forces enclosing of binary data
5197 * in an array brackets. It forces using
5198 * of designated API:
5199 * devlink_fmsg_binary_pair_nest_start()
5200 * devlink_fmsg_binary_pair_nest_end()
5201 */
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005202};
5203
5204static struct devlink_fmsg *devlink_fmsg_alloc(void)
5205{
5206 struct devlink_fmsg *fmsg;
5207
5208 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
5209 if (!fmsg)
5210 return NULL;
5211
5212 INIT_LIST_HEAD(&fmsg->item_list);
5213
5214 return fmsg;
5215}
5216
5217static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
5218{
5219 struct devlink_fmsg_item *item, *tmp;
5220
5221 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
5222 list_del(&item->list);
5223 kfree(item);
5224 }
5225 kfree(fmsg);
5226}
5227
5228static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
5229 int attrtype)
5230{
5231 struct devlink_fmsg_item *item;
5232
5233 item = kzalloc(sizeof(*item), GFP_KERNEL);
5234 if (!item)
5235 return -ENOMEM;
5236
5237 item->attrtype = attrtype;
5238 list_add_tail(&item->list, &fmsg->item_list);
5239
5240 return 0;
5241}
5242
5243int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
5244{
Aya Levin573ed902020-02-11 14:32:42 -08005245 if (fmsg->putting_binary)
5246 return -EINVAL;
5247
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005248 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
5249}
5250EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
5251
5252static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
5253{
Aya Levin573ed902020-02-11 14:32:42 -08005254 if (fmsg->putting_binary)
5255 return -EINVAL;
5256
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005257 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
5258}
5259
5260int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
5261{
Aya Levin573ed902020-02-11 14:32:42 -08005262 if (fmsg->putting_binary)
5263 return -EINVAL;
5264
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005265 return devlink_fmsg_nest_end(fmsg);
5266}
5267EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
5268
5269#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
5270
5271static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
5272{
5273 struct devlink_fmsg_item *item;
5274
Aya Levin573ed902020-02-11 14:32:42 -08005275 if (fmsg->putting_binary)
5276 return -EINVAL;
5277
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005278 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
5279 return -EMSGSIZE;
5280
5281 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
5282 if (!item)
5283 return -ENOMEM;
5284
5285 item->nla_type = NLA_NUL_STRING;
5286 item->len = strlen(name) + 1;
5287 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
5288 memcpy(&item->value, name, item->len);
5289 list_add_tail(&item->list, &fmsg->item_list);
5290
5291 return 0;
5292}
5293
5294int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
5295{
5296 int err;
5297
Aya Levin573ed902020-02-11 14:32:42 -08005298 if (fmsg->putting_binary)
5299 return -EINVAL;
5300
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005301 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
5302 if (err)
5303 return err;
5304
5305 err = devlink_fmsg_put_name(fmsg, name);
5306 if (err)
5307 return err;
5308
5309 return 0;
5310}
5311EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
5312
5313int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
5314{
Aya Levin573ed902020-02-11 14:32:42 -08005315 if (fmsg->putting_binary)
5316 return -EINVAL;
5317
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005318 return devlink_fmsg_nest_end(fmsg);
5319}
5320EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
5321
5322int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
5323 const char *name)
5324{
5325 int err;
5326
Aya Levin573ed902020-02-11 14:32:42 -08005327 if (fmsg->putting_binary)
5328 return -EINVAL;
5329
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005330 err = devlink_fmsg_pair_nest_start(fmsg, name);
5331 if (err)
5332 return err;
5333
5334 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
5335 if (err)
5336 return err;
5337
5338 return 0;
5339}
5340EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
5341
5342int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
5343{
5344 int err;
5345
Aya Levin573ed902020-02-11 14:32:42 -08005346 if (fmsg->putting_binary)
5347 return -EINVAL;
5348
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005349 err = devlink_fmsg_nest_end(fmsg);
5350 if (err)
5351 return err;
5352
5353 err = devlink_fmsg_nest_end(fmsg);
5354 if (err)
5355 return err;
5356
5357 return 0;
5358}
5359EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
5360
Aya Levin573ed902020-02-11 14:32:42 -08005361int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
5362 const char *name)
5363{
5364 int err;
5365
5366 err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
5367 if (err)
5368 return err;
5369
5370 fmsg->putting_binary = true;
5371 return err;
5372}
5373EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
5374
5375int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
5376{
5377 if (!fmsg->putting_binary)
5378 return -EINVAL;
5379
5380 fmsg->putting_binary = false;
5381 return devlink_fmsg_arr_pair_nest_end(fmsg);
5382}
5383EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
5384
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005385static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
5386 const void *value, u16 value_len,
5387 u8 value_nla_type)
5388{
5389 struct devlink_fmsg_item *item;
5390
5391 if (value_len > DEVLINK_FMSG_MAX_SIZE)
5392 return -EMSGSIZE;
5393
5394 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
5395 if (!item)
5396 return -ENOMEM;
5397
5398 item->nla_type = value_nla_type;
5399 item->len = value_len;
5400 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5401 memcpy(&item->value, value, item->len);
5402 list_add_tail(&item->list, &fmsg->item_list);
5403
5404 return 0;
5405}
5406
5407int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
5408{
Aya Levin573ed902020-02-11 14:32:42 -08005409 if (fmsg->putting_binary)
5410 return -EINVAL;
5411
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005412 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
5413}
5414EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
5415
5416int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
5417{
Aya Levin573ed902020-02-11 14:32:42 -08005418 if (fmsg->putting_binary)
5419 return -EINVAL;
5420
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005421 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
5422}
5423EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
5424
5425int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
5426{
Aya Levin573ed902020-02-11 14:32:42 -08005427 if (fmsg->putting_binary)
5428 return -EINVAL;
5429
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005430 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
5431}
5432EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
5433
5434int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
5435{
Aya Levin573ed902020-02-11 14:32:42 -08005436 if (fmsg->putting_binary)
5437 return -EINVAL;
5438
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005439 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
5440}
5441EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
5442
5443int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
5444{
Aya Levin573ed902020-02-11 14:32:42 -08005445 if (fmsg->putting_binary)
5446 return -EINVAL;
5447
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005448 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
5449 NLA_NUL_STRING);
5450}
5451EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
5452
Aya Levin573ed902020-02-11 14:32:42 -08005453int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
5454 u16 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005455{
Aya Levin573ed902020-02-11 14:32:42 -08005456 if (!fmsg->putting_binary)
5457 return -EINVAL;
5458
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005459 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
5460}
Aya Levin573ed902020-02-11 14:32:42 -08005461EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005462
5463int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
5464 bool value)
5465{
5466 int err;
5467
5468 err = devlink_fmsg_pair_nest_start(fmsg, name);
5469 if (err)
5470 return err;
5471
5472 err = devlink_fmsg_bool_put(fmsg, value);
5473 if (err)
5474 return err;
5475
5476 err = devlink_fmsg_pair_nest_end(fmsg);
5477 if (err)
5478 return err;
5479
5480 return 0;
5481}
5482EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
5483
5484int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
5485 u8 value)
5486{
5487 int err;
5488
5489 err = devlink_fmsg_pair_nest_start(fmsg, name);
5490 if (err)
5491 return err;
5492
5493 err = devlink_fmsg_u8_put(fmsg, value);
5494 if (err)
5495 return err;
5496
5497 err = devlink_fmsg_pair_nest_end(fmsg);
5498 if (err)
5499 return err;
5500
5501 return 0;
5502}
5503EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
5504
5505int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
5506 u32 value)
5507{
5508 int err;
5509
5510 err = devlink_fmsg_pair_nest_start(fmsg, name);
5511 if (err)
5512 return err;
5513
5514 err = devlink_fmsg_u32_put(fmsg, value);
5515 if (err)
5516 return err;
5517
5518 err = devlink_fmsg_pair_nest_end(fmsg);
5519 if (err)
5520 return err;
5521
5522 return 0;
5523}
5524EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
5525
5526int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
5527 u64 value)
5528{
5529 int err;
5530
5531 err = devlink_fmsg_pair_nest_start(fmsg, name);
5532 if (err)
5533 return err;
5534
5535 err = devlink_fmsg_u64_put(fmsg, value);
5536 if (err)
5537 return err;
5538
5539 err = devlink_fmsg_pair_nest_end(fmsg);
5540 if (err)
5541 return err;
5542
5543 return 0;
5544}
5545EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
5546
5547int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
5548 const char *value)
5549{
5550 int err;
5551
5552 err = devlink_fmsg_pair_nest_start(fmsg, name);
5553 if (err)
5554 return err;
5555
5556 err = devlink_fmsg_string_put(fmsg, value);
5557 if (err)
5558 return err;
5559
5560 err = devlink_fmsg_pair_nest_end(fmsg);
5561 if (err)
5562 return err;
5563
5564 return 0;
5565}
5566EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
5567
5568int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
Aya Levine2cde862019-11-12 14:07:49 +02005569 const void *value, u32 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005570{
Aya Levine2cde862019-11-12 14:07:49 +02005571 u32 data_size;
Aya Levin573ed902020-02-11 14:32:42 -08005572 int end_err;
Aya Levine2cde862019-11-12 14:07:49 +02005573 u32 offset;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005574 int err;
5575
Aya Levin573ed902020-02-11 14:32:42 -08005576 err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005577 if (err)
5578 return err;
5579
Aya Levine2cde862019-11-12 14:07:49 +02005580 for (offset = 0; offset < value_len; offset += data_size) {
5581 data_size = value_len - offset;
5582 if (data_size > DEVLINK_FMSG_MAX_SIZE)
5583 data_size = DEVLINK_FMSG_MAX_SIZE;
5584 err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
5585 if (err)
Aya Levin573ed902020-02-11 14:32:42 -08005586 break;
5587 /* Exit from loop with a break (instead of
5588 * return) to make sure putting_binary is turned off in
5589 * devlink_fmsg_binary_pair_nest_end
5590 */
Aya Levine2cde862019-11-12 14:07:49 +02005591 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005592
Aya Levin573ed902020-02-11 14:32:42 -08005593 end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
5594 if (end_err)
5595 err = end_err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005596
Aya Levin573ed902020-02-11 14:32:42 -08005597 return err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005598}
5599EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
5600
5601static int
5602devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5603{
5604 switch (msg->nla_type) {
5605 case NLA_FLAG:
5606 case NLA_U8:
5607 case NLA_U32:
5608 case NLA_U64:
5609 case NLA_NUL_STRING:
5610 case NLA_BINARY:
5611 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
5612 msg->nla_type);
5613 default:
5614 return -EINVAL;
5615 }
5616}
5617
5618static int
5619devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5620{
5621 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5622 u8 tmp;
5623
5624 switch (msg->nla_type) {
5625 case NLA_FLAG:
5626 /* Always provide flag data, regardless of its value */
5627 tmp = *(bool *) msg->value;
5628
5629 return nla_put_u8(skb, attrtype, tmp);
5630 case NLA_U8:
5631 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
5632 case NLA_U32:
5633 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
5634 case NLA_U64:
5635 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
5636 DEVLINK_ATTR_PAD);
5637 case NLA_NUL_STRING:
5638 return nla_put_string(skb, attrtype, (char *) &msg->value);
5639 case NLA_BINARY:
5640 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
5641 default:
5642 return -EINVAL;
5643 }
5644}
5645
5646static int
5647devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5648 int *start)
5649{
5650 struct devlink_fmsg_item *item;
5651 struct nlattr *fmsg_nlattr;
5652 int i = 0;
5653 int err;
5654
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005655 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005656 if (!fmsg_nlattr)
5657 return -EMSGSIZE;
5658
5659 list_for_each_entry(item, &fmsg->item_list, list) {
5660 if (i < *start) {
5661 i++;
5662 continue;
5663 }
5664
5665 switch (item->attrtype) {
5666 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
5667 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
5668 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
5669 case DEVLINK_ATTR_FMSG_NEST_END:
5670 err = nla_put_flag(skb, item->attrtype);
5671 break;
5672 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
5673 err = devlink_fmsg_item_fill_type(item, skb);
5674 if (err)
5675 break;
5676 err = devlink_fmsg_item_fill_data(item, skb);
5677 break;
5678 case DEVLINK_ATTR_FMSG_OBJ_NAME:
5679 err = nla_put_string(skb, item->attrtype,
5680 (char *) &item->value);
5681 break;
5682 default:
5683 err = -EINVAL;
5684 break;
5685 }
5686 if (!err)
5687 *start = ++i;
5688 else
5689 break;
5690 }
5691
5692 nla_nest_end(skb, fmsg_nlattr);
5693 return err;
5694}
5695
5696static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
5697 struct genl_info *info,
5698 enum devlink_command cmd, int flags)
5699{
5700 struct nlmsghdr *nlh;
5701 struct sk_buff *skb;
5702 bool last = false;
5703 int index = 0;
5704 void *hdr;
5705 int err;
5706
5707 while (!last) {
5708 int tmp_index = index;
5709
5710 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5711 if (!skb)
5712 return -ENOMEM;
5713
5714 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
5715 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
5716 if (!hdr) {
5717 err = -EMSGSIZE;
5718 goto nla_put_failure;
5719 }
5720
5721 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5722 if (!err)
5723 last = true;
5724 else if (err != -EMSGSIZE || tmp_index == index)
5725 goto nla_put_failure;
5726
5727 genlmsg_end(skb, hdr);
5728 err = genlmsg_reply(skb, info);
5729 if (err)
5730 return err;
5731 }
5732
5733 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5734 if (!skb)
5735 return -ENOMEM;
5736 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
5737 NLMSG_DONE, 0, flags | NLM_F_MULTI);
5738 if (!nlh) {
5739 err = -EMSGSIZE;
5740 goto nla_put_failure;
5741 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005742
Li RongQingfde55ea2019-02-11 19:09:07 +08005743 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005744
5745nla_put_failure:
5746 nlmsg_free(skb);
5747 return err;
5748}
5749
Aya Levine44ef4e2019-05-16 09:49:20 +03005750static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5751 struct netlink_callback *cb,
5752 enum devlink_command cmd)
5753{
5754 int index = cb->args[0];
5755 int tmp_index = index;
5756 void *hdr;
5757 int err;
5758
5759 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
5760 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
5761 if (!hdr) {
5762 err = -EMSGSIZE;
5763 goto nla_put_failure;
5764 }
5765
5766 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5767 if ((err && err != -EMSGSIZE) || tmp_index == index)
5768 goto nla_put_failure;
5769
5770 cb->args[0] = index;
5771 genlmsg_end(skb, hdr);
5772 return skb->len;
5773
5774nla_put_failure:
5775 genlmsg_cancel(skb, hdr);
5776 return err;
5777}
5778
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005779struct devlink_health_reporter {
5780 struct list_head list;
5781 void *priv;
5782 const struct devlink_health_reporter_ops *ops;
5783 struct devlink *devlink;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005784 struct devlink_port *devlink_port;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005785 struct devlink_fmsg *dump_fmsg;
5786 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005787 u64 graceful_period;
5788 bool auto_recover;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005789 bool auto_dump;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005790 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005791 u64 dump_ts;
Aya Levind2795052019-11-10 14:11:56 +02005792 u64 dump_real_ts;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005793 u64 error_count;
5794 u64 recovery_count;
5795 u64 last_recovery_ts;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005796 refcount_t refcount;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005797};
5798
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005799void *
5800devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
5801{
5802 return reporter->priv;
5803}
5804EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
5805
5806static struct devlink_health_reporter *
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005807__devlink_health_reporter_find_by_name(struct list_head *reporter_list,
5808 struct mutex *list_lock,
5809 const char *reporter_name)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005810{
5811 struct devlink_health_reporter *reporter;
5812
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005813 lockdep_assert_held(list_lock);
5814 list_for_each_entry(reporter, reporter_list, list)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005815 if (!strcmp(reporter->ops->name, reporter_name))
5816 return reporter;
5817 return NULL;
5818}
5819
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005820static struct devlink_health_reporter *
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005821devlink_health_reporter_find_by_name(struct devlink *devlink,
5822 const char *reporter_name)
5823{
5824 return __devlink_health_reporter_find_by_name(&devlink->reporter_list,
5825 &devlink->reporters_lock,
5826 reporter_name);
5827}
5828
5829static struct devlink_health_reporter *
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005830devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
5831 const char *reporter_name)
5832{
5833 return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
5834 &devlink_port->reporters_lock,
5835 reporter_name);
5836}
5837
5838static struct devlink_health_reporter *
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005839__devlink_health_reporter_create(struct devlink *devlink,
5840 const struct devlink_health_reporter_ops *ops,
5841 u64 graceful_period, void *priv)
5842{
5843 struct devlink_health_reporter *reporter;
5844
5845 if (WARN_ON(graceful_period && !ops->recover))
5846 return ERR_PTR(-EINVAL);
5847
5848 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
5849 if (!reporter)
5850 return ERR_PTR(-ENOMEM);
5851
5852 reporter->priv = priv;
5853 reporter->ops = ops;
5854 reporter->devlink = devlink;
5855 reporter->graceful_period = graceful_period;
5856 reporter->auto_recover = !!ops->recover;
5857 reporter->auto_dump = !!ops->dump;
5858 mutex_init(&reporter->dump_lock);
5859 refcount_set(&reporter->refcount, 1);
5860 return reporter;
5861}
5862
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005863/**
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005864 * devlink_port_health_reporter_create - create devlink health reporter for
5865 * specified port instance
5866 *
5867 * @port: devlink_port which should contain the new reporter
5868 * @ops: ops
5869 * @graceful_period: to avoid recovery loops, in msecs
5870 * @priv: priv
5871 */
5872struct devlink_health_reporter *
5873devlink_port_health_reporter_create(struct devlink_port *port,
5874 const struct devlink_health_reporter_ops *ops,
5875 u64 graceful_period, void *priv)
5876{
5877 struct devlink_health_reporter *reporter;
5878
5879 mutex_lock(&port->reporters_lock);
5880 if (__devlink_health_reporter_find_by_name(&port->reporter_list,
5881 &port->reporters_lock, ops->name)) {
5882 reporter = ERR_PTR(-EEXIST);
5883 goto unlock;
5884 }
5885
5886 reporter = __devlink_health_reporter_create(port->devlink, ops,
5887 graceful_period, priv);
5888 if (IS_ERR(reporter))
5889 goto unlock;
5890
5891 reporter->devlink_port = port;
5892 list_add_tail(&reporter->list, &port->reporter_list);
5893unlock:
5894 mutex_unlock(&port->reporters_lock);
5895 return reporter;
5896}
5897EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
5898
5899/**
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005900 * devlink_health_reporter_create - create devlink health reporter
5901 *
5902 * @devlink: devlink
5903 * @ops: ops
5904 * @graceful_period: to avoid recovery loops, in msecs
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005905 * @priv: priv
5906 */
5907struct devlink_health_reporter *
5908devlink_health_reporter_create(struct devlink *devlink,
5909 const struct devlink_health_reporter_ops *ops,
Eran Ben Elishaba7d16c2020-03-29 14:05:54 +03005910 u64 graceful_period, void *priv)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005911{
5912 struct devlink_health_reporter *reporter;
5913
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005914 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005915 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
5916 reporter = ERR_PTR(-EEXIST);
5917 goto unlock;
5918 }
5919
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005920 reporter = __devlink_health_reporter_create(devlink, ops,
5921 graceful_period, priv);
5922 if (IS_ERR(reporter))
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005923 goto unlock;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005924
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005925 list_add_tail(&reporter->list, &devlink->reporter_list);
5926unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005927 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005928 return reporter;
5929}
5930EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
5931
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005932static void
5933devlink_health_reporter_free(struct devlink_health_reporter *reporter)
5934{
5935 mutex_destroy(&reporter->dump_lock);
5936 if (reporter->dump_fmsg)
5937 devlink_fmsg_free(reporter->dump_fmsg);
5938 kfree(reporter);
5939}
5940
5941static void
5942devlink_health_reporter_put(struct devlink_health_reporter *reporter)
5943{
5944 if (refcount_dec_and_test(&reporter->refcount))
5945 devlink_health_reporter_free(reporter);
5946}
5947
5948static void
5949__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5950{
5951 list_del(&reporter->list);
5952 devlink_health_reporter_put(reporter);
5953}
5954
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005955/**
5956 * devlink_health_reporter_destroy - destroy devlink health reporter
5957 *
5958 * @reporter: devlink health reporter to destroy
5959 */
5960void
5961devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5962{
Ido Schimmel5d037b42020-07-13 18:20:14 +03005963 struct mutex *lock = &reporter->devlink->reporters_lock;
5964
5965 mutex_lock(lock);
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005966 __devlink_health_reporter_destroy(reporter);
Ido Schimmel5d037b42020-07-13 18:20:14 +03005967 mutex_unlock(lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005968}
5969EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
5970
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005971/**
5972 * devlink_port_health_reporter_destroy - destroy devlink port health reporter
5973 *
5974 * @reporter: devlink health reporter to destroy
5975 */
5976void
5977devlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter)
5978{
Ido Schimmel5d037b42020-07-13 18:20:14 +03005979 struct mutex *lock = &reporter->devlink_port->reporters_lock;
5980
5981 mutex_lock(lock);
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005982 __devlink_health_reporter_destroy(reporter);
Ido Schimmel5d037b42020-07-13 18:20:14 +03005983 mutex_unlock(lock);
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005984}
5985EXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy);
5986
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005987static int
5988devlink_nl_health_reporter_fill(struct sk_buff *msg,
5989 struct devlink *devlink,
5990 struct devlink_health_reporter *reporter,
5991 enum devlink_command cmd, u32 portid,
5992 u32 seq, int flags)
5993{
5994 struct nlattr *reporter_attr;
5995 void *hdr;
5996
5997 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5998 if (!hdr)
5999 return -EMSGSIZE;
6000
6001 if (devlink_nl_put_handle(msg, devlink))
6002 goto genlmsg_cancel;
6003
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006004 if (reporter->devlink_port) {
6005 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
6006 goto genlmsg_cancel;
6007 }
Michal Kubecekae0be8d2019-04-26 11:13:06 +02006008 reporter_attr = nla_nest_start_noflag(msg,
6009 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006010 if (!reporter_attr)
6011 goto genlmsg_cancel;
6012 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
6013 reporter->ops->name))
6014 goto reporter_nest_cancel;
6015 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
6016 reporter->health_state))
6017 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02006018 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006019 reporter->error_count, DEVLINK_ATTR_PAD))
6020 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02006021 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006022 reporter->recovery_count, DEVLINK_ATTR_PAD))
6023 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02006024 if (reporter->ops->recover &&
6025 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006026 reporter->graceful_period,
6027 DEVLINK_ATTR_PAD))
6028 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02006029 if (reporter->ops->recover &&
6030 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006031 reporter->auto_recover))
6032 goto reporter_nest_cancel;
6033 if (reporter->dump_fmsg &&
6034 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
6035 jiffies_to_msecs(reporter->dump_ts),
6036 DEVLINK_ATTR_PAD))
6037 goto reporter_nest_cancel;
Aya Levind2795052019-11-10 14:11:56 +02006038 if (reporter->dump_fmsg &&
6039 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
6040 reporter->dump_real_ts, DEVLINK_ATTR_PAD))
6041 goto reporter_nest_cancel;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006042 if (reporter->ops->dump &&
6043 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
6044 reporter->auto_dump))
6045 goto reporter_nest_cancel;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006046
6047 nla_nest_end(msg, reporter_attr);
6048 genlmsg_end(msg, hdr);
6049 return 0;
6050
6051reporter_nest_cancel:
6052 nla_nest_end(msg, reporter_attr);
6053genlmsg_cancel:
6054 genlmsg_cancel(msg, hdr);
6055 return -EMSGSIZE;
6056}
6057
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05306058static void devlink_recover_notify(struct devlink_health_reporter *reporter,
6059 enum devlink_command cmd)
6060{
6061 struct sk_buff *msg;
6062 int err;
6063
6064 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6065
6066 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6067 if (!msg)
6068 return;
6069
6070 err = devlink_nl_health_reporter_fill(msg, reporter->devlink,
6071 reporter, cmd, 0, 0, 0);
6072 if (err) {
6073 nlmsg_free(msg);
6074 return;
6075 }
6076
6077 genlmsg_multicast_netns(&devlink_nl_family,
6078 devlink_net(reporter->devlink),
6079 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
6080}
6081
6082void
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006083devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
6084{
6085 reporter->recovery_count++;
6086 reporter->last_recovery_ts = jiffies;
6087}
6088EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
6089
6090static int
6091devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
6092 void *priv_ctx, struct netlink_ext_ack *extack)
6093{
6094 int err;
6095
6096 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
6097 return 0;
6098
6099 if (!reporter->ops->recover)
6100 return -EOPNOTSUPP;
6101
6102 err = reporter->ops->recover(reporter, priv_ctx, extack);
6103 if (err)
6104 return err;
6105
6106 devlink_health_reporter_recovery_done(reporter);
6107 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
6108 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6109
6110 return 0;
6111}
6112
6113static void
6114devlink_health_dump_clear(struct devlink_health_reporter *reporter)
6115{
6116 if (!reporter->dump_fmsg)
6117 return;
6118 devlink_fmsg_free(reporter->dump_fmsg);
6119 reporter->dump_fmsg = NULL;
6120}
6121
6122static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
6123 void *priv_ctx,
6124 struct netlink_ext_ack *extack)
6125{
6126 int err;
6127
6128 if (!reporter->ops->dump)
6129 return 0;
6130
6131 if (reporter->dump_fmsg)
6132 return 0;
6133
6134 reporter->dump_fmsg = devlink_fmsg_alloc();
6135 if (!reporter->dump_fmsg) {
6136 err = -ENOMEM;
6137 return err;
6138 }
6139
6140 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
6141 if (err)
6142 goto dump_err;
6143
6144 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
6145 priv_ctx, extack);
6146 if (err)
6147 goto dump_err;
6148
6149 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
6150 if (err)
6151 goto dump_err;
6152
6153 reporter->dump_ts = jiffies;
6154 reporter->dump_real_ts = ktime_get_real_ns();
6155
6156 return 0;
6157
6158dump_err:
6159 devlink_health_dump_clear(reporter);
6160 return err;
6161}
6162
6163int devlink_health_report(struct devlink_health_reporter *reporter,
6164 const char *msg, void *priv_ctx)
6165{
6166 enum devlink_health_reporter_state prev_health_state;
6167 struct devlink *devlink = reporter->devlink;
Aya Levinbea0c5c2020-05-04 11:27:46 +03006168 unsigned long recover_ts_threshold;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006169
6170 /* write a log message of the current error */
6171 WARN_ON(!msg);
6172 trace_devlink_health_report(devlink, reporter->ops->name, msg);
6173 reporter->error_count++;
6174 prev_health_state = reporter->health_state;
6175 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
6176 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6177
6178 /* abort if the previous error wasn't recovered */
Aya Levinbea0c5c2020-05-04 11:27:46 +03006179 recover_ts_threshold = reporter->last_recovery_ts +
6180 msecs_to_jiffies(reporter->graceful_period);
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006181 if (reporter->auto_recover &&
6182 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Aya Levinbea0c5c2020-05-04 11:27:46 +03006183 (reporter->last_recovery_ts && reporter->recovery_count &&
6184 time_is_after_jiffies(recover_ts_threshold)))) {
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006185 trace_devlink_health_recover_aborted(devlink,
6186 reporter->ops->name,
6187 reporter->health_state,
6188 jiffies -
6189 reporter->last_recovery_ts);
6190 return -ECANCELED;
6191 }
6192
6193 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
6194
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006195 if (reporter->auto_dump) {
6196 mutex_lock(&reporter->dump_lock);
6197 /* store current dump of current error, for later analysis */
6198 devlink_health_do_dump(reporter, priv_ctx, NULL);
6199 mutex_unlock(&reporter->dump_lock);
6200 }
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006201
6202 if (reporter->auto_recover)
6203 return devlink_health_reporter_recover(reporter,
6204 priv_ctx, NULL);
6205
6206 return 0;
6207}
6208EXPORT_SYMBOL_GPL(devlink_health_report);
6209
6210static struct devlink_health_reporter *
6211devlink_health_reporter_get_from_attrs(struct devlink *devlink,
6212 struct nlattr **attrs)
6213{
6214 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006215 struct devlink_port *devlink_port;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006216 char *reporter_name;
6217
6218 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
6219 return NULL;
6220
6221 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006222 devlink_port = devlink_port_get_from_attrs(devlink, attrs);
6223 if (IS_ERR(devlink_port)) {
6224 mutex_lock(&devlink->reporters_lock);
6225 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
6226 if (reporter)
6227 refcount_inc(&reporter->refcount);
6228 mutex_unlock(&devlink->reporters_lock);
6229 } else {
6230 mutex_lock(&devlink_port->reporters_lock);
6231 reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name);
6232 if (reporter)
6233 refcount_inc(&reporter->refcount);
6234 mutex_unlock(&devlink_port->reporters_lock);
6235 }
6236
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006237 return reporter;
6238}
6239
6240static struct devlink_health_reporter *
6241devlink_health_reporter_get_from_info(struct devlink *devlink,
6242 struct genl_info *info)
6243{
6244 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
6245}
6246
6247static struct devlink_health_reporter *
6248devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
6249{
6250 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
6251 struct devlink_health_reporter *reporter;
6252 struct nlattr **attrs = info->attrs;
6253 struct devlink *devlink;
6254
6255 mutex_lock(&devlink_mutex);
6256 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
6257 if (IS_ERR(devlink))
6258 goto unlock;
6259
6260 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
6261 mutex_unlock(&devlink_mutex);
6262 return reporter;
6263unlock:
6264 mutex_unlock(&devlink_mutex);
6265 return NULL;
6266}
6267
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02006268void
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05306269devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
6270 enum devlink_health_reporter_state state)
6271{
6272 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
6273 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
6274 return;
6275
6276 if (reporter->health_state == state)
6277 return;
6278
6279 reporter->health_state = state;
6280 trace_devlink_health_reporter_state_update(reporter->devlink,
6281 reporter->ops->name, state);
6282 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
6283}
6284EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
6285
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006286static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
6287 struct genl_info *info)
6288{
6289 struct devlink *devlink = info->user_ptr[0];
6290 struct devlink_health_reporter *reporter;
6291 struct sk_buff *msg;
6292 int err;
6293
6294 reporter = devlink_health_reporter_get_from_info(devlink, info);
6295 if (!reporter)
6296 return -EINVAL;
6297
6298 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006299 if (!msg) {
6300 err = -ENOMEM;
6301 goto out;
6302 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006303
6304 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
6305 DEVLINK_CMD_HEALTH_REPORTER_GET,
6306 info->snd_portid, info->snd_seq,
6307 0);
6308 if (err) {
6309 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006310 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006311 }
6312
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006313 err = genlmsg_reply(msg, info);
6314out:
6315 devlink_health_reporter_put(reporter);
6316 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006317}
6318
6319static int
6320devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
6321 struct netlink_callback *cb)
6322{
6323 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006324 struct devlink_port *port;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006325 struct devlink *devlink;
6326 int start = cb->args[0];
6327 int idx = 0;
6328 int err;
6329
6330 mutex_lock(&devlink_mutex);
6331 list_for_each_entry(devlink, &devlink_list, list) {
6332 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6333 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006334 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006335 list_for_each_entry(reporter, &devlink->reporter_list,
6336 list) {
6337 if (idx < start) {
6338 idx++;
6339 continue;
6340 }
6341 err = devlink_nl_health_reporter_fill(msg, devlink,
6342 reporter,
6343 DEVLINK_CMD_HEALTH_REPORTER_GET,
6344 NETLINK_CB(cb->skb).portid,
6345 cb->nlh->nlmsg_seq,
6346 NLM_F_MULTI);
6347 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006348 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006349 goto out;
6350 }
6351 idx++;
6352 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006353 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006354 }
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006355
6356 list_for_each_entry(devlink, &devlink_list, list) {
6357 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6358 continue;
Parav Pandit5d080b52020-08-21 22:12:21 +03006359 mutex_lock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006360 list_for_each_entry(port, &devlink->port_list, list) {
6361 mutex_lock(&port->reporters_lock);
6362 list_for_each_entry(reporter, &port->reporter_list, list) {
6363 if (idx < start) {
6364 idx++;
6365 continue;
6366 }
6367 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
6368 DEVLINK_CMD_HEALTH_REPORTER_GET,
6369 NETLINK_CB(cb->skb).portid,
6370 cb->nlh->nlmsg_seq,
6371 NLM_F_MULTI);
6372 if (err) {
6373 mutex_unlock(&port->reporters_lock);
Parav Pandit5d080b52020-08-21 22:12:21 +03006374 mutex_unlock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006375 goto out;
6376 }
6377 idx++;
6378 }
6379 mutex_unlock(&port->reporters_lock);
6380 }
Parav Pandit5d080b52020-08-21 22:12:21 +03006381 mutex_unlock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03006382 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006383out:
6384 mutex_unlock(&devlink_mutex);
6385
6386 cb->args[0] = idx;
6387 return msg->len;
6388}
6389
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006390static int
6391devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
6392 struct genl_info *info)
6393{
6394 struct devlink *devlink = info->user_ptr[0];
6395 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006396 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006397
6398 reporter = devlink_health_reporter_get_from_info(devlink, info);
6399 if (!reporter)
6400 return -EINVAL;
6401
6402 if (!reporter->ops->recover &&
6403 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006404 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
6405 err = -EOPNOTSUPP;
6406 goto out;
6407 }
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006408 if (!reporter->ops->dump &&
6409 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
6410 err = -EOPNOTSUPP;
6411 goto out;
6412 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006413
6414 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
6415 reporter->graceful_period =
6416 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
6417
6418 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
6419 reporter->auto_recover =
6420 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
6421
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006422 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
6423 reporter->auto_dump =
6424 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
6425
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006426 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006427 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006428out:
6429 devlink_health_reporter_put(reporter);
6430 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006431}
6432
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006433static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
6434 struct genl_info *info)
6435{
6436 struct devlink *devlink = info->user_ptr[0];
6437 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006438 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006439
6440 reporter = devlink_health_reporter_get_from_info(devlink, info);
6441 if (!reporter)
6442 return -EINVAL;
6443
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006444 err = devlink_health_reporter_recover(reporter, NULL, info->extack);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006445
6446 devlink_health_reporter_put(reporter);
6447 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006448}
6449
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006450static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
6451 struct genl_info *info)
6452{
6453 struct devlink *devlink = info->user_ptr[0];
6454 struct devlink_health_reporter *reporter;
6455 struct devlink_fmsg *fmsg;
6456 int err;
6457
6458 reporter = devlink_health_reporter_get_from_info(devlink, info);
6459 if (!reporter)
6460 return -EINVAL;
6461
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006462 if (!reporter->ops->diagnose) {
6463 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006464 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006465 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006466
6467 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006468 if (!fmsg) {
6469 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006470 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006471 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006472
6473 err = devlink_fmsg_obj_nest_start(fmsg);
6474 if (err)
6475 goto out;
6476
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006477 err = reporter->ops->diagnose(reporter, fmsg, info->extack);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006478 if (err)
6479 goto out;
6480
6481 err = devlink_fmsg_obj_nest_end(fmsg);
6482 if (err)
6483 goto out;
6484
6485 err = devlink_fmsg_snd(fmsg, info,
6486 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
6487
6488out:
6489 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006490 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006491 return err;
6492}
6493
Aya Levine44ef4e2019-05-16 09:49:20 +03006494static int
6495devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
6496 struct netlink_callback *cb)
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006497{
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006498 struct devlink_health_reporter *reporter;
Aya Levine44ef4e2019-05-16 09:49:20 +03006499 u64 start = cb->args[0];
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006500 int err;
6501
Aya Levine44ef4e2019-05-16 09:49:20 +03006502 reporter = devlink_health_reporter_get_from_cb(cb);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006503 if (!reporter)
6504 return -EINVAL;
6505
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006506 if (!reporter->ops->dump) {
Aya Levine44ef4e2019-05-16 09:49:20 +03006507 err = -EOPNOTSUPP;
6508 goto out;
6509 }
6510 mutex_lock(&reporter->dump_lock);
6511 if (!start) {
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006512 err = devlink_health_do_dump(reporter, NULL, cb->extack);
Aya Levine44ef4e2019-05-16 09:49:20 +03006513 if (err)
6514 goto unlock;
6515 cb->args[1] = reporter->dump_ts;
6516 }
6517 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
6518 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
6519 err = -EAGAIN;
6520 goto unlock;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006521 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006522
Aya Levine44ef4e2019-05-16 09:49:20 +03006523 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
6524 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
6525unlock:
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006526 mutex_unlock(&reporter->dump_lock);
Aya Levine44ef4e2019-05-16 09:49:20 +03006527out:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006528 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006529 return err;
6530}
6531
6532static int
6533devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
6534 struct genl_info *info)
6535{
6536 struct devlink *devlink = info->user_ptr[0];
6537 struct devlink_health_reporter *reporter;
6538
6539 reporter = devlink_health_reporter_get_from_info(devlink, info);
6540 if (!reporter)
6541 return -EINVAL;
6542
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006543 if (!reporter->ops->dump) {
6544 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006545 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006546 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006547
6548 mutex_lock(&reporter->dump_lock);
6549 devlink_health_dump_clear(reporter);
6550 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006551 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006552 return 0;
6553}
6554
Jiri Pirkoe2ce94d2020-09-15 11:40:57 +03006555static int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
6556 struct genl_info *info)
6557{
6558 struct devlink *devlink = info->user_ptr[0];
6559 struct devlink_health_reporter *reporter;
6560 int err;
6561
6562 reporter = devlink_health_reporter_get_from_info(devlink, info);
6563 if (!reporter)
6564 return -EINVAL;
6565
6566 if (!reporter->ops->test) {
6567 devlink_health_reporter_put(reporter);
6568 return -EOPNOTSUPP;
6569 }
6570
6571 err = reporter->ops->test(reporter, info->extack);
6572
6573 devlink_health_reporter_put(reporter);
6574 return err;
6575}
6576
Ido Schimmel0f420b62019-08-17 16:28:17 +03006577struct devlink_stats {
6578 u64 rx_bytes;
6579 u64 rx_packets;
6580 struct u64_stats_sync syncp;
6581};
6582
6583/**
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006584 * struct devlink_trap_policer_item - Packet trap policer attributes.
6585 * @policer: Immutable packet trap policer attributes.
6586 * @rate: Rate in packets / sec.
6587 * @burst: Burst size in packets.
6588 * @list: trap_policer_list member.
6589 *
6590 * Describes packet trap policer attributes. Created by devlink during trap
6591 * policer registration.
6592 */
6593struct devlink_trap_policer_item {
6594 const struct devlink_trap_policer *policer;
6595 u64 rate;
6596 u64 burst;
6597 struct list_head list;
6598};
6599
6600/**
Ido Schimmel0f420b62019-08-17 16:28:17 +03006601 * struct devlink_trap_group_item - Packet trap group attributes.
6602 * @group: Immutable packet trap group attributes.
Ido Schimmelf9f54392020-03-30 22:38:21 +03006603 * @policer_item: Associated policer item. Can be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006604 * @list: trap_group_list member.
6605 * @stats: Trap group statistics.
6606 *
6607 * Describes packet trap group attributes. Created by devlink during trap
Ido Schimmela09b37f2020-03-22 20:48:29 +02006608 * group registration.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006609 */
6610struct devlink_trap_group_item {
6611 const struct devlink_trap_group *group;
Ido Schimmelf9f54392020-03-30 22:38:21 +03006612 struct devlink_trap_policer_item *policer_item;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006613 struct list_head list;
6614 struct devlink_stats __percpu *stats;
6615};
6616
6617/**
6618 * struct devlink_trap_item - Packet trap attributes.
6619 * @trap: Immutable packet trap attributes.
6620 * @group_item: Associated group item.
6621 * @list: trap_list member.
6622 * @action: Trap action.
6623 * @stats: Trap statistics.
6624 * @priv: Driver private information.
6625 *
6626 * Describes both mutable and immutable packet trap attributes. Created by
6627 * devlink during trap registration and used for all trap related operations.
6628 */
6629struct devlink_trap_item {
6630 const struct devlink_trap *trap;
6631 struct devlink_trap_group_item *group_item;
6632 struct list_head list;
6633 enum devlink_trap_action action;
6634 struct devlink_stats __percpu *stats;
6635 void *priv;
6636};
6637
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006638static struct devlink_trap_policer_item *
6639devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
6640{
6641 struct devlink_trap_policer_item *policer_item;
6642
6643 list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
6644 if (policer_item->policer->id == id)
6645 return policer_item;
6646 }
6647
6648 return NULL;
6649}
6650
Ido Schimmel0f420b62019-08-17 16:28:17 +03006651static struct devlink_trap_item *
6652devlink_trap_item_lookup(struct devlink *devlink, const char *name)
6653{
6654 struct devlink_trap_item *trap_item;
6655
6656 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6657 if (!strcmp(trap_item->trap->name, name))
6658 return trap_item;
6659 }
6660
6661 return NULL;
6662}
6663
6664static struct devlink_trap_item *
6665devlink_trap_item_get_from_info(struct devlink *devlink,
6666 struct genl_info *info)
6667{
6668 struct nlattr *attr;
6669
6670 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
6671 return NULL;
6672 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
6673
6674 return devlink_trap_item_lookup(devlink, nla_data(attr));
6675}
6676
6677static int
6678devlink_trap_action_get_from_info(struct genl_info *info,
6679 enum devlink_trap_action *p_trap_action)
6680{
6681 u8 val;
6682
6683 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
6684 switch (val) {
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05006685 case DEVLINK_TRAP_ACTION_DROP:
6686 case DEVLINK_TRAP_ACTION_TRAP:
Ido Schimmel9eefeab2020-05-29 21:36:39 +03006687 case DEVLINK_TRAP_ACTION_MIRROR:
Ido Schimmel0f420b62019-08-17 16:28:17 +03006688 *p_trap_action = val;
6689 break;
6690 default:
6691 return -EINVAL;
6692 }
6693
6694 return 0;
6695}
6696
6697static int devlink_trap_metadata_put(struct sk_buff *msg,
6698 const struct devlink_trap *trap)
6699{
6700 struct nlattr *attr;
6701
6702 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
6703 if (!attr)
6704 return -EMSGSIZE;
6705
6706 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
6707 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
6708 goto nla_put_failure;
Jiri Pirko85b05892020-02-25 11:45:19 +01006709 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
6710 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
6711 goto nla_put_failure;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006712
6713 nla_nest_end(msg, attr);
6714
6715 return 0;
6716
6717nla_put_failure:
6718 nla_nest_cancel(msg, attr);
6719 return -EMSGSIZE;
6720}
6721
6722static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
6723 struct devlink_stats *stats)
6724{
6725 int i;
6726
6727 memset(stats, 0, sizeof(*stats));
6728 for_each_possible_cpu(i) {
6729 struct devlink_stats *cpu_stats;
6730 u64 rx_packets, rx_bytes;
6731 unsigned int start;
6732
6733 cpu_stats = per_cpu_ptr(trap_stats, i);
6734 do {
6735 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
6736 rx_packets = cpu_stats->rx_packets;
6737 rx_bytes = cpu_stats->rx_bytes;
6738 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
6739
6740 stats->rx_packets += rx_packets;
6741 stats->rx_bytes += rx_bytes;
6742 }
6743}
6744
6745static int devlink_trap_stats_put(struct sk_buff *msg,
6746 struct devlink_stats __percpu *trap_stats)
6747{
6748 struct devlink_stats stats;
6749 struct nlattr *attr;
6750
6751 devlink_trap_stats_read(trap_stats, &stats);
6752
6753 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6754 if (!attr)
6755 return -EMSGSIZE;
6756
6757 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
6758 stats.rx_packets, DEVLINK_ATTR_PAD))
6759 goto nla_put_failure;
6760
6761 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
6762 stats.rx_bytes, DEVLINK_ATTR_PAD))
6763 goto nla_put_failure;
6764
6765 nla_nest_end(msg, attr);
6766
6767 return 0;
6768
6769nla_put_failure:
6770 nla_nest_cancel(msg, attr);
6771 return -EMSGSIZE;
6772}
6773
6774static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
6775 const struct devlink_trap_item *trap_item,
6776 enum devlink_command cmd, u32 portid, u32 seq,
6777 int flags)
6778{
6779 struct devlink_trap_group_item *group_item = trap_item->group_item;
6780 void *hdr;
6781 int err;
6782
6783 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6784 if (!hdr)
6785 return -EMSGSIZE;
6786
6787 if (devlink_nl_put_handle(msg, devlink))
6788 goto nla_put_failure;
6789
6790 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6791 group_item->group->name))
6792 goto nla_put_failure;
6793
6794 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
6795 goto nla_put_failure;
6796
6797 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
6798 goto nla_put_failure;
6799
6800 if (trap_item->trap->generic &&
6801 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6802 goto nla_put_failure;
6803
6804 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
6805 goto nla_put_failure;
6806
6807 err = devlink_trap_metadata_put(msg, trap_item->trap);
6808 if (err)
6809 goto nla_put_failure;
6810
6811 err = devlink_trap_stats_put(msg, trap_item->stats);
6812 if (err)
6813 goto nla_put_failure;
6814
6815 genlmsg_end(msg, hdr);
6816
6817 return 0;
6818
6819nla_put_failure:
6820 genlmsg_cancel(msg, hdr);
6821 return -EMSGSIZE;
6822}
6823
6824static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
6825 struct genl_info *info)
6826{
6827 struct netlink_ext_ack *extack = info->extack;
6828 struct devlink *devlink = info->user_ptr[0];
6829 struct devlink_trap_item *trap_item;
6830 struct sk_buff *msg;
6831 int err;
6832
6833 if (list_empty(&devlink->trap_list))
6834 return -EOPNOTSUPP;
6835
6836 trap_item = devlink_trap_item_get_from_info(devlink, info);
6837 if (!trap_item) {
6838 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6839 return -ENOENT;
6840 }
6841
6842 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6843 if (!msg)
6844 return -ENOMEM;
6845
6846 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6847 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
6848 info->snd_seq, 0);
6849 if (err)
6850 goto err_trap_fill;
6851
6852 return genlmsg_reply(msg, info);
6853
6854err_trap_fill:
6855 nlmsg_free(msg);
6856 return err;
6857}
6858
6859static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
6860 struct netlink_callback *cb)
6861{
6862 struct devlink_trap_item *trap_item;
6863 struct devlink *devlink;
6864 int start = cb->args[0];
6865 int idx = 0;
6866 int err;
6867
6868 mutex_lock(&devlink_mutex);
6869 list_for_each_entry(devlink, &devlink_list, list) {
6870 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6871 continue;
6872 mutex_lock(&devlink->lock);
6873 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6874 if (idx < start) {
6875 idx++;
6876 continue;
6877 }
6878 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6879 DEVLINK_CMD_TRAP_NEW,
6880 NETLINK_CB(cb->skb).portid,
6881 cb->nlh->nlmsg_seq,
6882 NLM_F_MULTI);
6883 if (err) {
6884 mutex_unlock(&devlink->lock);
6885 goto out;
6886 }
6887 idx++;
6888 }
6889 mutex_unlock(&devlink->lock);
6890 }
6891out:
6892 mutex_unlock(&devlink_mutex);
6893
6894 cb->args[0] = idx;
6895 return msg->len;
6896}
6897
6898static int __devlink_trap_action_set(struct devlink *devlink,
6899 struct devlink_trap_item *trap_item,
6900 enum devlink_trap_action trap_action,
6901 struct netlink_ext_ack *extack)
6902{
6903 int err;
6904
6905 if (trap_item->action != trap_action &&
6906 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
6907 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
6908 return 0;
6909 }
6910
6911 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
Ido Schimmelc88e11e2020-08-03 19:11:34 +03006912 trap_action, extack);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006913 if (err)
6914 return err;
6915
6916 trap_item->action = trap_action;
6917
6918 return 0;
6919}
6920
6921static int devlink_trap_action_set(struct devlink *devlink,
6922 struct devlink_trap_item *trap_item,
6923 struct genl_info *info)
6924{
6925 enum devlink_trap_action trap_action;
6926 int err;
6927
6928 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6929 return 0;
6930
6931 err = devlink_trap_action_get_from_info(info, &trap_action);
6932 if (err) {
6933 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6934 return -EINVAL;
6935 }
6936
6937 return __devlink_trap_action_set(devlink, trap_item, trap_action,
6938 info->extack);
6939}
6940
6941static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
6942 struct genl_info *info)
6943{
6944 struct netlink_ext_ack *extack = info->extack;
6945 struct devlink *devlink = info->user_ptr[0];
6946 struct devlink_trap_item *trap_item;
6947 int err;
6948
6949 if (list_empty(&devlink->trap_list))
6950 return -EOPNOTSUPP;
6951
6952 trap_item = devlink_trap_item_get_from_info(devlink, info);
6953 if (!trap_item) {
6954 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6955 return -ENOENT;
6956 }
6957
6958 err = devlink_trap_action_set(devlink, trap_item, info);
6959 if (err)
6960 return err;
6961
6962 return 0;
6963}
6964
6965static struct devlink_trap_group_item *
6966devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
6967{
6968 struct devlink_trap_group_item *group_item;
6969
6970 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6971 if (!strcmp(group_item->group->name, name))
6972 return group_item;
6973 }
6974
6975 return NULL;
6976}
6977
6978static struct devlink_trap_group_item *
Ido Schimmel107f1672020-03-22 20:48:30 +02006979devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
6980{
6981 struct devlink_trap_group_item *group_item;
6982
6983 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6984 if (group_item->group->id == id)
6985 return group_item;
6986 }
6987
6988 return NULL;
6989}
6990
6991static struct devlink_trap_group_item *
Ido Schimmel0f420b62019-08-17 16:28:17 +03006992devlink_trap_group_item_get_from_info(struct devlink *devlink,
6993 struct genl_info *info)
6994{
6995 char *name;
6996
6997 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
6998 return NULL;
6999 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
7000
7001 return devlink_trap_group_item_lookup(devlink, name);
7002}
7003
7004static int
7005devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
7006 const struct devlink_trap_group_item *group_item,
7007 enum devlink_command cmd, u32 portid, u32 seq,
7008 int flags)
7009{
7010 void *hdr;
7011 int err;
7012
7013 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
7014 if (!hdr)
7015 return -EMSGSIZE;
7016
7017 if (devlink_nl_put_handle(msg, devlink))
7018 goto nla_put_failure;
7019
7020 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
7021 group_item->group->name))
7022 goto nla_put_failure;
7023
7024 if (group_item->group->generic &&
7025 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
7026 goto nla_put_failure;
7027
Ido Schimmelf9f54392020-03-30 22:38:21 +03007028 if (group_item->policer_item &&
7029 nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
7030 group_item->policer_item->policer->id))
7031 goto nla_put_failure;
7032
Ido Schimmel0f420b62019-08-17 16:28:17 +03007033 err = devlink_trap_stats_put(msg, group_item->stats);
7034 if (err)
7035 goto nla_put_failure;
7036
7037 genlmsg_end(msg, hdr);
7038
7039 return 0;
7040
7041nla_put_failure:
7042 genlmsg_cancel(msg, hdr);
7043 return -EMSGSIZE;
7044}
7045
7046static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
7047 struct genl_info *info)
7048{
7049 struct netlink_ext_ack *extack = info->extack;
7050 struct devlink *devlink = info->user_ptr[0];
7051 struct devlink_trap_group_item *group_item;
7052 struct sk_buff *msg;
7053 int err;
7054
7055 if (list_empty(&devlink->trap_group_list))
7056 return -EOPNOTSUPP;
7057
7058 group_item = devlink_trap_group_item_get_from_info(devlink, info);
7059 if (!group_item) {
7060 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
7061 return -ENOENT;
7062 }
7063
7064 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7065 if (!msg)
7066 return -ENOMEM;
7067
7068 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
7069 DEVLINK_CMD_TRAP_GROUP_NEW,
7070 info->snd_portid, info->snd_seq, 0);
7071 if (err)
7072 goto err_trap_group_fill;
7073
7074 return genlmsg_reply(msg, info);
7075
7076err_trap_group_fill:
7077 nlmsg_free(msg);
7078 return err;
7079}
7080
7081static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
7082 struct netlink_callback *cb)
7083{
7084 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
7085 struct devlink_trap_group_item *group_item;
7086 u32 portid = NETLINK_CB(cb->skb).portid;
7087 struct devlink *devlink;
7088 int start = cb->args[0];
7089 int idx = 0;
7090 int err;
7091
7092 mutex_lock(&devlink_mutex);
7093 list_for_each_entry(devlink, &devlink_list, list) {
7094 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
7095 continue;
7096 mutex_lock(&devlink->lock);
7097 list_for_each_entry(group_item, &devlink->trap_group_list,
7098 list) {
7099 if (idx < start) {
7100 idx++;
7101 continue;
7102 }
7103 err = devlink_nl_trap_group_fill(msg, devlink,
7104 group_item, cmd,
7105 portid,
7106 cb->nlh->nlmsg_seq,
7107 NLM_F_MULTI);
7108 if (err) {
7109 mutex_unlock(&devlink->lock);
7110 goto out;
7111 }
7112 idx++;
7113 }
7114 mutex_unlock(&devlink->lock);
7115 }
7116out:
7117 mutex_unlock(&devlink_mutex);
7118
7119 cb->args[0] = idx;
7120 return msg->len;
7121}
7122
7123static int
7124__devlink_trap_group_action_set(struct devlink *devlink,
7125 struct devlink_trap_group_item *group_item,
7126 enum devlink_trap_action trap_action,
7127 struct netlink_ext_ack *extack)
7128{
7129 const char *group_name = group_item->group->name;
7130 struct devlink_trap_item *trap_item;
7131 int err;
7132
Ioana Ciorneic50bf2b2020-10-01 18:11:46 +03007133 if (devlink->ops->trap_group_action_set) {
7134 err = devlink->ops->trap_group_action_set(devlink, group_item->group,
7135 trap_action, extack);
7136 if (err)
7137 return err;
7138
7139 list_for_each_entry(trap_item, &devlink->trap_list, list) {
7140 if (strcmp(trap_item->group_item->group->name, group_name))
7141 continue;
7142 if (trap_item->action != trap_action &&
7143 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP)
7144 continue;
7145 trap_item->action = trap_action;
7146 }
7147
7148 return 0;
7149 }
7150
Ido Schimmel0f420b62019-08-17 16:28:17 +03007151 list_for_each_entry(trap_item, &devlink->trap_list, list) {
Ido Schimmel107f1672020-03-22 20:48:30 +02007152 if (strcmp(trap_item->group_item->group->name, group_name))
Ido Schimmel0f420b62019-08-17 16:28:17 +03007153 continue;
7154 err = __devlink_trap_action_set(devlink, trap_item,
7155 trap_action, extack);
7156 if (err)
7157 return err;
7158 }
7159
7160 return 0;
7161}
7162
7163static int
7164devlink_trap_group_action_set(struct devlink *devlink,
7165 struct devlink_trap_group_item *group_item,
Ido Schimmelc0648752020-03-30 22:38:22 +03007166 struct genl_info *info, bool *p_modified)
Ido Schimmel0f420b62019-08-17 16:28:17 +03007167{
7168 enum devlink_trap_action trap_action;
7169 int err;
7170
7171 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
7172 return 0;
7173
7174 err = devlink_trap_action_get_from_info(info, &trap_action);
7175 if (err) {
7176 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
7177 return -EINVAL;
7178 }
7179
7180 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
7181 info->extack);
7182 if (err)
7183 return err;
7184
Ido Schimmelc0648752020-03-30 22:38:22 +03007185 *p_modified = true;
7186
7187 return 0;
7188}
7189
7190static int devlink_trap_group_set(struct devlink *devlink,
7191 struct devlink_trap_group_item *group_item,
7192 struct genl_info *info)
7193{
7194 struct devlink_trap_policer_item *policer_item;
7195 struct netlink_ext_ack *extack = info->extack;
7196 const struct devlink_trap_policer *policer;
7197 struct nlattr **attrs = info->attrs;
7198 int err;
7199
7200 if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
7201 return 0;
7202
7203 if (!devlink->ops->trap_group_set)
7204 return -EOPNOTSUPP;
7205
7206 policer_item = group_item->policer_item;
7207 if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) {
7208 u32 policer_id;
7209
7210 policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
7211 policer_item = devlink_trap_policer_item_lookup(devlink,
7212 policer_id);
7213 if (policer_id && !policer_item) {
7214 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7215 return -ENOENT;
7216 }
7217 }
7218 policer = policer_item ? policer_item->policer : NULL;
7219
Ido Schimmelc88e11e2020-08-03 19:11:34 +03007220 err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
7221 extack);
Ido Schimmelc0648752020-03-30 22:38:22 +03007222 if (err)
7223 return err;
7224
7225 group_item->policer_item = policer_item;
7226
Ido Schimmel0f420b62019-08-17 16:28:17 +03007227 return 0;
7228}
7229
7230static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
7231 struct genl_info *info)
7232{
7233 struct netlink_ext_ack *extack = info->extack;
7234 struct devlink *devlink = info->user_ptr[0];
7235 struct devlink_trap_group_item *group_item;
Ido Schimmelc0648752020-03-30 22:38:22 +03007236 bool modified = false;
Ido Schimmel0f420b62019-08-17 16:28:17 +03007237 int err;
7238
7239 if (list_empty(&devlink->trap_group_list))
7240 return -EOPNOTSUPP;
7241
7242 group_item = devlink_trap_group_item_get_from_info(devlink, info);
7243 if (!group_item) {
7244 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
7245 return -ENOENT;
7246 }
7247
Ido Schimmelc0648752020-03-30 22:38:22 +03007248 err = devlink_trap_group_action_set(devlink, group_item, info,
7249 &modified);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007250 if (err)
7251 return err;
7252
Ido Schimmelc0648752020-03-30 22:38:22 +03007253 err = devlink_trap_group_set(devlink, group_item, info);
7254 if (err)
7255 goto err_trap_group_set;
7256
Ido Schimmel0f420b62019-08-17 16:28:17 +03007257 return 0;
Ido Schimmelc0648752020-03-30 22:38:22 +03007258
7259err_trap_group_set:
7260 if (modified)
7261 NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already");
7262 return err;
Ido Schimmel0f420b62019-08-17 16:28:17 +03007263}
7264
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007265static struct devlink_trap_policer_item *
7266devlink_trap_policer_item_get_from_info(struct devlink *devlink,
7267 struct genl_info *info)
7268{
7269 u32 id;
7270
7271 if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
7272 return NULL;
7273 id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
7274
7275 return devlink_trap_policer_item_lookup(devlink, id);
7276}
7277
7278static int
7279devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
7280 const struct devlink_trap_policer *policer)
7281{
7282 struct nlattr *attr;
7283 u64 drops;
7284 int err;
7285
7286 if (!devlink->ops->trap_policer_counter_get)
7287 return 0;
7288
7289 err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
7290 if (err)
7291 return err;
7292
7293 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
7294 if (!attr)
7295 return -EMSGSIZE;
7296
7297 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
7298 DEVLINK_ATTR_PAD))
7299 goto nla_put_failure;
7300
7301 nla_nest_end(msg, attr);
7302
7303 return 0;
7304
7305nla_put_failure:
7306 nla_nest_cancel(msg, attr);
7307 return -EMSGSIZE;
7308}
7309
7310static int
7311devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
7312 const struct devlink_trap_policer_item *policer_item,
7313 enum devlink_command cmd, u32 portid, u32 seq,
7314 int flags)
7315{
7316 void *hdr;
7317 int err;
7318
7319 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
7320 if (!hdr)
7321 return -EMSGSIZE;
7322
7323 if (devlink_nl_put_handle(msg, devlink))
7324 goto nla_put_failure;
7325
7326 if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
7327 policer_item->policer->id))
7328 goto nla_put_failure;
7329
7330 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
7331 policer_item->rate, DEVLINK_ATTR_PAD))
7332 goto nla_put_failure;
7333
7334 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
7335 policer_item->burst, DEVLINK_ATTR_PAD))
7336 goto nla_put_failure;
7337
7338 err = devlink_trap_policer_stats_put(msg, devlink,
7339 policer_item->policer);
7340 if (err)
7341 goto nla_put_failure;
7342
7343 genlmsg_end(msg, hdr);
7344
7345 return 0;
7346
7347nla_put_failure:
7348 genlmsg_cancel(msg, hdr);
7349 return -EMSGSIZE;
7350}
7351
7352static int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
7353 struct genl_info *info)
7354{
7355 struct devlink_trap_policer_item *policer_item;
7356 struct netlink_ext_ack *extack = info->extack;
7357 struct devlink *devlink = info->user_ptr[0];
7358 struct sk_buff *msg;
7359 int err;
7360
7361 if (list_empty(&devlink->trap_policer_list))
7362 return -EOPNOTSUPP;
7363
7364 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
7365 if (!policer_item) {
7366 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7367 return -ENOENT;
7368 }
7369
7370 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7371 if (!msg)
7372 return -ENOMEM;
7373
7374 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
7375 DEVLINK_CMD_TRAP_POLICER_NEW,
7376 info->snd_portid, info->snd_seq, 0);
7377 if (err)
7378 goto err_trap_policer_fill;
7379
7380 return genlmsg_reply(msg, info);
7381
7382err_trap_policer_fill:
7383 nlmsg_free(msg);
7384 return err;
7385}
7386
7387static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,
7388 struct netlink_callback *cb)
7389{
7390 enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW;
7391 struct devlink_trap_policer_item *policer_item;
7392 u32 portid = NETLINK_CB(cb->skb).portid;
7393 struct devlink *devlink;
7394 int start = cb->args[0];
7395 int idx = 0;
7396 int err;
7397
7398 mutex_lock(&devlink_mutex);
7399 list_for_each_entry(devlink, &devlink_list, list) {
7400 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
7401 continue;
7402 mutex_lock(&devlink->lock);
7403 list_for_each_entry(policer_item, &devlink->trap_policer_list,
7404 list) {
7405 if (idx < start) {
7406 idx++;
7407 continue;
7408 }
7409 err = devlink_nl_trap_policer_fill(msg, devlink,
7410 policer_item, cmd,
7411 portid,
7412 cb->nlh->nlmsg_seq,
7413 NLM_F_MULTI);
7414 if (err) {
7415 mutex_unlock(&devlink->lock);
7416 goto out;
7417 }
7418 idx++;
7419 }
7420 mutex_unlock(&devlink->lock);
7421 }
7422out:
7423 mutex_unlock(&devlink_mutex);
7424
7425 cb->args[0] = idx;
7426 return msg->len;
7427}
7428
7429static int
7430devlink_trap_policer_set(struct devlink *devlink,
7431 struct devlink_trap_policer_item *policer_item,
7432 struct genl_info *info)
7433{
7434 struct netlink_ext_ack *extack = info->extack;
7435 struct nlattr **attrs = info->attrs;
7436 u64 rate, burst;
7437 int err;
7438
7439 rate = policer_item->rate;
7440 burst = policer_item->burst;
7441
7442 if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
7443 rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
7444
7445 if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
7446 burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
7447
7448 if (rate < policer_item->policer->min_rate) {
7449 NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
7450 return -EINVAL;
7451 }
7452
7453 if (rate > policer_item->policer->max_rate) {
7454 NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
7455 return -EINVAL;
7456 }
7457
7458 if (burst < policer_item->policer->min_burst) {
7459 NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
7460 return -EINVAL;
7461 }
7462
7463 if (burst > policer_item->policer->max_burst) {
7464 NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
7465 return -EINVAL;
7466 }
7467
7468 err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
7469 rate, burst, info->extack);
7470 if (err)
7471 return err;
7472
7473 policer_item->rate = rate;
7474 policer_item->burst = burst;
7475
7476 return 0;
7477}
7478
7479static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
7480 struct genl_info *info)
7481{
7482 struct devlink_trap_policer_item *policer_item;
7483 struct netlink_ext_ack *extack = info->extack;
7484 struct devlink *devlink = info->user_ptr[0];
7485
7486 if (list_empty(&devlink->trap_policer_list))
7487 return -EOPNOTSUPP;
7488
7489 if (!devlink->ops->trap_policer_set)
7490 return -EOPNOTSUPP;
7491
7492 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
7493 if (!policer_item) {
7494 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7495 return -ENOENT;
7496 }
7497
7498 return devlink_trap_policer_set(devlink, policer_item, info);
7499}
7500
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007501static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007502 [DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
7503 DEVLINK_ATTR_TRAP_POLICER_ID },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007504 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
7505 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
7506 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
Parav Panditc49a9442020-09-21 19:41:30 +03007507 [DEVLINK_ATTR_PORT_TYPE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_PORT_TYPE_AUTO,
7508 DEVLINK_PORT_TYPE_IB),
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007509 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02007510 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
7511 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
7512 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
7513 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
7514 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
7515 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
7516 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Parav Panditba356c92020-09-21 19:41:29 +03007517 [DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_ESWITCH_MODE_LEGACY,
7518 DEVLINK_ESWITCH_MODE_SWITCHDEV),
Roi Dayan59bfde02016-11-22 23:09:57 +02007519 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03007520 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007521 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
7522 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007523 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
7524 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007525 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
7526 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
7527 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007528 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03007529 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Jakub Kicinskiff3b63b2020-03-02 21:05:12 -08007530 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
7531 [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007532 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007533 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
7534 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007535 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
7536 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Jacob Keller5d5b4122020-09-25 13:46:07 -07007537 [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] =
7538 NLA_POLICY_BITFIELD32(DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS),
Ido Schimmel0f420b62019-08-17 16:28:17 +03007539 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
7540 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
7541 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
Jiri Pirko070c63f2019-10-03 11:49:39 +02007542 [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
7543 [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
7544 [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03007545 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007546 [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
7547 [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
7548 [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
Parav Pandita1e8ae92020-06-19 03:32:49 +00007549 [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007550 [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
7551 DEVLINK_RELOAD_ACTION_MAX),
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03007552 [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK),
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007553};
7554
Jakub Kicinski66a9b922020-10-02 14:49:54 -07007555static const struct genl_small_ops devlink_nl_ops[] = {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007556 {
7557 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007558 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007559 .doit = devlink_nl_cmd_get_doit,
7560 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007561 /* can be retrieved by unprivileged users */
7562 },
7563 {
7564 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007565 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007566 .doit = devlink_nl_cmd_port_get_doit,
7567 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007568 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7569 /* can be retrieved by unprivileged users */
7570 },
7571 {
7572 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007573 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007574 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007575 .flags = GENL_ADMIN_PERM,
7576 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7577 },
7578 {
7579 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007580 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007581 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007582 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007583 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007584 },
7585 {
7586 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007587 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007588 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007589 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007590 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007591 },
Jiri Pirkobf797472016-04-14 18:19:13 +02007592 {
7593 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007594 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007595 .doit = devlink_nl_cmd_sb_get_doit,
7596 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007597 /* can be retrieved by unprivileged users */
7598 },
7599 {
7600 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007601 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007602 .doit = devlink_nl_cmd_sb_pool_get_doit,
7603 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007604 /* can be retrieved by unprivileged users */
7605 },
7606 {
7607 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007608 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007609 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007610 .flags = GENL_ADMIN_PERM,
Jiri Pirkobf797472016-04-14 18:19:13 +02007611 },
7612 {
7613 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007614 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007615 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
7616 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Parav Pandit637989b2020-07-22 18:57:11 +03007617 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007618 /* can be retrieved by unprivileged users */
7619 },
7620 {
7621 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007622 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007623 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007624 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007625 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007626 },
7627 {
7628 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007629 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007630 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
7631 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Parav Pandit637989b2020-07-22 18:57:11 +03007632 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007633 /* can be retrieved by unprivileged users */
7634 },
7635 {
7636 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007637 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007638 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007639 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007640 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007641 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007642 {
7643 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007644 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007645 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007646 .flags = GENL_ADMIN_PERM,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007647 },
7648 {
7649 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007650 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007651 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007652 .flags = GENL_ADMIN_PERM,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007653 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03007654 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007655 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007656 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007657 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007658 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007659 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007660 },
7661 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007662 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007663 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007664 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007665 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007666 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007667 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007668 {
7669 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007670 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007671 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007672 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007673 },
7674 {
7675 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007676 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007677 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007678 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007679 },
7680 {
7681 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007682 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007683 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007684 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007685 },
7686 {
7687 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007688 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007689 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007690 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007691 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007692 {
7693 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007694 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007695 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007696 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007697 },
7698 {
7699 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02007700 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007701 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007702 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007703 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007704 {
7705 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02007706 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007707 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007708 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007709 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007710 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007711 {
7712 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007713 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007714 .doit = devlink_nl_cmd_param_get_doit,
7715 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007716 /* can be retrieved by unprivileged users */
7717 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007718 {
7719 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007720 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007721 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007722 .flags = GENL_ADMIN_PERM,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007723 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007724 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307725 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007726 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307727 .doit = devlink_nl_cmd_port_param_get_doit,
7728 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307729 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7730 /* can be retrieved by unprivileged users */
7731 },
7732 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05307733 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007734 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307735 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307736 .flags = GENL_ADMIN_PERM,
7737 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7738 },
7739 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007740 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007741 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007742 .doit = devlink_nl_cmd_region_get_doit,
7743 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007744 .flags = GENL_ADMIN_PERM,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007745 },
Alex Vesker866319b2018-07-12 15:13:13 +03007746 {
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07007747 .cmd = DEVLINK_CMD_REGION_NEW,
7748 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7749 .doit = devlink_nl_cmd_region_new,
7750 .flags = GENL_ADMIN_PERM,
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07007751 },
7752 {
Alex Vesker866319b2018-07-12 15:13:13 +03007753 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02007754 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03007755 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03007756 .flags = GENL_ADMIN_PERM,
Alex Vesker866319b2018-07-12 15:13:13 +03007757 },
Alex Vesker4e547952018-07-12 15:13:14 +03007758 {
7759 .cmd = DEVLINK_CMD_REGION_READ,
Jiri Pirkoee85da52019-10-05 20:04:42 +02007760 .validate = GENL_DONT_VALIDATE_STRICT |
7761 GENL_DONT_VALIDATE_DUMP_STRICT,
Alex Vesker4e547952018-07-12 15:13:14 +03007762 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03007763 .flags = GENL_ADMIN_PERM,
Alex Vesker4e547952018-07-12 15:13:14 +03007764 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007765 {
7766 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007767 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007768 .doit = devlink_nl_cmd_info_get_doit,
7769 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007770 /* can be retrieved by unprivileged users */
7771 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007772 {
7773 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007774 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007775 .doit = devlink_nl_cmd_health_reporter_get_doit,
7776 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007777 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007778 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007779 /* can be retrieved by unprivileged users */
7780 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007781 {
7782 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007783 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007784 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007785 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007786 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007787 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007788 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007789 {
7790 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02007791 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007792 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007793 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007794 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007795 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007796 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007797 {
7798 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007799 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007800 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007801 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007802 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007803 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007804 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007805 {
7806 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Jiri Pirko82a843d2019-10-07 09:28:31 +02007807 .validate = GENL_DONT_VALIDATE_STRICT |
7808 GENL_DONT_VALIDATE_DUMP_STRICT,
Aya Levine44ef4e2019-05-16 09:49:20 +03007809 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007810 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007811 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007812 DEVLINK_NL_FLAG_NO_LOCK,
7813 },
7814 {
7815 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007816 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007817 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007818 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007819 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007820 DEVLINK_NL_FLAG_NO_LOCK,
7821 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007822 {
Jiri Pirkoe2ce94d2020-09-15 11:40:57 +03007823 .cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST,
7824 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7825 .doit = devlink_nl_cmd_health_reporter_test_doit,
7826 .flags = GENL_ADMIN_PERM,
7827 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
7828 DEVLINK_NL_FLAG_NO_LOCK,
7829 },
7830 {
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007831 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007832 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007833 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007834 .flags = GENL_ADMIN_PERM,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007835 },
Ido Schimmel0f420b62019-08-17 16:28:17 +03007836 {
7837 .cmd = DEVLINK_CMD_TRAP_GET,
7838 .doit = devlink_nl_cmd_trap_get_doit,
7839 .dumpit = devlink_nl_cmd_trap_get_dumpit,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007840 /* can be retrieved by unprivileged users */
7841 },
7842 {
7843 .cmd = DEVLINK_CMD_TRAP_SET,
7844 .doit = devlink_nl_cmd_trap_set_doit,
7845 .flags = GENL_ADMIN_PERM,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007846 },
7847 {
7848 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
7849 .doit = devlink_nl_cmd_trap_group_get_doit,
7850 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007851 /* can be retrieved by unprivileged users */
7852 },
7853 {
7854 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
7855 .doit = devlink_nl_cmd_trap_group_set_doit,
7856 .flags = GENL_ADMIN_PERM,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007857 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007858 {
7859 .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
7860 .doit = devlink_nl_cmd_trap_policer_get_doit,
7861 .dumpit = devlink_nl_cmd_trap_policer_get_dumpit,
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007862 /* can be retrieved by unprivileged users */
7863 },
7864 {
7865 .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
7866 .doit = devlink_nl_cmd_trap_policer_set_doit,
7867 .flags = GENL_ADMIN_PERM,
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007868 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007869};
7870
Johannes Berg56989f62016-10-24 14:40:05 +02007871static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02007872 .name = DEVLINK_GENL_NAME,
7873 .version = DEVLINK_GENL_VERSION,
7874 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01007875 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02007876 .netnsok = true,
7877 .pre_doit = devlink_nl_pre_doit,
7878 .post_doit = devlink_nl_post_doit,
7879 .module = THIS_MODULE,
Jakub Kicinski66a9b922020-10-02 14:49:54 -07007880 .small_ops = devlink_nl_ops,
7881 .n_small_ops = ARRAY_SIZE(devlink_nl_ops),
Johannes Berg489111e2016-10-24 14:40:03 +02007882 .mcgrps = devlink_nl_mcgrps,
7883 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
7884};
7885
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007886static bool devlink_reload_actions_valid(const struct devlink_ops *ops)
7887{
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03007888 const struct devlink_reload_combination *comb;
7889 int i;
7890
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007891 if (!devlink_reload_supported(ops)) {
7892 if (WARN_ON(ops->reload_actions))
7893 return false;
7894 return true;
7895 }
7896
7897 if (WARN_ON(!ops->reload_actions ||
7898 ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) ||
7899 ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX)))
7900 return false;
Moshe Shemeshdc64cc72020-10-07 09:00:44 +03007901
7902 if (WARN_ON(ops->reload_limits & BIT(DEVLINK_RELOAD_LIMIT_UNSPEC) ||
7903 ops->reload_limits >= BIT(__DEVLINK_RELOAD_LIMIT_MAX)))
7904 return false;
7905
7906 for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++) {
7907 comb = &devlink_reload_invalid_combinations[i];
7908 if (ops->reload_actions == BIT(comb->action) &&
7909 ops->reload_limits == BIT(comb->limit))
7910 return false;
7911 }
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007912 return true;
7913}
7914
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007915/**
7916 * devlink_alloc - Allocate new devlink instance resources
7917 *
7918 * @ops: ops
7919 * @priv_size: size of user private data
7920 *
7921 * Allocate new devlink instance resources, including devlink index
7922 * and name.
7923 */
7924struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
7925{
7926 struct devlink *devlink;
7927
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007928 if (WARN_ON(!ops))
7929 return NULL;
7930
Moshe Shemeshccdf0722020-10-07 09:00:43 +03007931 if (!devlink_reload_actions_valid(ops))
7932 return NULL;
7933
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007934 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
7935 if (!devlink)
7936 return NULL;
7937 devlink->ops = ops;
Jacob Keller12102432020-03-26 11:37:15 -07007938 xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
Jiri Pirko8273fd82019-10-05 08:10:31 +02007939 __devlink_net_set(devlink, &init_net);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007940 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02007941 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007942 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007943 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03007944 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03007945 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02007946 INIT_LIST_HEAD(&devlink->reporter_list);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007947 INIT_LIST_HEAD(&devlink->trap_list);
7948 INIT_LIST_HEAD(&devlink->trap_group_list);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007949 INIT_LIST_HEAD(&devlink->trap_policer_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007950 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007951 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007952 return devlink;
7953}
7954EXPORT_SYMBOL_GPL(devlink_alloc);
7955
7956/**
7957 * devlink_register - Register devlink instance
7958 *
7959 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007960 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007961 */
7962int devlink_register(struct devlink *devlink, struct device *dev)
7963{
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007964 devlink->dev = dev;
Jiri Pirko8273fd82019-10-05 08:10:31 +02007965 devlink->registered = true;
Parav Pandit6553e562020-07-21 19:53:51 +03007966 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007967 list_add_tail(&devlink->list, &devlink_list);
7968 devlink_notify(devlink, DEVLINK_CMD_NEW);
7969 mutex_unlock(&devlink_mutex);
7970 return 0;
7971}
7972EXPORT_SYMBOL_GPL(devlink_register);
7973
7974/**
7975 * devlink_unregister - Unregister devlink instance
7976 *
7977 * @devlink: devlink
7978 */
7979void devlink_unregister(struct devlink *devlink)
7980{
7981 mutex_lock(&devlink_mutex);
Moshe Shemesh69d56e02020-10-07 09:00:42 +03007982 WARN_ON(devlink_reload_supported(devlink->ops) &&
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007983 devlink->reload_enabled);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007984 devlink_notify(devlink, DEVLINK_CMD_DEL);
7985 list_del(&devlink->list);
7986 mutex_unlock(&devlink_mutex);
7987}
7988EXPORT_SYMBOL_GPL(devlink_unregister);
7989
7990/**
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007991 * devlink_reload_enable - Enable reload of devlink instance
7992 *
7993 * @devlink: devlink
7994 *
7995 * Should be called at end of device initialization
7996 * process when reload operation is supported.
7997 */
7998void devlink_reload_enable(struct devlink *devlink)
7999{
8000 mutex_lock(&devlink_mutex);
8001 devlink->reload_enabled = true;
8002 mutex_unlock(&devlink_mutex);
8003}
8004EXPORT_SYMBOL_GPL(devlink_reload_enable);
8005
8006/**
8007 * devlink_reload_disable - Disable reload of devlink instance
8008 *
8009 * @devlink: devlink
8010 *
8011 * Should be called at the beginning of device cleanup
8012 * process when reload operation is supported.
8013 */
8014void devlink_reload_disable(struct devlink *devlink)
8015{
8016 mutex_lock(&devlink_mutex);
8017 /* Mutex is taken which ensures that no reload operation is in
8018 * progress while setting up forbidded flag.
8019 */
8020 devlink->reload_enabled = false;
8021 mutex_unlock(&devlink_mutex);
8022}
8023EXPORT_SYMBOL_GPL(devlink_reload_disable);
8024
8025/**
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008026 * devlink_free - Free devlink instance resources
8027 *
8028 * @devlink: devlink
8029 */
8030void devlink_free(struct devlink *devlink)
8031{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03008032 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01008033 mutex_destroy(&devlink->lock);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03008034 WARN_ON(!list_empty(&devlink->trap_policer_list));
Ido Schimmel0f420b62019-08-17 16:28:17 +03008035 WARN_ON(!list_empty(&devlink->trap_group_list));
8036 WARN_ON(!list_empty(&devlink->trap_list));
Parav Panditb904aad2019-02-08 15:15:00 -06008037 WARN_ON(!list_empty(&devlink->reporter_list));
8038 WARN_ON(!list_empty(&devlink->region_list));
8039 WARN_ON(!list_empty(&devlink->param_list));
8040 WARN_ON(!list_empty(&devlink->resource_list));
8041 WARN_ON(!list_empty(&devlink->dpipe_table_list));
8042 WARN_ON(!list_empty(&devlink->sb_list));
8043 WARN_ON(!list_empty(&devlink->port_list));
8044
Jacob Keller12102432020-03-26 11:37:15 -07008045 xa_destroy(&devlink->snapshot_ids);
8046
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008047 kfree(devlink);
8048}
8049EXPORT_SYMBOL_GPL(devlink_free);
8050
Jiri Pirko136bf272019-05-23 10:43:35 +02008051static void devlink_port_type_warn(struct work_struct *work)
8052{
8053 WARN(true, "Type was not set for devlink port.");
8054}
8055
8056static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
8057{
8058 /* Ignore CPU and DSA flavours. */
8059 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
Andrew Lunncf116632020-10-04 18:12:51 +02008060 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA &&
8061 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_UNUSED;
Jiri Pirko136bf272019-05-23 10:43:35 +02008062}
8063
Ido Schimmel4c582232020-01-09 19:57:41 +02008064#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
Jiri Pirko136bf272019-05-23 10:43:35 +02008065
8066static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
8067{
8068 if (!devlink_port_type_should_warn(devlink_port))
8069 return;
8070 /* Schedule a work to WARN in case driver does not set port
8071 * type within timeout.
8072 */
8073 schedule_delayed_work(&devlink_port->type_warn_dw,
8074 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
8075}
8076
8077static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
8078{
8079 if (!devlink_port_type_should_warn(devlink_port))
8080 return;
8081 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
8082}
8083
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008084/**
8085 * devlink_port_register - Register devlink port
8086 *
8087 * @devlink: devlink
8088 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008089 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008090 *
8091 * Register devlink port with provided port index. User can use
8092 * any indexing, even hw-related one. devlink_port structure
8093 * is convenient to be embedded inside user driver private structure.
8094 * Note that the caller should take care of zeroing the devlink_port
8095 * structure.
8096 */
8097int devlink_port_register(struct devlink *devlink,
8098 struct devlink_port *devlink_port,
8099 unsigned int port_index)
8100{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008101 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008102 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008103 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008104 return -EEXIST;
8105 }
8106 devlink_port->devlink = devlink;
8107 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008108 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01008109 spin_lock_init(&devlink_port->type_lock);
Parav Pandit79604c52020-08-21 22:12:20 +03008110 INIT_LIST_HEAD(&devlink_port->reporter_list);
8111 mutex_init(&devlink_port->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008112 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308113 INIT_LIST_HEAD(&devlink_port->param_list);
Andrew Lunn544e7c32020-10-04 18:12:54 +02008114 INIT_LIST_HEAD(&devlink_port->region_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008115 mutex_unlock(&devlink->lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02008116 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
8117 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008118 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
8119 return 0;
8120}
8121EXPORT_SYMBOL_GPL(devlink_port_register);
8122
8123/**
8124 * devlink_port_unregister - Unregister devlink port
8125 *
8126 * @devlink_port: devlink port
8127 */
8128void devlink_port_unregister(struct devlink_port *devlink_port)
8129{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008130 struct devlink *devlink = devlink_port->devlink;
8131
Jiri Pirko136bf272019-05-23 10:43:35 +02008132 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008133 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008134 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008135 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008136 mutex_unlock(&devlink->lock);
Parav Pandit79604c52020-08-21 22:12:20 +03008137 WARN_ON(!list_empty(&devlink_port->reporter_list));
Andrew Lunn544e7c32020-10-04 18:12:54 +02008138 WARN_ON(!list_empty(&devlink_port->region_list));
Parav Pandit79604c52020-08-21 22:12:20 +03008139 mutex_destroy(&devlink_port->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008140}
8141EXPORT_SYMBOL_GPL(devlink_port_unregister);
8142
8143static void __devlink_port_type_set(struct devlink_port *devlink_port,
8144 enum devlink_port_type type,
8145 void *type_dev)
8146{
Jiri Pirko2b239e72019-03-24 11:14:36 +01008147 if (WARN_ON(!devlink_port->registered))
8148 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02008149 devlink_port_type_warn_cancel(devlink_port);
Ido Schimmel0f420b62019-08-17 16:28:17 +03008150 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008151 devlink_port->type = type;
8152 devlink_port->type_dev = type_dev;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008153 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008154 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
8155}
8156
Jakub Kicinski3ea87ca2020-09-08 15:21:13 -07008157static void devlink_port_type_netdev_checks(struct devlink_port *devlink_port,
8158 struct net_device *netdev)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008159{
Jiri Pirko119c0b52019-04-03 14:24:27 +02008160 const struct net_device_ops *ops = netdev->netdev_ops;
8161
Jiri Pirko746364f2019-03-28 13:56:46 +01008162 /* If driver registers devlink port, it should set devlink port
8163 * attributes accordingly so the compat functions are called
8164 * and the original ops are not used.
8165 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02008166 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01008167 /* Some drivers use the same set of ndos for netdevs
8168 * that have devlink_port registered and also for
8169 * those who don't. Make sure that ndo_get_phys_port_name
8170 * returns -EOPNOTSUPP here in case it is defined.
8171 * Warn if not.
8172 */
Jiri Pirko746364f2019-03-28 13:56:46 +01008173 char name[IFNAMSIZ];
8174 int err;
8175
8176 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
8177 WARN_ON(err != -EOPNOTSUPP);
8178 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02008179 if (ops->ndo_get_port_parent_id) {
8180 /* Some drivers use the same set of ndos for netdevs
8181 * that have devlink_port registered and also for
8182 * those who don't. Make sure that ndo_get_port_parent_id
8183 * returns -EOPNOTSUPP here in case it is defined.
8184 * Warn if not.
8185 */
8186 struct netdev_phys_item_id ppid;
8187 int err;
8188
8189 err = ops->ndo_get_port_parent_id(netdev, &ppid);
8190 WARN_ON(err != -EOPNOTSUPP);
8191 }
Jakub Kicinski3ea87ca2020-09-08 15:21:13 -07008192}
8193
8194/**
8195 * devlink_port_type_eth_set - Set port type to Ethernet
8196 *
8197 * @devlink_port: devlink port
8198 * @netdev: related netdevice
8199 */
8200void devlink_port_type_eth_set(struct devlink_port *devlink_port,
8201 struct net_device *netdev)
8202{
8203 if (netdev)
8204 devlink_port_type_netdev_checks(devlink_port, netdev);
8205 else
8206 dev_warn(devlink_port->devlink->dev,
8207 "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
8208 devlink_port->index);
8209
Jiri Pirko773b1f32019-03-24 11:14:30 +01008210 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008211}
8212EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
8213
8214/**
8215 * devlink_port_type_ib_set - Set port type to InfiniBand
8216 *
8217 * @devlink_port: devlink port
8218 * @ibdev: related IB device
8219 */
8220void devlink_port_type_ib_set(struct devlink_port *devlink_port,
8221 struct ib_device *ibdev)
8222{
Jiri Pirko773b1f32019-03-24 11:14:30 +01008223 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008224}
8225EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
8226
8227/**
8228 * devlink_port_type_clear - Clear port type
8229 *
8230 * @devlink_port: devlink port
8231 */
8232void devlink_port_type_clear(struct devlink_port *devlink_port)
8233{
Jiri Pirko773b1f32019-03-24 11:14:30 +01008234 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02008235 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008236}
8237EXPORT_SYMBOL_GPL(devlink_port_type_clear);
8238
Parav Pandit378ef012019-07-08 23:17:35 -05008239static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008240 enum devlink_port_flavour flavour)
Parav Pandit378ef012019-07-08 23:17:35 -05008241{
8242 struct devlink_port_attrs *attrs = &devlink_port->attrs;
8243
8244 if (WARN_ON(devlink_port->registered))
8245 return -EEXIST;
Danielle Ratson10a429b2020-07-09 16:18:14 +03008246 devlink_port->attrs_set = true;
Parav Pandit378ef012019-07-08 23:17:35 -05008247 attrs->flavour = flavour;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008248 if (attrs->switch_id.id_len) {
Danielle Ratson46737a12020-07-09 16:18:15 +03008249 devlink_port->switch_port = true;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008250 if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
8251 attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
Parav Pandit378ef012019-07-08 23:17:35 -05008252 } else {
Danielle Ratson46737a12020-07-09 16:18:15 +03008253 devlink_port->switch_port = false;
Parav Pandit378ef012019-07-08 23:17:35 -05008254 }
8255 return 0;
8256}
8257
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008258/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02008259 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008260 *
8261 * @devlink_port: devlink port
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008262 * @attrs: devlink port attrs
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008263 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02008264void devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008265 struct devlink_port_attrs *attrs)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008266{
Parav Pandit378ef012019-07-08 23:17:35 -05008267 int ret;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02008268
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008269 devlink_port->attrs = *attrs;
8270 ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
Parav Pandit378ef012019-07-08 23:17:35 -05008271 if (ret)
Jiri Pirko45b86112019-03-24 11:14:33 +01008272 return;
Danielle Ratsona0f49b52020-07-09 16:18:20 +03008273 WARN_ON(attrs->splittable && attrs->split);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008274}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02008275EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008276
Parav Pandit98fd2d62019-07-08 23:17:37 -05008277/**
8278 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
8279 *
8280 * @devlink_port: devlink port
Parav Pandit3a2d9582020-09-09 07:50:37 +03008281 * @controller: associated controller number for the devlink port instance
Parav Pandit98fd2d62019-07-08 23:17:37 -05008282 * @pf: associated PF for the devlink port instance
Parav Pandit05b595e2020-09-09 07:50:36 +03008283 * @external: indicates if the port is for an external controller
Parav Pandit98fd2d62019-07-08 23:17:37 -05008284 */
Parav Pandit3a2d9582020-09-09 07:50:37 +03008285void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 controller,
8286 u16 pf, bool external)
Parav Pandit98fd2d62019-07-08 23:17:37 -05008287{
8288 struct devlink_port_attrs *attrs = &devlink_port->attrs;
8289 int ret;
8290
8291 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008292 DEVLINK_PORT_FLAVOUR_PCI_PF);
Parav Pandit98fd2d62019-07-08 23:17:37 -05008293 if (ret)
8294 return;
Parav Pandit3a2d9582020-09-09 07:50:37 +03008295 attrs->pci_pf.controller = controller;
Parav Pandit98fd2d62019-07-08 23:17:37 -05008296 attrs->pci_pf.pf = pf;
Parav Pandit05b595e2020-09-09 07:50:36 +03008297 attrs->pci_pf.external = external;
Parav Pandit98fd2d62019-07-08 23:17:37 -05008298}
8299EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
8300
Parav Pandite41b6bf2019-07-08 23:17:38 -05008301/**
8302 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
8303 *
8304 * @devlink_port: devlink port
Parav Pandit3a2d9582020-09-09 07:50:37 +03008305 * @controller: associated controller number for the devlink port instance
Parav Pandite41b6bf2019-07-08 23:17:38 -05008306 * @pf: associated PF for the devlink port instance
8307 * @vf: associated VF of a PF for the devlink port instance
Parav Pandit05b595e2020-09-09 07:50:36 +03008308 * @external: indicates if the port is for an external controller
Parav Pandite41b6bf2019-07-08 23:17:38 -05008309 */
Parav Pandit3a2d9582020-09-09 07:50:37 +03008310void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller,
Parav Pandit05b595e2020-09-09 07:50:36 +03008311 u16 pf, u16 vf, bool external)
Parav Pandite41b6bf2019-07-08 23:17:38 -05008312{
8313 struct devlink_port_attrs *attrs = &devlink_port->attrs;
8314 int ret;
8315
8316 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03008317 DEVLINK_PORT_FLAVOUR_PCI_VF);
Parav Pandite41b6bf2019-07-08 23:17:38 -05008318 if (ret)
8319 return;
Parav Pandit3a2d9582020-09-09 07:50:37 +03008320 attrs->pci_vf.controller = controller;
Parav Pandite41b6bf2019-07-08 23:17:38 -05008321 attrs->pci_vf.pf = pf;
8322 attrs->pci_vf.vf = vf;
Parav Pandit05b595e2020-09-09 07:50:36 +03008323 attrs->pci_vf.external = external;
Parav Pandite41b6bf2019-07-08 23:17:38 -05008324}
8325EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
8326
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01008327static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
8328 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02008329{
8330 struct devlink_port_attrs *attrs = &devlink_port->attrs;
8331 int n = 0;
8332
Danielle Ratson10a429b2020-07-09 16:18:14 +03008333 if (!devlink_port->attrs_set)
Jiri Pirko08474c12018-05-18 09:29:02 +02008334 return -EOPNOTSUPP;
8335
8336 switch (attrs->flavour) {
8337 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
Parav Panditacf1ee42020-03-03 08:12:42 -06008338 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Jiri Pirko08474c12018-05-18 09:29:02 +02008339 if (!attrs->split)
Parav Pandit378ef012019-07-08 23:17:35 -05008340 n = snprintf(name, len, "p%u", attrs->phys.port_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02008341 else
Parav Pandit378ef012019-07-08 23:17:35 -05008342 n = snprintf(name, len, "p%us%u",
8343 attrs->phys.port_number,
8344 attrs->phys.split_subport_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02008345 break;
8346 case DEVLINK_PORT_FLAVOUR_CPU:
8347 case DEVLINK_PORT_FLAVOUR_DSA:
Andrew Lunncf116632020-10-04 18:12:51 +02008348 case DEVLINK_PORT_FLAVOUR_UNUSED:
Jiri Pirko08474c12018-05-18 09:29:02 +02008349 /* As CPU and DSA ports do not have a netdevice associated
8350 * case should not ever happen.
8351 */
8352 WARN_ON(1);
8353 return -EINVAL;
Parav Pandit98fd2d62019-07-08 23:17:37 -05008354 case DEVLINK_PORT_FLAVOUR_PCI_PF:
Parav Pandit66b17082020-09-09 07:50:38 +03008355 if (attrs->pci_pf.external) {
8356 n = snprintf(name, len, "c%u", attrs->pci_pf.controller);
8357 if (n >= len)
8358 return -EINVAL;
8359 len -= n;
8360 name += n;
8361 }
Parav Pandit98fd2d62019-07-08 23:17:37 -05008362 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
8363 break;
Parav Pandite41b6bf2019-07-08 23:17:38 -05008364 case DEVLINK_PORT_FLAVOUR_PCI_VF:
Parav Pandit66b17082020-09-09 07:50:38 +03008365 if (attrs->pci_vf.external) {
8366 n = snprintf(name, len, "c%u", attrs->pci_vf.controller);
8367 if (n >= len)
8368 return -EINVAL;
8369 len -= n;
8370 name += n;
8371 }
Parav Pandite41b6bf2019-07-08 23:17:38 -05008372 n = snprintf(name, len, "pf%uvf%u",
8373 attrs->pci_vf.pf, attrs->pci_vf.vf);
8374 break;
Jiri Pirko08474c12018-05-18 09:29:02 +02008375 }
8376
8377 if (n >= len)
8378 return -EINVAL;
8379
8380 return 0;
8381}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01008382
Jiri Pirkobf797472016-04-14 18:19:13 +02008383int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
8384 u32 size, u16 ingress_pools_count,
8385 u16 egress_pools_count, u16 ingress_tc_count,
8386 u16 egress_tc_count)
8387{
8388 struct devlink_sb *devlink_sb;
8389 int err = 0;
8390
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008391 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02008392 if (devlink_sb_index_exists(devlink, sb_index)) {
8393 err = -EEXIST;
8394 goto unlock;
8395 }
8396
8397 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
8398 if (!devlink_sb) {
8399 err = -ENOMEM;
8400 goto unlock;
8401 }
8402 devlink_sb->index = sb_index;
8403 devlink_sb->size = size;
8404 devlink_sb->ingress_pools_count = ingress_pools_count;
8405 devlink_sb->egress_pools_count = egress_pools_count;
8406 devlink_sb->ingress_tc_count = ingress_tc_count;
8407 devlink_sb->egress_tc_count = egress_tc_count;
8408 list_add_tail(&devlink_sb->list, &devlink->sb_list);
8409unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008410 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02008411 return err;
8412}
8413EXPORT_SYMBOL_GPL(devlink_sb_register);
8414
8415void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
8416{
8417 struct devlink_sb *devlink_sb;
8418
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008419 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02008420 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
8421 WARN_ON(!devlink_sb);
8422 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008423 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02008424 kfree(devlink_sb);
8425}
8426EXPORT_SYMBOL_GPL(devlink_sb_unregister);
8427
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008428/**
8429 * devlink_dpipe_headers_register - register dpipe headers
8430 *
8431 * @devlink: devlink
8432 * @dpipe_headers: dpipe header array
8433 *
8434 * Register the headers supported by hardware.
8435 */
8436int devlink_dpipe_headers_register(struct devlink *devlink,
8437 struct devlink_dpipe_headers *dpipe_headers)
8438{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008439 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008440 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008441 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008442 return 0;
8443}
8444EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
8445
8446/**
8447 * devlink_dpipe_headers_unregister - unregister dpipe headers
8448 *
8449 * @devlink: devlink
8450 *
8451 * Unregister the headers supported by hardware.
8452 */
8453void devlink_dpipe_headers_unregister(struct devlink *devlink)
8454{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008455 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008456 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008457 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008458}
8459EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
8460
8461/**
8462 * devlink_dpipe_table_counter_enabled - check if counter allocation
8463 * required
8464 * @devlink: devlink
8465 * @table_name: tables name
8466 *
8467 * Used by driver to check if counter allocation is required.
8468 * After counter allocation is turned on the table entries
8469 * are updated to include counter statistics.
8470 *
8471 * After that point on the driver must respect the counter
8472 * state so that each entry added to the table is added
8473 * with a counter.
8474 */
8475bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
8476 const char *table_name)
8477{
8478 struct devlink_dpipe_table *table;
8479 bool enabled;
8480
8481 rcu_read_lock();
8482 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308483 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008484 enabled = false;
8485 if (table)
8486 enabled = table->counters_enabled;
8487 rcu_read_unlock();
8488 return enabled;
8489}
8490EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
8491
8492/**
8493 * devlink_dpipe_table_register - register dpipe table
8494 *
8495 * @devlink: devlink
8496 * @table_name: table name
8497 * @table_ops: table ops
8498 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008499 * @counter_control_extern: external control for counters
8500 */
8501int devlink_dpipe_table_register(struct devlink *devlink,
8502 const char *table_name,
8503 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02008504 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008505{
8506 struct devlink_dpipe_table *table;
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308507 int err = 0;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008508
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02008509 if (WARN_ON(!table_ops->size_get))
8510 return -EINVAL;
8511
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308512 mutex_lock(&devlink->lock);
8513
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308514 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
8515 devlink)) {
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308516 err = -EEXIST;
8517 goto unlock;
8518 }
8519
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008520 table = kzalloc(sizeof(*table), GFP_KERNEL);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308521 if (!table) {
8522 err = -ENOMEM;
8523 goto unlock;
8524 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008525
8526 table->name = table_name;
8527 table->table_ops = table_ops;
8528 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008529 table->counter_control_extern = counter_control_extern;
8530
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008531 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308532unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008533 mutex_unlock(&devlink->lock);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308534 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008535}
8536EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
8537
8538/**
8539 * devlink_dpipe_table_unregister - unregister dpipe table
8540 *
8541 * @devlink: devlink
8542 * @table_name: table name
8543 */
8544void devlink_dpipe_table_unregister(struct devlink *devlink,
8545 const char *table_name)
8546{
8547 struct devlink_dpipe_table *table;
8548
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008549 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008550 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308551 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008552 if (!table)
8553 goto unlock;
8554 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008555 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008556 kfree_rcu(table, rcu);
8557 return;
8558unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008559 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008560}
8561EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
8562
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008563/**
8564 * devlink_resource_register - devlink resource register
8565 *
8566 * @devlink: devlink
8567 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008568 * @resource_size: resource's size
8569 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008570 * @parent_resource_id: resource's parent id
8571 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008572 */
8573int devlink_resource_register(struct devlink *devlink,
8574 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008575 u64 resource_size,
8576 u64 resource_id,
8577 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02008578 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008579{
8580 struct devlink_resource *resource;
8581 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07008582 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008583 int err = 0;
8584
David Ahern14530742018-03-20 19:31:14 -07008585 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
8586
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008587 mutex_lock(&devlink->lock);
8588 resource = devlink_resource_find(devlink, NULL, resource_id);
8589 if (resource) {
8590 err = -EINVAL;
8591 goto out;
8592 }
8593
8594 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
8595 if (!resource) {
8596 err = -ENOMEM;
8597 goto out;
8598 }
8599
8600 if (top_hierarchy) {
8601 resource_list = &devlink->resource_list;
8602 } else {
8603 struct devlink_resource *parent_resource;
8604
8605 parent_resource = devlink_resource_find(devlink, NULL,
8606 parent_resource_id);
8607 if (parent_resource) {
8608 resource_list = &parent_resource->resource_list;
8609 resource->parent = parent_resource;
8610 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00008611 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008612 err = -EINVAL;
8613 goto out;
8614 }
8615 }
8616
8617 resource->name = resource_name;
8618 resource->size = resource_size;
8619 resource->size_new = resource_size;
8620 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008621 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01008622 memcpy(&resource->size_params, size_params,
8623 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008624 INIT_LIST_HEAD(&resource->resource_list);
8625 list_add_tail(&resource->list, resource_list);
8626out:
8627 mutex_unlock(&devlink->lock);
8628 return err;
8629}
8630EXPORT_SYMBOL_GPL(devlink_resource_register);
8631
8632/**
8633 * devlink_resources_unregister - free all resources
8634 *
8635 * @devlink: devlink
8636 * @resource: resource
8637 */
8638void devlink_resources_unregister(struct devlink *devlink,
8639 struct devlink_resource *resource)
8640{
8641 struct devlink_resource *tmp, *child_resource;
8642 struct list_head *resource_list;
8643
8644 if (resource)
8645 resource_list = &resource->resource_list;
8646 else
8647 resource_list = &devlink->resource_list;
8648
8649 if (!resource)
8650 mutex_lock(&devlink->lock);
8651
8652 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
8653 devlink_resources_unregister(devlink, child_resource);
8654 list_del(&child_resource->list);
8655 kfree(child_resource);
8656 }
8657
8658 if (!resource)
8659 mutex_unlock(&devlink->lock);
8660}
8661EXPORT_SYMBOL_GPL(devlink_resources_unregister);
8662
8663/**
8664 * devlink_resource_size_get - get and update size
8665 *
8666 * @devlink: devlink
8667 * @resource_id: the requested resource id
8668 * @p_resource_size: ptr to update
8669 */
8670int devlink_resource_size_get(struct devlink *devlink,
8671 u64 resource_id,
8672 u64 *p_resource_size)
8673{
8674 struct devlink_resource *resource;
8675 int err = 0;
8676
8677 mutex_lock(&devlink->lock);
8678 resource = devlink_resource_find(devlink, NULL, resource_id);
8679 if (!resource) {
8680 err = -EINVAL;
8681 goto out;
8682 }
8683 *p_resource_size = resource->size_new;
8684 resource->size = resource->size_new;
8685out:
8686 mutex_unlock(&devlink->lock);
8687 return err;
8688}
8689EXPORT_SYMBOL_GPL(devlink_resource_size_get);
8690
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008691/**
8692 * devlink_dpipe_table_resource_set - set the resource id
8693 *
8694 * @devlink: devlink
8695 * @table_name: table name
8696 * @resource_id: resource id
8697 * @resource_units: number of resource's units consumed per table's entry
8698 */
8699int devlink_dpipe_table_resource_set(struct devlink *devlink,
8700 const char *table_name, u64 resource_id,
8701 u64 resource_units)
8702{
8703 struct devlink_dpipe_table *table;
8704 int err = 0;
8705
8706 mutex_lock(&devlink->lock);
8707 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308708 table_name, devlink);
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008709 if (!table) {
8710 err = -EINVAL;
8711 goto out;
8712 }
8713 table->resource_id = resource_id;
8714 table->resource_units = resource_units;
8715 table->resource_valid = true;
8716out:
8717 mutex_unlock(&devlink->lock);
8718 return err;
8719}
8720EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
8721
Jiri Pirkofc56be42018-04-05 22:13:21 +02008722/**
8723 * devlink_resource_occ_get_register - register occupancy getter
8724 *
8725 * @devlink: devlink
8726 * @resource_id: resource id
8727 * @occ_get: occupancy getter callback
8728 * @occ_get_priv: occupancy getter callback priv
8729 */
8730void devlink_resource_occ_get_register(struct devlink *devlink,
8731 u64 resource_id,
8732 devlink_resource_occ_get_t *occ_get,
8733 void *occ_get_priv)
8734{
8735 struct devlink_resource *resource;
8736
8737 mutex_lock(&devlink->lock);
8738 resource = devlink_resource_find(devlink, NULL, resource_id);
8739 if (WARN_ON(!resource))
8740 goto out;
8741 WARN_ON(resource->occ_get);
8742
8743 resource->occ_get = occ_get;
8744 resource->occ_get_priv = occ_get_priv;
8745out:
8746 mutex_unlock(&devlink->lock);
8747}
8748EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
8749
8750/**
8751 * devlink_resource_occ_get_unregister - unregister occupancy getter
8752 *
8753 * @devlink: devlink
8754 * @resource_id: resource id
8755 */
8756void devlink_resource_occ_get_unregister(struct devlink *devlink,
8757 u64 resource_id)
8758{
8759 struct devlink_resource *resource;
8760
8761 mutex_lock(&devlink->lock);
8762 resource = devlink_resource_find(devlink, NULL, resource_id);
8763 if (WARN_ON(!resource))
8764 goto out;
8765 WARN_ON(!resource->occ_get);
8766
8767 resource->occ_get = NULL;
8768 resource->occ_get_priv = NULL;
8769out:
8770 mutex_unlock(&devlink->lock);
8771}
8772EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
8773
Vasundhara Volam39e61602019-01-28 18:00:20 +05308774static int devlink_param_verify(const struct devlink_param *param)
8775{
8776 if (!param || !param->name || !param->supported_cmodes)
8777 return -EINVAL;
8778 if (param->generic)
8779 return devlink_param_generic_verify(param);
8780 else
8781 return devlink_param_driver_verify(param);
8782}
8783
8784static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308785 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308786 struct list_head *param_list,
8787 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308788 size_t params_count,
8789 enum devlink_command reg_cmd,
8790 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308791{
8792 const struct devlink_param *param = params;
8793 int i;
8794 int err;
8795
8796 mutex_lock(&devlink->lock);
8797 for (i = 0; i < params_count; i++, param++) {
8798 err = devlink_param_verify(param);
8799 if (err)
8800 goto rollback;
8801
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308802 err = devlink_param_register_one(devlink, port_index,
8803 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308804 if (err)
8805 goto rollback;
8806 }
8807
8808 mutex_unlock(&devlink->lock);
8809 return 0;
8810
8811rollback:
8812 if (!i)
8813 goto unlock;
8814 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308815 devlink_param_unregister_one(devlink, port_index, param_list,
8816 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308817unlock:
8818 mutex_unlock(&devlink->lock);
8819 return err;
8820}
8821
8822static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308823 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308824 struct list_head *param_list,
8825 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308826 size_t params_count,
8827 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308828{
8829 const struct devlink_param *param = params;
8830 int i;
8831
8832 mutex_lock(&devlink->lock);
8833 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308834 devlink_param_unregister_one(devlink, 0, param_list, param,
8835 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308836 mutex_unlock(&devlink->lock);
8837}
8838
Moshe Shemesheabaef12018-07-04 14:30:28 +03008839/**
8840 * devlink_params_register - register configuration parameters
8841 *
8842 * @devlink: devlink
8843 * @params: configuration parameters array
8844 * @params_count: number of parameters provided
8845 *
8846 * Register the configuration parameters supported by the driver.
8847 */
8848int devlink_params_register(struct devlink *devlink,
8849 const struct devlink_param *params,
8850 size_t params_count)
8851{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308852 return __devlink_params_register(devlink, 0, &devlink->param_list,
8853 params, params_count,
8854 DEVLINK_CMD_PARAM_NEW,
8855 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008856}
8857EXPORT_SYMBOL_GPL(devlink_params_register);
8858
8859/**
8860 * devlink_params_unregister - unregister configuration parameters
8861 * @devlink: devlink
8862 * @params: configuration parameters to unregister
8863 * @params_count: number of parameters provided
8864 */
8865void devlink_params_unregister(struct devlink *devlink,
8866 const struct devlink_param *params,
8867 size_t params_count)
8868{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308869 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
8870 params, params_count,
8871 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008872}
8873EXPORT_SYMBOL_GPL(devlink_params_unregister);
8874
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008875/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00008876 * devlink_params_publish - publish configuration parameters
8877 *
8878 * @devlink: devlink
8879 *
8880 * Publish previously registered configuration parameters.
8881 */
8882void devlink_params_publish(struct devlink *devlink)
8883{
8884 struct devlink_param_item *param_item;
8885
8886 list_for_each_entry(param_item, &devlink->param_list, list) {
8887 if (param_item->published)
8888 continue;
8889 param_item->published = true;
8890 devlink_param_notify(devlink, 0, param_item,
8891 DEVLINK_CMD_PARAM_NEW);
8892 }
8893}
8894EXPORT_SYMBOL_GPL(devlink_params_publish);
8895
8896/**
8897 * devlink_params_unpublish - unpublish configuration parameters
8898 *
8899 * @devlink: devlink
8900 *
8901 * Unpublish previously registered configuration parameters.
8902 */
8903void devlink_params_unpublish(struct devlink *devlink)
8904{
8905 struct devlink_param_item *param_item;
8906
8907 list_for_each_entry(param_item, &devlink->param_list, list) {
8908 if (!param_item->published)
8909 continue;
8910 param_item->published = false;
8911 devlink_param_notify(devlink, 0, param_item,
8912 DEVLINK_CMD_PARAM_DEL);
8913 }
8914}
8915EXPORT_SYMBOL_GPL(devlink_params_unpublish);
8916
8917/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05308918 * devlink_port_params_register - register port configuration parameters
8919 *
8920 * @devlink_port: devlink port
8921 * @params: configuration parameters array
8922 * @params_count: number of parameters provided
8923 *
8924 * Register the configuration parameters supported by the port.
8925 */
8926int devlink_port_params_register(struct devlink_port *devlink_port,
8927 const struct devlink_param *params,
8928 size_t params_count)
8929{
8930 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308931 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308932 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308933 params_count,
8934 DEVLINK_CMD_PORT_PARAM_NEW,
8935 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308936}
8937EXPORT_SYMBOL_GPL(devlink_port_params_register);
8938
8939/**
8940 * devlink_port_params_unregister - unregister port configuration
8941 * parameters
8942 *
8943 * @devlink_port: devlink port
8944 * @params: configuration parameters array
8945 * @params_count: number of parameters provided
8946 */
8947void devlink_port_params_unregister(struct devlink_port *devlink_port,
8948 const struct devlink_param *params,
8949 size_t params_count)
8950{
8951 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308952 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308953 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308954 params, params_count,
8955 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308956}
8957EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
8958
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308959static int
8960__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
8961 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008962{
8963 struct devlink_param_item *param_item;
8964
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308965 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008966 if (!param_item)
8967 return -EINVAL;
8968
8969 if (!param_item->driverinit_value_valid ||
8970 !devlink_param_cmode_is_supported(param_item->param,
8971 DEVLINK_PARAM_CMODE_DRIVERINIT))
8972 return -EOPNOTSUPP;
8973
Moshe Shemesh12765342018-10-10 16:09:26 +03008974 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8975 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
8976 else
8977 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008978
8979 return 0;
8980}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308981
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308982static int
8983__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308984 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308985 struct list_head *param_list, u32 param_id,
8986 union devlink_param_value init_val,
8987 enum devlink_command cmd)
8988{
8989 struct devlink_param_item *param_item;
8990
8991 param_item = devlink_param_find_by_id(param_list, param_id);
8992 if (!param_item)
8993 return -EINVAL;
8994
8995 if (!devlink_param_cmode_is_supported(param_item->param,
8996 DEVLINK_PARAM_CMODE_DRIVERINIT))
8997 return -EOPNOTSUPP;
8998
8999 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
9000 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
9001 else
9002 param_item->driverinit_value = init_val;
9003 param_item->driverinit_value_valid = true;
9004
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309005 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309006 return 0;
9007}
9008
Vasundhara Volamffd19b92019-01-28 18:00:23 +05309009/**
9010 * devlink_param_driverinit_value_get - get configuration parameter
9011 * value for driver initializing
9012 *
9013 * @devlink: devlink
9014 * @param_id: parameter ID
9015 * @init_val: value of parameter in driverinit configuration mode
9016 *
9017 * This function should be used by the driver to get driverinit
9018 * configuration for initialization after reload command.
9019 */
9020int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
9021 union devlink_param_value *init_val)
9022{
Moshe Shemesh69d56e02020-10-07 09:00:42 +03009023 if (!devlink_reload_supported(devlink->ops))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05309024 return -EOPNOTSUPP;
9025
9026 return __devlink_param_driverinit_value_get(&devlink->param_list,
9027 param_id, init_val);
9028}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03009029EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
9030
9031/**
9032 * devlink_param_driverinit_value_set - set value of configuration
9033 * parameter for driverinit
9034 * configuration mode
9035 *
9036 * @devlink: devlink
9037 * @param_id: parameter ID
9038 * @init_val: value of parameter to set for driverinit configuration mode
9039 *
9040 * This function should be used by the driver to set driverinit
9041 * configuration mode default value.
9042 */
9043int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
9044 union devlink_param_value init_val)
9045{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309046 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309047 &devlink->param_list,
9048 param_id, init_val,
9049 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03009050}
9051EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
9052
Moshe Shemeshea601e12018-07-04 14:30:32 +03009053/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05309054 * devlink_port_param_driverinit_value_get - get configuration parameter
9055 * value for driver initializing
9056 *
9057 * @devlink_port: devlink_port
9058 * @param_id: parameter ID
9059 * @init_val: value of parameter in driverinit configuration mode
9060 *
9061 * This function should be used by the driver to get driverinit
9062 * configuration for initialization after reload command.
9063 */
9064int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
9065 u32 param_id,
9066 union devlink_param_value *init_val)
9067{
9068 struct devlink *devlink = devlink_port->devlink;
9069
Moshe Shemesh69d56e02020-10-07 09:00:42 +03009070 if (!devlink_reload_supported(devlink->ops))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05309071 return -EOPNOTSUPP;
9072
9073 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
9074 param_id, init_val);
9075}
9076EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
9077
9078/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309079 * devlink_port_param_driverinit_value_set - set value of configuration
9080 * parameter for driverinit
9081 * configuration mode
9082 *
9083 * @devlink_port: devlink_port
9084 * @param_id: parameter ID
9085 * @init_val: value of parameter to set for driverinit configuration mode
9086 *
9087 * This function should be used by the driver to set driverinit
9088 * configuration mode default value.
9089 */
9090int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
9091 u32 param_id,
9092 union devlink_param_value init_val)
9093{
9094 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309095 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309096 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309097 param_id, init_val,
9098 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05309099}
9100EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
9101
9102/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03009103 * devlink_param_value_changed - notify devlink on a parameter's value
9104 * change. Should be called by the driver
9105 * right after the change.
9106 *
9107 * @devlink: devlink
9108 * @param_id: parameter ID
9109 *
9110 * This function should be used by the driver to notify devlink on value
9111 * change, excluding driverinit configuration mode.
9112 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03009113 */
9114void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
9115{
9116 struct devlink_param_item *param_item;
9117
9118 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
9119 WARN_ON(!param_item);
9120
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309121 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03009122}
9123EXPORT_SYMBOL_GPL(devlink_param_value_changed);
9124
Alex Veskerb16ebe92018-07-12 15:13:08 +03009125/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05309126 * devlink_port_param_value_changed - notify devlink on a parameter's value
9127 * change. Should be called by the driver
9128 * right after the change.
9129 *
9130 * @devlink_port: devlink_port
9131 * @param_id: parameter ID
9132 *
9133 * This function should be used by the driver to notify devlink on value
9134 * change, excluding driverinit configuration mode.
9135 * For driverinit configuration mode driver should use the function
9136 * devlink_port_param_driverinit_value_set() instead.
9137 */
9138void devlink_port_param_value_changed(struct devlink_port *devlink_port,
9139 u32 param_id)
9140{
9141 struct devlink_param_item *param_item;
9142
9143 param_item = devlink_param_find_by_id(&devlink_port->param_list,
9144 param_id);
9145 WARN_ON(!param_item);
9146
9147 devlink_param_notify(devlink_port->devlink, devlink_port->index,
9148 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
9149}
9150EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
9151
9152/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03009153 * devlink_param_value_str_fill - Safely fill-up the string preventing
9154 * from overflow of the preallocated buffer
9155 *
9156 * @dst_val: destination devlink_param_value
9157 * @src: source buffer
9158 */
9159void devlink_param_value_str_fill(union devlink_param_value *dst_val,
9160 const char *src)
9161{
9162 size_t len;
9163
9164 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
9165 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
9166}
9167EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
9168
9169/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03009170 * devlink_region_create - create a new address region
9171 *
9172 * @devlink: devlink
Jacob Kellere8937682020-03-26 11:37:08 -07009173 * @ops: region operations and name
Alex Veskerb16ebe92018-07-12 15:13:08 +03009174 * @region_max_snapshots: Maximum supported number of snapshots for region
9175 * @region_size: size of region
9176 */
Jacob Kellere8937682020-03-26 11:37:08 -07009177struct devlink_region *
9178devlink_region_create(struct devlink *devlink,
9179 const struct devlink_region_ops *ops,
9180 u32 region_max_snapshots, u64 region_size)
Alex Veskerb16ebe92018-07-12 15:13:08 +03009181{
9182 struct devlink_region *region;
9183 int err = 0;
9184
Jacob Kellera0a09f62020-03-26 11:37:09 -07009185 if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
9186 return ERR_PTR(-EINVAL);
9187
Alex Veskerb16ebe92018-07-12 15:13:08 +03009188 mutex_lock(&devlink->lock);
9189
Jacob Kellere8937682020-03-26 11:37:08 -07009190 if (devlink_region_get_by_name(devlink, ops->name)) {
Alex Veskerb16ebe92018-07-12 15:13:08 +03009191 err = -EEXIST;
9192 goto unlock;
9193 }
9194
9195 region = kzalloc(sizeof(*region), GFP_KERNEL);
9196 if (!region) {
9197 err = -ENOMEM;
9198 goto unlock;
9199 }
9200
9201 region->devlink = devlink;
9202 region->max_snapshots = region_max_snapshots;
Jacob Kellere8937682020-03-26 11:37:08 -07009203 region->ops = ops;
Alex Veskerb16ebe92018-07-12 15:13:08 +03009204 region->size = region_size;
9205 INIT_LIST_HEAD(&region->snapshot_list);
9206 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03009207 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03009208
9209 mutex_unlock(&devlink->lock);
9210 return region;
9211
9212unlock:
9213 mutex_unlock(&devlink->lock);
9214 return ERR_PTR(err);
9215}
9216EXPORT_SYMBOL_GPL(devlink_region_create);
9217
9218/**
Andrew Lunn544e7c32020-10-04 18:12:54 +02009219 * devlink_port_region_create - create a new address region for a port
9220 *
9221 * @port: devlink port
9222 * @ops: region operations and name
9223 * @region_max_snapshots: Maximum supported number of snapshots for region
9224 * @region_size: size of region
9225 */
9226struct devlink_region *
9227devlink_port_region_create(struct devlink_port *port,
9228 const struct devlink_port_region_ops *ops,
9229 u32 region_max_snapshots, u64 region_size)
9230{
9231 struct devlink *devlink = port->devlink;
9232 struct devlink_region *region;
9233 int err = 0;
9234
9235 if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
9236 return ERR_PTR(-EINVAL);
9237
9238 mutex_lock(&devlink->lock);
9239
9240 if (devlink_port_region_get_by_name(port, ops->name)) {
9241 err = -EEXIST;
9242 goto unlock;
9243 }
9244
9245 region = kzalloc(sizeof(*region), GFP_KERNEL);
9246 if (!region) {
9247 err = -ENOMEM;
9248 goto unlock;
9249 }
9250
9251 region->devlink = devlink;
9252 region->port = port;
9253 region->max_snapshots = region_max_snapshots;
9254 region->port_ops = ops;
9255 region->size = region_size;
9256 INIT_LIST_HEAD(&region->snapshot_list);
9257 list_add_tail(&region->list, &port->region_list);
9258 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
9259
9260 mutex_unlock(&devlink->lock);
9261 return region;
9262
9263unlock:
9264 mutex_unlock(&devlink->lock);
9265 return ERR_PTR(err);
9266}
9267EXPORT_SYMBOL_GPL(devlink_port_region_create);
9268
9269/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03009270 * devlink_region_destroy - destroy address region
9271 *
9272 * @region: devlink region to destroy
9273 */
9274void devlink_region_destroy(struct devlink_region *region)
9275{
9276 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03009277 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03009278
9279 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03009280
9281 /* Free all snapshots of region */
9282 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
Jiri Pirko92b49822019-08-12 14:28:31 +02009283 devlink_region_snapshot_del(region, snapshot);
Alex Veskerd7e52722018-07-12 15:13:10 +03009284
Alex Veskerb16ebe92018-07-12 15:13:08 +03009285 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03009286
9287 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03009288 mutex_unlock(&devlink->lock);
9289 kfree(region);
9290}
9291EXPORT_SYMBOL_GPL(devlink_region_destroy);
9292
Alex Veskerccadfa42018-07-12 15:13:09 +03009293/**
Jacob Kellerb0efcae2020-01-09 11:08:20 -08009294 * devlink_region_snapshot_id_get - get snapshot ID
Alex Veskerccadfa42018-07-12 15:13:09 +03009295 *
9296 * This callback should be called when adding a new snapshot,
9297 * Driver should use the same id for multiple snapshots taken
9298 * on multiple regions at the same time/by the same trigger.
9299 *
Jacob Keller12102432020-03-26 11:37:15 -07009300 * The caller of this function must use devlink_region_snapshot_id_put
9301 * when finished creating regions using this id.
9302 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07009303 * Returns zero on success, or a negative error code on failure.
9304 *
Alex Veskerccadfa42018-07-12 15:13:09 +03009305 * @devlink: devlink
Jacob Keller7ef19d32020-03-26 11:37:14 -07009306 * @id: storage to return id
Alex Veskerccadfa42018-07-12 15:13:09 +03009307 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07009308int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Alex Veskerccadfa42018-07-12 15:13:09 +03009309{
Jacob Keller7ef19d32020-03-26 11:37:14 -07009310 int err;
Alex Veskerccadfa42018-07-12 15:13:09 +03009311
9312 mutex_lock(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07009313 err = __devlink_region_snapshot_id_get(devlink, id);
Alex Veskerccadfa42018-07-12 15:13:09 +03009314 mutex_unlock(&devlink->lock);
9315
Jacob Keller7ef19d32020-03-26 11:37:14 -07009316 return err;
Alex Veskerccadfa42018-07-12 15:13:09 +03009317}
Jacob Kellerb0efcae2020-01-09 11:08:20 -08009318EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
Alex Veskerccadfa42018-07-12 15:13:09 +03009319
Alex Veskerd7e52722018-07-12 15:13:10 +03009320/**
Jacob Keller12102432020-03-26 11:37:15 -07009321 * devlink_region_snapshot_id_put - put snapshot ID reference
9322 *
9323 * This should be called by a driver after finishing creating snapshots
9324 * with an id. Doing so ensures that the ID can later be released in the
9325 * event that all snapshots using it have been destroyed.
9326 *
9327 * @devlink: devlink
9328 * @id: id to release reference on
9329 */
9330void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
9331{
9332 mutex_lock(&devlink->lock);
9333 __devlink_snapshot_id_decrement(devlink, id);
9334 mutex_unlock(&devlink->lock);
9335}
9336EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
9337
9338/**
Alex Veskerd7e52722018-07-12 15:13:10 +03009339 * devlink_region_snapshot_create - create a new snapshot
9340 * This will add a new snapshot of a region. The snapshot
9341 * will be stored on the region struct and can be accessed
Jacob Keller6d82f672020-03-26 11:37:10 -07009342 * from devlink. This is useful for future analyses of snapshots.
Alex Veskerd7e52722018-07-12 15:13:10 +03009343 * Multiple snapshots can be created on a region.
9344 * The @snapshot_id should be obtained using the getter function.
9345 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08009346 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03009347 * @data: snapshot data
9348 * @snapshot_id: snapshot id to be created
Alex Veskerd7e52722018-07-12 15:13:10 +03009349 */
Jiri Pirko3a5e5232019-08-09 15:27:15 +02009350int devlink_region_snapshot_create(struct devlink_region *region,
Jacob Kellera0a09f62020-03-26 11:37:09 -07009351 u8 *data, u32 snapshot_id)
Alex Veskerd7e52722018-07-12 15:13:10 +03009352{
9353 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03009354 int err;
9355
9356 mutex_lock(&devlink->lock);
Jacob Kellercf80fae2020-03-26 11:37:11 -07009357 err = __devlink_region_snapshot_create(region, data, snapshot_id);
Alex Veskerd7e52722018-07-12 15:13:10 +03009358 mutex_unlock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03009359
Alex Veskerd7e52722018-07-12 15:13:10 +03009360 return err;
9361}
9362EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
9363
Ido Schimmel0f420b62019-08-17 16:28:17 +03009364#define DEVLINK_TRAP(_id, _type) \
9365 { \
9366 .type = DEVLINK_TRAP_TYPE_##_type, \
9367 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
9368 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
9369 }
9370
9371static const struct devlink_trap devlink_trap_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03009372 DEVLINK_TRAP(SMAC_MC, DROP),
9373 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
9374 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
9375 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
9376 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
9377 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
9378 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
9379 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
9380 DEVLINK_TRAP(TAIL_DROP, DROP),
Amit Cohen6896cc42019-11-07 18:42:09 +02009381 DEVLINK_TRAP(NON_IP_PACKET, DROP),
9382 DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
9383 DEVLINK_TRAP(DIP_LB, DROP),
9384 DEVLINK_TRAP(SIP_MC, DROP),
9385 DEVLINK_TRAP(SIP_LB, DROP),
9386 DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
9387 DEVLINK_TRAP(IPV4_SIP_BC, DROP),
9388 DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
9389 DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
Amit Cohen3b063ae2019-11-07 18:42:14 +02009390 DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
9391 DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
9392 DEVLINK_TRAP(RPF, EXCEPTION),
9393 DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
9394 DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
9395 DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
Amit Cohen95f0ead2020-01-19 15:00:48 +02009396 DEVLINK_TRAP(NON_ROUTABLE, DROP),
Amit Cohen13c056e2020-01-19 15:00:54 +02009397 DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
Amit Cohenc3cae492020-01-19 15:00:58 +02009398 DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01009399 DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
9400 DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
Ido Schimmel515eac62020-05-29 21:36:41 +03009401 DEVLINK_TRAP(STP, CONTROL),
9402 DEVLINK_TRAP(LACP, CONTROL),
9403 DEVLINK_TRAP(LLDP, CONTROL),
9404 DEVLINK_TRAP(IGMP_QUERY, CONTROL),
9405 DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
9406 DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
9407 DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
9408 DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
9409 DEVLINK_TRAP(MLD_QUERY, CONTROL),
9410 DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
9411 DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
9412 DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03009413 DEVLINK_TRAP(IPV4_DHCP, CONTROL),
9414 DEVLINK_TRAP(IPV6_DHCP, CONTROL),
9415 DEVLINK_TRAP(ARP_REQUEST, CONTROL),
9416 DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
9417 DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
9418 DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
9419 DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
9420 DEVLINK_TRAP(IPV4_BFD, CONTROL),
9421 DEVLINK_TRAP(IPV6_BFD, CONTROL),
9422 DEVLINK_TRAP(IPV4_OSPF, CONTROL),
9423 DEVLINK_TRAP(IPV6_OSPF, CONTROL),
9424 DEVLINK_TRAP(IPV4_BGP, CONTROL),
9425 DEVLINK_TRAP(IPV6_BGP, CONTROL),
9426 DEVLINK_TRAP(IPV4_VRRP, CONTROL),
9427 DEVLINK_TRAP(IPV6_VRRP, CONTROL),
9428 DEVLINK_TRAP(IPV4_PIM, CONTROL),
9429 DEVLINK_TRAP(IPV6_PIM, CONTROL),
9430 DEVLINK_TRAP(UC_LB, CONTROL),
9431 DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
9432 DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
9433 DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
9434 DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
9435 DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
9436 DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
9437 DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
9438 DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
9439 DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
9440 DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
9441 DEVLINK_TRAP(PTP_EVENT, CONTROL),
9442 DEVLINK_TRAP(PTP_GENERAL, CONTROL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03009443 DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
9444 DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
Amit Cohen08e335f2020-08-03 19:11:33 +03009445 DEVLINK_TRAP(EARLY_DROP, DROP),
Ioana Ciornei10c24eb2020-10-01 18:11:45 +03009446 DEVLINK_TRAP(VXLAN_PARSING, DROP),
9447 DEVLINK_TRAP(LLC_SNAP_PARSING, DROP),
9448 DEVLINK_TRAP(VLAN_PARSING, DROP),
9449 DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP),
9450 DEVLINK_TRAP(MPLS_PARSING, DROP),
9451 DEVLINK_TRAP(ARP_PARSING, DROP),
9452 DEVLINK_TRAP(IP_1_PARSING, DROP),
9453 DEVLINK_TRAP(IP_N_PARSING, DROP),
9454 DEVLINK_TRAP(GRE_PARSING, DROP),
9455 DEVLINK_TRAP(UDP_PARSING, DROP),
9456 DEVLINK_TRAP(TCP_PARSING, DROP),
9457 DEVLINK_TRAP(IPSEC_PARSING, DROP),
9458 DEVLINK_TRAP(SCTP_PARSING, DROP),
9459 DEVLINK_TRAP(DCCP_PARSING, DROP),
9460 DEVLINK_TRAP(GTP_PARSING, DROP),
9461 DEVLINK_TRAP(ESP_PARSING, DROP),
Ido Schimmel0f420b62019-08-17 16:28:17 +03009462};
9463
9464#define DEVLINK_TRAP_GROUP(_id) \
9465 { \
9466 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
9467 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
9468 }
9469
9470static const struct devlink_trap_group devlink_trap_group_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03009471 DEVLINK_TRAP_GROUP(L2_DROPS),
9472 DEVLINK_TRAP_GROUP(L3_DROPS),
Ido Schimmel678eb192020-05-29 21:36:36 +03009473 DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
Ido Schimmel391203a2019-08-17 16:28:18 +03009474 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
Amit Cohen13c056e2020-01-19 15:00:54 +02009475 DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01009476 DEVLINK_TRAP_GROUP(ACL_DROPS),
Ido Schimmel515eac62020-05-29 21:36:41 +03009477 DEVLINK_TRAP_GROUP(STP),
9478 DEVLINK_TRAP_GROUP(LACP),
9479 DEVLINK_TRAP_GROUP(LLDP),
9480 DEVLINK_TRAP_GROUP(MC_SNOOPING),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03009481 DEVLINK_TRAP_GROUP(DHCP),
9482 DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
9483 DEVLINK_TRAP_GROUP(BFD),
9484 DEVLINK_TRAP_GROUP(OSPF),
9485 DEVLINK_TRAP_GROUP(BGP),
9486 DEVLINK_TRAP_GROUP(VRRP),
9487 DEVLINK_TRAP_GROUP(PIM),
9488 DEVLINK_TRAP_GROUP(UC_LB),
9489 DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
Ido Schimmelec4f5b32020-07-29 12:26:44 +03009490 DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03009491 DEVLINK_TRAP_GROUP(IPV6),
9492 DEVLINK_TRAP_GROUP(PTP_EVENT),
9493 DEVLINK_TRAP_GROUP(PTP_GENERAL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03009494 DEVLINK_TRAP_GROUP(ACL_SAMPLE),
9495 DEVLINK_TRAP_GROUP(ACL_TRAP),
Ioana Ciornei10c24eb2020-10-01 18:11:45 +03009496 DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS),
Ido Schimmel0f420b62019-08-17 16:28:17 +03009497};
9498
9499static int devlink_trap_generic_verify(const struct devlink_trap *trap)
9500{
9501 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
9502 return -EINVAL;
9503
9504 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
9505 return -EINVAL;
9506
9507 if (trap->type != devlink_trap_generic[trap->id].type)
9508 return -EINVAL;
9509
9510 return 0;
9511}
9512
9513static int devlink_trap_driver_verify(const struct devlink_trap *trap)
9514{
9515 int i;
9516
9517 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
9518 return -EINVAL;
9519
9520 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
9521 if (!strcmp(trap->name, devlink_trap_generic[i].name))
9522 return -EEXIST;
9523 }
9524
9525 return 0;
9526}
9527
9528static int devlink_trap_verify(const struct devlink_trap *trap)
9529{
Ido Schimmel107f1672020-03-22 20:48:30 +02009530 if (!trap || !trap->name)
Ido Schimmel0f420b62019-08-17 16:28:17 +03009531 return -EINVAL;
9532
9533 if (trap->generic)
9534 return devlink_trap_generic_verify(trap);
9535 else
9536 return devlink_trap_driver_verify(trap);
9537}
9538
9539static int
9540devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
9541{
9542 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
9543 return -EINVAL;
9544
9545 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
9546 return -EINVAL;
9547
9548 return 0;
9549}
9550
9551static int
9552devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
9553{
9554 int i;
9555
9556 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
9557 return -EINVAL;
9558
9559 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
9560 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
9561 return -EEXIST;
9562 }
9563
9564 return 0;
9565}
9566
9567static int devlink_trap_group_verify(const struct devlink_trap_group *group)
9568{
9569 if (group->generic)
9570 return devlink_trap_group_generic_verify(group);
9571 else
9572 return devlink_trap_group_driver_verify(group);
9573}
9574
9575static void
9576devlink_trap_group_notify(struct devlink *devlink,
9577 const struct devlink_trap_group_item *group_item,
9578 enum devlink_command cmd)
9579{
9580 struct sk_buff *msg;
9581 int err;
9582
9583 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
9584 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
9585
9586 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9587 if (!msg)
9588 return;
9589
9590 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
9591 0);
9592 if (err) {
9593 nlmsg_free(msg);
9594 return;
9595 }
9596
9597 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9598 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9599}
9600
Ido Schimmel0f420b62019-08-17 16:28:17 +03009601static int
9602devlink_trap_item_group_link(struct devlink *devlink,
9603 struct devlink_trap_item *trap_item)
9604{
Ido Schimmel107f1672020-03-22 20:48:30 +02009605 u16 group_id = trap_item->trap->init_group_id;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009606 struct devlink_trap_group_item *group_item;
9607
Ido Schimmel107f1672020-03-22 20:48:30 +02009608 group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
Ido Schimmela09b37f2020-03-22 20:48:29 +02009609 if (WARN_ON_ONCE(!group_item))
9610 return -EINVAL;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009611
9612 trap_item->group_item = group_item;
9613
9614 return 0;
9615}
9616
Ido Schimmel0f420b62019-08-17 16:28:17 +03009617static void devlink_trap_notify(struct devlink *devlink,
9618 const struct devlink_trap_item *trap_item,
9619 enum devlink_command cmd)
9620{
9621 struct sk_buff *msg;
9622 int err;
9623
9624 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
9625 cmd != DEVLINK_CMD_TRAP_DEL);
9626
9627 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9628 if (!msg)
9629 return;
9630
9631 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
9632 if (err) {
9633 nlmsg_free(msg);
9634 return;
9635 }
9636
9637 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9638 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9639}
9640
9641static int
9642devlink_trap_register(struct devlink *devlink,
9643 const struct devlink_trap *trap, void *priv)
9644{
9645 struct devlink_trap_item *trap_item;
9646 int err;
9647
9648 if (devlink_trap_item_lookup(devlink, trap->name))
9649 return -EEXIST;
9650
9651 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
9652 if (!trap_item)
9653 return -ENOMEM;
9654
9655 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9656 if (!trap_item->stats) {
9657 err = -ENOMEM;
9658 goto err_stats_alloc;
9659 }
9660
9661 trap_item->trap = trap;
9662 trap_item->action = trap->init_action;
9663 trap_item->priv = priv;
9664
9665 err = devlink_trap_item_group_link(devlink, trap_item);
9666 if (err)
9667 goto err_group_link;
9668
9669 err = devlink->ops->trap_init(devlink, trap, trap_item);
9670 if (err)
9671 goto err_trap_init;
9672
9673 list_add_tail(&trap_item->list, &devlink->trap_list);
9674 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
9675
9676 return 0;
9677
9678err_trap_init:
Ido Schimmel0f420b62019-08-17 16:28:17 +03009679err_group_link:
9680 free_percpu(trap_item->stats);
9681err_stats_alloc:
9682 kfree(trap_item);
9683 return err;
9684}
9685
9686static void devlink_trap_unregister(struct devlink *devlink,
9687 const struct devlink_trap *trap)
9688{
9689 struct devlink_trap_item *trap_item;
9690
9691 trap_item = devlink_trap_item_lookup(devlink, trap->name);
9692 if (WARN_ON_ONCE(!trap_item))
9693 return;
9694
9695 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
9696 list_del(&trap_item->list);
9697 if (devlink->ops->trap_fini)
9698 devlink->ops->trap_fini(devlink, trap, trap_item);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009699 free_percpu(trap_item->stats);
9700 kfree(trap_item);
9701}
9702
9703static void devlink_trap_disable(struct devlink *devlink,
9704 const struct devlink_trap *trap)
9705{
9706 struct devlink_trap_item *trap_item;
9707
9708 trap_item = devlink_trap_item_lookup(devlink, trap->name);
9709 if (WARN_ON_ONCE(!trap_item))
9710 return;
9711
Ido Schimmelc88e11e2020-08-03 19:11:34 +03009712 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
9713 NULL);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009714 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
9715}
9716
9717/**
9718 * devlink_traps_register - Register packet traps with devlink.
9719 * @devlink: devlink.
9720 * @traps: Packet traps.
9721 * @traps_count: Count of provided packet traps.
9722 * @priv: Driver private information.
9723 *
9724 * Return: Non-zero value on failure.
9725 */
9726int devlink_traps_register(struct devlink *devlink,
9727 const struct devlink_trap *traps,
9728 size_t traps_count, void *priv)
9729{
9730 int i, err;
9731
9732 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
9733 return -EINVAL;
9734
9735 mutex_lock(&devlink->lock);
9736 for (i = 0; i < traps_count; i++) {
9737 const struct devlink_trap *trap = &traps[i];
9738
9739 err = devlink_trap_verify(trap);
9740 if (err)
9741 goto err_trap_verify;
9742
9743 err = devlink_trap_register(devlink, trap, priv);
9744 if (err)
9745 goto err_trap_register;
9746 }
9747 mutex_unlock(&devlink->lock);
9748
9749 return 0;
9750
9751err_trap_register:
9752err_trap_verify:
9753 for (i--; i >= 0; i--)
9754 devlink_trap_unregister(devlink, &traps[i]);
9755 mutex_unlock(&devlink->lock);
9756 return err;
9757}
9758EXPORT_SYMBOL_GPL(devlink_traps_register);
9759
9760/**
9761 * devlink_traps_unregister - Unregister packet traps from devlink.
9762 * @devlink: devlink.
9763 * @traps: Packet traps.
9764 * @traps_count: Count of provided packet traps.
9765 */
9766void devlink_traps_unregister(struct devlink *devlink,
9767 const struct devlink_trap *traps,
9768 size_t traps_count)
9769{
9770 int i;
9771
9772 mutex_lock(&devlink->lock);
9773 /* Make sure we do not have any packets in-flight while unregistering
9774 * traps by disabling all of them and waiting for a grace period.
9775 */
9776 for (i = traps_count - 1; i >= 0; i--)
9777 devlink_trap_disable(devlink, &traps[i]);
9778 synchronize_rcu();
9779 for (i = traps_count - 1; i >= 0; i--)
9780 devlink_trap_unregister(devlink, &traps[i]);
9781 mutex_unlock(&devlink->lock);
9782}
9783EXPORT_SYMBOL_GPL(devlink_traps_unregister);
9784
9785static void
9786devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
9787 size_t skb_len)
9788{
9789 struct devlink_stats *stats;
9790
9791 stats = this_cpu_ptr(trap_stats);
9792 u64_stats_update_begin(&stats->syncp);
9793 stats->rx_bytes += skb_len;
9794 stats->rx_packets++;
9795 u64_stats_update_end(&stats->syncp);
9796}
9797
9798static void
Ido Schimmel5b888232020-09-29 11:15:50 +03009799devlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata,
9800 const struct devlink_trap_item *trap_item,
9801 struct devlink_port *in_devlink_port,
9802 const struct flow_action_cookie *fa_cookie)
9803{
9804 metadata->trap_name = trap_item->trap->name;
9805 metadata->trap_group_name = trap_item->group_item->group->name;
9806 metadata->fa_cookie = fa_cookie;
Ido Schimmel93e15592020-09-29 11:15:55 +03009807 metadata->trap_type = trap_item->trap->type;
Ido Schimmel5b888232020-09-29 11:15:50 +03009808
9809 spin_lock(&in_devlink_port->type_lock);
9810 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
9811 metadata->input_dev = in_devlink_port->type_dev;
9812 spin_unlock(&in_devlink_port->type_lock);
9813}
9814
Ido Schimmel0f420b62019-08-17 16:28:17 +03009815/**
9816 * devlink_trap_report - Report trapped packet to drop monitor.
9817 * @devlink: devlink.
9818 * @skb: Trapped packet.
9819 * @trap_ctx: Trap context.
9820 * @in_devlink_port: Input devlink port.
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009821 * @fa_cookie: Flow action cookie. Could be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03009822 */
9823void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009824 void *trap_ctx, struct devlink_port *in_devlink_port,
9825 const struct flow_action_cookie *fa_cookie)
9826
Ido Schimmel0f420b62019-08-17 16:28:17 +03009827{
9828 struct devlink_trap_item *trap_item = trap_ctx;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009829
9830 devlink_trap_stats_update(trap_item->stats, skb->len);
9831 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
9832
Ido Schimmel5b888232020-09-29 11:15:50 +03009833 if (trace_devlink_trap_report_enabled()) {
9834 struct devlink_trap_metadata metadata = {};
9835
9836 devlink_trap_report_metadata_set(&metadata, trap_item,
9837 in_devlink_port, fa_cookie);
9838 trace_devlink_trap_report(devlink, skb, &metadata);
9839 }
Ido Schimmel0f420b62019-08-17 16:28:17 +03009840}
9841EXPORT_SYMBOL_GPL(devlink_trap_report);
9842
9843/**
9844 * devlink_trap_ctx_priv - Trap context to driver private information.
9845 * @trap_ctx: Trap context.
9846 *
9847 * Return: Driver private information passed during registration.
9848 */
9849void *devlink_trap_ctx_priv(void *trap_ctx)
9850{
9851 struct devlink_trap_item *trap_item = trap_ctx;
9852
9853 return trap_item->priv;
9854}
9855EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
9856
Ido Schimmel95ad9552020-03-22 20:48:26 +02009857static int
Ido Schimmelf9f54392020-03-30 22:38:21 +03009858devlink_trap_group_item_policer_link(struct devlink *devlink,
9859 struct devlink_trap_group_item *group_item)
9860{
9861 u32 policer_id = group_item->group->init_policer_id;
9862 struct devlink_trap_policer_item *policer_item;
9863
9864 if (policer_id == 0)
9865 return 0;
9866
9867 policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
9868 if (WARN_ON_ONCE(!policer_item))
9869 return -EINVAL;
9870
9871 group_item->policer_item = policer_item;
9872
9873 return 0;
9874}
9875
9876static int
Ido Schimmel95ad9552020-03-22 20:48:26 +02009877devlink_trap_group_register(struct devlink *devlink,
9878 const struct devlink_trap_group *group)
9879{
9880 struct devlink_trap_group_item *group_item;
9881 int err;
9882
9883 if (devlink_trap_group_item_lookup(devlink, group->name))
9884 return -EEXIST;
9885
9886 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
9887 if (!group_item)
9888 return -ENOMEM;
9889
9890 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9891 if (!group_item->stats) {
9892 err = -ENOMEM;
9893 goto err_stats_alloc;
9894 }
9895
9896 group_item->group = group;
Ido Schimmel95ad9552020-03-22 20:48:26 +02009897
Ido Schimmelf9f54392020-03-30 22:38:21 +03009898 err = devlink_trap_group_item_policer_link(devlink, group_item);
9899 if (err)
9900 goto err_policer_link;
9901
Ido Schimmel95ad9552020-03-22 20:48:26 +02009902 if (devlink->ops->trap_group_init) {
9903 err = devlink->ops->trap_group_init(devlink, group);
9904 if (err)
9905 goto err_group_init;
9906 }
9907
9908 list_add_tail(&group_item->list, &devlink->trap_group_list);
9909 devlink_trap_group_notify(devlink, group_item,
9910 DEVLINK_CMD_TRAP_GROUP_NEW);
9911
9912 return 0;
9913
9914err_group_init:
Ido Schimmelf9f54392020-03-30 22:38:21 +03009915err_policer_link:
Ido Schimmel95ad9552020-03-22 20:48:26 +02009916 free_percpu(group_item->stats);
9917err_stats_alloc:
9918 kfree(group_item);
9919 return err;
9920}
9921
9922static void
9923devlink_trap_group_unregister(struct devlink *devlink,
9924 const struct devlink_trap_group *group)
9925{
9926 struct devlink_trap_group_item *group_item;
9927
9928 group_item = devlink_trap_group_item_lookup(devlink, group->name);
9929 if (WARN_ON_ONCE(!group_item))
9930 return;
9931
9932 devlink_trap_group_notify(devlink, group_item,
9933 DEVLINK_CMD_TRAP_GROUP_DEL);
9934 list_del(&group_item->list);
9935 free_percpu(group_item->stats);
9936 kfree(group_item);
9937}
9938
9939/**
9940 * devlink_trap_groups_register - Register packet trap groups with devlink.
9941 * @devlink: devlink.
9942 * @groups: Packet trap groups.
9943 * @groups_count: Count of provided packet trap groups.
9944 *
9945 * Return: Non-zero value on failure.
9946 */
9947int devlink_trap_groups_register(struct devlink *devlink,
9948 const struct devlink_trap_group *groups,
9949 size_t groups_count)
9950{
9951 int i, err;
9952
9953 mutex_lock(&devlink->lock);
9954 for (i = 0; i < groups_count; i++) {
9955 const struct devlink_trap_group *group = &groups[i];
9956
9957 err = devlink_trap_group_verify(group);
9958 if (err)
9959 goto err_trap_group_verify;
9960
9961 err = devlink_trap_group_register(devlink, group);
9962 if (err)
9963 goto err_trap_group_register;
9964 }
9965 mutex_unlock(&devlink->lock);
9966
9967 return 0;
9968
9969err_trap_group_register:
9970err_trap_group_verify:
9971 for (i--; i >= 0; i--)
9972 devlink_trap_group_unregister(devlink, &groups[i]);
9973 mutex_unlock(&devlink->lock);
9974 return err;
9975}
9976EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
9977
9978/**
9979 * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
9980 * @devlink: devlink.
9981 * @groups: Packet trap groups.
9982 * @groups_count: Count of provided packet trap groups.
9983 */
9984void devlink_trap_groups_unregister(struct devlink *devlink,
9985 const struct devlink_trap_group *groups,
9986 size_t groups_count)
9987{
9988 int i;
9989
9990 mutex_lock(&devlink->lock);
9991 for (i = groups_count - 1; i >= 0; i--)
9992 devlink_trap_group_unregister(devlink, &groups[i]);
9993 mutex_unlock(&devlink->lock);
9994}
9995EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
9996
Ido Schimmel1e8c6612020-03-30 22:38:18 +03009997static void
9998devlink_trap_policer_notify(struct devlink *devlink,
9999 const struct devlink_trap_policer_item *policer_item,
10000 enum devlink_command cmd)
10001{
10002 struct sk_buff *msg;
10003 int err;
10004
10005 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
10006 cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
10007
10008 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10009 if (!msg)
10010 return;
10011
10012 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
10013 0, 0);
10014 if (err) {
10015 nlmsg_free(msg);
10016 return;
10017 }
10018
10019 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
10020 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
10021}
10022
10023static int
10024devlink_trap_policer_register(struct devlink *devlink,
10025 const struct devlink_trap_policer *policer)
10026{
10027 struct devlink_trap_policer_item *policer_item;
10028 int err;
10029
10030 if (devlink_trap_policer_item_lookup(devlink, policer->id))
10031 return -EEXIST;
10032
10033 policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
10034 if (!policer_item)
10035 return -ENOMEM;
10036
10037 policer_item->policer = policer;
10038 policer_item->rate = policer->init_rate;
10039 policer_item->burst = policer->init_burst;
10040
10041 if (devlink->ops->trap_policer_init) {
10042 err = devlink->ops->trap_policer_init(devlink, policer);
10043 if (err)
10044 goto err_policer_init;
10045 }
10046
10047 list_add_tail(&policer_item->list, &devlink->trap_policer_list);
10048 devlink_trap_policer_notify(devlink, policer_item,
10049 DEVLINK_CMD_TRAP_POLICER_NEW);
10050
10051 return 0;
10052
10053err_policer_init:
10054 kfree(policer_item);
10055 return err;
10056}
10057
10058static void
10059devlink_trap_policer_unregister(struct devlink *devlink,
10060 const struct devlink_trap_policer *policer)
10061{
10062 struct devlink_trap_policer_item *policer_item;
10063
10064 policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
10065 if (WARN_ON_ONCE(!policer_item))
10066 return;
10067
10068 devlink_trap_policer_notify(devlink, policer_item,
10069 DEVLINK_CMD_TRAP_POLICER_DEL);
10070 list_del(&policer_item->list);
10071 if (devlink->ops->trap_policer_fini)
10072 devlink->ops->trap_policer_fini(devlink, policer);
10073 kfree(policer_item);
10074}
10075
10076/**
10077 * devlink_trap_policers_register - Register packet trap policers with devlink.
10078 * @devlink: devlink.
10079 * @policers: Packet trap policers.
10080 * @policers_count: Count of provided packet trap policers.
10081 *
10082 * Return: Non-zero value on failure.
10083 */
10084int
10085devlink_trap_policers_register(struct devlink *devlink,
10086 const struct devlink_trap_policer *policers,
10087 size_t policers_count)
10088{
10089 int i, err;
10090
10091 mutex_lock(&devlink->lock);
10092 for (i = 0; i < policers_count; i++) {
10093 const struct devlink_trap_policer *policer = &policers[i];
10094
10095 if (WARN_ON(policer->id == 0 ||
10096 policer->max_rate < policer->min_rate ||
10097 policer->max_burst < policer->min_burst)) {
10098 err = -EINVAL;
10099 goto err_trap_policer_verify;
10100 }
10101
10102 err = devlink_trap_policer_register(devlink, policer);
10103 if (err)
10104 goto err_trap_policer_register;
10105 }
10106 mutex_unlock(&devlink->lock);
10107
10108 return 0;
10109
10110err_trap_policer_register:
10111err_trap_policer_verify:
10112 for (i--; i >= 0; i--)
10113 devlink_trap_policer_unregister(devlink, &policers[i]);
10114 mutex_unlock(&devlink->lock);
10115 return err;
10116}
10117EXPORT_SYMBOL_GPL(devlink_trap_policers_register);
10118
10119/**
10120 * devlink_trap_policers_unregister - Unregister packet trap policers from devlink.
10121 * @devlink: devlink.
10122 * @policers: Packet trap policers.
10123 * @policers_count: Count of provided packet trap policers.
10124 */
10125void
10126devlink_trap_policers_unregister(struct devlink *devlink,
10127 const struct devlink_trap_policer *policers,
10128 size_t policers_count)
10129{
10130 int i;
10131
10132 mutex_lock(&devlink->lock);
10133 for (i = policers_count - 1; i >= 0; i--)
10134 devlink_trap_policer_unregister(devlink, &policers[i]);
10135 mutex_unlock(&devlink->lock);
10136}
10137EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister);
10138
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080010139static void __devlink_compat_running_version(struct devlink *devlink,
10140 char *buf, size_t len)
10141{
10142 const struct nlattr *nlattr;
10143 struct devlink_info_req req;
10144 struct sk_buff *msg;
10145 int rem, err;
10146
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080010147 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
10148 if (!msg)
10149 return;
10150
10151 req.msg = msg;
10152 err = devlink->ops->info_get(devlink, &req, NULL);
10153 if (err)
10154 goto free_msg;
10155
10156 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
10157 const struct nlattr *kv;
10158 int rem_kv;
10159
10160 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
10161 continue;
10162
10163 nla_for_each_nested(kv, nlattr, rem_kv) {
10164 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
10165 continue;
10166
10167 strlcat(buf, nla_data(kv), len);
10168 strlcat(buf, " ", len);
10169 }
10170 }
10171free_msg:
10172 nlmsg_free(msg);
10173}
10174
10175void devlink_compat_running_version(struct net_device *dev,
10176 char *buf, size_t len)
10177{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080010178 struct devlink *devlink;
10179
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010180 dev_hold(dev);
10181 rtnl_unlock();
10182
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010183 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -080010184 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010185 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010186
10187 mutex_lock(&devlink->lock);
10188 __devlink_compat_running_version(devlink, buf, len);
10189 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010190
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010191out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010192 rtnl_lock();
10193 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080010194}
10195
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010196int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
10197{
Jacob Kellerbc75c052020-09-25 13:46:06 -070010198 struct devlink_flash_update_params params = {};
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010199 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010200 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010201
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010202 dev_hold(dev);
10203 rtnl_unlock();
10204
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010205 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010206 if (!devlink || !devlink->ops->flash_update) {
10207 ret = -EOPNOTSUPP;
10208 goto out;
10209 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010210
Jacob Kellerbc75c052020-09-25 13:46:06 -070010211 params.file_name = file_name;
10212
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010213 mutex_lock(&devlink->lock);
Jacob Kellerbc75c052020-09-25 13:46:06 -070010214 ret = devlink->ops->flash_update(devlink, &params, NULL);
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010215 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010216
Jiri Pirkoe0dcd382019-03-24 11:14:29 +010010217out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -080010218 rtnl_lock();
10219 dev_put(dev);
10220
Jakub Kicinskib473b0d2019-02-25 19:34:03 -080010221 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -080010222}
10223
Jiri Pirkoaf3836d2019-03-28 13:56:37 +010010224int devlink_compat_phys_port_name_get(struct net_device *dev,
10225 char *name, size_t len)
10226{
10227 struct devlink_port *devlink_port;
10228
10229 /* RTNL mutex is held here which ensures that devlink_port
10230 * instance cannot disappear in the middle. No need to take
10231 * any devlink lock as only permanent values are accessed.
10232 */
10233 ASSERT_RTNL();
10234
10235 devlink_port = netdev_to_devlink_port(dev);
10236 if (!devlink_port)
10237 return -EOPNOTSUPP;
10238
10239 return __devlink_port_phys_port_name_get(devlink_port, name, len);
10240}
10241
Jiri Pirko7e1146e2019-04-03 14:24:17 +020010242int devlink_compat_switch_id_get(struct net_device *dev,
10243 struct netdev_phys_item_id *ppid)
10244{
10245 struct devlink_port *devlink_port;
10246
Vlad Buslov043b8412019-08-12 20:02:02 +030010247 /* Caller must hold RTNL mutex or reference to dev, which ensures that
10248 * devlink_port instance cannot disappear in the middle. No need to take
Jiri Pirko7e1146e2019-04-03 14:24:17 +020010249 * any devlink lock as only permanent values are accessed.
10250 */
Jiri Pirko7e1146e2019-04-03 14:24:17 +020010251 devlink_port = netdev_to_devlink_port(dev);
Danielle Ratson46737a12020-07-09 16:18:15 +030010252 if (!devlink_port || !devlink_port->switch_port)
Jiri Pirko7e1146e2019-04-03 14:24:17 +020010253 return -EOPNOTSUPP;
10254
10255 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
10256
10257 return 0;
10258}
10259
Jiri Pirko070c63f2019-10-03 11:49:39 +020010260static void __net_exit devlink_pernet_pre_exit(struct net *net)
10261{
10262 struct devlink *devlink;
Moshe Shemeshccdf0722020-10-07 09:00:43 +030010263 u32 actions_performed;
Jiri Pirko070c63f2019-10-03 11:49:39 +020010264 int err;
10265
10266 /* In case network namespace is getting destroyed, reload
10267 * all devlink instances from this namespace into init_net.
10268 */
10269 mutex_lock(&devlink_mutex);
10270 list_for_each_entry(devlink, &devlink_list, list) {
10271 if (net_eq(devlink_net(devlink), net)) {
Moshe Shemesh69d56e02020-10-07 09:00:42 +030010272 if (WARN_ON(!devlink_reload_supported(devlink->ops)))
Jiri Pirko070c63f2019-10-03 11:49:39 +020010273 continue;
Moshe Shemeshccdf0722020-10-07 09:00:43 +030010274 err = devlink_reload(devlink, &init_net,
10275 DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
Moshe Shemeshdc64cc72020-10-07 09:00:44 +030010276 DEVLINK_RELOAD_LIMIT_UNSPEC,
Moshe Shemeshccdf0722020-10-07 09:00:43 +030010277 &actions_performed, NULL);
Jiri Pirkoa0c76342019-11-08 21:42:43 +010010278 if (err && err != -EOPNOTSUPP)
Jiri Pirko070c63f2019-10-03 11:49:39 +020010279 pr_warn("Failed to reload devlink instance into init_net\n");
10280 }
10281 }
10282 mutex_unlock(&devlink_mutex);
10283}
10284
10285static struct pernet_operations devlink_pernet_ops __net_initdata = {
10286 .pre_exit = devlink_pernet_pre_exit,
10287};
10288
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -080010289static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010010290{
Jiri Pirko070c63f2019-10-03 11:49:39 +020010291 int err;
10292
10293 err = genl_register_family(&devlink_nl_family);
10294 if (err)
10295 goto out;
10296 err = register_pernet_subsys(&devlink_pernet_ops);
10297
10298out:
10299 WARN_ON(err);
10300 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010010301}
10302
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -080010303subsys_initcall(devlink_init);