blob: a203d35fb56f3edcf27d41fa239874f2356f0c3b [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01002/*
3 * net/core/devlink.c - Network physical/parent device Netlink interface
4 *
5 * Heavily inspired by net/wireless/
6 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
7 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008 */
9
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/slab.h>
14#include <linux/gfp.h>
15#include <linux/device.h>
16#include <linux/list.h>
17#include <linux/netdevice.h>
Jiri Pirkob8f97552019-03-24 11:14:37 +010018#include <linux/spinlock.h>
Moshe Shemeshb587bda2019-04-29 12:41:45 +030019#include <linux/refcount.h>
Jiri Pirko136bf272019-05-23 10:43:35 +020020#include <linux/workqueue.h>
Ido Schimmel0f420b62019-08-17 16:28:17 +030021#include <linux/u64_stats_sync.h>
22#include <linux/timekeeping.h>
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010023#include <rdma/ib_verbs.h>
24#include <net/netlink.h>
25#include <net/genetlink.h>
26#include <net/rtnetlink.h>
27#include <net/net_namespace.h>
28#include <net/sock.h>
29#include <net/devlink.h>
Ido Schimmel0f420b62019-08-17 16:28:17 +030030#include <net/drop_monitor.h>
Jiri Pirkoe5224f02016-07-12 18:05:03 +020031#define CREATE_TRACE_POINTS
32#include <trace/events/devlink.h>
33
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020034static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
35 {
David Ahern12bdc5e2017-08-30 17:07:30 -070036 .name = "destination mac",
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020037 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
38 .bitwidth = 48,
39 },
40};
41
42struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
43 .name = "ethernet",
44 .id = DEVLINK_DPIPE_HEADER_ETHERNET,
45 .fields = devlink_dpipe_fields_ethernet,
46 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
47 .global = true,
48};
49EXPORT_SYMBOL(devlink_dpipe_header_ethernet);
50
Arkadi Sharshevsky3fb886e2017-08-24 08:40:00 +020051static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
52 {
53 .name = "destination ip",
54 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
55 .bitwidth = 32,
56 },
57};
58
59struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
60 .name = "ipv4",
61 .id = DEVLINK_DPIPE_HEADER_IPV4,
62 .fields = devlink_dpipe_fields_ipv4,
63 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
64 .global = true,
65};
66EXPORT_SYMBOL(devlink_dpipe_header_ipv4);
67
Arkadi Sharshevsky1797f5b2017-08-31 17:59:12 +020068static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
69 {
70 .name = "destination ip",
71 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
72 .bitwidth = 128,
73 },
74};
75
76struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
77 .name = "ipv6",
78 .id = DEVLINK_DPIPE_HEADER_IPV6,
79 .fields = devlink_dpipe_fields_ipv6,
80 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
81 .global = true,
82};
83EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
84
Jiri Pirkoe5224f02016-07-12 18:05:03 +020085EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
Nir Dotan57186a52019-02-04 18:47:45 +000086EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010087
Parav Pandita1e8ae92020-06-19 03:32:49 +000088static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
89 [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY },
90};
91
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010092static LIST_HEAD(devlink_list);
93
94/* devlink_mutex
95 *
96 * An overall lock guarding every operation coming from userspace.
97 * It also guards devlink devices list and it is taken when
98 * driver registers/unregisters it.
99 */
100static DEFINE_MUTEX(devlink_mutex);
101
Jiri Pirko471f8942019-10-03 11:49:31 +0200102struct net *devlink_net(const struct devlink *devlink)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100103{
104 return read_pnet(&devlink->_net);
105}
Jiri Pirko471f8942019-10-03 11:49:31 +0200106EXPORT_SYMBOL_GPL(devlink_net);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100107
Jiri Pirko8273fd82019-10-05 08:10:31 +0200108static void __devlink_net_set(struct devlink *devlink, struct net *net)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100109{
110 write_pnet(&devlink->_net, net);
111}
112
Jiri Pirko8273fd82019-10-05 08:10:31 +0200113void devlink_net_set(struct devlink *devlink, struct net *net)
114{
115 if (WARN_ON(devlink->registered))
116 return;
117 __devlink_net_set(devlink, net);
118}
119EXPORT_SYMBOL_GPL(devlink_net_set);
120
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100121static struct devlink *devlink_get_from_attrs(struct net *net,
122 struct nlattr **attrs)
123{
124 struct devlink *devlink;
125 char *busname;
126 char *devname;
127
128 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
129 return ERR_PTR(-EINVAL);
130
131 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
132 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
133
Parav Panditdac7c082019-02-12 14:24:08 -0600134 lockdep_assert_held(&devlink_mutex);
135
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100136 list_for_each_entry(devlink, &devlink_list, list) {
137 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
138 strcmp(dev_name(devlink->dev), devname) == 0 &&
139 net_eq(devlink_net(devlink), net))
140 return devlink;
141 }
142
143 return ERR_PTR(-ENODEV);
144}
145
146static struct devlink *devlink_get_from_info(struct genl_info *info)
147{
148 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
149}
150
151static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
Parav Panditc7282b52019-08-30 05:39:44 -0500152 unsigned int port_index)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100153{
154 struct devlink_port *devlink_port;
155
156 list_for_each_entry(devlink_port, &devlink->port_list, list) {
157 if (devlink_port->index == port_index)
158 return devlink_port;
159 }
160 return NULL;
161}
162
Parav Panditc7282b52019-08-30 05:39:44 -0500163static bool devlink_port_index_exists(struct devlink *devlink,
164 unsigned int port_index)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100165{
166 return devlink_port_get_by_index(devlink, port_index);
167}
168
169static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
170 struct nlattr **attrs)
171{
172 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
173 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
174 struct devlink_port *devlink_port;
175
176 devlink_port = devlink_port_get_by_index(devlink, port_index);
177 if (!devlink_port)
178 return ERR_PTR(-ENODEV);
179 return devlink_port;
180 }
181 return ERR_PTR(-EINVAL);
182}
183
184static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
185 struct genl_info *info)
186{
187 return devlink_port_get_from_attrs(devlink, info->attrs);
188}
189
Jiri Pirkobf797472016-04-14 18:19:13 +0200190struct devlink_sb {
191 struct list_head list;
192 unsigned int index;
193 u32 size;
194 u16 ingress_pools_count;
195 u16 egress_pools_count;
196 u16 ingress_tc_count;
197 u16 egress_tc_count;
198};
199
200static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
201{
202 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
203}
204
205static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
206 unsigned int sb_index)
207{
208 struct devlink_sb *devlink_sb;
209
210 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
211 if (devlink_sb->index == sb_index)
212 return devlink_sb;
213 }
214 return NULL;
215}
216
217static bool devlink_sb_index_exists(struct devlink *devlink,
218 unsigned int sb_index)
219{
220 return devlink_sb_get_by_index(devlink, sb_index);
221}
222
223static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
224 struct nlattr **attrs)
225{
226 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
227 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
228 struct devlink_sb *devlink_sb;
229
230 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
231 if (!devlink_sb)
232 return ERR_PTR(-ENODEV);
233 return devlink_sb;
234 }
235 return ERR_PTR(-EINVAL);
236}
237
238static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
239 struct genl_info *info)
240{
241 return devlink_sb_get_from_attrs(devlink, info->attrs);
242}
243
244static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
245 struct nlattr **attrs,
246 u16 *p_pool_index)
247{
248 u16 val;
249
250 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
251 return -EINVAL;
252
253 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
254 if (val >= devlink_sb_pool_count(devlink_sb))
255 return -EINVAL;
256 *p_pool_index = val;
257 return 0;
258}
259
260static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
261 struct genl_info *info,
262 u16 *p_pool_index)
263{
264 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
265 p_pool_index);
266}
267
268static int
269devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
270 enum devlink_sb_pool_type *p_pool_type)
271{
272 u8 val;
273
274 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
275 return -EINVAL;
276
277 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
278 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
279 val != DEVLINK_SB_POOL_TYPE_EGRESS)
280 return -EINVAL;
281 *p_pool_type = val;
282 return 0;
283}
284
285static int
286devlink_sb_pool_type_get_from_info(struct genl_info *info,
287 enum devlink_sb_pool_type *p_pool_type)
288{
289 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
290}
291
292static int
293devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
294 enum devlink_sb_threshold_type *p_th_type)
295{
296 u8 val;
297
298 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
299 return -EINVAL;
300
301 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
302 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
303 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
304 return -EINVAL;
305 *p_th_type = val;
306 return 0;
307}
308
309static int
310devlink_sb_th_type_get_from_info(struct genl_info *info,
311 enum devlink_sb_threshold_type *p_th_type)
312{
313 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
314}
315
316static int
317devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
318 struct nlattr **attrs,
319 enum devlink_sb_pool_type pool_type,
320 u16 *p_tc_index)
321{
322 u16 val;
323
324 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
325 return -EINVAL;
326
327 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
328 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
329 val >= devlink_sb->ingress_tc_count)
330 return -EINVAL;
331 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
332 val >= devlink_sb->egress_tc_count)
333 return -EINVAL;
334 *p_tc_index = val;
335 return 0;
336}
337
338static int
339devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
340 struct genl_info *info,
341 enum devlink_sb_pool_type pool_type,
342 u16 *p_tc_index)
343{
344 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
345 pool_type, p_tc_index);
346}
347
Alex Veskerb16ebe92018-07-12 15:13:08 +0300348struct devlink_region {
349 struct devlink *devlink;
350 struct list_head list;
Jacob Kellere8937682020-03-26 11:37:08 -0700351 const struct devlink_region_ops *ops;
Alex Veskerb16ebe92018-07-12 15:13:08 +0300352 struct list_head snapshot_list;
353 u32 max_snapshots;
354 u32 cur_snapshots;
355 u64 size;
356};
357
Alex Veskerd7e52722018-07-12 15:13:10 +0300358struct devlink_snapshot {
359 struct list_head list;
360 struct devlink_region *region;
Alex Veskerd7e52722018-07-12 15:13:10 +0300361 u8 *data;
362 u32 id;
363};
364
Alex Veskerb16ebe92018-07-12 15:13:08 +0300365static struct devlink_region *
366devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
367{
368 struct devlink_region *region;
369
370 list_for_each_entry(region, &devlink->region_list, list)
Jacob Kellere8937682020-03-26 11:37:08 -0700371 if (!strcmp(region->ops->name, region_name))
Alex Veskerb16ebe92018-07-12 15:13:08 +0300372 return region;
373
374 return NULL;
375}
376
Alex Veskerd7e52722018-07-12 15:13:10 +0300377static struct devlink_snapshot *
378devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
379{
380 struct devlink_snapshot *snapshot;
381
382 list_for_each_entry(snapshot, &region->snapshot_list, list)
383 if (snapshot->id == id)
384 return snapshot;
385
386 return NULL;
387}
388
Jiri Pirko1fc22572016-04-08 19:12:48 +0200389#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
390#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
Jiri Pirkobf797472016-04-14 18:19:13 +0200391#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100392
393/* The per devlink instance lock is taken by default in the pre-doit
394 * operation, yet several commands do not require this. The global
395 * devlink lock is taken and protects from disruption by user-calls.
396 */
397#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100398
399static int devlink_nl_pre_doit(const struct genl_ops *ops,
400 struct sk_buff *skb, struct genl_info *info)
401{
402 struct devlink *devlink;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100403 int err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100404
405 mutex_lock(&devlink_mutex);
406 devlink = devlink_get_from_info(info);
407 if (IS_ERR(devlink)) {
408 mutex_unlock(&devlink_mutex);
409 return PTR_ERR(devlink);
410 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100411 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
412 mutex_lock(&devlink->lock);
Jiri Pirko1fc22572016-04-08 19:12:48 +0200413 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
414 info->user_ptr[0] = devlink;
415 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100416 struct devlink_port *devlink_port;
417
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100418 devlink_port = devlink_port_get_from_info(devlink, info);
419 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100420 err = PTR_ERR(devlink_port);
421 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100422 }
Jiri Pirko1fc22572016-04-08 19:12:48 +0200423 info->user_ptr[0] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100424 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200425 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
426 struct devlink_sb *devlink_sb;
427
428 devlink_sb = devlink_sb_get_from_info(devlink, info);
429 if (IS_ERR(devlink_sb)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100430 err = PTR_ERR(devlink_sb);
431 goto unlock;
Jiri Pirkobf797472016-04-14 18:19:13 +0200432 }
433 info->user_ptr[1] = devlink_sb;
434 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100435 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100436
437unlock:
438 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
439 mutex_unlock(&devlink->lock);
440 mutex_unlock(&devlink_mutex);
441 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100442}
443
444static void devlink_nl_post_doit(const struct genl_ops *ops,
445 struct sk_buff *skb, struct genl_info *info)
446{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100447 struct devlink *devlink;
448
Jiri Pirko070c63f2019-10-03 11:49:39 +0200449 /* When devlink changes netns, it would not be found
450 * by devlink_get_from_info(). So try if it is stored first.
451 */
452 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
453 devlink = info->user_ptr[0];
454 } else {
455 devlink = devlink_get_from_info(info);
456 WARN_ON(IS_ERR(devlink));
457 }
458 if (!IS_ERR(devlink) && ~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100459 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100460 mutex_unlock(&devlink_mutex);
461}
462
Johannes Berg489111e2016-10-24 14:40:03 +0200463static struct genl_family devlink_nl_family;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100464
465enum devlink_multicast_groups {
466 DEVLINK_MCGRP_CONFIG,
467};
468
469static const struct genl_multicast_group devlink_nl_mcgrps[] = {
470 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
471};
472
473static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
474{
475 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
476 return -EMSGSIZE;
477 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
478 return -EMSGSIZE;
479 return 0;
480}
481
482static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
483 enum devlink_command cmd, u32 portid,
484 u32 seq, int flags)
485{
486 void *hdr;
487
488 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
489 if (!hdr)
490 return -EMSGSIZE;
491
492 if (devlink_nl_put_handle(msg, devlink))
493 goto nla_put_failure;
Jiri Pirko2670ac22019-09-12 10:49:46 +0200494 if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed))
495 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100496
497 genlmsg_end(msg, hdr);
498 return 0;
499
500nla_put_failure:
501 genlmsg_cancel(msg, hdr);
502 return -EMSGSIZE;
503}
504
505static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
506{
507 struct sk_buff *msg;
508 int err;
509
510 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
511
512 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
513 if (!msg)
514 return;
515
516 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
517 if (err) {
518 nlmsg_free(msg);
519 return;
520 }
521
522 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
523 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
524}
525
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200526static int devlink_nl_port_attrs_put(struct sk_buff *msg,
527 struct devlink_port *devlink_port)
528{
529 struct devlink_port_attrs *attrs = &devlink_port->attrs;
530
Danielle Ratson10a429b2020-07-09 16:18:14 +0300531 if (!devlink_port->attrs_set)
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200532 return 0;
Danielle Ratsona21cf0a2020-07-09 16:18:18 +0300533 if (attrs->lanes) {
534 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
535 return -EMSGSIZE;
536 }
Danielle Ratsona0f49b52020-07-09 16:18:20 +0300537 if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
538 return -EMSGSIZE;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200539 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
540 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500541 switch (devlink_port->attrs.flavour) {
542 case DEVLINK_PORT_FLAVOUR_PCI_PF:
Parav Pandit98fd2d62019-07-08 23:17:37 -0500543 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
544 attrs->pci_pf.pf))
545 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500546 break;
547 case DEVLINK_PORT_FLAVOUR_PCI_VF:
Parav Pandite41b6bf2019-07-08 23:17:38 -0500548 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
549 attrs->pci_vf.pf) ||
550 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER,
551 attrs->pci_vf.vf))
552 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500553 break;
554 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
555 case DEVLINK_PORT_FLAVOUR_CPU:
556 case DEVLINK_PORT_FLAVOUR_DSA:
Parav Panditacf1ee42020-03-03 08:12:42 -0600557 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Parav Pandit58b6be42019-08-30 05:39:45 -0500558 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
559 attrs->phys.port_number))
560 return -EMSGSIZE;
561 if (!attrs->split)
562 return 0;
563 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
564 attrs->phys.port_number))
565 return -EMSGSIZE;
566 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
567 attrs->phys.split_subport_number))
568 return -EMSGSIZE;
569 break;
570 default:
571 break;
Parav Pandit98fd2d62019-07-08 23:17:37 -0500572 }
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200573 return 0;
574}
575
Parav Pandit2a916ec2020-06-19 03:32:48 +0000576static int
577devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
578 struct netlink_ext_ack *extack)
579{
580 struct devlink *devlink = port->devlink;
581 const struct devlink_ops *ops;
582 struct nlattr *function_attr;
583 bool empty_nest = true;
584 int err = 0;
585
586 function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
587 if (!function_attr)
588 return -EMSGSIZE;
589
590 ops = devlink->ops;
591 if (ops->port_function_hw_addr_get) {
Stephen Rothwell29cb9862020-06-23 13:43:06 +1000592 int hw_addr_len;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000593 u8 hw_addr[MAX_ADDR_LEN];
594
595 err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack);
596 if (err == -EOPNOTSUPP) {
597 /* Port function attributes are optional for a port. If port doesn't
598 * support function attribute, returning -EOPNOTSUPP is not an error.
599 */
600 err = 0;
601 goto out;
602 } else if (err) {
603 goto out;
604 }
605 err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr);
606 if (err)
607 goto out;
608 empty_nest = false;
609 }
610
611out:
612 if (err || empty_nest)
613 nla_nest_cancel(msg, function_attr);
614 else
615 nla_nest_end(msg, function_attr);
616 return err;
617}
618
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100619static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
620 struct devlink_port *devlink_port,
621 enum devlink_command cmd, u32 portid,
Parav Pandita829eb02020-06-19 03:32:47 +0000622 u32 seq, int flags,
623 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100624{
625 void *hdr;
626
627 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
628 if (!hdr)
629 return -EMSGSIZE;
630
631 if (devlink_nl_put_handle(msg, devlink))
632 goto nla_put_failure;
633 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
634 goto nla_put_failure;
Jiri Pirkob8f97552019-03-24 11:14:37 +0100635
Ido Schimmel0f420b62019-08-17 16:28:17 +0300636 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100637 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100638 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100639 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
640 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
641 devlink_port->desired_type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100642 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100643 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
644 struct net_device *netdev = devlink_port->type_dev;
645
646 if (netdev &&
647 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
648 netdev->ifindex) ||
649 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
650 netdev->name)))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100651 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100652 }
653 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
654 struct ib_device *ibdev = devlink_port->type_dev;
655
656 if (ibdev &&
657 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
658 ibdev->name))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100659 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100660 }
Ido Schimmel0f420b62019-08-17 16:28:17 +0300661 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200662 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100663 goto nla_put_failure;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000664 if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
665 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100666
667 genlmsg_end(msg, hdr);
668 return 0;
669
Jiri Pirkob8f97552019-03-24 11:14:37 +0100670nla_put_failure_type_locked:
Ido Schimmel0f420b62019-08-17 16:28:17 +0300671 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100672nla_put_failure:
673 genlmsg_cancel(msg, hdr);
674 return -EMSGSIZE;
675}
676
677static void devlink_port_notify(struct devlink_port *devlink_port,
678 enum devlink_command cmd)
679{
680 struct devlink *devlink = devlink_port->devlink;
681 struct sk_buff *msg;
682 int err;
683
684 if (!devlink_port->registered)
685 return;
686
687 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
688
689 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
690 if (!msg)
691 return;
692
Parav Pandita829eb02020-06-19 03:32:47 +0000693 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0,
694 NULL);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100695 if (err) {
696 nlmsg_free(msg);
697 return;
698 }
699
700 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
701 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
702}
703
704static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
705{
706 struct devlink *devlink = info->user_ptr[0];
707 struct sk_buff *msg;
708 int err;
709
710 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
711 if (!msg)
712 return -ENOMEM;
713
714 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
715 info->snd_portid, info->snd_seq, 0);
716 if (err) {
717 nlmsg_free(msg);
718 return err;
719 }
720
721 return genlmsg_reply(msg, info);
722}
723
724static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
725 struct netlink_callback *cb)
726{
727 struct devlink *devlink;
728 int start = cb->args[0];
729 int idx = 0;
730 int err;
731
732 mutex_lock(&devlink_mutex);
733 list_for_each_entry(devlink, &devlink_list, list) {
734 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
735 continue;
736 if (idx < start) {
737 idx++;
738 continue;
739 }
740 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
741 NETLINK_CB(cb->skb).portid,
742 cb->nlh->nlmsg_seq, NLM_F_MULTI);
743 if (err)
744 goto out;
745 idx++;
746 }
747out:
748 mutex_unlock(&devlink_mutex);
749
750 cb->args[0] = idx;
751 return msg->len;
752}
753
754static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
755 struct genl_info *info)
756{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200757 struct devlink_port *devlink_port = info->user_ptr[0];
758 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100759 struct sk_buff *msg;
760 int err;
761
762 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
763 if (!msg)
764 return -ENOMEM;
765
766 err = devlink_nl_port_fill(msg, devlink, devlink_port,
767 DEVLINK_CMD_PORT_NEW,
Parav Pandita829eb02020-06-19 03:32:47 +0000768 info->snd_portid, info->snd_seq, 0,
769 info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100770 if (err) {
771 nlmsg_free(msg);
772 return err;
773 }
774
775 return genlmsg_reply(msg, info);
776}
777
778static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
779 struct netlink_callback *cb)
780{
781 struct devlink *devlink;
782 struct devlink_port *devlink_port;
783 int start = cb->args[0];
784 int idx = 0;
785 int err;
786
787 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100788 list_for_each_entry(devlink, &devlink_list, list) {
789 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
790 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100791 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100792 list_for_each_entry(devlink_port, &devlink->port_list, list) {
793 if (idx < start) {
794 idx++;
795 continue;
796 }
797 err = devlink_nl_port_fill(msg, devlink, devlink_port,
798 DEVLINK_CMD_NEW,
799 NETLINK_CB(cb->skb).portid,
800 cb->nlh->nlmsg_seq,
Parav Pandita829eb02020-06-19 03:32:47 +0000801 NLM_F_MULTI,
802 cb->extack);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100803 if (err) {
804 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100805 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100806 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100807 idx++;
808 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100809 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100810 }
811out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100812 mutex_unlock(&devlink_mutex);
813
814 cb->args[0] = idx;
815 return msg->len;
816}
817
818static int devlink_port_type_set(struct devlink *devlink,
819 struct devlink_port *devlink_port,
820 enum devlink_port_type port_type)
821
822{
823 int err;
824
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800825 if (devlink->ops->port_type_set) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100826 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
827 return -EINVAL;
Elad Raz6edf1012016-10-23 17:43:05 +0200828 if (port_type == devlink_port->type)
829 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100830 err = devlink->ops->port_type_set(devlink_port, port_type);
831 if (err)
832 return err;
833 devlink_port->desired_type = port_type;
834 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
835 return 0;
836 }
837 return -EOPNOTSUPP;
838}
839
Parav Pandita1e8ae92020-06-19 03:32:49 +0000840static int
841devlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port,
842 const struct nlattr *attr, struct netlink_ext_ack *extack)
843{
844 const struct devlink_ops *ops;
845 const u8 *hw_addr;
846 int hw_addr_len;
847 int err;
848
849 hw_addr = nla_data(attr);
850 hw_addr_len = nla_len(attr);
851 if (hw_addr_len > MAX_ADDR_LEN) {
852 NL_SET_ERR_MSG_MOD(extack, "Port function hardware address too long");
853 return -EINVAL;
854 }
855 if (port->type == DEVLINK_PORT_TYPE_ETH) {
856 if (hw_addr_len != ETH_ALEN) {
857 NL_SET_ERR_MSG_MOD(extack, "Address must be 6 bytes for Ethernet device");
858 return -EINVAL;
859 }
860 if (!is_unicast_ether_addr(hw_addr)) {
861 NL_SET_ERR_MSG_MOD(extack, "Non-unicast hardware address unsupported");
862 return -EINVAL;
863 }
864 }
865
866 ops = devlink->ops;
867 if (!ops->port_function_hw_addr_set) {
868 NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes");
869 return -EOPNOTSUPP;
870 }
871
872 err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack);
873 if (err)
874 return err;
875
876 devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
877 return 0;
878}
879
880static int
881devlink_port_function_set(struct devlink *devlink, struct devlink_port *port,
882 const struct nlattr *attr, struct netlink_ext_ack *extack)
883{
884 struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];
885 int err;
886
887 err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr,
888 devlink_function_nl_policy, extack);
889 if (err < 0) {
890 NL_SET_ERR_MSG_MOD(extack, "Fail to parse port function attributes");
891 return err;
892 }
893
894 attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
895 if (attr)
896 err = devlink_port_function_hw_addr_set(devlink, port, attr, extack);
897
898 return err;
899}
900
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100901static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
902 struct genl_info *info)
903{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200904 struct devlink_port *devlink_port = info->user_ptr[0];
905 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100906 int err;
907
908 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
909 enum devlink_port_type port_type;
910
911 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
912 err = devlink_port_type_set(devlink, devlink_port, port_type);
913 if (err)
914 return err;
915 }
Parav Pandita1e8ae92020-06-19 03:32:49 +0000916
917 if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
918 struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
919 struct netlink_ext_ack *extack = info->extack;
920
921 err = devlink_port_function_set(devlink, devlink_port, attr, extack);
922 if (err)
923 return err;
924 }
925
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100926 return 0;
927}
928
David Ahernac0fc8a2018-06-05 08:14:09 -0700929static int devlink_port_split(struct devlink *devlink, u32 port_index,
930 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100931
932{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800933 if (devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -0700934 return devlink->ops->port_split(devlink, port_index, count,
935 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100936 return -EOPNOTSUPP;
937}
938
939static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
940 struct genl_info *info)
941{
942 struct devlink *devlink = info->user_ptr[0];
Danielle Ratson82901ad2020-07-09 16:18:21 +0300943 struct devlink_port *devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100944 u32 port_index;
945 u32 count;
946
947 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
948 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
949 return -EINVAL;
950
Danielle Ratson82901ad2020-07-09 16:18:21 +0300951 devlink_port = devlink_port_get_from_info(devlink, info);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100952 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
953 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
Danielle Ratson82901ad2020-07-09 16:18:21 +0300954
955 if (IS_ERR(devlink_port))
956 return -EINVAL;
957
958 if (!devlink_port->attrs.splittable) {
959 /* Split ports cannot be split. */
960 if (devlink_port->attrs.split)
961 NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split further");
962 else
963 NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split");
964 return -EINVAL;
965 }
966
967 if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
968 NL_SET_ERR_MSG_MOD(info->extack, "Invalid split count");
969 return -EINVAL;
970 }
971
David Ahernac0fc8a2018-06-05 08:14:09 -0700972 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100973}
974
David Ahernac0fc8a2018-06-05 08:14:09 -0700975static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
976 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100977
978{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800979 if (devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -0700980 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100981 return -EOPNOTSUPP;
982}
983
984static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
985 struct genl_info *info)
986{
987 struct devlink *devlink = info->user_ptr[0];
988 u32 port_index;
989
990 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
991 return -EINVAL;
992
993 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700994 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100995}
996
Jiri Pirkobf797472016-04-14 18:19:13 +0200997static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
998 struct devlink_sb *devlink_sb,
999 enum devlink_command cmd, u32 portid,
1000 u32 seq, int flags)
1001{
1002 void *hdr;
1003
1004 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1005 if (!hdr)
1006 return -EMSGSIZE;
1007
1008 if (devlink_nl_put_handle(msg, devlink))
1009 goto nla_put_failure;
1010 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1011 goto nla_put_failure;
1012 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
1013 goto nla_put_failure;
1014 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
1015 devlink_sb->ingress_pools_count))
1016 goto nla_put_failure;
1017 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
1018 devlink_sb->egress_pools_count))
1019 goto nla_put_failure;
1020 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
1021 devlink_sb->ingress_tc_count))
1022 goto nla_put_failure;
1023 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
1024 devlink_sb->egress_tc_count))
1025 goto nla_put_failure;
1026
1027 genlmsg_end(msg, hdr);
1028 return 0;
1029
1030nla_put_failure:
1031 genlmsg_cancel(msg, hdr);
1032 return -EMSGSIZE;
1033}
1034
1035static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
1036 struct genl_info *info)
1037{
1038 struct devlink *devlink = info->user_ptr[0];
1039 struct devlink_sb *devlink_sb = info->user_ptr[1];
1040 struct sk_buff *msg;
1041 int err;
1042
1043 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1044 if (!msg)
1045 return -ENOMEM;
1046
1047 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1048 DEVLINK_CMD_SB_NEW,
1049 info->snd_portid, info->snd_seq, 0);
1050 if (err) {
1051 nlmsg_free(msg);
1052 return err;
1053 }
1054
1055 return genlmsg_reply(msg, info);
1056}
1057
1058static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
1059 struct netlink_callback *cb)
1060{
1061 struct devlink *devlink;
1062 struct devlink_sb *devlink_sb;
1063 int start = cb->args[0];
1064 int idx = 0;
1065 int err;
1066
1067 mutex_lock(&devlink_mutex);
1068 list_for_each_entry(devlink, &devlink_list, list) {
1069 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
1070 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001071 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001072 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1073 if (idx < start) {
1074 idx++;
1075 continue;
1076 }
1077 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1078 DEVLINK_CMD_SB_NEW,
1079 NETLINK_CB(cb->skb).portid,
1080 cb->nlh->nlmsg_seq,
1081 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001082 if (err) {
1083 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001084 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001085 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001086 idx++;
1087 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001088 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001089 }
1090out:
1091 mutex_unlock(&devlink_mutex);
1092
1093 cb->args[0] = idx;
1094 return msg->len;
1095}
1096
1097static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
1098 struct devlink_sb *devlink_sb,
1099 u16 pool_index, enum devlink_command cmd,
1100 u32 portid, u32 seq, int flags)
1101{
1102 struct devlink_sb_pool_info pool_info;
1103 void *hdr;
1104 int err;
1105
1106 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
1107 pool_index, &pool_info);
1108 if (err)
1109 return err;
1110
1111 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1112 if (!hdr)
1113 return -EMSGSIZE;
1114
1115 if (devlink_nl_put_handle(msg, devlink))
1116 goto nla_put_failure;
1117 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1118 goto nla_put_failure;
1119 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1120 goto nla_put_failure;
1121 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
1122 goto nla_put_failure;
1123 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
1124 goto nla_put_failure;
1125 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1126 pool_info.threshold_type))
1127 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -08001128 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
1129 pool_info.cell_size))
1130 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +02001131
1132 genlmsg_end(msg, hdr);
1133 return 0;
1134
1135nla_put_failure:
1136 genlmsg_cancel(msg, hdr);
1137 return -EMSGSIZE;
1138}
1139
1140static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
1141 struct genl_info *info)
1142{
1143 struct devlink *devlink = info->user_ptr[0];
1144 struct devlink_sb *devlink_sb = info->user_ptr[1];
1145 struct sk_buff *msg;
1146 u16 pool_index;
1147 int err;
1148
1149 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1150 &pool_index);
1151 if (err)
1152 return err;
1153
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001154 if (!devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001155 return -EOPNOTSUPP;
1156
1157 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1158 if (!msg)
1159 return -ENOMEM;
1160
1161 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
1162 DEVLINK_CMD_SB_POOL_NEW,
1163 info->snd_portid, info->snd_seq, 0);
1164 if (err) {
1165 nlmsg_free(msg);
1166 return err;
1167 }
1168
1169 return genlmsg_reply(msg, info);
1170}
1171
1172static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1173 struct devlink *devlink,
1174 struct devlink_sb *devlink_sb,
1175 u32 portid, u32 seq)
1176{
1177 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1178 u16 pool_index;
1179 int err;
1180
1181 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1182 if (*p_idx < start) {
1183 (*p_idx)++;
1184 continue;
1185 }
1186 err = devlink_nl_sb_pool_fill(msg, devlink,
1187 devlink_sb,
1188 pool_index,
1189 DEVLINK_CMD_SB_POOL_NEW,
1190 portid, seq, NLM_F_MULTI);
1191 if (err)
1192 return err;
1193 (*p_idx)++;
1194 }
1195 return 0;
1196}
1197
1198static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1199 struct netlink_callback *cb)
1200{
1201 struct devlink *devlink;
1202 struct devlink_sb *devlink_sb;
1203 int start = cb->args[0];
1204 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001205 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001206
1207 mutex_lock(&devlink_mutex);
1208 list_for_each_entry(devlink, &devlink_list, list) {
1209 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001210 !devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001211 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001212 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001213 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1214 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1215 devlink_sb,
1216 NETLINK_CB(cb->skb).portid,
1217 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001218 if (err && err != -EOPNOTSUPP) {
1219 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001220 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001221 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001222 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001223 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001224 }
1225out:
1226 mutex_unlock(&devlink_mutex);
1227
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001228 if (err != -EMSGSIZE)
1229 return err;
1230
Jiri Pirkobf797472016-04-14 18:19:13 +02001231 cb->args[0] = idx;
1232 return msg->len;
1233}
1234
1235static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1236 u16 pool_index, u32 size,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001237 enum devlink_sb_threshold_type threshold_type,
1238 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001239
1240{
1241 const struct devlink_ops *ops = devlink->ops;
1242
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001243 if (ops->sb_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001244 return ops->sb_pool_set(devlink, sb_index, pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001245 size, threshold_type, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001246 return -EOPNOTSUPP;
1247}
1248
1249static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1250 struct genl_info *info)
1251{
1252 struct devlink *devlink = info->user_ptr[0];
1253 struct devlink_sb *devlink_sb = info->user_ptr[1];
1254 enum devlink_sb_threshold_type threshold_type;
1255 u16 pool_index;
1256 u32 size;
1257 int err;
1258
1259 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1260 &pool_index);
1261 if (err)
1262 return err;
1263
1264 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1265 if (err)
1266 return err;
1267
1268 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1269 return -EINVAL;
1270
1271 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1272 return devlink_sb_pool_set(devlink, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001273 pool_index, size, threshold_type,
1274 info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001275}
1276
1277static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1278 struct devlink *devlink,
1279 struct devlink_port *devlink_port,
1280 struct devlink_sb *devlink_sb,
1281 u16 pool_index,
1282 enum devlink_command cmd,
1283 u32 portid, u32 seq, int flags)
1284{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001285 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001286 u32 threshold;
1287 void *hdr;
1288 int err;
1289
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001290 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1291 pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001292 if (err)
1293 return err;
1294
1295 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1296 if (!hdr)
1297 return -EMSGSIZE;
1298
1299 if (devlink_nl_put_handle(msg, devlink))
1300 goto nla_put_failure;
1301 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1302 goto nla_put_failure;
1303 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1304 goto nla_put_failure;
1305 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1306 goto nla_put_failure;
1307 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1308 goto nla_put_failure;
1309
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001310 if (ops->sb_occ_port_pool_get) {
1311 u32 cur;
1312 u32 max;
1313
1314 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1315 pool_index, &cur, &max);
1316 if (err && err != -EOPNOTSUPP)
1317 return err;
1318 if (!err) {
1319 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1320 goto nla_put_failure;
1321 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1322 goto nla_put_failure;
1323 }
1324 }
1325
Jiri Pirkobf797472016-04-14 18:19:13 +02001326 genlmsg_end(msg, hdr);
1327 return 0;
1328
1329nla_put_failure:
1330 genlmsg_cancel(msg, hdr);
1331 return -EMSGSIZE;
1332}
1333
1334static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1335 struct genl_info *info)
1336{
1337 struct devlink_port *devlink_port = info->user_ptr[0];
1338 struct devlink *devlink = devlink_port->devlink;
1339 struct devlink_sb *devlink_sb = info->user_ptr[1];
1340 struct sk_buff *msg;
1341 u16 pool_index;
1342 int err;
1343
1344 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1345 &pool_index);
1346 if (err)
1347 return err;
1348
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001349 if (!devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001350 return -EOPNOTSUPP;
1351
1352 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1353 if (!msg)
1354 return -ENOMEM;
1355
1356 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1357 devlink_sb, pool_index,
1358 DEVLINK_CMD_SB_PORT_POOL_NEW,
1359 info->snd_portid, info->snd_seq, 0);
1360 if (err) {
1361 nlmsg_free(msg);
1362 return err;
1363 }
1364
1365 return genlmsg_reply(msg, info);
1366}
1367
1368static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1369 struct devlink *devlink,
1370 struct devlink_sb *devlink_sb,
1371 u32 portid, u32 seq)
1372{
1373 struct devlink_port *devlink_port;
1374 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1375 u16 pool_index;
1376 int err;
1377
1378 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1379 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1380 if (*p_idx < start) {
1381 (*p_idx)++;
1382 continue;
1383 }
1384 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1385 devlink_port,
1386 devlink_sb,
1387 pool_index,
1388 DEVLINK_CMD_SB_PORT_POOL_NEW,
1389 portid, seq,
1390 NLM_F_MULTI);
1391 if (err)
1392 return err;
1393 (*p_idx)++;
1394 }
1395 }
1396 return 0;
1397}
1398
1399static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1400 struct netlink_callback *cb)
1401{
1402 struct devlink *devlink;
1403 struct devlink_sb *devlink_sb;
1404 int start = cb->args[0];
1405 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001406 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001407
1408 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001409 list_for_each_entry(devlink, &devlink_list, list) {
1410 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001411 !devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001412 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001413 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001414 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1415 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1416 devlink, devlink_sb,
1417 NETLINK_CB(cb->skb).portid,
1418 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001419 if (err && err != -EOPNOTSUPP) {
1420 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001421 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001422 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001423 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001424 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001425 }
1426out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001427 mutex_unlock(&devlink_mutex);
1428
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001429 if (err != -EMSGSIZE)
1430 return err;
1431
Jiri Pirkobf797472016-04-14 18:19:13 +02001432 cb->args[0] = idx;
1433 return msg->len;
1434}
1435
1436static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1437 unsigned int sb_index, u16 pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001438 u32 threshold,
1439 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001440
1441{
1442 const struct devlink_ops *ops = devlink_port->devlink->ops;
1443
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001444 if (ops->sb_port_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001445 return ops->sb_port_pool_set(devlink_port, sb_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001446 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001447 return -EOPNOTSUPP;
1448}
1449
1450static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1451 struct genl_info *info)
1452{
1453 struct devlink_port *devlink_port = info->user_ptr[0];
1454 struct devlink_sb *devlink_sb = info->user_ptr[1];
1455 u16 pool_index;
1456 u32 threshold;
1457 int err;
1458
1459 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1460 &pool_index);
1461 if (err)
1462 return err;
1463
1464 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1465 return -EINVAL;
1466
1467 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1468 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001469 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001470}
1471
1472static int
1473devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1474 struct devlink_port *devlink_port,
1475 struct devlink_sb *devlink_sb, u16 tc_index,
1476 enum devlink_sb_pool_type pool_type,
1477 enum devlink_command cmd,
1478 u32 portid, u32 seq, int flags)
1479{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001480 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001481 u16 pool_index;
1482 u32 threshold;
1483 void *hdr;
1484 int err;
1485
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001486 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1487 tc_index, pool_type,
1488 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001489 if (err)
1490 return err;
1491
1492 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1493 if (!hdr)
1494 return -EMSGSIZE;
1495
1496 if (devlink_nl_put_handle(msg, devlink))
1497 goto nla_put_failure;
1498 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1499 goto nla_put_failure;
1500 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1501 goto nla_put_failure;
1502 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1503 goto nla_put_failure;
1504 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1505 goto nla_put_failure;
1506 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1507 goto nla_put_failure;
1508 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1509 goto nla_put_failure;
1510
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001511 if (ops->sb_occ_tc_port_bind_get) {
1512 u32 cur;
1513 u32 max;
1514
1515 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1516 devlink_sb->index,
1517 tc_index, pool_type,
1518 &cur, &max);
1519 if (err && err != -EOPNOTSUPP)
1520 return err;
1521 if (!err) {
1522 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1523 goto nla_put_failure;
1524 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1525 goto nla_put_failure;
1526 }
1527 }
1528
Jiri Pirkobf797472016-04-14 18:19:13 +02001529 genlmsg_end(msg, hdr);
1530 return 0;
1531
1532nla_put_failure:
1533 genlmsg_cancel(msg, hdr);
1534 return -EMSGSIZE;
1535}
1536
1537static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1538 struct genl_info *info)
1539{
1540 struct devlink_port *devlink_port = info->user_ptr[0];
1541 struct devlink *devlink = devlink_port->devlink;
1542 struct devlink_sb *devlink_sb = info->user_ptr[1];
1543 struct sk_buff *msg;
1544 enum devlink_sb_pool_type pool_type;
1545 u16 tc_index;
1546 int err;
1547
1548 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1549 if (err)
1550 return err;
1551
1552 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1553 pool_type, &tc_index);
1554 if (err)
1555 return err;
1556
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001557 if (!devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001558 return -EOPNOTSUPP;
1559
1560 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1561 if (!msg)
1562 return -ENOMEM;
1563
1564 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1565 devlink_sb, tc_index, pool_type,
1566 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1567 info->snd_portid,
1568 info->snd_seq, 0);
1569 if (err) {
1570 nlmsg_free(msg);
1571 return err;
1572 }
1573
1574 return genlmsg_reply(msg, info);
1575}
1576
1577static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1578 int start, int *p_idx,
1579 struct devlink *devlink,
1580 struct devlink_sb *devlink_sb,
1581 u32 portid, u32 seq)
1582{
1583 struct devlink_port *devlink_port;
1584 u16 tc_index;
1585 int err;
1586
1587 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1588 for (tc_index = 0;
1589 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1590 if (*p_idx < start) {
1591 (*p_idx)++;
1592 continue;
1593 }
1594 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1595 devlink_port,
1596 devlink_sb,
1597 tc_index,
1598 DEVLINK_SB_POOL_TYPE_INGRESS,
1599 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1600 portid, seq,
1601 NLM_F_MULTI);
1602 if (err)
1603 return err;
1604 (*p_idx)++;
1605 }
1606 for (tc_index = 0;
1607 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1608 if (*p_idx < start) {
1609 (*p_idx)++;
1610 continue;
1611 }
1612 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1613 devlink_port,
1614 devlink_sb,
1615 tc_index,
1616 DEVLINK_SB_POOL_TYPE_EGRESS,
1617 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1618 portid, seq,
1619 NLM_F_MULTI);
1620 if (err)
1621 return err;
1622 (*p_idx)++;
1623 }
1624 }
1625 return 0;
1626}
1627
1628static int
1629devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1630 struct netlink_callback *cb)
1631{
1632 struct devlink *devlink;
1633 struct devlink_sb *devlink_sb;
1634 int start = cb->args[0];
1635 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001636 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001637
1638 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001639 list_for_each_entry(devlink, &devlink_list, list) {
1640 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001641 !devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001642 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001643
1644 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001645 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1646 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1647 devlink,
1648 devlink_sb,
1649 NETLINK_CB(cb->skb).portid,
1650 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001651 if (err && err != -EOPNOTSUPP) {
1652 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001653 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001654 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001655 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001656 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001657 }
1658out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001659 mutex_unlock(&devlink_mutex);
1660
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001661 if (err != -EMSGSIZE)
1662 return err;
1663
Jiri Pirkobf797472016-04-14 18:19:13 +02001664 cb->args[0] = idx;
1665 return msg->len;
1666}
1667
1668static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1669 unsigned int sb_index, u16 tc_index,
1670 enum devlink_sb_pool_type pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001671 u16 pool_index, u32 threshold,
1672 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001673
1674{
1675 const struct devlink_ops *ops = devlink_port->devlink->ops;
1676
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001677 if (ops->sb_tc_pool_bind_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001678 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1679 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001680 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001681 return -EOPNOTSUPP;
1682}
1683
1684static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1685 struct genl_info *info)
1686{
1687 struct devlink_port *devlink_port = info->user_ptr[0];
1688 struct devlink_sb *devlink_sb = info->user_ptr[1];
1689 enum devlink_sb_pool_type pool_type;
1690 u16 tc_index;
1691 u16 pool_index;
1692 u32 threshold;
1693 int err;
1694
1695 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1696 if (err)
1697 return err;
1698
1699 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1700 pool_type, &tc_index);
1701 if (err)
1702 return err;
1703
1704 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1705 &pool_index);
1706 if (err)
1707 return err;
1708
1709 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1710 return -EINVAL;
1711
1712 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1713 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1714 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001715 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001716}
1717
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001718static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1719 struct genl_info *info)
1720{
1721 struct devlink *devlink = info->user_ptr[0];
1722 struct devlink_sb *devlink_sb = info->user_ptr[1];
1723 const struct devlink_ops *ops = devlink->ops;
1724
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001725 if (ops->sb_occ_snapshot)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001726 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1727 return -EOPNOTSUPP;
1728}
1729
1730static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1731 struct genl_info *info)
1732{
1733 struct devlink *devlink = info->user_ptr[0];
1734 struct devlink_sb *devlink_sb = info->user_ptr[1];
1735 const struct devlink_ops *ops = devlink->ops;
1736
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001737 if (ops->sb_occ_max_clear)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001738 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1739 return -EOPNOTSUPP;
1740}
1741
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001742static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1743 enum devlink_command cmd, u32 portid,
1744 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001745{
Roi Dayan59bfde02016-11-22 23:09:57 +02001746 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001747 enum devlink_eswitch_encap_mode encap_mode;
1748 u8 inline_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001749 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001750 int err = 0;
1751 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001752
1753 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1754 if (!hdr)
1755 return -EMSGSIZE;
1756
Roi Dayan59bfde02016-11-22 23:09:57 +02001757 err = devlink_nl_put_handle(msg, devlink);
1758 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001759 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001760
Jiri Pirko4456f612017-02-09 15:54:36 +01001761 if (ops->eswitch_mode_get) {
1762 err = ops->eswitch_mode_get(devlink, &mode);
1763 if (err)
1764 goto nla_put_failure;
1765 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1766 if (err)
1767 goto nla_put_failure;
1768 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001769
1770 if (ops->eswitch_inline_mode_get) {
1771 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1772 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001773 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001774 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1775 inline_mode);
1776 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001777 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001778 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001779
Roi Dayanf43e9b02016-09-25 13:52:44 +03001780 if (ops->eswitch_encap_mode_get) {
1781 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1782 if (err)
1783 goto nla_put_failure;
1784 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1785 if (err)
1786 goto nla_put_failure;
1787 }
1788
Or Gerlitz08f4b592016-07-01 14:51:01 +03001789 genlmsg_end(msg, hdr);
1790 return 0;
1791
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001792nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001793 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001794 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001795}
1796
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001797static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1798 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001799{
1800 struct devlink *devlink = info->user_ptr[0];
Or Gerlitz08f4b592016-07-01 14:51:01 +03001801 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001802 int err;
1803
Or Gerlitz08f4b592016-07-01 14:51:01 +03001804 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1805 if (!msg)
1806 return -ENOMEM;
1807
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001808 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1809 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001810
1811 if (err) {
1812 nlmsg_free(msg);
1813 return err;
1814 }
1815
1816 return genlmsg_reply(msg, info);
1817}
1818
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001819static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1820 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001821{
1822 struct devlink *devlink = info->user_ptr[0];
1823 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001824 enum devlink_eswitch_encap_mode encap_mode;
1825 u8 inline_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001826 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001827 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001828
Roi Dayan59bfde02016-11-22 23:09:57 +02001829 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1830 if (!ops->eswitch_mode_set)
1831 return -EOPNOTSUPP;
1832 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001833 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001834 if (err)
1835 return err;
1836 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001837
Roi Dayan59bfde02016-11-22 23:09:57 +02001838 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1839 if (!ops->eswitch_inline_mode_set)
1840 return -EOPNOTSUPP;
1841 inline_mode = nla_get_u8(
1842 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001843 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1844 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001845 if (err)
1846 return err;
1847 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03001848
1849 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1850 if (!ops->eswitch_encap_mode_set)
1851 return -EOPNOTSUPP;
1852 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001853 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1854 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03001855 if (err)
1856 return err;
1857 }
1858
Roi Dayan59bfde02016-11-22 23:09:57 +02001859 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001860}
1861
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001862int devlink_dpipe_match_put(struct sk_buff *skb,
1863 struct devlink_dpipe_match *match)
1864{
1865 struct devlink_dpipe_header *header = match->header;
1866 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1867 struct nlattr *match_attr;
1868
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001869 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001870 if (!match_attr)
1871 return -EMSGSIZE;
1872
1873 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1874 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1875 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1876 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1877 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1878 goto nla_put_failure;
1879
1880 nla_nest_end(skb, match_attr);
1881 return 0;
1882
1883nla_put_failure:
1884 nla_nest_cancel(skb, match_attr);
1885 return -EMSGSIZE;
1886}
1887EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1888
1889static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1890 struct sk_buff *skb)
1891{
1892 struct nlattr *matches_attr;
1893
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001894 matches_attr = nla_nest_start_noflag(skb,
1895 DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001896 if (!matches_attr)
1897 return -EMSGSIZE;
1898
1899 if (table->table_ops->matches_dump(table->priv, skb))
1900 goto nla_put_failure;
1901
1902 nla_nest_end(skb, matches_attr);
1903 return 0;
1904
1905nla_put_failure:
1906 nla_nest_cancel(skb, matches_attr);
1907 return -EMSGSIZE;
1908}
1909
1910int devlink_dpipe_action_put(struct sk_buff *skb,
1911 struct devlink_dpipe_action *action)
1912{
1913 struct devlink_dpipe_header *header = action->header;
1914 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1915 struct nlattr *action_attr;
1916
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001917 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001918 if (!action_attr)
1919 return -EMSGSIZE;
1920
1921 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1922 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1923 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1924 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1925 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1926 goto nla_put_failure;
1927
1928 nla_nest_end(skb, action_attr);
1929 return 0;
1930
1931nla_put_failure:
1932 nla_nest_cancel(skb, action_attr);
1933 return -EMSGSIZE;
1934}
1935EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1936
1937static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1938 struct sk_buff *skb)
1939{
1940 struct nlattr *actions_attr;
1941
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001942 actions_attr = nla_nest_start_noflag(skb,
1943 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001944 if (!actions_attr)
1945 return -EMSGSIZE;
1946
1947 if (table->table_ops->actions_dump(table->priv, skb))
1948 goto nla_put_failure;
1949
1950 nla_nest_end(skb, actions_attr);
1951 return 0;
1952
1953nla_put_failure:
1954 nla_nest_cancel(skb, actions_attr);
1955 return -EMSGSIZE;
1956}
1957
1958static int devlink_dpipe_table_put(struct sk_buff *skb,
1959 struct devlink_dpipe_table *table)
1960{
1961 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001962 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001963
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001964 table_size = table->table_ops->size_get(table->priv);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001965 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001966 if (!table_attr)
1967 return -EMSGSIZE;
1968
1969 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001970 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001971 DEVLINK_ATTR_PAD))
1972 goto nla_put_failure;
1973 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1974 table->counters_enabled))
1975 goto nla_put_failure;
1976
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001977 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02001978 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1979 table->resource_id, DEVLINK_ATTR_PAD) ||
1980 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1981 table->resource_units, DEVLINK_ATTR_PAD))
1982 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001983 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001984 if (devlink_dpipe_matches_put(table, skb))
1985 goto nla_put_failure;
1986
1987 if (devlink_dpipe_actions_put(table, skb))
1988 goto nla_put_failure;
1989
1990 nla_nest_end(skb, table_attr);
1991 return 0;
1992
1993nla_put_failure:
1994 nla_nest_cancel(skb, table_attr);
1995 return -EMSGSIZE;
1996}
1997
1998static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1999 struct genl_info *info)
2000{
2001 int err;
2002
2003 if (*pskb) {
2004 err = genlmsg_reply(*pskb, info);
2005 if (err)
2006 return err;
2007 }
2008 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
2009 if (!*pskb)
2010 return -ENOMEM;
2011 return 0;
2012}
2013
2014static int devlink_dpipe_tables_fill(struct genl_info *info,
2015 enum devlink_command cmd, int flags,
2016 struct list_head *dpipe_tables,
2017 const char *table_name)
2018{
2019 struct devlink *devlink = info->user_ptr[0];
2020 struct devlink_dpipe_table *table;
2021 struct nlattr *tables_attr;
2022 struct sk_buff *skb = NULL;
2023 struct nlmsghdr *nlh;
2024 bool incomplete;
2025 void *hdr;
2026 int i;
2027 int err;
2028
2029 table = list_first_entry(dpipe_tables,
2030 struct devlink_dpipe_table, list);
2031start_again:
2032 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2033 if (err)
2034 return err;
2035
2036 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2037 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002038 if (!hdr) {
2039 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002040 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002041 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002042
2043 if (devlink_nl_put_handle(skb, devlink))
2044 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002045 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002046 if (!tables_attr)
2047 goto nla_put_failure;
2048
2049 i = 0;
2050 incomplete = false;
2051 list_for_each_entry_from(table, dpipe_tables, list) {
2052 if (!table_name) {
2053 err = devlink_dpipe_table_put(skb, table);
2054 if (err) {
2055 if (!i)
2056 goto err_table_put;
2057 incomplete = true;
2058 break;
2059 }
2060 } else {
2061 if (!strcmp(table->name, table_name)) {
2062 err = devlink_dpipe_table_put(skb, table);
2063 if (err)
2064 break;
2065 }
2066 }
2067 i++;
2068 }
2069
2070 nla_nest_end(skb, tables_attr);
2071 genlmsg_end(skb, hdr);
2072 if (incomplete)
2073 goto start_again;
2074
2075send_done:
2076 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2077 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2078 if (!nlh) {
2079 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2080 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002081 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002082 goto send_done;
2083 }
2084
2085 return genlmsg_reply(skb, info);
2086
2087nla_put_failure:
2088 err = -EMSGSIZE;
2089err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002090 nlmsg_free(skb);
2091 return err;
2092}
2093
2094static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
2095 struct genl_info *info)
2096{
2097 struct devlink *devlink = info->user_ptr[0];
2098 const char *table_name = NULL;
2099
2100 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2101 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2102
2103 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
2104 &devlink->dpipe_table_list,
2105 table_name);
2106}
2107
2108static int devlink_dpipe_value_put(struct sk_buff *skb,
2109 struct devlink_dpipe_value *value)
2110{
2111 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
2112 value->value_size, value->value))
2113 return -EMSGSIZE;
2114 if (value->mask)
2115 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
2116 value->value_size, value->mask))
2117 return -EMSGSIZE;
2118 if (value->mapping_valid)
2119 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
2120 value->mapping_value))
2121 return -EMSGSIZE;
2122 return 0;
2123}
2124
2125static int devlink_dpipe_action_value_put(struct sk_buff *skb,
2126 struct devlink_dpipe_value *value)
2127{
2128 if (!value->action)
2129 return -EINVAL;
2130 if (devlink_dpipe_action_put(skb, value->action))
2131 return -EMSGSIZE;
2132 if (devlink_dpipe_value_put(skb, value))
2133 return -EMSGSIZE;
2134 return 0;
2135}
2136
2137static int devlink_dpipe_action_values_put(struct sk_buff *skb,
2138 struct devlink_dpipe_value *values,
2139 unsigned int values_count)
2140{
2141 struct nlattr *action_attr;
2142 int i;
2143 int err;
2144
2145 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002146 action_attr = nla_nest_start_noflag(skb,
2147 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002148 if (!action_attr)
2149 return -EMSGSIZE;
2150 err = devlink_dpipe_action_value_put(skb, &values[i]);
2151 if (err)
2152 goto err_action_value_put;
2153 nla_nest_end(skb, action_attr);
2154 }
2155 return 0;
2156
2157err_action_value_put:
2158 nla_nest_cancel(skb, action_attr);
2159 return err;
2160}
2161
2162static int devlink_dpipe_match_value_put(struct sk_buff *skb,
2163 struct devlink_dpipe_value *value)
2164{
2165 if (!value->match)
2166 return -EINVAL;
2167 if (devlink_dpipe_match_put(skb, value->match))
2168 return -EMSGSIZE;
2169 if (devlink_dpipe_value_put(skb, value))
2170 return -EMSGSIZE;
2171 return 0;
2172}
2173
2174static int devlink_dpipe_match_values_put(struct sk_buff *skb,
2175 struct devlink_dpipe_value *values,
2176 unsigned int values_count)
2177{
2178 struct nlattr *match_attr;
2179 int i;
2180 int err;
2181
2182 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002183 match_attr = nla_nest_start_noflag(skb,
2184 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002185 if (!match_attr)
2186 return -EMSGSIZE;
2187 err = devlink_dpipe_match_value_put(skb, &values[i]);
2188 if (err)
2189 goto err_match_value_put;
2190 nla_nest_end(skb, match_attr);
2191 }
2192 return 0;
2193
2194err_match_value_put:
2195 nla_nest_cancel(skb, match_attr);
2196 return err;
2197}
2198
2199static int devlink_dpipe_entry_put(struct sk_buff *skb,
2200 struct devlink_dpipe_entry *entry)
2201{
2202 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2203 int err;
2204
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002205 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002206 if (!entry_attr)
2207 return -EMSGSIZE;
2208
2209 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2210 DEVLINK_ATTR_PAD))
2211 goto nla_put_failure;
2212 if (entry->counter_valid)
2213 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2214 entry->counter, DEVLINK_ATTR_PAD))
2215 goto nla_put_failure;
2216
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002217 matches_attr = nla_nest_start_noflag(skb,
2218 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002219 if (!matches_attr)
2220 goto nla_put_failure;
2221
2222 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2223 entry->match_values_count);
2224 if (err) {
2225 nla_nest_cancel(skb, matches_attr);
2226 goto err_match_values_put;
2227 }
2228 nla_nest_end(skb, matches_attr);
2229
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002230 actions_attr = nla_nest_start_noflag(skb,
2231 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002232 if (!actions_attr)
2233 goto nla_put_failure;
2234
2235 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2236 entry->action_values_count);
2237 if (err) {
2238 nla_nest_cancel(skb, actions_attr);
2239 goto err_action_values_put;
2240 }
2241 nla_nest_end(skb, actions_attr);
2242
2243 nla_nest_end(skb, entry_attr);
2244 return 0;
2245
2246nla_put_failure:
2247 err = -EMSGSIZE;
2248err_match_values_put:
2249err_action_values_put:
2250 nla_nest_cancel(skb, entry_attr);
2251 return err;
2252}
2253
2254static struct devlink_dpipe_table *
2255devlink_dpipe_table_find(struct list_head *dpipe_tables,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302256 const char *table_name, struct devlink *devlink)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002257{
2258 struct devlink_dpipe_table *table;
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302259 list_for_each_entry_rcu(table, dpipe_tables, list,
2260 lockdep_is_held(&devlink->lock)) {
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002261 if (!strcmp(table->name, table_name))
2262 return table;
2263 }
2264 return NULL;
2265}
2266
2267int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2268{
2269 struct devlink *devlink;
2270 int err;
2271
2272 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2273 dump_ctx->info);
2274 if (err)
2275 return err;
2276
2277 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2278 dump_ctx->info->snd_portid,
2279 dump_ctx->info->snd_seq,
2280 &devlink_nl_family, NLM_F_MULTI,
2281 dump_ctx->cmd);
2282 if (!dump_ctx->hdr)
2283 goto nla_put_failure;
2284
2285 devlink = dump_ctx->info->user_ptr[0];
2286 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2287 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002288 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2289 DEVLINK_ATTR_DPIPE_ENTRIES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002290 if (!dump_ctx->nest)
2291 goto nla_put_failure;
2292 return 0;
2293
2294nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002295 nlmsg_free(dump_ctx->skb);
2296 return -EMSGSIZE;
2297}
2298EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2299
2300int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2301 struct devlink_dpipe_entry *entry)
2302{
2303 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2304}
2305EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2306
2307int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2308{
2309 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2310 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2311 return 0;
2312}
2313EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2314
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002315void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2316
2317{
2318 unsigned int value_count, value_index;
2319 struct devlink_dpipe_value *value;
2320
2321 value = entry->action_values;
2322 value_count = entry->action_values_count;
2323 for (value_index = 0; value_index < value_count; value_index++) {
2324 kfree(value[value_index].value);
2325 kfree(value[value_index].mask);
2326 }
2327
2328 value = entry->match_values;
2329 value_count = entry->match_values_count;
2330 for (value_index = 0; value_index < value_count; value_index++) {
2331 kfree(value[value_index].value);
2332 kfree(value[value_index].mask);
2333 }
2334}
2335EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2336
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002337static int devlink_dpipe_entries_fill(struct genl_info *info,
2338 enum devlink_command cmd, int flags,
2339 struct devlink_dpipe_table *table)
2340{
2341 struct devlink_dpipe_dump_ctx dump_ctx;
2342 struct nlmsghdr *nlh;
2343 int err;
2344
2345 dump_ctx.skb = NULL;
2346 dump_ctx.cmd = cmd;
2347 dump_ctx.info = info;
2348
2349 err = table->table_ops->entries_dump(table->priv,
2350 table->counters_enabled,
2351 &dump_ctx);
2352 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002353 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002354
2355send_done:
2356 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2357 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2358 if (!nlh) {
2359 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2360 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002361 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002362 goto send_done;
2363 }
2364 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002365}
2366
2367static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2368 struct genl_info *info)
2369{
2370 struct devlink *devlink = info->user_ptr[0];
2371 struct devlink_dpipe_table *table;
2372 const char *table_name;
2373
2374 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2375 return -EINVAL;
2376
2377 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2378 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302379 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002380 if (!table)
2381 return -EINVAL;
2382
2383 if (!table->table_ops->entries_dump)
2384 return -EINVAL;
2385
2386 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2387 0, table);
2388}
2389
2390static int devlink_dpipe_fields_put(struct sk_buff *skb,
2391 const struct devlink_dpipe_header *header)
2392{
2393 struct devlink_dpipe_field *field;
2394 struct nlattr *field_attr;
2395 int i;
2396
2397 for (i = 0; i < header->fields_count; i++) {
2398 field = &header->fields[i];
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002399 field_attr = nla_nest_start_noflag(skb,
2400 DEVLINK_ATTR_DPIPE_FIELD);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002401 if (!field_attr)
2402 return -EMSGSIZE;
2403 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2404 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2405 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2406 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2407 goto nla_put_failure;
2408 nla_nest_end(skb, field_attr);
2409 }
2410 return 0;
2411
2412nla_put_failure:
2413 nla_nest_cancel(skb, field_attr);
2414 return -EMSGSIZE;
2415}
2416
2417static int devlink_dpipe_header_put(struct sk_buff *skb,
2418 struct devlink_dpipe_header *header)
2419{
2420 struct nlattr *fields_attr, *header_attr;
2421 int err;
2422
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002423 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002424 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002425 return -EMSGSIZE;
2426
2427 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2428 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2429 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2430 goto nla_put_failure;
2431
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002432 fields_attr = nla_nest_start_noflag(skb,
2433 DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002434 if (!fields_attr)
2435 goto nla_put_failure;
2436
2437 err = devlink_dpipe_fields_put(skb, header);
2438 if (err) {
2439 nla_nest_cancel(skb, fields_attr);
2440 goto nla_put_failure;
2441 }
2442 nla_nest_end(skb, fields_attr);
2443 nla_nest_end(skb, header_attr);
2444 return 0;
2445
2446nla_put_failure:
2447 err = -EMSGSIZE;
2448 nla_nest_cancel(skb, header_attr);
2449 return err;
2450}
2451
2452static int devlink_dpipe_headers_fill(struct genl_info *info,
2453 enum devlink_command cmd, int flags,
2454 struct devlink_dpipe_headers *
2455 dpipe_headers)
2456{
2457 struct devlink *devlink = info->user_ptr[0];
2458 struct nlattr *headers_attr;
2459 struct sk_buff *skb = NULL;
2460 struct nlmsghdr *nlh;
2461 void *hdr;
2462 int i, j;
2463 int err;
2464
2465 i = 0;
2466start_again:
2467 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2468 if (err)
2469 return err;
2470
2471 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2472 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002473 if (!hdr) {
2474 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002475 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002476 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002477
2478 if (devlink_nl_put_handle(skb, devlink))
2479 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002480 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002481 if (!headers_attr)
2482 goto nla_put_failure;
2483
2484 j = 0;
2485 for (; i < dpipe_headers->headers_count; i++) {
2486 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2487 if (err) {
2488 if (!j)
2489 goto err_table_put;
2490 break;
2491 }
2492 j++;
2493 }
2494 nla_nest_end(skb, headers_attr);
2495 genlmsg_end(skb, hdr);
2496 if (i != dpipe_headers->headers_count)
2497 goto start_again;
2498
2499send_done:
2500 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2501 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2502 if (!nlh) {
2503 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2504 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002505 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002506 goto send_done;
2507 }
2508 return genlmsg_reply(skb, info);
2509
2510nla_put_failure:
2511 err = -EMSGSIZE;
2512err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002513 nlmsg_free(skb);
2514 return err;
2515}
2516
2517static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2518 struct genl_info *info)
2519{
2520 struct devlink *devlink = info->user_ptr[0];
2521
2522 if (!devlink->dpipe_headers)
2523 return -EOPNOTSUPP;
2524 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2525 0, devlink->dpipe_headers);
2526}
2527
2528static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2529 const char *table_name,
2530 bool enable)
2531{
2532 struct devlink_dpipe_table *table;
2533
2534 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302535 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002536 if (!table)
2537 return -EINVAL;
2538
2539 if (table->counter_control_extern)
2540 return -EOPNOTSUPP;
2541
2542 if (!(table->counters_enabled ^ enable))
2543 return 0;
2544
2545 table->counters_enabled = enable;
2546 if (table->table_ops->counters_set_update)
2547 table->table_ops->counters_set_update(table->priv, enable);
2548 return 0;
2549}
2550
2551static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2552 struct genl_info *info)
2553{
2554 struct devlink *devlink = info->user_ptr[0];
2555 const char *table_name;
2556 bool counters_enable;
2557
2558 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2559 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2560 return -EINVAL;
2561
2562 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2563 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2564
2565 return devlink_dpipe_table_counters_set(devlink, table_name,
2566 counters_enable);
2567}
2568
Wei Yongjun43dd7512018-01-17 03:27:42 +00002569static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002570devlink_resource_find(struct devlink *devlink,
2571 struct devlink_resource *resource, u64 resource_id)
2572{
2573 struct list_head *resource_list;
2574
2575 if (resource)
2576 resource_list = &resource->resource_list;
2577 else
2578 resource_list = &devlink->resource_list;
2579
2580 list_for_each_entry(resource, resource_list, list) {
2581 struct devlink_resource *child_resource;
2582
2583 if (resource->id == resource_id)
2584 return resource;
2585
2586 child_resource = devlink_resource_find(devlink, resource,
2587 resource_id);
2588 if (child_resource)
2589 return child_resource;
2590 }
2591 return NULL;
2592}
2593
Wei Yongjun43dd7512018-01-17 03:27:42 +00002594static void
2595devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002596{
2597 struct devlink_resource *child_resource;
2598 bool size_valid = true;
2599 u64 parts_size = 0;
2600
2601 if (list_empty(&resource->resource_list))
2602 goto out;
2603
2604 list_for_each_entry(child_resource, &resource->resource_list, list)
2605 parts_size += child_resource->size_new;
2606
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002607 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002608 size_valid = false;
2609out:
2610 resource->size_valid = size_valid;
2611}
2612
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002613static int
2614devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2615 struct netlink_ext_ack *extack)
2616{
2617 u64 reminder;
2618 int err = 0;
2619
David S. Miller0f3e9c92018-03-06 00:53:44 -05002620 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002621 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2622 err = -EINVAL;
2623 }
2624
David S. Miller0f3e9c92018-03-06 00:53:44 -05002625 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002626 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2627 err = -EINVAL;
2628 }
2629
David S. Miller0f3e9c92018-03-06 00:53:44 -05002630 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002631 if (reminder) {
2632 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2633 err = -EINVAL;
2634 }
2635
2636 return err;
2637}
2638
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002639static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2640 struct genl_info *info)
2641{
2642 struct devlink *devlink = info->user_ptr[0];
2643 struct devlink_resource *resource;
2644 u64 resource_id;
2645 u64 size;
2646 int err;
2647
2648 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2649 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2650 return -EINVAL;
2651 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2652
2653 resource = devlink_resource_find(devlink, NULL, resource_id);
2654 if (!resource)
2655 return -EINVAL;
2656
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002657 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002658 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002659 if (err)
2660 return err;
2661
2662 resource->size_new = size;
2663 devlink_resource_validate_children(resource);
2664 if (resource->parent)
2665 devlink_resource_validate_children(resource->parent);
2666 return 0;
2667}
2668
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002669static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002670devlink_resource_size_params_put(struct devlink_resource *resource,
2671 struct sk_buff *skb)
2672{
2673 struct devlink_resource_size_params *size_params;
2674
Jiri Pirko77d27092018-02-28 13:12:09 +01002675 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002676 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2677 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2678 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2679 size_params->size_max, DEVLINK_ATTR_PAD) ||
2680 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2681 size_params->size_min, DEVLINK_ATTR_PAD) ||
2682 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2683 return -EMSGSIZE;
2684 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002685}
2686
Jiri Pirkofc56be42018-04-05 22:13:21 +02002687static int devlink_resource_occ_put(struct devlink_resource *resource,
2688 struct sk_buff *skb)
2689{
2690 if (!resource->occ_get)
2691 return 0;
2692 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2693 resource->occ_get(resource->occ_get_priv),
2694 DEVLINK_ATTR_PAD);
2695}
2696
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002697static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2698 struct devlink_resource *resource)
2699{
2700 struct devlink_resource *child_resource;
2701 struct nlattr *child_resource_attr;
2702 struct nlattr *resource_attr;
2703
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002704 resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002705 if (!resource_attr)
2706 return -EMSGSIZE;
2707
2708 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2709 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2710 DEVLINK_ATTR_PAD) ||
2711 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2712 DEVLINK_ATTR_PAD))
2713 goto nla_put_failure;
2714 if (resource->size != resource->size_new)
2715 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2716 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002717 if (devlink_resource_occ_put(resource, skb))
2718 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002719 if (devlink_resource_size_params_put(resource, skb))
2720 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002721 if (list_empty(&resource->resource_list))
2722 goto out;
2723
2724 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2725 resource->size_valid))
2726 goto nla_put_failure;
2727
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002728 child_resource_attr = nla_nest_start_noflag(skb,
2729 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002730 if (!child_resource_attr)
2731 goto nla_put_failure;
2732
2733 list_for_each_entry(child_resource, &resource->resource_list, list) {
2734 if (devlink_resource_put(devlink, skb, child_resource))
2735 goto resource_put_failure;
2736 }
2737
2738 nla_nest_end(skb, child_resource_attr);
2739out:
2740 nla_nest_end(skb, resource_attr);
2741 return 0;
2742
2743resource_put_failure:
2744 nla_nest_cancel(skb, child_resource_attr);
2745nla_put_failure:
2746 nla_nest_cancel(skb, resource_attr);
2747 return -EMSGSIZE;
2748}
2749
2750static int devlink_resource_fill(struct genl_info *info,
2751 enum devlink_command cmd, int flags)
2752{
2753 struct devlink *devlink = info->user_ptr[0];
2754 struct devlink_resource *resource;
2755 struct nlattr *resources_attr;
2756 struct sk_buff *skb = NULL;
2757 struct nlmsghdr *nlh;
2758 bool incomplete;
2759 void *hdr;
2760 int i;
2761 int err;
2762
2763 resource = list_first_entry(&devlink->resource_list,
2764 struct devlink_resource, list);
2765start_again:
2766 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2767 if (err)
2768 return err;
2769
2770 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2771 &devlink_nl_family, NLM_F_MULTI, cmd);
2772 if (!hdr) {
2773 nlmsg_free(skb);
2774 return -EMSGSIZE;
2775 }
2776
2777 if (devlink_nl_put_handle(skb, devlink))
2778 goto nla_put_failure;
2779
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002780 resources_attr = nla_nest_start_noflag(skb,
2781 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002782 if (!resources_attr)
2783 goto nla_put_failure;
2784
2785 incomplete = false;
2786 i = 0;
2787 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2788 err = devlink_resource_put(devlink, skb, resource);
2789 if (err) {
2790 if (!i)
2791 goto err_resource_put;
2792 incomplete = true;
2793 break;
2794 }
2795 i++;
2796 }
2797 nla_nest_end(skb, resources_attr);
2798 genlmsg_end(skb, hdr);
2799 if (incomplete)
2800 goto start_again;
2801send_done:
2802 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2803 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2804 if (!nlh) {
2805 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2806 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002807 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002808 goto send_done;
2809 }
2810 return genlmsg_reply(skb, info);
2811
2812nla_put_failure:
2813 err = -EMSGSIZE;
2814err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002815 nlmsg_free(skb);
2816 return err;
2817}
2818
2819static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2820 struct genl_info *info)
2821{
2822 struct devlink *devlink = info->user_ptr[0];
2823
2824 if (list_empty(&devlink->resource_list))
2825 return -EOPNOTSUPP;
2826
2827 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2828}
2829
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002830static int
2831devlink_resources_validate(struct devlink *devlink,
2832 struct devlink_resource *resource,
2833 struct genl_info *info)
2834{
2835 struct list_head *resource_list;
2836 int err = 0;
2837
2838 if (resource)
2839 resource_list = &resource->resource_list;
2840 else
2841 resource_list = &devlink->resource_list;
2842
2843 list_for_each_entry(resource, resource_list, list) {
2844 if (!resource->size_valid)
2845 return -EINVAL;
2846 err = devlink_resources_validate(devlink, resource, info);
2847 if (err)
2848 return err;
2849 }
2850 return err;
2851}
2852
Jiri Pirko070c63f2019-10-03 11:49:39 +02002853static struct net *devlink_netns_get(struct sk_buff *skb,
2854 struct genl_info *info)
2855{
2856 struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID];
2857 struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD];
2858 struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID];
2859 struct net *net;
2860
2861 if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) {
Jiri Pirko054eae82020-03-28 19:25:29 +01002862 NL_SET_ERR_MSG_MOD(info->extack, "multiple netns identifying attributes specified");
Jiri Pirko070c63f2019-10-03 11:49:39 +02002863 return ERR_PTR(-EINVAL);
2864 }
2865
2866 if (netns_pid_attr) {
2867 net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr));
2868 } else if (netns_fd_attr) {
2869 net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr));
2870 } else if (netns_id_attr) {
2871 net = get_net_ns_by_id(sock_net(skb->sk),
2872 nla_get_u32(netns_id_attr));
2873 if (!net)
2874 net = ERR_PTR(-EINVAL);
2875 } else {
2876 WARN_ON(1);
2877 net = ERR_PTR(-EINVAL);
2878 }
2879 if (IS_ERR(net)) {
Jiri Pirko054eae82020-03-28 19:25:29 +01002880 NL_SET_ERR_MSG_MOD(info->extack, "Unknown network namespace");
Jiri Pirko070c63f2019-10-03 11:49:39 +02002881 return ERR_PTR(-EINVAL);
2882 }
2883 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
2884 put_net(net);
2885 return ERR_PTR(-EPERM);
2886 }
2887 return net;
2888}
2889
2890static void devlink_param_notify(struct devlink *devlink,
2891 unsigned int port_index,
2892 struct devlink_param_item *param_item,
2893 enum devlink_command cmd);
2894
2895static void devlink_reload_netns_change(struct devlink *devlink,
2896 struct net *dest_net)
2897{
2898 struct devlink_param_item *param_item;
2899
2900 /* Userspace needs to be notified about devlink objects
2901 * removed from original and entering new network namespace.
2902 * The rest of the devlink objects are re-created during
2903 * reload process so the notifications are generated separatelly.
2904 */
2905
2906 list_for_each_entry(param_item, &devlink->param_list, list)
2907 devlink_param_notify(devlink, 0, param_item,
2908 DEVLINK_CMD_PARAM_DEL);
2909 devlink_notify(devlink, DEVLINK_CMD_DEL);
2910
Jiri Pirko8273fd82019-10-05 08:10:31 +02002911 __devlink_net_set(devlink, dest_net);
Jiri Pirko070c63f2019-10-03 11:49:39 +02002912
2913 devlink_notify(devlink, DEVLINK_CMD_NEW);
2914 list_for_each_entry(param_item, &devlink->param_list, list)
2915 devlink_param_notify(devlink, 0, param_item,
2916 DEVLINK_CMD_PARAM_NEW);
2917}
2918
Jiri Pirko97691062019-09-12 10:49:45 +02002919static bool devlink_reload_supported(struct devlink *devlink)
2920{
2921 return devlink->ops->reload_down && devlink->ops->reload_up;
2922}
2923
Jiri Pirko2670ac22019-09-12 10:49:46 +02002924static void devlink_reload_failed_set(struct devlink *devlink,
2925 bool reload_failed)
2926{
2927 if (devlink->reload_failed == reload_failed)
2928 return;
2929 devlink->reload_failed = reload_failed;
2930 devlink_notify(devlink, DEVLINK_CMD_NEW);
2931}
2932
2933bool devlink_is_reload_failed(const struct devlink *devlink)
2934{
2935 return devlink->reload_failed;
2936}
2937EXPORT_SYMBOL_GPL(devlink_is_reload_failed);
2938
Jiri Pirko070c63f2019-10-03 11:49:39 +02002939static int devlink_reload(struct devlink *devlink, struct net *dest_net,
2940 struct netlink_ext_ack *extack)
2941{
2942 int err;
2943
Jiri Pirkoa0c76342019-11-08 21:42:43 +01002944 if (!devlink->reload_enabled)
2945 return -EOPNOTSUPP;
2946
Jiri Pirko070c63f2019-10-03 11:49:39 +02002947 err = devlink->ops->reload_down(devlink, !!dest_net, extack);
2948 if (err)
2949 return err;
2950
2951 if (dest_net && !net_eq(dest_net, devlink_net(devlink)))
2952 devlink_reload_netns_change(devlink, dest_net);
2953
2954 err = devlink->ops->reload_up(devlink, extack);
2955 devlink_reload_failed_set(devlink, !!err);
2956 return err;
2957}
2958
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002959static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2960{
2961 struct devlink *devlink = info->user_ptr[0];
Jiri Pirko070c63f2019-10-03 11:49:39 +02002962 struct net *dest_net = NULL;
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002963 int err;
2964
Jiri Pirko5a508a22019-11-09 11:29:46 +01002965 if (!devlink_reload_supported(devlink) || !devlink->reload_enabled)
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002966 return -EOPNOTSUPP;
2967
2968 err = devlink_resources_validate(devlink, NULL, info);
2969 if (err) {
2970 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2971 return err;
2972 }
Jiri Pirko070c63f2019-10-03 11:49:39 +02002973
2974 if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
2975 info->attrs[DEVLINK_ATTR_NETNS_FD] ||
2976 info->attrs[DEVLINK_ATTR_NETNS_ID]) {
2977 dest_net = devlink_netns_get(skb, info);
2978 if (IS_ERR(dest_net))
2979 return PTR_ERR(dest_net);
2980 }
2981
2982 err = devlink_reload(devlink, dest_net, info->extack);
2983
2984 if (dest_net)
2985 put_net(dest_net);
2986
Jiri Pirko2670ac22019-09-12 10:49:46 +02002987 return err;
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002988}
2989
Jiri Pirko191ed202019-06-04 15:40:40 +02002990static int devlink_nl_flash_update_fill(struct sk_buff *msg,
2991 struct devlink *devlink,
2992 enum devlink_command cmd,
2993 const char *status_msg,
2994 const char *component,
2995 unsigned long done, unsigned long total)
2996{
2997 void *hdr;
2998
2999 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3000 if (!hdr)
3001 return -EMSGSIZE;
3002
3003 if (devlink_nl_put_handle(msg, devlink))
3004 goto nla_put_failure;
3005
3006 if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
3007 goto out;
3008
3009 if (status_msg &&
3010 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
3011 status_msg))
3012 goto nla_put_failure;
3013 if (component &&
3014 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
3015 component))
3016 goto nla_put_failure;
3017 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
3018 done, DEVLINK_ATTR_PAD))
3019 goto nla_put_failure;
3020 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
3021 total, DEVLINK_ATTR_PAD))
3022 goto nla_put_failure;
3023
3024out:
3025 genlmsg_end(msg, hdr);
3026 return 0;
3027
3028nla_put_failure:
3029 genlmsg_cancel(msg, hdr);
3030 return -EMSGSIZE;
3031}
3032
3033static void __devlink_flash_update_notify(struct devlink *devlink,
3034 enum devlink_command cmd,
3035 const char *status_msg,
3036 const char *component,
3037 unsigned long done,
3038 unsigned long total)
3039{
3040 struct sk_buff *msg;
3041 int err;
3042
3043 WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
3044 cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
3045 cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
3046
3047 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3048 if (!msg)
3049 return;
3050
3051 err = devlink_nl_flash_update_fill(msg, devlink, cmd, status_msg,
3052 component, done, total);
3053 if (err)
3054 goto out_free_msg;
3055
3056 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3057 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3058 return;
3059
3060out_free_msg:
3061 nlmsg_free(msg);
3062}
3063
3064void devlink_flash_update_begin_notify(struct devlink *devlink)
3065{
3066 __devlink_flash_update_notify(devlink,
3067 DEVLINK_CMD_FLASH_UPDATE,
3068 NULL, NULL, 0, 0);
3069}
3070EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
3071
3072void devlink_flash_update_end_notify(struct devlink *devlink)
3073{
3074 __devlink_flash_update_notify(devlink,
3075 DEVLINK_CMD_FLASH_UPDATE_END,
3076 NULL, NULL, 0, 0);
3077}
3078EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
3079
3080void devlink_flash_update_status_notify(struct devlink *devlink,
3081 const char *status_msg,
3082 const char *component,
3083 unsigned long done,
3084 unsigned long total)
3085{
3086 __devlink_flash_update_notify(devlink,
3087 DEVLINK_CMD_FLASH_UPDATE_STATUS,
3088 status_msg, component, done, total);
3089}
3090EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
3091
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003092static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
3093 struct genl_info *info)
3094{
3095 struct devlink *devlink = info->user_ptr[0];
3096 const char *file_name, *component;
3097 struct nlattr *nla_component;
3098
3099 if (!devlink->ops->flash_update)
3100 return -EOPNOTSUPP;
3101
3102 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
3103 return -EINVAL;
3104 file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
3105
3106 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
3107 component = nla_component ? nla_data(nla_component) : NULL;
3108
3109 return devlink->ops->flash_update(devlink, file_name, component,
3110 info->extack);
3111}
3112
Moshe Shemesh036467c2018-07-04 14:30:33 +03003113static const struct devlink_param devlink_param_generic[] = {
3114 {
3115 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
3116 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
3117 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
3118 },
3119 {
3120 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
3121 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
3122 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
3123 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03003124 {
3125 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
3126 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
3127 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
3128 },
Alex Veskerf6a698852018-07-12 15:13:17 +03003129 {
3130 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
3131 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
3132 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
3133 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05303134 {
3135 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
3136 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
3137 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
3138 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05303139 {
3140 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
3141 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
3142 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
3143 },
Vasundhara Volam16511782018-10-04 11:13:46 +05303144 {
3145 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
3146 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
3147 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
3148 },
Shalom Toledo846e9802018-12-03 07:58:59 +00003149 {
3150 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
3151 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
3152 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
3153 },
Dirk van der Merwe5bbd21d2019-09-09 00:54:18 +01003154 {
3155 .id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
3156 .name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
3157 .type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
3158 },
Michael Guralnik6c7295e2019-11-08 23:45:20 +00003159 {
3160 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
3161 .name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
3162 .type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
3163 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03003164};
Moshe Shemesheabaef12018-07-04 14:30:28 +03003165
3166static int devlink_param_generic_verify(const struct devlink_param *param)
3167{
3168 /* verify it match generic parameter by id and name */
3169 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
3170 return -EINVAL;
3171 if (strcmp(param->name, devlink_param_generic[param->id].name))
3172 return -ENOENT;
3173
3174 WARN_ON(param->type != devlink_param_generic[param->id].type);
3175
3176 return 0;
3177}
3178
3179static int devlink_param_driver_verify(const struct devlink_param *param)
3180{
3181 int i;
3182
3183 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
3184 return -EINVAL;
3185 /* verify no such name in generic params */
3186 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
3187 if (!strcmp(param->name, devlink_param_generic[i].name))
3188 return -EEXIST;
3189
3190 return 0;
3191}
3192
3193static struct devlink_param_item *
3194devlink_param_find_by_name(struct list_head *param_list,
3195 const char *param_name)
3196{
3197 struct devlink_param_item *param_item;
3198
3199 list_for_each_entry(param_item, param_list, list)
3200 if (!strcmp(param_item->param->name, param_name))
3201 return param_item;
3202 return NULL;
3203}
3204
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03003205static struct devlink_param_item *
3206devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
3207{
3208 struct devlink_param_item *param_item;
3209
3210 list_for_each_entry(param_item, param_list, list)
3211 if (param_item->param->id == param_id)
3212 return param_item;
3213 return NULL;
3214}
3215
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003216static bool
3217devlink_param_cmode_is_supported(const struct devlink_param *param,
3218 enum devlink_param_cmode cmode)
3219{
3220 return test_bit(cmode, &param->supported_cmodes);
3221}
3222
3223static int devlink_param_get(struct devlink *devlink,
3224 const struct devlink_param *param,
3225 struct devlink_param_gset_ctx *ctx)
3226{
3227 if (!param->get)
3228 return -EOPNOTSUPP;
3229 return param->get(devlink, param->id, ctx);
3230}
3231
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003232static int devlink_param_set(struct devlink *devlink,
3233 const struct devlink_param *param,
3234 struct devlink_param_gset_ctx *ctx)
3235{
3236 if (!param->set)
3237 return -EOPNOTSUPP;
3238 return param->set(devlink, param->id, ctx);
3239}
3240
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003241static int
3242devlink_param_type_to_nla_type(enum devlink_param_type param_type)
3243{
3244 switch (param_type) {
3245 case DEVLINK_PARAM_TYPE_U8:
3246 return NLA_U8;
3247 case DEVLINK_PARAM_TYPE_U16:
3248 return NLA_U16;
3249 case DEVLINK_PARAM_TYPE_U32:
3250 return NLA_U32;
3251 case DEVLINK_PARAM_TYPE_STRING:
3252 return NLA_STRING;
3253 case DEVLINK_PARAM_TYPE_BOOL:
3254 return NLA_FLAG;
3255 default:
3256 return -EINVAL;
3257 }
3258}
3259
3260static int
3261devlink_nl_param_value_fill_one(struct sk_buff *msg,
3262 enum devlink_param_type type,
3263 enum devlink_param_cmode cmode,
3264 union devlink_param_value val)
3265{
3266 struct nlattr *param_value_attr;
3267
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003268 param_value_attr = nla_nest_start_noflag(msg,
3269 DEVLINK_ATTR_PARAM_VALUE);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003270 if (!param_value_attr)
3271 goto nla_put_failure;
3272
3273 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
3274 goto value_nest_cancel;
3275
3276 switch (type) {
3277 case DEVLINK_PARAM_TYPE_U8:
3278 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
3279 goto value_nest_cancel;
3280 break;
3281 case DEVLINK_PARAM_TYPE_U16:
3282 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
3283 goto value_nest_cancel;
3284 break;
3285 case DEVLINK_PARAM_TYPE_U32:
3286 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
3287 goto value_nest_cancel;
3288 break;
3289 case DEVLINK_PARAM_TYPE_STRING:
3290 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
3291 val.vstr))
3292 goto value_nest_cancel;
3293 break;
3294 case DEVLINK_PARAM_TYPE_BOOL:
3295 if (val.vbool &&
3296 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
3297 goto value_nest_cancel;
3298 break;
3299 }
3300
3301 nla_nest_end(msg, param_value_attr);
3302 return 0;
3303
3304value_nest_cancel:
3305 nla_nest_cancel(msg, param_value_attr);
3306nla_put_failure:
3307 return -EMSGSIZE;
3308}
3309
3310static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303311 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003312 struct devlink_param_item *param_item,
3313 enum devlink_command cmd,
3314 u32 portid, u32 seq, int flags)
3315{
3316 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003317 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003318 const struct devlink_param *param = param_item->param;
3319 struct devlink_param_gset_ctx ctx;
3320 struct nlattr *param_values_list;
3321 struct nlattr *param_attr;
3322 int nla_type;
3323 void *hdr;
3324 int err;
3325 int i;
3326
3327 /* Get value from driver part to driverinit configuration mode */
3328 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3329 if (!devlink_param_cmode_is_supported(param, i))
3330 continue;
3331 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3332 if (!param_item->driverinit_value_valid)
3333 return -EOPNOTSUPP;
3334 param_value[i] = param_item->driverinit_value;
3335 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003336 if (!param_item->published)
3337 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003338 ctx.cmode = i;
3339 err = devlink_param_get(devlink, param, &ctx);
3340 if (err)
3341 return err;
3342 param_value[i] = ctx.val;
3343 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003344 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003345 }
3346
3347 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3348 if (!hdr)
3349 return -EMSGSIZE;
3350
3351 if (devlink_nl_put_handle(msg, devlink))
3352 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303353
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303354 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3355 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3356 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303357 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3358 goto genlmsg_cancel;
3359
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003360 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003361 if (!param_attr)
3362 goto genlmsg_cancel;
3363 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3364 goto param_nest_cancel;
3365 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3366 goto param_nest_cancel;
3367
3368 nla_type = devlink_param_type_to_nla_type(param->type);
3369 if (nla_type < 0)
3370 goto param_nest_cancel;
3371 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3372 goto param_nest_cancel;
3373
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003374 param_values_list = nla_nest_start_noflag(msg,
3375 DEVLINK_ATTR_PARAM_VALUES_LIST);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003376 if (!param_values_list)
3377 goto param_nest_cancel;
3378
3379 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003380 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003381 continue;
3382 err = devlink_nl_param_value_fill_one(msg, param->type,
3383 i, param_value[i]);
3384 if (err)
3385 goto values_list_nest_cancel;
3386 }
3387
3388 nla_nest_end(msg, param_values_list);
3389 nla_nest_end(msg, param_attr);
3390 genlmsg_end(msg, hdr);
3391 return 0;
3392
3393values_list_nest_cancel:
3394 nla_nest_end(msg, param_values_list);
3395param_nest_cancel:
3396 nla_nest_cancel(msg, param_attr);
3397genlmsg_cancel:
3398 genlmsg_cancel(msg, hdr);
3399 return -EMSGSIZE;
3400}
3401
Moshe Shemeshea601e12018-07-04 14:30:32 +03003402static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303403 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03003404 struct devlink_param_item *param_item,
3405 enum devlink_command cmd)
3406{
3407 struct sk_buff *msg;
3408 int err;
3409
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303410 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3411 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3412 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003413
3414 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3415 if (!msg)
3416 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303417 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3418 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003419 if (err) {
3420 nlmsg_free(msg);
3421 return;
3422 }
3423
3424 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3425 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3426}
3427
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003428static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3429 struct netlink_callback *cb)
3430{
3431 struct devlink_param_item *param_item;
3432 struct devlink *devlink;
3433 int start = cb->args[0];
3434 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003435 int err = 0;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003436
3437 mutex_lock(&devlink_mutex);
3438 list_for_each_entry(devlink, &devlink_list, list) {
3439 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3440 continue;
3441 mutex_lock(&devlink->lock);
3442 list_for_each_entry(param_item, &devlink->param_list, list) {
3443 if (idx < start) {
3444 idx++;
3445 continue;
3446 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303447 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003448 DEVLINK_CMD_PARAM_GET,
3449 NETLINK_CB(cb->skb).portid,
3450 cb->nlh->nlmsg_seq,
3451 NLM_F_MULTI);
Vasundhara Volam93c2fcb2019-09-30 11:52:21 +05303452 if (err && err != -EOPNOTSUPP) {
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003453 mutex_unlock(&devlink->lock);
3454 goto out;
3455 }
3456 idx++;
3457 }
3458 mutex_unlock(&devlink->lock);
3459 }
3460out:
3461 mutex_unlock(&devlink_mutex);
3462
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003463 if (err != -EMSGSIZE)
3464 return err;
3465
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003466 cb->args[0] = idx;
3467 return msg->len;
3468}
3469
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003470static int
3471devlink_param_type_get_from_info(struct genl_info *info,
3472 enum devlink_param_type *param_type)
3473{
3474 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3475 return -EINVAL;
3476
3477 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3478 case NLA_U8:
3479 *param_type = DEVLINK_PARAM_TYPE_U8;
3480 break;
3481 case NLA_U16:
3482 *param_type = DEVLINK_PARAM_TYPE_U16;
3483 break;
3484 case NLA_U32:
3485 *param_type = DEVLINK_PARAM_TYPE_U32;
3486 break;
3487 case NLA_STRING:
3488 *param_type = DEVLINK_PARAM_TYPE_STRING;
3489 break;
3490 case NLA_FLAG:
3491 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3492 break;
3493 default:
3494 return -EINVAL;
3495 }
3496
3497 return 0;
3498}
3499
3500static int
3501devlink_param_value_get_from_info(const struct devlink_param *param,
3502 struct genl_info *info,
3503 union devlink_param_value *value)
3504{
Jakub Kicinski87509392020-03-02 21:05:11 -08003505 struct nlattr *param_data;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003506 int len;
3507
Jakub Kicinski87509392020-03-02 21:05:11 -08003508 param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
3509
3510 if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003511 return -EINVAL;
3512
3513 switch (param->type) {
3514 case DEVLINK_PARAM_TYPE_U8:
Jakub Kicinski87509392020-03-02 21:05:11 -08003515 if (nla_len(param_data) != sizeof(u8))
3516 return -EINVAL;
3517 value->vu8 = nla_get_u8(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003518 break;
3519 case DEVLINK_PARAM_TYPE_U16:
Jakub Kicinski87509392020-03-02 21:05:11 -08003520 if (nla_len(param_data) != sizeof(u16))
3521 return -EINVAL;
3522 value->vu16 = nla_get_u16(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003523 break;
3524 case DEVLINK_PARAM_TYPE_U32:
Jakub Kicinski87509392020-03-02 21:05:11 -08003525 if (nla_len(param_data) != sizeof(u32))
3526 return -EINVAL;
3527 value->vu32 = nla_get_u32(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003528 break;
3529 case DEVLINK_PARAM_TYPE_STRING:
Jakub Kicinski87509392020-03-02 21:05:11 -08003530 len = strnlen(nla_data(param_data), nla_len(param_data));
3531 if (len == nla_len(param_data) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003532 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003533 return -EINVAL;
Jakub Kicinski87509392020-03-02 21:05:11 -08003534 strcpy(value->vstr, nla_data(param_data));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003535 break;
3536 case DEVLINK_PARAM_TYPE_BOOL:
Jakub Kicinski87509392020-03-02 21:05:11 -08003537 if (param_data && nla_len(param_data))
3538 return -EINVAL;
3539 value->vbool = nla_get_flag(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003540 break;
3541 }
3542 return 0;
3543}
3544
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003545static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303546devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003547 struct genl_info *info)
3548{
3549 char *param_name;
3550
3551 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3552 return NULL;
3553
3554 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303555 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003556}
3557
3558static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3559 struct genl_info *info)
3560{
3561 struct devlink *devlink = info->user_ptr[0];
3562 struct devlink_param_item *param_item;
3563 struct sk_buff *msg;
3564 int err;
3565
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303566 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003567 if (!param_item)
3568 return -EINVAL;
3569
3570 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3571 if (!msg)
3572 return -ENOMEM;
3573
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303574 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003575 DEVLINK_CMD_PARAM_GET,
3576 info->snd_portid, info->snd_seq, 0);
3577 if (err) {
3578 nlmsg_free(msg);
3579 return err;
3580 }
3581
3582 return genlmsg_reply(msg, info);
3583}
3584
Vasundhara Volam9c548732019-01-28 18:00:22 +05303585static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303586 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303587 struct list_head *param_list,
3588 struct genl_info *info,
3589 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003590{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003591 enum devlink_param_type param_type;
3592 struct devlink_param_gset_ctx ctx;
3593 enum devlink_param_cmode cmode;
3594 struct devlink_param_item *param_item;
3595 const struct devlink_param *param;
3596 union devlink_param_value value;
3597 int err = 0;
3598
Vasundhara Volam9c548732019-01-28 18:00:22 +05303599 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003600 if (!param_item)
3601 return -EINVAL;
3602 param = param_item->param;
3603 err = devlink_param_type_get_from_info(info, &param_type);
3604 if (err)
3605 return err;
3606 if (param_type != param->type)
3607 return -EINVAL;
3608 err = devlink_param_value_get_from_info(param, info, &value);
3609 if (err)
3610 return err;
3611 if (param->validate) {
3612 err = param->validate(devlink, param->id, value, info->extack);
3613 if (err)
3614 return err;
3615 }
3616
3617 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3618 return -EINVAL;
3619 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3620 if (!devlink_param_cmode_is_supported(param, cmode))
3621 return -EOPNOTSUPP;
3622
3623 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003624 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3625 strcpy(param_item->driverinit_value.vstr, value.vstr);
3626 else
3627 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003628 param_item->driverinit_value_valid = true;
3629 } else {
3630 if (!param->set)
3631 return -EOPNOTSUPP;
3632 ctx.val = value;
3633 ctx.cmode = cmode;
3634 err = devlink_param_set(devlink, param, &ctx);
3635 if (err)
3636 return err;
3637 }
3638
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303639 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003640 return 0;
3641}
3642
Vasundhara Volam9c548732019-01-28 18:00:22 +05303643static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3644 struct genl_info *info)
3645{
3646 struct devlink *devlink = info->user_ptr[0];
3647
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303648 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303649 info, DEVLINK_CMD_PARAM_NEW);
3650}
3651
Moshe Shemesheabaef12018-07-04 14:30:28 +03003652static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303653 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303654 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303655 const struct devlink_param *param,
3656 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003657{
3658 struct devlink_param_item *param_item;
3659
Vasundhara Volam39e61602019-01-28 18:00:20 +05303660 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03003661 return -EEXIST;
3662
3663 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3664 WARN_ON(param->get || param->set);
3665 else
3666 WARN_ON(!param->get || !param->set);
3667
3668 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3669 if (!param_item)
3670 return -ENOMEM;
3671 param_item->param = param;
3672
Vasundhara Volam39e61602019-01-28 18:00:20 +05303673 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303674 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003675 return 0;
3676}
3677
3678static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303679 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303680 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303681 const struct devlink_param *param,
3682 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003683{
3684 struct devlink_param_item *param_item;
3685
Vasundhara Volam39e61602019-01-28 18:00:20 +05303686 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003687 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303688 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003689 list_del(&param_item->list);
3690 kfree(param_item);
3691}
3692
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303693static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3694 struct netlink_callback *cb)
3695{
3696 struct devlink_param_item *param_item;
3697 struct devlink_port *devlink_port;
3698 struct devlink *devlink;
3699 int start = cb->args[0];
3700 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003701 int err = 0;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303702
3703 mutex_lock(&devlink_mutex);
3704 list_for_each_entry(devlink, &devlink_list, list) {
3705 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3706 continue;
3707 mutex_lock(&devlink->lock);
3708 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3709 list_for_each_entry(param_item,
3710 &devlink_port->param_list, list) {
3711 if (idx < start) {
3712 idx++;
3713 continue;
3714 }
3715 err = devlink_nl_param_fill(msg,
3716 devlink_port->devlink,
3717 devlink_port->index, param_item,
3718 DEVLINK_CMD_PORT_PARAM_GET,
3719 NETLINK_CB(cb->skb).portid,
3720 cb->nlh->nlmsg_seq,
3721 NLM_F_MULTI);
Vasundhara Volam93c2fcb2019-09-30 11:52:21 +05303722 if (err && err != -EOPNOTSUPP) {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303723 mutex_unlock(&devlink->lock);
3724 goto out;
3725 }
3726 idx++;
3727 }
3728 }
3729 mutex_unlock(&devlink->lock);
3730 }
3731out:
3732 mutex_unlock(&devlink_mutex);
3733
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003734 if (err != -EMSGSIZE)
3735 return err;
3736
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303737 cb->args[0] = idx;
3738 return msg->len;
3739}
3740
3741static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3742 struct genl_info *info)
3743{
3744 struct devlink_port *devlink_port = info->user_ptr[0];
3745 struct devlink_param_item *param_item;
3746 struct sk_buff *msg;
3747 int err;
3748
3749 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3750 info);
3751 if (!param_item)
3752 return -EINVAL;
3753
3754 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3755 if (!msg)
3756 return -ENOMEM;
3757
3758 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3759 devlink_port->index, param_item,
3760 DEVLINK_CMD_PORT_PARAM_GET,
3761 info->snd_portid, info->snd_seq, 0);
3762 if (err) {
3763 nlmsg_free(msg);
3764 return err;
3765 }
3766
3767 return genlmsg_reply(msg, info);
3768}
3769
Vasundhara Volam9c548732019-01-28 18:00:22 +05303770static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3771 struct genl_info *info)
3772{
3773 struct devlink_port *devlink_port = info->user_ptr[0];
3774
3775 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303776 devlink_port->index,
3777 &devlink_port->param_list, info,
3778 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05303779}
3780
Alex Veskera006d462018-07-12 15:13:12 +03003781static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3782 struct devlink *devlink,
3783 struct devlink_snapshot *snapshot)
3784{
3785 struct nlattr *snap_attr;
3786 int err;
3787
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003788 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
Alex Veskera006d462018-07-12 15:13:12 +03003789 if (!snap_attr)
3790 return -EINVAL;
3791
3792 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3793 if (err)
3794 goto nla_put_failure;
3795
3796 nla_nest_end(msg, snap_attr);
3797 return 0;
3798
3799nla_put_failure:
3800 nla_nest_cancel(msg, snap_attr);
3801 return err;
3802}
3803
3804static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3805 struct devlink *devlink,
3806 struct devlink_region *region)
3807{
3808 struct devlink_snapshot *snapshot;
3809 struct nlattr *snapshots_attr;
3810 int err;
3811
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003812 snapshots_attr = nla_nest_start_noflag(msg,
3813 DEVLINK_ATTR_REGION_SNAPSHOTS);
Alex Veskera006d462018-07-12 15:13:12 +03003814 if (!snapshots_attr)
3815 return -EINVAL;
3816
3817 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3818 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3819 if (err)
3820 goto nla_put_failure;
3821 }
3822
3823 nla_nest_end(msg, snapshots_attr);
3824 return 0;
3825
3826nla_put_failure:
3827 nla_nest_cancel(msg, snapshots_attr);
3828 return err;
3829}
3830
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003831static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3832 enum devlink_command cmd, u32 portid,
3833 u32 seq, int flags,
3834 struct devlink_region *region)
3835{
3836 void *hdr;
3837 int err;
3838
3839 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3840 if (!hdr)
3841 return -EMSGSIZE;
3842
3843 err = devlink_nl_put_handle(msg, devlink);
3844 if (err)
3845 goto nla_put_failure;
3846
Jacob Kellere8937682020-03-26 11:37:08 -07003847 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003848 if (err)
3849 goto nla_put_failure;
3850
3851 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3852 region->size,
3853 DEVLINK_ATTR_PAD);
3854 if (err)
3855 goto nla_put_failure;
3856
Alex Veskera006d462018-07-12 15:13:12 +03003857 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3858 if (err)
3859 goto nla_put_failure;
3860
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003861 genlmsg_end(msg, hdr);
3862 return 0;
3863
3864nla_put_failure:
3865 genlmsg_cancel(msg, hdr);
3866 return err;
3867}
3868
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003869static struct sk_buff *
3870devlink_nl_region_notify_build(struct devlink_region *region,
3871 struct devlink_snapshot *snapshot,
3872 enum devlink_command cmd, u32 portid, u32 seq)
Alex Vesker866319b2018-07-12 15:13:13 +03003873{
3874 struct devlink *devlink = region->devlink;
3875 struct sk_buff *msg;
3876 void *hdr;
3877 int err;
3878
Alex Vesker866319b2018-07-12 15:13:13 +03003879
3880 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3881 if (!msg)
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003882 return ERR_PTR(-ENOMEM);
Alex Vesker866319b2018-07-12 15:13:13 +03003883
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003884 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
3885 if (!hdr) {
3886 err = -EMSGSIZE;
Alex Vesker866319b2018-07-12 15:13:13 +03003887 goto out_free_msg;
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003888 }
Alex Vesker866319b2018-07-12 15:13:13 +03003889
3890 err = devlink_nl_put_handle(msg, devlink);
3891 if (err)
3892 goto out_cancel_msg;
3893
3894 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
Jacob Kellere8937682020-03-26 11:37:08 -07003895 region->ops->name);
Alex Vesker866319b2018-07-12 15:13:13 +03003896 if (err)
3897 goto out_cancel_msg;
3898
3899 if (snapshot) {
3900 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3901 snapshot->id);
3902 if (err)
3903 goto out_cancel_msg;
3904 } else {
3905 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3906 region->size, DEVLINK_ATTR_PAD);
3907 if (err)
3908 goto out_cancel_msg;
3909 }
3910 genlmsg_end(msg, hdr);
3911
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003912 return msg;
Alex Vesker866319b2018-07-12 15:13:13 +03003913
3914out_cancel_msg:
3915 genlmsg_cancel(msg, hdr);
3916out_free_msg:
3917 nlmsg_free(msg);
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003918 return ERR_PTR(err);
3919}
3920
3921static void devlink_nl_region_notify(struct devlink_region *region,
3922 struct devlink_snapshot *snapshot,
3923 enum devlink_command cmd)
3924{
3925 struct devlink *devlink = region->devlink;
3926 struct sk_buff *msg;
3927
3928 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3929
3930 msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
3931 if (IS_ERR(msg))
3932 return;
3933
3934 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3935 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
Alex Vesker866319b2018-07-12 15:13:13 +03003936}
3937
Jacob Kellercf80fae2020-03-26 11:37:11 -07003938/**
Jacob Keller12102432020-03-26 11:37:15 -07003939 * __devlink_snapshot_id_increment - Increment number of snapshots using an id
3940 * @devlink: devlink instance
3941 * @id: the snapshot id
3942 *
3943 * Track when a new snapshot begins using an id. Load the count for the
3944 * given id from the snapshot xarray, increment it, and store it back.
3945 *
3946 * Called when a new snapshot is created with the given id.
3947 *
3948 * The id *must* have been previously allocated by
3949 * devlink_region_snapshot_id_get().
3950 *
3951 * Returns 0 on success, or an error on failure.
3952 */
3953static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
3954{
3955 unsigned long count;
3956 void *p;
3957
3958 lockdep_assert_held(&devlink->lock);
3959
3960 p = xa_load(&devlink->snapshot_ids, id);
3961 if (WARN_ON(!p))
3962 return -EINVAL;
3963
3964 if (WARN_ON(!xa_is_value(p)))
3965 return -EINVAL;
3966
3967 count = xa_to_value(p);
3968 count++;
3969
3970 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
3971 GFP_KERNEL));
3972}
3973
3974/**
3975 * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
3976 * @devlink: devlink instance
3977 * @id: the snapshot id
3978 *
3979 * Track when a snapshot is deleted and stops using an id. Load the count
3980 * for the given id from the snapshot xarray, decrement it, and store it
3981 * back.
3982 *
3983 * If the count reaches zero, erase this id from the xarray, freeing it
3984 * up for future re-use by devlink_region_snapshot_id_get().
3985 *
3986 * Called when a snapshot using the given id is deleted, and when the
3987 * initial allocator of the id is finished using it.
3988 */
3989static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
3990{
3991 unsigned long count;
3992 void *p;
3993
3994 lockdep_assert_held(&devlink->lock);
3995
3996 p = xa_load(&devlink->snapshot_ids, id);
3997 if (WARN_ON(!p))
3998 return;
3999
4000 if (WARN_ON(!xa_is_value(p)))
4001 return;
4002
4003 count = xa_to_value(p);
4004
4005 if (count > 1) {
4006 count--;
4007 xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4008 GFP_KERNEL);
4009 } else {
4010 /* If this was the last user, we can erase this id */
4011 xa_erase(&devlink->snapshot_ids, id);
4012 }
4013}
4014
4015/**
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07004016 * __devlink_snapshot_id_insert - Insert a specific snapshot ID
4017 * @devlink: devlink instance
4018 * @id: the snapshot id
4019 *
4020 * Mark the given snapshot id as used by inserting a zero value into the
4021 * snapshot xarray.
4022 *
4023 * This must be called while holding the devlink instance lock. Unlike
4024 * devlink_snapshot_id_get, the initial reference count is zero, not one.
4025 * It is expected that the id will immediately be used before
4026 * releasing the devlink instance lock.
4027 *
4028 * Returns zero on success, or an error code if the snapshot id could not
4029 * be inserted.
4030 */
4031static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
4032{
4033 lockdep_assert_held(&devlink->lock);
4034
4035 if (WARN_ON(xa_load(&devlink->snapshot_ids, id)))
4036 return -EEXIST;
4037
4038 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
4039 GFP_KERNEL));
4040}
4041
4042/**
Jacob Keller70001082020-03-26 11:37:13 -07004043 * __devlink_region_snapshot_id_get - get snapshot ID
4044 * @devlink: devlink instance
Jacob Keller7ef19d32020-03-26 11:37:14 -07004045 * @id: storage to return snapshot id
Jacob Keller70001082020-03-26 11:37:13 -07004046 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07004047 * Allocates a new snapshot id. Returns zero on success, or a negative
4048 * error on failure. Must be called while holding the devlink instance
4049 * lock.
Jacob Keller12102432020-03-26 11:37:15 -07004050 *
4051 * Snapshot IDs are tracked using an xarray which stores the number of
4052 * users of the snapshot id.
4053 *
4054 * Note that the caller of this function counts as a 'user', in order to
4055 * avoid race conditions. The caller must release its hold on the
4056 * snapshot by using devlink_region_snapshot_id_put.
Jacob Keller70001082020-03-26 11:37:13 -07004057 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07004058static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Jacob Keller70001082020-03-26 11:37:13 -07004059{
4060 lockdep_assert_held(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07004061
Jacob Keller12102432020-03-26 11:37:15 -07004062 return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
4063 xa_limit_32b, GFP_KERNEL);
Jacob Keller70001082020-03-26 11:37:13 -07004064}
4065
4066/**
Jacob Kellercf80fae2020-03-26 11:37:11 -07004067 * __devlink_region_snapshot_create - create a new snapshot
4068 * This will add a new snapshot of a region. The snapshot
4069 * will be stored on the region struct and can be accessed
4070 * from devlink. This is useful for future analyses of snapshots.
4071 * Multiple snapshots can be created on a region.
4072 * The @snapshot_id should be obtained using the getter function.
4073 *
4074 * Must be called only while holding the devlink instance lock.
4075 *
4076 * @region: devlink region of the snapshot
4077 * @data: snapshot data
4078 * @snapshot_id: snapshot id to be created
4079 */
4080static int
4081__devlink_region_snapshot_create(struct devlink_region *region,
4082 u8 *data, u32 snapshot_id)
4083{
4084 struct devlink *devlink = region->devlink;
4085 struct devlink_snapshot *snapshot;
Jacob Keller12102432020-03-26 11:37:15 -07004086 int err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004087
4088 lockdep_assert_held(&devlink->lock);
4089
4090 /* check if region can hold one more snapshot */
4091 if (region->cur_snapshots == region->max_snapshots)
Jacob Keller47a39f62020-03-26 11:37:12 -07004092 return -ENOSPC;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004093
4094 if (devlink_region_snapshot_get_by_id(region, snapshot_id))
4095 return -EEXIST;
4096
4097 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
4098 if (!snapshot)
4099 return -ENOMEM;
4100
Jacob Keller12102432020-03-26 11:37:15 -07004101 err = __devlink_snapshot_id_increment(devlink, snapshot_id);
4102 if (err)
4103 goto err_snapshot_id_increment;
4104
Jacob Kellercf80fae2020-03-26 11:37:11 -07004105 snapshot->id = snapshot_id;
4106 snapshot->region = region;
4107 snapshot->data = data;
4108
4109 list_add_tail(&snapshot->list, &region->snapshot_list);
4110
4111 region->cur_snapshots++;
4112
4113 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
4114 return 0;
Jacob Keller12102432020-03-26 11:37:15 -07004115
4116err_snapshot_id_increment:
4117 kfree(snapshot);
4118 return err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004119}
4120
Jiri Pirko92b49822019-08-12 14:28:31 +02004121static void devlink_region_snapshot_del(struct devlink_region *region,
4122 struct devlink_snapshot *snapshot)
4123{
Jacob Keller12102432020-03-26 11:37:15 -07004124 struct devlink *devlink = region->devlink;
4125
4126 lockdep_assert_held(&devlink->lock);
4127
Jiri Pirko92b49822019-08-12 14:28:31 +02004128 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
4129 region->cur_snapshots--;
4130 list_del(&snapshot->list);
Jacob Kellera0a09f62020-03-26 11:37:09 -07004131 region->ops->destructor(snapshot->data);
Jacob Keller12102432020-03-26 11:37:15 -07004132 __devlink_snapshot_id_decrement(devlink, snapshot->id);
Jiri Pirko92b49822019-08-12 14:28:31 +02004133 kfree(snapshot);
4134}
4135
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004136static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
4137 struct genl_info *info)
4138{
4139 struct devlink *devlink = info->user_ptr[0];
4140 struct devlink_region *region;
4141 const char *region_name;
4142 struct sk_buff *msg;
4143 int err;
4144
4145 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
4146 return -EINVAL;
4147
4148 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4149 region = devlink_region_get_by_name(devlink, region_name);
4150 if (!region)
4151 return -EINVAL;
4152
4153 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4154 if (!msg)
4155 return -ENOMEM;
4156
4157 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
4158 info->snd_portid, info->snd_seq, 0,
4159 region);
4160 if (err) {
4161 nlmsg_free(msg);
4162 return err;
4163 }
4164
4165 return genlmsg_reply(msg, info);
4166}
4167
4168static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
4169 struct netlink_callback *cb)
4170{
4171 struct devlink_region *region;
4172 struct devlink *devlink;
4173 int start = cb->args[0];
4174 int idx = 0;
4175 int err;
4176
4177 mutex_lock(&devlink_mutex);
4178 list_for_each_entry(devlink, &devlink_list, list) {
4179 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4180 continue;
4181
4182 mutex_lock(&devlink->lock);
4183 list_for_each_entry(region, &devlink->region_list, list) {
4184 if (idx < start) {
4185 idx++;
4186 continue;
4187 }
4188 err = devlink_nl_region_fill(msg, devlink,
4189 DEVLINK_CMD_REGION_GET,
4190 NETLINK_CB(cb->skb).portid,
4191 cb->nlh->nlmsg_seq,
4192 NLM_F_MULTI, region);
4193 if (err) {
4194 mutex_unlock(&devlink->lock);
4195 goto out;
4196 }
4197 idx++;
4198 }
4199 mutex_unlock(&devlink->lock);
4200 }
4201out:
4202 mutex_unlock(&devlink_mutex);
4203 cb->args[0] = idx;
4204 return msg->len;
4205}
4206
Alex Vesker866319b2018-07-12 15:13:13 +03004207static int devlink_nl_cmd_region_del(struct sk_buff *skb,
4208 struct genl_info *info)
4209{
4210 struct devlink *devlink = info->user_ptr[0];
4211 struct devlink_snapshot *snapshot;
4212 struct devlink_region *region;
4213 const char *region_name;
4214 u32 snapshot_id;
4215
4216 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
4217 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
4218 return -EINVAL;
4219
4220 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4221 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4222
4223 region = devlink_region_get_by_name(devlink, region_name);
4224 if (!region)
4225 return -EINVAL;
4226
4227 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4228 if (!snapshot)
4229 return -EINVAL;
4230
Jiri Pirko92b49822019-08-12 14:28:31 +02004231 devlink_region_snapshot_del(region, snapshot);
Alex Vesker866319b2018-07-12 15:13:13 +03004232 return 0;
4233}
4234
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07004235static int
4236devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
4237{
4238 struct devlink *devlink = info->user_ptr[0];
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004239 struct devlink_snapshot *snapshot;
4240 struct nlattr *snapshot_id_attr;
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07004241 struct devlink_region *region;
4242 const char *region_name;
4243 u32 snapshot_id;
4244 u8 *data;
4245 int err;
4246
4247 if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) {
4248 NL_SET_ERR_MSG_MOD(info->extack, "No region name provided");
4249 return -EINVAL;
4250 }
4251
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07004252 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4253 region = devlink_region_get_by_name(devlink, region_name);
4254 if (!region) {
4255 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist");
4256 return -EINVAL;
4257 }
4258
4259 if (!region->ops->snapshot) {
4260 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not support taking an immediate snapshot");
4261 return -EOPNOTSUPP;
4262 }
4263
4264 if (region->cur_snapshots == region->max_snapshots) {
4265 NL_SET_ERR_MSG_MOD(info->extack, "The region has reached the maximum number of stored snapshots");
4266 return -ENOSPC;
4267 }
4268
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004269 snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
4270 if (snapshot_id_attr) {
4271 snapshot_id = nla_get_u32(snapshot_id_attr);
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07004272
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004273 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
4274 NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
4275 return -EEXIST;
4276 }
4277
4278 err = __devlink_snapshot_id_insert(devlink, snapshot_id);
4279 if (err)
4280 return err;
4281 } else {
4282 err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
4283 if (err) {
4284 NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
4285 return err;
4286 }
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07004287 }
4288
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07004289 err = region->ops->snapshot(devlink, info->extack, &data);
4290 if (err)
4291 goto err_snapshot_capture;
4292
4293 err = __devlink_region_snapshot_create(region, data, snapshot_id);
4294 if (err)
4295 goto err_snapshot_create;
4296
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004297 if (!snapshot_id_attr) {
4298 struct sk_buff *msg;
4299
4300 snapshot = devlink_region_snapshot_get_by_id(region,
4301 snapshot_id);
4302 if (WARN_ON(!snapshot))
4303 return -EINVAL;
4304
4305 msg = devlink_nl_region_notify_build(region, snapshot,
4306 DEVLINK_CMD_REGION_NEW,
4307 info->snd_portid,
4308 info->snd_seq);
4309 err = PTR_ERR_OR_ZERO(msg);
4310 if (err)
4311 goto err_notify;
4312
4313 err = genlmsg_reply(msg, info);
4314 if (err)
4315 goto err_notify;
4316 }
4317
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07004318 return 0;
4319
4320err_snapshot_create:
4321 region->ops->destructor(data);
4322err_snapshot_capture:
4323 __devlink_snapshot_id_decrement(devlink, snapshot_id);
4324 return err;
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004325
4326err_notify:
4327 devlink_region_snapshot_del(region, snapshot);
4328 return err;
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07004329}
4330
Alex Vesker4e547952018-07-12 15:13:14 +03004331static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
4332 struct devlink *devlink,
4333 u8 *chunk, u32 chunk_size,
4334 u64 addr)
4335{
4336 struct nlattr *chunk_attr;
4337 int err;
4338
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004339 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
Alex Vesker4e547952018-07-12 15:13:14 +03004340 if (!chunk_attr)
4341 return -EINVAL;
4342
4343 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
4344 if (err)
4345 goto nla_put_failure;
4346
4347 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
4348 DEVLINK_ATTR_PAD);
4349 if (err)
4350 goto nla_put_failure;
4351
4352 nla_nest_end(msg, chunk_attr);
4353 return 0;
4354
4355nla_put_failure:
4356 nla_nest_cancel(msg, chunk_attr);
4357 return err;
4358}
4359
4360#define DEVLINK_REGION_READ_CHUNK_SIZE 256
4361
4362static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
4363 struct devlink *devlink,
4364 struct devlink_region *region,
4365 struct nlattr **attrs,
4366 u64 start_offset,
4367 u64 end_offset,
Alex Vesker4e547952018-07-12 15:13:14 +03004368 u64 *new_offset)
4369{
4370 struct devlink_snapshot *snapshot;
4371 u64 curr_offset = start_offset;
4372 u32 snapshot_id;
4373 int err = 0;
4374
4375 *new_offset = start_offset;
4376
4377 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4378 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4379 if (!snapshot)
4380 return -EINVAL;
4381
Alex Vesker4e547952018-07-12 15:13:14 +03004382 while (curr_offset < end_offset) {
4383 u32 data_size;
4384 u8 *data;
4385
4386 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
4387 data_size = end_offset - curr_offset;
4388 else
4389 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
4390
4391 data = &snapshot->data[curr_offset];
4392 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
4393 data, data_size,
4394 curr_offset);
4395 if (err)
4396 break;
4397
4398 curr_offset += data_size;
4399 }
4400 *new_offset = curr_offset;
4401
4402 return err;
4403}
4404
4405static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
4406 struct netlink_callback *cb)
4407{
Jiri Pirkoee85da52019-10-05 20:04:42 +02004408 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004409 u64 ret_offset, start_offset, end_offset = U64_MAX;
Jiri Pirkoee85da52019-10-05 20:04:42 +02004410 struct nlattr **attrs = info->attrs;
Alex Vesker4e547952018-07-12 15:13:14 +03004411 struct devlink_region *region;
4412 struct nlattr *chunks_attr;
4413 const char *region_name;
4414 struct devlink *devlink;
Alex Vesker4e547952018-07-12 15:13:14 +03004415 void *hdr;
4416 int err;
4417
4418 start_offset = *((u64 *)&cb->args[0]);
4419
Parav Panditdac7c082019-02-12 14:24:08 -06004420 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03004421 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004422 if (IS_ERR(devlink)) {
4423 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06004424 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004425 }
Alex Vesker4e547952018-07-12 15:13:14 +03004426
Alex Vesker4e547952018-07-12 15:13:14 +03004427 mutex_lock(&devlink->lock);
4428
4429 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06004430 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
4431 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004432 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004433 }
Alex Vesker4e547952018-07-12 15:13:14 +03004434
4435 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
4436 region = devlink_region_get_by_name(devlink, region_name);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004437 if (!region) {
4438 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004439 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004440 }
Alex Vesker4e547952018-07-12 15:13:14 +03004441
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004442 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
4443 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
4444 if (!start_offset)
4445 start_offset =
4446 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4447
4448 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4449 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
4450 }
4451
4452 if (end_offset > region->size)
4453 end_offset = region->size;
4454
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004455 /* return 0 if there is no further data to read */
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004456 if (start_offset == end_offset) {
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004457 err = 0;
4458 goto out_unlock;
4459 }
4460
Alex Vesker4e547952018-07-12 15:13:14 +03004461 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4462 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
4463 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004464 if (!hdr) {
4465 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004466 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004467 }
Alex Vesker4e547952018-07-12 15:13:14 +03004468
4469 err = devlink_nl_put_handle(skb, devlink);
4470 if (err)
4471 goto nla_put_failure;
4472
4473 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
4474 if (err)
4475 goto nla_put_failure;
4476
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004477 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004478 if (!chunks_attr) {
4479 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004480 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004481 }
Alex Vesker4e547952018-07-12 15:13:14 +03004482
Alex Vesker4e547952018-07-12 15:13:14 +03004483 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
4484 region, attrs,
4485 start_offset,
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004486 end_offset, &ret_offset);
Alex Vesker4e547952018-07-12 15:13:14 +03004487
4488 if (err && err != -EMSGSIZE)
4489 goto nla_put_failure;
4490
4491 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06004492 if (ret_offset == start_offset) {
4493 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004494 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004495 }
Alex Vesker4e547952018-07-12 15:13:14 +03004496
4497 *((u64 *)&cb->args[0]) = ret_offset;
4498
4499 nla_nest_end(skb, chunks_attr);
4500 genlmsg_end(skb, hdr);
4501 mutex_unlock(&devlink->lock);
4502 mutex_unlock(&devlink_mutex);
4503
4504 return skb->len;
4505
4506nla_put_failure:
4507 genlmsg_cancel(skb, hdr);
4508out_unlock:
4509 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06004510out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03004511 mutex_unlock(&devlink_mutex);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004512 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03004513}
4514
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004515struct devlink_info_req {
4516 struct sk_buff *msg;
4517};
4518
4519int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
4520{
4521 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
4522}
4523EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
4524
4525int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
4526{
4527 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
4528}
4529EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
4530
Vasundhara Volamb5872cd2020-06-20 22:01:56 +05304531int devlink_info_board_serial_number_put(struct devlink_info_req *req,
4532 const char *bsn)
4533{
4534 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER,
4535 bsn);
4536}
4537EXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put);
4538
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08004539static int devlink_info_version_put(struct devlink_info_req *req, int attr,
4540 const char *version_name,
4541 const char *version_value)
4542{
4543 struct nlattr *nest;
4544 int err;
4545
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004546 nest = nla_nest_start_noflag(req->msg, attr);
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08004547 if (!nest)
4548 return -EMSGSIZE;
4549
4550 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
4551 version_name);
4552 if (err)
4553 goto nla_put_failure;
4554
4555 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
4556 version_value);
4557 if (err)
4558 goto nla_put_failure;
4559
4560 nla_nest_end(req->msg, nest);
4561
4562 return 0;
4563
4564nla_put_failure:
4565 nla_nest_cancel(req->msg, nest);
4566 return err;
4567}
4568
4569int devlink_info_version_fixed_put(struct devlink_info_req *req,
4570 const char *version_name,
4571 const char *version_value)
4572{
4573 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
4574 version_name, version_value);
4575}
4576EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
4577
4578int devlink_info_version_stored_put(struct devlink_info_req *req,
4579 const char *version_name,
4580 const char *version_value)
4581{
4582 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
4583 version_name, version_value);
4584}
4585EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
4586
4587int devlink_info_version_running_put(struct devlink_info_req *req,
4588 const char *version_name,
4589 const char *version_value)
4590{
4591 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
4592 version_name, version_value);
4593}
4594EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
4595
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004596static int
4597devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
4598 enum devlink_command cmd, u32 portid,
4599 u32 seq, int flags, struct netlink_ext_ack *extack)
4600{
4601 struct devlink_info_req req;
4602 void *hdr;
4603 int err;
4604
4605 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4606 if (!hdr)
4607 return -EMSGSIZE;
4608
4609 err = -EMSGSIZE;
4610 if (devlink_nl_put_handle(msg, devlink))
4611 goto err_cancel_msg;
4612
4613 req.msg = msg;
4614 err = devlink->ops->info_get(devlink, &req, extack);
4615 if (err)
4616 goto err_cancel_msg;
4617
4618 genlmsg_end(msg, hdr);
4619 return 0;
4620
4621err_cancel_msg:
4622 genlmsg_cancel(msg, hdr);
4623 return err;
4624}
4625
4626static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
4627 struct genl_info *info)
4628{
4629 struct devlink *devlink = info->user_ptr[0];
4630 struct sk_buff *msg;
4631 int err;
4632
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08004633 if (!devlink->ops->info_get)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004634 return -EOPNOTSUPP;
4635
4636 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4637 if (!msg)
4638 return -ENOMEM;
4639
4640 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4641 info->snd_portid, info->snd_seq, 0,
4642 info->extack);
4643 if (err) {
4644 nlmsg_free(msg);
4645 return err;
4646 }
4647
4648 return genlmsg_reply(msg, info);
4649}
4650
4651static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
4652 struct netlink_callback *cb)
4653{
4654 struct devlink *devlink;
4655 int start = cb->args[0];
4656 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004657 int err = 0;
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004658
4659 mutex_lock(&devlink_mutex);
4660 list_for_each_entry(devlink, &devlink_list, list) {
4661 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4662 continue;
4663 if (idx < start) {
4664 idx++;
4665 continue;
4666 }
4667
Jiri Pirkoc493b09b2019-03-24 00:21:03 +01004668 if (!devlink->ops->info_get) {
4669 idx++;
4670 continue;
4671 }
4672
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004673 mutex_lock(&devlink->lock);
4674 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4675 NETLINK_CB(cb->skb).portid,
4676 cb->nlh->nlmsg_seq, NLM_F_MULTI,
4677 cb->extack);
4678 mutex_unlock(&devlink->lock);
Vasundhara Volam93c2fcb2019-09-30 11:52:21 +05304679 if (err && err != -EOPNOTSUPP)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004680 break;
4681 idx++;
4682 }
4683 mutex_unlock(&devlink_mutex);
4684
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004685 if (err != -EMSGSIZE)
4686 return err;
4687
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004688 cb->args[0] = idx;
4689 return msg->len;
4690}
4691
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004692struct devlink_fmsg_item {
4693 struct list_head list;
4694 int attrtype;
4695 u8 nla_type;
4696 u16 len;
Gustavo A. R. Silvad2afb412020-02-28 07:43:24 -06004697 int value[];
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004698};
4699
4700struct devlink_fmsg {
4701 struct list_head item_list;
Aya Levin573ed902020-02-11 14:32:42 -08004702 bool putting_binary; /* This flag forces enclosing of binary data
4703 * in an array brackets. It forces using
4704 * of designated API:
4705 * devlink_fmsg_binary_pair_nest_start()
4706 * devlink_fmsg_binary_pair_nest_end()
4707 */
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004708};
4709
4710static struct devlink_fmsg *devlink_fmsg_alloc(void)
4711{
4712 struct devlink_fmsg *fmsg;
4713
4714 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
4715 if (!fmsg)
4716 return NULL;
4717
4718 INIT_LIST_HEAD(&fmsg->item_list);
4719
4720 return fmsg;
4721}
4722
4723static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
4724{
4725 struct devlink_fmsg_item *item, *tmp;
4726
4727 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
4728 list_del(&item->list);
4729 kfree(item);
4730 }
4731 kfree(fmsg);
4732}
4733
4734static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
4735 int attrtype)
4736{
4737 struct devlink_fmsg_item *item;
4738
4739 item = kzalloc(sizeof(*item), GFP_KERNEL);
4740 if (!item)
4741 return -ENOMEM;
4742
4743 item->attrtype = attrtype;
4744 list_add_tail(&item->list, &fmsg->item_list);
4745
4746 return 0;
4747}
4748
4749int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
4750{
Aya Levin573ed902020-02-11 14:32:42 -08004751 if (fmsg->putting_binary)
4752 return -EINVAL;
4753
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004754 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
4755}
4756EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
4757
4758static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
4759{
Aya Levin573ed902020-02-11 14:32:42 -08004760 if (fmsg->putting_binary)
4761 return -EINVAL;
4762
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004763 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
4764}
4765
4766int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
4767{
Aya Levin573ed902020-02-11 14:32:42 -08004768 if (fmsg->putting_binary)
4769 return -EINVAL;
4770
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004771 return devlink_fmsg_nest_end(fmsg);
4772}
4773EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
4774
4775#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
4776
4777static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
4778{
4779 struct devlink_fmsg_item *item;
4780
Aya Levin573ed902020-02-11 14:32:42 -08004781 if (fmsg->putting_binary)
4782 return -EINVAL;
4783
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004784 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4785 return -EMSGSIZE;
4786
4787 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4788 if (!item)
4789 return -ENOMEM;
4790
4791 item->nla_type = NLA_NUL_STRING;
4792 item->len = strlen(name) + 1;
4793 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4794 memcpy(&item->value, name, item->len);
4795 list_add_tail(&item->list, &fmsg->item_list);
4796
4797 return 0;
4798}
4799
4800int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4801{
4802 int err;
4803
Aya Levin573ed902020-02-11 14:32:42 -08004804 if (fmsg->putting_binary)
4805 return -EINVAL;
4806
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004807 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4808 if (err)
4809 return err;
4810
4811 err = devlink_fmsg_put_name(fmsg, name);
4812 if (err)
4813 return err;
4814
4815 return 0;
4816}
4817EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4818
4819int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4820{
Aya Levin573ed902020-02-11 14:32:42 -08004821 if (fmsg->putting_binary)
4822 return -EINVAL;
4823
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004824 return devlink_fmsg_nest_end(fmsg);
4825}
4826EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4827
4828int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4829 const char *name)
4830{
4831 int err;
4832
Aya Levin573ed902020-02-11 14:32:42 -08004833 if (fmsg->putting_binary)
4834 return -EINVAL;
4835
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004836 err = devlink_fmsg_pair_nest_start(fmsg, name);
4837 if (err)
4838 return err;
4839
4840 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4841 if (err)
4842 return err;
4843
4844 return 0;
4845}
4846EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4847
4848int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4849{
4850 int err;
4851
Aya Levin573ed902020-02-11 14:32:42 -08004852 if (fmsg->putting_binary)
4853 return -EINVAL;
4854
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004855 err = devlink_fmsg_nest_end(fmsg);
4856 if (err)
4857 return err;
4858
4859 err = devlink_fmsg_nest_end(fmsg);
4860 if (err)
4861 return err;
4862
4863 return 0;
4864}
4865EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4866
Aya Levin573ed902020-02-11 14:32:42 -08004867int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
4868 const char *name)
4869{
4870 int err;
4871
4872 err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
4873 if (err)
4874 return err;
4875
4876 fmsg->putting_binary = true;
4877 return err;
4878}
4879EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
4880
4881int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
4882{
4883 if (!fmsg->putting_binary)
4884 return -EINVAL;
4885
4886 fmsg->putting_binary = false;
4887 return devlink_fmsg_arr_pair_nest_end(fmsg);
4888}
4889EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
4890
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004891static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4892 const void *value, u16 value_len,
4893 u8 value_nla_type)
4894{
4895 struct devlink_fmsg_item *item;
4896
4897 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4898 return -EMSGSIZE;
4899
4900 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4901 if (!item)
4902 return -ENOMEM;
4903
4904 item->nla_type = value_nla_type;
4905 item->len = value_len;
4906 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4907 memcpy(&item->value, value, item->len);
4908 list_add_tail(&item->list, &fmsg->item_list);
4909
4910 return 0;
4911}
4912
4913int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4914{
Aya Levin573ed902020-02-11 14:32:42 -08004915 if (fmsg->putting_binary)
4916 return -EINVAL;
4917
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004918 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4919}
4920EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4921
4922int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4923{
Aya Levin573ed902020-02-11 14:32:42 -08004924 if (fmsg->putting_binary)
4925 return -EINVAL;
4926
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004927 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4928}
4929EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4930
4931int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4932{
Aya Levin573ed902020-02-11 14:32:42 -08004933 if (fmsg->putting_binary)
4934 return -EINVAL;
4935
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004936 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4937}
4938EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4939
4940int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4941{
Aya Levin573ed902020-02-11 14:32:42 -08004942 if (fmsg->putting_binary)
4943 return -EINVAL;
4944
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004945 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4946}
4947EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4948
4949int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4950{
Aya Levin573ed902020-02-11 14:32:42 -08004951 if (fmsg->putting_binary)
4952 return -EINVAL;
4953
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004954 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4955 NLA_NUL_STRING);
4956}
4957EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4958
Aya Levin573ed902020-02-11 14:32:42 -08004959int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4960 u16 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004961{
Aya Levin573ed902020-02-11 14:32:42 -08004962 if (!fmsg->putting_binary)
4963 return -EINVAL;
4964
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004965 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4966}
Aya Levin573ed902020-02-11 14:32:42 -08004967EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004968
4969int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4970 bool value)
4971{
4972 int err;
4973
4974 err = devlink_fmsg_pair_nest_start(fmsg, name);
4975 if (err)
4976 return err;
4977
4978 err = devlink_fmsg_bool_put(fmsg, value);
4979 if (err)
4980 return err;
4981
4982 err = devlink_fmsg_pair_nest_end(fmsg);
4983 if (err)
4984 return err;
4985
4986 return 0;
4987}
4988EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4989
4990int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4991 u8 value)
4992{
4993 int err;
4994
4995 err = devlink_fmsg_pair_nest_start(fmsg, name);
4996 if (err)
4997 return err;
4998
4999 err = devlink_fmsg_u8_put(fmsg, value);
5000 if (err)
5001 return err;
5002
5003 err = devlink_fmsg_pair_nest_end(fmsg);
5004 if (err)
5005 return err;
5006
5007 return 0;
5008}
5009EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
5010
5011int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
5012 u32 value)
5013{
5014 int err;
5015
5016 err = devlink_fmsg_pair_nest_start(fmsg, name);
5017 if (err)
5018 return err;
5019
5020 err = devlink_fmsg_u32_put(fmsg, value);
5021 if (err)
5022 return err;
5023
5024 err = devlink_fmsg_pair_nest_end(fmsg);
5025 if (err)
5026 return err;
5027
5028 return 0;
5029}
5030EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
5031
5032int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
5033 u64 value)
5034{
5035 int err;
5036
5037 err = devlink_fmsg_pair_nest_start(fmsg, name);
5038 if (err)
5039 return err;
5040
5041 err = devlink_fmsg_u64_put(fmsg, value);
5042 if (err)
5043 return err;
5044
5045 err = devlink_fmsg_pair_nest_end(fmsg);
5046 if (err)
5047 return err;
5048
5049 return 0;
5050}
5051EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
5052
5053int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
5054 const char *value)
5055{
5056 int err;
5057
5058 err = devlink_fmsg_pair_nest_start(fmsg, name);
5059 if (err)
5060 return err;
5061
5062 err = devlink_fmsg_string_put(fmsg, value);
5063 if (err)
5064 return err;
5065
5066 err = devlink_fmsg_pair_nest_end(fmsg);
5067 if (err)
5068 return err;
5069
5070 return 0;
5071}
5072EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
5073
5074int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
Aya Levine2cde862019-11-12 14:07:49 +02005075 const void *value, u32 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005076{
Aya Levine2cde862019-11-12 14:07:49 +02005077 u32 data_size;
Aya Levin573ed902020-02-11 14:32:42 -08005078 int end_err;
Aya Levine2cde862019-11-12 14:07:49 +02005079 u32 offset;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005080 int err;
5081
Aya Levin573ed902020-02-11 14:32:42 -08005082 err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005083 if (err)
5084 return err;
5085
Aya Levine2cde862019-11-12 14:07:49 +02005086 for (offset = 0; offset < value_len; offset += data_size) {
5087 data_size = value_len - offset;
5088 if (data_size > DEVLINK_FMSG_MAX_SIZE)
5089 data_size = DEVLINK_FMSG_MAX_SIZE;
5090 err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
5091 if (err)
Aya Levin573ed902020-02-11 14:32:42 -08005092 break;
5093 /* Exit from loop with a break (instead of
5094 * return) to make sure putting_binary is turned off in
5095 * devlink_fmsg_binary_pair_nest_end
5096 */
Aya Levine2cde862019-11-12 14:07:49 +02005097 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005098
Aya Levin573ed902020-02-11 14:32:42 -08005099 end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
5100 if (end_err)
5101 err = end_err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005102
Aya Levin573ed902020-02-11 14:32:42 -08005103 return err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005104}
5105EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
5106
5107static int
5108devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5109{
5110 switch (msg->nla_type) {
5111 case NLA_FLAG:
5112 case NLA_U8:
5113 case NLA_U32:
5114 case NLA_U64:
5115 case NLA_NUL_STRING:
5116 case NLA_BINARY:
5117 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
5118 msg->nla_type);
5119 default:
5120 return -EINVAL;
5121 }
5122}
5123
5124static int
5125devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5126{
5127 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5128 u8 tmp;
5129
5130 switch (msg->nla_type) {
5131 case NLA_FLAG:
5132 /* Always provide flag data, regardless of its value */
5133 tmp = *(bool *) msg->value;
5134
5135 return nla_put_u8(skb, attrtype, tmp);
5136 case NLA_U8:
5137 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
5138 case NLA_U32:
5139 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
5140 case NLA_U64:
5141 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
5142 DEVLINK_ATTR_PAD);
5143 case NLA_NUL_STRING:
5144 return nla_put_string(skb, attrtype, (char *) &msg->value);
5145 case NLA_BINARY:
5146 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
5147 default:
5148 return -EINVAL;
5149 }
5150}
5151
5152static int
5153devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5154 int *start)
5155{
5156 struct devlink_fmsg_item *item;
5157 struct nlattr *fmsg_nlattr;
5158 int i = 0;
5159 int err;
5160
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005161 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005162 if (!fmsg_nlattr)
5163 return -EMSGSIZE;
5164
5165 list_for_each_entry(item, &fmsg->item_list, list) {
5166 if (i < *start) {
5167 i++;
5168 continue;
5169 }
5170
5171 switch (item->attrtype) {
5172 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
5173 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
5174 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
5175 case DEVLINK_ATTR_FMSG_NEST_END:
5176 err = nla_put_flag(skb, item->attrtype);
5177 break;
5178 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
5179 err = devlink_fmsg_item_fill_type(item, skb);
5180 if (err)
5181 break;
5182 err = devlink_fmsg_item_fill_data(item, skb);
5183 break;
5184 case DEVLINK_ATTR_FMSG_OBJ_NAME:
5185 err = nla_put_string(skb, item->attrtype,
5186 (char *) &item->value);
5187 break;
5188 default:
5189 err = -EINVAL;
5190 break;
5191 }
5192 if (!err)
5193 *start = ++i;
5194 else
5195 break;
5196 }
5197
5198 nla_nest_end(skb, fmsg_nlattr);
5199 return err;
5200}
5201
5202static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
5203 struct genl_info *info,
5204 enum devlink_command cmd, int flags)
5205{
5206 struct nlmsghdr *nlh;
5207 struct sk_buff *skb;
5208 bool last = false;
5209 int index = 0;
5210 void *hdr;
5211 int err;
5212
5213 while (!last) {
5214 int tmp_index = index;
5215
5216 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5217 if (!skb)
5218 return -ENOMEM;
5219
5220 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
5221 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
5222 if (!hdr) {
5223 err = -EMSGSIZE;
5224 goto nla_put_failure;
5225 }
5226
5227 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5228 if (!err)
5229 last = true;
5230 else if (err != -EMSGSIZE || tmp_index == index)
5231 goto nla_put_failure;
5232
5233 genlmsg_end(skb, hdr);
5234 err = genlmsg_reply(skb, info);
5235 if (err)
5236 return err;
5237 }
5238
5239 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5240 if (!skb)
5241 return -ENOMEM;
5242 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
5243 NLMSG_DONE, 0, flags | NLM_F_MULTI);
5244 if (!nlh) {
5245 err = -EMSGSIZE;
5246 goto nla_put_failure;
5247 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005248
Li RongQingfde55ea2019-02-11 19:09:07 +08005249 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005250
5251nla_put_failure:
5252 nlmsg_free(skb);
5253 return err;
5254}
5255
Aya Levine44ef4e2019-05-16 09:49:20 +03005256static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5257 struct netlink_callback *cb,
5258 enum devlink_command cmd)
5259{
5260 int index = cb->args[0];
5261 int tmp_index = index;
5262 void *hdr;
5263 int err;
5264
5265 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
5266 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
5267 if (!hdr) {
5268 err = -EMSGSIZE;
5269 goto nla_put_failure;
5270 }
5271
5272 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5273 if ((err && err != -EMSGSIZE) || tmp_index == index)
5274 goto nla_put_failure;
5275
5276 cb->args[0] = index;
5277 genlmsg_end(skb, hdr);
5278 return skb->len;
5279
5280nla_put_failure:
5281 genlmsg_cancel(skb, hdr);
5282 return err;
5283}
5284
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005285struct devlink_health_reporter {
5286 struct list_head list;
5287 void *priv;
5288 const struct devlink_health_reporter_ops *ops;
5289 struct devlink *devlink;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005290 struct devlink_fmsg *dump_fmsg;
5291 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005292 u64 graceful_period;
5293 bool auto_recover;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005294 bool auto_dump;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005295 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005296 u64 dump_ts;
Aya Levind2795052019-11-10 14:11:56 +02005297 u64 dump_real_ts;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005298 u64 error_count;
5299 u64 recovery_count;
5300 u64 last_recovery_ts;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005301 refcount_t refcount;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005302};
5303
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005304void *
5305devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
5306{
5307 return reporter->priv;
5308}
5309EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
5310
5311static struct devlink_health_reporter *
5312devlink_health_reporter_find_by_name(struct devlink *devlink,
5313 const char *reporter_name)
5314{
5315 struct devlink_health_reporter *reporter;
5316
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005317 lockdep_assert_held(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005318 list_for_each_entry(reporter, &devlink->reporter_list, list)
5319 if (!strcmp(reporter->ops->name, reporter_name))
5320 return reporter;
5321 return NULL;
5322}
5323
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005324static struct devlink_health_reporter *
5325__devlink_health_reporter_create(struct devlink *devlink,
5326 const struct devlink_health_reporter_ops *ops,
5327 u64 graceful_period, void *priv)
5328{
5329 struct devlink_health_reporter *reporter;
5330
5331 if (WARN_ON(graceful_period && !ops->recover))
5332 return ERR_PTR(-EINVAL);
5333
5334 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
5335 if (!reporter)
5336 return ERR_PTR(-ENOMEM);
5337
5338 reporter->priv = priv;
5339 reporter->ops = ops;
5340 reporter->devlink = devlink;
5341 reporter->graceful_period = graceful_period;
5342 reporter->auto_recover = !!ops->recover;
5343 reporter->auto_dump = !!ops->dump;
5344 mutex_init(&reporter->dump_lock);
5345 refcount_set(&reporter->refcount, 1);
5346 return reporter;
5347}
5348
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005349/**
5350 * devlink_health_reporter_create - create devlink health reporter
5351 *
5352 * @devlink: devlink
5353 * @ops: ops
5354 * @graceful_period: to avoid recovery loops, in msecs
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005355 * @priv: priv
5356 */
5357struct devlink_health_reporter *
5358devlink_health_reporter_create(struct devlink *devlink,
5359 const struct devlink_health_reporter_ops *ops,
Eran Ben Elishaba7d16c2020-03-29 14:05:54 +03005360 u64 graceful_period, void *priv)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005361{
5362 struct devlink_health_reporter *reporter;
5363
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005364 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005365 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
5366 reporter = ERR_PTR(-EEXIST);
5367 goto unlock;
5368 }
5369
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005370 reporter = __devlink_health_reporter_create(devlink, ops,
5371 graceful_period, priv);
5372 if (IS_ERR(reporter))
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005373 goto unlock;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005374
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005375 list_add_tail(&reporter->list, &devlink->reporter_list);
5376unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005377 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005378 return reporter;
5379}
5380EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
5381
5382/**
5383 * devlink_health_reporter_destroy - destroy devlink health reporter
5384 *
5385 * @reporter: devlink health reporter to destroy
5386 */
5387void
5388devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5389{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005390 mutex_lock(&reporter->devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005391 list_del(&reporter->list);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005392 mutex_unlock(&reporter->devlink->reporters_lock);
5393 while (refcount_read(&reporter->refcount) > 1)
5394 msleep(100);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01005395 mutex_destroy(&reporter->dump_lock);
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005396 if (reporter->dump_fmsg)
5397 devlink_fmsg_free(reporter->dump_fmsg);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005398 kfree(reporter);
5399}
5400EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
5401
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005402static int
5403devlink_nl_health_reporter_fill(struct sk_buff *msg,
5404 struct devlink *devlink,
5405 struct devlink_health_reporter *reporter,
5406 enum devlink_command cmd, u32 portid,
5407 u32 seq, int flags)
5408{
5409 struct nlattr *reporter_attr;
5410 void *hdr;
5411
5412 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5413 if (!hdr)
5414 return -EMSGSIZE;
5415
5416 if (devlink_nl_put_handle(msg, devlink))
5417 goto genlmsg_cancel;
5418
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005419 reporter_attr = nla_nest_start_noflag(msg,
5420 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005421 if (!reporter_attr)
5422 goto genlmsg_cancel;
5423 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
5424 reporter->ops->name))
5425 goto reporter_nest_cancel;
5426 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
5427 reporter->health_state))
5428 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005429 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005430 reporter->error_count, DEVLINK_ATTR_PAD))
5431 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005432 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005433 reporter->recovery_count, DEVLINK_ATTR_PAD))
5434 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005435 if (reporter->ops->recover &&
5436 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005437 reporter->graceful_period,
5438 DEVLINK_ATTR_PAD))
5439 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005440 if (reporter->ops->recover &&
5441 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005442 reporter->auto_recover))
5443 goto reporter_nest_cancel;
5444 if (reporter->dump_fmsg &&
5445 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
5446 jiffies_to_msecs(reporter->dump_ts),
5447 DEVLINK_ATTR_PAD))
5448 goto reporter_nest_cancel;
Aya Levind2795052019-11-10 14:11:56 +02005449 if (reporter->dump_fmsg &&
5450 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
5451 reporter->dump_real_ts, DEVLINK_ATTR_PAD))
5452 goto reporter_nest_cancel;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005453 if (reporter->ops->dump &&
5454 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
5455 reporter->auto_dump))
5456 goto reporter_nest_cancel;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005457
5458 nla_nest_end(msg, reporter_attr);
5459 genlmsg_end(msg, hdr);
5460 return 0;
5461
5462reporter_nest_cancel:
5463 nla_nest_end(msg, reporter_attr);
5464genlmsg_cancel:
5465 genlmsg_cancel(msg, hdr);
5466 return -EMSGSIZE;
5467}
5468
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305469static void devlink_recover_notify(struct devlink_health_reporter *reporter,
5470 enum devlink_command cmd)
5471{
5472 struct sk_buff *msg;
5473 int err;
5474
5475 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5476
5477 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5478 if (!msg)
5479 return;
5480
5481 err = devlink_nl_health_reporter_fill(msg, reporter->devlink,
5482 reporter, cmd, 0, 0, 0);
5483 if (err) {
5484 nlmsg_free(msg);
5485 return;
5486 }
5487
5488 genlmsg_multicast_netns(&devlink_nl_family,
5489 devlink_net(reporter->devlink),
5490 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
5491}
5492
5493void
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005494devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
5495{
5496 reporter->recovery_count++;
5497 reporter->last_recovery_ts = jiffies;
5498}
5499EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
5500
5501static int
5502devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
5503 void *priv_ctx, struct netlink_ext_ack *extack)
5504{
5505 int err;
5506
5507 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
5508 return 0;
5509
5510 if (!reporter->ops->recover)
5511 return -EOPNOTSUPP;
5512
5513 err = reporter->ops->recover(reporter, priv_ctx, extack);
5514 if (err)
5515 return err;
5516
5517 devlink_health_reporter_recovery_done(reporter);
5518 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
5519 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5520
5521 return 0;
5522}
5523
5524static void
5525devlink_health_dump_clear(struct devlink_health_reporter *reporter)
5526{
5527 if (!reporter->dump_fmsg)
5528 return;
5529 devlink_fmsg_free(reporter->dump_fmsg);
5530 reporter->dump_fmsg = NULL;
5531}
5532
5533static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
5534 void *priv_ctx,
5535 struct netlink_ext_ack *extack)
5536{
5537 int err;
5538
5539 if (!reporter->ops->dump)
5540 return 0;
5541
5542 if (reporter->dump_fmsg)
5543 return 0;
5544
5545 reporter->dump_fmsg = devlink_fmsg_alloc();
5546 if (!reporter->dump_fmsg) {
5547 err = -ENOMEM;
5548 return err;
5549 }
5550
5551 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
5552 if (err)
5553 goto dump_err;
5554
5555 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
5556 priv_ctx, extack);
5557 if (err)
5558 goto dump_err;
5559
5560 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
5561 if (err)
5562 goto dump_err;
5563
5564 reporter->dump_ts = jiffies;
5565 reporter->dump_real_ts = ktime_get_real_ns();
5566
5567 return 0;
5568
5569dump_err:
5570 devlink_health_dump_clear(reporter);
5571 return err;
5572}
5573
5574int devlink_health_report(struct devlink_health_reporter *reporter,
5575 const char *msg, void *priv_ctx)
5576{
5577 enum devlink_health_reporter_state prev_health_state;
5578 struct devlink *devlink = reporter->devlink;
Aya Levinbea0c5c2020-05-04 11:27:46 +03005579 unsigned long recover_ts_threshold;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005580
5581 /* write a log message of the current error */
5582 WARN_ON(!msg);
5583 trace_devlink_health_report(devlink, reporter->ops->name, msg);
5584 reporter->error_count++;
5585 prev_health_state = reporter->health_state;
5586 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5587 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5588
5589 /* abort if the previous error wasn't recovered */
Aya Levinbea0c5c2020-05-04 11:27:46 +03005590 recover_ts_threshold = reporter->last_recovery_ts +
5591 msecs_to_jiffies(reporter->graceful_period);
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005592 if (reporter->auto_recover &&
5593 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Aya Levinbea0c5c2020-05-04 11:27:46 +03005594 (reporter->last_recovery_ts && reporter->recovery_count &&
5595 time_is_after_jiffies(recover_ts_threshold)))) {
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005596 trace_devlink_health_recover_aborted(devlink,
5597 reporter->ops->name,
5598 reporter->health_state,
5599 jiffies -
5600 reporter->last_recovery_ts);
5601 return -ECANCELED;
5602 }
5603
5604 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5605
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005606 if (reporter->auto_dump) {
5607 mutex_lock(&reporter->dump_lock);
5608 /* store current dump of current error, for later analysis */
5609 devlink_health_do_dump(reporter, priv_ctx, NULL);
5610 mutex_unlock(&reporter->dump_lock);
5611 }
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005612
5613 if (reporter->auto_recover)
5614 return devlink_health_reporter_recover(reporter,
5615 priv_ctx, NULL);
5616
5617 return 0;
5618}
5619EXPORT_SYMBOL_GPL(devlink_health_report);
5620
5621static struct devlink_health_reporter *
5622devlink_health_reporter_get_from_attrs(struct devlink *devlink,
5623 struct nlattr **attrs)
5624{
5625 struct devlink_health_reporter *reporter;
5626 char *reporter_name;
5627
5628 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
5629 return NULL;
5630
5631 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
5632 mutex_lock(&devlink->reporters_lock);
5633 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
5634 if (reporter)
5635 refcount_inc(&reporter->refcount);
5636 mutex_unlock(&devlink->reporters_lock);
5637 return reporter;
5638}
5639
5640static struct devlink_health_reporter *
5641devlink_health_reporter_get_from_info(struct devlink *devlink,
5642 struct genl_info *info)
5643{
5644 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
5645}
5646
5647static struct devlink_health_reporter *
5648devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
5649{
5650 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
5651 struct devlink_health_reporter *reporter;
5652 struct nlattr **attrs = info->attrs;
5653 struct devlink *devlink;
5654
5655 mutex_lock(&devlink_mutex);
5656 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
5657 if (IS_ERR(devlink))
5658 goto unlock;
5659
5660 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
5661 mutex_unlock(&devlink_mutex);
5662 return reporter;
5663unlock:
5664 mutex_unlock(&devlink_mutex);
5665 return NULL;
5666}
5667
5668static void
5669devlink_health_reporter_put(struct devlink_health_reporter *reporter)
5670{
5671 refcount_dec(&reporter->refcount);
5672}
5673
5674void
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305675devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
5676 enum devlink_health_reporter_state state)
5677{
5678 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
5679 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
5680 return;
5681
5682 if (reporter->health_state == state)
5683 return;
5684
5685 reporter->health_state = state;
5686 trace_devlink_health_reporter_state_update(reporter->devlink,
5687 reporter->ops->name, state);
5688 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5689}
5690EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
5691
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005692static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
5693 struct genl_info *info)
5694{
5695 struct devlink *devlink = info->user_ptr[0];
5696 struct devlink_health_reporter *reporter;
5697 struct sk_buff *msg;
5698 int err;
5699
5700 reporter = devlink_health_reporter_get_from_info(devlink, info);
5701 if (!reporter)
5702 return -EINVAL;
5703
5704 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005705 if (!msg) {
5706 err = -ENOMEM;
5707 goto out;
5708 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005709
5710 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
5711 DEVLINK_CMD_HEALTH_REPORTER_GET,
5712 info->snd_portid, info->snd_seq,
5713 0);
5714 if (err) {
5715 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005716 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005717 }
5718
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005719 err = genlmsg_reply(msg, info);
5720out:
5721 devlink_health_reporter_put(reporter);
5722 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005723}
5724
5725static int
5726devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
5727 struct netlink_callback *cb)
5728{
5729 struct devlink_health_reporter *reporter;
5730 struct devlink *devlink;
5731 int start = cb->args[0];
5732 int idx = 0;
5733 int err;
5734
5735 mutex_lock(&devlink_mutex);
5736 list_for_each_entry(devlink, &devlink_list, list) {
5737 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5738 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005739 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005740 list_for_each_entry(reporter, &devlink->reporter_list,
5741 list) {
5742 if (idx < start) {
5743 idx++;
5744 continue;
5745 }
5746 err = devlink_nl_health_reporter_fill(msg, devlink,
5747 reporter,
5748 DEVLINK_CMD_HEALTH_REPORTER_GET,
5749 NETLINK_CB(cb->skb).portid,
5750 cb->nlh->nlmsg_seq,
5751 NLM_F_MULTI);
5752 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005753 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005754 goto out;
5755 }
5756 idx++;
5757 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005758 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005759 }
5760out:
5761 mutex_unlock(&devlink_mutex);
5762
5763 cb->args[0] = idx;
5764 return msg->len;
5765}
5766
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005767static int
5768devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
5769 struct genl_info *info)
5770{
5771 struct devlink *devlink = info->user_ptr[0];
5772 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005773 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005774
5775 reporter = devlink_health_reporter_get_from_info(devlink, info);
5776 if (!reporter)
5777 return -EINVAL;
5778
5779 if (!reporter->ops->recover &&
5780 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005781 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
5782 err = -EOPNOTSUPP;
5783 goto out;
5784 }
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005785 if (!reporter->ops->dump &&
5786 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
5787 err = -EOPNOTSUPP;
5788 goto out;
5789 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005790
5791 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
5792 reporter->graceful_period =
5793 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
5794
5795 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
5796 reporter->auto_recover =
5797 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
5798
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005799 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
5800 reporter->auto_dump =
5801 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
5802
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005803 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005804 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005805out:
5806 devlink_health_reporter_put(reporter);
5807 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005808}
5809
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005810static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
5811 struct genl_info *info)
5812{
5813 struct devlink *devlink = info->user_ptr[0];
5814 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005815 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005816
5817 reporter = devlink_health_reporter_get_from_info(devlink, info);
5818 if (!reporter)
5819 return -EINVAL;
5820
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005821 err = devlink_health_reporter_recover(reporter, NULL, info->extack);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005822
5823 devlink_health_reporter_put(reporter);
5824 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005825}
5826
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005827static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
5828 struct genl_info *info)
5829{
5830 struct devlink *devlink = info->user_ptr[0];
5831 struct devlink_health_reporter *reporter;
5832 struct devlink_fmsg *fmsg;
5833 int err;
5834
5835 reporter = devlink_health_reporter_get_from_info(devlink, info);
5836 if (!reporter)
5837 return -EINVAL;
5838
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005839 if (!reporter->ops->diagnose) {
5840 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005841 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005842 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005843
5844 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005845 if (!fmsg) {
5846 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005847 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005848 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005849
5850 err = devlink_fmsg_obj_nest_start(fmsg);
5851 if (err)
5852 goto out;
5853
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005854 err = reporter->ops->diagnose(reporter, fmsg, info->extack);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005855 if (err)
5856 goto out;
5857
5858 err = devlink_fmsg_obj_nest_end(fmsg);
5859 if (err)
5860 goto out;
5861
5862 err = devlink_fmsg_snd(fmsg, info,
5863 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
5864
5865out:
5866 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005867 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005868 return err;
5869}
5870
Aya Levine44ef4e2019-05-16 09:49:20 +03005871static int
5872devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
5873 struct netlink_callback *cb)
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005874{
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005875 struct devlink_health_reporter *reporter;
Aya Levine44ef4e2019-05-16 09:49:20 +03005876 u64 start = cb->args[0];
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005877 int err;
5878
Aya Levine44ef4e2019-05-16 09:49:20 +03005879 reporter = devlink_health_reporter_get_from_cb(cb);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005880 if (!reporter)
5881 return -EINVAL;
5882
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005883 if (!reporter->ops->dump) {
Aya Levine44ef4e2019-05-16 09:49:20 +03005884 err = -EOPNOTSUPP;
5885 goto out;
5886 }
5887 mutex_lock(&reporter->dump_lock);
5888 if (!start) {
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005889 err = devlink_health_do_dump(reporter, NULL, cb->extack);
Aya Levine44ef4e2019-05-16 09:49:20 +03005890 if (err)
5891 goto unlock;
5892 cb->args[1] = reporter->dump_ts;
5893 }
5894 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
5895 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
5896 err = -EAGAIN;
5897 goto unlock;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005898 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005899
Aya Levine44ef4e2019-05-16 09:49:20 +03005900 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
5901 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
5902unlock:
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005903 mutex_unlock(&reporter->dump_lock);
Aya Levine44ef4e2019-05-16 09:49:20 +03005904out:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005905 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005906 return err;
5907}
5908
5909static int
5910devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
5911 struct genl_info *info)
5912{
5913 struct devlink *devlink = info->user_ptr[0];
5914 struct devlink_health_reporter *reporter;
5915
5916 reporter = devlink_health_reporter_get_from_info(devlink, info);
5917 if (!reporter)
5918 return -EINVAL;
5919
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005920 if (!reporter->ops->dump) {
5921 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005922 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005923 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005924
5925 mutex_lock(&reporter->dump_lock);
5926 devlink_health_dump_clear(reporter);
5927 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005928 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005929 return 0;
5930}
5931
Ido Schimmel0f420b62019-08-17 16:28:17 +03005932struct devlink_stats {
5933 u64 rx_bytes;
5934 u64 rx_packets;
5935 struct u64_stats_sync syncp;
5936};
5937
5938/**
Ido Schimmel1e8c6612020-03-30 22:38:18 +03005939 * struct devlink_trap_policer_item - Packet trap policer attributes.
5940 * @policer: Immutable packet trap policer attributes.
5941 * @rate: Rate in packets / sec.
5942 * @burst: Burst size in packets.
5943 * @list: trap_policer_list member.
5944 *
5945 * Describes packet trap policer attributes. Created by devlink during trap
5946 * policer registration.
5947 */
5948struct devlink_trap_policer_item {
5949 const struct devlink_trap_policer *policer;
5950 u64 rate;
5951 u64 burst;
5952 struct list_head list;
5953};
5954
5955/**
Ido Schimmel0f420b62019-08-17 16:28:17 +03005956 * struct devlink_trap_group_item - Packet trap group attributes.
5957 * @group: Immutable packet trap group attributes.
Ido Schimmelf9f54392020-03-30 22:38:21 +03005958 * @policer_item: Associated policer item. Can be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03005959 * @list: trap_group_list member.
5960 * @stats: Trap group statistics.
5961 *
5962 * Describes packet trap group attributes. Created by devlink during trap
Ido Schimmela09b37f2020-03-22 20:48:29 +02005963 * group registration.
Ido Schimmel0f420b62019-08-17 16:28:17 +03005964 */
5965struct devlink_trap_group_item {
5966 const struct devlink_trap_group *group;
Ido Schimmelf9f54392020-03-30 22:38:21 +03005967 struct devlink_trap_policer_item *policer_item;
Ido Schimmel0f420b62019-08-17 16:28:17 +03005968 struct list_head list;
5969 struct devlink_stats __percpu *stats;
5970};
5971
5972/**
5973 * struct devlink_trap_item - Packet trap attributes.
5974 * @trap: Immutable packet trap attributes.
5975 * @group_item: Associated group item.
5976 * @list: trap_list member.
5977 * @action: Trap action.
5978 * @stats: Trap statistics.
5979 * @priv: Driver private information.
5980 *
5981 * Describes both mutable and immutable packet trap attributes. Created by
5982 * devlink during trap registration and used for all trap related operations.
5983 */
5984struct devlink_trap_item {
5985 const struct devlink_trap *trap;
5986 struct devlink_trap_group_item *group_item;
5987 struct list_head list;
5988 enum devlink_trap_action action;
5989 struct devlink_stats __percpu *stats;
5990 void *priv;
5991};
5992
Ido Schimmel1e8c6612020-03-30 22:38:18 +03005993static struct devlink_trap_policer_item *
5994devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
5995{
5996 struct devlink_trap_policer_item *policer_item;
5997
5998 list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
5999 if (policer_item->policer->id == id)
6000 return policer_item;
6001 }
6002
6003 return NULL;
6004}
6005
Ido Schimmel0f420b62019-08-17 16:28:17 +03006006static struct devlink_trap_item *
6007devlink_trap_item_lookup(struct devlink *devlink, const char *name)
6008{
6009 struct devlink_trap_item *trap_item;
6010
6011 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6012 if (!strcmp(trap_item->trap->name, name))
6013 return trap_item;
6014 }
6015
6016 return NULL;
6017}
6018
6019static struct devlink_trap_item *
6020devlink_trap_item_get_from_info(struct devlink *devlink,
6021 struct genl_info *info)
6022{
6023 struct nlattr *attr;
6024
6025 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
6026 return NULL;
6027 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
6028
6029 return devlink_trap_item_lookup(devlink, nla_data(attr));
6030}
6031
6032static int
6033devlink_trap_action_get_from_info(struct genl_info *info,
6034 enum devlink_trap_action *p_trap_action)
6035{
6036 u8 val;
6037
6038 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
6039 switch (val) {
6040 case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
Ido Schimmel9eefeab2020-05-29 21:36:39 +03006041 case DEVLINK_TRAP_ACTION_TRAP: /* fall-through */
6042 case DEVLINK_TRAP_ACTION_MIRROR:
Ido Schimmel0f420b62019-08-17 16:28:17 +03006043 *p_trap_action = val;
6044 break;
6045 default:
6046 return -EINVAL;
6047 }
6048
6049 return 0;
6050}
6051
6052static int devlink_trap_metadata_put(struct sk_buff *msg,
6053 const struct devlink_trap *trap)
6054{
6055 struct nlattr *attr;
6056
6057 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
6058 if (!attr)
6059 return -EMSGSIZE;
6060
6061 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
6062 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
6063 goto nla_put_failure;
Jiri Pirko85b05892020-02-25 11:45:19 +01006064 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
6065 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
6066 goto nla_put_failure;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006067
6068 nla_nest_end(msg, attr);
6069
6070 return 0;
6071
6072nla_put_failure:
6073 nla_nest_cancel(msg, attr);
6074 return -EMSGSIZE;
6075}
6076
6077static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
6078 struct devlink_stats *stats)
6079{
6080 int i;
6081
6082 memset(stats, 0, sizeof(*stats));
6083 for_each_possible_cpu(i) {
6084 struct devlink_stats *cpu_stats;
6085 u64 rx_packets, rx_bytes;
6086 unsigned int start;
6087
6088 cpu_stats = per_cpu_ptr(trap_stats, i);
6089 do {
6090 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
6091 rx_packets = cpu_stats->rx_packets;
6092 rx_bytes = cpu_stats->rx_bytes;
6093 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
6094
6095 stats->rx_packets += rx_packets;
6096 stats->rx_bytes += rx_bytes;
6097 }
6098}
6099
6100static int devlink_trap_stats_put(struct sk_buff *msg,
6101 struct devlink_stats __percpu *trap_stats)
6102{
6103 struct devlink_stats stats;
6104 struct nlattr *attr;
6105
6106 devlink_trap_stats_read(trap_stats, &stats);
6107
6108 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6109 if (!attr)
6110 return -EMSGSIZE;
6111
6112 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
6113 stats.rx_packets, DEVLINK_ATTR_PAD))
6114 goto nla_put_failure;
6115
6116 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
6117 stats.rx_bytes, DEVLINK_ATTR_PAD))
6118 goto nla_put_failure;
6119
6120 nla_nest_end(msg, attr);
6121
6122 return 0;
6123
6124nla_put_failure:
6125 nla_nest_cancel(msg, attr);
6126 return -EMSGSIZE;
6127}
6128
6129static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
6130 const struct devlink_trap_item *trap_item,
6131 enum devlink_command cmd, u32 portid, u32 seq,
6132 int flags)
6133{
6134 struct devlink_trap_group_item *group_item = trap_item->group_item;
6135 void *hdr;
6136 int err;
6137
6138 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6139 if (!hdr)
6140 return -EMSGSIZE;
6141
6142 if (devlink_nl_put_handle(msg, devlink))
6143 goto nla_put_failure;
6144
6145 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6146 group_item->group->name))
6147 goto nla_put_failure;
6148
6149 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
6150 goto nla_put_failure;
6151
6152 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
6153 goto nla_put_failure;
6154
6155 if (trap_item->trap->generic &&
6156 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6157 goto nla_put_failure;
6158
6159 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
6160 goto nla_put_failure;
6161
6162 err = devlink_trap_metadata_put(msg, trap_item->trap);
6163 if (err)
6164 goto nla_put_failure;
6165
6166 err = devlink_trap_stats_put(msg, trap_item->stats);
6167 if (err)
6168 goto nla_put_failure;
6169
6170 genlmsg_end(msg, hdr);
6171
6172 return 0;
6173
6174nla_put_failure:
6175 genlmsg_cancel(msg, hdr);
6176 return -EMSGSIZE;
6177}
6178
6179static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
6180 struct genl_info *info)
6181{
6182 struct netlink_ext_ack *extack = info->extack;
6183 struct devlink *devlink = info->user_ptr[0];
6184 struct devlink_trap_item *trap_item;
6185 struct sk_buff *msg;
6186 int err;
6187
6188 if (list_empty(&devlink->trap_list))
6189 return -EOPNOTSUPP;
6190
6191 trap_item = devlink_trap_item_get_from_info(devlink, info);
6192 if (!trap_item) {
6193 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6194 return -ENOENT;
6195 }
6196
6197 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6198 if (!msg)
6199 return -ENOMEM;
6200
6201 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6202 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
6203 info->snd_seq, 0);
6204 if (err)
6205 goto err_trap_fill;
6206
6207 return genlmsg_reply(msg, info);
6208
6209err_trap_fill:
6210 nlmsg_free(msg);
6211 return err;
6212}
6213
6214static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
6215 struct netlink_callback *cb)
6216{
6217 struct devlink_trap_item *trap_item;
6218 struct devlink *devlink;
6219 int start = cb->args[0];
6220 int idx = 0;
6221 int err;
6222
6223 mutex_lock(&devlink_mutex);
6224 list_for_each_entry(devlink, &devlink_list, list) {
6225 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6226 continue;
6227 mutex_lock(&devlink->lock);
6228 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6229 if (idx < start) {
6230 idx++;
6231 continue;
6232 }
6233 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6234 DEVLINK_CMD_TRAP_NEW,
6235 NETLINK_CB(cb->skb).portid,
6236 cb->nlh->nlmsg_seq,
6237 NLM_F_MULTI);
6238 if (err) {
6239 mutex_unlock(&devlink->lock);
6240 goto out;
6241 }
6242 idx++;
6243 }
6244 mutex_unlock(&devlink->lock);
6245 }
6246out:
6247 mutex_unlock(&devlink_mutex);
6248
6249 cb->args[0] = idx;
6250 return msg->len;
6251}
6252
6253static int __devlink_trap_action_set(struct devlink *devlink,
6254 struct devlink_trap_item *trap_item,
6255 enum devlink_trap_action trap_action,
6256 struct netlink_ext_ack *extack)
6257{
6258 int err;
6259
6260 if (trap_item->action != trap_action &&
6261 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
6262 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
6263 return 0;
6264 }
6265
6266 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
6267 trap_action);
6268 if (err)
6269 return err;
6270
6271 trap_item->action = trap_action;
6272
6273 return 0;
6274}
6275
6276static int devlink_trap_action_set(struct devlink *devlink,
6277 struct devlink_trap_item *trap_item,
6278 struct genl_info *info)
6279{
6280 enum devlink_trap_action trap_action;
6281 int err;
6282
6283 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6284 return 0;
6285
6286 err = devlink_trap_action_get_from_info(info, &trap_action);
6287 if (err) {
6288 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6289 return -EINVAL;
6290 }
6291
6292 return __devlink_trap_action_set(devlink, trap_item, trap_action,
6293 info->extack);
6294}
6295
6296static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
6297 struct genl_info *info)
6298{
6299 struct netlink_ext_ack *extack = info->extack;
6300 struct devlink *devlink = info->user_ptr[0];
6301 struct devlink_trap_item *trap_item;
6302 int err;
6303
6304 if (list_empty(&devlink->trap_list))
6305 return -EOPNOTSUPP;
6306
6307 trap_item = devlink_trap_item_get_from_info(devlink, info);
6308 if (!trap_item) {
6309 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6310 return -ENOENT;
6311 }
6312
6313 err = devlink_trap_action_set(devlink, trap_item, info);
6314 if (err)
6315 return err;
6316
6317 return 0;
6318}
6319
6320static struct devlink_trap_group_item *
6321devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
6322{
6323 struct devlink_trap_group_item *group_item;
6324
6325 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6326 if (!strcmp(group_item->group->name, name))
6327 return group_item;
6328 }
6329
6330 return NULL;
6331}
6332
6333static struct devlink_trap_group_item *
Ido Schimmel107f1672020-03-22 20:48:30 +02006334devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
6335{
6336 struct devlink_trap_group_item *group_item;
6337
6338 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6339 if (group_item->group->id == id)
6340 return group_item;
6341 }
6342
6343 return NULL;
6344}
6345
6346static struct devlink_trap_group_item *
Ido Schimmel0f420b62019-08-17 16:28:17 +03006347devlink_trap_group_item_get_from_info(struct devlink *devlink,
6348 struct genl_info *info)
6349{
6350 char *name;
6351
6352 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
6353 return NULL;
6354 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
6355
6356 return devlink_trap_group_item_lookup(devlink, name);
6357}
6358
6359static int
6360devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
6361 const struct devlink_trap_group_item *group_item,
6362 enum devlink_command cmd, u32 portid, u32 seq,
6363 int flags)
6364{
6365 void *hdr;
6366 int err;
6367
6368 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6369 if (!hdr)
6370 return -EMSGSIZE;
6371
6372 if (devlink_nl_put_handle(msg, devlink))
6373 goto nla_put_failure;
6374
6375 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6376 group_item->group->name))
6377 goto nla_put_failure;
6378
6379 if (group_item->group->generic &&
6380 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6381 goto nla_put_failure;
6382
Ido Schimmelf9f54392020-03-30 22:38:21 +03006383 if (group_item->policer_item &&
6384 nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6385 group_item->policer_item->policer->id))
6386 goto nla_put_failure;
6387
Ido Schimmel0f420b62019-08-17 16:28:17 +03006388 err = devlink_trap_stats_put(msg, group_item->stats);
6389 if (err)
6390 goto nla_put_failure;
6391
6392 genlmsg_end(msg, hdr);
6393
6394 return 0;
6395
6396nla_put_failure:
6397 genlmsg_cancel(msg, hdr);
6398 return -EMSGSIZE;
6399}
6400
6401static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
6402 struct genl_info *info)
6403{
6404 struct netlink_ext_ack *extack = info->extack;
6405 struct devlink *devlink = info->user_ptr[0];
6406 struct devlink_trap_group_item *group_item;
6407 struct sk_buff *msg;
6408 int err;
6409
6410 if (list_empty(&devlink->trap_group_list))
6411 return -EOPNOTSUPP;
6412
6413 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6414 if (!group_item) {
6415 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6416 return -ENOENT;
6417 }
6418
6419 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6420 if (!msg)
6421 return -ENOMEM;
6422
6423 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
6424 DEVLINK_CMD_TRAP_GROUP_NEW,
6425 info->snd_portid, info->snd_seq, 0);
6426 if (err)
6427 goto err_trap_group_fill;
6428
6429 return genlmsg_reply(msg, info);
6430
6431err_trap_group_fill:
6432 nlmsg_free(msg);
6433 return err;
6434}
6435
6436static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
6437 struct netlink_callback *cb)
6438{
6439 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
6440 struct devlink_trap_group_item *group_item;
6441 u32 portid = NETLINK_CB(cb->skb).portid;
6442 struct devlink *devlink;
6443 int start = cb->args[0];
6444 int idx = 0;
6445 int err;
6446
6447 mutex_lock(&devlink_mutex);
6448 list_for_each_entry(devlink, &devlink_list, list) {
6449 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6450 continue;
6451 mutex_lock(&devlink->lock);
6452 list_for_each_entry(group_item, &devlink->trap_group_list,
6453 list) {
6454 if (idx < start) {
6455 idx++;
6456 continue;
6457 }
6458 err = devlink_nl_trap_group_fill(msg, devlink,
6459 group_item, cmd,
6460 portid,
6461 cb->nlh->nlmsg_seq,
6462 NLM_F_MULTI);
6463 if (err) {
6464 mutex_unlock(&devlink->lock);
6465 goto out;
6466 }
6467 idx++;
6468 }
6469 mutex_unlock(&devlink->lock);
6470 }
6471out:
6472 mutex_unlock(&devlink_mutex);
6473
6474 cb->args[0] = idx;
6475 return msg->len;
6476}
6477
6478static int
6479__devlink_trap_group_action_set(struct devlink *devlink,
6480 struct devlink_trap_group_item *group_item,
6481 enum devlink_trap_action trap_action,
6482 struct netlink_ext_ack *extack)
6483{
6484 const char *group_name = group_item->group->name;
6485 struct devlink_trap_item *trap_item;
6486 int err;
6487
6488 list_for_each_entry(trap_item, &devlink->trap_list, list) {
Ido Schimmel107f1672020-03-22 20:48:30 +02006489 if (strcmp(trap_item->group_item->group->name, group_name))
Ido Schimmel0f420b62019-08-17 16:28:17 +03006490 continue;
6491 err = __devlink_trap_action_set(devlink, trap_item,
6492 trap_action, extack);
6493 if (err)
6494 return err;
6495 }
6496
6497 return 0;
6498}
6499
6500static int
6501devlink_trap_group_action_set(struct devlink *devlink,
6502 struct devlink_trap_group_item *group_item,
Ido Schimmelc0648752020-03-30 22:38:22 +03006503 struct genl_info *info, bool *p_modified)
Ido Schimmel0f420b62019-08-17 16:28:17 +03006504{
6505 enum devlink_trap_action trap_action;
6506 int err;
6507
6508 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6509 return 0;
6510
6511 err = devlink_trap_action_get_from_info(info, &trap_action);
6512 if (err) {
6513 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6514 return -EINVAL;
6515 }
6516
6517 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
6518 info->extack);
6519 if (err)
6520 return err;
6521
Ido Schimmelc0648752020-03-30 22:38:22 +03006522 *p_modified = true;
6523
6524 return 0;
6525}
6526
6527static int devlink_trap_group_set(struct devlink *devlink,
6528 struct devlink_trap_group_item *group_item,
6529 struct genl_info *info)
6530{
6531 struct devlink_trap_policer_item *policer_item;
6532 struct netlink_ext_ack *extack = info->extack;
6533 const struct devlink_trap_policer *policer;
6534 struct nlattr **attrs = info->attrs;
6535 int err;
6536
6537 if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6538 return 0;
6539
6540 if (!devlink->ops->trap_group_set)
6541 return -EOPNOTSUPP;
6542
6543 policer_item = group_item->policer_item;
6544 if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) {
6545 u32 policer_id;
6546
6547 policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6548 policer_item = devlink_trap_policer_item_lookup(devlink,
6549 policer_id);
6550 if (policer_id && !policer_item) {
6551 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6552 return -ENOENT;
6553 }
6554 }
6555 policer = policer_item ? policer_item->policer : NULL;
6556
6557 err = devlink->ops->trap_group_set(devlink, group_item->group, policer);
6558 if (err)
6559 return err;
6560
6561 group_item->policer_item = policer_item;
6562
Ido Schimmel0f420b62019-08-17 16:28:17 +03006563 return 0;
6564}
6565
6566static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
6567 struct genl_info *info)
6568{
6569 struct netlink_ext_ack *extack = info->extack;
6570 struct devlink *devlink = info->user_ptr[0];
6571 struct devlink_trap_group_item *group_item;
Ido Schimmelc0648752020-03-30 22:38:22 +03006572 bool modified = false;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006573 int err;
6574
6575 if (list_empty(&devlink->trap_group_list))
6576 return -EOPNOTSUPP;
6577
6578 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6579 if (!group_item) {
6580 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6581 return -ENOENT;
6582 }
6583
Ido Schimmelc0648752020-03-30 22:38:22 +03006584 err = devlink_trap_group_action_set(devlink, group_item, info,
6585 &modified);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006586 if (err)
6587 return err;
6588
Ido Schimmelc0648752020-03-30 22:38:22 +03006589 err = devlink_trap_group_set(devlink, group_item, info);
6590 if (err)
6591 goto err_trap_group_set;
6592
Ido Schimmel0f420b62019-08-17 16:28:17 +03006593 return 0;
Ido Schimmelc0648752020-03-30 22:38:22 +03006594
6595err_trap_group_set:
6596 if (modified)
6597 NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already");
6598 return err;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006599}
6600
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006601static struct devlink_trap_policer_item *
6602devlink_trap_policer_item_get_from_info(struct devlink *devlink,
6603 struct genl_info *info)
6604{
6605 u32 id;
6606
6607 if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6608 return NULL;
6609 id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6610
6611 return devlink_trap_policer_item_lookup(devlink, id);
6612}
6613
6614static int
6615devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
6616 const struct devlink_trap_policer *policer)
6617{
6618 struct nlattr *attr;
6619 u64 drops;
6620 int err;
6621
6622 if (!devlink->ops->trap_policer_counter_get)
6623 return 0;
6624
6625 err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
6626 if (err)
6627 return err;
6628
6629 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6630 if (!attr)
6631 return -EMSGSIZE;
6632
6633 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
6634 DEVLINK_ATTR_PAD))
6635 goto nla_put_failure;
6636
6637 nla_nest_end(msg, attr);
6638
6639 return 0;
6640
6641nla_put_failure:
6642 nla_nest_cancel(msg, attr);
6643 return -EMSGSIZE;
6644}
6645
6646static int
6647devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
6648 const struct devlink_trap_policer_item *policer_item,
6649 enum devlink_command cmd, u32 portid, u32 seq,
6650 int flags)
6651{
6652 void *hdr;
6653 int err;
6654
6655 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6656 if (!hdr)
6657 return -EMSGSIZE;
6658
6659 if (devlink_nl_put_handle(msg, devlink))
6660 goto nla_put_failure;
6661
6662 if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6663 policer_item->policer->id))
6664 goto nla_put_failure;
6665
6666 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
6667 policer_item->rate, DEVLINK_ATTR_PAD))
6668 goto nla_put_failure;
6669
6670 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
6671 policer_item->burst, DEVLINK_ATTR_PAD))
6672 goto nla_put_failure;
6673
6674 err = devlink_trap_policer_stats_put(msg, devlink,
6675 policer_item->policer);
6676 if (err)
6677 goto nla_put_failure;
6678
6679 genlmsg_end(msg, hdr);
6680
6681 return 0;
6682
6683nla_put_failure:
6684 genlmsg_cancel(msg, hdr);
6685 return -EMSGSIZE;
6686}
6687
6688static int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
6689 struct genl_info *info)
6690{
6691 struct devlink_trap_policer_item *policer_item;
6692 struct netlink_ext_ack *extack = info->extack;
6693 struct devlink *devlink = info->user_ptr[0];
6694 struct sk_buff *msg;
6695 int err;
6696
6697 if (list_empty(&devlink->trap_policer_list))
6698 return -EOPNOTSUPP;
6699
6700 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
6701 if (!policer_item) {
6702 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6703 return -ENOENT;
6704 }
6705
6706 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6707 if (!msg)
6708 return -ENOMEM;
6709
6710 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
6711 DEVLINK_CMD_TRAP_POLICER_NEW,
6712 info->snd_portid, info->snd_seq, 0);
6713 if (err)
6714 goto err_trap_policer_fill;
6715
6716 return genlmsg_reply(msg, info);
6717
6718err_trap_policer_fill:
6719 nlmsg_free(msg);
6720 return err;
6721}
6722
6723static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,
6724 struct netlink_callback *cb)
6725{
6726 enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW;
6727 struct devlink_trap_policer_item *policer_item;
6728 u32 portid = NETLINK_CB(cb->skb).portid;
6729 struct devlink *devlink;
6730 int start = cb->args[0];
6731 int idx = 0;
6732 int err;
6733
6734 mutex_lock(&devlink_mutex);
6735 list_for_each_entry(devlink, &devlink_list, list) {
6736 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6737 continue;
6738 mutex_lock(&devlink->lock);
6739 list_for_each_entry(policer_item, &devlink->trap_policer_list,
6740 list) {
6741 if (idx < start) {
6742 idx++;
6743 continue;
6744 }
6745 err = devlink_nl_trap_policer_fill(msg, devlink,
6746 policer_item, cmd,
6747 portid,
6748 cb->nlh->nlmsg_seq,
6749 NLM_F_MULTI);
6750 if (err) {
6751 mutex_unlock(&devlink->lock);
6752 goto out;
6753 }
6754 idx++;
6755 }
6756 mutex_unlock(&devlink->lock);
6757 }
6758out:
6759 mutex_unlock(&devlink_mutex);
6760
6761 cb->args[0] = idx;
6762 return msg->len;
6763}
6764
6765static int
6766devlink_trap_policer_set(struct devlink *devlink,
6767 struct devlink_trap_policer_item *policer_item,
6768 struct genl_info *info)
6769{
6770 struct netlink_ext_ack *extack = info->extack;
6771 struct nlattr **attrs = info->attrs;
6772 u64 rate, burst;
6773 int err;
6774
6775 rate = policer_item->rate;
6776 burst = policer_item->burst;
6777
6778 if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
6779 rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
6780
6781 if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
6782 burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
6783
6784 if (rate < policer_item->policer->min_rate) {
6785 NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
6786 return -EINVAL;
6787 }
6788
6789 if (rate > policer_item->policer->max_rate) {
6790 NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
6791 return -EINVAL;
6792 }
6793
6794 if (burst < policer_item->policer->min_burst) {
6795 NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
6796 return -EINVAL;
6797 }
6798
6799 if (burst > policer_item->policer->max_burst) {
6800 NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
6801 return -EINVAL;
6802 }
6803
6804 err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
6805 rate, burst, info->extack);
6806 if (err)
6807 return err;
6808
6809 policer_item->rate = rate;
6810 policer_item->burst = burst;
6811
6812 return 0;
6813}
6814
6815static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
6816 struct genl_info *info)
6817{
6818 struct devlink_trap_policer_item *policer_item;
6819 struct netlink_ext_ack *extack = info->extack;
6820 struct devlink *devlink = info->user_ptr[0];
6821
6822 if (list_empty(&devlink->trap_policer_list))
6823 return -EOPNOTSUPP;
6824
6825 if (!devlink->ops->trap_policer_set)
6826 return -EOPNOTSUPP;
6827
6828 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
6829 if (!policer_item) {
6830 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6831 return -ENOENT;
6832 }
6833
6834 return devlink_trap_policer_set(devlink, policer_item, info);
6835}
6836
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006837static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006838 [DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
6839 DEVLINK_ATTR_TRAP_POLICER_ID },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006840 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
6841 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
6842 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
6843 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
6844 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02006845 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
6846 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
6847 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
6848 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
6849 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
6850 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
6851 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03006852 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
Roi Dayan59bfde02016-11-22 23:09:57 +02006853 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03006854 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006855 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
6856 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006857 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
6858 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03006859 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
6860 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
6861 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03006862 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03006863 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Jakub Kicinskiff3b63b2020-03-02 21:05:12 -08006864 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
6865 [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006866 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006867 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
6868 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08006869 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
6870 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Ido Schimmel0f420b62019-08-17 16:28:17 +03006871 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
6872 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
6873 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
Jiri Pirko070c63f2019-10-03 11:49:39 +02006874 [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
6875 [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
6876 [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006877 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006878 [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
6879 [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
6880 [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
Parav Pandita1e8ae92020-06-19 03:32:49 +00006881 [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006882};
6883
6884static const struct genl_ops devlink_nl_ops[] = {
6885 {
6886 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006887 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006888 .doit = devlink_nl_cmd_get_doit,
6889 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirko1fc22572016-04-08 19:12:48 +02006890 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006891 /* can be retrieved by unprivileged users */
6892 },
6893 {
6894 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006895 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006896 .doit = devlink_nl_cmd_port_get_doit,
6897 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006898 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
6899 /* can be retrieved by unprivileged users */
6900 },
6901 {
6902 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006903 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006904 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006905 .flags = GENL_ADMIN_PERM,
6906 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
6907 },
6908 {
6909 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02006910 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006911 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006912 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006913 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6914 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006915 },
6916 {
6917 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02006918 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006919 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006920 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006921 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6922 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006923 },
Jiri Pirkobf797472016-04-14 18:19:13 +02006924 {
6925 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006926 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006927 .doit = devlink_nl_cmd_sb_get_doit,
6928 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006929 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6930 DEVLINK_NL_FLAG_NEED_SB,
6931 /* can be retrieved by unprivileged users */
6932 },
6933 {
6934 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006935 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006936 .doit = devlink_nl_cmd_sb_pool_get_doit,
6937 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006938 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6939 DEVLINK_NL_FLAG_NEED_SB,
6940 /* can be retrieved by unprivileged users */
6941 },
6942 {
6943 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006944 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006945 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006946 .flags = GENL_ADMIN_PERM,
6947 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6948 DEVLINK_NL_FLAG_NEED_SB,
6949 },
6950 {
6951 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006952 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006953 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
6954 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006955 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
6956 DEVLINK_NL_FLAG_NEED_SB,
6957 /* can be retrieved by unprivileged users */
6958 },
6959 {
6960 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006961 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006962 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006963 .flags = GENL_ADMIN_PERM,
6964 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
6965 DEVLINK_NL_FLAG_NEED_SB,
6966 },
6967 {
6968 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006969 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006970 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
6971 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006972 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
6973 DEVLINK_NL_FLAG_NEED_SB,
6974 /* can be retrieved by unprivileged users */
6975 },
6976 {
6977 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006978 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02006979 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02006980 .flags = GENL_ADMIN_PERM,
6981 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
6982 DEVLINK_NL_FLAG_NEED_SB,
6983 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006984 {
6985 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02006986 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006987 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006988 .flags = GENL_ADMIN_PERM,
6989 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006990 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006991 },
6992 {
6993 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02006994 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006995 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006996 .flags = GENL_ADMIN_PERM,
6997 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006998 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02006999 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03007000 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007001 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007002 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007003 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007004 .flags = GENL_ADMIN_PERM,
Parav Pandit98fed6e2020-02-23 19:06:56 -06007005 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7006 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007007 },
7008 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007009 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007010 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007011 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007012 .flags = GENL_ADMIN_PERM,
Jakub Kicinski7ac1cc92018-05-21 22:12:50 -07007013 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7014 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007015 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007016 {
7017 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007018 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007019 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007020 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007021 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007022 },
7023 {
7024 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007025 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007026 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007027 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007028 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007029 },
7030 {
7031 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007032 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007033 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007034 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007035 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007036 },
7037 {
7038 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007039 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007040 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007041 .flags = GENL_ADMIN_PERM,
7042 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7043 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007044 {
7045 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007046 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007047 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007048 .flags = GENL_ADMIN_PERM,
7049 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7050 },
7051 {
7052 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02007053 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007054 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007055 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007056 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007057 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007058 {
7059 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02007060 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007061 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007062 .flags = GENL_ADMIN_PERM,
7063 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7064 DEVLINK_NL_FLAG_NO_LOCK,
7065 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007066 {
7067 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007068 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007069 .doit = devlink_nl_cmd_param_get_doit,
7070 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007071 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7072 /* can be retrieved by unprivileged users */
7073 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007074 {
7075 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007076 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007077 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007078 .flags = GENL_ADMIN_PERM,
7079 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7080 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007081 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307082 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007083 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307084 .doit = devlink_nl_cmd_port_param_get_doit,
7085 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307086 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7087 /* can be retrieved by unprivileged users */
7088 },
7089 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05307090 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007091 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307092 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307093 .flags = GENL_ADMIN_PERM,
7094 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7095 },
7096 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007097 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007098 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007099 .doit = devlink_nl_cmd_region_get_doit,
7100 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007101 .flags = GENL_ADMIN_PERM,
7102 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7103 },
Alex Vesker866319b2018-07-12 15:13:13 +03007104 {
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07007105 .cmd = DEVLINK_CMD_REGION_NEW,
7106 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7107 .doit = devlink_nl_cmd_region_new,
7108 .flags = GENL_ADMIN_PERM,
7109 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7110 },
7111 {
Alex Vesker866319b2018-07-12 15:13:13 +03007112 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02007113 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03007114 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03007115 .flags = GENL_ADMIN_PERM,
7116 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7117 },
Alex Vesker4e547952018-07-12 15:13:14 +03007118 {
7119 .cmd = DEVLINK_CMD_REGION_READ,
Jiri Pirkoee85da52019-10-05 20:04:42 +02007120 .validate = GENL_DONT_VALIDATE_STRICT |
7121 GENL_DONT_VALIDATE_DUMP_STRICT,
Alex Vesker4e547952018-07-12 15:13:14 +03007122 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03007123 .flags = GENL_ADMIN_PERM,
7124 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7125 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007126 {
7127 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007128 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007129 .doit = devlink_nl_cmd_info_get_doit,
7130 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007131 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7132 /* can be retrieved by unprivileged users */
7133 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007134 {
7135 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007136 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007137 .doit = devlink_nl_cmd_health_reporter_get_doit,
7138 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007139 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7140 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007141 /* can be retrieved by unprivileged users */
7142 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007143 {
7144 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007145 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007146 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007147 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007148 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7149 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007150 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007151 {
7152 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02007153 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007154 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007155 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007156 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7157 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007158 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007159 {
7160 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007161 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007162 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007163 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007164 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7165 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007166 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007167 {
7168 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Jiri Pirko82a843d2019-10-07 09:28:31 +02007169 .validate = GENL_DONT_VALIDATE_STRICT |
7170 GENL_DONT_VALIDATE_DUMP_STRICT,
Aya Levine44ef4e2019-05-16 09:49:20 +03007171 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007172 .flags = GENL_ADMIN_PERM,
7173 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7174 DEVLINK_NL_FLAG_NO_LOCK,
7175 },
7176 {
7177 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007178 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007179 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007180 .flags = GENL_ADMIN_PERM,
7181 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7182 DEVLINK_NL_FLAG_NO_LOCK,
7183 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007184 {
7185 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007186 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007187 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007188 .flags = GENL_ADMIN_PERM,
7189 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7190 },
Ido Schimmel0f420b62019-08-17 16:28:17 +03007191 {
7192 .cmd = DEVLINK_CMD_TRAP_GET,
7193 .doit = devlink_nl_cmd_trap_get_doit,
7194 .dumpit = devlink_nl_cmd_trap_get_dumpit,
7195 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7196 /* can be retrieved by unprivileged users */
7197 },
7198 {
7199 .cmd = DEVLINK_CMD_TRAP_SET,
7200 .doit = devlink_nl_cmd_trap_set_doit,
7201 .flags = GENL_ADMIN_PERM,
7202 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7203 },
7204 {
7205 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
7206 .doit = devlink_nl_cmd_trap_group_get_doit,
7207 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
7208 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7209 /* can be retrieved by unprivileged users */
7210 },
7211 {
7212 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
7213 .doit = devlink_nl_cmd_trap_group_set_doit,
7214 .flags = GENL_ADMIN_PERM,
7215 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7216 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007217 {
7218 .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
7219 .doit = devlink_nl_cmd_trap_policer_get_doit,
7220 .dumpit = devlink_nl_cmd_trap_policer_get_dumpit,
7221 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7222 /* can be retrieved by unprivileged users */
7223 },
7224 {
7225 .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
7226 .doit = devlink_nl_cmd_trap_policer_set_doit,
7227 .flags = GENL_ADMIN_PERM,
7228 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7229 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007230};
7231
Johannes Berg56989f62016-10-24 14:40:05 +02007232static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02007233 .name = DEVLINK_GENL_NAME,
7234 .version = DEVLINK_GENL_VERSION,
7235 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01007236 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02007237 .netnsok = true,
7238 .pre_doit = devlink_nl_pre_doit,
7239 .post_doit = devlink_nl_post_doit,
7240 .module = THIS_MODULE,
7241 .ops = devlink_nl_ops,
7242 .n_ops = ARRAY_SIZE(devlink_nl_ops),
7243 .mcgrps = devlink_nl_mcgrps,
7244 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
7245};
7246
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007247/**
7248 * devlink_alloc - Allocate new devlink instance resources
7249 *
7250 * @ops: ops
7251 * @priv_size: size of user private data
7252 *
7253 * Allocate new devlink instance resources, including devlink index
7254 * and name.
7255 */
7256struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
7257{
7258 struct devlink *devlink;
7259
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007260 if (WARN_ON(!ops))
7261 return NULL;
7262
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007263 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
7264 if (!devlink)
7265 return NULL;
7266 devlink->ops = ops;
Jacob Keller12102432020-03-26 11:37:15 -07007267 xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
Jiri Pirko8273fd82019-10-05 08:10:31 +02007268 __devlink_net_set(devlink, &init_net);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007269 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02007270 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007271 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007272 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03007273 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03007274 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02007275 INIT_LIST_HEAD(&devlink->reporter_list);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007276 INIT_LIST_HEAD(&devlink->trap_list);
7277 INIT_LIST_HEAD(&devlink->trap_group_list);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007278 INIT_LIST_HEAD(&devlink->trap_policer_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007279 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007280 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007281 return devlink;
7282}
7283EXPORT_SYMBOL_GPL(devlink_alloc);
7284
7285/**
7286 * devlink_register - Register devlink instance
7287 *
7288 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007289 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007290 */
7291int devlink_register(struct devlink *devlink, struct device *dev)
7292{
7293 mutex_lock(&devlink_mutex);
7294 devlink->dev = dev;
Jiri Pirko8273fd82019-10-05 08:10:31 +02007295 devlink->registered = true;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007296 list_add_tail(&devlink->list, &devlink_list);
7297 devlink_notify(devlink, DEVLINK_CMD_NEW);
7298 mutex_unlock(&devlink_mutex);
7299 return 0;
7300}
7301EXPORT_SYMBOL_GPL(devlink_register);
7302
7303/**
7304 * devlink_unregister - Unregister devlink instance
7305 *
7306 * @devlink: devlink
7307 */
7308void devlink_unregister(struct devlink *devlink)
7309{
7310 mutex_lock(&devlink_mutex);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007311 WARN_ON(devlink_reload_supported(devlink) &&
7312 devlink->reload_enabled);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007313 devlink_notify(devlink, DEVLINK_CMD_DEL);
7314 list_del(&devlink->list);
7315 mutex_unlock(&devlink_mutex);
7316}
7317EXPORT_SYMBOL_GPL(devlink_unregister);
7318
7319/**
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007320 * devlink_reload_enable - Enable reload of devlink instance
7321 *
7322 * @devlink: devlink
7323 *
7324 * Should be called at end of device initialization
7325 * process when reload operation is supported.
7326 */
7327void devlink_reload_enable(struct devlink *devlink)
7328{
7329 mutex_lock(&devlink_mutex);
7330 devlink->reload_enabled = true;
7331 mutex_unlock(&devlink_mutex);
7332}
7333EXPORT_SYMBOL_GPL(devlink_reload_enable);
7334
7335/**
7336 * devlink_reload_disable - Disable reload of devlink instance
7337 *
7338 * @devlink: devlink
7339 *
7340 * Should be called at the beginning of device cleanup
7341 * process when reload operation is supported.
7342 */
7343void devlink_reload_disable(struct devlink *devlink)
7344{
7345 mutex_lock(&devlink_mutex);
7346 /* Mutex is taken which ensures that no reload operation is in
7347 * progress while setting up forbidded flag.
7348 */
7349 devlink->reload_enabled = false;
7350 mutex_unlock(&devlink_mutex);
7351}
7352EXPORT_SYMBOL_GPL(devlink_reload_disable);
7353
7354/**
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007355 * devlink_free - Free devlink instance resources
7356 *
7357 * @devlink: devlink
7358 */
7359void devlink_free(struct devlink *devlink)
7360{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007361 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01007362 mutex_destroy(&devlink->lock);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007363 WARN_ON(!list_empty(&devlink->trap_policer_list));
Ido Schimmel0f420b62019-08-17 16:28:17 +03007364 WARN_ON(!list_empty(&devlink->trap_group_list));
7365 WARN_ON(!list_empty(&devlink->trap_list));
Parav Panditb904aad2019-02-08 15:15:00 -06007366 WARN_ON(!list_empty(&devlink->reporter_list));
7367 WARN_ON(!list_empty(&devlink->region_list));
7368 WARN_ON(!list_empty(&devlink->param_list));
7369 WARN_ON(!list_empty(&devlink->resource_list));
7370 WARN_ON(!list_empty(&devlink->dpipe_table_list));
7371 WARN_ON(!list_empty(&devlink->sb_list));
7372 WARN_ON(!list_empty(&devlink->port_list));
7373
Jacob Keller12102432020-03-26 11:37:15 -07007374 xa_destroy(&devlink->snapshot_ids);
7375
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007376 kfree(devlink);
7377}
7378EXPORT_SYMBOL_GPL(devlink_free);
7379
Jiri Pirko136bf272019-05-23 10:43:35 +02007380static void devlink_port_type_warn(struct work_struct *work)
7381{
7382 WARN(true, "Type was not set for devlink port.");
7383}
7384
7385static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
7386{
7387 /* Ignore CPU and DSA flavours. */
7388 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
7389 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
7390}
7391
Ido Schimmel4c582232020-01-09 19:57:41 +02007392#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
Jiri Pirko136bf272019-05-23 10:43:35 +02007393
7394static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
7395{
7396 if (!devlink_port_type_should_warn(devlink_port))
7397 return;
7398 /* Schedule a work to WARN in case driver does not set port
7399 * type within timeout.
7400 */
7401 schedule_delayed_work(&devlink_port->type_warn_dw,
7402 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
7403}
7404
7405static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
7406{
7407 if (!devlink_port_type_should_warn(devlink_port))
7408 return;
7409 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
7410}
7411
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007412/**
7413 * devlink_port_register - Register devlink port
7414 *
7415 * @devlink: devlink
7416 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007417 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007418 *
7419 * Register devlink port with provided port index. User can use
7420 * any indexing, even hw-related one. devlink_port structure
7421 * is convenient to be embedded inside user driver private structure.
7422 * Note that the caller should take care of zeroing the devlink_port
7423 * structure.
7424 */
7425int devlink_port_register(struct devlink *devlink,
7426 struct devlink_port *devlink_port,
7427 unsigned int port_index)
7428{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007429 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007430 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007431 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007432 return -EEXIST;
7433 }
7434 devlink_port->devlink = devlink;
7435 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007436 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01007437 spin_lock_init(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007438 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05307439 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007440 mutex_unlock(&devlink->lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02007441 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
7442 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007443 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7444 return 0;
7445}
7446EXPORT_SYMBOL_GPL(devlink_port_register);
7447
7448/**
7449 * devlink_port_unregister - Unregister devlink port
7450 *
7451 * @devlink_port: devlink port
7452 */
7453void devlink_port_unregister(struct devlink_port *devlink_port)
7454{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007455 struct devlink *devlink = devlink_port->devlink;
7456
Jiri Pirko136bf272019-05-23 10:43:35 +02007457 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007458 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007459 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007460 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007461 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007462}
7463EXPORT_SYMBOL_GPL(devlink_port_unregister);
7464
7465static void __devlink_port_type_set(struct devlink_port *devlink_port,
7466 enum devlink_port_type type,
7467 void *type_dev)
7468{
Jiri Pirko2b239e72019-03-24 11:14:36 +01007469 if (WARN_ON(!devlink_port->registered))
7470 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02007471 devlink_port_type_warn_cancel(devlink_port);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007472 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007473 devlink_port->type = type;
7474 devlink_port->type_dev = type_dev;
Ido Schimmel0f420b62019-08-17 16:28:17 +03007475 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007476 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7477}
7478
7479/**
7480 * devlink_port_type_eth_set - Set port type to Ethernet
7481 *
7482 * @devlink_port: devlink port
7483 * @netdev: related netdevice
7484 */
7485void devlink_port_type_eth_set(struct devlink_port *devlink_port,
7486 struct net_device *netdev)
7487{
Jiri Pirko119c0b52019-04-03 14:24:27 +02007488 const struct net_device_ops *ops = netdev->netdev_ops;
7489
Jiri Pirko746364f2019-03-28 13:56:46 +01007490 /* If driver registers devlink port, it should set devlink port
7491 * attributes accordingly so the compat functions are called
7492 * and the original ops are not used.
7493 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02007494 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01007495 /* Some drivers use the same set of ndos for netdevs
7496 * that have devlink_port registered and also for
7497 * those who don't. Make sure that ndo_get_phys_port_name
7498 * returns -EOPNOTSUPP here in case it is defined.
7499 * Warn if not.
7500 */
Jiri Pirko746364f2019-03-28 13:56:46 +01007501 char name[IFNAMSIZ];
7502 int err;
7503
7504 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
7505 WARN_ON(err != -EOPNOTSUPP);
7506 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02007507 if (ops->ndo_get_port_parent_id) {
7508 /* Some drivers use the same set of ndos for netdevs
7509 * that have devlink_port registered and also for
7510 * those who don't. Make sure that ndo_get_port_parent_id
7511 * returns -EOPNOTSUPP here in case it is defined.
7512 * Warn if not.
7513 */
7514 struct netdev_phys_item_id ppid;
7515 int err;
7516
7517 err = ops->ndo_get_port_parent_id(netdev, &ppid);
7518 WARN_ON(err != -EOPNOTSUPP);
7519 }
Jiri Pirko773b1f32019-03-24 11:14:30 +01007520 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007521}
7522EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
7523
7524/**
7525 * devlink_port_type_ib_set - Set port type to InfiniBand
7526 *
7527 * @devlink_port: devlink port
7528 * @ibdev: related IB device
7529 */
7530void devlink_port_type_ib_set(struct devlink_port *devlink_port,
7531 struct ib_device *ibdev)
7532{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007533 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007534}
7535EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
7536
7537/**
7538 * devlink_port_type_clear - Clear port type
7539 *
7540 * @devlink_port: devlink port
7541 */
7542void devlink_port_type_clear(struct devlink_port *devlink_port)
7543{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007544 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02007545 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007546}
7547EXPORT_SYMBOL_GPL(devlink_port_type_clear);
7548
Parav Pandit378ef012019-07-08 23:17:35 -05007549static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007550 enum devlink_port_flavour flavour)
Parav Pandit378ef012019-07-08 23:17:35 -05007551{
7552 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7553
7554 if (WARN_ON(devlink_port->registered))
7555 return -EEXIST;
Danielle Ratson10a429b2020-07-09 16:18:14 +03007556 devlink_port->attrs_set = true;
Parav Pandit378ef012019-07-08 23:17:35 -05007557 attrs->flavour = flavour;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007558 if (attrs->switch_id.id_len) {
Danielle Ratson46737a12020-07-09 16:18:15 +03007559 devlink_port->switch_port = true;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007560 if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
7561 attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
Parav Pandit378ef012019-07-08 23:17:35 -05007562 } else {
Danielle Ratson46737a12020-07-09 16:18:15 +03007563 devlink_port->switch_port = false;
Parav Pandit378ef012019-07-08 23:17:35 -05007564 }
7565 return 0;
7566}
7567
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007568/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007569 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007570 *
7571 * @devlink_port: devlink port
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007572 * @attrs: devlink port attrs
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007573 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007574void devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007575 struct devlink_port_attrs *attrs)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007576{
Parav Pandit378ef012019-07-08 23:17:35 -05007577 int ret;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007578
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007579 devlink_port->attrs = *attrs;
7580 ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
Parav Pandit378ef012019-07-08 23:17:35 -05007581 if (ret)
Jiri Pirko45b86112019-03-24 11:14:33 +01007582 return;
Danielle Ratsona0f49b52020-07-09 16:18:20 +03007583 WARN_ON(attrs->splittable && attrs->split);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007584}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007585EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007586
Parav Pandit98fd2d62019-07-08 23:17:37 -05007587/**
7588 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
7589 *
7590 * @devlink_port: devlink port
7591 * @pf: associated PF for the devlink port instance
Parav Pandit98fd2d62019-07-08 23:17:37 -05007592 */
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007593void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u16 pf)
Parav Pandit98fd2d62019-07-08 23:17:37 -05007594{
7595 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7596 int ret;
7597
7598 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007599 DEVLINK_PORT_FLAVOUR_PCI_PF);
Parav Pandit98fd2d62019-07-08 23:17:37 -05007600 if (ret)
7601 return;
7602
7603 attrs->pci_pf.pf = pf;
7604}
7605EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
7606
Parav Pandite41b6bf2019-07-08 23:17:38 -05007607/**
7608 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
7609 *
7610 * @devlink_port: devlink port
7611 * @pf: associated PF for the devlink port instance
7612 * @vf: associated VF of a PF for the devlink port instance
Parav Pandite41b6bf2019-07-08 23:17:38 -05007613 */
7614void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
Parav Pandite41b6bf2019-07-08 23:17:38 -05007615 u16 pf, u16 vf)
7616{
7617 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7618 int ret;
7619
7620 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007621 DEVLINK_PORT_FLAVOUR_PCI_VF);
Parav Pandite41b6bf2019-07-08 23:17:38 -05007622 if (ret)
7623 return;
7624 attrs->pci_vf.pf = pf;
7625 attrs->pci_vf.vf = vf;
7626}
7627EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
7628
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007629static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
7630 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02007631{
7632 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7633 int n = 0;
7634
Danielle Ratson10a429b2020-07-09 16:18:14 +03007635 if (!devlink_port->attrs_set)
Jiri Pirko08474c12018-05-18 09:29:02 +02007636 return -EOPNOTSUPP;
7637
7638 switch (attrs->flavour) {
7639 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
Parav Panditacf1ee42020-03-03 08:12:42 -06007640 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Jiri Pirko08474c12018-05-18 09:29:02 +02007641 if (!attrs->split)
Parav Pandit378ef012019-07-08 23:17:35 -05007642 n = snprintf(name, len, "p%u", attrs->phys.port_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007643 else
Parav Pandit378ef012019-07-08 23:17:35 -05007644 n = snprintf(name, len, "p%us%u",
7645 attrs->phys.port_number,
7646 attrs->phys.split_subport_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007647 break;
7648 case DEVLINK_PORT_FLAVOUR_CPU:
7649 case DEVLINK_PORT_FLAVOUR_DSA:
7650 /* As CPU and DSA ports do not have a netdevice associated
7651 * case should not ever happen.
7652 */
7653 WARN_ON(1);
7654 return -EINVAL;
Parav Pandit98fd2d62019-07-08 23:17:37 -05007655 case DEVLINK_PORT_FLAVOUR_PCI_PF:
7656 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
7657 break;
Parav Pandite41b6bf2019-07-08 23:17:38 -05007658 case DEVLINK_PORT_FLAVOUR_PCI_VF:
7659 n = snprintf(name, len, "pf%uvf%u",
7660 attrs->pci_vf.pf, attrs->pci_vf.vf);
7661 break;
Jiri Pirko08474c12018-05-18 09:29:02 +02007662 }
7663
7664 if (n >= len)
7665 return -EINVAL;
7666
7667 return 0;
7668}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007669
Jiri Pirkobf797472016-04-14 18:19:13 +02007670int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
7671 u32 size, u16 ingress_pools_count,
7672 u16 egress_pools_count, u16 ingress_tc_count,
7673 u16 egress_tc_count)
7674{
7675 struct devlink_sb *devlink_sb;
7676 int err = 0;
7677
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007678 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007679 if (devlink_sb_index_exists(devlink, sb_index)) {
7680 err = -EEXIST;
7681 goto unlock;
7682 }
7683
7684 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
7685 if (!devlink_sb) {
7686 err = -ENOMEM;
7687 goto unlock;
7688 }
7689 devlink_sb->index = sb_index;
7690 devlink_sb->size = size;
7691 devlink_sb->ingress_pools_count = ingress_pools_count;
7692 devlink_sb->egress_pools_count = egress_pools_count;
7693 devlink_sb->ingress_tc_count = ingress_tc_count;
7694 devlink_sb->egress_tc_count = egress_tc_count;
7695 list_add_tail(&devlink_sb->list, &devlink->sb_list);
7696unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007697 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007698 return err;
7699}
7700EXPORT_SYMBOL_GPL(devlink_sb_register);
7701
7702void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
7703{
7704 struct devlink_sb *devlink_sb;
7705
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007706 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007707 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
7708 WARN_ON(!devlink_sb);
7709 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007710 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007711 kfree(devlink_sb);
7712}
7713EXPORT_SYMBOL_GPL(devlink_sb_unregister);
7714
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007715/**
7716 * devlink_dpipe_headers_register - register dpipe headers
7717 *
7718 * @devlink: devlink
7719 * @dpipe_headers: dpipe header array
7720 *
7721 * Register the headers supported by hardware.
7722 */
7723int devlink_dpipe_headers_register(struct devlink *devlink,
7724 struct devlink_dpipe_headers *dpipe_headers)
7725{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007726 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007727 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007728 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007729 return 0;
7730}
7731EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
7732
7733/**
7734 * devlink_dpipe_headers_unregister - unregister dpipe headers
7735 *
7736 * @devlink: devlink
7737 *
7738 * Unregister the headers supported by hardware.
7739 */
7740void devlink_dpipe_headers_unregister(struct devlink *devlink)
7741{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007742 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007743 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007744 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007745}
7746EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
7747
7748/**
7749 * devlink_dpipe_table_counter_enabled - check if counter allocation
7750 * required
7751 * @devlink: devlink
7752 * @table_name: tables name
7753 *
7754 * Used by driver to check if counter allocation is required.
7755 * After counter allocation is turned on the table entries
7756 * are updated to include counter statistics.
7757 *
7758 * After that point on the driver must respect the counter
7759 * state so that each entry added to the table is added
7760 * with a counter.
7761 */
7762bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
7763 const char *table_name)
7764{
7765 struct devlink_dpipe_table *table;
7766 bool enabled;
7767
7768 rcu_read_lock();
7769 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307770 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007771 enabled = false;
7772 if (table)
7773 enabled = table->counters_enabled;
7774 rcu_read_unlock();
7775 return enabled;
7776}
7777EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
7778
7779/**
7780 * devlink_dpipe_table_register - register dpipe table
7781 *
7782 * @devlink: devlink
7783 * @table_name: table name
7784 * @table_ops: table ops
7785 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007786 * @counter_control_extern: external control for counters
7787 */
7788int devlink_dpipe_table_register(struct devlink *devlink,
7789 const char *table_name,
7790 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02007791 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007792{
7793 struct devlink_dpipe_table *table;
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307794 int err = 0;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007795
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02007796 if (WARN_ON(!table_ops->size_get))
7797 return -EINVAL;
7798
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307799 mutex_lock(&devlink->lock);
7800
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307801 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
7802 devlink)) {
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307803 err = -EEXIST;
7804 goto unlock;
7805 }
7806
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007807 table = kzalloc(sizeof(*table), GFP_KERNEL);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307808 if (!table) {
7809 err = -ENOMEM;
7810 goto unlock;
7811 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007812
7813 table->name = table_name;
7814 table->table_ops = table_ops;
7815 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007816 table->counter_control_extern = counter_control_extern;
7817
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007818 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307819unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007820 mutex_unlock(&devlink->lock);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307821 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007822}
7823EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
7824
7825/**
7826 * devlink_dpipe_table_unregister - unregister dpipe table
7827 *
7828 * @devlink: devlink
7829 * @table_name: table name
7830 */
7831void devlink_dpipe_table_unregister(struct devlink *devlink,
7832 const char *table_name)
7833{
7834 struct devlink_dpipe_table *table;
7835
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007836 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007837 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307838 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007839 if (!table)
7840 goto unlock;
7841 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007842 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007843 kfree_rcu(table, rcu);
7844 return;
7845unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007846 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007847}
7848EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
7849
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007850/**
7851 * devlink_resource_register - devlink resource register
7852 *
7853 * @devlink: devlink
7854 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007855 * @resource_size: resource's size
7856 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007857 * @parent_resource_id: resource's parent id
7858 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007859 */
7860int devlink_resource_register(struct devlink *devlink,
7861 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007862 u64 resource_size,
7863 u64 resource_id,
7864 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02007865 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007866{
7867 struct devlink_resource *resource;
7868 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07007869 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007870 int err = 0;
7871
David Ahern14530742018-03-20 19:31:14 -07007872 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
7873
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007874 mutex_lock(&devlink->lock);
7875 resource = devlink_resource_find(devlink, NULL, resource_id);
7876 if (resource) {
7877 err = -EINVAL;
7878 goto out;
7879 }
7880
7881 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
7882 if (!resource) {
7883 err = -ENOMEM;
7884 goto out;
7885 }
7886
7887 if (top_hierarchy) {
7888 resource_list = &devlink->resource_list;
7889 } else {
7890 struct devlink_resource *parent_resource;
7891
7892 parent_resource = devlink_resource_find(devlink, NULL,
7893 parent_resource_id);
7894 if (parent_resource) {
7895 resource_list = &parent_resource->resource_list;
7896 resource->parent = parent_resource;
7897 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00007898 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007899 err = -EINVAL;
7900 goto out;
7901 }
7902 }
7903
7904 resource->name = resource_name;
7905 resource->size = resource_size;
7906 resource->size_new = resource_size;
7907 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007908 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01007909 memcpy(&resource->size_params, size_params,
7910 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007911 INIT_LIST_HEAD(&resource->resource_list);
7912 list_add_tail(&resource->list, resource_list);
7913out:
7914 mutex_unlock(&devlink->lock);
7915 return err;
7916}
7917EXPORT_SYMBOL_GPL(devlink_resource_register);
7918
7919/**
7920 * devlink_resources_unregister - free all resources
7921 *
7922 * @devlink: devlink
7923 * @resource: resource
7924 */
7925void devlink_resources_unregister(struct devlink *devlink,
7926 struct devlink_resource *resource)
7927{
7928 struct devlink_resource *tmp, *child_resource;
7929 struct list_head *resource_list;
7930
7931 if (resource)
7932 resource_list = &resource->resource_list;
7933 else
7934 resource_list = &devlink->resource_list;
7935
7936 if (!resource)
7937 mutex_lock(&devlink->lock);
7938
7939 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
7940 devlink_resources_unregister(devlink, child_resource);
7941 list_del(&child_resource->list);
7942 kfree(child_resource);
7943 }
7944
7945 if (!resource)
7946 mutex_unlock(&devlink->lock);
7947}
7948EXPORT_SYMBOL_GPL(devlink_resources_unregister);
7949
7950/**
7951 * devlink_resource_size_get - get and update size
7952 *
7953 * @devlink: devlink
7954 * @resource_id: the requested resource id
7955 * @p_resource_size: ptr to update
7956 */
7957int devlink_resource_size_get(struct devlink *devlink,
7958 u64 resource_id,
7959 u64 *p_resource_size)
7960{
7961 struct devlink_resource *resource;
7962 int err = 0;
7963
7964 mutex_lock(&devlink->lock);
7965 resource = devlink_resource_find(devlink, NULL, resource_id);
7966 if (!resource) {
7967 err = -EINVAL;
7968 goto out;
7969 }
7970 *p_resource_size = resource->size_new;
7971 resource->size = resource->size_new;
7972out:
7973 mutex_unlock(&devlink->lock);
7974 return err;
7975}
7976EXPORT_SYMBOL_GPL(devlink_resource_size_get);
7977
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01007978/**
7979 * devlink_dpipe_table_resource_set - set the resource id
7980 *
7981 * @devlink: devlink
7982 * @table_name: table name
7983 * @resource_id: resource id
7984 * @resource_units: number of resource's units consumed per table's entry
7985 */
7986int devlink_dpipe_table_resource_set(struct devlink *devlink,
7987 const char *table_name, u64 resource_id,
7988 u64 resource_units)
7989{
7990 struct devlink_dpipe_table *table;
7991 int err = 0;
7992
7993 mutex_lock(&devlink->lock);
7994 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307995 table_name, devlink);
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01007996 if (!table) {
7997 err = -EINVAL;
7998 goto out;
7999 }
8000 table->resource_id = resource_id;
8001 table->resource_units = resource_units;
8002 table->resource_valid = true;
8003out:
8004 mutex_unlock(&devlink->lock);
8005 return err;
8006}
8007EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
8008
Jiri Pirkofc56be42018-04-05 22:13:21 +02008009/**
8010 * devlink_resource_occ_get_register - register occupancy getter
8011 *
8012 * @devlink: devlink
8013 * @resource_id: resource id
8014 * @occ_get: occupancy getter callback
8015 * @occ_get_priv: occupancy getter callback priv
8016 */
8017void devlink_resource_occ_get_register(struct devlink *devlink,
8018 u64 resource_id,
8019 devlink_resource_occ_get_t *occ_get,
8020 void *occ_get_priv)
8021{
8022 struct devlink_resource *resource;
8023
8024 mutex_lock(&devlink->lock);
8025 resource = devlink_resource_find(devlink, NULL, resource_id);
8026 if (WARN_ON(!resource))
8027 goto out;
8028 WARN_ON(resource->occ_get);
8029
8030 resource->occ_get = occ_get;
8031 resource->occ_get_priv = occ_get_priv;
8032out:
8033 mutex_unlock(&devlink->lock);
8034}
8035EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
8036
8037/**
8038 * devlink_resource_occ_get_unregister - unregister occupancy getter
8039 *
8040 * @devlink: devlink
8041 * @resource_id: resource id
8042 */
8043void devlink_resource_occ_get_unregister(struct devlink *devlink,
8044 u64 resource_id)
8045{
8046 struct devlink_resource *resource;
8047
8048 mutex_lock(&devlink->lock);
8049 resource = devlink_resource_find(devlink, NULL, resource_id);
8050 if (WARN_ON(!resource))
8051 goto out;
8052 WARN_ON(!resource->occ_get);
8053
8054 resource->occ_get = NULL;
8055 resource->occ_get_priv = NULL;
8056out:
8057 mutex_unlock(&devlink->lock);
8058}
8059EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
8060
Vasundhara Volam39e61602019-01-28 18:00:20 +05308061static int devlink_param_verify(const struct devlink_param *param)
8062{
8063 if (!param || !param->name || !param->supported_cmodes)
8064 return -EINVAL;
8065 if (param->generic)
8066 return devlink_param_generic_verify(param);
8067 else
8068 return devlink_param_driver_verify(param);
8069}
8070
8071static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308072 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308073 struct list_head *param_list,
8074 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308075 size_t params_count,
8076 enum devlink_command reg_cmd,
8077 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308078{
8079 const struct devlink_param *param = params;
8080 int i;
8081 int err;
8082
8083 mutex_lock(&devlink->lock);
8084 for (i = 0; i < params_count; i++, param++) {
8085 err = devlink_param_verify(param);
8086 if (err)
8087 goto rollback;
8088
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308089 err = devlink_param_register_one(devlink, port_index,
8090 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308091 if (err)
8092 goto rollback;
8093 }
8094
8095 mutex_unlock(&devlink->lock);
8096 return 0;
8097
8098rollback:
8099 if (!i)
8100 goto unlock;
8101 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308102 devlink_param_unregister_one(devlink, port_index, param_list,
8103 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308104unlock:
8105 mutex_unlock(&devlink->lock);
8106 return err;
8107}
8108
8109static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308110 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308111 struct list_head *param_list,
8112 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308113 size_t params_count,
8114 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308115{
8116 const struct devlink_param *param = params;
8117 int i;
8118
8119 mutex_lock(&devlink->lock);
8120 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308121 devlink_param_unregister_one(devlink, 0, param_list, param,
8122 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308123 mutex_unlock(&devlink->lock);
8124}
8125
Moshe Shemesheabaef12018-07-04 14:30:28 +03008126/**
8127 * devlink_params_register - register configuration parameters
8128 *
8129 * @devlink: devlink
8130 * @params: configuration parameters array
8131 * @params_count: number of parameters provided
8132 *
8133 * Register the configuration parameters supported by the driver.
8134 */
8135int devlink_params_register(struct devlink *devlink,
8136 const struct devlink_param *params,
8137 size_t params_count)
8138{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308139 return __devlink_params_register(devlink, 0, &devlink->param_list,
8140 params, params_count,
8141 DEVLINK_CMD_PARAM_NEW,
8142 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008143}
8144EXPORT_SYMBOL_GPL(devlink_params_register);
8145
8146/**
8147 * devlink_params_unregister - unregister configuration parameters
8148 * @devlink: devlink
8149 * @params: configuration parameters to unregister
8150 * @params_count: number of parameters provided
8151 */
8152void devlink_params_unregister(struct devlink *devlink,
8153 const struct devlink_param *params,
8154 size_t params_count)
8155{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308156 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
8157 params, params_count,
8158 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008159}
8160EXPORT_SYMBOL_GPL(devlink_params_unregister);
8161
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008162/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00008163 * devlink_params_publish - publish configuration parameters
8164 *
8165 * @devlink: devlink
8166 *
8167 * Publish previously registered configuration parameters.
8168 */
8169void devlink_params_publish(struct devlink *devlink)
8170{
8171 struct devlink_param_item *param_item;
8172
8173 list_for_each_entry(param_item, &devlink->param_list, list) {
8174 if (param_item->published)
8175 continue;
8176 param_item->published = true;
8177 devlink_param_notify(devlink, 0, param_item,
8178 DEVLINK_CMD_PARAM_NEW);
8179 }
8180}
8181EXPORT_SYMBOL_GPL(devlink_params_publish);
8182
8183/**
8184 * devlink_params_unpublish - unpublish configuration parameters
8185 *
8186 * @devlink: devlink
8187 *
8188 * Unpublish previously registered configuration parameters.
8189 */
8190void devlink_params_unpublish(struct devlink *devlink)
8191{
8192 struct devlink_param_item *param_item;
8193
8194 list_for_each_entry(param_item, &devlink->param_list, list) {
8195 if (!param_item->published)
8196 continue;
8197 param_item->published = false;
8198 devlink_param_notify(devlink, 0, param_item,
8199 DEVLINK_CMD_PARAM_DEL);
8200 }
8201}
8202EXPORT_SYMBOL_GPL(devlink_params_unpublish);
8203
8204/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05308205 * devlink_port_params_register - register port configuration parameters
8206 *
8207 * @devlink_port: devlink port
8208 * @params: configuration parameters array
8209 * @params_count: number of parameters provided
8210 *
8211 * Register the configuration parameters supported by the port.
8212 */
8213int devlink_port_params_register(struct devlink_port *devlink_port,
8214 const struct devlink_param *params,
8215 size_t params_count)
8216{
8217 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308218 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308219 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308220 params_count,
8221 DEVLINK_CMD_PORT_PARAM_NEW,
8222 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308223}
8224EXPORT_SYMBOL_GPL(devlink_port_params_register);
8225
8226/**
8227 * devlink_port_params_unregister - unregister port configuration
8228 * parameters
8229 *
8230 * @devlink_port: devlink port
8231 * @params: configuration parameters array
8232 * @params_count: number of parameters provided
8233 */
8234void devlink_port_params_unregister(struct devlink_port *devlink_port,
8235 const struct devlink_param *params,
8236 size_t params_count)
8237{
8238 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308239 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308240 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308241 params, params_count,
8242 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308243}
8244EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
8245
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308246static int
8247__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
8248 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008249{
8250 struct devlink_param_item *param_item;
8251
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308252 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008253 if (!param_item)
8254 return -EINVAL;
8255
8256 if (!param_item->driverinit_value_valid ||
8257 !devlink_param_cmode_is_supported(param_item->param,
8258 DEVLINK_PARAM_CMODE_DRIVERINIT))
8259 return -EOPNOTSUPP;
8260
Moshe Shemesh12765342018-10-10 16:09:26 +03008261 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8262 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
8263 else
8264 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008265
8266 return 0;
8267}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308268
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308269static int
8270__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308271 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308272 struct list_head *param_list, u32 param_id,
8273 union devlink_param_value init_val,
8274 enum devlink_command cmd)
8275{
8276 struct devlink_param_item *param_item;
8277
8278 param_item = devlink_param_find_by_id(param_list, param_id);
8279 if (!param_item)
8280 return -EINVAL;
8281
8282 if (!devlink_param_cmode_is_supported(param_item->param,
8283 DEVLINK_PARAM_CMODE_DRIVERINIT))
8284 return -EOPNOTSUPP;
8285
8286 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8287 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
8288 else
8289 param_item->driverinit_value = init_val;
8290 param_item->driverinit_value_valid = true;
8291
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308292 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308293 return 0;
8294}
8295
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308296/**
8297 * devlink_param_driverinit_value_get - get configuration parameter
8298 * value for driver initializing
8299 *
8300 * @devlink: devlink
8301 * @param_id: parameter ID
8302 * @init_val: value of parameter in driverinit configuration mode
8303 *
8304 * This function should be used by the driver to get driverinit
8305 * configuration for initialization after reload command.
8306 */
8307int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
8308 union devlink_param_value *init_val)
8309{
Jiri Pirko97691062019-09-12 10:49:45 +02008310 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308311 return -EOPNOTSUPP;
8312
8313 return __devlink_param_driverinit_value_get(&devlink->param_list,
8314 param_id, init_val);
8315}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008316EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
8317
8318/**
8319 * devlink_param_driverinit_value_set - set value of configuration
8320 * parameter for driverinit
8321 * configuration mode
8322 *
8323 * @devlink: devlink
8324 * @param_id: parameter ID
8325 * @init_val: value of parameter to set for driverinit configuration mode
8326 *
8327 * This function should be used by the driver to set driverinit
8328 * configuration mode default value.
8329 */
8330int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
8331 union devlink_param_value init_val)
8332{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308333 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308334 &devlink->param_list,
8335 param_id, init_val,
8336 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008337}
8338EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
8339
Moshe Shemeshea601e12018-07-04 14:30:32 +03008340/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308341 * devlink_port_param_driverinit_value_get - get configuration parameter
8342 * value for driver initializing
8343 *
8344 * @devlink_port: devlink_port
8345 * @param_id: parameter ID
8346 * @init_val: value of parameter in driverinit configuration mode
8347 *
8348 * This function should be used by the driver to get driverinit
8349 * configuration for initialization after reload command.
8350 */
8351int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
8352 u32 param_id,
8353 union devlink_param_value *init_val)
8354{
8355 struct devlink *devlink = devlink_port->devlink;
8356
Jiri Pirko97691062019-09-12 10:49:45 +02008357 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308358 return -EOPNOTSUPP;
8359
8360 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
8361 param_id, init_val);
8362}
8363EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
8364
8365/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308366 * devlink_port_param_driverinit_value_set - set value of configuration
8367 * parameter for driverinit
8368 * configuration mode
8369 *
8370 * @devlink_port: devlink_port
8371 * @param_id: parameter ID
8372 * @init_val: value of parameter to set for driverinit configuration mode
8373 *
8374 * This function should be used by the driver to set driverinit
8375 * configuration mode default value.
8376 */
8377int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
8378 u32 param_id,
8379 union devlink_param_value init_val)
8380{
8381 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308382 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308383 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308384 param_id, init_val,
8385 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308386}
8387EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
8388
8389/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03008390 * devlink_param_value_changed - notify devlink on a parameter's value
8391 * change. Should be called by the driver
8392 * right after the change.
8393 *
8394 * @devlink: devlink
8395 * @param_id: parameter ID
8396 *
8397 * This function should be used by the driver to notify devlink on value
8398 * change, excluding driverinit configuration mode.
8399 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03008400 */
8401void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
8402{
8403 struct devlink_param_item *param_item;
8404
8405 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
8406 WARN_ON(!param_item);
8407
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308408 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03008409}
8410EXPORT_SYMBOL_GPL(devlink_param_value_changed);
8411
Alex Veskerb16ebe92018-07-12 15:13:08 +03008412/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308413 * devlink_port_param_value_changed - notify devlink on a parameter's value
8414 * change. Should be called by the driver
8415 * right after the change.
8416 *
8417 * @devlink_port: devlink_port
8418 * @param_id: parameter ID
8419 *
8420 * This function should be used by the driver to notify devlink on value
8421 * change, excluding driverinit configuration mode.
8422 * For driverinit configuration mode driver should use the function
8423 * devlink_port_param_driverinit_value_set() instead.
8424 */
8425void devlink_port_param_value_changed(struct devlink_port *devlink_port,
8426 u32 param_id)
8427{
8428 struct devlink_param_item *param_item;
8429
8430 param_item = devlink_param_find_by_id(&devlink_port->param_list,
8431 param_id);
8432 WARN_ON(!param_item);
8433
8434 devlink_param_notify(devlink_port->devlink, devlink_port->index,
8435 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
8436}
8437EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
8438
8439/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03008440 * devlink_param_value_str_fill - Safely fill-up the string preventing
8441 * from overflow of the preallocated buffer
8442 *
8443 * @dst_val: destination devlink_param_value
8444 * @src: source buffer
8445 */
8446void devlink_param_value_str_fill(union devlink_param_value *dst_val,
8447 const char *src)
8448{
8449 size_t len;
8450
8451 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
8452 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
8453}
8454EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
8455
8456/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03008457 * devlink_region_create - create a new address region
8458 *
8459 * @devlink: devlink
Jacob Kellere8937682020-03-26 11:37:08 -07008460 * @ops: region operations and name
Alex Veskerb16ebe92018-07-12 15:13:08 +03008461 * @region_max_snapshots: Maximum supported number of snapshots for region
8462 * @region_size: size of region
8463 */
Jacob Kellere8937682020-03-26 11:37:08 -07008464struct devlink_region *
8465devlink_region_create(struct devlink *devlink,
8466 const struct devlink_region_ops *ops,
8467 u32 region_max_snapshots, u64 region_size)
Alex Veskerb16ebe92018-07-12 15:13:08 +03008468{
8469 struct devlink_region *region;
8470 int err = 0;
8471
Jacob Kellera0a09f62020-03-26 11:37:09 -07008472 if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
8473 return ERR_PTR(-EINVAL);
8474
Alex Veskerb16ebe92018-07-12 15:13:08 +03008475 mutex_lock(&devlink->lock);
8476
Jacob Kellere8937682020-03-26 11:37:08 -07008477 if (devlink_region_get_by_name(devlink, ops->name)) {
Alex Veskerb16ebe92018-07-12 15:13:08 +03008478 err = -EEXIST;
8479 goto unlock;
8480 }
8481
8482 region = kzalloc(sizeof(*region), GFP_KERNEL);
8483 if (!region) {
8484 err = -ENOMEM;
8485 goto unlock;
8486 }
8487
8488 region->devlink = devlink;
8489 region->max_snapshots = region_max_snapshots;
Jacob Kellere8937682020-03-26 11:37:08 -07008490 region->ops = ops;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008491 region->size = region_size;
8492 INIT_LIST_HEAD(&region->snapshot_list);
8493 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03008494 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008495
8496 mutex_unlock(&devlink->lock);
8497 return region;
8498
8499unlock:
8500 mutex_unlock(&devlink->lock);
8501 return ERR_PTR(err);
8502}
8503EXPORT_SYMBOL_GPL(devlink_region_create);
8504
8505/**
8506 * devlink_region_destroy - destroy address region
8507 *
8508 * @region: devlink region to destroy
8509 */
8510void devlink_region_destroy(struct devlink_region *region)
8511{
8512 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008513 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008514
8515 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008516
8517 /* Free all snapshots of region */
8518 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
Jiri Pirko92b49822019-08-12 14:28:31 +02008519 devlink_region_snapshot_del(region, snapshot);
Alex Veskerd7e52722018-07-12 15:13:10 +03008520
Alex Veskerb16ebe92018-07-12 15:13:08 +03008521 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03008522
8523 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008524 mutex_unlock(&devlink->lock);
8525 kfree(region);
8526}
8527EXPORT_SYMBOL_GPL(devlink_region_destroy);
8528
Alex Veskerccadfa42018-07-12 15:13:09 +03008529/**
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008530 * devlink_region_snapshot_id_get - get snapshot ID
Alex Veskerccadfa42018-07-12 15:13:09 +03008531 *
8532 * This callback should be called when adding a new snapshot,
8533 * Driver should use the same id for multiple snapshots taken
8534 * on multiple regions at the same time/by the same trigger.
8535 *
Jacob Keller12102432020-03-26 11:37:15 -07008536 * The caller of this function must use devlink_region_snapshot_id_put
8537 * when finished creating regions using this id.
8538 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07008539 * Returns zero on success, or a negative error code on failure.
8540 *
Alex Veskerccadfa42018-07-12 15:13:09 +03008541 * @devlink: devlink
Jacob Keller7ef19d32020-03-26 11:37:14 -07008542 * @id: storage to return id
Alex Veskerccadfa42018-07-12 15:13:09 +03008543 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07008544int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Alex Veskerccadfa42018-07-12 15:13:09 +03008545{
Jacob Keller7ef19d32020-03-26 11:37:14 -07008546 int err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008547
8548 mutex_lock(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07008549 err = __devlink_region_snapshot_id_get(devlink, id);
Alex Veskerccadfa42018-07-12 15:13:09 +03008550 mutex_unlock(&devlink->lock);
8551
Jacob Keller7ef19d32020-03-26 11:37:14 -07008552 return err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008553}
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008554EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
Alex Veskerccadfa42018-07-12 15:13:09 +03008555
Alex Veskerd7e52722018-07-12 15:13:10 +03008556/**
Jacob Keller12102432020-03-26 11:37:15 -07008557 * devlink_region_snapshot_id_put - put snapshot ID reference
8558 *
8559 * This should be called by a driver after finishing creating snapshots
8560 * with an id. Doing so ensures that the ID can later be released in the
8561 * event that all snapshots using it have been destroyed.
8562 *
8563 * @devlink: devlink
8564 * @id: id to release reference on
8565 */
8566void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
8567{
8568 mutex_lock(&devlink->lock);
8569 __devlink_snapshot_id_decrement(devlink, id);
8570 mutex_unlock(&devlink->lock);
8571}
8572EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
8573
8574/**
Alex Veskerd7e52722018-07-12 15:13:10 +03008575 * devlink_region_snapshot_create - create a new snapshot
8576 * This will add a new snapshot of a region. The snapshot
8577 * will be stored on the region struct and can be accessed
Jacob Keller6d82f672020-03-26 11:37:10 -07008578 * from devlink. This is useful for future analyses of snapshots.
Alex Veskerd7e52722018-07-12 15:13:10 +03008579 * Multiple snapshots can be created on a region.
8580 * The @snapshot_id should be obtained using the getter function.
8581 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008582 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03008583 * @data: snapshot data
8584 * @snapshot_id: snapshot id to be created
Alex Veskerd7e52722018-07-12 15:13:10 +03008585 */
Jiri Pirko3a5e5232019-08-09 15:27:15 +02008586int devlink_region_snapshot_create(struct devlink_region *region,
Jacob Kellera0a09f62020-03-26 11:37:09 -07008587 u8 *data, u32 snapshot_id)
Alex Veskerd7e52722018-07-12 15:13:10 +03008588{
8589 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008590 int err;
8591
8592 mutex_lock(&devlink->lock);
Jacob Kellercf80fae2020-03-26 11:37:11 -07008593 err = __devlink_region_snapshot_create(region, data, snapshot_id);
Alex Veskerd7e52722018-07-12 15:13:10 +03008594 mutex_unlock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008595
Alex Veskerd7e52722018-07-12 15:13:10 +03008596 return err;
8597}
8598EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
8599
Ido Schimmel0f420b62019-08-17 16:28:17 +03008600#define DEVLINK_TRAP(_id, _type) \
8601 { \
8602 .type = DEVLINK_TRAP_TYPE_##_type, \
8603 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
8604 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
8605 }
8606
8607static const struct devlink_trap devlink_trap_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008608 DEVLINK_TRAP(SMAC_MC, DROP),
8609 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
8610 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
8611 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
8612 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
8613 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
8614 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
8615 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
8616 DEVLINK_TRAP(TAIL_DROP, DROP),
Amit Cohen6896cc42019-11-07 18:42:09 +02008617 DEVLINK_TRAP(NON_IP_PACKET, DROP),
8618 DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
8619 DEVLINK_TRAP(DIP_LB, DROP),
8620 DEVLINK_TRAP(SIP_MC, DROP),
8621 DEVLINK_TRAP(SIP_LB, DROP),
8622 DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
8623 DEVLINK_TRAP(IPV4_SIP_BC, DROP),
8624 DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
8625 DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
Amit Cohen3b063ae2019-11-07 18:42:14 +02008626 DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
8627 DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
8628 DEVLINK_TRAP(RPF, EXCEPTION),
8629 DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
8630 DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
8631 DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
Amit Cohen95f0ead2020-01-19 15:00:48 +02008632 DEVLINK_TRAP(NON_ROUTABLE, DROP),
Amit Cohen13c056e2020-01-19 15:00:54 +02008633 DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
Amit Cohenc3cae492020-01-19 15:00:58 +02008634 DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008635 DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
8636 DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
Ido Schimmel515eac62020-05-29 21:36:41 +03008637 DEVLINK_TRAP(STP, CONTROL),
8638 DEVLINK_TRAP(LACP, CONTROL),
8639 DEVLINK_TRAP(LLDP, CONTROL),
8640 DEVLINK_TRAP(IGMP_QUERY, CONTROL),
8641 DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
8642 DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
8643 DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
8644 DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
8645 DEVLINK_TRAP(MLD_QUERY, CONTROL),
8646 DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
8647 DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
8648 DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008649 DEVLINK_TRAP(IPV4_DHCP, CONTROL),
8650 DEVLINK_TRAP(IPV6_DHCP, CONTROL),
8651 DEVLINK_TRAP(ARP_REQUEST, CONTROL),
8652 DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
8653 DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
8654 DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
8655 DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
8656 DEVLINK_TRAP(IPV4_BFD, CONTROL),
8657 DEVLINK_TRAP(IPV6_BFD, CONTROL),
8658 DEVLINK_TRAP(IPV4_OSPF, CONTROL),
8659 DEVLINK_TRAP(IPV6_OSPF, CONTROL),
8660 DEVLINK_TRAP(IPV4_BGP, CONTROL),
8661 DEVLINK_TRAP(IPV6_BGP, CONTROL),
8662 DEVLINK_TRAP(IPV4_VRRP, CONTROL),
8663 DEVLINK_TRAP(IPV6_VRRP, CONTROL),
8664 DEVLINK_TRAP(IPV4_PIM, CONTROL),
8665 DEVLINK_TRAP(IPV6_PIM, CONTROL),
8666 DEVLINK_TRAP(UC_LB, CONTROL),
8667 DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
8668 DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
8669 DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
8670 DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
8671 DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
8672 DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
8673 DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
8674 DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
8675 DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
8676 DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
8677 DEVLINK_TRAP(PTP_EVENT, CONTROL),
8678 DEVLINK_TRAP(PTP_GENERAL, CONTROL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008679 DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
8680 DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008681};
8682
8683#define DEVLINK_TRAP_GROUP(_id) \
8684 { \
8685 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
8686 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
8687 }
8688
8689static const struct devlink_trap_group devlink_trap_group_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008690 DEVLINK_TRAP_GROUP(L2_DROPS),
8691 DEVLINK_TRAP_GROUP(L3_DROPS),
Ido Schimmel678eb192020-05-29 21:36:36 +03008692 DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
Ido Schimmel391203a2019-08-17 16:28:18 +03008693 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
Amit Cohen13c056e2020-01-19 15:00:54 +02008694 DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008695 DEVLINK_TRAP_GROUP(ACL_DROPS),
Ido Schimmel515eac62020-05-29 21:36:41 +03008696 DEVLINK_TRAP_GROUP(STP),
8697 DEVLINK_TRAP_GROUP(LACP),
8698 DEVLINK_TRAP_GROUP(LLDP),
8699 DEVLINK_TRAP_GROUP(MC_SNOOPING),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008700 DEVLINK_TRAP_GROUP(DHCP),
8701 DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
8702 DEVLINK_TRAP_GROUP(BFD),
8703 DEVLINK_TRAP_GROUP(OSPF),
8704 DEVLINK_TRAP_GROUP(BGP),
8705 DEVLINK_TRAP_GROUP(VRRP),
8706 DEVLINK_TRAP_GROUP(PIM),
8707 DEVLINK_TRAP_GROUP(UC_LB),
8708 DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
8709 DEVLINK_TRAP_GROUP(IPV6),
8710 DEVLINK_TRAP_GROUP(PTP_EVENT),
8711 DEVLINK_TRAP_GROUP(PTP_GENERAL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008712 DEVLINK_TRAP_GROUP(ACL_SAMPLE),
8713 DEVLINK_TRAP_GROUP(ACL_TRAP),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008714};
8715
8716static int devlink_trap_generic_verify(const struct devlink_trap *trap)
8717{
8718 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
8719 return -EINVAL;
8720
8721 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
8722 return -EINVAL;
8723
8724 if (trap->type != devlink_trap_generic[trap->id].type)
8725 return -EINVAL;
8726
8727 return 0;
8728}
8729
8730static int devlink_trap_driver_verify(const struct devlink_trap *trap)
8731{
8732 int i;
8733
8734 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
8735 return -EINVAL;
8736
8737 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
8738 if (!strcmp(trap->name, devlink_trap_generic[i].name))
8739 return -EEXIST;
8740 }
8741
8742 return 0;
8743}
8744
8745static int devlink_trap_verify(const struct devlink_trap *trap)
8746{
Ido Schimmel107f1672020-03-22 20:48:30 +02008747 if (!trap || !trap->name)
Ido Schimmel0f420b62019-08-17 16:28:17 +03008748 return -EINVAL;
8749
8750 if (trap->generic)
8751 return devlink_trap_generic_verify(trap);
8752 else
8753 return devlink_trap_driver_verify(trap);
8754}
8755
8756static int
8757devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
8758{
8759 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
8760 return -EINVAL;
8761
8762 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
8763 return -EINVAL;
8764
8765 return 0;
8766}
8767
8768static int
8769devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
8770{
8771 int i;
8772
8773 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
8774 return -EINVAL;
8775
8776 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
8777 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
8778 return -EEXIST;
8779 }
8780
8781 return 0;
8782}
8783
8784static int devlink_trap_group_verify(const struct devlink_trap_group *group)
8785{
8786 if (group->generic)
8787 return devlink_trap_group_generic_verify(group);
8788 else
8789 return devlink_trap_group_driver_verify(group);
8790}
8791
8792static void
8793devlink_trap_group_notify(struct devlink *devlink,
8794 const struct devlink_trap_group_item *group_item,
8795 enum devlink_command cmd)
8796{
8797 struct sk_buff *msg;
8798 int err;
8799
8800 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
8801 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
8802
8803 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8804 if (!msg)
8805 return;
8806
8807 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
8808 0);
8809 if (err) {
8810 nlmsg_free(msg);
8811 return;
8812 }
8813
8814 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
8815 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
8816}
8817
Ido Schimmel0f420b62019-08-17 16:28:17 +03008818static int
8819devlink_trap_item_group_link(struct devlink *devlink,
8820 struct devlink_trap_item *trap_item)
8821{
Ido Schimmel107f1672020-03-22 20:48:30 +02008822 u16 group_id = trap_item->trap->init_group_id;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008823 struct devlink_trap_group_item *group_item;
8824
Ido Schimmel107f1672020-03-22 20:48:30 +02008825 group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
Ido Schimmela09b37f2020-03-22 20:48:29 +02008826 if (WARN_ON_ONCE(!group_item))
8827 return -EINVAL;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008828
8829 trap_item->group_item = group_item;
8830
8831 return 0;
8832}
8833
Ido Schimmel0f420b62019-08-17 16:28:17 +03008834static void devlink_trap_notify(struct devlink *devlink,
8835 const struct devlink_trap_item *trap_item,
8836 enum devlink_command cmd)
8837{
8838 struct sk_buff *msg;
8839 int err;
8840
8841 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
8842 cmd != DEVLINK_CMD_TRAP_DEL);
8843
8844 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8845 if (!msg)
8846 return;
8847
8848 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
8849 if (err) {
8850 nlmsg_free(msg);
8851 return;
8852 }
8853
8854 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
8855 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
8856}
8857
8858static int
8859devlink_trap_register(struct devlink *devlink,
8860 const struct devlink_trap *trap, void *priv)
8861{
8862 struct devlink_trap_item *trap_item;
8863 int err;
8864
8865 if (devlink_trap_item_lookup(devlink, trap->name))
8866 return -EEXIST;
8867
8868 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
8869 if (!trap_item)
8870 return -ENOMEM;
8871
8872 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
8873 if (!trap_item->stats) {
8874 err = -ENOMEM;
8875 goto err_stats_alloc;
8876 }
8877
8878 trap_item->trap = trap;
8879 trap_item->action = trap->init_action;
8880 trap_item->priv = priv;
8881
8882 err = devlink_trap_item_group_link(devlink, trap_item);
8883 if (err)
8884 goto err_group_link;
8885
8886 err = devlink->ops->trap_init(devlink, trap, trap_item);
8887 if (err)
8888 goto err_trap_init;
8889
8890 list_add_tail(&trap_item->list, &devlink->trap_list);
8891 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
8892
8893 return 0;
8894
8895err_trap_init:
Ido Schimmel0f420b62019-08-17 16:28:17 +03008896err_group_link:
8897 free_percpu(trap_item->stats);
8898err_stats_alloc:
8899 kfree(trap_item);
8900 return err;
8901}
8902
8903static void devlink_trap_unregister(struct devlink *devlink,
8904 const struct devlink_trap *trap)
8905{
8906 struct devlink_trap_item *trap_item;
8907
8908 trap_item = devlink_trap_item_lookup(devlink, trap->name);
8909 if (WARN_ON_ONCE(!trap_item))
8910 return;
8911
8912 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
8913 list_del(&trap_item->list);
8914 if (devlink->ops->trap_fini)
8915 devlink->ops->trap_fini(devlink, trap, trap_item);
Ido Schimmel0f420b62019-08-17 16:28:17 +03008916 free_percpu(trap_item->stats);
8917 kfree(trap_item);
8918}
8919
8920static void devlink_trap_disable(struct devlink *devlink,
8921 const struct devlink_trap *trap)
8922{
8923 struct devlink_trap_item *trap_item;
8924
8925 trap_item = devlink_trap_item_lookup(devlink, trap->name);
8926 if (WARN_ON_ONCE(!trap_item))
8927 return;
8928
8929 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP);
8930 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
8931}
8932
8933/**
8934 * devlink_traps_register - Register packet traps with devlink.
8935 * @devlink: devlink.
8936 * @traps: Packet traps.
8937 * @traps_count: Count of provided packet traps.
8938 * @priv: Driver private information.
8939 *
8940 * Return: Non-zero value on failure.
8941 */
8942int devlink_traps_register(struct devlink *devlink,
8943 const struct devlink_trap *traps,
8944 size_t traps_count, void *priv)
8945{
8946 int i, err;
8947
8948 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
8949 return -EINVAL;
8950
8951 mutex_lock(&devlink->lock);
8952 for (i = 0; i < traps_count; i++) {
8953 const struct devlink_trap *trap = &traps[i];
8954
8955 err = devlink_trap_verify(trap);
8956 if (err)
8957 goto err_trap_verify;
8958
8959 err = devlink_trap_register(devlink, trap, priv);
8960 if (err)
8961 goto err_trap_register;
8962 }
8963 mutex_unlock(&devlink->lock);
8964
8965 return 0;
8966
8967err_trap_register:
8968err_trap_verify:
8969 for (i--; i >= 0; i--)
8970 devlink_trap_unregister(devlink, &traps[i]);
8971 mutex_unlock(&devlink->lock);
8972 return err;
8973}
8974EXPORT_SYMBOL_GPL(devlink_traps_register);
8975
8976/**
8977 * devlink_traps_unregister - Unregister packet traps from devlink.
8978 * @devlink: devlink.
8979 * @traps: Packet traps.
8980 * @traps_count: Count of provided packet traps.
8981 */
8982void devlink_traps_unregister(struct devlink *devlink,
8983 const struct devlink_trap *traps,
8984 size_t traps_count)
8985{
8986 int i;
8987
8988 mutex_lock(&devlink->lock);
8989 /* Make sure we do not have any packets in-flight while unregistering
8990 * traps by disabling all of them and waiting for a grace period.
8991 */
8992 for (i = traps_count - 1; i >= 0; i--)
8993 devlink_trap_disable(devlink, &traps[i]);
8994 synchronize_rcu();
8995 for (i = traps_count - 1; i >= 0; i--)
8996 devlink_trap_unregister(devlink, &traps[i]);
8997 mutex_unlock(&devlink->lock);
8998}
8999EXPORT_SYMBOL_GPL(devlink_traps_unregister);
9000
9001static void
9002devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
9003 size_t skb_len)
9004{
9005 struct devlink_stats *stats;
9006
9007 stats = this_cpu_ptr(trap_stats);
9008 u64_stats_update_begin(&stats->syncp);
9009 stats->rx_bytes += skb_len;
9010 stats->rx_packets++;
9011 u64_stats_update_end(&stats->syncp);
9012}
9013
9014static void
9015devlink_trap_report_metadata_fill(struct net_dm_hw_metadata *hw_metadata,
9016 const struct devlink_trap_item *trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009017 struct devlink_port *in_devlink_port,
9018 const struct flow_action_cookie *fa_cookie)
Ido Schimmel0f420b62019-08-17 16:28:17 +03009019{
9020 struct devlink_trap_group_item *group_item = trap_item->group_item;
9021
9022 hw_metadata->trap_group_name = group_item->group->name;
9023 hw_metadata->trap_name = trap_item->trap->name;
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009024 hw_metadata->fa_cookie = fa_cookie;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009025
9026 spin_lock(&in_devlink_port->type_lock);
9027 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
9028 hw_metadata->input_dev = in_devlink_port->type_dev;
9029 spin_unlock(&in_devlink_port->type_lock);
9030}
9031
9032/**
9033 * devlink_trap_report - Report trapped packet to drop monitor.
9034 * @devlink: devlink.
9035 * @skb: Trapped packet.
9036 * @trap_ctx: Trap context.
9037 * @in_devlink_port: Input devlink port.
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009038 * @fa_cookie: Flow action cookie. Could be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03009039 */
9040void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009041 void *trap_ctx, struct devlink_port *in_devlink_port,
9042 const struct flow_action_cookie *fa_cookie)
9043
Ido Schimmel0f420b62019-08-17 16:28:17 +03009044{
9045 struct devlink_trap_item *trap_item = trap_ctx;
9046 struct net_dm_hw_metadata hw_metadata = {};
9047
9048 devlink_trap_stats_update(trap_item->stats, skb->len);
9049 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
9050
Ido Schimmel30a4e9a2020-05-29 21:36:40 +03009051 /* Control packets were not dropped by the device or encountered an
9052 * exception during forwarding and therefore should not be reported to
9053 * the kernel's drop monitor.
9054 */
9055 if (trap_item->trap->type == DEVLINK_TRAP_TYPE_CONTROL)
9056 return;
9057
Ido Schimmel0f420b62019-08-17 16:28:17 +03009058 devlink_trap_report_metadata_fill(&hw_metadata, trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009059 in_devlink_port, fa_cookie);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009060 net_dm_hw_report(skb, &hw_metadata);
9061}
9062EXPORT_SYMBOL_GPL(devlink_trap_report);
9063
9064/**
9065 * devlink_trap_ctx_priv - Trap context to driver private information.
9066 * @trap_ctx: Trap context.
9067 *
9068 * Return: Driver private information passed during registration.
9069 */
9070void *devlink_trap_ctx_priv(void *trap_ctx)
9071{
9072 struct devlink_trap_item *trap_item = trap_ctx;
9073
9074 return trap_item->priv;
9075}
9076EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
9077
Ido Schimmel95ad9552020-03-22 20:48:26 +02009078static int
Ido Schimmelf9f54392020-03-30 22:38:21 +03009079devlink_trap_group_item_policer_link(struct devlink *devlink,
9080 struct devlink_trap_group_item *group_item)
9081{
9082 u32 policer_id = group_item->group->init_policer_id;
9083 struct devlink_trap_policer_item *policer_item;
9084
9085 if (policer_id == 0)
9086 return 0;
9087
9088 policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
9089 if (WARN_ON_ONCE(!policer_item))
9090 return -EINVAL;
9091
9092 group_item->policer_item = policer_item;
9093
9094 return 0;
9095}
9096
9097static int
Ido Schimmel95ad9552020-03-22 20:48:26 +02009098devlink_trap_group_register(struct devlink *devlink,
9099 const struct devlink_trap_group *group)
9100{
9101 struct devlink_trap_group_item *group_item;
9102 int err;
9103
9104 if (devlink_trap_group_item_lookup(devlink, group->name))
9105 return -EEXIST;
9106
9107 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
9108 if (!group_item)
9109 return -ENOMEM;
9110
9111 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9112 if (!group_item->stats) {
9113 err = -ENOMEM;
9114 goto err_stats_alloc;
9115 }
9116
9117 group_item->group = group;
Ido Schimmel95ad9552020-03-22 20:48:26 +02009118
Ido Schimmelf9f54392020-03-30 22:38:21 +03009119 err = devlink_trap_group_item_policer_link(devlink, group_item);
9120 if (err)
9121 goto err_policer_link;
9122
Ido Schimmel95ad9552020-03-22 20:48:26 +02009123 if (devlink->ops->trap_group_init) {
9124 err = devlink->ops->trap_group_init(devlink, group);
9125 if (err)
9126 goto err_group_init;
9127 }
9128
9129 list_add_tail(&group_item->list, &devlink->trap_group_list);
9130 devlink_trap_group_notify(devlink, group_item,
9131 DEVLINK_CMD_TRAP_GROUP_NEW);
9132
9133 return 0;
9134
9135err_group_init:
Ido Schimmelf9f54392020-03-30 22:38:21 +03009136err_policer_link:
Ido Schimmel95ad9552020-03-22 20:48:26 +02009137 free_percpu(group_item->stats);
9138err_stats_alloc:
9139 kfree(group_item);
9140 return err;
9141}
9142
9143static void
9144devlink_trap_group_unregister(struct devlink *devlink,
9145 const struct devlink_trap_group *group)
9146{
9147 struct devlink_trap_group_item *group_item;
9148
9149 group_item = devlink_trap_group_item_lookup(devlink, group->name);
9150 if (WARN_ON_ONCE(!group_item))
9151 return;
9152
9153 devlink_trap_group_notify(devlink, group_item,
9154 DEVLINK_CMD_TRAP_GROUP_DEL);
9155 list_del(&group_item->list);
9156 free_percpu(group_item->stats);
9157 kfree(group_item);
9158}
9159
9160/**
9161 * devlink_trap_groups_register - Register packet trap groups with devlink.
9162 * @devlink: devlink.
9163 * @groups: Packet trap groups.
9164 * @groups_count: Count of provided packet trap groups.
9165 *
9166 * Return: Non-zero value on failure.
9167 */
9168int devlink_trap_groups_register(struct devlink *devlink,
9169 const struct devlink_trap_group *groups,
9170 size_t groups_count)
9171{
9172 int i, err;
9173
9174 mutex_lock(&devlink->lock);
9175 for (i = 0; i < groups_count; i++) {
9176 const struct devlink_trap_group *group = &groups[i];
9177
9178 err = devlink_trap_group_verify(group);
9179 if (err)
9180 goto err_trap_group_verify;
9181
9182 err = devlink_trap_group_register(devlink, group);
9183 if (err)
9184 goto err_trap_group_register;
9185 }
9186 mutex_unlock(&devlink->lock);
9187
9188 return 0;
9189
9190err_trap_group_register:
9191err_trap_group_verify:
9192 for (i--; i >= 0; i--)
9193 devlink_trap_group_unregister(devlink, &groups[i]);
9194 mutex_unlock(&devlink->lock);
9195 return err;
9196}
9197EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
9198
9199/**
9200 * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
9201 * @devlink: devlink.
9202 * @groups: Packet trap groups.
9203 * @groups_count: Count of provided packet trap groups.
9204 */
9205void devlink_trap_groups_unregister(struct devlink *devlink,
9206 const struct devlink_trap_group *groups,
9207 size_t groups_count)
9208{
9209 int i;
9210
9211 mutex_lock(&devlink->lock);
9212 for (i = groups_count - 1; i >= 0; i--)
9213 devlink_trap_group_unregister(devlink, &groups[i]);
9214 mutex_unlock(&devlink->lock);
9215}
9216EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
9217
Ido Schimmel1e8c6612020-03-30 22:38:18 +03009218static void
9219devlink_trap_policer_notify(struct devlink *devlink,
9220 const struct devlink_trap_policer_item *policer_item,
9221 enum devlink_command cmd)
9222{
9223 struct sk_buff *msg;
9224 int err;
9225
9226 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
9227 cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
9228
9229 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9230 if (!msg)
9231 return;
9232
9233 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
9234 0, 0);
9235 if (err) {
9236 nlmsg_free(msg);
9237 return;
9238 }
9239
9240 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9241 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9242}
9243
9244static int
9245devlink_trap_policer_register(struct devlink *devlink,
9246 const struct devlink_trap_policer *policer)
9247{
9248 struct devlink_trap_policer_item *policer_item;
9249 int err;
9250
9251 if (devlink_trap_policer_item_lookup(devlink, policer->id))
9252 return -EEXIST;
9253
9254 policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
9255 if (!policer_item)
9256 return -ENOMEM;
9257
9258 policer_item->policer = policer;
9259 policer_item->rate = policer->init_rate;
9260 policer_item->burst = policer->init_burst;
9261
9262 if (devlink->ops->trap_policer_init) {
9263 err = devlink->ops->trap_policer_init(devlink, policer);
9264 if (err)
9265 goto err_policer_init;
9266 }
9267
9268 list_add_tail(&policer_item->list, &devlink->trap_policer_list);
9269 devlink_trap_policer_notify(devlink, policer_item,
9270 DEVLINK_CMD_TRAP_POLICER_NEW);
9271
9272 return 0;
9273
9274err_policer_init:
9275 kfree(policer_item);
9276 return err;
9277}
9278
9279static void
9280devlink_trap_policer_unregister(struct devlink *devlink,
9281 const struct devlink_trap_policer *policer)
9282{
9283 struct devlink_trap_policer_item *policer_item;
9284
9285 policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
9286 if (WARN_ON_ONCE(!policer_item))
9287 return;
9288
9289 devlink_trap_policer_notify(devlink, policer_item,
9290 DEVLINK_CMD_TRAP_POLICER_DEL);
9291 list_del(&policer_item->list);
9292 if (devlink->ops->trap_policer_fini)
9293 devlink->ops->trap_policer_fini(devlink, policer);
9294 kfree(policer_item);
9295}
9296
9297/**
9298 * devlink_trap_policers_register - Register packet trap policers with devlink.
9299 * @devlink: devlink.
9300 * @policers: Packet trap policers.
9301 * @policers_count: Count of provided packet trap policers.
9302 *
9303 * Return: Non-zero value on failure.
9304 */
9305int
9306devlink_trap_policers_register(struct devlink *devlink,
9307 const struct devlink_trap_policer *policers,
9308 size_t policers_count)
9309{
9310 int i, err;
9311
9312 mutex_lock(&devlink->lock);
9313 for (i = 0; i < policers_count; i++) {
9314 const struct devlink_trap_policer *policer = &policers[i];
9315
9316 if (WARN_ON(policer->id == 0 ||
9317 policer->max_rate < policer->min_rate ||
9318 policer->max_burst < policer->min_burst)) {
9319 err = -EINVAL;
9320 goto err_trap_policer_verify;
9321 }
9322
9323 err = devlink_trap_policer_register(devlink, policer);
9324 if (err)
9325 goto err_trap_policer_register;
9326 }
9327 mutex_unlock(&devlink->lock);
9328
9329 return 0;
9330
9331err_trap_policer_register:
9332err_trap_policer_verify:
9333 for (i--; i >= 0; i--)
9334 devlink_trap_policer_unregister(devlink, &policers[i]);
9335 mutex_unlock(&devlink->lock);
9336 return err;
9337}
9338EXPORT_SYMBOL_GPL(devlink_trap_policers_register);
9339
9340/**
9341 * devlink_trap_policers_unregister - Unregister packet trap policers from devlink.
9342 * @devlink: devlink.
9343 * @policers: Packet trap policers.
9344 * @policers_count: Count of provided packet trap policers.
9345 */
9346void
9347devlink_trap_policers_unregister(struct devlink *devlink,
9348 const struct devlink_trap_policer *policers,
9349 size_t policers_count)
9350{
9351 int i;
9352
9353 mutex_lock(&devlink->lock);
9354 for (i = policers_count - 1; i >= 0; i--)
9355 devlink_trap_policer_unregister(devlink, &policers[i]);
9356 mutex_unlock(&devlink->lock);
9357}
9358EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister);
9359
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009360static void __devlink_compat_running_version(struct devlink *devlink,
9361 char *buf, size_t len)
9362{
9363 const struct nlattr *nlattr;
9364 struct devlink_info_req req;
9365 struct sk_buff *msg;
9366 int rem, err;
9367
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009368 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9369 if (!msg)
9370 return;
9371
9372 req.msg = msg;
9373 err = devlink->ops->info_get(devlink, &req, NULL);
9374 if (err)
9375 goto free_msg;
9376
9377 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
9378 const struct nlattr *kv;
9379 int rem_kv;
9380
9381 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
9382 continue;
9383
9384 nla_for_each_nested(kv, nlattr, rem_kv) {
9385 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
9386 continue;
9387
9388 strlcat(buf, nla_data(kv), len);
9389 strlcat(buf, " ", len);
9390 }
9391 }
9392free_msg:
9393 nlmsg_free(msg);
9394}
9395
9396void devlink_compat_running_version(struct net_device *dev,
9397 char *buf, size_t len)
9398{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009399 struct devlink *devlink;
9400
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009401 dev_hold(dev);
9402 rtnl_unlock();
9403
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009404 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08009405 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009406 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009407
9408 mutex_lock(&devlink->lock);
9409 __devlink_compat_running_version(devlink, buf, len);
9410 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009411
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009412out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009413 rtnl_lock();
9414 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009415}
9416
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009417int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
9418{
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009419 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009420 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009421
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009422 dev_hold(dev);
9423 rtnl_unlock();
9424
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009425 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009426 if (!devlink || !devlink->ops->flash_update) {
9427 ret = -EOPNOTSUPP;
9428 goto out;
9429 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009430
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009431 mutex_lock(&devlink->lock);
9432 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
9433 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009434
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009435out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009436 rtnl_lock();
9437 dev_put(dev);
9438
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009439 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009440}
9441
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01009442int devlink_compat_phys_port_name_get(struct net_device *dev,
9443 char *name, size_t len)
9444{
9445 struct devlink_port *devlink_port;
9446
9447 /* RTNL mutex is held here which ensures that devlink_port
9448 * instance cannot disappear in the middle. No need to take
9449 * any devlink lock as only permanent values are accessed.
9450 */
9451 ASSERT_RTNL();
9452
9453 devlink_port = netdev_to_devlink_port(dev);
9454 if (!devlink_port)
9455 return -EOPNOTSUPP;
9456
9457 return __devlink_port_phys_port_name_get(devlink_port, name, len);
9458}
9459
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009460int devlink_compat_switch_id_get(struct net_device *dev,
9461 struct netdev_phys_item_id *ppid)
9462{
9463 struct devlink_port *devlink_port;
9464
Vlad Buslov043b8412019-08-12 20:02:02 +03009465 /* Caller must hold RTNL mutex or reference to dev, which ensures that
9466 * devlink_port instance cannot disappear in the middle. No need to take
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009467 * any devlink lock as only permanent values are accessed.
9468 */
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009469 devlink_port = netdev_to_devlink_port(dev);
Danielle Ratson46737a12020-07-09 16:18:15 +03009470 if (!devlink_port || !devlink_port->switch_port)
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009471 return -EOPNOTSUPP;
9472
9473 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
9474
9475 return 0;
9476}
9477
Jiri Pirko070c63f2019-10-03 11:49:39 +02009478static void __net_exit devlink_pernet_pre_exit(struct net *net)
9479{
9480 struct devlink *devlink;
9481 int err;
9482
9483 /* In case network namespace is getting destroyed, reload
9484 * all devlink instances from this namespace into init_net.
9485 */
9486 mutex_lock(&devlink_mutex);
9487 list_for_each_entry(devlink, &devlink_list, list) {
9488 if (net_eq(devlink_net(devlink), net)) {
9489 if (WARN_ON(!devlink_reload_supported(devlink)))
9490 continue;
9491 err = devlink_reload(devlink, &init_net, NULL);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01009492 if (err && err != -EOPNOTSUPP)
Jiri Pirko070c63f2019-10-03 11:49:39 +02009493 pr_warn("Failed to reload devlink instance into init_net\n");
9494 }
9495 }
9496 mutex_unlock(&devlink_mutex);
9497}
9498
9499static struct pernet_operations devlink_pernet_ops __net_initdata = {
9500 .pre_exit = devlink_pernet_pre_exit,
9501};
9502
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009503static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009504{
Jiri Pirko070c63f2019-10-03 11:49:39 +02009505 int err;
9506
9507 err = genl_register_family(&devlink_nl_family);
9508 if (err)
9509 goto out;
9510 err = register_pernet_subsys(&devlink_pernet_ops);
9511
9512out:
9513 WARN_ON(err);
9514 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009515}
9516
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009517subsys_initcall(devlink_init);