blob: 6766f9ef3152aab633382531a2cd7d6710f7ce0d [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
Parav Pandit637989b2020-07-22 18:57:11 +0300389#define DEVLINK_NL_FLAG_NEED_PORT BIT(0)
390#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100391
392/* The per devlink instance lock is taken by default in the pre-doit
393 * operation, yet several commands do not require this. The global
394 * devlink lock is taken and protects from disruption by user-calls.
395 */
Parav Pandit637989b2020-07-22 18:57:11 +0300396#define DEVLINK_NL_FLAG_NO_LOCK BIT(2)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100397
398static int devlink_nl_pre_doit(const struct genl_ops *ops,
399 struct sk_buff *skb, struct genl_info *info)
400{
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300401 struct devlink_port *devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100402 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);
Parav Pandit637989b2020-07-22 18:57:11 +0300413 info->user_ptr[0] = devlink;
414 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100415 devlink_port = devlink_port_get_from_info(devlink, info);
416 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100417 err = PTR_ERR(devlink_port);
418 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100419 }
Parav Pandit637989b2020-07-22 18:57:11 +0300420 info->user_ptr[1] = devlink_port;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300421 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300422 devlink_port = devlink_port_get_from_info(devlink, info);
423 if (!IS_ERR(devlink_port))
424 info->user_ptr[1] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100425 }
426 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100427
428unlock:
429 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
430 mutex_unlock(&devlink->lock);
431 mutex_unlock(&devlink_mutex);
432 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100433}
434
435static void devlink_nl_post_doit(const struct genl_ops *ops,
436 struct sk_buff *skb, struct genl_info *info)
437{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100438 struct devlink *devlink;
439
Parav Pandit637989b2020-07-22 18:57:11 +0300440 devlink = info->user_ptr[0];
441 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100442 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100443 mutex_unlock(&devlink_mutex);
444}
445
Johannes Berg489111e2016-10-24 14:40:03 +0200446static struct genl_family devlink_nl_family;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100447
448enum devlink_multicast_groups {
449 DEVLINK_MCGRP_CONFIG,
450};
451
452static const struct genl_multicast_group devlink_nl_mcgrps[] = {
453 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
454};
455
456static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
457{
458 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
459 return -EMSGSIZE;
460 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
461 return -EMSGSIZE;
462 return 0;
463}
464
465static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
466 enum devlink_command cmd, u32 portid,
467 u32 seq, int flags)
468{
469 void *hdr;
470
471 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
472 if (!hdr)
473 return -EMSGSIZE;
474
475 if (devlink_nl_put_handle(msg, devlink))
476 goto nla_put_failure;
Jiri Pirko2670ac22019-09-12 10:49:46 +0200477 if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed))
478 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100479
480 genlmsg_end(msg, hdr);
481 return 0;
482
483nla_put_failure:
484 genlmsg_cancel(msg, hdr);
485 return -EMSGSIZE;
486}
487
488static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
489{
490 struct sk_buff *msg;
491 int err;
492
493 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
494
495 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
496 if (!msg)
497 return;
498
499 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
500 if (err) {
501 nlmsg_free(msg);
502 return;
503 }
504
505 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
506 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
507}
508
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200509static int devlink_nl_port_attrs_put(struct sk_buff *msg,
510 struct devlink_port *devlink_port)
511{
512 struct devlink_port_attrs *attrs = &devlink_port->attrs;
513
Danielle Ratson10a429b2020-07-09 16:18:14 +0300514 if (!devlink_port->attrs_set)
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200515 return 0;
Danielle Ratsona21cf0a2020-07-09 16:18:18 +0300516 if (attrs->lanes) {
517 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
518 return -EMSGSIZE;
519 }
Danielle Ratsona0f49b52020-07-09 16:18:20 +0300520 if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
521 return -EMSGSIZE;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200522 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
523 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500524 switch (devlink_port->attrs.flavour) {
525 case DEVLINK_PORT_FLAVOUR_PCI_PF:
Parav Pandit3a2d9582020-09-09 07:50:37 +0300526 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
527 attrs->pci_pf.controller) ||
528 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_pf.pf))
Parav Pandit98fd2d62019-07-08 23:17:37 -0500529 return -EMSGSIZE;
Parav Pandit05b595e2020-09-09 07:50:36 +0300530 if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_pf.external))
531 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500532 break;
533 case DEVLINK_PORT_FLAVOUR_PCI_VF:
Parav Pandit3a2d9582020-09-09 07:50:37 +0300534 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
535 attrs->pci_vf.controller) ||
536 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_vf.pf) ||
537 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER, attrs->pci_vf.vf))
Parav Pandite41b6bf2019-07-08 23:17:38 -0500538 return -EMSGSIZE;
Parav Pandit05b595e2020-09-09 07:50:36 +0300539 if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_vf.external))
540 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500541 break;
542 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
543 case DEVLINK_PORT_FLAVOUR_CPU:
544 case DEVLINK_PORT_FLAVOUR_DSA:
Parav Panditacf1ee42020-03-03 08:12:42 -0600545 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Parav Pandit58b6be42019-08-30 05:39:45 -0500546 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
547 attrs->phys.port_number))
548 return -EMSGSIZE;
549 if (!attrs->split)
550 return 0;
551 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
552 attrs->phys.port_number))
553 return -EMSGSIZE;
554 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
555 attrs->phys.split_subport_number))
556 return -EMSGSIZE;
557 break;
558 default:
559 break;
Parav Pandit98fd2d62019-07-08 23:17:37 -0500560 }
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200561 return 0;
562}
563
Parav Pandit2a916ec2020-06-19 03:32:48 +0000564static int
565devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
566 struct netlink_ext_ack *extack)
567{
568 struct devlink *devlink = port->devlink;
569 const struct devlink_ops *ops;
570 struct nlattr *function_attr;
571 bool empty_nest = true;
572 int err = 0;
573
574 function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
575 if (!function_attr)
576 return -EMSGSIZE;
577
578 ops = devlink->ops;
579 if (ops->port_function_hw_addr_get) {
Stephen Rothwell29cb9862020-06-23 13:43:06 +1000580 int hw_addr_len;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000581 u8 hw_addr[MAX_ADDR_LEN];
582
583 err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack);
584 if (err == -EOPNOTSUPP) {
585 /* Port function attributes are optional for a port. If port doesn't
586 * support function attribute, returning -EOPNOTSUPP is not an error.
587 */
588 err = 0;
589 goto out;
590 } else if (err) {
591 goto out;
592 }
593 err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr);
594 if (err)
595 goto out;
596 empty_nest = false;
597 }
598
599out:
600 if (err || empty_nest)
601 nla_nest_cancel(msg, function_attr);
602 else
603 nla_nest_end(msg, function_attr);
604 return err;
605}
606
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100607static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
608 struct devlink_port *devlink_port,
609 enum devlink_command cmd, u32 portid,
Parav Pandita829eb02020-06-19 03:32:47 +0000610 u32 seq, int flags,
611 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100612{
613 void *hdr;
614
615 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
616 if (!hdr)
617 return -EMSGSIZE;
618
619 if (devlink_nl_put_handle(msg, devlink))
620 goto nla_put_failure;
621 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
622 goto nla_put_failure;
Jiri Pirkob8f97552019-03-24 11:14:37 +0100623
Ido Schimmel0f420b62019-08-17 16:28:17 +0300624 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100625 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100626 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100627 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
628 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
629 devlink_port->desired_type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100630 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100631 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
632 struct net_device *netdev = devlink_port->type_dev;
633
634 if (netdev &&
635 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
636 netdev->ifindex) ||
637 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
638 netdev->name)))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100639 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100640 }
641 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
642 struct ib_device *ibdev = devlink_port->type_dev;
643
644 if (ibdev &&
645 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
646 ibdev->name))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100647 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100648 }
Ido Schimmel0f420b62019-08-17 16:28:17 +0300649 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200650 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100651 goto nla_put_failure;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000652 if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
653 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100654
655 genlmsg_end(msg, hdr);
656 return 0;
657
Jiri Pirkob8f97552019-03-24 11:14:37 +0100658nla_put_failure_type_locked:
Ido Schimmel0f420b62019-08-17 16:28:17 +0300659 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100660nla_put_failure:
661 genlmsg_cancel(msg, hdr);
662 return -EMSGSIZE;
663}
664
665static void devlink_port_notify(struct devlink_port *devlink_port,
666 enum devlink_command cmd)
667{
668 struct devlink *devlink = devlink_port->devlink;
669 struct sk_buff *msg;
670 int err;
671
672 if (!devlink_port->registered)
673 return;
674
675 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
676
677 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
678 if (!msg)
679 return;
680
Parav Pandita829eb02020-06-19 03:32:47 +0000681 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0,
682 NULL);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100683 if (err) {
684 nlmsg_free(msg);
685 return;
686 }
687
688 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
689 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
690}
691
692static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
693{
694 struct devlink *devlink = info->user_ptr[0];
695 struct sk_buff *msg;
696 int err;
697
698 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
699 if (!msg)
700 return -ENOMEM;
701
702 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
703 info->snd_portid, info->snd_seq, 0);
704 if (err) {
705 nlmsg_free(msg);
706 return err;
707 }
708
709 return genlmsg_reply(msg, info);
710}
711
712static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
713 struct netlink_callback *cb)
714{
715 struct devlink *devlink;
716 int start = cb->args[0];
717 int idx = 0;
718 int err;
719
720 mutex_lock(&devlink_mutex);
721 list_for_each_entry(devlink, &devlink_list, list) {
722 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
723 continue;
724 if (idx < start) {
725 idx++;
726 continue;
727 }
728 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
729 NETLINK_CB(cb->skb).portid,
730 cb->nlh->nlmsg_seq, NLM_F_MULTI);
731 if (err)
732 goto out;
733 idx++;
734 }
735out:
736 mutex_unlock(&devlink_mutex);
737
738 cb->args[0] = idx;
739 return msg->len;
740}
741
742static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
743 struct genl_info *info)
744{
Parav Pandit637989b2020-07-22 18:57:11 +0300745 struct devlink_port *devlink_port = info->user_ptr[1];
Jiri Pirko1fc22572016-04-08 19:12:48 +0200746 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100747 struct sk_buff *msg;
748 int err;
749
750 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
751 if (!msg)
752 return -ENOMEM;
753
754 err = devlink_nl_port_fill(msg, devlink, devlink_port,
755 DEVLINK_CMD_PORT_NEW,
Parav Pandita829eb02020-06-19 03:32:47 +0000756 info->snd_portid, info->snd_seq, 0,
757 info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100758 if (err) {
759 nlmsg_free(msg);
760 return err;
761 }
762
763 return genlmsg_reply(msg, info);
764}
765
766static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
767 struct netlink_callback *cb)
768{
769 struct devlink *devlink;
770 struct devlink_port *devlink_port;
771 int start = cb->args[0];
772 int idx = 0;
773 int err;
774
775 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100776 list_for_each_entry(devlink, &devlink_list, list) {
777 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
778 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100779 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100780 list_for_each_entry(devlink_port, &devlink->port_list, list) {
781 if (idx < start) {
782 idx++;
783 continue;
784 }
785 err = devlink_nl_port_fill(msg, devlink, devlink_port,
786 DEVLINK_CMD_NEW,
787 NETLINK_CB(cb->skb).portid,
788 cb->nlh->nlmsg_seq,
Parav Pandita829eb02020-06-19 03:32:47 +0000789 NLM_F_MULTI,
790 cb->extack);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100791 if (err) {
792 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100793 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100794 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100795 idx++;
796 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100797 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100798 }
799out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100800 mutex_unlock(&devlink_mutex);
801
802 cb->args[0] = idx;
803 return msg->len;
804}
805
806static int devlink_port_type_set(struct devlink *devlink,
807 struct devlink_port *devlink_port,
808 enum devlink_port_type port_type)
809
810{
811 int err;
812
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800813 if (devlink->ops->port_type_set) {
Elad Raz6edf1012016-10-23 17:43:05 +0200814 if (port_type == devlink_port->type)
815 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100816 err = devlink->ops->port_type_set(devlink_port, port_type);
817 if (err)
818 return err;
819 devlink_port->desired_type = port_type;
820 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
821 return 0;
822 }
823 return -EOPNOTSUPP;
824}
825
Parav Pandita1e8ae92020-06-19 03:32:49 +0000826static int
827devlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port,
828 const struct nlattr *attr, struct netlink_ext_ack *extack)
829{
830 const struct devlink_ops *ops;
831 const u8 *hw_addr;
832 int hw_addr_len;
833 int err;
834
835 hw_addr = nla_data(attr);
836 hw_addr_len = nla_len(attr);
837 if (hw_addr_len > MAX_ADDR_LEN) {
838 NL_SET_ERR_MSG_MOD(extack, "Port function hardware address too long");
839 return -EINVAL;
840 }
841 if (port->type == DEVLINK_PORT_TYPE_ETH) {
842 if (hw_addr_len != ETH_ALEN) {
843 NL_SET_ERR_MSG_MOD(extack, "Address must be 6 bytes for Ethernet device");
844 return -EINVAL;
845 }
846 if (!is_unicast_ether_addr(hw_addr)) {
847 NL_SET_ERR_MSG_MOD(extack, "Non-unicast hardware address unsupported");
848 return -EINVAL;
849 }
850 }
851
852 ops = devlink->ops;
853 if (!ops->port_function_hw_addr_set) {
854 NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes");
855 return -EOPNOTSUPP;
856 }
857
858 err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack);
859 if (err)
860 return err;
861
862 devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
863 return 0;
864}
865
866static int
867devlink_port_function_set(struct devlink *devlink, struct devlink_port *port,
868 const struct nlattr *attr, struct netlink_ext_ack *extack)
869{
870 struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];
871 int err;
872
873 err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr,
874 devlink_function_nl_policy, extack);
875 if (err < 0) {
876 NL_SET_ERR_MSG_MOD(extack, "Fail to parse port function attributes");
877 return err;
878 }
879
880 attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
881 if (attr)
882 err = devlink_port_function_hw_addr_set(devlink, port, attr, extack);
883
884 return err;
885}
886
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100887static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
888 struct genl_info *info)
889{
Parav Pandit637989b2020-07-22 18:57:11 +0300890 struct devlink_port *devlink_port = info->user_ptr[1];
Jiri Pirko1fc22572016-04-08 19:12:48 +0200891 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100892 int err;
893
894 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
895 enum devlink_port_type port_type;
896
897 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
898 err = devlink_port_type_set(devlink, devlink_port, port_type);
899 if (err)
900 return err;
901 }
Parav Pandita1e8ae92020-06-19 03:32:49 +0000902
903 if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
904 struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
905 struct netlink_ext_ack *extack = info->extack;
906
907 err = devlink_port_function_set(devlink, devlink_port, attr, extack);
908 if (err)
909 return err;
910 }
911
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100912 return 0;
913}
914
David Ahernac0fc8a2018-06-05 08:14:09 -0700915static int devlink_port_split(struct devlink *devlink, u32 port_index,
916 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100917
918{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800919 if (devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -0700920 return devlink->ops->port_split(devlink, port_index, count,
921 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100922 return -EOPNOTSUPP;
923}
924
925static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
926 struct genl_info *info)
927{
928 struct devlink *devlink = info->user_ptr[0];
Danielle Ratson82901ad2020-07-09 16:18:21 +0300929 struct devlink_port *devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100930 u32 port_index;
931 u32 count;
932
933 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
934 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
935 return -EINVAL;
936
Danielle Ratson82901ad2020-07-09 16:18:21 +0300937 devlink_port = devlink_port_get_from_info(devlink, info);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100938 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
939 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
Danielle Ratson82901ad2020-07-09 16:18:21 +0300940
941 if (IS_ERR(devlink_port))
942 return -EINVAL;
943
944 if (!devlink_port->attrs.splittable) {
945 /* Split ports cannot be split. */
946 if (devlink_port->attrs.split)
947 NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split further");
948 else
949 NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split");
950 return -EINVAL;
951 }
952
953 if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
954 NL_SET_ERR_MSG_MOD(info->extack, "Invalid split count");
955 return -EINVAL;
956 }
957
David Ahernac0fc8a2018-06-05 08:14:09 -0700958 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100959}
960
David Ahernac0fc8a2018-06-05 08:14:09 -0700961static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
962 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100963
964{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800965 if (devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -0700966 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100967 return -EOPNOTSUPP;
968}
969
970static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
971 struct genl_info *info)
972{
973 struct devlink *devlink = info->user_ptr[0];
974 u32 port_index;
975
976 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
977 return -EINVAL;
978
979 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700980 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100981}
982
Jiri Pirkobf797472016-04-14 18:19:13 +0200983static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
984 struct devlink_sb *devlink_sb,
985 enum devlink_command cmd, u32 portid,
986 u32 seq, int flags)
987{
988 void *hdr;
989
990 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
991 if (!hdr)
992 return -EMSGSIZE;
993
994 if (devlink_nl_put_handle(msg, devlink))
995 goto nla_put_failure;
996 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
997 goto nla_put_failure;
998 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
999 goto nla_put_failure;
1000 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
1001 devlink_sb->ingress_pools_count))
1002 goto nla_put_failure;
1003 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
1004 devlink_sb->egress_pools_count))
1005 goto nla_put_failure;
1006 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
1007 devlink_sb->ingress_tc_count))
1008 goto nla_put_failure;
1009 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
1010 devlink_sb->egress_tc_count))
1011 goto nla_put_failure;
1012
1013 genlmsg_end(msg, hdr);
1014 return 0;
1015
1016nla_put_failure:
1017 genlmsg_cancel(msg, hdr);
1018 return -EMSGSIZE;
1019}
1020
1021static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
1022 struct genl_info *info)
1023{
1024 struct devlink *devlink = info->user_ptr[0];
Parav Pandit637989b2020-07-22 18:57:11 +03001025 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001026 struct sk_buff *msg;
1027 int err;
1028
Parav Pandit637989b2020-07-22 18:57:11 +03001029 devlink_sb = devlink_sb_get_from_info(devlink, info);
1030 if (IS_ERR(devlink_sb))
1031 return PTR_ERR(devlink_sb);
1032
Jiri Pirkobf797472016-04-14 18:19:13 +02001033 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1034 if (!msg)
1035 return -ENOMEM;
1036
1037 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1038 DEVLINK_CMD_SB_NEW,
1039 info->snd_portid, info->snd_seq, 0);
1040 if (err) {
1041 nlmsg_free(msg);
1042 return err;
1043 }
1044
1045 return genlmsg_reply(msg, info);
1046}
1047
1048static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
1049 struct netlink_callback *cb)
1050{
1051 struct devlink *devlink;
1052 struct devlink_sb *devlink_sb;
1053 int start = cb->args[0];
1054 int idx = 0;
1055 int err;
1056
1057 mutex_lock(&devlink_mutex);
1058 list_for_each_entry(devlink, &devlink_list, list) {
1059 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
1060 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001061 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001062 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1063 if (idx < start) {
1064 idx++;
1065 continue;
1066 }
1067 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1068 DEVLINK_CMD_SB_NEW,
1069 NETLINK_CB(cb->skb).portid,
1070 cb->nlh->nlmsg_seq,
1071 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001072 if (err) {
1073 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001074 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001075 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001076 idx++;
1077 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001078 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001079 }
1080out:
1081 mutex_unlock(&devlink_mutex);
1082
1083 cb->args[0] = idx;
1084 return msg->len;
1085}
1086
1087static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
1088 struct devlink_sb *devlink_sb,
1089 u16 pool_index, enum devlink_command cmd,
1090 u32 portid, u32 seq, int flags)
1091{
1092 struct devlink_sb_pool_info pool_info;
1093 void *hdr;
1094 int err;
1095
1096 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
1097 pool_index, &pool_info);
1098 if (err)
1099 return err;
1100
1101 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1102 if (!hdr)
1103 return -EMSGSIZE;
1104
1105 if (devlink_nl_put_handle(msg, devlink))
1106 goto nla_put_failure;
1107 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1108 goto nla_put_failure;
1109 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1110 goto nla_put_failure;
1111 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
1112 goto nla_put_failure;
1113 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
1114 goto nla_put_failure;
1115 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1116 pool_info.threshold_type))
1117 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -08001118 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
1119 pool_info.cell_size))
1120 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +02001121
1122 genlmsg_end(msg, hdr);
1123 return 0;
1124
1125nla_put_failure:
1126 genlmsg_cancel(msg, hdr);
1127 return -EMSGSIZE;
1128}
1129
1130static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
1131 struct genl_info *info)
1132{
1133 struct devlink *devlink = info->user_ptr[0];
Parav Pandit637989b2020-07-22 18:57:11 +03001134 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001135 struct sk_buff *msg;
1136 u16 pool_index;
1137 int err;
1138
Parav Pandit637989b2020-07-22 18:57:11 +03001139 devlink_sb = devlink_sb_get_from_info(devlink, info);
1140 if (IS_ERR(devlink_sb))
1141 return PTR_ERR(devlink_sb);
1142
Jiri Pirkobf797472016-04-14 18:19:13 +02001143 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1144 &pool_index);
1145 if (err)
1146 return err;
1147
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001148 if (!devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001149 return -EOPNOTSUPP;
1150
1151 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1152 if (!msg)
1153 return -ENOMEM;
1154
1155 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
1156 DEVLINK_CMD_SB_POOL_NEW,
1157 info->snd_portid, info->snd_seq, 0);
1158 if (err) {
1159 nlmsg_free(msg);
1160 return err;
1161 }
1162
1163 return genlmsg_reply(msg, info);
1164}
1165
1166static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1167 struct devlink *devlink,
1168 struct devlink_sb *devlink_sb,
1169 u32 portid, u32 seq)
1170{
1171 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1172 u16 pool_index;
1173 int err;
1174
1175 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1176 if (*p_idx < start) {
1177 (*p_idx)++;
1178 continue;
1179 }
1180 err = devlink_nl_sb_pool_fill(msg, devlink,
1181 devlink_sb,
1182 pool_index,
1183 DEVLINK_CMD_SB_POOL_NEW,
1184 portid, seq, NLM_F_MULTI);
1185 if (err)
1186 return err;
1187 (*p_idx)++;
1188 }
1189 return 0;
1190}
1191
1192static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1193 struct netlink_callback *cb)
1194{
1195 struct devlink *devlink;
1196 struct devlink_sb *devlink_sb;
1197 int start = cb->args[0];
1198 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001199 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001200
1201 mutex_lock(&devlink_mutex);
1202 list_for_each_entry(devlink, &devlink_list, list) {
1203 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001204 !devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001205 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001206 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001207 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1208 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1209 devlink_sb,
1210 NETLINK_CB(cb->skb).portid,
1211 cb->nlh->nlmsg_seq);
Jakub Kicinski82274d02020-07-28 16:15:07 -07001212 if (err == -EOPNOTSUPP) {
1213 err = 0;
1214 } else if (err) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001215 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001216 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001217 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001218 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001219 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001220 }
1221out:
1222 mutex_unlock(&devlink_mutex);
1223
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001224 if (err != -EMSGSIZE)
1225 return err;
1226
Jiri Pirkobf797472016-04-14 18:19:13 +02001227 cb->args[0] = idx;
1228 return msg->len;
1229}
1230
1231static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1232 u16 pool_index, u32 size,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001233 enum devlink_sb_threshold_type threshold_type,
1234 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001235
1236{
1237 const struct devlink_ops *ops = devlink->ops;
1238
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001239 if (ops->sb_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001240 return ops->sb_pool_set(devlink, sb_index, pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001241 size, threshold_type, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001242 return -EOPNOTSUPP;
1243}
1244
1245static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1246 struct genl_info *info)
1247{
1248 struct devlink *devlink = info->user_ptr[0];
Jiri Pirkobf797472016-04-14 18:19:13 +02001249 enum devlink_sb_threshold_type threshold_type;
Parav Pandit637989b2020-07-22 18:57:11 +03001250 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001251 u16 pool_index;
1252 u32 size;
1253 int err;
1254
Parav Pandit637989b2020-07-22 18:57:11 +03001255 devlink_sb = devlink_sb_get_from_info(devlink, info);
1256 if (IS_ERR(devlink_sb))
1257 return PTR_ERR(devlink_sb);
1258
Jiri Pirkobf797472016-04-14 18:19:13 +02001259 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{
Parav Pandit637989b2020-07-22 18:57:11 +03001337 struct devlink_port *devlink_port = info->user_ptr[1];
Jiri Pirkobf797472016-04-14 18:19:13 +02001338 struct devlink *devlink = devlink_port->devlink;
Parav Pandit637989b2020-07-22 18:57:11 +03001339 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001340 struct sk_buff *msg;
1341 u16 pool_index;
1342 int err;
1343
Parav Pandit637989b2020-07-22 18:57:11 +03001344 devlink_sb = devlink_sb_get_from_info(devlink, info);
1345 if (IS_ERR(devlink_sb))
1346 return PTR_ERR(devlink_sb);
1347
Jiri Pirkobf797472016-04-14 18:19:13 +02001348 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1349 &pool_index);
1350 if (err)
1351 return err;
1352
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001353 if (!devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001354 return -EOPNOTSUPP;
1355
1356 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1357 if (!msg)
1358 return -ENOMEM;
1359
1360 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1361 devlink_sb, pool_index,
1362 DEVLINK_CMD_SB_PORT_POOL_NEW,
1363 info->snd_portid, info->snd_seq, 0);
1364 if (err) {
1365 nlmsg_free(msg);
1366 return err;
1367 }
1368
1369 return genlmsg_reply(msg, info);
1370}
1371
1372static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1373 struct devlink *devlink,
1374 struct devlink_sb *devlink_sb,
1375 u32 portid, u32 seq)
1376{
1377 struct devlink_port *devlink_port;
1378 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1379 u16 pool_index;
1380 int err;
1381
1382 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1383 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1384 if (*p_idx < start) {
1385 (*p_idx)++;
1386 continue;
1387 }
1388 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1389 devlink_port,
1390 devlink_sb,
1391 pool_index,
1392 DEVLINK_CMD_SB_PORT_POOL_NEW,
1393 portid, seq,
1394 NLM_F_MULTI);
1395 if (err)
1396 return err;
1397 (*p_idx)++;
1398 }
1399 }
1400 return 0;
1401}
1402
1403static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1404 struct netlink_callback *cb)
1405{
1406 struct devlink *devlink;
1407 struct devlink_sb *devlink_sb;
1408 int start = cb->args[0];
1409 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001410 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001411
1412 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001413 list_for_each_entry(devlink, &devlink_list, list) {
1414 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001415 !devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001416 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001417 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001418 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1419 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1420 devlink, devlink_sb,
1421 NETLINK_CB(cb->skb).portid,
1422 cb->nlh->nlmsg_seq);
Jakub Kicinski82274d02020-07-28 16:15:07 -07001423 if (err == -EOPNOTSUPP) {
1424 err = 0;
1425 } else if (err) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001426 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001427 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001428 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001429 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001430 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001431 }
1432out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001433 mutex_unlock(&devlink_mutex);
1434
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001435 if (err != -EMSGSIZE)
1436 return err;
1437
Jiri Pirkobf797472016-04-14 18:19:13 +02001438 cb->args[0] = idx;
1439 return msg->len;
1440}
1441
1442static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1443 unsigned int sb_index, u16 pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001444 u32 threshold,
1445 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001446
1447{
1448 const struct devlink_ops *ops = devlink_port->devlink->ops;
1449
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001450 if (ops->sb_port_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001451 return ops->sb_port_pool_set(devlink_port, sb_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001452 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001453 return -EOPNOTSUPP;
1454}
1455
1456static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1457 struct genl_info *info)
1458{
Parav Pandit637989b2020-07-22 18:57:11 +03001459 struct devlink_port *devlink_port = info->user_ptr[1];
1460 struct devlink *devlink = info->user_ptr[0];
1461 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001462 u16 pool_index;
1463 u32 threshold;
1464 int err;
1465
Parav Pandit637989b2020-07-22 18:57:11 +03001466 devlink_sb = devlink_sb_get_from_info(devlink, info);
1467 if (IS_ERR(devlink_sb))
1468 return PTR_ERR(devlink_sb);
1469
Jiri Pirkobf797472016-04-14 18:19:13 +02001470 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1471 &pool_index);
1472 if (err)
1473 return err;
1474
1475 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1476 return -EINVAL;
1477
1478 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1479 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001480 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001481}
1482
1483static int
1484devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1485 struct devlink_port *devlink_port,
1486 struct devlink_sb *devlink_sb, u16 tc_index,
1487 enum devlink_sb_pool_type pool_type,
1488 enum devlink_command cmd,
1489 u32 portid, u32 seq, int flags)
1490{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001491 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001492 u16 pool_index;
1493 u32 threshold;
1494 void *hdr;
1495 int err;
1496
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001497 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1498 tc_index, pool_type,
1499 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001500 if (err)
1501 return err;
1502
1503 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1504 if (!hdr)
1505 return -EMSGSIZE;
1506
1507 if (devlink_nl_put_handle(msg, devlink))
1508 goto nla_put_failure;
1509 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1510 goto nla_put_failure;
1511 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1512 goto nla_put_failure;
1513 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1514 goto nla_put_failure;
1515 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1516 goto nla_put_failure;
1517 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1518 goto nla_put_failure;
1519 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1520 goto nla_put_failure;
1521
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001522 if (ops->sb_occ_tc_port_bind_get) {
1523 u32 cur;
1524 u32 max;
1525
1526 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1527 devlink_sb->index,
1528 tc_index, pool_type,
1529 &cur, &max);
1530 if (err && err != -EOPNOTSUPP)
1531 return err;
1532 if (!err) {
1533 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1534 goto nla_put_failure;
1535 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1536 goto nla_put_failure;
1537 }
1538 }
1539
Jiri Pirkobf797472016-04-14 18:19:13 +02001540 genlmsg_end(msg, hdr);
1541 return 0;
1542
1543nla_put_failure:
1544 genlmsg_cancel(msg, hdr);
1545 return -EMSGSIZE;
1546}
1547
1548static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1549 struct genl_info *info)
1550{
Parav Pandit637989b2020-07-22 18:57:11 +03001551 struct devlink_port *devlink_port = info->user_ptr[1];
Jiri Pirkobf797472016-04-14 18:19:13 +02001552 struct devlink *devlink = devlink_port->devlink;
Parav Pandit637989b2020-07-22 18:57:11 +03001553 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001554 struct sk_buff *msg;
1555 enum devlink_sb_pool_type pool_type;
1556 u16 tc_index;
1557 int err;
1558
Parav Pandit637989b2020-07-22 18:57:11 +03001559 devlink_sb = devlink_sb_get_from_info(devlink, info);
1560 if (IS_ERR(devlink_sb))
1561 return PTR_ERR(devlink_sb);
1562
Jiri Pirkobf797472016-04-14 18:19:13 +02001563 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1564 if (err)
1565 return err;
1566
1567 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1568 pool_type, &tc_index);
1569 if (err)
1570 return err;
1571
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001572 if (!devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001573 return -EOPNOTSUPP;
1574
1575 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1576 if (!msg)
1577 return -ENOMEM;
1578
1579 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1580 devlink_sb, tc_index, pool_type,
1581 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1582 info->snd_portid,
1583 info->snd_seq, 0);
1584 if (err) {
1585 nlmsg_free(msg);
1586 return err;
1587 }
1588
1589 return genlmsg_reply(msg, info);
1590}
1591
1592static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1593 int start, int *p_idx,
1594 struct devlink *devlink,
1595 struct devlink_sb *devlink_sb,
1596 u32 portid, u32 seq)
1597{
1598 struct devlink_port *devlink_port;
1599 u16 tc_index;
1600 int err;
1601
1602 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1603 for (tc_index = 0;
1604 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1605 if (*p_idx < start) {
1606 (*p_idx)++;
1607 continue;
1608 }
1609 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1610 devlink_port,
1611 devlink_sb,
1612 tc_index,
1613 DEVLINK_SB_POOL_TYPE_INGRESS,
1614 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1615 portid, seq,
1616 NLM_F_MULTI);
1617 if (err)
1618 return err;
1619 (*p_idx)++;
1620 }
1621 for (tc_index = 0;
1622 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1623 if (*p_idx < start) {
1624 (*p_idx)++;
1625 continue;
1626 }
1627 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1628 devlink_port,
1629 devlink_sb,
1630 tc_index,
1631 DEVLINK_SB_POOL_TYPE_EGRESS,
1632 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1633 portid, seq,
1634 NLM_F_MULTI);
1635 if (err)
1636 return err;
1637 (*p_idx)++;
1638 }
1639 }
1640 return 0;
1641}
1642
1643static int
1644devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1645 struct netlink_callback *cb)
1646{
1647 struct devlink *devlink;
1648 struct devlink_sb *devlink_sb;
1649 int start = cb->args[0];
1650 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001651 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001652
1653 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001654 list_for_each_entry(devlink, &devlink_list, list) {
1655 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001656 !devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001657 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001658
1659 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001660 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1661 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1662 devlink,
1663 devlink_sb,
1664 NETLINK_CB(cb->skb).portid,
1665 cb->nlh->nlmsg_seq);
Jakub Kicinski82274d02020-07-28 16:15:07 -07001666 if (err == -EOPNOTSUPP) {
1667 err = 0;
1668 } else if (err) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001669 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001670 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001671 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001672 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001673 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001674 }
1675out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001676 mutex_unlock(&devlink_mutex);
1677
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001678 if (err != -EMSGSIZE)
1679 return err;
1680
Jiri Pirkobf797472016-04-14 18:19:13 +02001681 cb->args[0] = idx;
1682 return msg->len;
1683}
1684
1685static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1686 unsigned int sb_index, u16 tc_index,
1687 enum devlink_sb_pool_type pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001688 u16 pool_index, u32 threshold,
1689 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001690
1691{
1692 const struct devlink_ops *ops = devlink_port->devlink->ops;
1693
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001694 if (ops->sb_tc_pool_bind_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001695 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1696 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001697 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001698 return -EOPNOTSUPP;
1699}
1700
1701static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1702 struct genl_info *info)
1703{
Parav Pandit637989b2020-07-22 18:57:11 +03001704 struct devlink_port *devlink_port = info->user_ptr[1];
1705 struct devlink *devlink = info->user_ptr[0];
Jiri Pirkobf797472016-04-14 18:19:13 +02001706 enum devlink_sb_pool_type pool_type;
Parav Pandit637989b2020-07-22 18:57:11 +03001707 struct devlink_sb *devlink_sb;
Jiri Pirkobf797472016-04-14 18:19:13 +02001708 u16 tc_index;
1709 u16 pool_index;
1710 u32 threshold;
1711 int err;
1712
Parav Pandit637989b2020-07-22 18:57:11 +03001713 devlink_sb = devlink_sb_get_from_info(devlink, info);
1714 if (IS_ERR(devlink_sb))
1715 return PTR_ERR(devlink_sb);
1716
Jiri Pirkobf797472016-04-14 18:19:13 +02001717 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1718 if (err)
1719 return err;
1720
1721 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1722 pool_type, &tc_index);
1723 if (err)
1724 return err;
1725
1726 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1727 &pool_index);
1728 if (err)
1729 return err;
1730
1731 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1732 return -EINVAL;
1733
1734 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1735 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1736 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001737 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001738}
1739
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001740static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1741 struct genl_info *info)
1742{
1743 struct devlink *devlink = info->user_ptr[0];
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001744 const struct devlink_ops *ops = devlink->ops;
Parav Pandit637989b2020-07-22 18:57:11 +03001745 struct devlink_sb *devlink_sb;
1746
1747 devlink_sb = devlink_sb_get_from_info(devlink, info);
1748 if (IS_ERR(devlink_sb))
1749 return PTR_ERR(devlink_sb);
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001750
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001751 if (ops->sb_occ_snapshot)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001752 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1753 return -EOPNOTSUPP;
1754}
1755
1756static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1757 struct genl_info *info)
1758{
1759 struct devlink *devlink = info->user_ptr[0];
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001760 const struct devlink_ops *ops = devlink->ops;
Parav Pandit637989b2020-07-22 18:57:11 +03001761 struct devlink_sb *devlink_sb;
1762
1763 devlink_sb = devlink_sb_get_from_info(devlink, info);
1764 if (IS_ERR(devlink_sb))
1765 return PTR_ERR(devlink_sb);
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001766
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001767 if (ops->sb_occ_max_clear)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001768 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1769 return -EOPNOTSUPP;
1770}
1771
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001772static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1773 enum devlink_command cmd, u32 portid,
1774 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001775{
Roi Dayan59bfde02016-11-22 23:09:57 +02001776 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001777 enum devlink_eswitch_encap_mode encap_mode;
1778 u8 inline_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001779 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001780 int err = 0;
1781 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001782
1783 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1784 if (!hdr)
1785 return -EMSGSIZE;
1786
Roi Dayan59bfde02016-11-22 23:09:57 +02001787 err = devlink_nl_put_handle(msg, devlink);
1788 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001789 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001790
Jiri Pirko4456f612017-02-09 15:54:36 +01001791 if (ops->eswitch_mode_get) {
1792 err = ops->eswitch_mode_get(devlink, &mode);
1793 if (err)
1794 goto nla_put_failure;
1795 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1796 if (err)
1797 goto nla_put_failure;
1798 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001799
1800 if (ops->eswitch_inline_mode_get) {
1801 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1802 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001803 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001804 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1805 inline_mode);
1806 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001807 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001808 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001809
Roi Dayanf43e9b02016-09-25 13:52:44 +03001810 if (ops->eswitch_encap_mode_get) {
1811 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1812 if (err)
1813 goto nla_put_failure;
1814 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1815 if (err)
1816 goto nla_put_failure;
1817 }
1818
Or Gerlitz08f4b592016-07-01 14:51:01 +03001819 genlmsg_end(msg, hdr);
1820 return 0;
1821
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001822nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001823 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001824 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001825}
1826
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001827static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1828 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001829{
1830 struct devlink *devlink = info->user_ptr[0];
Or Gerlitz08f4b592016-07-01 14:51:01 +03001831 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001832 int err;
1833
Or Gerlitz08f4b592016-07-01 14:51:01 +03001834 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1835 if (!msg)
1836 return -ENOMEM;
1837
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001838 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1839 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001840
1841 if (err) {
1842 nlmsg_free(msg);
1843 return err;
1844 }
1845
1846 return genlmsg_reply(msg, info);
1847}
1848
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001849static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1850 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001851{
1852 struct devlink *devlink = info->user_ptr[0];
1853 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001854 enum devlink_eswitch_encap_mode encap_mode;
1855 u8 inline_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001856 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001857 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001858
Roi Dayan59bfde02016-11-22 23:09:57 +02001859 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1860 if (!ops->eswitch_mode_set)
1861 return -EOPNOTSUPP;
1862 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001863 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001864 if (err)
1865 return err;
1866 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001867
Roi Dayan59bfde02016-11-22 23:09:57 +02001868 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1869 if (!ops->eswitch_inline_mode_set)
1870 return -EOPNOTSUPP;
1871 inline_mode = nla_get_u8(
1872 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001873 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1874 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001875 if (err)
1876 return err;
1877 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03001878
1879 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1880 if (!ops->eswitch_encap_mode_set)
1881 return -EOPNOTSUPP;
1882 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001883 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1884 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03001885 if (err)
1886 return err;
1887 }
1888
Roi Dayan59bfde02016-11-22 23:09:57 +02001889 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001890}
1891
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001892int devlink_dpipe_match_put(struct sk_buff *skb,
1893 struct devlink_dpipe_match *match)
1894{
1895 struct devlink_dpipe_header *header = match->header;
1896 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1897 struct nlattr *match_attr;
1898
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001899 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001900 if (!match_attr)
1901 return -EMSGSIZE;
1902
1903 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1904 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1905 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1906 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1907 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1908 goto nla_put_failure;
1909
1910 nla_nest_end(skb, match_attr);
1911 return 0;
1912
1913nla_put_failure:
1914 nla_nest_cancel(skb, match_attr);
1915 return -EMSGSIZE;
1916}
1917EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1918
1919static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1920 struct sk_buff *skb)
1921{
1922 struct nlattr *matches_attr;
1923
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001924 matches_attr = nla_nest_start_noflag(skb,
1925 DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001926 if (!matches_attr)
1927 return -EMSGSIZE;
1928
1929 if (table->table_ops->matches_dump(table->priv, skb))
1930 goto nla_put_failure;
1931
1932 nla_nest_end(skb, matches_attr);
1933 return 0;
1934
1935nla_put_failure:
1936 nla_nest_cancel(skb, matches_attr);
1937 return -EMSGSIZE;
1938}
1939
1940int devlink_dpipe_action_put(struct sk_buff *skb,
1941 struct devlink_dpipe_action *action)
1942{
1943 struct devlink_dpipe_header *header = action->header;
1944 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1945 struct nlattr *action_attr;
1946
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001947 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001948 if (!action_attr)
1949 return -EMSGSIZE;
1950
1951 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1952 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1953 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1954 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1955 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1956 goto nla_put_failure;
1957
1958 nla_nest_end(skb, action_attr);
1959 return 0;
1960
1961nla_put_failure:
1962 nla_nest_cancel(skb, action_attr);
1963 return -EMSGSIZE;
1964}
1965EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1966
1967static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1968 struct sk_buff *skb)
1969{
1970 struct nlattr *actions_attr;
1971
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001972 actions_attr = nla_nest_start_noflag(skb,
1973 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001974 if (!actions_attr)
1975 return -EMSGSIZE;
1976
1977 if (table->table_ops->actions_dump(table->priv, skb))
1978 goto nla_put_failure;
1979
1980 nla_nest_end(skb, actions_attr);
1981 return 0;
1982
1983nla_put_failure:
1984 nla_nest_cancel(skb, actions_attr);
1985 return -EMSGSIZE;
1986}
1987
1988static int devlink_dpipe_table_put(struct sk_buff *skb,
1989 struct devlink_dpipe_table *table)
1990{
1991 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001992 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001993
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001994 table_size = table->table_ops->size_get(table->priv);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001995 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001996 if (!table_attr)
1997 return -EMSGSIZE;
1998
1999 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02002000 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002001 DEVLINK_ATTR_PAD))
2002 goto nla_put_failure;
2003 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
2004 table->counters_enabled))
2005 goto nla_put_failure;
2006
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01002007 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002008 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
2009 table->resource_id, DEVLINK_ATTR_PAD) ||
2010 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
2011 table->resource_units, DEVLINK_ATTR_PAD))
2012 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01002013 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002014 if (devlink_dpipe_matches_put(table, skb))
2015 goto nla_put_failure;
2016
2017 if (devlink_dpipe_actions_put(table, skb))
2018 goto nla_put_failure;
2019
2020 nla_nest_end(skb, table_attr);
2021 return 0;
2022
2023nla_put_failure:
2024 nla_nest_cancel(skb, table_attr);
2025 return -EMSGSIZE;
2026}
2027
2028static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
2029 struct genl_info *info)
2030{
2031 int err;
2032
2033 if (*pskb) {
2034 err = genlmsg_reply(*pskb, info);
2035 if (err)
2036 return err;
2037 }
2038 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
2039 if (!*pskb)
2040 return -ENOMEM;
2041 return 0;
2042}
2043
2044static int devlink_dpipe_tables_fill(struct genl_info *info,
2045 enum devlink_command cmd, int flags,
2046 struct list_head *dpipe_tables,
2047 const char *table_name)
2048{
2049 struct devlink *devlink = info->user_ptr[0];
2050 struct devlink_dpipe_table *table;
2051 struct nlattr *tables_attr;
2052 struct sk_buff *skb = NULL;
2053 struct nlmsghdr *nlh;
2054 bool incomplete;
2055 void *hdr;
2056 int i;
2057 int err;
2058
2059 table = list_first_entry(dpipe_tables,
2060 struct devlink_dpipe_table, list);
2061start_again:
2062 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2063 if (err)
2064 return err;
2065
2066 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2067 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002068 if (!hdr) {
2069 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002070 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002071 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002072
2073 if (devlink_nl_put_handle(skb, devlink))
2074 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002075 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002076 if (!tables_attr)
2077 goto nla_put_failure;
2078
2079 i = 0;
2080 incomplete = false;
2081 list_for_each_entry_from(table, dpipe_tables, list) {
2082 if (!table_name) {
2083 err = devlink_dpipe_table_put(skb, table);
2084 if (err) {
2085 if (!i)
2086 goto err_table_put;
2087 incomplete = true;
2088 break;
2089 }
2090 } else {
2091 if (!strcmp(table->name, table_name)) {
2092 err = devlink_dpipe_table_put(skb, table);
2093 if (err)
2094 break;
2095 }
2096 }
2097 i++;
2098 }
2099
2100 nla_nest_end(skb, tables_attr);
2101 genlmsg_end(skb, hdr);
2102 if (incomplete)
2103 goto start_again;
2104
2105send_done:
2106 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2107 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2108 if (!nlh) {
2109 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2110 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002111 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002112 goto send_done;
2113 }
2114
2115 return genlmsg_reply(skb, info);
2116
2117nla_put_failure:
2118 err = -EMSGSIZE;
2119err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002120 nlmsg_free(skb);
2121 return err;
2122}
2123
2124static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
2125 struct genl_info *info)
2126{
2127 struct devlink *devlink = info->user_ptr[0];
2128 const char *table_name = NULL;
2129
2130 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2131 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2132
2133 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
2134 &devlink->dpipe_table_list,
2135 table_name);
2136}
2137
2138static int devlink_dpipe_value_put(struct sk_buff *skb,
2139 struct devlink_dpipe_value *value)
2140{
2141 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
2142 value->value_size, value->value))
2143 return -EMSGSIZE;
2144 if (value->mask)
2145 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
2146 value->value_size, value->mask))
2147 return -EMSGSIZE;
2148 if (value->mapping_valid)
2149 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
2150 value->mapping_value))
2151 return -EMSGSIZE;
2152 return 0;
2153}
2154
2155static int devlink_dpipe_action_value_put(struct sk_buff *skb,
2156 struct devlink_dpipe_value *value)
2157{
2158 if (!value->action)
2159 return -EINVAL;
2160 if (devlink_dpipe_action_put(skb, value->action))
2161 return -EMSGSIZE;
2162 if (devlink_dpipe_value_put(skb, value))
2163 return -EMSGSIZE;
2164 return 0;
2165}
2166
2167static int devlink_dpipe_action_values_put(struct sk_buff *skb,
2168 struct devlink_dpipe_value *values,
2169 unsigned int values_count)
2170{
2171 struct nlattr *action_attr;
2172 int i;
2173 int err;
2174
2175 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002176 action_attr = nla_nest_start_noflag(skb,
2177 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002178 if (!action_attr)
2179 return -EMSGSIZE;
2180 err = devlink_dpipe_action_value_put(skb, &values[i]);
2181 if (err)
2182 goto err_action_value_put;
2183 nla_nest_end(skb, action_attr);
2184 }
2185 return 0;
2186
2187err_action_value_put:
2188 nla_nest_cancel(skb, action_attr);
2189 return err;
2190}
2191
2192static int devlink_dpipe_match_value_put(struct sk_buff *skb,
2193 struct devlink_dpipe_value *value)
2194{
2195 if (!value->match)
2196 return -EINVAL;
2197 if (devlink_dpipe_match_put(skb, value->match))
2198 return -EMSGSIZE;
2199 if (devlink_dpipe_value_put(skb, value))
2200 return -EMSGSIZE;
2201 return 0;
2202}
2203
2204static int devlink_dpipe_match_values_put(struct sk_buff *skb,
2205 struct devlink_dpipe_value *values,
2206 unsigned int values_count)
2207{
2208 struct nlattr *match_attr;
2209 int i;
2210 int err;
2211
2212 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002213 match_attr = nla_nest_start_noflag(skb,
2214 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002215 if (!match_attr)
2216 return -EMSGSIZE;
2217 err = devlink_dpipe_match_value_put(skb, &values[i]);
2218 if (err)
2219 goto err_match_value_put;
2220 nla_nest_end(skb, match_attr);
2221 }
2222 return 0;
2223
2224err_match_value_put:
2225 nla_nest_cancel(skb, match_attr);
2226 return err;
2227}
2228
2229static int devlink_dpipe_entry_put(struct sk_buff *skb,
2230 struct devlink_dpipe_entry *entry)
2231{
2232 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2233 int err;
2234
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002235 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002236 if (!entry_attr)
2237 return -EMSGSIZE;
2238
2239 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2240 DEVLINK_ATTR_PAD))
2241 goto nla_put_failure;
2242 if (entry->counter_valid)
2243 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2244 entry->counter, DEVLINK_ATTR_PAD))
2245 goto nla_put_failure;
2246
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002247 matches_attr = nla_nest_start_noflag(skb,
2248 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002249 if (!matches_attr)
2250 goto nla_put_failure;
2251
2252 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2253 entry->match_values_count);
2254 if (err) {
2255 nla_nest_cancel(skb, matches_attr);
2256 goto err_match_values_put;
2257 }
2258 nla_nest_end(skb, matches_attr);
2259
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002260 actions_attr = nla_nest_start_noflag(skb,
2261 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002262 if (!actions_attr)
2263 goto nla_put_failure;
2264
2265 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2266 entry->action_values_count);
2267 if (err) {
2268 nla_nest_cancel(skb, actions_attr);
2269 goto err_action_values_put;
2270 }
2271 nla_nest_end(skb, actions_attr);
2272
2273 nla_nest_end(skb, entry_attr);
2274 return 0;
2275
2276nla_put_failure:
2277 err = -EMSGSIZE;
2278err_match_values_put:
2279err_action_values_put:
2280 nla_nest_cancel(skb, entry_attr);
2281 return err;
2282}
2283
2284static struct devlink_dpipe_table *
2285devlink_dpipe_table_find(struct list_head *dpipe_tables,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302286 const char *table_name, struct devlink *devlink)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002287{
2288 struct devlink_dpipe_table *table;
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302289 list_for_each_entry_rcu(table, dpipe_tables, list,
2290 lockdep_is_held(&devlink->lock)) {
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002291 if (!strcmp(table->name, table_name))
2292 return table;
2293 }
2294 return NULL;
2295}
2296
2297int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2298{
2299 struct devlink *devlink;
2300 int err;
2301
2302 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2303 dump_ctx->info);
2304 if (err)
2305 return err;
2306
2307 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2308 dump_ctx->info->snd_portid,
2309 dump_ctx->info->snd_seq,
2310 &devlink_nl_family, NLM_F_MULTI,
2311 dump_ctx->cmd);
2312 if (!dump_ctx->hdr)
2313 goto nla_put_failure;
2314
2315 devlink = dump_ctx->info->user_ptr[0];
2316 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2317 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002318 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2319 DEVLINK_ATTR_DPIPE_ENTRIES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002320 if (!dump_ctx->nest)
2321 goto nla_put_failure;
2322 return 0;
2323
2324nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002325 nlmsg_free(dump_ctx->skb);
2326 return -EMSGSIZE;
2327}
2328EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2329
2330int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2331 struct devlink_dpipe_entry *entry)
2332{
2333 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2334}
2335EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2336
2337int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2338{
2339 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2340 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2341 return 0;
2342}
2343EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2344
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002345void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2346
2347{
2348 unsigned int value_count, value_index;
2349 struct devlink_dpipe_value *value;
2350
2351 value = entry->action_values;
2352 value_count = entry->action_values_count;
2353 for (value_index = 0; value_index < value_count; value_index++) {
2354 kfree(value[value_index].value);
2355 kfree(value[value_index].mask);
2356 }
2357
2358 value = entry->match_values;
2359 value_count = entry->match_values_count;
2360 for (value_index = 0; value_index < value_count; value_index++) {
2361 kfree(value[value_index].value);
2362 kfree(value[value_index].mask);
2363 }
2364}
2365EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2366
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002367static int devlink_dpipe_entries_fill(struct genl_info *info,
2368 enum devlink_command cmd, int flags,
2369 struct devlink_dpipe_table *table)
2370{
2371 struct devlink_dpipe_dump_ctx dump_ctx;
2372 struct nlmsghdr *nlh;
2373 int err;
2374
2375 dump_ctx.skb = NULL;
2376 dump_ctx.cmd = cmd;
2377 dump_ctx.info = info;
2378
2379 err = table->table_ops->entries_dump(table->priv,
2380 table->counters_enabled,
2381 &dump_ctx);
2382 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002383 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002384
2385send_done:
2386 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2387 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2388 if (!nlh) {
2389 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2390 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002391 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002392 goto send_done;
2393 }
2394 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002395}
2396
2397static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2398 struct genl_info *info)
2399{
2400 struct devlink *devlink = info->user_ptr[0];
2401 struct devlink_dpipe_table *table;
2402 const char *table_name;
2403
2404 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2405 return -EINVAL;
2406
2407 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2408 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302409 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002410 if (!table)
2411 return -EINVAL;
2412
2413 if (!table->table_ops->entries_dump)
2414 return -EINVAL;
2415
2416 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2417 0, table);
2418}
2419
2420static int devlink_dpipe_fields_put(struct sk_buff *skb,
2421 const struct devlink_dpipe_header *header)
2422{
2423 struct devlink_dpipe_field *field;
2424 struct nlattr *field_attr;
2425 int i;
2426
2427 for (i = 0; i < header->fields_count; i++) {
2428 field = &header->fields[i];
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002429 field_attr = nla_nest_start_noflag(skb,
2430 DEVLINK_ATTR_DPIPE_FIELD);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002431 if (!field_attr)
2432 return -EMSGSIZE;
2433 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2434 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2435 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2436 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2437 goto nla_put_failure;
2438 nla_nest_end(skb, field_attr);
2439 }
2440 return 0;
2441
2442nla_put_failure:
2443 nla_nest_cancel(skb, field_attr);
2444 return -EMSGSIZE;
2445}
2446
2447static int devlink_dpipe_header_put(struct sk_buff *skb,
2448 struct devlink_dpipe_header *header)
2449{
2450 struct nlattr *fields_attr, *header_attr;
2451 int err;
2452
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002453 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002454 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002455 return -EMSGSIZE;
2456
2457 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2458 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2459 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2460 goto nla_put_failure;
2461
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002462 fields_attr = nla_nest_start_noflag(skb,
2463 DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002464 if (!fields_attr)
2465 goto nla_put_failure;
2466
2467 err = devlink_dpipe_fields_put(skb, header);
2468 if (err) {
2469 nla_nest_cancel(skb, fields_attr);
2470 goto nla_put_failure;
2471 }
2472 nla_nest_end(skb, fields_attr);
2473 nla_nest_end(skb, header_attr);
2474 return 0;
2475
2476nla_put_failure:
2477 err = -EMSGSIZE;
2478 nla_nest_cancel(skb, header_attr);
2479 return err;
2480}
2481
2482static int devlink_dpipe_headers_fill(struct genl_info *info,
2483 enum devlink_command cmd, int flags,
2484 struct devlink_dpipe_headers *
2485 dpipe_headers)
2486{
2487 struct devlink *devlink = info->user_ptr[0];
2488 struct nlattr *headers_attr;
2489 struct sk_buff *skb = NULL;
2490 struct nlmsghdr *nlh;
2491 void *hdr;
2492 int i, j;
2493 int err;
2494
2495 i = 0;
2496start_again:
2497 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2498 if (err)
2499 return err;
2500
2501 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2502 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002503 if (!hdr) {
2504 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002505 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002506 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002507
2508 if (devlink_nl_put_handle(skb, devlink))
2509 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002510 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002511 if (!headers_attr)
2512 goto nla_put_failure;
2513
2514 j = 0;
2515 for (; i < dpipe_headers->headers_count; i++) {
2516 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2517 if (err) {
2518 if (!j)
2519 goto err_table_put;
2520 break;
2521 }
2522 j++;
2523 }
2524 nla_nest_end(skb, headers_attr);
2525 genlmsg_end(skb, hdr);
2526 if (i != dpipe_headers->headers_count)
2527 goto start_again;
2528
2529send_done:
2530 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2531 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2532 if (!nlh) {
2533 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2534 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002535 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002536 goto send_done;
2537 }
2538 return genlmsg_reply(skb, info);
2539
2540nla_put_failure:
2541 err = -EMSGSIZE;
2542err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002543 nlmsg_free(skb);
2544 return err;
2545}
2546
2547static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2548 struct genl_info *info)
2549{
2550 struct devlink *devlink = info->user_ptr[0];
2551
2552 if (!devlink->dpipe_headers)
2553 return -EOPNOTSUPP;
2554 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2555 0, devlink->dpipe_headers);
2556}
2557
2558static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2559 const char *table_name,
2560 bool enable)
2561{
2562 struct devlink_dpipe_table *table;
2563
2564 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302565 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002566 if (!table)
2567 return -EINVAL;
2568
2569 if (table->counter_control_extern)
2570 return -EOPNOTSUPP;
2571
2572 if (!(table->counters_enabled ^ enable))
2573 return 0;
2574
2575 table->counters_enabled = enable;
2576 if (table->table_ops->counters_set_update)
2577 table->table_ops->counters_set_update(table->priv, enable);
2578 return 0;
2579}
2580
2581static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2582 struct genl_info *info)
2583{
2584 struct devlink *devlink = info->user_ptr[0];
2585 const char *table_name;
2586 bool counters_enable;
2587
2588 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2589 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2590 return -EINVAL;
2591
2592 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2593 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2594
2595 return devlink_dpipe_table_counters_set(devlink, table_name,
2596 counters_enable);
2597}
2598
Wei Yongjun43dd7512018-01-17 03:27:42 +00002599static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002600devlink_resource_find(struct devlink *devlink,
2601 struct devlink_resource *resource, u64 resource_id)
2602{
2603 struct list_head *resource_list;
2604
2605 if (resource)
2606 resource_list = &resource->resource_list;
2607 else
2608 resource_list = &devlink->resource_list;
2609
2610 list_for_each_entry(resource, resource_list, list) {
2611 struct devlink_resource *child_resource;
2612
2613 if (resource->id == resource_id)
2614 return resource;
2615
2616 child_resource = devlink_resource_find(devlink, resource,
2617 resource_id);
2618 if (child_resource)
2619 return child_resource;
2620 }
2621 return NULL;
2622}
2623
Wei Yongjun43dd7512018-01-17 03:27:42 +00002624static void
2625devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002626{
2627 struct devlink_resource *child_resource;
2628 bool size_valid = true;
2629 u64 parts_size = 0;
2630
2631 if (list_empty(&resource->resource_list))
2632 goto out;
2633
2634 list_for_each_entry(child_resource, &resource->resource_list, list)
2635 parts_size += child_resource->size_new;
2636
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002637 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002638 size_valid = false;
2639out:
2640 resource->size_valid = size_valid;
2641}
2642
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002643static int
2644devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2645 struct netlink_ext_ack *extack)
2646{
2647 u64 reminder;
2648 int err = 0;
2649
David S. Miller0f3e9c92018-03-06 00:53:44 -05002650 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002651 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2652 err = -EINVAL;
2653 }
2654
David S. Miller0f3e9c92018-03-06 00:53:44 -05002655 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002656 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2657 err = -EINVAL;
2658 }
2659
David S. Miller0f3e9c92018-03-06 00:53:44 -05002660 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002661 if (reminder) {
2662 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2663 err = -EINVAL;
2664 }
2665
2666 return err;
2667}
2668
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002669static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2670 struct genl_info *info)
2671{
2672 struct devlink *devlink = info->user_ptr[0];
2673 struct devlink_resource *resource;
2674 u64 resource_id;
2675 u64 size;
2676 int err;
2677
2678 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2679 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2680 return -EINVAL;
2681 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2682
2683 resource = devlink_resource_find(devlink, NULL, resource_id);
2684 if (!resource)
2685 return -EINVAL;
2686
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002687 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002688 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002689 if (err)
2690 return err;
2691
2692 resource->size_new = size;
2693 devlink_resource_validate_children(resource);
2694 if (resource->parent)
2695 devlink_resource_validate_children(resource->parent);
2696 return 0;
2697}
2698
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002699static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002700devlink_resource_size_params_put(struct devlink_resource *resource,
2701 struct sk_buff *skb)
2702{
2703 struct devlink_resource_size_params *size_params;
2704
Jiri Pirko77d27092018-02-28 13:12:09 +01002705 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002706 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2707 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2708 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2709 size_params->size_max, DEVLINK_ATTR_PAD) ||
2710 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2711 size_params->size_min, DEVLINK_ATTR_PAD) ||
2712 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2713 return -EMSGSIZE;
2714 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002715}
2716
Jiri Pirkofc56be42018-04-05 22:13:21 +02002717static int devlink_resource_occ_put(struct devlink_resource *resource,
2718 struct sk_buff *skb)
2719{
2720 if (!resource->occ_get)
2721 return 0;
2722 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2723 resource->occ_get(resource->occ_get_priv),
2724 DEVLINK_ATTR_PAD);
2725}
2726
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002727static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2728 struct devlink_resource *resource)
2729{
2730 struct devlink_resource *child_resource;
2731 struct nlattr *child_resource_attr;
2732 struct nlattr *resource_attr;
2733
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002734 resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002735 if (!resource_attr)
2736 return -EMSGSIZE;
2737
2738 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2739 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2740 DEVLINK_ATTR_PAD) ||
2741 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2742 DEVLINK_ATTR_PAD))
2743 goto nla_put_failure;
2744 if (resource->size != resource->size_new)
2745 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2746 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002747 if (devlink_resource_occ_put(resource, skb))
2748 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002749 if (devlink_resource_size_params_put(resource, skb))
2750 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002751 if (list_empty(&resource->resource_list))
2752 goto out;
2753
2754 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2755 resource->size_valid))
2756 goto nla_put_failure;
2757
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002758 child_resource_attr = nla_nest_start_noflag(skb,
2759 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002760 if (!child_resource_attr)
2761 goto nla_put_failure;
2762
2763 list_for_each_entry(child_resource, &resource->resource_list, list) {
2764 if (devlink_resource_put(devlink, skb, child_resource))
2765 goto resource_put_failure;
2766 }
2767
2768 nla_nest_end(skb, child_resource_attr);
2769out:
2770 nla_nest_end(skb, resource_attr);
2771 return 0;
2772
2773resource_put_failure:
2774 nla_nest_cancel(skb, child_resource_attr);
2775nla_put_failure:
2776 nla_nest_cancel(skb, resource_attr);
2777 return -EMSGSIZE;
2778}
2779
2780static int devlink_resource_fill(struct genl_info *info,
2781 enum devlink_command cmd, int flags)
2782{
2783 struct devlink *devlink = info->user_ptr[0];
2784 struct devlink_resource *resource;
2785 struct nlattr *resources_attr;
2786 struct sk_buff *skb = NULL;
2787 struct nlmsghdr *nlh;
2788 bool incomplete;
2789 void *hdr;
2790 int i;
2791 int err;
2792
2793 resource = list_first_entry(&devlink->resource_list,
2794 struct devlink_resource, list);
2795start_again:
2796 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2797 if (err)
2798 return err;
2799
2800 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2801 &devlink_nl_family, NLM_F_MULTI, cmd);
2802 if (!hdr) {
2803 nlmsg_free(skb);
2804 return -EMSGSIZE;
2805 }
2806
2807 if (devlink_nl_put_handle(skb, devlink))
2808 goto nla_put_failure;
2809
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002810 resources_attr = nla_nest_start_noflag(skb,
2811 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002812 if (!resources_attr)
2813 goto nla_put_failure;
2814
2815 incomplete = false;
2816 i = 0;
2817 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2818 err = devlink_resource_put(devlink, skb, resource);
2819 if (err) {
2820 if (!i)
2821 goto err_resource_put;
2822 incomplete = true;
2823 break;
2824 }
2825 i++;
2826 }
2827 nla_nest_end(skb, resources_attr);
2828 genlmsg_end(skb, hdr);
2829 if (incomplete)
2830 goto start_again;
2831send_done:
2832 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2833 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2834 if (!nlh) {
2835 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2836 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002837 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002838 goto send_done;
2839 }
2840 return genlmsg_reply(skb, info);
2841
2842nla_put_failure:
2843 err = -EMSGSIZE;
2844err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002845 nlmsg_free(skb);
2846 return err;
2847}
2848
2849static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2850 struct genl_info *info)
2851{
2852 struct devlink *devlink = info->user_ptr[0];
2853
2854 if (list_empty(&devlink->resource_list))
2855 return -EOPNOTSUPP;
2856
2857 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2858}
2859
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002860static int
2861devlink_resources_validate(struct devlink *devlink,
2862 struct devlink_resource *resource,
2863 struct genl_info *info)
2864{
2865 struct list_head *resource_list;
2866 int err = 0;
2867
2868 if (resource)
2869 resource_list = &resource->resource_list;
2870 else
2871 resource_list = &devlink->resource_list;
2872
2873 list_for_each_entry(resource, resource_list, list) {
2874 if (!resource->size_valid)
2875 return -EINVAL;
2876 err = devlink_resources_validate(devlink, resource, info);
2877 if (err)
2878 return err;
2879 }
2880 return err;
2881}
2882
Jiri Pirko070c63f2019-10-03 11:49:39 +02002883static struct net *devlink_netns_get(struct sk_buff *skb,
2884 struct genl_info *info)
2885{
2886 struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID];
2887 struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD];
2888 struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID];
2889 struct net *net;
2890
2891 if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) {
Jiri Pirko054eae82020-03-28 19:25:29 +01002892 NL_SET_ERR_MSG_MOD(info->extack, "multiple netns identifying attributes specified");
Jiri Pirko070c63f2019-10-03 11:49:39 +02002893 return ERR_PTR(-EINVAL);
2894 }
2895
2896 if (netns_pid_attr) {
2897 net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr));
2898 } else if (netns_fd_attr) {
2899 net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr));
2900 } else if (netns_id_attr) {
2901 net = get_net_ns_by_id(sock_net(skb->sk),
2902 nla_get_u32(netns_id_attr));
2903 if (!net)
2904 net = ERR_PTR(-EINVAL);
2905 } else {
2906 WARN_ON(1);
2907 net = ERR_PTR(-EINVAL);
2908 }
2909 if (IS_ERR(net)) {
Jiri Pirko054eae82020-03-28 19:25:29 +01002910 NL_SET_ERR_MSG_MOD(info->extack, "Unknown network namespace");
Jiri Pirko070c63f2019-10-03 11:49:39 +02002911 return ERR_PTR(-EINVAL);
2912 }
2913 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
2914 put_net(net);
2915 return ERR_PTR(-EPERM);
2916 }
2917 return net;
2918}
2919
2920static void devlink_param_notify(struct devlink *devlink,
2921 unsigned int port_index,
2922 struct devlink_param_item *param_item,
2923 enum devlink_command cmd);
2924
2925static void devlink_reload_netns_change(struct devlink *devlink,
2926 struct net *dest_net)
2927{
2928 struct devlink_param_item *param_item;
2929
2930 /* Userspace needs to be notified about devlink objects
2931 * removed from original and entering new network namespace.
2932 * The rest of the devlink objects are re-created during
2933 * reload process so the notifications are generated separatelly.
2934 */
2935
2936 list_for_each_entry(param_item, &devlink->param_list, list)
2937 devlink_param_notify(devlink, 0, param_item,
2938 DEVLINK_CMD_PARAM_DEL);
2939 devlink_notify(devlink, DEVLINK_CMD_DEL);
2940
Jiri Pirko8273fd82019-10-05 08:10:31 +02002941 __devlink_net_set(devlink, dest_net);
Jiri Pirko070c63f2019-10-03 11:49:39 +02002942
2943 devlink_notify(devlink, DEVLINK_CMD_NEW);
2944 list_for_each_entry(param_item, &devlink->param_list, list)
2945 devlink_param_notify(devlink, 0, param_item,
2946 DEVLINK_CMD_PARAM_NEW);
2947}
2948
Parav Panditeac5f8a2020-07-21 19:53:54 +03002949static bool devlink_reload_supported(const struct devlink *devlink)
Jiri Pirko97691062019-09-12 10:49:45 +02002950{
2951 return devlink->ops->reload_down && devlink->ops->reload_up;
2952}
2953
Jiri Pirko2670ac22019-09-12 10:49:46 +02002954static void devlink_reload_failed_set(struct devlink *devlink,
2955 bool reload_failed)
2956{
2957 if (devlink->reload_failed == reload_failed)
2958 return;
2959 devlink->reload_failed = reload_failed;
2960 devlink_notify(devlink, DEVLINK_CMD_NEW);
2961}
2962
2963bool devlink_is_reload_failed(const struct devlink *devlink)
2964{
2965 return devlink->reload_failed;
2966}
2967EXPORT_SYMBOL_GPL(devlink_is_reload_failed);
2968
Jiri Pirko070c63f2019-10-03 11:49:39 +02002969static int devlink_reload(struct devlink *devlink, struct net *dest_net,
2970 struct netlink_ext_ack *extack)
2971{
2972 int err;
2973
Jiri Pirkoa0c76342019-11-08 21:42:43 +01002974 if (!devlink->reload_enabled)
2975 return -EOPNOTSUPP;
2976
Jiri Pirko070c63f2019-10-03 11:49:39 +02002977 err = devlink->ops->reload_down(devlink, !!dest_net, extack);
2978 if (err)
2979 return err;
2980
2981 if (dest_net && !net_eq(dest_net, devlink_net(devlink)))
2982 devlink_reload_netns_change(devlink, dest_net);
2983
2984 err = devlink->ops->reload_up(devlink, extack);
2985 devlink_reload_failed_set(devlink, !!err);
2986 return err;
2987}
2988
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002989static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2990{
2991 struct devlink *devlink = info->user_ptr[0];
Jiri Pirko070c63f2019-10-03 11:49:39 +02002992 struct net *dest_net = NULL;
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002993 int err;
2994
Parav Pandit9232a3e2020-07-21 19:53:52 +03002995 if (!devlink_reload_supported(devlink))
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002996 return -EOPNOTSUPP;
2997
2998 err = devlink_resources_validate(devlink, NULL, info);
2999 if (err) {
3000 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
3001 return err;
3002 }
Jiri Pirko070c63f2019-10-03 11:49:39 +02003003
3004 if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
3005 info->attrs[DEVLINK_ATTR_NETNS_FD] ||
3006 info->attrs[DEVLINK_ATTR_NETNS_ID]) {
3007 dest_net = devlink_netns_get(skb, info);
3008 if (IS_ERR(dest_net))
3009 return PTR_ERR(dest_net);
3010 }
3011
3012 err = devlink_reload(devlink, dest_net, info->extack);
3013
3014 if (dest_net)
3015 put_net(dest_net);
3016
Jiri Pirko2670ac22019-09-12 10:49:46 +02003017 return err;
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01003018}
3019
Jiri Pirko191ed202019-06-04 15:40:40 +02003020static int devlink_nl_flash_update_fill(struct sk_buff *msg,
3021 struct devlink *devlink,
3022 enum devlink_command cmd,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003023 struct devlink_flash_notify *params)
Jiri Pirko191ed202019-06-04 15:40:40 +02003024{
3025 void *hdr;
3026
3027 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3028 if (!hdr)
3029 return -EMSGSIZE;
3030
3031 if (devlink_nl_put_handle(msg, devlink))
3032 goto nla_put_failure;
3033
3034 if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
3035 goto out;
3036
Shannon Nelson6700acc2020-09-17 18:13:24 -07003037 if (params->status_msg &&
Jiri Pirko191ed202019-06-04 15:40:40 +02003038 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003039 params->status_msg))
Jiri Pirko191ed202019-06-04 15:40:40 +02003040 goto nla_put_failure;
Shannon Nelson6700acc2020-09-17 18:13:24 -07003041 if (params->component &&
Jiri Pirko191ed202019-06-04 15:40:40 +02003042 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003043 params->component))
Jiri Pirko191ed202019-06-04 15:40:40 +02003044 goto nla_put_failure;
3045 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003046 params->done, DEVLINK_ATTR_PAD))
Jiri Pirko191ed202019-06-04 15:40:40 +02003047 goto nla_put_failure;
3048 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003049 params->total, DEVLINK_ATTR_PAD))
Jiri Pirko191ed202019-06-04 15:40:40 +02003050 goto nla_put_failure;
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003051 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003052 params->timeout, DEVLINK_ATTR_PAD))
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003053 goto nla_put_failure;
Jiri Pirko191ed202019-06-04 15:40:40 +02003054
3055out:
3056 genlmsg_end(msg, hdr);
3057 return 0;
3058
3059nla_put_failure:
3060 genlmsg_cancel(msg, hdr);
3061 return -EMSGSIZE;
3062}
3063
3064static void __devlink_flash_update_notify(struct devlink *devlink,
3065 enum devlink_command cmd,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003066 struct devlink_flash_notify *params)
Jiri Pirko191ed202019-06-04 15:40:40 +02003067{
3068 struct sk_buff *msg;
3069 int err;
3070
3071 WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
3072 cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
3073 cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
3074
3075 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3076 if (!msg)
3077 return;
3078
Shannon Nelson6700acc2020-09-17 18:13:24 -07003079 err = devlink_nl_flash_update_fill(msg, devlink, cmd, params);
Jiri Pirko191ed202019-06-04 15:40:40 +02003080 if (err)
3081 goto out_free_msg;
3082
3083 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3084 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3085 return;
3086
3087out_free_msg:
3088 nlmsg_free(msg);
3089}
3090
3091void devlink_flash_update_begin_notify(struct devlink *devlink)
3092{
Shannon Nelson6700acc2020-09-17 18:13:24 -07003093 struct devlink_flash_notify params = { 0 };
3094
Jiri Pirko191ed202019-06-04 15:40:40 +02003095 __devlink_flash_update_notify(devlink,
3096 DEVLINK_CMD_FLASH_UPDATE,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003097 &params);
Jiri Pirko191ed202019-06-04 15:40:40 +02003098}
3099EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
3100
3101void devlink_flash_update_end_notify(struct devlink *devlink)
3102{
Shannon Nelson6700acc2020-09-17 18:13:24 -07003103 struct devlink_flash_notify params = { 0 };
3104
Jiri Pirko191ed202019-06-04 15:40:40 +02003105 __devlink_flash_update_notify(devlink,
3106 DEVLINK_CMD_FLASH_UPDATE_END,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003107 &params);
Jiri Pirko191ed202019-06-04 15:40:40 +02003108}
3109EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
3110
3111void devlink_flash_update_status_notify(struct devlink *devlink,
3112 const char *status_msg,
3113 const char *component,
3114 unsigned long done,
3115 unsigned long total)
3116{
Shannon Nelson6700acc2020-09-17 18:13:24 -07003117 struct devlink_flash_notify params = {
3118 .status_msg = status_msg,
3119 .component = component,
3120 .done = done,
3121 .total = total,
3122 };
3123
Jiri Pirko191ed202019-06-04 15:40:40 +02003124 __devlink_flash_update_notify(devlink,
3125 DEVLINK_CMD_FLASH_UPDATE_STATUS,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003126 &params);
Jiri Pirko191ed202019-06-04 15:40:40 +02003127}
3128EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
3129
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003130void devlink_flash_update_timeout_notify(struct devlink *devlink,
3131 const char *status_msg,
3132 const char *component,
3133 unsigned long timeout)
3134{
Shannon Nelson6700acc2020-09-17 18:13:24 -07003135 struct devlink_flash_notify params = {
3136 .status_msg = status_msg,
3137 .component = component,
3138 .timeout = timeout,
3139 };
3140
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003141 __devlink_flash_update_notify(devlink,
3142 DEVLINK_CMD_FLASH_UPDATE_STATUS,
Shannon Nelson6700acc2020-09-17 18:13:24 -07003143 &params);
Shannon Nelsonf92970c2020-09-17 18:13:23 -07003144}
3145EXPORT_SYMBOL_GPL(devlink_flash_update_timeout_notify);
3146
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003147static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
3148 struct genl_info *info)
3149{
Jacob Kellerbc75c052020-09-25 13:46:06 -07003150 struct devlink_flash_update_params params = {};
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003151 struct devlink *devlink = info->user_ptr[0];
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003152 struct nlattr *nla_component;
Jacob Keller22ec3d22020-09-25 13:46:05 -07003153 u32 supported_params;
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003154
3155 if (!devlink->ops->flash_update)
3156 return -EOPNOTSUPP;
3157
3158 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
3159 return -EINVAL;
Jacob Keller22ec3d22020-09-25 13:46:05 -07003160
3161 supported_params = devlink->ops->supported_flash_update_params;
3162
Jacob Kellerbc75c052020-09-25 13:46:06 -07003163 params.file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003164
3165 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
Jacob Keller22ec3d22020-09-25 13:46:05 -07003166 if (nla_component) {
3167 if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT)) {
3168 NL_SET_ERR_MSG_ATTR(info->extack, nla_component,
3169 "component update is not supported by this device");
3170 return -EOPNOTSUPP;
3171 }
Jacob Kellerbc75c052020-09-25 13:46:06 -07003172 params.component = nla_data(nla_component);
Jacob Keller22ec3d22020-09-25 13:46:05 -07003173 }
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003174
Jacob Kellerbc75c052020-09-25 13:46:06 -07003175 return devlink->ops->flash_update(devlink, &params, info->extack);
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003176}
3177
Moshe Shemesh036467c2018-07-04 14:30:33 +03003178static const struct devlink_param devlink_param_generic[] = {
3179 {
3180 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
3181 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
3182 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
3183 },
3184 {
3185 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
3186 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
3187 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
3188 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03003189 {
3190 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
3191 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
3192 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
3193 },
Alex Veskerf6a698852018-07-12 15:13:17 +03003194 {
3195 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
3196 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
3197 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
3198 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05303199 {
3200 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
3201 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
3202 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
3203 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05303204 {
3205 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
3206 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
3207 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
3208 },
Vasundhara Volam16511782018-10-04 11:13:46 +05303209 {
3210 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
3211 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
3212 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
3213 },
Shalom Toledo846e9802018-12-03 07:58:59 +00003214 {
3215 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
3216 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
3217 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
3218 },
Dirk van der Merwe5bbd21d2019-09-09 00:54:18 +01003219 {
3220 .id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
3221 .name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
3222 .type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
3223 },
Michael Guralnik6c7295e2019-11-08 23:45:20 +00003224 {
3225 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
3226 .name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
3227 .type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
3228 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03003229};
Moshe Shemesheabaef12018-07-04 14:30:28 +03003230
3231static int devlink_param_generic_verify(const struct devlink_param *param)
3232{
3233 /* verify it match generic parameter by id and name */
3234 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
3235 return -EINVAL;
3236 if (strcmp(param->name, devlink_param_generic[param->id].name))
3237 return -ENOENT;
3238
3239 WARN_ON(param->type != devlink_param_generic[param->id].type);
3240
3241 return 0;
3242}
3243
3244static int devlink_param_driver_verify(const struct devlink_param *param)
3245{
3246 int i;
3247
3248 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
3249 return -EINVAL;
3250 /* verify no such name in generic params */
3251 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
3252 if (!strcmp(param->name, devlink_param_generic[i].name))
3253 return -EEXIST;
3254
3255 return 0;
3256}
3257
3258static struct devlink_param_item *
3259devlink_param_find_by_name(struct list_head *param_list,
3260 const char *param_name)
3261{
3262 struct devlink_param_item *param_item;
3263
3264 list_for_each_entry(param_item, param_list, list)
3265 if (!strcmp(param_item->param->name, param_name))
3266 return param_item;
3267 return NULL;
3268}
3269
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03003270static struct devlink_param_item *
3271devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
3272{
3273 struct devlink_param_item *param_item;
3274
3275 list_for_each_entry(param_item, param_list, list)
3276 if (param_item->param->id == param_id)
3277 return param_item;
3278 return NULL;
3279}
3280
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003281static bool
3282devlink_param_cmode_is_supported(const struct devlink_param *param,
3283 enum devlink_param_cmode cmode)
3284{
3285 return test_bit(cmode, &param->supported_cmodes);
3286}
3287
3288static int devlink_param_get(struct devlink *devlink,
3289 const struct devlink_param *param,
3290 struct devlink_param_gset_ctx *ctx)
3291{
3292 if (!param->get)
3293 return -EOPNOTSUPP;
3294 return param->get(devlink, param->id, ctx);
3295}
3296
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003297static int devlink_param_set(struct devlink *devlink,
3298 const struct devlink_param *param,
3299 struct devlink_param_gset_ctx *ctx)
3300{
3301 if (!param->set)
3302 return -EOPNOTSUPP;
3303 return param->set(devlink, param->id, ctx);
3304}
3305
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003306static int
3307devlink_param_type_to_nla_type(enum devlink_param_type param_type)
3308{
3309 switch (param_type) {
3310 case DEVLINK_PARAM_TYPE_U8:
3311 return NLA_U8;
3312 case DEVLINK_PARAM_TYPE_U16:
3313 return NLA_U16;
3314 case DEVLINK_PARAM_TYPE_U32:
3315 return NLA_U32;
3316 case DEVLINK_PARAM_TYPE_STRING:
3317 return NLA_STRING;
3318 case DEVLINK_PARAM_TYPE_BOOL:
3319 return NLA_FLAG;
3320 default:
3321 return -EINVAL;
3322 }
3323}
3324
3325static int
3326devlink_nl_param_value_fill_one(struct sk_buff *msg,
3327 enum devlink_param_type type,
3328 enum devlink_param_cmode cmode,
3329 union devlink_param_value val)
3330{
3331 struct nlattr *param_value_attr;
3332
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003333 param_value_attr = nla_nest_start_noflag(msg,
3334 DEVLINK_ATTR_PARAM_VALUE);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003335 if (!param_value_attr)
3336 goto nla_put_failure;
3337
3338 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
3339 goto value_nest_cancel;
3340
3341 switch (type) {
3342 case DEVLINK_PARAM_TYPE_U8:
3343 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
3344 goto value_nest_cancel;
3345 break;
3346 case DEVLINK_PARAM_TYPE_U16:
3347 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
3348 goto value_nest_cancel;
3349 break;
3350 case DEVLINK_PARAM_TYPE_U32:
3351 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
3352 goto value_nest_cancel;
3353 break;
3354 case DEVLINK_PARAM_TYPE_STRING:
3355 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
3356 val.vstr))
3357 goto value_nest_cancel;
3358 break;
3359 case DEVLINK_PARAM_TYPE_BOOL:
3360 if (val.vbool &&
3361 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
3362 goto value_nest_cancel;
3363 break;
3364 }
3365
3366 nla_nest_end(msg, param_value_attr);
3367 return 0;
3368
3369value_nest_cancel:
3370 nla_nest_cancel(msg, param_value_attr);
3371nla_put_failure:
3372 return -EMSGSIZE;
3373}
3374
3375static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303376 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003377 struct devlink_param_item *param_item,
3378 enum devlink_command cmd,
3379 u32 portid, u32 seq, int flags)
3380{
3381 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003382 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003383 const struct devlink_param *param = param_item->param;
3384 struct devlink_param_gset_ctx ctx;
3385 struct nlattr *param_values_list;
3386 struct nlattr *param_attr;
3387 int nla_type;
3388 void *hdr;
3389 int err;
3390 int i;
3391
3392 /* Get value from driver part to driverinit configuration mode */
3393 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3394 if (!devlink_param_cmode_is_supported(param, i))
3395 continue;
3396 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3397 if (!param_item->driverinit_value_valid)
3398 return -EOPNOTSUPP;
3399 param_value[i] = param_item->driverinit_value;
3400 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003401 if (!param_item->published)
3402 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003403 ctx.cmode = i;
3404 err = devlink_param_get(devlink, param, &ctx);
3405 if (err)
3406 return err;
3407 param_value[i] = ctx.val;
3408 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003409 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003410 }
3411
3412 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3413 if (!hdr)
3414 return -EMSGSIZE;
3415
3416 if (devlink_nl_put_handle(msg, devlink))
3417 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303418
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303419 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3420 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3421 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303422 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3423 goto genlmsg_cancel;
3424
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003425 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003426 if (!param_attr)
3427 goto genlmsg_cancel;
3428 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3429 goto param_nest_cancel;
3430 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3431 goto param_nest_cancel;
3432
3433 nla_type = devlink_param_type_to_nla_type(param->type);
3434 if (nla_type < 0)
3435 goto param_nest_cancel;
3436 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3437 goto param_nest_cancel;
3438
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003439 param_values_list = nla_nest_start_noflag(msg,
3440 DEVLINK_ATTR_PARAM_VALUES_LIST);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003441 if (!param_values_list)
3442 goto param_nest_cancel;
3443
3444 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003445 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003446 continue;
3447 err = devlink_nl_param_value_fill_one(msg, param->type,
3448 i, param_value[i]);
3449 if (err)
3450 goto values_list_nest_cancel;
3451 }
3452
3453 nla_nest_end(msg, param_values_list);
3454 nla_nest_end(msg, param_attr);
3455 genlmsg_end(msg, hdr);
3456 return 0;
3457
3458values_list_nest_cancel:
3459 nla_nest_end(msg, param_values_list);
3460param_nest_cancel:
3461 nla_nest_cancel(msg, param_attr);
3462genlmsg_cancel:
3463 genlmsg_cancel(msg, hdr);
3464 return -EMSGSIZE;
3465}
3466
Moshe Shemeshea601e12018-07-04 14:30:32 +03003467static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303468 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03003469 struct devlink_param_item *param_item,
3470 enum devlink_command cmd)
3471{
3472 struct sk_buff *msg;
3473 int err;
3474
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303475 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3476 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3477 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003478
3479 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3480 if (!msg)
3481 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303482 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3483 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003484 if (err) {
3485 nlmsg_free(msg);
3486 return;
3487 }
3488
3489 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3490 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3491}
3492
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003493static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3494 struct netlink_callback *cb)
3495{
3496 struct devlink_param_item *param_item;
3497 struct devlink *devlink;
3498 int start = cb->args[0];
3499 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003500 int err = 0;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003501
3502 mutex_lock(&devlink_mutex);
3503 list_for_each_entry(devlink, &devlink_list, list) {
3504 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3505 continue;
3506 mutex_lock(&devlink->lock);
3507 list_for_each_entry(param_item, &devlink->param_list, list) {
3508 if (idx < start) {
3509 idx++;
3510 continue;
3511 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303512 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003513 DEVLINK_CMD_PARAM_GET,
3514 NETLINK_CB(cb->skb).portid,
3515 cb->nlh->nlmsg_seq,
3516 NLM_F_MULTI);
Jakub Kicinski82274d02020-07-28 16:15:07 -07003517 if (err == -EOPNOTSUPP) {
3518 err = 0;
3519 } else if (err) {
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003520 mutex_unlock(&devlink->lock);
3521 goto out;
3522 }
3523 idx++;
3524 }
3525 mutex_unlock(&devlink->lock);
3526 }
3527out:
3528 mutex_unlock(&devlink_mutex);
3529
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003530 if (err != -EMSGSIZE)
3531 return err;
3532
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003533 cb->args[0] = idx;
3534 return msg->len;
3535}
3536
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003537static int
3538devlink_param_type_get_from_info(struct genl_info *info,
3539 enum devlink_param_type *param_type)
3540{
3541 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3542 return -EINVAL;
3543
3544 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3545 case NLA_U8:
3546 *param_type = DEVLINK_PARAM_TYPE_U8;
3547 break;
3548 case NLA_U16:
3549 *param_type = DEVLINK_PARAM_TYPE_U16;
3550 break;
3551 case NLA_U32:
3552 *param_type = DEVLINK_PARAM_TYPE_U32;
3553 break;
3554 case NLA_STRING:
3555 *param_type = DEVLINK_PARAM_TYPE_STRING;
3556 break;
3557 case NLA_FLAG:
3558 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3559 break;
3560 default:
3561 return -EINVAL;
3562 }
3563
3564 return 0;
3565}
3566
3567static int
3568devlink_param_value_get_from_info(const struct devlink_param *param,
3569 struct genl_info *info,
3570 union devlink_param_value *value)
3571{
Jakub Kicinski87509392020-03-02 21:05:11 -08003572 struct nlattr *param_data;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003573 int len;
3574
Jakub Kicinski87509392020-03-02 21:05:11 -08003575 param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
3576
3577 if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003578 return -EINVAL;
3579
3580 switch (param->type) {
3581 case DEVLINK_PARAM_TYPE_U8:
Jakub Kicinski87509392020-03-02 21:05:11 -08003582 if (nla_len(param_data) != sizeof(u8))
3583 return -EINVAL;
3584 value->vu8 = nla_get_u8(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003585 break;
3586 case DEVLINK_PARAM_TYPE_U16:
Jakub Kicinski87509392020-03-02 21:05:11 -08003587 if (nla_len(param_data) != sizeof(u16))
3588 return -EINVAL;
3589 value->vu16 = nla_get_u16(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003590 break;
3591 case DEVLINK_PARAM_TYPE_U32:
Jakub Kicinski87509392020-03-02 21:05:11 -08003592 if (nla_len(param_data) != sizeof(u32))
3593 return -EINVAL;
3594 value->vu32 = nla_get_u32(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003595 break;
3596 case DEVLINK_PARAM_TYPE_STRING:
Jakub Kicinski87509392020-03-02 21:05:11 -08003597 len = strnlen(nla_data(param_data), nla_len(param_data));
3598 if (len == nla_len(param_data) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003599 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003600 return -EINVAL;
Jakub Kicinski87509392020-03-02 21:05:11 -08003601 strcpy(value->vstr, nla_data(param_data));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003602 break;
3603 case DEVLINK_PARAM_TYPE_BOOL:
Jakub Kicinski87509392020-03-02 21:05:11 -08003604 if (param_data && nla_len(param_data))
3605 return -EINVAL;
3606 value->vbool = nla_get_flag(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003607 break;
3608 }
3609 return 0;
3610}
3611
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003612static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303613devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003614 struct genl_info *info)
3615{
3616 char *param_name;
3617
3618 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3619 return NULL;
3620
3621 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303622 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003623}
3624
3625static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3626 struct genl_info *info)
3627{
3628 struct devlink *devlink = info->user_ptr[0];
3629 struct devlink_param_item *param_item;
3630 struct sk_buff *msg;
3631 int err;
3632
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303633 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003634 if (!param_item)
3635 return -EINVAL;
3636
3637 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3638 if (!msg)
3639 return -ENOMEM;
3640
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303641 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003642 DEVLINK_CMD_PARAM_GET,
3643 info->snd_portid, info->snd_seq, 0);
3644 if (err) {
3645 nlmsg_free(msg);
3646 return err;
3647 }
3648
3649 return genlmsg_reply(msg, info);
3650}
3651
Vasundhara Volam9c548732019-01-28 18:00:22 +05303652static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303653 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303654 struct list_head *param_list,
3655 struct genl_info *info,
3656 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003657{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003658 enum devlink_param_type param_type;
3659 struct devlink_param_gset_ctx ctx;
3660 enum devlink_param_cmode cmode;
3661 struct devlink_param_item *param_item;
3662 const struct devlink_param *param;
3663 union devlink_param_value value;
3664 int err = 0;
3665
Vasundhara Volam9c548732019-01-28 18:00:22 +05303666 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003667 if (!param_item)
3668 return -EINVAL;
3669 param = param_item->param;
3670 err = devlink_param_type_get_from_info(info, &param_type);
3671 if (err)
3672 return err;
3673 if (param_type != param->type)
3674 return -EINVAL;
3675 err = devlink_param_value_get_from_info(param, info, &value);
3676 if (err)
3677 return err;
3678 if (param->validate) {
3679 err = param->validate(devlink, param->id, value, info->extack);
3680 if (err)
3681 return err;
3682 }
3683
3684 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3685 return -EINVAL;
3686 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3687 if (!devlink_param_cmode_is_supported(param, cmode))
3688 return -EOPNOTSUPP;
3689
3690 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003691 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3692 strcpy(param_item->driverinit_value.vstr, value.vstr);
3693 else
3694 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003695 param_item->driverinit_value_valid = true;
3696 } else {
3697 if (!param->set)
3698 return -EOPNOTSUPP;
3699 ctx.val = value;
3700 ctx.cmode = cmode;
3701 err = devlink_param_set(devlink, param, &ctx);
3702 if (err)
3703 return err;
3704 }
3705
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303706 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003707 return 0;
3708}
3709
Vasundhara Volam9c548732019-01-28 18:00:22 +05303710static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3711 struct genl_info *info)
3712{
3713 struct devlink *devlink = info->user_ptr[0];
3714
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303715 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303716 info, DEVLINK_CMD_PARAM_NEW);
3717}
3718
Moshe Shemesheabaef12018-07-04 14:30:28 +03003719static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303720 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303721 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303722 const struct devlink_param *param,
3723 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003724{
3725 struct devlink_param_item *param_item;
3726
Vasundhara Volam39e61602019-01-28 18:00:20 +05303727 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03003728 return -EEXIST;
3729
3730 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3731 WARN_ON(param->get || param->set);
3732 else
3733 WARN_ON(!param->get || !param->set);
3734
3735 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3736 if (!param_item)
3737 return -ENOMEM;
3738 param_item->param = param;
3739
Vasundhara Volam39e61602019-01-28 18:00:20 +05303740 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303741 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003742 return 0;
3743}
3744
3745static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303746 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303747 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303748 const struct devlink_param *param,
3749 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003750{
3751 struct devlink_param_item *param_item;
3752
Vasundhara Volam39e61602019-01-28 18:00:20 +05303753 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003754 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303755 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003756 list_del(&param_item->list);
3757 kfree(param_item);
3758}
3759
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303760static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3761 struct netlink_callback *cb)
3762{
3763 struct devlink_param_item *param_item;
3764 struct devlink_port *devlink_port;
3765 struct devlink *devlink;
3766 int start = cb->args[0];
3767 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003768 int err = 0;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303769
3770 mutex_lock(&devlink_mutex);
3771 list_for_each_entry(devlink, &devlink_list, list) {
3772 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3773 continue;
3774 mutex_lock(&devlink->lock);
3775 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3776 list_for_each_entry(param_item,
3777 &devlink_port->param_list, list) {
3778 if (idx < start) {
3779 idx++;
3780 continue;
3781 }
3782 err = devlink_nl_param_fill(msg,
3783 devlink_port->devlink,
3784 devlink_port->index, param_item,
3785 DEVLINK_CMD_PORT_PARAM_GET,
3786 NETLINK_CB(cb->skb).portid,
3787 cb->nlh->nlmsg_seq,
3788 NLM_F_MULTI);
Jakub Kicinski82274d02020-07-28 16:15:07 -07003789 if (err == -EOPNOTSUPP) {
3790 err = 0;
3791 } else if (err) {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303792 mutex_unlock(&devlink->lock);
3793 goto out;
3794 }
3795 idx++;
3796 }
3797 }
3798 mutex_unlock(&devlink->lock);
3799 }
3800out:
3801 mutex_unlock(&devlink_mutex);
3802
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003803 if (err != -EMSGSIZE)
3804 return err;
3805
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303806 cb->args[0] = idx;
3807 return msg->len;
3808}
3809
3810static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3811 struct genl_info *info)
3812{
3813 struct devlink_port *devlink_port = info->user_ptr[0];
3814 struct devlink_param_item *param_item;
3815 struct sk_buff *msg;
3816 int err;
3817
3818 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3819 info);
3820 if (!param_item)
3821 return -EINVAL;
3822
3823 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3824 if (!msg)
3825 return -ENOMEM;
3826
3827 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3828 devlink_port->index, param_item,
3829 DEVLINK_CMD_PORT_PARAM_GET,
3830 info->snd_portid, info->snd_seq, 0);
3831 if (err) {
3832 nlmsg_free(msg);
3833 return err;
3834 }
3835
3836 return genlmsg_reply(msg, info);
3837}
3838
Vasundhara Volam9c548732019-01-28 18:00:22 +05303839static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3840 struct genl_info *info)
3841{
3842 struct devlink_port *devlink_port = info->user_ptr[0];
3843
3844 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303845 devlink_port->index,
3846 &devlink_port->param_list, info,
3847 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05303848}
3849
Alex Veskera006d462018-07-12 15:13:12 +03003850static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3851 struct devlink *devlink,
3852 struct devlink_snapshot *snapshot)
3853{
3854 struct nlattr *snap_attr;
3855 int err;
3856
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003857 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
Alex Veskera006d462018-07-12 15:13:12 +03003858 if (!snap_attr)
3859 return -EINVAL;
3860
3861 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3862 if (err)
3863 goto nla_put_failure;
3864
3865 nla_nest_end(msg, snap_attr);
3866 return 0;
3867
3868nla_put_failure:
3869 nla_nest_cancel(msg, snap_attr);
3870 return err;
3871}
3872
3873static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3874 struct devlink *devlink,
3875 struct devlink_region *region)
3876{
3877 struct devlink_snapshot *snapshot;
3878 struct nlattr *snapshots_attr;
3879 int err;
3880
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003881 snapshots_attr = nla_nest_start_noflag(msg,
3882 DEVLINK_ATTR_REGION_SNAPSHOTS);
Alex Veskera006d462018-07-12 15:13:12 +03003883 if (!snapshots_attr)
3884 return -EINVAL;
3885
3886 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3887 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3888 if (err)
3889 goto nla_put_failure;
3890 }
3891
3892 nla_nest_end(msg, snapshots_attr);
3893 return 0;
3894
3895nla_put_failure:
3896 nla_nest_cancel(msg, snapshots_attr);
3897 return err;
3898}
3899
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003900static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3901 enum devlink_command cmd, u32 portid,
3902 u32 seq, int flags,
3903 struct devlink_region *region)
3904{
3905 void *hdr;
3906 int err;
3907
3908 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3909 if (!hdr)
3910 return -EMSGSIZE;
3911
3912 err = devlink_nl_put_handle(msg, devlink);
3913 if (err)
3914 goto nla_put_failure;
3915
Jacob Kellere8937682020-03-26 11:37:08 -07003916 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003917 if (err)
3918 goto nla_put_failure;
3919
3920 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3921 region->size,
3922 DEVLINK_ATTR_PAD);
3923 if (err)
3924 goto nla_put_failure;
3925
Alex Veskera006d462018-07-12 15:13:12 +03003926 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3927 if (err)
3928 goto nla_put_failure;
3929
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003930 genlmsg_end(msg, hdr);
3931 return 0;
3932
3933nla_put_failure:
3934 genlmsg_cancel(msg, hdr);
3935 return err;
3936}
3937
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003938static struct sk_buff *
3939devlink_nl_region_notify_build(struct devlink_region *region,
3940 struct devlink_snapshot *snapshot,
3941 enum devlink_command cmd, u32 portid, u32 seq)
Alex Vesker866319b2018-07-12 15:13:13 +03003942{
3943 struct devlink *devlink = region->devlink;
3944 struct sk_buff *msg;
3945 void *hdr;
3946 int err;
3947
Alex Vesker866319b2018-07-12 15:13:13 +03003948
3949 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3950 if (!msg)
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003951 return ERR_PTR(-ENOMEM);
Alex Vesker866319b2018-07-12 15:13:13 +03003952
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003953 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
3954 if (!hdr) {
3955 err = -EMSGSIZE;
Alex Vesker866319b2018-07-12 15:13:13 +03003956 goto out_free_msg;
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003957 }
Alex Vesker866319b2018-07-12 15:13:13 +03003958
3959 err = devlink_nl_put_handle(msg, devlink);
3960 if (err)
3961 goto out_cancel_msg;
3962
3963 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
Jacob Kellere8937682020-03-26 11:37:08 -07003964 region->ops->name);
Alex Vesker866319b2018-07-12 15:13:13 +03003965 if (err)
3966 goto out_cancel_msg;
3967
3968 if (snapshot) {
3969 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3970 snapshot->id);
3971 if (err)
3972 goto out_cancel_msg;
3973 } else {
3974 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3975 region->size, DEVLINK_ATTR_PAD);
3976 if (err)
3977 goto out_cancel_msg;
3978 }
3979 genlmsg_end(msg, hdr);
3980
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003981 return msg;
Alex Vesker866319b2018-07-12 15:13:13 +03003982
3983out_cancel_msg:
3984 genlmsg_cancel(msg, hdr);
3985out_free_msg:
3986 nlmsg_free(msg);
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003987 return ERR_PTR(err);
3988}
3989
3990static void devlink_nl_region_notify(struct devlink_region *region,
3991 struct devlink_snapshot *snapshot,
3992 enum devlink_command cmd)
3993{
3994 struct devlink *devlink = region->devlink;
3995 struct sk_buff *msg;
3996
3997 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3998
3999 msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
4000 if (IS_ERR(msg))
4001 return;
4002
4003 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
4004 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
Alex Vesker866319b2018-07-12 15:13:13 +03004005}
4006
Jacob Kellercf80fae2020-03-26 11:37:11 -07004007/**
Jacob Keller12102432020-03-26 11:37:15 -07004008 * __devlink_snapshot_id_increment - Increment number of snapshots using an id
4009 * @devlink: devlink instance
4010 * @id: the snapshot id
4011 *
4012 * Track when a new snapshot begins using an id. Load the count for the
4013 * given id from the snapshot xarray, increment it, and store it back.
4014 *
4015 * Called when a new snapshot is created with the given id.
4016 *
4017 * The id *must* have been previously allocated by
4018 * devlink_region_snapshot_id_get().
4019 *
4020 * Returns 0 on success, or an error on failure.
4021 */
4022static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
4023{
4024 unsigned long count;
4025 void *p;
4026
4027 lockdep_assert_held(&devlink->lock);
4028
4029 p = xa_load(&devlink->snapshot_ids, id);
4030 if (WARN_ON(!p))
4031 return -EINVAL;
4032
4033 if (WARN_ON(!xa_is_value(p)))
4034 return -EINVAL;
4035
4036 count = xa_to_value(p);
4037 count++;
4038
4039 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4040 GFP_KERNEL));
4041}
4042
4043/**
4044 * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
4045 * @devlink: devlink instance
4046 * @id: the snapshot id
4047 *
4048 * Track when a snapshot is deleted and stops using an id. Load the count
4049 * for the given id from the snapshot xarray, decrement it, and store it
4050 * back.
4051 *
4052 * If the count reaches zero, erase this id from the xarray, freeing it
4053 * up for future re-use by devlink_region_snapshot_id_get().
4054 *
4055 * Called when a snapshot using the given id is deleted, and when the
4056 * initial allocator of the id is finished using it.
4057 */
4058static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
4059{
4060 unsigned long count;
4061 void *p;
4062
4063 lockdep_assert_held(&devlink->lock);
4064
4065 p = xa_load(&devlink->snapshot_ids, id);
4066 if (WARN_ON(!p))
4067 return;
4068
4069 if (WARN_ON(!xa_is_value(p)))
4070 return;
4071
4072 count = xa_to_value(p);
4073
4074 if (count > 1) {
4075 count--;
4076 xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4077 GFP_KERNEL);
4078 } else {
4079 /* If this was the last user, we can erase this id */
4080 xa_erase(&devlink->snapshot_ids, id);
4081 }
4082}
4083
4084/**
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004085 * __devlink_snapshot_id_insert - Insert a specific snapshot ID
4086 * @devlink: devlink instance
4087 * @id: the snapshot id
4088 *
4089 * Mark the given snapshot id as used by inserting a zero value into the
4090 * snapshot xarray.
4091 *
4092 * This must be called while holding the devlink instance lock. Unlike
4093 * devlink_snapshot_id_get, the initial reference count is zero, not one.
4094 * It is expected that the id will immediately be used before
4095 * releasing the devlink instance lock.
4096 *
4097 * Returns zero on success, or an error code if the snapshot id could not
4098 * be inserted.
4099 */
4100static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
4101{
4102 lockdep_assert_held(&devlink->lock);
4103
Andrew Lunnbd71ea62020-08-16 21:26:38 +02004104 if (xa_load(&devlink->snapshot_ids, id))
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004105 return -EEXIST;
4106
4107 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
4108 GFP_KERNEL));
4109}
4110
4111/**
Jacob Keller70001082020-03-26 11:37:13 -07004112 * __devlink_region_snapshot_id_get - get snapshot ID
4113 * @devlink: devlink instance
Jacob Keller7ef19d32020-03-26 11:37:14 -07004114 * @id: storage to return snapshot id
Jacob Keller70001082020-03-26 11:37:13 -07004115 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07004116 * Allocates a new snapshot id. Returns zero on success, or a negative
4117 * error on failure. Must be called while holding the devlink instance
4118 * lock.
Jacob Keller12102432020-03-26 11:37:15 -07004119 *
4120 * Snapshot IDs are tracked using an xarray which stores the number of
4121 * users of the snapshot id.
4122 *
4123 * Note that the caller of this function counts as a 'user', in order to
4124 * avoid race conditions. The caller must release its hold on the
4125 * snapshot by using devlink_region_snapshot_id_put.
Jacob Keller70001082020-03-26 11:37:13 -07004126 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07004127static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Jacob Keller70001082020-03-26 11:37:13 -07004128{
4129 lockdep_assert_held(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07004130
Jacob Keller12102432020-03-26 11:37:15 -07004131 return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
4132 xa_limit_32b, GFP_KERNEL);
Jacob Keller70001082020-03-26 11:37:13 -07004133}
4134
4135/**
Jacob Kellercf80fae2020-03-26 11:37:11 -07004136 * __devlink_region_snapshot_create - create a new snapshot
4137 * This will add a new snapshot of a region. The snapshot
4138 * will be stored on the region struct and can be accessed
4139 * from devlink. This is useful for future analyses of snapshots.
4140 * Multiple snapshots can be created on a region.
4141 * The @snapshot_id should be obtained using the getter function.
4142 *
4143 * Must be called only while holding the devlink instance lock.
4144 *
4145 * @region: devlink region of the snapshot
4146 * @data: snapshot data
4147 * @snapshot_id: snapshot id to be created
4148 */
4149static int
4150__devlink_region_snapshot_create(struct devlink_region *region,
4151 u8 *data, u32 snapshot_id)
4152{
4153 struct devlink *devlink = region->devlink;
4154 struct devlink_snapshot *snapshot;
Jacob Keller12102432020-03-26 11:37:15 -07004155 int err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004156
4157 lockdep_assert_held(&devlink->lock);
4158
4159 /* check if region can hold one more snapshot */
4160 if (region->cur_snapshots == region->max_snapshots)
Jacob Keller47a39f62020-03-26 11:37:12 -07004161 return -ENOSPC;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004162
4163 if (devlink_region_snapshot_get_by_id(region, snapshot_id))
4164 return -EEXIST;
4165
4166 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
4167 if (!snapshot)
4168 return -ENOMEM;
4169
Jacob Keller12102432020-03-26 11:37:15 -07004170 err = __devlink_snapshot_id_increment(devlink, snapshot_id);
4171 if (err)
4172 goto err_snapshot_id_increment;
4173
Jacob Kellercf80fae2020-03-26 11:37:11 -07004174 snapshot->id = snapshot_id;
4175 snapshot->region = region;
4176 snapshot->data = data;
4177
4178 list_add_tail(&snapshot->list, &region->snapshot_list);
4179
4180 region->cur_snapshots++;
4181
4182 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
4183 return 0;
Jacob Keller12102432020-03-26 11:37:15 -07004184
4185err_snapshot_id_increment:
4186 kfree(snapshot);
4187 return err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004188}
4189
Jiri Pirko92b49822019-08-12 14:28:31 +02004190static void devlink_region_snapshot_del(struct devlink_region *region,
4191 struct devlink_snapshot *snapshot)
4192{
Jacob Keller12102432020-03-26 11:37:15 -07004193 struct devlink *devlink = region->devlink;
4194
4195 lockdep_assert_held(&devlink->lock);
4196
Jiri Pirko92b49822019-08-12 14:28:31 +02004197 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
4198 region->cur_snapshots--;
4199 list_del(&snapshot->list);
Jacob Kellera0a09f62020-03-26 11:37:09 -07004200 region->ops->destructor(snapshot->data);
Jacob Keller12102432020-03-26 11:37:15 -07004201 __devlink_snapshot_id_decrement(devlink, snapshot->id);
Jiri Pirko92b49822019-08-12 14:28:31 +02004202 kfree(snapshot);
4203}
4204
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004205static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
4206 struct genl_info *info)
4207{
4208 struct devlink *devlink = info->user_ptr[0];
4209 struct devlink_region *region;
4210 const char *region_name;
4211 struct sk_buff *msg;
4212 int err;
4213
4214 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
4215 return -EINVAL;
4216
4217 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4218 region = devlink_region_get_by_name(devlink, region_name);
4219 if (!region)
4220 return -EINVAL;
4221
4222 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4223 if (!msg)
4224 return -ENOMEM;
4225
4226 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
4227 info->snd_portid, info->snd_seq, 0,
4228 region);
4229 if (err) {
4230 nlmsg_free(msg);
4231 return err;
4232 }
4233
4234 return genlmsg_reply(msg, info);
4235}
4236
4237static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
4238 struct netlink_callback *cb)
4239{
4240 struct devlink_region *region;
4241 struct devlink *devlink;
4242 int start = cb->args[0];
4243 int idx = 0;
4244 int err;
4245
4246 mutex_lock(&devlink_mutex);
4247 list_for_each_entry(devlink, &devlink_list, list) {
4248 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4249 continue;
4250
4251 mutex_lock(&devlink->lock);
4252 list_for_each_entry(region, &devlink->region_list, list) {
4253 if (idx < start) {
4254 idx++;
4255 continue;
4256 }
4257 err = devlink_nl_region_fill(msg, devlink,
4258 DEVLINK_CMD_REGION_GET,
4259 NETLINK_CB(cb->skb).portid,
4260 cb->nlh->nlmsg_seq,
4261 NLM_F_MULTI, region);
4262 if (err) {
4263 mutex_unlock(&devlink->lock);
4264 goto out;
4265 }
4266 idx++;
4267 }
4268 mutex_unlock(&devlink->lock);
4269 }
4270out:
4271 mutex_unlock(&devlink_mutex);
4272 cb->args[0] = idx;
4273 return msg->len;
4274}
4275
Alex Vesker866319b2018-07-12 15:13:13 +03004276static int devlink_nl_cmd_region_del(struct sk_buff *skb,
4277 struct genl_info *info)
4278{
4279 struct devlink *devlink = info->user_ptr[0];
4280 struct devlink_snapshot *snapshot;
4281 struct devlink_region *region;
4282 const char *region_name;
4283 u32 snapshot_id;
4284
4285 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
4286 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
4287 return -EINVAL;
4288
4289 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4290 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4291
4292 region = devlink_region_get_by_name(devlink, region_name);
4293 if (!region)
4294 return -EINVAL;
4295
4296 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4297 if (!snapshot)
4298 return -EINVAL;
4299
Jiri Pirko92b49822019-08-12 14:28:31 +02004300 devlink_region_snapshot_del(region, snapshot);
Alex Vesker866319b2018-07-12 15:13:13 +03004301 return 0;
4302}
4303
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004304static int
4305devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
4306{
4307 struct devlink *devlink = info->user_ptr[0];
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004308 struct devlink_snapshot *snapshot;
4309 struct nlattr *snapshot_id_attr;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004310 struct devlink_region *region;
4311 const char *region_name;
4312 u32 snapshot_id;
4313 u8 *data;
4314 int err;
4315
4316 if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) {
4317 NL_SET_ERR_MSG_MOD(info->extack, "No region name provided");
4318 return -EINVAL;
4319 }
4320
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004321 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4322 region = devlink_region_get_by_name(devlink, region_name);
4323 if (!region) {
4324 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist");
4325 return -EINVAL;
4326 }
4327
4328 if (!region->ops->snapshot) {
4329 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not support taking an immediate snapshot");
4330 return -EOPNOTSUPP;
4331 }
4332
4333 if (region->cur_snapshots == region->max_snapshots) {
4334 NL_SET_ERR_MSG_MOD(info->extack, "The region has reached the maximum number of stored snapshots");
4335 return -ENOSPC;
4336 }
4337
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004338 snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
4339 if (snapshot_id_attr) {
4340 snapshot_id = nla_get_u32(snapshot_id_attr);
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004341
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004342 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
4343 NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
4344 return -EEXIST;
4345 }
4346
4347 err = __devlink_snapshot_id_insert(devlink, snapshot_id);
4348 if (err)
4349 return err;
4350 } else {
4351 err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
4352 if (err) {
4353 NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
4354 return err;
4355 }
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004356 }
4357
Andrew Lunnd4602a92020-09-18 21:11:02 +02004358 err = region->ops->snapshot(devlink, region->ops, info->extack, &data);
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004359 if (err)
4360 goto err_snapshot_capture;
4361
4362 err = __devlink_region_snapshot_create(region, data, snapshot_id);
4363 if (err)
4364 goto err_snapshot_create;
4365
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004366 if (!snapshot_id_attr) {
4367 struct sk_buff *msg;
4368
4369 snapshot = devlink_region_snapshot_get_by_id(region,
4370 snapshot_id);
4371 if (WARN_ON(!snapshot))
4372 return -EINVAL;
4373
4374 msg = devlink_nl_region_notify_build(region, snapshot,
4375 DEVLINK_CMD_REGION_NEW,
4376 info->snd_portid,
4377 info->snd_seq);
4378 err = PTR_ERR_OR_ZERO(msg);
4379 if (err)
4380 goto err_notify;
4381
4382 err = genlmsg_reply(msg, info);
4383 if (err)
4384 goto err_notify;
4385 }
4386
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004387 return 0;
4388
4389err_snapshot_create:
4390 region->ops->destructor(data);
4391err_snapshot_capture:
4392 __devlink_snapshot_id_decrement(devlink, snapshot_id);
4393 return err;
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004394
4395err_notify:
4396 devlink_region_snapshot_del(region, snapshot);
4397 return err;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004398}
4399
Alex Vesker4e547952018-07-12 15:13:14 +03004400static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
4401 struct devlink *devlink,
4402 u8 *chunk, u32 chunk_size,
4403 u64 addr)
4404{
4405 struct nlattr *chunk_attr;
4406 int err;
4407
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004408 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
Alex Vesker4e547952018-07-12 15:13:14 +03004409 if (!chunk_attr)
4410 return -EINVAL;
4411
4412 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
4413 if (err)
4414 goto nla_put_failure;
4415
4416 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
4417 DEVLINK_ATTR_PAD);
4418 if (err)
4419 goto nla_put_failure;
4420
4421 nla_nest_end(msg, chunk_attr);
4422 return 0;
4423
4424nla_put_failure:
4425 nla_nest_cancel(msg, chunk_attr);
4426 return err;
4427}
4428
4429#define DEVLINK_REGION_READ_CHUNK_SIZE 256
4430
4431static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
4432 struct devlink *devlink,
4433 struct devlink_region *region,
4434 struct nlattr **attrs,
4435 u64 start_offset,
4436 u64 end_offset,
Alex Vesker4e547952018-07-12 15:13:14 +03004437 u64 *new_offset)
4438{
4439 struct devlink_snapshot *snapshot;
4440 u64 curr_offset = start_offset;
4441 u32 snapshot_id;
4442 int err = 0;
4443
4444 *new_offset = start_offset;
4445
4446 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4447 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4448 if (!snapshot)
4449 return -EINVAL;
4450
Alex Vesker4e547952018-07-12 15:13:14 +03004451 while (curr_offset < end_offset) {
4452 u32 data_size;
4453 u8 *data;
4454
4455 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
4456 data_size = end_offset - curr_offset;
4457 else
4458 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
4459
4460 data = &snapshot->data[curr_offset];
4461 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
4462 data, data_size,
4463 curr_offset);
4464 if (err)
4465 break;
4466
4467 curr_offset += data_size;
4468 }
4469 *new_offset = curr_offset;
4470
4471 return err;
4472}
4473
4474static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
4475 struct netlink_callback *cb)
4476{
Jiri Pirkoee85da52019-10-05 20:04:42 +02004477 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004478 u64 ret_offset, start_offset, end_offset = U64_MAX;
Jiri Pirkoee85da52019-10-05 20:04:42 +02004479 struct nlattr **attrs = info->attrs;
Alex Vesker4e547952018-07-12 15:13:14 +03004480 struct devlink_region *region;
4481 struct nlattr *chunks_attr;
4482 const char *region_name;
4483 struct devlink *devlink;
Alex Vesker4e547952018-07-12 15:13:14 +03004484 void *hdr;
4485 int err;
4486
4487 start_offset = *((u64 *)&cb->args[0]);
4488
Parav Panditdac7c082019-02-12 14:24:08 -06004489 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03004490 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004491 if (IS_ERR(devlink)) {
4492 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06004493 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004494 }
Alex Vesker4e547952018-07-12 15:13:14 +03004495
Alex Vesker4e547952018-07-12 15:13:14 +03004496 mutex_lock(&devlink->lock);
4497
4498 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06004499 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
4500 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004501 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004502 }
Alex Vesker4e547952018-07-12 15:13:14 +03004503
4504 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
4505 region = devlink_region_get_by_name(devlink, region_name);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004506 if (!region) {
4507 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004508 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004509 }
Alex Vesker4e547952018-07-12 15:13:14 +03004510
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004511 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
4512 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
4513 if (!start_offset)
4514 start_offset =
4515 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4516
4517 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4518 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
4519 }
4520
4521 if (end_offset > region->size)
4522 end_offset = region->size;
4523
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004524 /* return 0 if there is no further data to read */
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004525 if (start_offset == end_offset) {
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004526 err = 0;
4527 goto out_unlock;
4528 }
4529
Alex Vesker4e547952018-07-12 15:13:14 +03004530 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4531 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
4532 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004533 if (!hdr) {
4534 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004535 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004536 }
Alex Vesker4e547952018-07-12 15:13:14 +03004537
4538 err = devlink_nl_put_handle(skb, devlink);
4539 if (err)
4540 goto nla_put_failure;
4541
4542 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
4543 if (err)
4544 goto nla_put_failure;
4545
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004546 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004547 if (!chunks_attr) {
4548 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004549 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004550 }
Alex Vesker4e547952018-07-12 15:13:14 +03004551
Alex Vesker4e547952018-07-12 15:13:14 +03004552 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
4553 region, attrs,
4554 start_offset,
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004555 end_offset, &ret_offset);
Alex Vesker4e547952018-07-12 15:13:14 +03004556
4557 if (err && err != -EMSGSIZE)
4558 goto nla_put_failure;
4559
4560 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06004561 if (ret_offset == start_offset) {
4562 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004563 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004564 }
Alex Vesker4e547952018-07-12 15:13:14 +03004565
4566 *((u64 *)&cb->args[0]) = ret_offset;
4567
4568 nla_nest_end(skb, chunks_attr);
4569 genlmsg_end(skb, hdr);
4570 mutex_unlock(&devlink->lock);
4571 mutex_unlock(&devlink_mutex);
4572
4573 return skb->len;
4574
4575nla_put_failure:
4576 genlmsg_cancel(skb, hdr);
4577out_unlock:
4578 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06004579out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03004580 mutex_unlock(&devlink_mutex);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004581 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03004582}
4583
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004584struct devlink_info_req {
4585 struct sk_buff *msg;
4586};
4587
4588int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
4589{
4590 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
4591}
4592EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
4593
4594int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
4595{
4596 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
4597}
4598EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
4599
Vasundhara Volamb5872cd2020-06-20 22:01:56 +05304600int devlink_info_board_serial_number_put(struct devlink_info_req *req,
4601 const char *bsn)
4602{
4603 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER,
4604 bsn);
4605}
4606EXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put);
4607
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08004608static int devlink_info_version_put(struct devlink_info_req *req, int attr,
4609 const char *version_name,
4610 const char *version_value)
4611{
4612 struct nlattr *nest;
4613 int err;
4614
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004615 nest = nla_nest_start_noflag(req->msg, attr);
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08004616 if (!nest)
4617 return -EMSGSIZE;
4618
4619 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
4620 version_name);
4621 if (err)
4622 goto nla_put_failure;
4623
4624 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
4625 version_value);
4626 if (err)
4627 goto nla_put_failure;
4628
4629 nla_nest_end(req->msg, nest);
4630
4631 return 0;
4632
4633nla_put_failure:
4634 nla_nest_cancel(req->msg, nest);
4635 return err;
4636}
4637
4638int devlink_info_version_fixed_put(struct devlink_info_req *req,
4639 const char *version_name,
4640 const char *version_value)
4641{
4642 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
4643 version_name, version_value);
4644}
4645EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
4646
4647int devlink_info_version_stored_put(struct devlink_info_req *req,
4648 const char *version_name,
4649 const char *version_value)
4650{
4651 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
4652 version_name, version_value);
4653}
4654EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
4655
4656int devlink_info_version_running_put(struct devlink_info_req *req,
4657 const char *version_name,
4658 const char *version_value)
4659{
4660 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
4661 version_name, version_value);
4662}
4663EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
4664
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004665static int
4666devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
4667 enum devlink_command cmd, u32 portid,
4668 u32 seq, int flags, struct netlink_ext_ack *extack)
4669{
4670 struct devlink_info_req req;
4671 void *hdr;
4672 int err;
4673
4674 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4675 if (!hdr)
4676 return -EMSGSIZE;
4677
4678 err = -EMSGSIZE;
4679 if (devlink_nl_put_handle(msg, devlink))
4680 goto err_cancel_msg;
4681
4682 req.msg = msg;
4683 err = devlink->ops->info_get(devlink, &req, extack);
4684 if (err)
4685 goto err_cancel_msg;
4686
4687 genlmsg_end(msg, hdr);
4688 return 0;
4689
4690err_cancel_msg:
4691 genlmsg_cancel(msg, hdr);
4692 return err;
4693}
4694
4695static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
4696 struct genl_info *info)
4697{
4698 struct devlink *devlink = info->user_ptr[0];
4699 struct sk_buff *msg;
4700 int err;
4701
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08004702 if (!devlink->ops->info_get)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004703 return -EOPNOTSUPP;
4704
4705 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4706 if (!msg)
4707 return -ENOMEM;
4708
4709 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4710 info->snd_portid, info->snd_seq, 0,
4711 info->extack);
4712 if (err) {
4713 nlmsg_free(msg);
4714 return err;
4715 }
4716
4717 return genlmsg_reply(msg, info);
4718}
4719
4720static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
4721 struct netlink_callback *cb)
4722{
4723 struct devlink *devlink;
4724 int start = cb->args[0];
4725 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004726 int err = 0;
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004727
4728 mutex_lock(&devlink_mutex);
4729 list_for_each_entry(devlink, &devlink_list, list) {
4730 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4731 continue;
4732 if (idx < start) {
4733 idx++;
4734 continue;
4735 }
4736
Jiri Pirkoc493b09b2019-03-24 00:21:03 +01004737 if (!devlink->ops->info_get) {
4738 idx++;
4739 continue;
4740 }
4741
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004742 mutex_lock(&devlink->lock);
4743 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4744 NETLINK_CB(cb->skb).portid,
4745 cb->nlh->nlmsg_seq, NLM_F_MULTI,
4746 cb->extack);
4747 mutex_unlock(&devlink->lock);
Jakub Kicinski82274d02020-07-28 16:15:07 -07004748 if (err == -EOPNOTSUPP)
4749 err = 0;
4750 else if (err)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004751 break;
4752 idx++;
4753 }
4754 mutex_unlock(&devlink_mutex);
4755
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004756 if (err != -EMSGSIZE)
4757 return err;
4758
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004759 cb->args[0] = idx;
4760 return msg->len;
4761}
4762
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004763struct devlink_fmsg_item {
4764 struct list_head list;
4765 int attrtype;
4766 u8 nla_type;
4767 u16 len;
Gustavo A. R. Silvad2afb412020-02-28 07:43:24 -06004768 int value[];
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004769};
4770
4771struct devlink_fmsg {
4772 struct list_head item_list;
Aya Levin573ed902020-02-11 14:32:42 -08004773 bool putting_binary; /* This flag forces enclosing of binary data
4774 * in an array brackets. It forces using
4775 * of designated API:
4776 * devlink_fmsg_binary_pair_nest_start()
4777 * devlink_fmsg_binary_pair_nest_end()
4778 */
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004779};
4780
4781static struct devlink_fmsg *devlink_fmsg_alloc(void)
4782{
4783 struct devlink_fmsg *fmsg;
4784
4785 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
4786 if (!fmsg)
4787 return NULL;
4788
4789 INIT_LIST_HEAD(&fmsg->item_list);
4790
4791 return fmsg;
4792}
4793
4794static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
4795{
4796 struct devlink_fmsg_item *item, *tmp;
4797
4798 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
4799 list_del(&item->list);
4800 kfree(item);
4801 }
4802 kfree(fmsg);
4803}
4804
4805static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
4806 int attrtype)
4807{
4808 struct devlink_fmsg_item *item;
4809
4810 item = kzalloc(sizeof(*item), GFP_KERNEL);
4811 if (!item)
4812 return -ENOMEM;
4813
4814 item->attrtype = attrtype;
4815 list_add_tail(&item->list, &fmsg->item_list);
4816
4817 return 0;
4818}
4819
4820int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
4821{
Aya Levin573ed902020-02-11 14:32:42 -08004822 if (fmsg->putting_binary)
4823 return -EINVAL;
4824
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004825 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
4826}
4827EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
4828
4829static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
4830{
Aya Levin573ed902020-02-11 14:32:42 -08004831 if (fmsg->putting_binary)
4832 return -EINVAL;
4833
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004834 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
4835}
4836
4837int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
4838{
Aya Levin573ed902020-02-11 14:32:42 -08004839 if (fmsg->putting_binary)
4840 return -EINVAL;
4841
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004842 return devlink_fmsg_nest_end(fmsg);
4843}
4844EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
4845
4846#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
4847
4848static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
4849{
4850 struct devlink_fmsg_item *item;
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 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4856 return -EMSGSIZE;
4857
4858 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4859 if (!item)
4860 return -ENOMEM;
4861
4862 item->nla_type = NLA_NUL_STRING;
4863 item->len = strlen(name) + 1;
4864 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4865 memcpy(&item->value, name, item->len);
4866 list_add_tail(&item->list, &fmsg->item_list);
4867
4868 return 0;
4869}
4870
4871int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4872{
4873 int err;
4874
Aya Levin573ed902020-02-11 14:32:42 -08004875 if (fmsg->putting_binary)
4876 return -EINVAL;
4877
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004878 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4879 if (err)
4880 return err;
4881
4882 err = devlink_fmsg_put_name(fmsg, name);
4883 if (err)
4884 return err;
4885
4886 return 0;
4887}
4888EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4889
4890int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4891{
Aya Levin573ed902020-02-11 14:32:42 -08004892 if (fmsg->putting_binary)
4893 return -EINVAL;
4894
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004895 return devlink_fmsg_nest_end(fmsg);
4896}
4897EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4898
4899int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4900 const char *name)
4901{
4902 int err;
4903
Aya Levin573ed902020-02-11 14:32:42 -08004904 if (fmsg->putting_binary)
4905 return -EINVAL;
4906
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004907 err = devlink_fmsg_pair_nest_start(fmsg, name);
4908 if (err)
4909 return err;
4910
4911 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4912 if (err)
4913 return err;
4914
4915 return 0;
4916}
4917EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4918
4919int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4920{
4921 int err;
4922
Aya Levin573ed902020-02-11 14:32:42 -08004923 if (fmsg->putting_binary)
4924 return -EINVAL;
4925
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004926 err = devlink_fmsg_nest_end(fmsg);
4927 if (err)
4928 return err;
4929
4930 err = devlink_fmsg_nest_end(fmsg);
4931 if (err)
4932 return err;
4933
4934 return 0;
4935}
4936EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4937
Aya Levin573ed902020-02-11 14:32:42 -08004938int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
4939 const char *name)
4940{
4941 int err;
4942
4943 err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
4944 if (err)
4945 return err;
4946
4947 fmsg->putting_binary = true;
4948 return err;
4949}
4950EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
4951
4952int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
4953{
4954 if (!fmsg->putting_binary)
4955 return -EINVAL;
4956
4957 fmsg->putting_binary = false;
4958 return devlink_fmsg_arr_pair_nest_end(fmsg);
4959}
4960EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
4961
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004962static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4963 const void *value, u16 value_len,
4964 u8 value_nla_type)
4965{
4966 struct devlink_fmsg_item *item;
4967
4968 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4969 return -EMSGSIZE;
4970
4971 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4972 if (!item)
4973 return -ENOMEM;
4974
4975 item->nla_type = value_nla_type;
4976 item->len = value_len;
4977 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4978 memcpy(&item->value, value, item->len);
4979 list_add_tail(&item->list, &fmsg->item_list);
4980
4981 return 0;
4982}
4983
4984int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4985{
Aya Levin573ed902020-02-11 14:32:42 -08004986 if (fmsg->putting_binary)
4987 return -EINVAL;
4988
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004989 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4990}
4991EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4992
4993int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4994{
Aya Levin573ed902020-02-11 14:32:42 -08004995 if (fmsg->putting_binary)
4996 return -EINVAL;
4997
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004998 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4999}
5000EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
5001
5002int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
5003{
Aya Levin573ed902020-02-11 14:32:42 -08005004 if (fmsg->putting_binary)
5005 return -EINVAL;
5006
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005007 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
5008}
5009EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
5010
5011int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
5012{
Aya Levin573ed902020-02-11 14:32:42 -08005013 if (fmsg->putting_binary)
5014 return -EINVAL;
5015
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005016 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
5017}
5018EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
5019
5020int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
5021{
Aya Levin573ed902020-02-11 14:32:42 -08005022 if (fmsg->putting_binary)
5023 return -EINVAL;
5024
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005025 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
5026 NLA_NUL_STRING);
5027}
5028EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
5029
Aya Levin573ed902020-02-11 14:32:42 -08005030int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
5031 u16 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005032{
Aya Levin573ed902020-02-11 14:32:42 -08005033 if (!fmsg->putting_binary)
5034 return -EINVAL;
5035
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005036 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
5037}
Aya Levin573ed902020-02-11 14:32:42 -08005038EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005039
5040int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
5041 bool value)
5042{
5043 int err;
5044
5045 err = devlink_fmsg_pair_nest_start(fmsg, name);
5046 if (err)
5047 return err;
5048
5049 err = devlink_fmsg_bool_put(fmsg, value);
5050 if (err)
5051 return err;
5052
5053 err = devlink_fmsg_pair_nest_end(fmsg);
5054 if (err)
5055 return err;
5056
5057 return 0;
5058}
5059EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
5060
5061int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
5062 u8 value)
5063{
5064 int err;
5065
5066 err = devlink_fmsg_pair_nest_start(fmsg, name);
5067 if (err)
5068 return err;
5069
5070 err = devlink_fmsg_u8_put(fmsg, value);
5071 if (err)
5072 return err;
5073
5074 err = devlink_fmsg_pair_nest_end(fmsg);
5075 if (err)
5076 return err;
5077
5078 return 0;
5079}
5080EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
5081
5082int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
5083 u32 value)
5084{
5085 int err;
5086
5087 err = devlink_fmsg_pair_nest_start(fmsg, name);
5088 if (err)
5089 return err;
5090
5091 err = devlink_fmsg_u32_put(fmsg, value);
5092 if (err)
5093 return err;
5094
5095 err = devlink_fmsg_pair_nest_end(fmsg);
5096 if (err)
5097 return err;
5098
5099 return 0;
5100}
5101EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
5102
5103int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
5104 u64 value)
5105{
5106 int err;
5107
5108 err = devlink_fmsg_pair_nest_start(fmsg, name);
5109 if (err)
5110 return err;
5111
5112 err = devlink_fmsg_u64_put(fmsg, value);
5113 if (err)
5114 return err;
5115
5116 err = devlink_fmsg_pair_nest_end(fmsg);
5117 if (err)
5118 return err;
5119
5120 return 0;
5121}
5122EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
5123
5124int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
5125 const char *value)
5126{
5127 int err;
5128
5129 err = devlink_fmsg_pair_nest_start(fmsg, name);
5130 if (err)
5131 return err;
5132
5133 err = devlink_fmsg_string_put(fmsg, value);
5134 if (err)
5135 return err;
5136
5137 err = devlink_fmsg_pair_nest_end(fmsg);
5138 if (err)
5139 return err;
5140
5141 return 0;
5142}
5143EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
5144
5145int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
Aya Levine2cde862019-11-12 14:07:49 +02005146 const void *value, u32 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005147{
Aya Levine2cde862019-11-12 14:07:49 +02005148 u32 data_size;
Aya Levin573ed902020-02-11 14:32:42 -08005149 int end_err;
Aya Levine2cde862019-11-12 14:07:49 +02005150 u32 offset;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005151 int err;
5152
Aya Levin573ed902020-02-11 14:32:42 -08005153 err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005154 if (err)
5155 return err;
5156
Aya Levine2cde862019-11-12 14:07:49 +02005157 for (offset = 0; offset < value_len; offset += data_size) {
5158 data_size = value_len - offset;
5159 if (data_size > DEVLINK_FMSG_MAX_SIZE)
5160 data_size = DEVLINK_FMSG_MAX_SIZE;
5161 err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
5162 if (err)
Aya Levin573ed902020-02-11 14:32:42 -08005163 break;
5164 /* Exit from loop with a break (instead of
5165 * return) to make sure putting_binary is turned off in
5166 * devlink_fmsg_binary_pair_nest_end
5167 */
Aya Levine2cde862019-11-12 14:07:49 +02005168 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005169
Aya Levin573ed902020-02-11 14:32:42 -08005170 end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
5171 if (end_err)
5172 err = end_err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005173
Aya Levin573ed902020-02-11 14:32:42 -08005174 return err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005175}
5176EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
5177
5178static int
5179devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5180{
5181 switch (msg->nla_type) {
5182 case NLA_FLAG:
5183 case NLA_U8:
5184 case NLA_U32:
5185 case NLA_U64:
5186 case NLA_NUL_STRING:
5187 case NLA_BINARY:
5188 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
5189 msg->nla_type);
5190 default:
5191 return -EINVAL;
5192 }
5193}
5194
5195static int
5196devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5197{
5198 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5199 u8 tmp;
5200
5201 switch (msg->nla_type) {
5202 case NLA_FLAG:
5203 /* Always provide flag data, regardless of its value */
5204 tmp = *(bool *) msg->value;
5205
5206 return nla_put_u8(skb, attrtype, tmp);
5207 case NLA_U8:
5208 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
5209 case NLA_U32:
5210 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
5211 case NLA_U64:
5212 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
5213 DEVLINK_ATTR_PAD);
5214 case NLA_NUL_STRING:
5215 return nla_put_string(skb, attrtype, (char *) &msg->value);
5216 case NLA_BINARY:
5217 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
5218 default:
5219 return -EINVAL;
5220 }
5221}
5222
5223static int
5224devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5225 int *start)
5226{
5227 struct devlink_fmsg_item *item;
5228 struct nlattr *fmsg_nlattr;
5229 int i = 0;
5230 int err;
5231
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005232 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005233 if (!fmsg_nlattr)
5234 return -EMSGSIZE;
5235
5236 list_for_each_entry(item, &fmsg->item_list, list) {
5237 if (i < *start) {
5238 i++;
5239 continue;
5240 }
5241
5242 switch (item->attrtype) {
5243 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
5244 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
5245 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
5246 case DEVLINK_ATTR_FMSG_NEST_END:
5247 err = nla_put_flag(skb, item->attrtype);
5248 break;
5249 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
5250 err = devlink_fmsg_item_fill_type(item, skb);
5251 if (err)
5252 break;
5253 err = devlink_fmsg_item_fill_data(item, skb);
5254 break;
5255 case DEVLINK_ATTR_FMSG_OBJ_NAME:
5256 err = nla_put_string(skb, item->attrtype,
5257 (char *) &item->value);
5258 break;
5259 default:
5260 err = -EINVAL;
5261 break;
5262 }
5263 if (!err)
5264 *start = ++i;
5265 else
5266 break;
5267 }
5268
5269 nla_nest_end(skb, fmsg_nlattr);
5270 return err;
5271}
5272
5273static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
5274 struct genl_info *info,
5275 enum devlink_command cmd, int flags)
5276{
5277 struct nlmsghdr *nlh;
5278 struct sk_buff *skb;
5279 bool last = false;
5280 int index = 0;
5281 void *hdr;
5282 int err;
5283
5284 while (!last) {
5285 int tmp_index = index;
5286
5287 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5288 if (!skb)
5289 return -ENOMEM;
5290
5291 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
5292 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
5293 if (!hdr) {
5294 err = -EMSGSIZE;
5295 goto nla_put_failure;
5296 }
5297
5298 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5299 if (!err)
5300 last = true;
5301 else if (err != -EMSGSIZE || tmp_index == index)
5302 goto nla_put_failure;
5303
5304 genlmsg_end(skb, hdr);
5305 err = genlmsg_reply(skb, info);
5306 if (err)
5307 return err;
5308 }
5309
5310 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5311 if (!skb)
5312 return -ENOMEM;
5313 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
5314 NLMSG_DONE, 0, flags | NLM_F_MULTI);
5315 if (!nlh) {
5316 err = -EMSGSIZE;
5317 goto nla_put_failure;
5318 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005319
Li RongQingfde55ea2019-02-11 19:09:07 +08005320 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005321
5322nla_put_failure:
5323 nlmsg_free(skb);
5324 return err;
5325}
5326
Aya Levine44ef4e2019-05-16 09:49:20 +03005327static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5328 struct netlink_callback *cb,
5329 enum devlink_command cmd)
5330{
5331 int index = cb->args[0];
5332 int tmp_index = index;
5333 void *hdr;
5334 int err;
5335
5336 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
5337 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
5338 if (!hdr) {
5339 err = -EMSGSIZE;
5340 goto nla_put_failure;
5341 }
5342
5343 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5344 if ((err && err != -EMSGSIZE) || tmp_index == index)
5345 goto nla_put_failure;
5346
5347 cb->args[0] = index;
5348 genlmsg_end(skb, hdr);
5349 return skb->len;
5350
5351nla_put_failure:
5352 genlmsg_cancel(skb, hdr);
5353 return err;
5354}
5355
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005356struct devlink_health_reporter {
5357 struct list_head list;
5358 void *priv;
5359 const struct devlink_health_reporter_ops *ops;
5360 struct devlink *devlink;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005361 struct devlink_port *devlink_port;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005362 struct devlink_fmsg *dump_fmsg;
5363 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005364 u64 graceful_period;
5365 bool auto_recover;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005366 bool auto_dump;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005367 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005368 u64 dump_ts;
Aya Levind2795052019-11-10 14:11:56 +02005369 u64 dump_real_ts;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005370 u64 error_count;
5371 u64 recovery_count;
5372 u64 last_recovery_ts;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005373 refcount_t refcount;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005374};
5375
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005376void *
5377devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
5378{
5379 return reporter->priv;
5380}
5381EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
5382
5383static struct devlink_health_reporter *
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005384__devlink_health_reporter_find_by_name(struct list_head *reporter_list,
5385 struct mutex *list_lock,
5386 const char *reporter_name)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005387{
5388 struct devlink_health_reporter *reporter;
5389
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005390 lockdep_assert_held(list_lock);
5391 list_for_each_entry(reporter, reporter_list, list)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005392 if (!strcmp(reporter->ops->name, reporter_name))
5393 return reporter;
5394 return NULL;
5395}
5396
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005397static struct devlink_health_reporter *
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005398devlink_health_reporter_find_by_name(struct devlink *devlink,
5399 const char *reporter_name)
5400{
5401 return __devlink_health_reporter_find_by_name(&devlink->reporter_list,
5402 &devlink->reporters_lock,
5403 reporter_name);
5404}
5405
5406static struct devlink_health_reporter *
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005407devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
5408 const char *reporter_name)
5409{
5410 return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
5411 &devlink_port->reporters_lock,
5412 reporter_name);
5413}
5414
5415static struct devlink_health_reporter *
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005416__devlink_health_reporter_create(struct devlink *devlink,
5417 const struct devlink_health_reporter_ops *ops,
5418 u64 graceful_period, void *priv)
5419{
5420 struct devlink_health_reporter *reporter;
5421
5422 if (WARN_ON(graceful_period && !ops->recover))
5423 return ERR_PTR(-EINVAL);
5424
5425 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
5426 if (!reporter)
5427 return ERR_PTR(-ENOMEM);
5428
5429 reporter->priv = priv;
5430 reporter->ops = ops;
5431 reporter->devlink = devlink;
5432 reporter->graceful_period = graceful_period;
5433 reporter->auto_recover = !!ops->recover;
5434 reporter->auto_dump = !!ops->dump;
5435 mutex_init(&reporter->dump_lock);
5436 refcount_set(&reporter->refcount, 1);
5437 return reporter;
5438}
5439
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005440/**
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005441 * devlink_port_health_reporter_create - create devlink health reporter for
5442 * specified port instance
5443 *
5444 * @port: devlink_port which should contain the new reporter
5445 * @ops: ops
5446 * @graceful_period: to avoid recovery loops, in msecs
5447 * @priv: priv
5448 */
5449struct devlink_health_reporter *
5450devlink_port_health_reporter_create(struct devlink_port *port,
5451 const struct devlink_health_reporter_ops *ops,
5452 u64 graceful_period, void *priv)
5453{
5454 struct devlink_health_reporter *reporter;
5455
5456 mutex_lock(&port->reporters_lock);
5457 if (__devlink_health_reporter_find_by_name(&port->reporter_list,
5458 &port->reporters_lock, ops->name)) {
5459 reporter = ERR_PTR(-EEXIST);
5460 goto unlock;
5461 }
5462
5463 reporter = __devlink_health_reporter_create(port->devlink, ops,
5464 graceful_period, priv);
5465 if (IS_ERR(reporter))
5466 goto unlock;
5467
5468 reporter->devlink_port = port;
5469 list_add_tail(&reporter->list, &port->reporter_list);
5470unlock:
5471 mutex_unlock(&port->reporters_lock);
5472 return reporter;
5473}
5474EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
5475
5476/**
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005477 * devlink_health_reporter_create - create devlink health reporter
5478 *
5479 * @devlink: devlink
5480 * @ops: ops
5481 * @graceful_period: to avoid recovery loops, in msecs
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005482 * @priv: priv
5483 */
5484struct devlink_health_reporter *
5485devlink_health_reporter_create(struct devlink *devlink,
5486 const struct devlink_health_reporter_ops *ops,
Eran Ben Elishaba7d16c2020-03-29 14:05:54 +03005487 u64 graceful_period, void *priv)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005488{
5489 struct devlink_health_reporter *reporter;
5490
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005491 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005492 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
5493 reporter = ERR_PTR(-EEXIST);
5494 goto unlock;
5495 }
5496
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005497 reporter = __devlink_health_reporter_create(devlink, ops,
5498 graceful_period, priv);
5499 if (IS_ERR(reporter))
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005500 goto unlock;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005501
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005502 list_add_tail(&reporter->list, &devlink->reporter_list);
5503unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005504 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005505 return reporter;
5506}
5507EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
5508
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005509static void
5510devlink_health_reporter_free(struct devlink_health_reporter *reporter)
5511{
5512 mutex_destroy(&reporter->dump_lock);
5513 if (reporter->dump_fmsg)
5514 devlink_fmsg_free(reporter->dump_fmsg);
5515 kfree(reporter);
5516}
5517
5518static void
5519devlink_health_reporter_put(struct devlink_health_reporter *reporter)
5520{
5521 if (refcount_dec_and_test(&reporter->refcount))
5522 devlink_health_reporter_free(reporter);
5523}
5524
5525static void
5526__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5527{
5528 list_del(&reporter->list);
5529 devlink_health_reporter_put(reporter);
5530}
5531
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005532/**
5533 * devlink_health_reporter_destroy - destroy devlink health reporter
5534 *
5535 * @reporter: devlink health reporter to destroy
5536 */
5537void
5538devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5539{
Ido Schimmel5d037b42020-07-13 18:20:14 +03005540 struct mutex *lock = &reporter->devlink->reporters_lock;
5541
5542 mutex_lock(lock);
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005543 __devlink_health_reporter_destroy(reporter);
Ido Schimmel5d037b42020-07-13 18:20:14 +03005544 mutex_unlock(lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005545}
5546EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
5547
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005548/**
5549 * devlink_port_health_reporter_destroy - destroy devlink port health reporter
5550 *
5551 * @reporter: devlink health reporter to destroy
5552 */
5553void
5554devlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter)
5555{
Ido Schimmel5d037b42020-07-13 18:20:14 +03005556 struct mutex *lock = &reporter->devlink_port->reporters_lock;
5557
5558 mutex_lock(lock);
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005559 __devlink_health_reporter_destroy(reporter);
Ido Schimmel5d037b42020-07-13 18:20:14 +03005560 mutex_unlock(lock);
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005561}
5562EXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy);
5563
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005564static int
5565devlink_nl_health_reporter_fill(struct sk_buff *msg,
5566 struct devlink *devlink,
5567 struct devlink_health_reporter *reporter,
5568 enum devlink_command cmd, u32 portid,
5569 u32 seq, int flags)
5570{
5571 struct nlattr *reporter_attr;
5572 void *hdr;
5573
5574 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5575 if (!hdr)
5576 return -EMSGSIZE;
5577
5578 if (devlink_nl_put_handle(msg, devlink))
5579 goto genlmsg_cancel;
5580
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005581 if (reporter->devlink_port) {
5582 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
5583 goto genlmsg_cancel;
5584 }
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005585 reporter_attr = nla_nest_start_noflag(msg,
5586 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005587 if (!reporter_attr)
5588 goto genlmsg_cancel;
5589 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
5590 reporter->ops->name))
5591 goto reporter_nest_cancel;
5592 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
5593 reporter->health_state))
5594 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005595 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005596 reporter->error_count, DEVLINK_ATTR_PAD))
5597 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005598 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005599 reporter->recovery_count, DEVLINK_ATTR_PAD))
5600 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005601 if (reporter->ops->recover &&
5602 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005603 reporter->graceful_period,
5604 DEVLINK_ATTR_PAD))
5605 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005606 if (reporter->ops->recover &&
5607 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005608 reporter->auto_recover))
5609 goto reporter_nest_cancel;
5610 if (reporter->dump_fmsg &&
5611 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
5612 jiffies_to_msecs(reporter->dump_ts),
5613 DEVLINK_ATTR_PAD))
5614 goto reporter_nest_cancel;
Aya Levind2795052019-11-10 14:11:56 +02005615 if (reporter->dump_fmsg &&
5616 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
5617 reporter->dump_real_ts, DEVLINK_ATTR_PAD))
5618 goto reporter_nest_cancel;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005619 if (reporter->ops->dump &&
5620 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
5621 reporter->auto_dump))
5622 goto reporter_nest_cancel;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005623
5624 nla_nest_end(msg, reporter_attr);
5625 genlmsg_end(msg, hdr);
5626 return 0;
5627
5628reporter_nest_cancel:
5629 nla_nest_end(msg, reporter_attr);
5630genlmsg_cancel:
5631 genlmsg_cancel(msg, hdr);
5632 return -EMSGSIZE;
5633}
5634
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305635static void devlink_recover_notify(struct devlink_health_reporter *reporter,
5636 enum devlink_command cmd)
5637{
5638 struct sk_buff *msg;
5639 int err;
5640
5641 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5642
5643 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5644 if (!msg)
5645 return;
5646
5647 err = devlink_nl_health_reporter_fill(msg, reporter->devlink,
5648 reporter, cmd, 0, 0, 0);
5649 if (err) {
5650 nlmsg_free(msg);
5651 return;
5652 }
5653
5654 genlmsg_multicast_netns(&devlink_nl_family,
5655 devlink_net(reporter->devlink),
5656 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
5657}
5658
5659void
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005660devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
5661{
5662 reporter->recovery_count++;
5663 reporter->last_recovery_ts = jiffies;
5664}
5665EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
5666
5667static int
5668devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
5669 void *priv_ctx, struct netlink_ext_ack *extack)
5670{
5671 int err;
5672
5673 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
5674 return 0;
5675
5676 if (!reporter->ops->recover)
5677 return -EOPNOTSUPP;
5678
5679 err = reporter->ops->recover(reporter, priv_ctx, extack);
5680 if (err)
5681 return err;
5682
5683 devlink_health_reporter_recovery_done(reporter);
5684 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
5685 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5686
5687 return 0;
5688}
5689
5690static void
5691devlink_health_dump_clear(struct devlink_health_reporter *reporter)
5692{
5693 if (!reporter->dump_fmsg)
5694 return;
5695 devlink_fmsg_free(reporter->dump_fmsg);
5696 reporter->dump_fmsg = NULL;
5697}
5698
5699static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
5700 void *priv_ctx,
5701 struct netlink_ext_ack *extack)
5702{
5703 int err;
5704
5705 if (!reporter->ops->dump)
5706 return 0;
5707
5708 if (reporter->dump_fmsg)
5709 return 0;
5710
5711 reporter->dump_fmsg = devlink_fmsg_alloc();
5712 if (!reporter->dump_fmsg) {
5713 err = -ENOMEM;
5714 return err;
5715 }
5716
5717 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
5718 if (err)
5719 goto dump_err;
5720
5721 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
5722 priv_ctx, extack);
5723 if (err)
5724 goto dump_err;
5725
5726 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
5727 if (err)
5728 goto dump_err;
5729
5730 reporter->dump_ts = jiffies;
5731 reporter->dump_real_ts = ktime_get_real_ns();
5732
5733 return 0;
5734
5735dump_err:
5736 devlink_health_dump_clear(reporter);
5737 return err;
5738}
5739
5740int devlink_health_report(struct devlink_health_reporter *reporter,
5741 const char *msg, void *priv_ctx)
5742{
5743 enum devlink_health_reporter_state prev_health_state;
5744 struct devlink *devlink = reporter->devlink;
Aya Levinbea0c5c2020-05-04 11:27:46 +03005745 unsigned long recover_ts_threshold;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005746
5747 /* write a log message of the current error */
5748 WARN_ON(!msg);
5749 trace_devlink_health_report(devlink, reporter->ops->name, msg);
5750 reporter->error_count++;
5751 prev_health_state = reporter->health_state;
5752 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5753 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5754
5755 /* abort if the previous error wasn't recovered */
Aya Levinbea0c5c2020-05-04 11:27:46 +03005756 recover_ts_threshold = reporter->last_recovery_ts +
5757 msecs_to_jiffies(reporter->graceful_period);
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005758 if (reporter->auto_recover &&
5759 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Aya Levinbea0c5c2020-05-04 11:27:46 +03005760 (reporter->last_recovery_ts && reporter->recovery_count &&
5761 time_is_after_jiffies(recover_ts_threshold)))) {
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005762 trace_devlink_health_recover_aborted(devlink,
5763 reporter->ops->name,
5764 reporter->health_state,
5765 jiffies -
5766 reporter->last_recovery_ts);
5767 return -ECANCELED;
5768 }
5769
5770 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5771
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005772 if (reporter->auto_dump) {
5773 mutex_lock(&reporter->dump_lock);
5774 /* store current dump of current error, for later analysis */
5775 devlink_health_do_dump(reporter, priv_ctx, NULL);
5776 mutex_unlock(&reporter->dump_lock);
5777 }
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005778
5779 if (reporter->auto_recover)
5780 return devlink_health_reporter_recover(reporter,
5781 priv_ctx, NULL);
5782
5783 return 0;
5784}
5785EXPORT_SYMBOL_GPL(devlink_health_report);
5786
5787static struct devlink_health_reporter *
5788devlink_health_reporter_get_from_attrs(struct devlink *devlink,
5789 struct nlattr **attrs)
5790{
5791 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005792 struct devlink_port *devlink_port;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005793 char *reporter_name;
5794
5795 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
5796 return NULL;
5797
5798 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005799 devlink_port = devlink_port_get_from_attrs(devlink, attrs);
5800 if (IS_ERR(devlink_port)) {
5801 mutex_lock(&devlink->reporters_lock);
5802 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
5803 if (reporter)
5804 refcount_inc(&reporter->refcount);
5805 mutex_unlock(&devlink->reporters_lock);
5806 } else {
5807 mutex_lock(&devlink_port->reporters_lock);
5808 reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name);
5809 if (reporter)
5810 refcount_inc(&reporter->refcount);
5811 mutex_unlock(&devlink_port->reporters_lock);
5812 }
5813
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005814 return reporter;
5815}
5816
5817static struct devlink_health_reporter *
5818devlink_health_reporter_get_from_info(struct devlink *devlink,
5819 struct genl_info *info)
5820{
5821 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
5822}
5823
5824static struct devlink_health_reporter *
5825devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
5826{
5827 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
5828 struct devlink_health_reporter *reporter;
5829 struct nlattr **attrs = info->attrs;
5830 struct devlink *devlink;
5831
5832 mutex_lock(&devlink_mutex);
5833 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
5834 if (IS_ERR(devlink))
5835 goto unlock;
5836
5837 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
5838 mutex_unlock(&devlink_mutex);
5839 return reporter;
5840unlock:
5841 mutex_unlock(&devlink_mutex);
5842 return NULL;
5843}
5844
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005845void
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305846devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
5847 enum devlink_health_reporter_state state)
5848{
5849 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
5850 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
5851 return;
5852
5853 if (reporter->health_state == state)
5854 return;
5855
5856 reporter->health_state = state;
5857 trace_devlink_health_reporter_state_update(reporter->devlink,
5858 reporter->ops->name, state);
5859 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5860}
5861EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
5862
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005863static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
5864 struct genl_info *info)
5865{
5866 struct devlink *devlink = info->user_ptr[0];
5867 struct devlink_health_reporter *reporter;
5868 struct sk_buff *msg;
5869 int err;
5870
5871 reporter = devlink_health_reporter_get_from_info(devlink, info);
5872 if (!reporter)
5873 return -EINVAL;
5874
5875 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005876 if (!msg) {
5877 err = -ENOMEM;
5878 goto out;
5879 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005880
5881 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
5882 DEVLINK_CMD_HEALTH_REPORTER_GET,
5883 info->snd_portid, info->snd_seq,
5884 0);
5885 if (err) {
5886 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005887 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005888 }
5889
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005890 err = genlmsg_reply(msg, info);
5891out:
5892 devlink_health_reporter_put(reporter);
5893 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005894}
5895
5896static int
5897devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
5898 struct netlink_callback *cb)
5899{
5900 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005901 struct devlink_port *port;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005902 struct devlink *devlink;
5903 int start = cb->args[0];
5904 int idx = 0;
5905 int err;
5906
5907 mutex_lock(&devlink_mutex);
5908 list_for_each_entry(devlink, &devlink_list, list) {
5909 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5910 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005911 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005912 list_for_each_entry(reporter, &devlink->reporter_list,
5913 list) {
5914 if (idx < start) {
5915 idx++;
5916 continue;
5917 }
5918 err = devlink_nl_health_reporter_fill(msg, devlink,
5919 reporter,
5920 DEVLINK_CMD_HEALTH_REPORTER_GET,
5921 NETLINK_CB(cb->skb).portid,
5922 cb->nlh->nlmsg_seq,
5923 NLM_F_MULTI);
5924 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005925 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005926 goto out;
5927 }
5928 idx++;
5929 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005930 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005931 }
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005932
5933 list_for_each_entry(devlink, &devlink_list, list) {
5934 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5935 continue;
Parav Pandit5d080b52020-08-21 22:12:21 +03005936 mutex_lock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005937 list_for_each_entry(port, &devlink->port_list, list) {
5938 mutex_lock(&port->reporters_lock);
5939 list_for_each_entry(reporter, &port->reporter_list, list) {
5940 if (idx < start) {
5941 idx++;
5942 continue;
5943 }
5944 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
5945 DEVLINK_CMD_HEALTH_REPORTER_GET,
5946 NETLINK_CB(cb->skb).portid,
5947 cb->nlh->nlmsg_seq,
5948 NLM_F_MULTI);
5949 if (err) {
5950 mutex_unlock(&port->reporters_lock);
Parav Pandit5d080b52020-08-21 22:12:21 +03005951 mutex_unlock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005952 goto out;
5953 }
5954 idx++;
5955 }
5956 mutex_unlock(&port->reporters_lock);
5957 }
Parav Pandit5d080b52020-08-21 22:12:21 +03005958 mutex_unlock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005959 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005960out:
5961 mutex_unlock(&devlink_mutex);
5962
5963 cb->args[0] = idx;
5964 return msg->len;
5965}
5966
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005967static int
5968devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
5969 struct genl_info *info)
5970{
5971 struct devlink *devlink = info->user_ptr[0];
5972 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005973 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005974
5975 reporter = devlink_health_reporter_get_from_info(devlink, info);
5976 if (!reporter)
5977 return -EINVAL;
5978
5979 if (!reporter->ops->recover &&
5980 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005981 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
5982 err = -EOPNOTSUPP;
5983 goto out;
5984 }
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005985 if (!reporter->ops->dump &&
5986 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
5987 err = -EOPNOTSUPP;
5988 goto out;
5989 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005990
5991 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
5992 reporter->graceful_period =
5993 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
5994
5995 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
5996 reporter->auto_recover =
5997 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
5998
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005999 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
6000 reporter->auto_dump =
6001 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
6002
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006003 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006004 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006005out:
6006 devlink_health_reporter_put(reporter);
6007 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006008}
6009
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006010static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
6011 struct genl_info *info)
6012{
6013 struct devlink *devlink = info->user_ptr[0];
6014 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006015 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006016
6017 reporter = devlink_health_reporter_get_from_info(devlink, info);
6018 if (!reporter)
6019 return -EINVAL;
6020
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006021 err = devlink_health_reporter_recover(reporter, NULL, info->extack);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006022
6023 devlink_health_reporter_put(reporter);
6024 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006025}
6026
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006027static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
6028 struct genl_info *info)
6029{
6030 struct devlink *devlink = info->user_ptr[0];
6031 struct devlink_health_reporter *reporter;
6032 struct devlink_fmsg *fmsg;
6033 int err;
6034
6035 reporter = devlink_health_reporter_get_from_info(devlink, info);
6036 if (!reporter)
6037 return -EINVAL;
6038
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006039 if (!reporter->ops->diagnose) {
6040 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006041 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006042 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006043
6044 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006045 if (!fmsg) {
6046 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006047 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006048 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006049
6050 err = devlink_fmsg_obj_nest_start(fmsg);
6051 if (err)
6052 goto out;
6053
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006054 err = reporter->ops->diagnose(reporter, fmsg, info->extack);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006055 if (err)
6056 goto out;
6057
6058 err = devlink_fmsg_obj_nest_end(fmsg);
6059 if (err)
6060 goto out;
6061
6062 err = devlink_fmsg_snd(fmsg, info,
6063 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
6064
6065out:
6066 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006067 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006068 return err;
6069}
6070
Aya Levine44ef4e2019-05-16 09:49:20 +03006071static int
6072devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
6073 struct netlink_callback *cb)
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006074{
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006075 struct devlink_health_reporter *reporter;
Aya Levine44ef4e2019-05-16 09:49:20 +03006076 u64 start = cb->args[0];
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006077 int err;
6078
Aya Levine44ef4e2019-05-16 09:49:20 +03006079 reporter = devlink_health_reporter_get_from_cb(cb);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006080 if (!reporter)
6081 return -EINVAL;
6082
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006083 if (!reporter->ops->dump) {
Aya Levine44ef4e2019-05-16 09:49:20 +03006084 err = -EOPNOTSUPP;
6085 goto out;
6086 }
6087 mutex_lock(&reporter->dump_lock);
6088 if (!start) {
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006089 err = devlink_health_do_dump(reporter, NULL, cb->extack);
Aya Levine44ef4e2019-05-16 09:49:20 +03006090 if (err)
6091 goto unlock;
6092 cb->args[1] = reporter->dump_ts;
6093 }
6094 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
6095 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
6096 err = -EAGAIN;
6097 goto unlock;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006098 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006099
Aya Levine44ef4e2019-05-16 09:49:20 +03006100 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
6101 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
6102unlock:
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006103 mutex_unlock(&reporter->dump_lock);
Aya Levine44ef4e2019-05-16 09:49:20 +03006104out:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006105 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006106 return err;
6107}
6108
6109static int
6110devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
6111 struct genl_info *info)
6112{
6113 struct devlink *devlink = info->user_ptr[0];
6114 struct devlink_health_reporter *reporter;
6115
6116 reporter = devlink_health_reporter_get_from_info(devlink, info);
6117 if (!reporter)
6118 return -EINVAL;
6119
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006120 if (!reporter->ops->dump) {
6121 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006122 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006123 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006124
6125 mutex_lock(&reporter->dump_lock);
6126 devlink_health_dump_clear(reporter);
6127 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006128 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006129 return 0;
6130}
6131
Jiri Pirkoe2ce94d2020-09-15 11:40:57 +03006132static int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
6133 struct genl_info *info)
6134{
6135 struct devlink *devlink = info->user_ptr[0];
6136 struct devlink_health_reporter *reporter;
6137 int err;
6138
6139 reporter = devlink_health_reporter_get_from_info(devlink, info);
6140 if (!reporter)
6141 return -EINVAL;
6142
6143 if (!reporter->ops->test) {
6144 devlink_health_reporter_put(reporter);
6145 return -EOPNOTSUPP;
6146 }
6147
6148 err = reporter->ops->test(reporter, info->extack);
6149
6150 devlink_health_reporter_put(reporter);
6151 return err;
6152}
6153
Ido Schimmel0f420b62019-08-17 16:28:17 +03006154struct devlink_stats {
6155 u64 rx_bytes;
6156 u64 rx_packets;
6157 struct u64_stats_sync syncp;
6158};
6159
6160/**
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006161 * struct devlink_trap_policer_item - Packet trap policer attributes.
6162 * @policer: Immutable packet trap policer attributes.
6163 * @rate: Rate in packets / sec.
6164 * @burst: Burst size in packets.
6165 * @list: trap_policer_list member.
6166 *
6167 * Describes packet trap policer attributes. Created by devlink during trap
6168 * policer registration.
6169 */
6170struct devlink_trap_policer_item {
6171 const struct devlink_trap_policer *policer;
6172 u64 rate;
6173 u64 burst;
6174 struct list_head list;
6175};
6176
6177/**
Ido Schimmel0f420b62019-08-17 16:28:17 +03006178 * struct devlink_trap_group_item - Packet trap group attributes.
6179 * @group: Immutable packet trap group attributes.
Ido Schimmelf9f54392020-03-30 22:38:21 +03006180 * @policer_item: Associated policer item. Can be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006181 * @list: trap_group_list member.
6182 * @stats: Trap group statistics.
6183 *
6184 * Describes packet trap group attributes. Created by devlink during trap
Ido Schimmela09b37f2020-03-22 20:48:29 +02006185 * group registration.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006186 */
6187struct devlink_trap_group_item {
6188 const struct devlink_trap_group *group;
Ido Schimmelf9f54392020-03-30 22:38:21 +03006189 struct devlink_trap_policer_item *policer_item;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006190 struct list_head list;
6191 struct devlink_stats __percpu *stats;
6192};
6193
6194/**
6195 * struct devlink_trap_item - Packet trap attributes.
6196 * @trap: Immutable packet trap attributes.
6197 * @group_item: Associated group item.
6198 * @list: trap_list member.
6199 * @action: Trap action.
6200 * @stats: Trap statistics.
6201 * @priv: Driver private information.
6202 *
6203 * Describes both mutable and immutable packet trap attributes. Created by
6204 * devlink during trap registration and used for all trap related operations.
6205 */
6206struct devlink_trap_item {
6207 const struct devlink_trap *trap;
6208 struct devlink_trap_group_item *group_item;
6209 struct list_head list;
6210 enum devlink_trap_action action;
6211 struct devlink_stats __percpu *stats;
6212 void *priv;
6213};
6214
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006215static struct devlink_trap_policer_item *
6216devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
6217{
6218 struct devlink_trap_policer_item *policer_item;
6219
6220 list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
6221 if (policer_item->policer->id == id)
6222 return policer_item;
6223 }
6224
6225 return NULL;
6226}
6227
Ido Schimmel0f420b62019-08-17 16:28:17 +03006228static struct devlink_trap_item *
6229devlink_trap_item_lookup(struct devlink *devlink, const char *name)
6230{
6231 struct devlink_trap_item *trap_item;
6232
6233 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6234 if (!strcmp(trap_item->trap->name, name))
6235 return trap_item;
6236 }
6237
6238 return NULL;
6239}
6240
6241static struct devlink_trap_item *
6242devlink_trap_item_get_from_info(struct devlink *devlink,
6243 struct genl_info *info)
6244{
6245 struct nlattr *attr;
6246
6247 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
6248 return NULL;
6249 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
6250
6251 return devlink_trap_item_lookup(devlink, nla_data(attr));
6252}
6253
6254static int
6255devlink_trap_action_get_from_info(struct genl_info *info,
6256 enum devlink_trap_action *p_trap_action)
6257{
6258 u8 val;
6259
6260 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
6261 switch (val) {
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05006262 case DEVLINK_TRAP_ACTION_DROP:
6263 case DEVLINK_TRAP_ACTION_TRAP:
Ido Schimmel9eefeab2020-05-29 21:36:39 +03006264 case DEVLINK_TRAP_ACTION_MIRROR:
Ido Schimmel0f420b62019-08-17 16:28:17 +03006265 *p_trap_action = val;
6266 break;
6267 default:
6268 return -EINVAL;
6269 }
6270
6271 return 0;
6272}
6273
6274static int devlink_trap_metadata_put(struct sk_buff *msg,
6275 const struct devlink_trap *trap)
6276{
6277 struct nlattr *attr;
6278
6279 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
6280 if (!attr)
6281 return -EMSGSIZE;
6282
6283 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
6284 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
6285 goto nla_put_failure;
Jiri Pirko85b05892020-02-25 11:45:19 +01006286 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
6287 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
6288 goto nla_put_failure;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006289
6290 nla_nest_end(msg, attr);
6291
6292 return 0;
6293
6294nla_put_failure:
6295 nla_nest_cancel(msg, attr);
6296 return -EMSGSIZE;
6297}
6298
6299static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
6300 struct devlink_stats *stats)
6301{
6302 int i;
6303
6304 memset(stats, 0, sizeof(*stats));
6305 for_each_possible_cpu(i) {
6306 struct devlink_stats *cpu_stats;
6307 u64 rx_packets, rx_bytes;
6308 unsigned int start;
6309
6310 cpu_stats = per_cpu_ptr(trap_stats, i);
6311 do {
6312 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
6313 rx_packets = cpu_stats->rx_packets;
6314 rx_bytes = cpu_stats->rx_bytes;
6315 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
6316
6317 stats->rx_packets += rx_packets;
6318 stats->rx_bytes += rx_bytes;
6319 }
6320}
6321
6322static int devlink_trap_stats_put(struct sk_buff *msg,
6323 struct devlink_stats __percpu *trap_stats)
6324{
6325 struct devlink_stats stats;
6326 struct nlattr *attr;
6327
6328 devlink_trap_stats_read(trap_stats, &stats);
6329
6330 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6331 if (!attr)
6332 return -EMSGSIZE;
6333
6334 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
6335 stats.rx_packets, DEVLINK_ATTR_PAD))
6336 goto nla_put_failure;
6337
6338 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
6339 stats.rx_bytes, DEVLINK_ATTR_PAD))
6340 goto nla_put_failure;
6341
6342 nla_nest_end(msg, attr);
6343
6344 return 0;
6345
6346nla_put_failure:
6347 nla_nest_cancel(msg, attr);
6348 return -EMSGSIZE;
6349}
6350
6351static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
6352 const struct devlink_trap_item *trap_item,
6353 enum devlink_command cmd, u32 portid, u32 seq,
6354 int flags)
6355{
6356 struct devlink_trap_group_item *group_item = trap_item->group_item;
6357 void *hdr;
6358 int err;
6359
6360 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6361 if (!hdr)
6362 return -EMSGSIZE;
6363
6364 if (devlink_nl_put_handle(msg, devlink))
6365 goto nla_put_failure;
6366
6367 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6368 group_item->group->name))
6369 goto nla_put_failure;
6370
6371 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
6372 goto nla_put_failure;
6373
6374 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
6375 goto nla_put_failure;
6376
6377 if (trap_item->trap->generic &&
6378 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6379 goto nla_put_failure;
6380
6381 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
6382 goto nla_put_failure;
6383
6384 err = devlink_trap_metadata_put(msg, trap_item->trap);
6385 if (err)
6386 goto nla_put_failure;
6387
6388 err = devlink_trap_stats_put(msg, trap_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_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_item *trap_item;
6407 struct sk_buff *msg;
6408 int err;
6409
6410 if (list_empty(&devlink->trap_list))
6411 return -EOPNOTSUPP;
6412
6413 trap_item = devlink_trap_item_get_from_info(devlink, info);
6414 if (!trap_item) {
6415 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
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_fill(msg, devlink, trap_item,
6424 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
6425 info->snd_seq, 0);
6426 if (err)
6427 goto err_trap_fill;
6428
6429 return genlmsg_reply(msg, info);
6430
6431err_trap_fill:
6432 nlmsg_free(msg);
6433 return err;
6434}
6435
6436static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
6437 struct netlink_callback *cb)
6438{
6439 struct devlink_trap_item *trap_item;
6440 struct devlink *devlink;
6441 int start = cb->args[0];
6442 int idx = 0;
6443 int err;
6444
6445 mutex_lock(&devlink_mutex);
6446 list_for_each_entry(devlink, &devlink_list, list) {
6447 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6448 continue;
6449 mutex_lock(&devlink->lock);
6450 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6451 if (idx < start) {
6452 idx++;
6453 continue;
6454 }
6455 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6456 DEVLINK_CMD_TRAP_NEW,
6457 NETLINK_CB(cb->skb).portid,
6458 cb->nlh->nlmsg_seq,
6459 NLM_F_MULTI);
6460 if (err) {
6461 mutex_unlock(&devlink->lock);
6462 goto out;
6463 }
6464 idx++;
6465 }
6466 mutex_unlock(&devlink->lock);
6467 }
6468out:
6469 mutex_unlock(&devlink_mutex);
6470
6471 cb->args[0] = idx;
6472 return msg->len;
6473}
6474
6475static int __devlink_trap_action_set(struct devlink *devlink,
6476 struct devlink_trap_item *trap_item,
6477 enum devlink_trap_action trap_action,
6478 struct netlink_ext_ack *extack)
6479{
6480 int err;
6481
6482 if (trap_item->action != trap_action &&
6483 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
6484 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
6485 return 0;
6486 }
6487
6488 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
Ido Schimmelc88e11e2020-08-03 19:11:34 +03006489 trap_action, extack);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006490 if (err)
6491 return err;
6492
6493 trap_item->action = trap_action;
6494
6495 return 0;
6496}
6497
6498static int devlink_trap_action_set(struct devlink *devlink,
6499 struct devlink_trap_item *trap_item,
6500 struct genl_info *info)
6501{
6502 enum devlink_trap_action trap_action;
6503 int err;
6504
6505 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6506 return 0;
6507
6508 err = devlink_trap_action_get_from_info(info, &trap_action);
6509 if (err) {
6510 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6511 return -EINVAL;
6512 }
6513
6514 return __devlink_trap_action_set(devlink, trap_item, trap_action,
6515 info->extack);
6516}
6517
6518static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
6519 struct genl_info *info)
6520{
6521 struct netlink_ext_ack *extack = info->extack;
6522 struct devlink *devlink = info->user_ptr[0];
6523 struct devlink_trap_item *trap_item;
6524 int err;
6525
6526 if (list_empty(&devlink->trap_list))
6527 return -EOPNOTSUPP;
6528
6529 trap_item = devlink_trap_item_get_from_info(devlink, info);
6530 if (!trap_item) {
6531 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6532 return -ENOENT;
6533 }
6534
6535 err = devlink_trap_action_set(devlink, trap_item, info);
6536 if (err)
6537 return err;
6538
6539 return 0;
6540}
6541
6542static struct devlink_trap_group_item *
6543devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
6544{
6545 struct devlink_trap_group_item *group_item;
6546
6547 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6548 if (!strcmp(group_item->group->name, name))
6549 return group_item;
6550 }
6551
6552 return NULL;
6553}
6554
6555static struct devlink_trap_group_item *
Ido Schimmel107f1672020-03-22 20:48:30 +02006556devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
6557{
6558 struct devlink_trap_group_item *group_item;
6559
6560 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6561 if (group_item->group->id == id)
6562 return group_item;
6563 }
6564
6565 return NULL;
6566}
6567
6568static struct devlink_trap_group_item *
Ido Schimmel0f420b62019-08-17 16:28:17 +03006569devlink_trap_group_item_get_from_info(struct devlink *devlink,
6570 struct genl_info *info)
6571{
6572 char *name;
6573
6574 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
6575 return NULL;
6576 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
6577
6578 return devlink_trap_group_item_lookup(devlink, name);
6579}
6580
6581static int
6582devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
6583 const struct devlink_trap_group_item *group_item,
6584 enum devlink_command cmd, u32 portid, u32 seq,
6585 int flags)
6586{
6587 void *hdr;
6588 int err;
6589
6590 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6591 if (!hdr)
6592 return -EMSGSIZE;
6593
6594 if (devlink_nl_put_handle(msg, devlink))
6595 goto nla_put_failure;
6596
6597 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6598 group_item->group->name))
6599 goto nla_put_failure;
6600
6601 if (group_item->group->generic &&
6602 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6603 goto nla_put_failure;
6604
Ido Schimmelf9f54392020-03-30 22:38:21 +03006605 if (group_item->policer_item &&
6606 nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6607 group_item->policer_item->policer->id))
6608 goto nla_put_failure;
6609
Ido Schimmel0f420b62019-08-17 16:28:17 +03006610 err = devlink_trap_stats_put(msg, group_item->stats);
6611 if (err)
6612 goto nla_put_failure;
6613
6614 genlmsg_end(msg, hdr);
6615
6616 return 0;
6617
6618nla_put_failure:
6619 genlmsg_cancel(msg, hdr);
6620 return -EMSGSIZE;
6621}
6622
6623static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
6624 struct genl_info *info)
6625{
6626 struct netlink_ext_ack *extack = info->extack;
6627 struct devlink *devlink = info->user_ptr[0];
6628 struct devlink_trap_group_item *group_item;
6629 struct sk_buff *msg;
6630 int err;
6631
6632 if (list_empty(&devlink->trap_group_list))
6633 return -EOPNOTSUPP;
6634
6635 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6636 if (!group_item) {
6637 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6638 return -ENOENT;
6639 }
6640
6641 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6642 if (!msg)
6643 return -ENOMEM;
6644
6645 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
6646 DEVLINK_CMD_TRAP_GROUP_NEW,
6647 info->snd_portid, info->snd_seq, 0);
6648 if (err)
6649 goto err_trap_group_fill;
6650
6651 return genlmsg_reply(msg, info);
6652
6653err_trap_group_fill:
6654 nlmsg_free(msg);
6655 return err;
6656}
6657
6658static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
6659 struct netlink_callback *cb)
6660{
6661 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
6662 struct devlink_trap_group_item *group_item;
6663 u32 portid = NETLINK_CB(cb->skb).portid;
6664 struct devlink *devlink;
6665 int start = cb->args[0];
6666 int idx = 0;
6667 int err;
6668
6669 mutex_lock(&devlink_mutex);
6670 list_for_each_entry(devlink, &devlink_list, list) {
6671 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6672 continue;
6673 mutex_lock(&devlink->lock);
6674 list_for_each_entry(group_item, &devlink->trap_group_list,
6675 list) {
6676 if (idx < start) {
6677 idx++;
6678 continue;
6679 }
6680 err = devlink_nl_trap_group_fill(msg, devlink,
6681 group_item, cmd,
6682 portid,
6683 cb->nlh->nlmsg_seq,
6684 NLM_F_MULTI);
6685 if (err) {
6686 mutex_unlock(&devlink->lock);
6687 goto out;
6688 }
6689 idx++;
6690 }
6691 mutex_unlock(&devlink->lock);
6692 }
6693out:
6694 mutex_unlock(&devlink_mutex);
6695
6696 cb->args[0] = idx;
6697 return msg->len;
6698}
6699
6700static int
6701__devlink_trap_group_action_set(struct devlink *devlink,
6702 struct devlink_trap_group_item *group_item,
6703 enum devlink_trap_action trap_action,
6704 struct netlink_ext_ack *extack)
6705{
6706 const char *group_name = group_item->group->name;
6707 struct devlink_trap_item *trap_item;
6708 int err;
6709
6710 list_for_each_entry(trap_item, &devlink->trap_list, list) {
Ido Schimmel107f1672020-03-22 20:48:30 +02006711 if (strcmp(trap_item->group_item->group->name, group_name))
Ido Schimmel0f420b62019-08-17 16:28:17 +03006712 continue;
6713 err = __devlink_trap_action_set(devlink, trap_item,
6714 trap_action, extack);
6715 if (err)
6716 return err;
6717 }
6718
6719 return 0;
6720}
6721
6722static int
6723devlink_trap_group_action_set(struct devlink *devlink,
6724 struct devlink_trap_group_item *group_item,
Ido Schimmelc0648752020-03-30 22:38:22 +03006725 struct genl_info *info, bool *p_modified)
Ido Schimmel0f420b62019-08-17 16:28:17 +03006726{
6727 enum devlink_trap_action trap_action;
6728 int err;
6729
6730 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6731 return 0;
6732
6733 err = devlink_trap_action_get_from_info(info, &trap_action);
6734 if (err) {
6735 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6736 return -EINVAL;
6737 }
6738
6739 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
6740 info->extack);
6741 if (err)
6742 return err;
6743
Ido Schimmelc0648752020-03-30 22:38:22 +03006744 *p_modified = true;
6745
6746 return 0;
6747}
6748
6749static int devlink_trap_group_set(struct devlink *devlink,
6750 struct devlink_trap_group_item *group_item,
6751 struct genl_info *info)
6752{
6753 struct devlink_trap_policer_item *policer_item;
6754 struct netlink_ext_ack *extack = info->extack;
6755 const struct devlink_trap_policer *policer;
6756 struct nlattr **attrs = info->attrs;
6757 int err;
6758
6759 if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6760 return 0;
6761
6762 if (!devlink->ops->trap_group_set)
6763 return -EOPNOTSUPP;
6764
6765 policer_item = group_item->policer_item;
6766 if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) {
6767 u32 policer_id;
6768
6769 policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6770 policer_item = devlink_trap_policer_item_lookup(devlink,
6771 policer_id);
6772 if (policer_id && !policer_item) {
6773 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6774 return -ENOENT;
6775 }
6776 }
6777 policer = policer_item ? policer_item->policer : NULL;
6778
Ido Schimmelc88e11e2020-08-03 19:11:34 +03006779 err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
6780 extack);
Ido Schimmelc0648752020-03-30 22:38:22 +03006781 if (err)
6782 return err;
6783
6784 group_item->policer_item = policer_item;
6785
Ido Schimmel0f420b62019-08-17 16:28:17 +03006786 return 0;
6787}
6788
6789static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
6790 struct genl_info *info)
6791{
6792 struct netlink_ext_ack *extack = info->extack;
6793 struct devlink *devlink = info->user_ptr[0];
6794 struct devlink_trap_group_item *group_item;
Ido Schimmelc0648752020-03-30 22:38:22 +03006795 bool modified = false;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006796 int err;
6797
6798 if (list_empty(&devlink->trap_group_list))
6799 return -EOPNOTSUPP;
6800
6801 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6802 if (!group_item) {
6803 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6804 return -ENOENT;
6805 }
6806
Ido Schimmelc0648752020-03-30 22:38:22 +03006807 err = devlink_trap_group_action_set(devlink, group_item, info,
6808 &modified);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006809 if (err)
6810 return err;
6811
Ido Schimmelc0648752020-03-30 22:38:22 +03006812 err = devlink_trap_group_set(devlink, group_item, info);
6813 if (err)
6814 goto err_trap_group_set;
6815
Ido Schimmel0f420b62019-08-17 16:28:17 +03006816 return 0;
Ido Schimmelc0648752020-03-30 22:38:22 +03006817
6818err_trap_group_set:
6819 if (modified)
6820 NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already");
6821 return err;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006822}
6823
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006824static struct devlink_trap_policer_item *
6825devlink_trap_policer_item_get_from_info(struct devlink *devlink,
6826 struct genl_info *info)
6827{
6828 u32 id;
6829
6830 if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6831 return NULL;
6832 id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6833
6834 return devlink_trap_policer_item_lookup(devlink, id);
6835}
6836
6837static int
6838devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
6839 const struct devlink_trap_policer *policer)
6840{
6841 struct nlattr *attr;
6842 u64 drops;
6843 int err;
6844
6845 if (!devlink->ops->trap_policer_counter_get)
6846 return 0;
6847
6848 err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
6849 if (err)
6850 return err;
6851
6852 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6853 if (!attr)
6854 return -EMSGSIZE;
6855
6856 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
6857 DEVLINK_ATTR_PAD))
6858 goto nla_put_failure;
6859
6860 nla_nest_end(msg, attr);
6861
6862 return 0;
6863
6864nla_put_failure:
6865 nla_nest_cancel(msg, attr);
6866 return -EMSGSIZE;
6867}
6868
6869static int
6870devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
6871 const struct devlink_trap_policer_item *policer_item,
6872 enum devlink_command cmd, u32 portid, u32 seq,
6873 int flags)
6874{
6875 void *hdr;
6876 int err;
6877
6878 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6879 if (!hdr)
6880 return -EMSGSIZE;
6881
6882 if (devlink_nl_put_handle(msg, devlink))
6883 goto nla_put_failure;
6884
6885 if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6886 policer_item->policer->id))
6887 goto nla_put_failure;
6888
6889 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
6890 policer_item->rate, DEVLINK_ATTR_PAD))
6891 goto nla_put_failure;
6892
6893 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
6894 policer_item->burst, DEVLINK_ATTR_PAD))
6895 goto nla_put_failure;
6896
6897 err = devlink_trap_policer_stats_put(msg, devlink,
6898 policer_item->policer);
6899 if (err)
6900 goto nla_put_failure;
6901
6902 genlmsg_end(msg, hdr);
6903
6904 return 0;
6905
6906nla_put_failure:
6907 genlmsg_cancel(msg, hdr);
6908 return -EMSGSIZE;
6909}
6910
6911static int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
6912 struct genl_info *info)
6913{
6914 struct devlink_trap_policer_item *policer_item;
6915 struct netlink_ext_ack *extack = info->extack;
6916 struct devlink *devlink = info->user_ptr[0];
6917 struct sk_buff *msg;
6918 int err;
6919
6920 if (list_empty(&devlink->trap_policer_list))
6921 return -EOPNOTSUPP;
6922
6923 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
6924 if (!policer_item) {
6925 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6926 return -ENOENT;
6927 }
6928
6929 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6930 if (!msg)
6931 return -ENOMEM;
6932
6933 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
6934 DEVLINK_CMD_TRAP_POLICER_NEW,
6935 info->snd_portid, info->snd_seq, 0);
6936 if (err)
6937 goto err_trap_policer_fill;
6938
6939 return genlmsg_reply(msg, info);
6940
6941err_trap_policer_fill:
6942 nlmsg_free(msg);
6943 return err;
6944}
6945
6946static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,
6947 struct netlink_callback *cb)
6948{
6949 enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW;
6950 struct devlink_trap_policer_item *policer_item;
6951 u32 portid = NETLINK_CB(cb->skb).portid;
6952 struct devlink *devlink;
6953 int start = cb->args[0];
6954 int idx = 0;
6955 int err;
6956
6957 mutex_lock(&devlink_mutex);
6958 list_for_each_entry(devlink, &devlink_list, list) {
6959 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6960 continue;
6961 mutex_lock(&devlink->lock);
6962 list_for_each_entry(policer_item, &devlink->trap_policer_list,
6963 list) {
6964 if (idx < start) {
6965 idx++;
6966 continue;
6967 }
6968 err = devlink_nl_trap_policer_fill(msg, devlink,
6969 policer_item, cmd,
6970 portid,
6971 cb->nlh->nlmsg_seq,
6972 NLM_F_MULTI);
6973 if (err) {
6974 mutex_unlock(&devlink->lock);
6975 goto out;
6976 }
6977 idx++;
6978 }
6979 mutex_unlock(&devlink->lock);
6980 }
6981out:
6982 mutex_unlock(&devlink_mutex);
6983
6984 cb->args[0] = idx;
6985 return msg->len;
6986}
6987
6988static int
6989devlink_trap_policer_set(struct devlink *devlink,
6990 struct devlink_trap_policer_item *policer_item,
6991 struct genl_info *info)
6992{
6993 struct netlink_ext_ack *extack = info->extack;
6994 struct nlattr **attrs = info->attrs;
6995 u64 rate, burst;
6996 int err;
6997
6998 rate = policer_item->rate;
6999 burst = policer_item->burst;
7000
7001 if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
7002 rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
7003
7004 if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
7005 burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
7006
7007 if (rate < policer_item->policer->min_rate) {
7008 NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
7009 return -EINVAL;
7010 }
7011
7012 if (rate > policer_item->policer->max_rate) {
7013 NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
7014 return -EINVAL;
7015 }
7016
7017 if (burst < policer_item->policer->min_burst) {
7018 NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
7019 return -EINVAL;
7020 }
7021
7022 if (burst > policer_item->policer->max_burst) {
7023 NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
7024 return -EINVAL;
7025 }
7026
7027 err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
7028 rate, burst, info->extack);
7029 if (err)
7030 return err;
7031
7032 policer_item->rate = rate;
7033 policer_item->burst = burst;
7034
7035 return 0;
7036}
7037
7038static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
7039 struct genl_info *info)
7040{
7041 struct devlink_trap_policer_item *policer_item;
7042 struct netlink_ext_ack *extack = info->extack;
7043 struct devlink *devlink = info->user_ptr[0];
7044
7045 if (list_empty(&devlink->trap_policer_list))
7046 return -EOPNOTSUPP;
7047
7048 if (!devlink->ops->trap_policer_set)
7049 return -EOPNOTSUPP;
7050
7051 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
7052 if (!policer_item) {
7053 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
7054 return -ENOENT;
7055 }
7056
7057 return devlink_trap_policer_set(devlink, policer_item, info);
7058}
7059
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007060static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007061 [DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
7062 DEVLINK_ATTR_TRAP_POLICER_ID },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007063 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
7064 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
7065 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
Parav Panditc49a9442020-09-21 19:41:30 +03007066 [DEVLINK_ATTR_PORT_TYPE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_PORT_TYPE_AUTO,
7067 DEVLINK_PORT_TYPE_IB),
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007068 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02007069 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
7070 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
7071 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
7072 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
7073 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
7074 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
7075 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Parav Panditba356c92020-09-21 19:41:29 +03007076 [DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_ESWITCH_MODE_LEGACY,
7077 DEVLINK_ESWITCH_MODE_SWITCHDEV),
Roi Dayan59bfde02016-11-22 23:09:57 +02007078 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03007079 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007080 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
7081 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007082 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
7083 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007084 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
7085 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
7086 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007087 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03007088 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Jakub Kicinskiff3b63b2020-03-02 21:05:12 -08007089 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
7090 [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007091 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007092 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
7093 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007094 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
7095 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Ido Schimmel0f420b62019-08-17 16:28:17 +03007096 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
7097 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
7098 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
Jiri Pirko070c63f2019-10-03 11:49:39 +02007099 [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
7100 [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
7101 [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03007102 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007103 [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
7104 [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
7105 [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
Parav Pandita1e8ae92020-06-19 03:32:49 +00007106 [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007107};
7108
7109static const struct genl_ops devlink_nl_ops[] = {
7110 {
7111 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007112 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007113 .doit = devlink_nl_cmd_get_doit,
7114 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007115 /* can be retrieved by unprivileged users */
7116 },
7117 {
7118 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007119 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007120 .doit = devlink_nl_cmd_port_get_doit,
7121 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007122 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7123 /* can be retrieved by unprivileged users */
7124 },
7125 {
7126 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007127 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007128 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007129 .flags = GENL_ADMIN_PERM,
7130 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7131 },
7132 {
7133 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007134 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007135 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007136 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007137 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007138 },
7139 {
7140 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007141 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007142 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007143 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007144 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007145 },
Jiri Pirkobf797472016-04-14 18:19:13 +02007146 {
7147 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007148 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007149 .doit = devlink_nl_cmd_sb_get_doit,
7150 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007151 /* can be retrieved by unprivileged users */
7152 },
7153 {
7154 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007155 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007156 .doit = devlink_nl_cmd_sb_pool_get_doit,
7157 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007158 /* can be retrieved by unprivileged users */
7159 },
7160 {
7161 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007162 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007163 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007164 .flags = GENL_ADMIN_PERM,
Jiri Pirkobf797472016-04-14 18:19:13 +02007165 },
7166 {
7167 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007168 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007169 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
7170 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Parav Pandit637989b2020-07-22 18:57:11 +03007171 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007172 /* can be retrieved by unprivileged users */
7173 },
7174 {
7175 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007176 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007177 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007178 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007179 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007180 },
7181 {
7182 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007183 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007184 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
7185 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Parav Pandit637989b2020-07-22 18:57:11 +03007186 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007187 /* can be retrieved by unprivileged users */
7188 },
7189 {
7190 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007191 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007192 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007193 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007194 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
Jiri Pirkobf797472016-04-14 18:19:13 +02007195 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007196 {
7197 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007198 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007199 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007200 .flags = GENL_ADMIN_PERM,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007201 },
7202 {
7203 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007204 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007205 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007206 .flags = GENL_ADMIN_PERM,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007207 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03007208 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007209 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007210 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007211 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007212 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007213 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007214 },
7215 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007216 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007217 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007218 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007219 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007220 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007221 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007222 {
7223 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007224 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007225 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007226 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007227 },
7228 {
7229 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007230 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007231 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007232 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007233 },
7234 {
7235 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007236 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007237 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007238 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007239 },
7240 {
7241 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007242 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007243 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007244 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007245 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007246 {
7247 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007248 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007249 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007250 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007251 },
7252 {
7253 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02007254 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007255 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007256 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007257 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007258 {
7259 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02007260 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007261 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007262 .flags = GENL_ADMIN_PERM,
Parav Pandit637989b2020-07-22 18:57:11 +03007263 .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007264 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007265 {
7266 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007267 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007268 .doit = devlink_nl_cmd_param_get_doit,
7269 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007270 /* can be retrieved by unprivileged users */
7271 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007272 {
7273 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007274 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007275 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007276 .flags = GENL_ADMIN_PERM,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007277 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007278 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307279 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007280 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307281 .doit = devlink_nl_cmd_port_param_get_doit,
7282 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307283 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7284 /* can be retrieved by unprivileged users */
7285 },
7286 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05307287 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007288 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307289 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307290 .flags = GENL_ADMIN_PERM,
7291 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7292 },
7293 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007294 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007295 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007296 .doit = devlink_nl_cmd_region_get_doit,
7297 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007298 .flags = GENL_ADMIN_PERM,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007299 },
Alex Vesker866319b2018-07-12 15:13:13 +03007300 {
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07007301 .cmd = DEVLINK_CMD_REGION_NEW,
7302 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7303 .doit = devlink_nl_cmd_region_new,
7304 .flags = GENL_ADMIN_PERM,
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07007305 },
7306 {
Alex Vesker866319b2018-07-12 15:13:13 +03007307 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02007308 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03007309 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03007310 .flags = GENL_ADMIN_PERM,
Alex Vesker866319b2018-07-12 15:13:13 +03007311 },
Alex Vesker4e547952018-07-12 15:13:14 +03007312 {
7313 .cmd = DEVLINK_CMD_REGION_READ,
Jiri Pirkoee85da52019-10-05 20:04:42 +02007314 .validate = GENL_DONT_VALIDATE_STRICT |
7315 GENL_DONT_VALIDATE_DUMP_STRICT,
Alex Vesker4e547952018-07-12 15:13:14 +03007316 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03007317 .flags = GENL_ADMIN_PERM,
Alex Vesker4e547952018-07-12 15:13:14 +03007318 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007319 {
7320 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007321 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007322 .doit = devlink_nl_cmd_info_get_doit,
7323 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007324 /* can be retrieved by unprivileged users */
7325 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007326 {
7327 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007328 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007329 .doit = devlink_nl_cmd_health_reporter_get_doit,
7330 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007331 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007332 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007333 /* can be retrieved by unprivileged users */
7334 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007335 {
7336 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007337 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007338 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007339 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007340 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007341 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007342 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007343 {
7344 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02007345 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007346 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007347 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007348 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007349 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007350 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007351 {
7352 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007353 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007354 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007355 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007356 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007357 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007358 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007359 {
7360 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Jiri Pirko82a843d2019-10-07 09:28:31 +02007361 .validate = GENL_DONT_VALIDATE_STRICT |
7362 GENL_DONT_VALIDATE_DUMP_STRICT,
Aya Levine44ef4e2019-05-16 09:49:20 +03007363 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007364 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007365 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007366 DEVLINK_NL_FLAG_NO_LOCK,
7367 },
7368 {
7369 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007370 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007371 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007372 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007373 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007374 DEVLINK_NL_FLAG_NO_LOCK,
7375 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007376 {
Jiri Pirkoe2ce94d2020-09-15 11:40:57 +03007377 .cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST,
7378 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7379 .doit = devlink_nl_cmd_health_reporter_test_doit,
7380 .flags = GENL_ADMIN_PERM,
7381 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
7382 DEVLINK_NL_FLAG_NO_LOCK,
7383 },
7384 {
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007385 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007386 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007387 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007388 .flags = GENL_ADMIN_PERM,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007389 },
Ido Schimmel0f420b62019-08-17 16:28:17 +03007390 {
7391 .cmd = DEVLINK_CMD_TRAP_GET,
7392 .doit = devlink_nl_cmd_trap_get_doit,
7393 .dumpit = devlink_nl_cmd_trap_get_dumpit,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007394 /* can be retrieved by unprivileged users */
7395 },
7396 {
7397 .cmd = DEVLINK_CMD_TRAP_SET,
7398 .doit = devlink_nl_cmd_trap_set_doit,
7399 .flags = GENL_ADMIN_PERM,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007400 },
7401 {
7402 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
7403 .doit = devlink_nl_cmd_trap_group_get_doit,
7404 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007405 /* can be retrieved by unprivileged users */
7406 },
7407 {
7408 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
7409 .doit = devlink_nl_cmd_trap_group_set_doit,
7410 .flags = GENL_ADMIN_PERM,
Ido Schimmel0f420b62019-08-17 16:28:17 +03007411 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007412 {
7413 .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
7414 .doit = devlink_nl_cmd_trap_policer_get_doit,
7415 .dumpit = devlink_nl_cmd_trap_policer_get_dumpit,
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007416 /* can be retrieved by unprivileged users */
7417 },
7418 {
7419 .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
7420 .doit = devlink_nl_cmd_trap_policer_set_doit,
7421 .flags = GENL_ADMIN_PERM,
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007422 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007423};
7424
Johannes Berg56989f62016-10-24 14:40:05 +02007425static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02007426 .name = DEVLINK_GENL_NAME,
7427 .version = DEVLINK_GENL_VERSION,
7428 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01007429 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02007430 .netnsok = true,
7431 .pre_doit = devlink_nl_pre_doit,
7432 .post_doit = devlink_nl_post_doit,
7433 .module = THIS_MODULE,
7434 .ops = devlink_nl_ops,
7435 .n_ops = ARRAY_SIZE(devlink_nl_ops),
7436 .mcgrps = devlink_nl_mcgrps,
7437 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
7438};
7439
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007440/**
7441 * devlink_alloc - Allocate new devlink instance resources
7442 *
7443 * @ops: ops
7444 * @priv_size: size of user private data
7445 *
7446 * Allocate new devlink instance resources, including devlink index
7447 * and name.
7448 */
7449struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
7450{
7451 struct devlink *devlink;
7452
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007453 if (WARN_ON(!ops))
7454 return NULL;
7455
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007456 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
7457 if (!devlink)
7458 return NULL;
7459 devlink->ops = ops;
Jacob Keller12102432020-03-26 11:37:15 -07007460 xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
Jiri Pirko8273fd82019-10-05 08:10:31 +02007461 __devlink_net_set(devlink, &init_net);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007462 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02007463 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007464 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007465 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03007466 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03007467 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02007468 INIT_LIST_HEAD(&devlink->reporter_list);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007469 INIT_LIST_HEAD(&devlink->trap_list);
7470 INIT_LIST_HEAD(&devlink->trap_group_list);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007471 INIT_LIST_HEAD(&devlink->trap_policer_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007472 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007473 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007474 return devlink;
7475}
7476EXPORT_SYMBOL_GPL(devlink_alloc);
7477
7478/**
7479 * devlink_register - Register devlink instance
7480 *
7481 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007482 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007483 */
7484int devlink_register(struct devlink *devlink, struct device *dev)
7485{
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007486 devlink->dev = dev;
Jiri Pirko8273fd82019-10-05 08:10:31 +02007487 devlink->registered = true;
Parav Pandit6553e562020-07-21 19:53:51 +03007488 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007489 list_add_tail(&devlink->list, &devlink_list);
7490 devlink_notify(devlink, DEVLINK_CMD_NEW);
7491 mutex_unlock(&devlink_mutex);
7492 return 0;
7493}
7494EXPORT_SYMBOL_GPL(devlink_register);
7495
7496/**
7497 * devlink_unregister - Unregister devlink instance
7498 *
7499 * @devlink: devlink
7500 */
7501void devlink_unregister(struct devlink *devlink)
7502{
7503 mutex_lock(&devlink_mutex);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007504 WARN_ON(devlink_reload_supported(devlink) &&
7505 devlink->reload_enabled);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007506 devlink_notify(devlink, DEVLINK_CMD_DEL);
7507 list_del(&devlink->list);
7508 mutex_unlock(&devlink_mutex);
7509}
7510EXPORT_SYMBOL_GPL(devlink_unregister);
7511
7512/**
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007513 * devlink_reload_enable - Enable reload of devlink instance
7514 *
7515 * @devlink: devlink
7516 *
7517 * Should be called at end of device initialization
7518 * process when reload operation is supported.
7519 */
7520void devlink_reload_enable(struct devlink *devlink)
7521{
7522 mutex_lock(&devlink_mutex);
7523 devlink->reload_enabled = true;
7524 mutex_unlock(&devlink_mutex);
7525}
7526EXPORT_SYMBOL_GPL(devlink_reload_enable);
7527
7528/**
7529 * devlink_reload_disable - Disable reload of devlink instance
7530 *
7531 * @devlink: devlink
7532 *
7533 * Should be called at the beginning of device cleanup
7534 * process when reload operation is supported.
7535 */
7536void devlink_reload_disable(struct devlink *devlink)
7537{
7538 mutex_lock(&devlink_mutex);
7539 /* Mutex is taken which ensures that no reload operation is in
7540 * progress while setting up forbidded flag.
7541 */
7542 devlink->reload_enabled = false;
7543 mutex_unlock(&devlink_mutex);
7544}
7545EXPORT_SYMBOL_GPL(devlink_reload_disable);
7546
7547/**
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007548 * devlink_free - Free devlink instance resources
7549 *
7550 * @devlink: devlink
7551 */
7552void devlink_free(struct devlink *devlink)
7553{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007554 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01007555 mutex_destroy(&devlink->lock);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007556 WARN_ON(!list_empty(&devlink->trap_policer_list));
Ido Schimmel0f420b62019-08-17 16:28:17 +03007557 WARN_ON(!list_empty(&devlink->trap_group_list));
7558 WARN_ON(!list_empty(&devlink->trap_list));
Parav Panditb904aad2019-02-08 15:15:00 -06007559 WARN_ON(!list_empty(&devlink->reporter_list));
7560 WARN_ON(!list_empty(&devlink->region_list));
7561 WARN_ON(!list_empty(&devlink->param_list));
7562 WARN_ON(!list_empty(&devlink->resource_list));
7563 WARN_ON(!list_empty(&devlink->dpipe_table_list));
7564 WARN_ON(!list_empty(&devlink->sb_list));
7565 WARN_ON(!list_empty(&devlink->port_list));
7566
Jacob Keller12102432020-03-26 11:37:15 -07007567 xa_destroy(&devlink->snapshot_ids);
7568
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007569 kfree(devlink);
7570}
7571EXPORT_SYMBOL_GPL(devlink_free);
7572
Jiri Pirko136bf272019-05-23 10:43:35 +02007573static void devlink_port_type_warn(struct work_struct *work)
7574{
7575 WARN(true, "Type was not set for devlink port.");
7576}
7577
7578static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
7579{
7580 /* Ignore CPU and DSA flavours. */
7581 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
7582 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
7583}
7584
Ido Schimmel4c582232020-01-09 19:57:41 +02007585#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
Jiri Pirko136bf272019-05-23 10:43:35 +02007586
7587static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
7588{
7589 if (!devlink_port_type_should_warn(devlink_port))
7590 return;
7591 /* Schedule a work to WARN in case driver does not set port
7592 * type within timeout.
7593 */
7594 schedule_delayed_work(&devlink_port->type_warn_dw,
7595 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
7596}
7597
7598static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
7599{
7600 if (!devlink_port_type_should_warn(devlink_port))
7601 return;
7602 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
7603}
7604
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007605/**
7606 * devlink_port_register - Register devlink port
7607 *
7608 * @devlink: devlink
7609 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007610 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007611 *
7612 * Register devlink port with provided port index. User can use
7613 * any indexing, even hw-related one. devlink_port structure
7614 * is convenient to be embedded inside user driver private structure.
7615 * Note that the caller should take care of zeroing the devlink_port
7616 * structure.
7617 */
7618int devlink_port_register(struct devlink *devlink,
7619 struct devlink_port *devlink_port,
7620 unsigned int port_index)
7621{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007622 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007623 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007624 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007625 return -EEXIST;
7626 }
7627 devlink_port->devlink = devlink;
7628 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007629 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01007630 spin_lock_init(&devlink_port->type_lock);
Parav Pandit79604c52020-08-21 22:12:20 +03007631 INIT_LIST_HEAD(&devlink_port->reporter_list);
7632 mutex_init(&devlink_port->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007633 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05307634 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007635 mutex_unlock(&devlink->lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02007636 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
7637 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007638 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7639 return 0;
7640}
7641EXPORT_SYMBOL_GPL(devlink_port_register);
7642
7643/**
7644 * devlink_port_unregister - Unregister devlink port
7645 *
7646 * @devlink_port: devlink port
7647 */
7648void devlink_port_unregister(struct devlink_port *devlink_port)
7649{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007650 struct devlink *devlink = devlink_port->devlink;
7651
Jiri Pirko136bf272019-05-23 10:43:35 +02007652 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007653 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007654 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007655 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007656 mutex_unlock(&devlink->lock);
Parav Pandit79604c52020-08-21 22:12:20 +03007657 WARN_ON(!list_empty(&devlink_port->reporter_list));
7658 mutex_destroy(&devlink_port->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007659}
7660EXPORT_SYMBOL_GPL(devlink_port_unregister);
7661
7662static void __devlink_port_type_set(struct devlink_port *devlink_port,
7663 enum devlink_port_type type,
7664 void *type_dev)
7665{
Jiri Pirko2b239e72019-03-24 11:14:36 +01007666 if (WARN_ON(!devlink_port->registered))
7667 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02007668 devlink_port_type_warn_cancel(devlink_port);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007669 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007670 devlink_port->type = type;
7671 devlink_port->type_dev = type_dev;
Ido Schimmel0f420b62019-08-17 16:28:17 +03007672 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007673 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7674}
7675
Jakub Kicinski3ea87ca2020-09-08 15:21:13 -07007676static void devlink_port_type_netdev_checks(struct devlink_port *devlink_port,
7677 struct net_device *netdev)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007678{
Jiri Pirko119c0b52019-04-03 14:24:27 +02007679 const struct net_device_ops *ops = netdev->netdev_ops;
7680
Jiri Pirko746364f2019-03-28 13:56:46 +01007681 /* If driver registers devlink port, it should set devlink port
7682 * attributes accordingly so the compat functions are called
7683 * and the original ops are not used.
7684 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02007685 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01007686 /* Some drivers use the same set of ndos for netdevs
7687 * that have devlink_port registered and also for
7688 * those who don't. Make sure that ndo_get_phys_port_name
7689 * returns -EOPNOTSUPP here in case it is defined.
7690 * Warn if not.
7691 */
Jiri Pirko746364f2019-03-28 13:56:46 +01007692 char name[IFNAMSIZ];
7693 int err;
7694
7695 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
7696 WARN_ON(err != -EOPNOTSUPP);
7697 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02007698 if (ops->ndo_get_port_parent_id) {
7699 /* Some drivers use the same set of ndos for netdevs
7700 * that have devlink_port registered and also for
7701 * those who don't. Make sure that ndo_get_port_parent_id
7702 * returns -EOPNOTSUPP here in case it is defined.
7703 * Warn if not.
7704 */
7705 struct netdev_phys_item_id ppid;
7706 int err;
7707
7708 err = ops->ndo_get_port_parent_id(netdev, &ppid);
7709 WARN_ON(err != -EOPNOTSUPP);
7710 }
Jakub Kicinski3ea87ca2020-09-08 15:21:13 -07007711}
7712
7713/**
7714 * devlink_port_type_eth_set - Set port type to Ethernet
7715 *
7716 * @devlink_port: devlink port
7717 * @netdev: related netdevice
7718 */
7719void devlink_port_type_eth_set(struct devlink_port *devlink_port,
7720 struct net_device *netdev)
7721{
7722 if (netdev)
7723 devlink_port_type_netdev_checks(devlink_port, netdev);
7724 else
7725 dev_warn(devlink_port->devlink->dev,
7726 "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
7727 devlink_port->index);
7728
Jiri Pirko773b1f32019-03-24 11:14:30 +01007729 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007730}
7731EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
7732
7733/**
7734 * devlink_port_type_ib_set - Set port type to InfiniBand
7735 *
7736 * @devlink_port: devlink port
7737 * @ibdev: related IB device
7738 */
7739void devlink_port_type_ib_set(struct devlink_port *devlink_port,
7740 struct ib_device *ibdev)
7741{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007742 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007743}
7744EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
7745
7746/**
7747 * devlink_port_type_clear - Clear port type
7748 *
7749 * @devlink_port: devlink port
7750 */
7751void devlink_port_type_clear(struct devlink_port *devlink_port)
7752{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007753 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02007754 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007755}
7756EXPORT_SYMBOL_GPL(devlink_port_type_clear);
7757
Parav Pandit378ef012019-07-08 23:17:35 -05007758static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007759 enum devlink_port_flavour flavour)
Parav Pandit378ef012019-07-08 23:17:35 -05007760{
7761 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7762
7763 if (WARN_ON(devlink_port->registered))
7764 return -EEXIST;
Danielle Ratson10a429b2020-07-09 16:18:14 +03007765 devlink_port->attrs_set = true;
Parav Pandit378ef012019-07-08 23:17:35 -05007766 attrs->flavour = flavour;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007767 if (attrs->switch_id.id_len) {
Danielle Ratson46737a12020-07-09 16:18:15 +03007768 devlink_port->switch_port = true;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007769 if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
7770 attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
Parav Pandit378ef012019-07-08 23:17:35 -05007771 } else {
Danielle Ratson46737a12020-07-09 16:18:15 +03007772 devlink_port->switch_port = false;
Parav Pandit378ef012019-07-08 23:17:35 -05007773 }
7774 return 0;
7775}
7776
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007777/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007778 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007779 *
7780 * @devlink_port: devlink port
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007781 * @attrs: devlink port attrs
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007782 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007783void devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007784 struct devlink_port_attrs *attrs)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007785{
Parav Pandit378ef012019-07-08 23:17:35 -05007786 int ret;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007787
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007788 devlink_port->attrs = *attrs;
7789 ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
Parav Pandit378ef012019-07-08 23:17:35 -05007790 if (ret)
Jiri Pirko45b86112019-03-24 11:14:33 +01007791 return;
Danielle Ratsona0f49b52020-07-09 16:18:20 +03007792 WARN_ON(attrs->splittable && attrs->split);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007793}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007794EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007795
Parav Pandit98fd2d62019-07-08 23:17:37 -05007796/**
7797 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
7798 *
7799 * @devlink_port: devlink port
Parav Pandit3a2d9582020-09-09 07:50:37 +03007800 * @controller: associated controller number for the devlink port instance
Parav Pandit98fd2d62019-07-08 23:17:37 -05007801 * @pf: associated PF for the devlink port instance
Parav Pandit05b595e2020-09-09 07:50:36 +03007802 * @external: indicates if the port is for an external controller
Parav Pandit98fd2d62019-07-08 23:17:37 -05007803 */
Parav Pandit3a2d9582020-09-09 07:50:37 +03007804void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 controller,
7805 u16 pf, bool external)
Parav Pandit98fd2d62019-07-08 23:17:37 -05007806{
7807 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7808 int ret;
7809
7810 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007811 DEVLINK_PORT_FLAVOUR_PCI_PF);
Parav Pandit98fd2d62019-07-08 23:17:37 -05007812 if (ret)
7813 return;
Parav Pandit3a2d9582020-09-09 07:50:37 +03007814 attrs->pci_pf.controller = controller;
Parav Pandit98fd2d62019-07-08 23:17:37 -05007815 attrs->pci_pf.pf = pf;
Parav Pandit05b595e2020-09-09 07:50:36 +03007816 attrs->pci_pf.external = external;
Parav Pandit98fd2d62019-07-08 23:17:37 -05007817}
7818EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
7819
Parav Pandite41b6bf2019-07-08 23:17:38 -05007820/**
7821 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
7822 *
7823 * @devlink_port: devlink port
Parav Pandit3a2d9582020-09-09 07:50:37 +03007824 * @controller: associated controller number for the devlink port instance
Parav Pandite41b6bf2019-07-08 23:17:38 -05007825 * @pf: associated PF for the devlink port instance
7826 * @vf: associated VF of a PF for the devlink port instance
Parav Pandit05b595e2020-09-09 07:50:36 +03007827 * @external: indicates if the port is for an external controller
Parav Pandite41b6bf2019-07-08 23:17:38 -05007828 */
Parav Pandit3a2d9582020-09-09 07:50:37 +03007829void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller,
Parav Pandit05b595e2020-09-09 07:50:36 +03007830 u16 pf, u16 vf, bool external)
Parav Pandite41b6bf2019-07-08 23:17:38 -05007831{
7832 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7833 int ret;
7834
7835 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007836 DEVLINK_PORT_FLAVOUR_PCI_VF);
Parav Pandite41b6bf2019-07-08 23:17:38 -05007837 if (ret)
7838 return;
Parav Pandit3a2d9582020-09-09 07:50:37 +03007839 attrs->pci_vf.controller = controller;
Parav Pandite41b6bf2019-07-08 23:17:38 -05007840 attrs->pci_vf.pf = pf;
7841 attrs->pci_vf.vf = vf;
Parav Pandit05b595e2020-09-09 07:50:36 +03007842 attrs->pci_vf.external = external;
Parav Pandite41b6bf2019-07-08 23:17:38 -05007843}
7844EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
7845
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007846static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
7847 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02007848{
7849 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7850 int n = 0;
7851
Danielle Ratson10a429b2020-07-09 16:18:14 +03007852 if (!devlink_port->attrs_set)
Jiri Pirko08474c12018-05-18 09:29:02 +02007853 return -EOPNOTSUPP;
7854
7855 switch (attrs->flavour) {
7856 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
Parav Panditacf1ee42020-03-03 08:12:42 -06007857 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Jiri Pirko08474c12018-05-18 09:29:02 +02007858 if (!attrs->split)
Parav Pandit378ef012019-07-08 23:17:35 -05007859 n = snprintf(name, len, "p%u", attrs->phys.port_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007860 else
Parav Pandit378ef012019-07-08 23:17:35 -05007861 n = snprintf(name, len, "p%us%u",
7862 attrs->phys.port_number,
7863 attrs->phys.split_subport_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007864 break;
7865 case DEVLINK_PORT_FLAVOUR_CPU:
7866 case DEVLINK_PORT_FLAVOUR_DSA:
7867 /* As CPU and DSA ports do not have a netdevice associated
7868 * case should not ever happen.
7869 */
7870 WARN_ON(1);
7871 return -EINVAL;
Parav Pandit98fd2d62019-07-08 23:17:37 -05007872 case DEVLINK_PORT_FLAVOUR_PCI_PF:
Parav Pandit66b17082020-09-09 07:50:38 +03007873 if (attrs->pci_pf.external) {
7874 n = snprintf(name, len, "c%u", attrs->pci_pf.controller);
7875 if (n >= len)
7876 return -EINVAL;
7877 len -= n;
7878 name += n;
7879 }
Parav Pandit98fd2d62019-07-08 23:17:37 -05007880 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
7881 break;
Parav Pandite41b6bf2019-07-08 23:17:38 -05007882 case DEVLINK_PORT_FLAVOUR_PCI_VF:
Parav Pandit66b17082020-09-09 07:50:38 +03007883 if (attrs->pci_vf.external) {
7884 n = snprintf(name, len, "c%u", attrs->pci_vf.controller);
7885 if (n >= len)
7886 return -EINVAL;
7887 len -= n;
7888 name += n;
7889 }
Parav Pandite41b6bf2019-07-08 23:17:38 -05007890 n = snprintf(name, len, "pf%uvf%u",
7891 attrs->pci_vf.pf, attrs->pci_vf.vf);
7892 break;
Jiri Pirko08474c12018-05-18 09:29:02 +02007893 }
7894
7895 if (n >= len)
7896 return -EINVAL;
7897
7898 return 0;
7899}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007900
Jiri Pirkobf797472016-04-14 18:19:13 +02007901int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
7902 u32 size, u16 ingress_pools_count,
7903 u16 egress_pools_count, u16 ingress_tc_count,
7904 u16 egress_tc_count)
7905{
7906 struct devlink_sb *devlink_sb;
7907 int err = 0;
7908
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007909 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007910 if (devlink_sb_index_exists(devlink, sb_index)) {
7911 err = -EEXIST;
7912 goto unlock;
7913 }
7914
7915 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
7916 if (!devlink_sb) {
7917 err = -ENOMEM;
7918 goto unlock;
7919 }
7920 devlink_sb->index = sb_index;
7921 devlink_sb->size = size;
7922 devlink_sb->ingress_pools_count = ingress_pools_count;
7923 devlink_sb->egress_pools_count = egress_pools_count;
7924 devlink_sb->ingress_tc_count = ingress_tc_count;
7925 devlink_sb->egress_tc_count = egress_tc_count;
7926 list_add_tail(&devlink_sb->list, &devlink->sb_list);
7927unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007928 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007929 return err;
7930}
7931EXPORT_SYMBOL_GPL(devlink_sb_register);
7932
7933void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
7934{
7935 struct devlink_sb *devlink_sb;
7936
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007937 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007938 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
7939 WARN_ON(!devlink_sb);
7940 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007941 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007942 kfree(devlink_sb);
7943}
7944EXPORT_SYMBOL_GPL(devlink_sb_unregister);
7945
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007946/**
7947 * devlink_dpipe_headers_register - register dpipe headers
7948 *
7949 * @devlink: devlink
7950 * @dpipe_headers: dpipe header array
7951 *
7952 * Register the headers supported by hardware.
7953 */
7954int devlink_dpipe_headers_register(struct devlink *devlink,
7955 struct devlink_dpipe_headers *dpipe_headers)
7956{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007957 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007958 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007959 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007960 return 0;
7961}
7962EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
7963
7964/**
7965 * devlink_dpipe_headers_unregister - unregister dpipe headers
7966 *
7967 * @devlink: devlink
7968 *
7969 * Unregister the headers supported by hardware.
7970 */
7971void devlink_dpipe_headers_unregister(struct devlink *devlink)
7972{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007973 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007974 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007975 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007976}
7977EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
7978
7979/**
7980 * devlink_dpipe_table_counter_enabled - check if counter allocation
7981 * required
7982 * @devlink: devlink
7983 * @table_name: tables name
7984 *
7985 * Used by driver to check if counter allocation is required.
7986 * After counter allocation is turned on the table entries
7987 * are updated to include counter statistics.
7988 *
7989 * After that point on the driver must respect the counter
7990 * state so that each entry added to the table is added
7991 * with a counter.
7992 */
7993bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
7994 const char *table_name)
7995{
7996 struct devlink_dpipe_table *table;
7997 bool enabled;
7998
7999 rcu_read_lock();
8000 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308001 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008002 enabled = false;
8003 if (table)
8004 enabled = table->counters_enabled;
8005 rcu_read_unlock();
8006 return enabled;
8007}
8008EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
8009
8010/**
8011 * devlink_dpipe_table_register - register dpipe table
8012 *
8013 * @devlink: devlink
8014 * @table_name: table name
8015 * @table_ops: table ops
8016 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008017 * @counter_control_extern: external control for counters
8018 */
8019int devlink_dpipe_table_register(struct devlink *devlink,
8020 const char *table_name,
8021 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02008022 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008023{
8024 struct devlink_dpipe_table *table;
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308025 int err = 0;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008026
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02008027 if (WARN_ON(!table_ops->size_get))
8028 return -EINVAL;
8029
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308030 mutex_lock(&devlink->lock);
8031
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308032 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
8033 devlink)) {
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308034 err = -EEXIST;
8035 goto unlock;
8036 }
8037
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008038 table = kzalloc(sizeof(*table), GFP_KERNEL);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308039 if (!table) {
8040 err = -ENOMEM;
8041 goto unlock;
8042 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008043
8044 table->name = table_name;
8045 table->table_ops = table_ops;
8046 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008047 table->counter_control_extern = counter_control_extern;
8048
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008049 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308050unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008051 mutex_unlock(&devlink->lock);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05308052 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008053}
8054EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
8055
8056/**
8057 * devlink_dpipe_table_unregister - unregister dpipe table
8058 *
8059 * @devlink: devlink
8060 * @table_name: table name
8061 */
8062void devlink_dpipe_table_unregister(struct devlink *devlink,
8063 const char *table_name)
8064{
8065 struct devlink_dpipe_table *table;
8066
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008067 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008068 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308069 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008070 if (!table)
8071 goto unlock;
8072 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008073 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008074 kfree_rcu(table, rcu);
8075 return;
8076unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01008077 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02008078}
8079EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
8080
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008081/**
8082 * devlink_resource_register - devlink resource register
8083 *
8084 * @devlink: devlink
8085 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008086 * @resource_size: resource's size
8087 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008088 * @parent_resource_id: resource's parent id
8089 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008090 */
8091int devlink_resource_register(struct devlink *devlink,
8092 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008093 u64 resource_size,
8094 u64 resource_id,
8095 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02008096 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008097{
8098 struct devlink_resource *resource;
8099 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07008100 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008101 int err = 0;
8102
David Ahern14530742018-03-20 19:31:14 -07008103 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
8104
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008105 mutex_lock(&devlink->lock);
8106 resource = devlink_resource_find(devlink, NULL, resource_id);
8107 if (resource) {
8108 err = -EINVAL;
8109 goto out;
8110 }
8111
8112 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
8113 if (!resource) {
8114 err = -ENOMEM;
8115 goto out;
8116 }
8117
8118 if (top_hierarchy) {
8119 resource_list = &devlink->resource_list;
8120 } else {
8121 struct devlink_resource *parent_resource;
8122
8123 parent_resource = devlink_resource_find(devlink, NULL,
8124 parent_resource_id);
8125 if (parent_resource) {
8126 resource_list = &parent_resource->resource_list;
8127 resource->parent = parent_resource;
8128 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00008129 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008130 err = -EINVAL;
8131 goto out;
8132 }
8133 }
8134
8135 resource->name = resource_name;
8136 resource->size = resource_size;
8137 resource->size_new = resource_size;
8138 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008139 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01008140 memcpy(&resource->size_params, size_params,
8141 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008142 INIT_LIST_HEAD(&resource->resource_list);
8143 list_add_tail(&resource->list, resource_list);
8144out:
8145 mutex_unlock(&devlink->lock);
8146 return err;
8147}
8148EXPORT_SYMBOL_GPL(devlink_resource_register);
8149
8150/**
8151 * devlink_resources_unregister - free all resources
8152 *
8153 * @devlink: devlink
8154 * @resource: resource
8155 */
8156void devlink_resources_unregister(struct devlink *devlink,
8157 struct devlink_resource *resource)
8158{
8159 struct devlink_resource *tmp, *child_resource;
8160 struct list_head *resource_list;
8161
8162 if (resource)
8163 resource_list = &resource->resource_list;
8164 else
8165 resource_list = &devlink->resource_list;
8166
8167 if (!resource)
8168 mutex_lock(&devlink->lock);
8169
8170 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
8171 devlink_resources_unregister(devlink, child_resource);
8172 list_del(&child_resource->list);
8173 kfree(child_resource);
8174 }
8175
8176 if (!resource)
8177 mutex_unlock(&devlink->lock);
8178}
8179EXPORT_SYMBOL_GPL(devlink_resources_unregister);
8180
8181/**
8182 * devlink_resource_size_get - get and update size
8183 *
8184 * @devlink: devlink
8185 * @resource_id: the requested resource id
8186 * @p_resource_size: ptr to update
8187 */
8188int devlink_resource_size_get(struct devlink *devlink,
8189 u64 resource_id,
8190 u64 *p_resource_size)
8191{
8192 struct devlink_resource *resource;
8193 int err = 0;
8194
8195 mutex_lock(&devlink->lock);
8196 resource = devlink_resource_find(devlink, NULL, resource_id);
8197 if (!resource) {
8198 err = -EINVAL;
8199 goto out;
8200 }
8201 *p_resource_size = resource->size_new;
8202 resource->size = resource->size_new;
8203out:
8204 mutex_unlock(&devlink->lock);
8205 return err;
8206}
8207EXPORT_SYMBOL_GPL(devlink_resource_size_get);
8208
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008209/**
8210 * devlink_dpipe_table_resource_set - set the resource id
8211 *
8212 * @devlink: devlink
8213 * @table_name: table name
8214 * @resource_id: resource id
8215 * @resource_units: number of resource's units consumed per table's entry
8216 */
8217int devlink_dpipe_table_resource_set(struct devlink *devlink,
8218 const char *table_name, u64 resource_id,
8219 u64 resource_units)
8220{
8221 struct devlink_dpipe_table *table;
8222 int err = 0;
8223
8224 mutex_lock(&devlink->lock);
8225 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308226 table_name, devlink);
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008227 if (!table) {
8228 err = -EINVAL;
8229 goto out;
8230 }
8231 table->resource_id = resource_id;
8232 table->resource_units = resource_units;
8233 table->resource_valid = true;
8234out:
8235 mutex_unlock(&devlink->lock);
8236 return err;
8237}
8238EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
8239
Jiri Pirkofc56be42018-04-05 22:13:21 +02008240/**
8241 * devlink_resource_occ_get_register - register occupancy getter
8242 *
8243 * @devlink: devlink
8244 * @resource_id: resource id
8245 * @occ_get: occupancy getter callback
8246 * @occ_get_priv: occupancy getter callback priv
8247 */
8248void devlink_resource_occ_get_register(struct devlink *devlink,
8249 u64 resource_id,
8250 devlink_resource_occ_get_t *occ_get,
8251 void *occ_get_priv)
8252{
8253 struct devlink_resource *resource;
8254
8255 mutex_lock(&devlink->lock);
8256 resource = devlink_resource_find(devlink, NULL, resource_id);
8257 if (WARN_ON(!resource))
8258 goto out;
8259 WARN_ON(resource->occ_get);
8260
8261 resource->occ_get = occ_get;
8262 resource->occ_get_priv = occ_get_priv;
8263out:
8264 mutex_unlock(&devlink->lock);
8265}
8266EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
8267
8268/**
8269 * devlink_resource_occ_get_unregister - unregister occupancy getter
8270 *
8271 * @devlink: devlink
8272 * @resource_id: resource id
8273 */
8274void devlink_resource_occ_get_unregister(struct devlink *devlink,
8275 u64 resource_id)
8276{
8277 struct devlink_resource *resource;
8278
8279 mutex_lock(&devlink->lock);
8280 resource = devlink_resource_find(devlink, NULL, resource_id);
8281 if (WARN_ON(!resource))
8282 goto out;
8283 WARN_ON(!resource->occ_get);
8284
8285 resource->occ_get = NULL;
8286 resource->occ_get_priv = NULL;
8287out:
8288 mutex_unlock(&devlink->lock);
8289}
8290EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
8291
Vasundhara Volam39e61602019-01-28 18:00:20 +05308292static int devlink_param_verify(const struct devlink_param *param)
8293{
8294 if (!param || !param->name || !param->supported_cmodes)
8295 return -EINVAL;
8296 if (param->generic)
8297 return devlink_param_generic_verify(param);
8298 else
8299 return devlink_param_driver_verify(param);
8300}
8301
8302static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308303 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308304 struct list_head *param_list,
8305 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308306 size_t params_count,
8307 enum devlink_command reg_cmd,
8308 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308309{
8310 const struct devlink_param *param = params;
8311 int i;
8312 int err;
8313
8314 mutex_lock(&devlink->lock);
8315 for (i = 0; i < params_count; i++, param++) {
8316 err = devlink_param_verify(param);
8317 if (err)
8318 goto rollback;
8319
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308320 err = devlink_param_register_one(devlink, port_index,
8321 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308322 if (err)
8323 goto rollback;
8324 }
8325
8326 mutex_unlock(&devlink->lock);
8327 return 0;
8328
8329rollback:
8330 if (!i)
8331 goto unlock;
8332 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308333 devlink_param_unregister_one(devlink, port_index, param_list,
8334 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308335unlock:
8336 mutex_unlock(&devlink->lock);
8337 return err;
8338}
8339
8340static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308341 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308342 struct list_head *param_list,
8343 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308344 size_t params_count,
8345 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308346{
8347 const struct devlink_param *param = params;
8348 int i;
8349
8350 mutex_lock(&devlink->lock);
8351 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308352 devlink_param_unregister_one(devlink, 0, param_list, param,
8353 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308354 mutex_unlock(&devlink->lock);
8355}
8356
Moshe Shemesheabaef12018-07-04 14:30:28 +03008357/**
8358 * devlink_params_register - register configuration parameters
8359 *
8360 * @devlink: devlink
8361 * @params: configuration parameters array
8362 * @params_count: number of parameters provided
8363 *
8364 * Register the configuration parameters supported by the driver.
8365 */
8366int devlink_params_register(struct devlink *devlink,
8367 const struct devlink_param *params,
8368 size_t params_count)
8369{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308370 return __devlink_params_register(devlink, 0, &devlink->param_list,
8371 params, params_count,
8372 DEVLINK_CMD_PARAM_NEW,
8373 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008374}
8375EXPORT_SYMBOL_GPL(devlink_params_register);
8376
8377/**
8378 * devlink_params_unregister - unregister configuration parameters
8379 * @devlink: devlink
8380 * @params: configuration parameters to unregister
8381 * @params_count: number of parameters provided
8382 */
8383void devlink_params_unregister(struct devlink *devlink,
8384 const struct devlink_param *params,
8385 size_t params_count)
8386{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308387 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
8388 params, params_count,
8389 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008390}
8391EXPORT_SYMBOL_GPL(devlink_params_unregister);
8392
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008393/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00008394 * devlink_params_publish - publish configuration parameters
8395 *
8396 * @devlink: devlink
8397 *
8398 * Publish previously registered configuration parameters.
8399 */
8400void devlink_params_publish(struct devlink *devlink)
8401{
8402 struct devlink_param_item *param_item;
8403
8404 list_for_each_entry(param_item, &devlink->param_list, list) {
8405 if (param_item->published)
8406 continue;
8407 param_item->published = true;
8408 devlink_param_notify(devlink, 0, param_item,
8409 DEVLINK_CMD_PARAM_NEW);
8410 }
8411}
8412EXPORT_SYMBOL_GPL(devlink_params_publish);
8413
8414/**
8415 * devlink_params_unpublish - unpublish configuration parameters
8416 *
8417 * @devlink: devlink
8418 *
8419 * Unpublish previously registered configuration parameters.
8420 */
8421void devlink_params_unpublish(struct devlink *devlink)
8422{
8423 struct devlink_param_item *param_item;
8424
8425 list_for_each_entry(param_item, &devlink->param_list, list) {
8426 if (!param_item->published)
8427 continue;
8428 param_item->published = false;
8429 devlink_param_notify(devlink, 0, param_item,
8430 DEVLINK_CMD_PARAM_DEL);
8431 }
8432}
8433EXPORT_SYMBOL_GPL(devlink_params_unpublish);
8434
8435/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05308436 * devlink_port_params_register - register port configuration parameters
8437 *
8438 * @devlink_port: devlink port
8439 * @params: configuration parameters array
8440 * @params_count: number of parameters provided
8441 *
8442 * Register the configuration parameters supported by the port.
8443 */
8444int devlink_port_params_register(struct devlink_port *devlink_port,
8445 const struct devlink_param *params,
8446 size_t params_count)
8447{
8448 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308449 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308450 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308451 params_count,
8452 DEVLINK_CMD_PORT_PARAM_NEW,
8453 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308454}
8455EXPORT_SYMBOL_GPL(devlink_port_params_register);
8456
8457/**
8458 * devlink_port_params_unregister - unregister port configuration
8459 * parameters
8460 *
8461 * @devlink_port: devlink port
8462 * @params: configuration parameters array
8463 * @params_count: number of parameters provided
8464 */
8465void devlink_port_params_unregister(struct devlink_port *devlink_port,
8466 const struct devlink_param *params,
8467 size_t params_count)
8468{
8469 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308470 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308471 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308472 params, params_count,
8473 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308474}
8475EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
8476
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308477static int
8478__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
8479 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008480{
8481 struct devlink_param_item *param_item;
8482
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308483 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008484 if (!param_item)
8485 return -EINVAL;
8486
8487 if (!param_item->driverinit_value_valid ||
8488 !devlink_param_cmode_is_supported(param_item->param,
8489 DEVLINK_PARAM_CMODE_DRIVERINIT))
8490 return -EOPNOTSUPP;
8491
Moshe Shemesh12765342018-10-10 16:09:26 +03008492 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8493 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
8494 else
8495 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008496
8497 return 0;
8498}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308499
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308500static int
8501__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308502 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308503 struct list_head *param_list, u32 param_id,
8504 union devlink_param_value init_val,
8505 enum devlink_command cmd)
8506{
8507 struct devlink_param_item *param_item;
8508
8509 param_item = devlink_param_find_by_id(param_list, param_id);
8510 if (!param_item)
8511 return -EINVAL;
8512
8513 if (!devlink_param_cmode_is_supported(param_item->param,
8514 DEVLINK_PARAM_CMODE_DRIVERINIT))
8515 return -EOPNOTSUPP;
8516
8517 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8518 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
8519 else
8520 param_item->driverinit_value = init_val;
8521 param_item->driverinit_value_valid = true;
8522
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308523 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308524 return 0;
8525}
8526
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308527/**
8528 * devlink_param_driverinit_value_get - get configuration parameter
8529 * value for driver initializing
8530 *
8531 * @devlink: devlink
8532 * @param_id: parameter ID
8533 * @init_val: value of parameter in driverinit configuration mode
8534 *
8535 * This function should be used by the driver to get driverinit
8536 * configuration for initialization after reload command.
8537 */
8538int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
8539 union devlink_param_value *init_val)
8540{
Jiri Pirko97691062019-09-12 10:49:45 +02008541 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308542 return -EOPNOTSUPP;
8543
8544 return __devlink_param_driverinit_value_get(&devlink->param_list,
8545 param_id, init_val);
8546}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008547EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
8548
8549/**
8550 * devlink_param_driverinit_value_set - set value of configuration
8551 * parameter for driverinit
8552 * configuration mode
8553 *
8554 * @devlink: devlink
8555 * @param_id: parameter ID
8556 * @init_val: value of parameter to set for driverinit configuration mode
8557 *
8558 * This function should be used by the driver to set driverinit
8559 * configuration mode default value.
8560 */
8561int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
8562 union devlink_param_value init_val)
8563{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308564 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308565 &devlink->param_list,
8566 param_id, init_val,
8567 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008568}
8569EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
8570
Moshe Shemeshea601e12018-07-04 14:30:32 +03008571/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308572 * devlink_port_param_driverinit_value_get - get configuration parameter
8573 * value for driver initializing
8574 *
8575 * @devlink_port: devlink_port
8576 * @param_id: parameter ID
8577 * @init_val: value of parameter in driverinit configuration mode
8578 *
8579 * This function should be used by the driver to get driverinit
8580 * configuration for initialization after reload command.
8581 */
8582int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
8583 u32 param_id,
8584 union devlink_param_value *init_val)
8585{
8586 struct devlink *devlink = devlink_port->devlink;
8587
Jiri Pirko97691062019-09-12 10:49:45 +02008588 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308589 return -EOPNOTSUPP;
8590
8591 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
8592 param_id, init_val);
8593}
8594EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
8595
8596/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308597 * devlink_port_param_driverinit_value_set - set value of configuration
8598 * parameter for driverinit
8599 * configuration mode
8600 *
8601 * @devlink_port: devlink_port
8602 * @param_id: parameter ID
8603 * @init_val: value of parameter to set for driverinit configuration mode
8604 *
8605 * This function should be used by the driver to set driverinit
8606 * configuration mode default value.
8607 */
8608int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
8609 u32 param_id,
8610 union devlink_param_value init_val)
8611{
8612 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308613 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308614 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308615 param_id, init_val,
8616 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308617}
8618EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
8619
8620/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03008621 * devlink_param_value_changed - notify devlink on a parameter's value
8622 * change. Should be called by the driver
8623 * right after the change.
8624 *
8625 * @devlink: devlink
8626 * @param_id: parameter ID
8627 *
8628 * This function should be used by the driver to notify devlink on value
8629 * change, excluding driverinit configuration mode.
8630 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03008631 */
8632void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
8633{
8634 struct devlink_param_item *param_item;
8635
8636 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
8637 WARN_ON(!param_item);
8638
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308639 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03008640}
8641EXPORT_SYMBOL_GPL(devlink_param_value_changed);
8642
Alex Veskerb16ebe92018-07-12 15:13:08 +03008643/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308644 * devlink_port_param_value_changed - notify devlink on a parameter's value
8645 * change. Should be called by the driver
8646 * right after the change.
8647 *
8648 * @devlink_port: devlink_port
8649 * @param_id: parameter ID
8650 *
8651 * This function should be used by the driver to notify devlink on value
8652 * change, excluding driverinit configuration mode.
8653 * For driverinit configuration mode driver should use the function
8654 * devlink_port_param_driverinit_value_set() instead.
8655 */
8656void devlink_port_param_value_changed(struct devlink_port *devlink_port,
8657 u32 param_id)
8658{
8659 struct devlink_param_item *param_item;
8660
8661 param_item = devlink_param_find_by_id(&devlink_port->param_list,
8662 param_id);
8663 WARN_ON(!param_item);
8664
8665 devlink_param_notify(devlink_port->devlink, devlink_port->index,
8666 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
8667}
8668EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
8669
8670/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03008671 * devlink_param_value_str_fill - Safely fill-up the string preventing
8672 * from overflow of the preallocated buffer
8673 *
8674 * @dst_val: destination devlink_param_value
8675 * @src: source buffer
8676 */
8677void devlink_param_value_str_fill(union devlink_param_value *dst_val,
8678 const char *src)
8679{
8680 size_t len;
8681
8682 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
8683 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
8684}
8685EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
8686
8687/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03008688 * devlink_region_create - create a new address region
8689 *
8690 * @devlink: devlink
Jacob Kellere8937682020-03-26 11:37:08 -07008691 * @ops: region operations and name
Alex Veskerb16ebe92018-07-12 15:13:08 +03008692 * @region_max_snapshots: Maximum supported number of snapshots for region
8693 * @region_size: size of region
8694 */
Jacob Kellere8937682020-03-26 11:37:08 -07008695struct devlink_region *
8696devlink_region_create(struct devlink *devlink,
8697 const struct devlink_region_ops *ops,
8698 u32 region_max_snapshots, u64 region_size)
Alex Veskerb16ebe92018-07-12 15:13:08 +03008699{
8700 struct devlink_region *region;
8701 int err = 0;
8702
Jacob Kellera0a09f62020-03-26 11:37:09 -07008703 if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
8704 return ERR_PTR(-EINVAL);
8705
Alex Veskerb16ebe92018-07-12 15:13:08 +03008706 mutex_lock(&devlink->lock);
8707
Jacob Kellere8937682020-03-26 11:37:08 -07008708 if (devlink_region_get_by_name(devlink, ops->name)) {
Alex Veskerb16ebe92018-07-12 15:13:08 +03008709 err = -EEXIST;
8710 goto unlock;
8711 }
8712
8713 region = kzalloc(sizeof(*region), GFP_KERNEL);
8714 if (!region) {
8715 err = -ENOMEM;
8716 goto unlock;
8717 }
8718
8719 region->devlink = devlink;
8720 region->max_snapshots = region_max_snapshots;
Jacob Kellere8937682020-03-26 11:37:08 -07008721 region->ops = ops;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008722 region->size = region_size;
8723 INIT_LIST_HEAD(&region->snapshot_list);
8724 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03008725 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008726
8727 mutex_unlock(&devlink->lock);
8728 return region;
8729
8730unlock:
8731 mutex_unlock(&devlink->lock);
8732 return ERR_PTR(err);
8733}
8734EXPORT_SYMBOL_GPL(devlink_region_create);
8735
8736/**
8737 * devlink_region_destroy - destroy address region
8738 *
8739 * @region: devlink region to destroy
8740 */
8741void devlink_region_destroy(struct devlink_region *region)
8742{
8743 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008744 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008745
8746 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008747
8748 /* Free all snapshots of region */
8749 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
Jiri Pirko92b49822019-08-12 14:28:31 +02008750 devlink_region_snapshot_del(region, snapshot);
Alex Veskerd7e52722018-07-12 15:13:10 +03008751
Alex Veskerb16ebe92018-07-12 15:13:08 +03008752 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03008753
8754 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008755 mutex_unlock(&devlink->lock);
8756 kfree(region);
8757}
8758EXPORT_SYMBOL_GPL(devlink_region_destroy);
8759
Alex Veskerccadfa42018-07-12 15:13:09 +03008760/**
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008761 * devlink_region_snapshot_id_get - get snapshot ID
Alex Veskerccadfa42018-07-12 15:13:09 +03008762 *
8763 * This callback should be called when adding a new snapshot,
8764 * Driver should use the same id for multiple snapshots taken
8765 * on multiple regions at the same time/by the same trigger.
8766 *
Jacob Keller12102432020-03-26 11:37:15 -07008767 * The caller of this function must use devlink_region_snapshot_id_put
8768 * when finished creating regions using this id.
8769 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07008770 * Returns zero on success, or a negative error code on failure.
8771 *
Alex Veskerccadfa42018-07-12 15:13:09 +03008772 * @devlink: devlink
Jacob Keller7ef19d32020-03-26 11:37:14 -07008773 * @id: storage to return id
Alex Veskerccadfa42018-07-12 15:13:09 +03008774 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07008775int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Alex Veskerccadfa42018-07-12 15:13:09 +03008776{
Jacob Keller7ef19d32020-03-26 11:37:14 -07008777 int err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008778
8779 mutex_lock(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07008780 err = __devlink_region_snapshot_id_get(devlink, id);
Alex Veskerccadfa42018-07-12 15:13:09 +03008781 mutex_unlock(&devlink->lock);
8782
Jacob Keller7ef19d32020-03-26 11:37:14 -07008783 return err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008784}
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008785EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
Alex Veskerccadfa42018-07-12 15:13:09 +03008786
Alex Veskerd7e52722018-07-12 15:13:10 +03008787/**
Jacob Keller12102432020-03-26 11:37:15 -07008788 * devlink_region_snapshot_id_put - put snapshot ID reference
8789 *
8790 * This should be called by a driver after finishing creating snapshots
8791 * with an id. Doing so ensures that the ID can later be released in the
8792 * event that all snapshots using it have been destroyed.
8793 *
8794 * @devlink: devlink
8795 * @id: id to release reference on
8796 */
8797void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
8798{
8799 mutex_lock(&devlink->lock);
8800 __devlink_snapshot_id_decrement(devlink, id);
8801 mutex_unlock(&devlink->lock);
8802}
8803EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
8804
8805/**
Alex Veskerd7e52722018-07-12 15:13:10 +03008806 * devlink_region_snapshot_create - create a new snapshot
8807 * This will add a new snapshot of a region. The snapshot
8808 * will be stored on the region struct and can be accessed
Jacob Keller6d82f672020-03-26 11:37:10 -07008809 * from devlink. This is useful for future analyses of snapshots.
Alex Veskerd7e52722018-07-12 15:13:10 +03008810 * Multiple snapshots can be created on a region.
8811 * The @snapshot_id should be obtained using the getter function.
8812 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008813 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03008814 * @data: snapshot data
8815 * @snapshot_id: snapshot id to be created
Alex Veskerd7e52722018-07-12 15:13:10 +03008816 */
Jiri Pirko3a5e5232019-08-09 15:27:15 +02008817int devlink_region_snapshot_create(struct devlink_region *region,
Jacob Kellera0a09f62020-03-26 11:37:09 -07008818 u8 *data, u32 snapshot_id)
Alex Veskerd7e52722018-07-12 15:13:10 +03008819{
8820 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008821 int err;
8822
8823 mutex_lock(&devlink->lock);
Jacob Kellercf80fae2020-03-26 11:37:11 -07008824 err = __devlink_region_snapshot_create(region, data, snapshot_id);
Alex Veskerd7e52722018-07-12 15:13:10 +03008825 mutex_unlock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008826
Alex Veskerd7e52722018-07-12 15:13:10 +03008827 return err;
8828}
8829EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
8830
Ido Schimmel0f420b62019-08-17 16:28:17 +03008831#define DEVLINK_TRAP(_id, _type) \
8832 { \
8833 .type = DEVLINK_TRAP_TYPE_##_type, \
8834 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
8835 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
8836 }
8837
8838static const struct devlink_trap devlink_trap_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008839 DEVLINK_TRAP(SMAC_MC, DROP),
8840 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
8841 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
8842 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
8843 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
8844 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
8845 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
8846 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
8847 DEVLINK_TRAP(TAIL_DROP, DROP),
Amit Cohen6896cc42019-11-07 18:42:09 +02008848 DEVLINK_TRAP(NON_IP_PACKET, DROP),
8849 DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
8850 DEVLINK_TRAP(DIP_LB, DROP),
8851 DEVLINK_TRAP(SIP_MC, DROP),
8852 DEVLINK_TRAP(SIP_LB, DROP),
8853 DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
8854 DEVLINK_TRAP(IPV4_SIP_BC, DROP),
8855 DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
8856 DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
Amit Cohen3b063ae2019-11-07 18:42:14 +02008857 DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
8858 DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
8859 DEVLINK_TRAP(RPF, EXCEPTION),
8860 DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
8861 DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
8862 DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
Amit Cohen95f0ead2020-01-19 15:00:48 +02008863 DEVLINK_TRAP(NON_ROUTABLE, DROP),
Amit Cohen13c056e2020-01-19 15:00:54 +02008864 DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
Amit Cohenc3cae492020-01-19 15:00:58 +02008865 DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008866 DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
8867 DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
Ido Schimmel515eac62020-05-29 21:36:41 +03008868 DEVLINK_TRAP(STP, CONTROL),
8869 DEVLINK_TRAP(LACP, CONTROL),
8870 DEVLINK_TRAP(LLDP, CONTROL),
8871 DEVLINK_TRAP(IGMP_QUERY, CONTROL),
8872 DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
8873 DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
8874 DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
8875 DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
8876 DEVLINK_TRAP(MLD_QUERY, CONTROL),
8877 DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
8878 DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
8879 DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008880 DEVLINK_TRAP(IPV4_DHCP, CONTROL),
8881 DEVLINK_TRAP(IPV6_DHCP, CONTROL),
8882 DEVLINK_TRAP(ARP_REQUEST, CONTROL),
8883 DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
8884 DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
8885 DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
8886 DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
8887 DEVLINK_TRAP(IPV4_BFD, CONTROL),
8888 DEVLINK_TRAP(IPV6_BFD, CONTROL),
8889 DEVLINK_TRAP(IPV4_OSPF, CONTROL),
8890 DEVLINK_TRAP(IPV6_OSPF, CONTROL),
8891 DEVLINK_TRAP(IPV4_BGP, CONTROL),
8892 DEVLINK_TRAP(IPV6_BGP, CONTROL),
8893 DEVLINK_TRAP(IPV4_VRRP, CONTROL),
8894 DEVLINK_TRAP(IPV6_VRRP, CONTROL),
8895 DEVLINK_TRAP(IPV4_PIM, CONTROL),
8896 DEVLINK_TRAP(IPV6_PIM, CONTROL),
8897 DEVLINK_TRAP(UC_LB, CONTROL),
8898 DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
8899 DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
8900 DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
8901 DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
8902 DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
8903 DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
8904 DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
8905 DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
8906 DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
8907 DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
8908 DEVLINK_TRAP(PTP_EVENT, CONTROL),
8909 DEVLINK_TRAP(PTP_GENERAL, CONTROL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008910 DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
8911 DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
Amit Cohen08e335f2020-08-03 19:11:33 +03008912 DEVLINK_TRAP(EARLY_DROP, DROP),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008913};
8914
8915#define DEVLINK_TRAP_GROUP(_id) \
8916 { \
8917 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
8918 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
8919 }
8920
8921static const struct devlink_trap_group devlink_trap_group_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008922 DEVLINK_TRAP_GROUP(L2_DROPS),
8923 DEVLINK_TRAP_GROUP(L3_DROPS),
Ido Schimmel678eb192020-05-29 21:36:36 +03008924 DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
Ido Schimmel391203a2019-08-17 16:28:18 +03008925 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
Amit Cohen13c056e2020-01-19 15:00:54 +02008926 DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008927 DEVLINK_TRAP_GROUP(ACL_DROPS),
Ido Schimmel515eac62020-05-29 21:36:41 +03008928 DEVLINK_TRAP_GROUP(STP),
8929 DEVLINK_TRAP_GROUP(LACP),
8930 DEVLINK_TRAP_GROUP(LLDP),
8931 DEVLINK_TRAP_GROUP(MC_SNOOPING),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008932 DEVLINK_TRAP_GROUP(DHCP),
8933 DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
8934 DEVLINK_TRAP_GROUP(BFD),
8935 DEVLINK_TRAP_GROUP(OSPF),
8936 DEVLINK_TRAP_GROUP(BGP),
8937 DEVLINK_TRAP_GROUP(VRRP),
8938 DEVLINK_TRAP_GROUP(PIM),
8939 DEVLINK_TRAP_GROUP(UC_LB),
8940 DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
Ido Schimmelec4f5b32020-07-29 12:26:44 +03008941 DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008942 DEVLINK_TRAP_GROUP(IPV6),
8943 DEVLINK_TRAP_GROUP(PTP_EVENT),
8944 DEVLINK_TRAP_GROUP(PTP_GENERAL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008945 DEVLINK_TRAP_GROUP(ACL_SAMPLE),
8946 DEVLINK_TRAP_GROUP(ACL_TRAP),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008947};
8948
8949static int devlink_trap_generic_verify(const struct devlink_trap *trap)
8950{
8951 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
8952 return -EINVAL;
8953
8954 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
8955 return -EINVAL;
8956
8957 if (trap->type != devlink_trap_generic[trap->id].type)
8958 return -EINVAL;
8959
8960 return 0;
8961}
8962
8963static int devlink_trap_driver_verify(const struct devlink_trap *trap)
8964{
8965 int i;
8966
8967 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
8968 return -EINVAL;
8969
8970 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
8971 if (!strcmp(trap->name, devlink_trap_generic[i].name))
8972 return -EEXIST;
8973 }
8974
8975 return 0;
8976}
8977
8978static int devlink_trap_verify(const struct devlink_trap *trap)
8979{
Ido Schimmel107f1672020-03-22 20:48:30 +02008980 if (!trap || !trap->name)
Ido Schimmel0f420b62019-08-17 16:28:17 +03008981 return -EINVAL;
8982
8983 if (trap->generic)
8984 return devlink_trap_generic_verify(trap);
8985 else
8986 return devlink_trap_driver_verify(trap);
8987}
8988
8989static int
8990devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
8991{
8992 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
8993 return -EINVAL;
8994
8995 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
8996 return -EINVAL;
8997
8998 return 0;
8999}
9000
9001static int
9002devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
9003{
9004 int i;
9005
9006 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
9007 return -EINVAL;
9008
9009 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
9010 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
9011 return -EEXIST;
9012 }
9013
9014 return 0;
9015}
9016
9017static int devlink_trap_group_verify(const struct devlink_trap_group *group)
9018{
9019 if (group->generic)
9020 return devlink_trap_group_generic_verify(group);
9021 else
9022 return devlink_trap_group_driver_verify(group);
9023}
9024
9025static void
9026devlink_trap_group_notify(struct devlink *devlink,
9027 const struct devlink_trap_group_item *group_item,
9028 enum devlink_command cmd)
9029{
9030 struct sk_buff *msg;
9031 int err;
9032
9033 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
9034 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
9035
9036 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9037 if (!msg)
9038 return;
9039
9040 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
9041 0);
9042 if (err) {
9043 nlmsg_free(msg);
9044 return;
9045 }
9046
9047 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9048 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9049}
9050
Ido Schimmel0f420b62019-08-17 16:28:17 +03009051static int
9052devlink_trap_item_group_link(struct devlink *devlink,
9053 struct devlink_trap_item *trap_item)
9054{
Ido Schimmel107f1672020-03-22 20:48:30 +02009055 u16 group_id = trap_item->trap->init_group_id;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009056 struct devlink_trap_group_item *group_item;
9057
Ido Schimmel107f1672020-03-22 20:48:30 +02009058 group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
Ido Schimmela09b37f2020-03-22 20:48:29 +02009059 if (WARN_ON_ONCE(!group_item))
9060 return -EINVAL;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009061
9062 trap_item->group_item = group_item;
9063
9064 return 0;
9065}
9066
Ido Schimmel0f420b62019-08-17 16:28:17 +03009067static void devlink_trap_notify(struct devlink *devlink,
9068 const struct devlink_trap_item *trap_item,
9069 enum devlink_command cmd)
9070{
9071 struct sk_buff *msg;
9072 int err;
9073
9074 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
9075 cmd != DEVLINK_CMD_TRAP_DEL);
9076
9077 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9078 if (!msg)
9079 return;
9080
9081 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
9082 if (err) {
9083 nlmsg_free(msg);
9084 return;
9085 }
9086
9087 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9088 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9089}
9090
9091static int
9092devlink_trap_register(struct devlink *devlink,
9093 const struct devlink_trap *trap, void *priv)
9094{
9095 struct devlink_trap_item *trap_item;
9096 int err;
9097
9098 if (devlink_trap_item_lookup(devlink, trap->name))
9099 return -EEXIST;
9100
9101 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
9102 if (!trap_item)
9103 return -ENOMEM;
9104
9105 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9106 if (!trap_item->stats) {
9107 err = -ENOMEM;
9108 goto err_stats_alloc;
9109 }
9110
9111 trap_item->trap = trap;
9112 trap_item->action = trap->init_action;
9113 trap_item->priv = priv;
9114
9115 err = devlink_trap_item_group_link(devlink, trap_item);
9116 if (err)
9117 goto err_group_link;
9118
9119 err = devlink->ops->trap_init(devlink, trap, trap_item);
9120 if (err)
9121 goto err_trap_init;
9122
9123 list_add_tail(&trap_item->list, &devlink->trap_list);
9124 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
9125
9126 return 0;
9127
9128err_trap_init:
Ido Schimmel0f420b62019-08-17 16:28:17 +03009129err_group_link:
9130 free_percpu(trap_item->stats);
9131err_stats_alloc:
9132 kfree(trap_item);
9133 return err;
9134}
9135
9136static void devlink_trap_unregister(struct devlink *devlink,
9137 const struct devlink_trap *trap)
9138{
9139 struct devlink_trap_item *trap_item;
9140
9141 trap_item = devlink_trap_item_lookup(devlink, trap->name);
9142 if (WARN_ON_ONCE(!trap_item))
9143 return;
9144
9145 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
9146 list_del(&trap_item->list);
9147 if (devlink->ops->trap_fini)
9148 devlink->ops->trap_fini(devlink, trap, trap_item);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009149 free_percpu(trap_item->stats);
9150 kfree(trap_item);
9151}
9152
9153static void devlink_trap_disable(struct devlink *devlink,
9154 const struct devlink_trap *trap)
9155{
9156 struct devlink_trap_item *trap_item;
9157
9158 trap_item = devlink_trap_item_lookup(devlink, trap->name);
9159 if (WARN_ON_ONCE(!trap_item))
9160 return;
9161
Ido Schimmelc88e11e2020-08-03 19:11:34 +03009162 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
9163 NULL);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009164 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
9165}
9166
9167/**
9168 * devlink_traps_register - Register packet traps with devlink.
9169 * @devlink: devlink.
9170 * @traps: Packet traps.
9171 * @traps_count: Count of provided packet traps.
9172 * @priv: Driver private information.
9173 *
9174 * Return: Non-zero value on failure.
9175 */
9176int devlink_traps_register(struct devlink *devlink,
9177 const struct devlink_trap *traps,
9178 size_t traps_count, void *priv)
9179{
9180 int i, err;
9181
9182 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
9183 return -EINVAL;
9184
9185 mutex_lock(&devlink->lock);
9186 for (i = 0; i < traps_count; i++) {
9187 const struct devlink_trap *trap = &traps[i];
9188
9189 err = devlink_trap_verify(trap);
9190 if (err)
9191 goto err_trap_verify;
9192
9193 err = devlink_trap_register(devlink, trap, priv);
9194 if (err)
9195 goto err_trap_register;
9196 }
9197 mutex_unlock(&devlink->lock);
9198
9199 return 0;
9200
9201err_trap_register:
9202err_trap_verify:
9203 for (i--; i >= 0; i--)
9204 devlink_trap_unregister(devlink, &traps[i]);
9205 mutex_unlock(&devlink->lock);
9206 return err;
9207}
9208EXPORT_SYMBOL_GPL(devlink_traps_register);
9209
9210/**
9211 * devlink_traps_unregister - Unregister packet traps from devlink.
9212 * @devlink: devlink.
9213 * @traps: Packet traps.
9214 * @traps_count: Count of provided packet traps.
9215 */
9216void devlink_traps_unregister(struct devlink *devlink,
9217 const struct devlink_trap *traps,
9218 size_t traps_count)
9219{
9220 int i;
9221
9222 mutex_lock(&devlink->lock);
9223 /* Make sure we do not have any packets in-flight while unregistering
9224 * traps by disabling all of them and waiting for a grace period.
9225 */
9226 for (i = traps_count - 1; i >= 0; i--)
9227 devlink_trap_disable(devlink, &traps[i]);
9228 synchronize_rcu();
9229 for (i = traps_count - 1; i >= 0; i--)
9230 devlink_trap_unregister(devlink, &traps[i]);
9231 mutex_unlock(&devlink->lock);
9232}
9233EXPORT_SYMBOL_GPL(devlink_traps_unregister);
9234
9235static void
9236devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
9237 size_t skb_len)
9238{
9239 struct devlink_stats *stats;
9240
9241 stats = this_cpu_ptr(trap_stats);
9242 u64_stats_update_begin(&stats->syncp);
9243 stats->rx_bytes += skb_len;
9244 stats->rx_packets++;
9245 u64_stats_update_end(&stats->syncp);
9246}
9247
9248static void
9249devlink_trap_report_metadata_fill(struct net_dm_hw_metadata *hw_metadata,
9250 const struct devlink_trap_item *trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009251 struct devlink_port *in_devlink_port,
9252 const struct flow_action_cookie *fa_cookie)
Ido Schimmel0f420b62019-08-17 16:28:17 +03009253{
9254 struct devlink_trap_group_item *group_item = trap_item->group_item;
9255
9256 hw_metadata->trap_group_name = group_item->group->name;
9257 hw_metadata->trap_name = trap_item->trap->name;
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009258 hw_metadata->fa_cookie = fa_cookie;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009259
9260 spin_lock(&in_devlink_port->type_lock);
9261 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
9262 hw_metadata->input_dev = in_devlink_port->type_dev;
9263 spin_unlock(&in_devlink_port->type_lock);
9264}
9265
9266/**
9267 * devlink_trap_report - Report trapped packet to drop monitor.
9268 * @devlink: devlink.
9269 * @skb: Trapped packet.
9270 * @trap_ctx: Trap context.
9271 * @in_devlink_port: Input devlink port.
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009272 * @fa_cookie: Flow action cookie. Could be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03009273 */
9274void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009275 void *trap_ctx, struct devlink_port *in_devlink_port,
9276 const struct flow_action_cookie *fa_cookie)
9277
Ido Schimmel0f420b62019-08-17 16:28:17 +03009278{
9279 struct devlink_trap_item *trap_item = trap_ctx;
9280 struct net_dm_hw_metadata hw_metadata = {};
9281
9282 devlink_trap_stats_update(trap_item->stats, skb->len);
9283 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
9284
Ido Schimmel30a4e9a2020-05-29 21:36:40 +03009285 /* Control packets were not dropped by the device or encountered an
9286 * exception during forwarding and therefore should not be reported to
9287 * the kernel's drop monitor.
9288 */
9289 if (trap_item->trap->type == DEVLINK_TRAP_TYPE_CONTROL)
9290 return;
9291
Ido Schimmel0f420b62019-08-17 16:28:17 +03009292 devlink_trap_report_metadata_fill(&hw_metadata, trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009293 in_devlink_port, fa_cookie);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009294 net_dm_hw_report(skb, &hw_metadata);
9295}
9296EXPORT_SYMBOL_GPL(devlink_trap_report);
9297
9298/**
9299 * devlink_trap_ctx_priv - Trap context to driver private information.
9300 * @trap_ctx: Trap context.
9301 *
9302 * Return: Driver private information passed during registration.
9303 */
9304void *devlink_trap_ctx_priv(void *trap_ctx)
9305{
9306 struct devlink_trap_item *trap_item = trap_ctx;
9307
9308 return trap_item->priv;
9309}
9310EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
9311
Ido Schimmel95ad9552020-03-22 20:48:26 +02009312static int
Ido Schimmelf9f54392020-03-30 22:38:21 +03009313devlink_trap_group_item_policer_link(struct devlink *devlink,
9314 struct devlink_trap_group_item *group_item)
9315{
9316 u32 policer_id = group_item->group->init_policer_id;
9317 struct devlink_trap_policer_item *policer_item;
9318
9319 if (policer_id == 0)
9320 return 0;
9321
9322 policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
9323 if (WARN_ON_ONCE(!policer_item))
9324 return -EINVAL;
9325
9326 group_item->policer_item = policer_item;
9327
9328 return 0;
9329}
9330
9331static int
Ido Schimmel95ad9552020-03-22 20:48:26 +02009332devlink_trap_group_register(struct devlink *devlink,
9333 const struct devlink_trap_group *group)
9334{
9335 struct devlink_trap_group_item *group_item;
9336 int err;
9337
9338 if (devlink_trap_group_item_lookup(devlink, group->name))
9339 return -EEXIST;
9340
9341 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
9342 if (!group_item)
9343 return -ENOMEM;
9344
9345 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9346 if (!group_item->stats) {
9347 err = -ENOMEM;
9348 goto err_stats_alloc;
9349 }
9350
9351 group_item->group = group;
Ido Schimmel95ad9552020-03-22 20:48:26 +02009352
Ido Schimmelf9f54392020-03-30 22:38:21 +03009353 err = devlink_trap_group_item_policer_link(devlink, group_item);
9354 if (err)
9355 goto err_policer_link;
9356
Ido Schimmel95ad9552020-03-22 20:48:26 +02009357 if (devlink->ops->trap_group_init) {
9358 err = devlink->ops->trap_group_init(devlink, group);
9359 if (err)
9360 goto err_group_init;
9361 }
9362
9363 list_add_tail(&group_item->list, &devlink->trap_group_list);
9364 devlink_trap_group_notify(devlink, group_item,
9365 DEVLINK_CMD_TRAP_GROUP_NEW);
9366
9367 return 0;
9368
9369err_group_init:
Ido Schimmelf9f54392020-03-30 22:38:21 +03009370err_policer_link:
Ido Schimmel95ad9552020-03-22 20:48:26 +02009371 free_percpu(group_item->stats);
9372err_stats_alloc:
9373 kfree(group_item);
9374 return err;
9375}
9376
9377static void
9378devlink_trap_group_unregister(struct devlink *devlink,
9379 const struct devlink_trap_group *group)
9380{
9381 struct devlink_trap_group_item *group_item;
9382
9383 group_item = devlink_trap_group_item_lookup(devlink, group->name);
9384 if (WARN_ON_ONCE(!group_item))
9385 return;
9386
9387 devlink_trap_group_notify(devlink, group_item,
9388 DEVLINK_CMD_TRAP_GROUP_DEL);
9389 list_del(&group_item->list);
9390 free_percpu(group_item->stats);
9391 kfree(group_item);
9392}
9393
9394/**
9395 * devlink_trap_groups_register - Register packet trap groups with devlink.
9396 * @devlink: devlink.
9397 * @groups: Packet trap groups.
9398 * @groups_count: Count of provided packet trap groups.
9399 *
9400 * Return: Non-zero value on failure.
9401 */
9402int devlink_trap_groups_register(struct devlink *devlink,
9403 const struct devlink_trap_group *groups,
9404 size_t groups_count)
9405{
9406 int i, err;
9407
9408 mutex_lock(&devlink->lock);
9409 for (i = 0; i < groups_count; i++) {
9410 const struct devlink_trap_group *group = &groups[i];
9411
9412 err = devlink_trap_group_verify(group);
9413 if (err)
9414 goto err_trap_group_verify;
9415
9416 err = devlink_trap_group_register(devlink, group);
9417 if (err)
9418 goto err_trap_group_register;
9419 }
9420 mutex_unlock(&devlink->lock);
9421
9422 return 0;
9423
9424err_trap_group_register:
9425err_trap_group_verify:
9426 for (i--; i >= 0; i--)
9427 devlink_trap_group_unregister(devlink, &groups[i]);
9428 mutex_unlock(&devlink->lock);
9429 return err;
9430}
9431EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
9432
9433/**
9434 * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
9435 * @devlink: devlink.
9436 * @groups: Packet trap groups.
9437 * @groups_count: Count of provided packet trap groups.
9438 */
9439void devlink_trap_groups_unregister(struct devlink *devlink,
9440 const struct devlink_trap_group *groups,
9441 size_t groups_count)
9442{
9443 int i;
9444
9445 mutex_lock(&devlink->lock);
9446 for (i = groups_count - 1; i >= 0; i--)
9447 devlink_trap_group_unregister(devlink, &groups[i]);
9448 mutex_unlock(&devlink->lock);
9449}
9450EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
9451
Ido Schimmel1e8c6612020-03-30 22:38:18 +03009452static void
9453devlink_trap_policer_notify(struct devlink *devlink,
9454 const struct devlink_trap_policer_item *policer_item,
9455 enum devlink_command cmd)
9456{
9457 struct sk_buff *msg;
9458 int err;
9459
9460 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
9461 cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
9462
9463 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9464 if (!msg)
9465 return;
9466
9467 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
9468 0, 0);
9469 if (err) {
9470 nlmsg_free(msg);
9471 return;
9472 }
9473
9474 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9475 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9476}
9477
9478static int
9479devlink_trap_policer_register(struct devlink *devlink,
9480 const struct devlink_trap_policer *policer)
9481{
9482 struct devlink_trap_policer_item *policer_item;
9483 int err;
9484
9485 if (devlink_trap_policer_item_lookup(devlink, policer->id))
9486 return -EEXIST;
9487
9488 policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
9489 if (!policer_item)
9490 return -ENOMEM;
9491
9492 policer_item->policer = policer;
9493 policer_item->rate = policer->init_rate;
9494 policer_item->burst = policer->init_burst;
9495
9496 if (devlink->ops->trap_policer_init) {
9497 err = devlink->ops->trap_policer_init(devlink, policer);
9498 if (err)
9499 goto err_policer_init;
9500 }
9501
9502 list_add_tail(&policer_item->list, &devlink->trap_policer_list);
9503 devlink_trap_policer_notify(devlink, policer_item,
9504 DEVLINK_CMD_TRAP_POLICER_NEW);
9505
9506 return 0;
9507
9508err_policer_init:
9509 kfree(policer_item);
9510 return err;
9511}
9512
9513static void
9514devlink_trap_policer_unregister(struct devlink *devlink,
9515 const struct devlink_trap_policer *policer)
9516{
9517 struct devlink_trap_policer_item *policer_item;
9518
9519 policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
9520 if (WARN_ON_ONCE(!policer_item))
9521 return;
9522
9523 devlink_trap_policer_notify(devlink, policer_item,
9524 DEVLINK_CMD_TRAP_POLICER_DEL);
9525 list_del(&policer_item->list);
9526 if (devlink->ops->trap_policer_fini)
9527 devlink->ops->trap_policer_fini(devlink, policer);
9528 kfree(policer_item);
9529}
9530
9531/**
9532 * devlink_trap_policers_register - Register packet trap policers with devlink.
9533 * @devlink: devlink.
9534 * @policers: Packet trap policers.
9535 * @policers_count: Count of provided packet trap policers.
9536 *
9537 * Return: Non-zero value on failure.
9538 */
9539int
9540devlink_trap_policers_register(struct devlink *devlink,
9541 const struct devlink_trap_policer *policers,
9542 size_t policers_count)
9543{
9544 int i, err;
9545
9546 mutex_lock(&devlink->lock);
9547 for (i = 0; i < policers_count; i++) {
9548 const struct devlink_trap_policer *policer = &policers[i];
9549
9550 if (WARN_ON(policer->id == 0 ||
9551 policer->max_rate < policer->min_rate ||
9552 policer->max_burst < policer->min_burst)) {
9553 err = -EINVAL;
9554 goto err_trap_policer_verify;
9555 }
9556
9557 err = devlink_trap_policer_register(devlink, policer);
9558 if (err)
9559 goto err_trap_policer_register;
9560 }
9561 mutex_unlock(&devlink->lock);
9562
9563 return 0;
9564
9565err_trap_policer_register:
9566err_trap_policer_verify:
9567 for (i--; i >= 0; i--)
9568 devlink_trap_policer_unregister(devlink, &policers[i]);
9569 mutex_unlock(&devlink->lock);
9570 return err;
9571}
9572EXPORT_SYMBOL_GPL(devlink_trap_policers_register);
9573
9574/**
9575 * devlink_trap_policers_unregister - Unregister packet trap policers from devlink.
9576 * @devlink: devlink.
9577 * @policers: Packet trap policers.
9578 * @policers_count: Count of provided packet trap policers.
9579 */
9580void
9581devlink_trap_policers_unregister(struct devlink *devlink,
9582 const struct devlink_trap_policer *policers,
9583 size_t policers_count)
9584{
9585 int i;
9586
9587 mutex_lock(&devlink->lock);
9588 for (i = policers_count - 1; i >= 0; i--)
9589 devlink_trap_policer_unregister(devlink, &policers[i]);
9590 mutex_unlock(&devlink->lock);
9591}
9592EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister);
9593
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009594static void __devlink_compat_running_version(struct devlink *devlink,
9595 char *buf, size_t len)
9596{
9597 const struct nlattr *nlattr;
9598 struct devlink_info_req req;
9599 struct sk_buff *msg;
9600 int rem, err;
9601
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009602 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9603 if (!msg)
9604 return;
9605
9606 req.msg = msg;
9607 err = devlink->ops->info_get(devlink, &req, NULL);
9608 if (err)
9609 goto free_msg;
9610
9611 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
9612 const struct nlattr *kv;
9613 int rem_kv;
9614
9615 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
9616 continue;
9617
9618 nla_for_each_nested(kv, nlattr, rem_kv) {
9619 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
9620 continue;
9621
9622 strlcat(buf, nla_data(kv), len);
9623 strlcat(buf, " ", len);
9624 }
9625 }
9626free_msg:
9627 nlmsg_free(msg);
9628}
9629
9630void devlink_compat_running_version(struct net_device *dev,
9631 char *buf, size_t len)
9632{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009633 struct devlink *devlink;
9634
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009635 dev_hold(dev);
9636 rtnl_unlock();
9637
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009638 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08009639 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009640 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009641
9642 mutex_lock(&devlink->lock);
9643 __devlink_compat_running_version(devlink, buf, len);
9644 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009645
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009646out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009647 rtnl_lock();
9648 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009649}
9650
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009651int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
9652{
Jacob Kellerbc75c052020-09-25 13:46:06 -07009653 struct devlink_flash_update_params params = {};
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009654 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009655 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009656
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009657 dev_hold(dev);
9658 rtnl_unlock();
9659
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009660 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009661 if (!devlink || !devlink->ops->flash_update) {
9662 ret = -EOPNOTSUPP;
9663 goto out;
9664 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009665
Jacob Kellerbc75c052020-09-25 13:46:06 -07009666 params.file_name = file_name;
9667
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009668 mutex_lock(&devlink->lock);
Jacob Kellerbc75c052020-09-25 13:46:06 -07009669 ret = devlink->ops->flash_update(devlink, &params, NULL);
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009670 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009671
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009672out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009673 rtnl_lock();
9674 dev_put(dev);
9675
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009676 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009677}
9678
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01009679int devlink_compat_phys_port_name_get(struct net_device *dev,
9680 char *name, size_t len)
9681{
9682 struct devlink_port *devlink_port;
9683
9684 /* RTNL mutex is held here which ensures that devlink_port
9685 * instance cannot disappear in the middle. No need to take
9686 * any devlink lock as only permanent values are accessed.
9687 */
9688 ASSERT_RTNL();
9689
9690 devlink_port = netdev_to_devlink_port(dev);
9691 if (!devlink_port)
9692 return -EOPNOTSUPP;
9693
9694 return __devlink_port_phys_port_name_get(devlink_port, name, len);
9695}
9696
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009697int devlink_compat_switch_id_get(struct net_device *dev,
9698 struct netdev_phys_item_id *ppid)
9699{
9700 struct devlink_port *devlink_port;
9701
Vlad Buslov043b8412019-08-12 20:02:02 +03009702 /* Caller must hold RTNL mutex or reference to dev, which ensures that
9703 * devlink_port instance cannot disappear in the middle. No need to take
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009704 * any devlink lock as only permanent values are accessed.
9705 */
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009706 devlink_port = netdev_to_devlink_port(dev);
Danielle Ratson46737a12020-07-09 16:18:15 +03009707 if (!devlink_port || !devlink_port->switch_port)
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009708 return -EOPNOTSUPP;
9709
9710 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
9711
9712 return 0;
9713}
9714
Jiri Pirko070c63f2019-10-03 11:49:39 +02009715static void __net_exit devlink_pernet_pre_exit(struct net *net)
9716{
9717 struct devlink *devlink;
9718 int err;
9719
9720 /* In case network namespace is getting destroyed, reload
9721 * all devlink instances from this namespace into init_net.
9722 */
9723 mutex_lock(&devlink_mutex);
9724 list_for_each_entry(devlink, &devlink_list, list) {
9725 if (net_eq(devlink_net(devlink), net)) {
9726 if (WARN_ON(!devlink_reload_supported(devlink)))
9727 continue;
9728 err = devlink_reload(devlink, &init_net, NULL);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01009729 if (err && err != -EOPNOTSUPP)
Jiri Pirko070c63f2019-10-03 11:49:39 +02009730 pr_warn("Failed to reload devlink instance into init_net\n");
9731 }
9732 }
9733 mutex_unlock(&devlink_mutex);
9734}
9735
9736static struct pernet_operations devlink_pernet_ops __net_initdata = {
9737 .pre_exit = devlink_pernet_pre_exit,
9738};
9739
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009740static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009741{
Jiri Pirko070c63f2019-10-03 11:49:39 +02009742 int err;
9743
9744 err = genl_register_family(&devlink_nl_family);
9745 if (err)
9746 goto out;
9747 err = register_pernet_subsys(&devlink_pernet_ops);
9748
9749out:
9750 WARN_ON(err);
9751 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009752}
9753
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009754subsys_initcall(devlink_init);