blob: b4a231ca7135226cc51fabb960b90b3f3015fd00 [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
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300389#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
390#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
391#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(2)
392#define DEVLINK_NL_FLAG_NEED_SB BIT(3)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100393
394/* The per devlink instance lock is taken by default in the pre-doit
395 * operation, yet several commands do not require this. The global
396 * devlink lock is taken and protects from disruption by user-calls.
397 */
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300398#define DEVLINK_NL_FLAG_NO_LOCK BIT(4)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100399
400static int devlink_nl_pre_doit(const struct genl_ops *ops,
401 struct sk_buff *skb, struct genl_info *info)
402{
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300403 struct devlink_port *devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100404 struct devlink *devlink;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100405 int err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100406
407 mutex_lock(&devlink_mutex);
408 devlink = devlink_get_from_info(info);
409 if (IS_ERR(devlink)) {
410 mutex_unlock(&devlink_mutex);
411 return PTR_ERR(devlink);
412 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100413 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
414 mutex_lock(&devlink->lock);
Jiri Pirko1fc22572016-04-08 19:12:48 +0200415 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
416 info->user_ptr[0] = devlink;
417 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100418 devlink_port = devlink_port_get_from_info(devlink, info);
419 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100420 err = PTR_ERR(devlink_port);
421 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100422 }
Jiri Pirko1fc22572016-04-08 19:12:48 +0200423 info->user_ptr[0] = devlink_port;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +0300424 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
425 info->user_ptr[0] = devlink;
426 devlink_port = devlink_port_get_from_info(devlink, info);
427 if (!IS_ERR(devlink_port))
428 info->user_ptr[1] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100429 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200430 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
431 struct devlink_sb *devlink_sb;
432
433 devlink_sb = devlink_sb_get_from_info(devlink, info);
434 if (IS_ERR(devlink_sb)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100435 err = PTR_ERR(devlink_sb);
436 goto unlock;
Jiri Pirkobf797472016-04-14 18:19:13 +0200437 }
438 info->user_ptr[1] = devlink_sb;
439 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100440 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100441
442unlock:
443 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
444 mutex_unlock(&devlink->lock);
445 mutex_unlock(&devlink_mutex);
446 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100447}
448
449static void devlink_nl_post_doit(const struct genl_ops *ops,
450 struct sk_buff *skb, struct genl_info *info)
451{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100452 struct devlink *devlink;
453
Jiri Pirko070c63f2019-10-03 11:49:39 +0200454 /* When devlink changes netns, it would not be found
455 * by devlink_get_from_info(). So try if it is stored first.
456 */
457 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
458 devlink = info->user_ptr[0];
459 } else {
460 devlink = devlink_get_from_info(info);
461 WARN_ON(IS_ERR(devlink));
462 }
463 if (!IS_ERR(devlink) && ~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100464 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100465 mutex_unlock(&devlink_mutex);
466}
467
Johannes Berg489111e2016-10-24 14:40:03 +0200468static struct genl_family devlink_nl_family;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100469
470enum devlink_multicast_groups {
471 DEVLINK_MCGRP_CONFIG,
472};
473
474static const struct genl_multicast_group devlink_nl_mcgrps[] = {
475 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
476};
477
478static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
479{
480 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
481 return -EMSGSIZE;
482 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
483 return -EMSGSIZE;
484 return 0;
485}
486
487static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
488 enum devlink_command cmd, u32 portid,
489 u32 seq, int flags)
490{
491 void *hdr;
492
493 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
494 if (!hdr)
495 return -EMSGSIZE;
496
497 if (devlink_nl_put_handle(msg, devlink))
498 goto nla_put_failure;
Jiri Pirko2670ac22019-09-12 10:49:46 +0200499 if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed))
500 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100501
502 genlmsg_end(msg, hdr);
503 return 0;
504
505nla_put_failure:
506 genlmsg_cancel(msg, hdr);
507 return -EMSGSIZE;
508}
509
510static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
511{
512 struct sk_buff *msg;
513 int err;
514
515 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
516
517 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
518 if (!msg)
519 return;
520
521 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
522 if (err) {
523 nlmsg_free(msg);
524 return;
525 }
526
527 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
528 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
529}
530
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200531static int devlink_nl_port_attrs_put(struct sk_buff *msg,
532 struct devlink_port *devlink_port)
533{
534 struct devlink_port_attrs *attrs = &devlink_port->attrs;
535
Danielle Ratson10a429b2020-07-09 16:18:14 +0300536 if (!devlink_port->attrs_set)
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200537 return 0;
Danielle Ratsona21cf0a2020-07-09 16:18:18 +0300538 if (attrs->lanes) {
539 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
540 return -EMSGSIZE;
541 }
Danielle Ratsona0f49b52020-07-09 16:18:20 +0300542 if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
543 return -EMSGSIZE;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200544 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
545 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500546 switch (devlink_port->attrs.flavour) {
547 case DEVLINK_PORT_FLAVOUR_PCI_PF:
Parav Pandit98fd2d62019-07-08 23:17:37 -0500548 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
549 attrs->pci_pf.pf))
550 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500551 break;
552 case DEVLINK_PORT_FLAVOUR_PCI_VF:
Parav Pandite41b6bf2019-07-08 23:17:38 -0500553 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
554 attrs->pci_vf.pf) ||
555 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER,
556 attrs->pci_vf.vf))
557 return -EMSGSIZE;
Parav Pandit58b6be42019-08-30 05:39:45 -0500558 break;
559 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
560 case DEVLINK_PORT_FLAVOUR_CPU:
561 case DEVLINK_PORT_FLAVOUR_DSA:
Parav Panditacf1ee42020-03-03 08:12:42 -0600562 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Parav Pandit58b6be42019-08-30 05:39:45 -0500563 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
564 attrs->phys.port_number))
565 return -EMSGSIZE;
566 if (!attrs->split)
567 return 0;
568 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
569 attrs->phys.port_number))
570 return -EMSGSIZE;
571 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
572 attrs->phys.split_subport_number))
573 return -EMSGSIZE;
574 break;
575 default:
576 break;
Parav Pandit98fd2d62019-07-08 23:17:37 -0500577 }
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200578 return 0;
579}
580
Parav Pandit2a916ec2020-06-19 03:32:48 +0000581static int
582devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
583 struct netlink_ext_ack *extack)
584{
585 struct devlink *devlink = port->devlink;
586 const struct devlink_ops *ops;
587 struct nlattr *function_attr;
588 bool empty_nest = true;
589 int err = 0;
590
591 function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
592 if (!function_attr)
593 return -EMSGSIZE;
594
595 ops = devlink->ops;
596 if (ops->port_function_hw_addr_get) {
Stephen Rothwell29cb9862020-06-23 13:43:06 +1000597 int hw_addr_len;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000598 u8 hw_addr[MAX_ADDR_LEN];
599
600 err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack);
601 if (err == -EOPNOTSUPP) {
602 /* Port function attributes are optional for a port. If port doesn't
603 * support function attribute, returning -EOPNOTSUPP is not an error.
604 */
605 err = 0;
606 goto out;
607 } else if (err) {
608 goto out;
609 }
610 err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr);
611 if (err)
612 goto out;
613 empty_nest = false;
614 }
615
616out:
617 if (err || empty_nest)
618 nla_nest_cancel(msg, function_attr);
619 else
620 nla_nest_end(msg, function_attr);
621 return err;
622}
623
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100624static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
625 struct devlink_port *devlink_port,
626 enum devlink_command cmd, u32 portid,
Parav Pandita829eb02020-06-19 03:32:47 +0000627 u32 seq, int flags,
628 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100629{
630 void *hdr;
631
632 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
633 if (!hdr)
634 return -EMSGSIZE;
635
636 if (devlink_nl_put_handle(msg, devlink))
637 goto nla_put_failure;
638 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
639 goto nla_put_failure;
Jiri Pirkob8f97552019-03-24 11:14:37 +0100640
Ido Schimmel0f420b62019-08-17 16:28:17 +0300641 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100642 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100643 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100644 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
645 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
646 devlink_port->desired_type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100647 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100648 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
649 struct net_device *netdev = devlink_port->type_dev;
650
651 if (netdev &&
652 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
653 netdev->ifindex) ||
654 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
655 netdev->name)))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100656 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100657 }
658 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
659 struct ib_device *ibdev = devlink_port->type_dev;
660
661 if (ibdev &&
662 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
663 ibdev->name))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100664 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100665 }
Ido Schimmel0f420b62019-08-17 16:28:17 +0300666 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200667 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100668 goto nla_put_failure;
Parav Pandit2a916ec2020-06-19 03:32:48 +0000669 if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
670 goto nla_put_failure;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100671
672 genlmsg_end(msg, hdr);
673 return 0;
674
Jiri Pirkob8f97552019-03-24 11:14:37 +0100675nla_put_failure_type_locked:
Ido Schimmel0f420b62019-08-17 16:28:17 +0300676 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100677nla_put_failure:
678 genlmsg_cancel(msg, hdr);
679 return -EMSGSIZE;
680}
681
682static void devlink_port_notify(struct devlink_port *devlink_port,
683 enum devlink_command cmd)
684{
685 struct devlink *devlink = devlink_port->devlink;
686 struct sk_buff *msg;
687 int err;
688
689 if (!devlink_port->registered)
690 return;
691
692 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
693
694 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
695 if (!msg)
696 return;
697
Parav Pandita829eb02020-06-19 03:32:47 +0000698 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0,
699 NULL);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100700 if (err) {
701 nlmsg_free(msg);
702 return;
703 }
704
705 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
706 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
707}
708
709static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
710{
711 struct devlink *devlink = info->user_ptr[0];
712 struct sk_buff *msg;
713 int err;
714
715 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
716 if (!msg)
717 return -ENOMEM;
718
719 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
720 info->snd_portid, info->snd_seq, 0);
721 if (err) {
722 nlmsg_free(msg);
723 return err;
724 }
725
726 return genlmsg_reply(msg, info);
727}
728
729static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
730 struct netlink_callback *cb)
731{
732 struct devlink *devlink;
733 int start = cb->args[0];
734 int idx = 0;
735 int err;
736
737 mutex_lock(&devlink_mutex);
738 list_for_each_entry(devlink, &devlink_list, list) {
739 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
740 continue;
741 if (idx < start) {
742 idx++;
743 continue;
744 }
745 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
746 NETLINK_CB(cb->skb).portid,
747 cb->nlh->nlmsg_seq, NLM_F_MULTI);
748 if (err)
749 goto out;
750 idx++;
751 }
752out:
753 mutex_unlock(&devlink_mutex);
754
755 cb->args[0] = idx;
756 return msg->len;
757}
758
759static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
760 struct genl_info *info)
761{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200762 struct devlink_port *devlink_port = info->user_ptr[0];
763 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100764 struct sk_buff *msg;
765 int err;
766
767 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
768 if (!msg)
769 return -ENOMEM;
770
771 err = devlink_nl_port_fill(msg, devlink, devlink_port,
772 DEVLINK_CMD_PORT_NEW,
Parav Pandita829eb02020-06-19 03:32:47 +0000773 info->snd_portid, info->snd_seq, 0,
774 info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100775 if (err) {
776 nlmsg_free(msg);
777 return err;
778 }
779
780 return genlmsg_reply(msg, info);
781}
782
783static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
784 struct netlink_callback *cb)
785{
786 struct devlink *devlink;
787 struct devlink_port *devlink_port;
788 int start = cb->args[0];
789 int idx = 0;
790 int err;
791
792 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100793 list_for_each_entry(devlink, &devlink_list, list) {
794 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
795 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100796 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100797 list_for_each_entry(devlink_port, &devlink->port_list, list) {
798 if (idx < start) {
799 idx++;
800 continue;
801 }
802 err = devlink_nl_port_fill(msg, devlink, devlink_port,
803 DEVLINK_CMD_NEW,
804 NETLINK_CB(cb->skb).portid,
805 cb->nlh->nlmsg_seq,
Parav Pandita829eb02020-06-19 03:32:47 +0000806 NLM_F_MULTI,
807 cb->extack);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100808 if (err) {
809 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100810 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100811 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100812 idx++;
813 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100814 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100815 }
816out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100817 mutex_unlock(&devlink_mutex);
818
819 cb->args[0] = idx;
820 return msg->len;
821}
822
823static int devlink_port_type_set(struct devlink *devlink,
824 struct devlink_port *devlink_port,
825 enum devlink_port_type port_type)
826
827{
828 int err;
829
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800830 if (devlink->ops->port_type_set) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100831 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
832 return -EINVAL;
Elad Raz6edf1012016-10-23 17:43:05 +0200833 if (port_type == devlink_port->type)
834 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100835 err = devlink->ops->port_type_set(devlink_port, port_type);
836 if (err)
837 return err;
838 devlink_port->desired_type = port_type;
839 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
840 return 0;
841 }
842 return -EOPNOTSUPP;
843}
844
Parav Pandita1e8ae92020-06-19 03:32:49 +0000845static int
846devlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port,
847 const struct nlattr *attr, struct netlink_ext_ack *extack)
848{
849 const struct devlink_ops *ops;
850 const u8 *hw_addr;
851 int hw_addr_len;
852 int err;
853
854 hw_addr = nla_data(attr);
855 hw_addr_len = nla_len(attr);
856 if (hw_addr_len > MAX_ADDR_LEN) {
857 NL_SET_ERR_MSG_MOD(extack, "Port function hardware address too long");
858 return -EINVAL;
859 }
860 if (port->type == DEVLINK_PORT_TYPE_ETH) {
861 if (hw_addr_len != ETH_ALEN) {
862 NL_SET_ERR_MSG_MOD(extack, "Address must be 6 bytes for Ethernet device");
863 return -EINVAL;
864 }
865 if (!is_unicast_ether_addr(hw_addr)) {
866 NL_SET_ERR_MSG_MOD(extack, "Non-unicast hardware address unsupported");
867 return -EINVAL;
868 }
869 }
870
871 ops = devlink->ops;
872 if (!ops->port_function_hw_addr_set) {
873 NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes");
874 return -EOPNOTSUPP;
875 }
876
877 err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack);
878 if (err)
879 return err;
880
881 devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
882 return 0;
883}
884
885static int
886devlink_port_function_set(struct devlink *devlink, struct devlink_port *port,
887 const struct nlattr *attr, struct netlink_ext_ack *extack)
888{
889 struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];
890 int err;
891
892 err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr,
893 devlink_function_nl_policy, extack);
894 if (err < 0) {
895 NL_SET_ERR_MSG_MOD(extack, "Fail to parse port function attributes");
896 return err;
897 }
898
899 attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
900 if (attr)
901 err = devlink_port_function_hw_addr_set(devlink, port, attr, extack);
902
903 return err;
904}
905
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100906static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
907 struct genl_info *info)
908{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200909 struct devlink_port *devlink_port = info->user_ptr[0];
910 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100911 int err;
912
913 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
914 enum devlink_port_type port_type;
915
916 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
917 err = devlink_port_type_set(devlink, devlink_port, port_type);
918 if (err)
919 return err;
920 }
Parav Pandita1e8ae92020-06-19 03:32:49 +0000921
922 if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
923 struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
924 struct netlink_ext_ack *extack = info->extack;
925
926 err = devlink_port_function_set(devlink, devlink_port, attr, extack);
927 if (err)
928 return err;
929 }
930
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100931 return 0;
932}
933
David Ahernac0fc8a2018-06-05 08:14:09 -0700934static int devlink_port_split(struct devlink *devlink, u32 port_index,
935 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100936
937{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800938 if (devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -0700939 return devlink->ops->port_split(devlink, port_index, count,
940 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100941 return -EOPNOTSUPP;
942}
943
944static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
945 struct genl_info *info)
946{
947 struct devlink *devlink = info->user_ptr[0];
Danielle Ratson82901ad2020-07-09 16:18:21 +0300948 struct devlink_port *devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100949 u32 port_index;
950 u32 count;
951
952 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
953 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
954 return -EINVAL;
955
Danielle Ratson82901ad2020-07-09 16:18:21 +0300956 devlink_port = devlink_port_get_from_info(devlink, info);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100957 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
958 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
Danielle Ratson82901ad2020-07-09 16:18:21 +0300959
960 if (IS_ERR(devlink_port))
961 return -EINVAL;
962
963 if (!devlink_port->attrs.splittable) {
964 /* Split ports cannot be split. */
965 if (devlink_port->attrs.split)
966 NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split further");
967 else
968 NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split");
969 return -EINVAL;
970 }
971
972 if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
973 NL_SET_ERR_MSG_MOD(info->extack, "Invalid split count");
974 return -EINVAL;
975 }
976
David Ahernac0fc8a2018-06-05 08:14:09 -0700977 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100978}
979
David Ahernac0fc8a2018-06-05 08:14:09 -0700980static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
981 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100982
983{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800984 if (devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -0700985 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100986 return -EOPNOTSUPP;
987}
988
989static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
990 struct genl_info *info)
991{
992 struct devlink *devlink = info->user_ptr[0];
993 u32 port_index;
994
995 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
996 return -EINVAL;
997
998 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700999 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001000}
1001
Jiri Pirkobf797472016-04-14 18:19:13 +02001002static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
1003 struct devlink_sb *devlink_sb,
1004 enum devlink_command cmd, u32 portid,
1005 u32 seq, int flags)
1006{
1007 void *hdr;
1008
1009 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1010 if (!hdr)
1011 return -EMSGSIZE;
1012
1013 if (devlink_nl_put_handle(msg, devlink))
1014 goto nla_put_failure;
1015 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1016 goto nla_put_failure;
1017 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
1018 goto nla_put_failure;
1019 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
1020 devlink_sb->ingress_pools_count))
1021 goto nla_put_failure;
1022 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
1023 devlink_sb->egress_pools_count))
1024 goto nla_put_failure;
1025 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
1026 devlink_sb->ingress_tc_count))
1027 goto nla_put_failure;
1028 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
1029 devlink_sb->egress_tc_count))
1030 goto nla_put_failure;
1031
1032 genlmsg_end(msg, hdr);
1033 return 0;
1034
1035nla_put_failure:
1036 genlmsg_cancel(msg, hdr);
1037 return -EMSGSIZE;
1038}
1039
1040static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
1041 struct genl_info *info)
1042{
1043 struct devlink *devlink = info->user_ptr[0];
1044 struct devlink_sb *devlink_sb = info->user_ptr[1];
1045 struct sk_buff *msg;
1046 int err;
1047
1048 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1049 if (!msg)
1050 return -ENOMEM;
1051
1052 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1053 DEVLINK_CMD_SB_NEW,
1054 info->snd_portid, info->snd_seq, 0);
1055 if (err) {
1056 nlmsg_free(msg);
1057 return err;
1058 }
1059
1060 return genlmsg_reply(msg, info);
1061}
1062
1063static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
1064 struct netlink_callback *cb)
1065{
1066 struct devlink *devlink;
1067 struct devlink_sb *devlink_sb;
1068 int start = cb->args[0];
1069 int idx = 0;
1070 int err;
1071
1072 mutex_lock(&devlink_mutex);
1073 list_for_each_entry(devlink, &devlink_list, list) {
1074 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
1075 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001076 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001077 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1078 if (idx < start) {
1079 idx++;
1080 continue;
1081 }
1082 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
1083 DEVLINK_CMD_SB_NEW,
1084 NETLINK_CB(cb->skb).portid,
1085 cb->nlh->nlmsg_seq,
1086 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001087 if (err) {
1088 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001089 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001090 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001091 idx++;
1092 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001093 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001094 }
1095out:
1096 mutex_unlock(&devlink_mutex);
1097
1098 cb->args[0] = idx;
1099 return msg->len;
1100}
1101
1102static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
1103 struct devlink_sb *devlink_sb,
1104 u16 pool_index, enum devlink_command cmd,
1105 u32 portid, u32 seq, int flags)
1106{
1107 struct devlink_sb_pool_info pool_info;
1108 void *hdr;
1109 int err;
1110
1111 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
1112 pool_index, &pool_info);
1113 if (err)
1114 return err;
1115
1116 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1117 if (!hdr)
1118 return -EMSGSIZE;
1119
1120 if (devlink_nl_put_handle(msg, devlink))
1121 goto nla_put_failure;
1122 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1123 goto nla_put_failure;
1124 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1125 goto nla_put_failure;
1126 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
1127 goto nla_put_failure;
1128 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
1129 goto nla_put_failure;
1130 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1131 pool_info.threshold_type))
1132 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -08001133 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
1134 pool_info.cell_size))
1135 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +02001136
1137 genlmsg_end(msg, hdr);
1138 return 0;
1139
1140nla_put_failure:
1141 genlmsg_cancel(msg, hdr);
1142 return -EMSGSIZE;
1143}
1144
1145static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
1146 struct genl_info *info)
1147{
1148 struct devlink *devlink = info->user_ptr[0];
1149 struct devlink_sb *devlink_sb = info->user_ptr[1];
1150 struct sk_buff *msg;
1151 u16 pool_index;
1152 int err;
1153
1154 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1155 &pool_index);
1156 if (err)
1157 return err;
1158
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001159 if (!devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001160 return -EOPNOTSUPP;
1161
1162 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1163 if (!msg)
1164 return -ENOMEM;
1165
1166 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
1167 DEVLINK_CMD_SB_POOL_NEW,
1168 info->snd_portid, info->snd_seq, 0);
1169 if (err) {
1170 nlmsg_free(msg);
1171 return err;
1172 }
1173
1174 return genlmsg_reply(msg, info);
1175}
1176
1177static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1178 struct devlink *devlink,
1179 struct devlink_sb *devlink_sb,
1180 u32 portid, u32 seq)
1181{
1182 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1183 u16 pool_index;
1184 int err;
1185
1186 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1187 if (*p_idx < start) {
1188 (*p_idx)++;
1189 continue;
1190 }
1191 err = devlink_nl_sb_pool_fill(msg, devlink,
1192 devlink_sb,
1193 pool_index,
1194 DEVLINK_CMD_SB_POOL_NEW,
1195 portid, seq, NLM_F_MULTI);
1196 if (err)
1197 return err;
1198 (*p_idx)++;
1199 }
1200 return 0;
1201}
1202
1203static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1204 struct netlink_callback *cb)
1205{
1206 struct devlink *devlink;
1207 struct devlink_sb *devlink_sb;
1208 int start = cb->args[0];
1209 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001210 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001211
1212 mutex_lock(&devlink_mutex);
1213 list_for_each_entry(devlink, &devlink_list, list) {
1214 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001215 !devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001216 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001217 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001218 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1219 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1220 devlink_sb,
1221 NETLINK_CB(cb->skb).portid,
1222 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001223 if (err && err != -EOPNOTSUPP) {
1224 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001225 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001226 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001227 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001228 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001229 }
1230out:
1231 mutex_unlock(&devlink_mutex);
1232
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001233 if (err != -EMSGSIZE)
1234 return err;
1235
Jiri Pirkobf797472016-04-14 18:19:13 +02001236 cb->args[0] = idx;
1237 return msg->len;
1238}
1239
1240static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1241 u16 pool_index, u32 size,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001242 enum devlink_sb_threshold_type threshold_type,
1243 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001244
1245{
1246 const struct devlink_ops *ops = devlink->ops;
1247
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001248 if (ops->sb_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001249 return ops->sb_pool_set(devlink, sb_index, pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001250 size, threshold_type, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001251 return -EOPNOTSUPP;
1252}
1253
1254static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1255 struct genl_info *info)
1256{
1257 struct devlink *devlink = info->user_ptr[0];
1258 struct devlink_sb *devlink_sb = info->user_ptr[1];
1259 enum devlink_sb_threshold_type threshold_type;
1260 u16 pool_index;
1261 u32 size;
1262 int err;
1263
1264 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1265 &pool_index);
1266 if (err)
1267 return err;
1268
1269 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1270 if (err)
1271 return err;
1272
1273 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1274 return -EINVAL;
1275
1276 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1277 return devlink_sb_pool_set(devlink, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001278 pool_index, size, threshold_type,
1279 info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001280}
1281
1282static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1283 struct devlink *devlink,
1284 struct devlink_port *devlink_port,
1285 struct devlink_sb *devlink_sb,
1286 u16 pool_index,
1287 enum devlink_command cmd,
1288 u32 portid, u32 seq, int flags)
1289{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001290 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001291 u32 threshold;
1292 void *hdr;
1293 int err;
1294
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001295 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1296 pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001297 if (err)
1298 return err;
1299
1300 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1301 if (!hdr)
1302 return -EMSGSIZE;
1303
1304 if (devlink_nl_put_handle(msg, devlink))
1305 goto nla_put_failure;
1306 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1307 goto nla_put_failure;
1308 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1309 goto nla_put_failure;
1310 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1311 goto nla_put_failure;
1312 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1313 goto nla_put_failure;
1314
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001315 if (ops->sb_occ_port_pool_get) {
1316 u32 cur;
1317 u32 max;
1318
1319 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1320 pool_index, &cur, &max);
1321 if (err && err != -EOPNOTSUPP)
1322 return err;
1323 if (!err) {
1324 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1325 goto nla_put_failure;
1326 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1327 goto nla_put_failure;
1328 }
1329 }
1330
Jiri Pirkobf797472016-04-14 18:19:13 +02001331 genlmsg_end(msg, hdr);
1332 return 0;
1333
1334nla_put_failure:
1335 genlmsg_cancel(msg, hdr);
1336 return -EMSGSIZE;
1337}
1338
1339static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1340 struct genl_info *info)
1341{
1342 struct devlink_port *devlink_port = info->user_ptr[0];
1343 struct devlink *devlink = devlink_port->devlink;
1344 struct devlink_sb *devlink_sb = info->user_ptr[1];
1345 struct sk_buff *msg;
1346 u16 pool_index;
1347 int err;
1348
1349 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1350 &pool_index);
1351 if (err)
1352 return err;
1353
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001354 if (!devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001355 return -EOPNOTSUPP;
1356
1357 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1358 if (!msg)
1359 return -ENOMEM;
1360
1361 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1362 devlink_sb, pool_index,
1363 DEVLINK_CMD_SB_PORT_POOL_NEW,
1364 info->snd_portid, info->snd_seq, 0);
1365 if (err) {
1366 nlmsg_free(msg);
1367 return err;
1368 }
1369
1370 return genlmsg_reply(msg, info);
1371}
1372
1373static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1374 struct devlink *devlink,
1375 struct devlink_sb *devlink_sb,
1376 u32 portid, u32 seq)
1377{
1378 struct devlink_port *devlink_port;
1379 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1380 u16 pool_index;
1381 int err;
1382
1383 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1384 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1385 if (*p_idx < start) {
1386 (*p_idx)++;
1387 continue;
1388 }
1389 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1390 devlink_port,
1391 devlink_sb,
1392 pool_index,
1393 DEVLINK_CMD_SB_PORT_POOL_NEW,
1394 portid, seq,
1395 NLM_F_MULTI);
1396 if (err)
1397 return err;
1398 (*p_idx)++;
1399 }
1400 }
1401 return 0;
1402}
1403
1404static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1405 struct netlink_callback *cb)
1406{
1407 struct devlink *devlink;
1408 struct devlink_sb *devlink_sb;
1409 int start = cb->args[0];
1410 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001411 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001412
1413 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001414 list_for_each_entry(devlink, &devlink_list, list) {
1415 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001416 !devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001417 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001418 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001419 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1420 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1421 devlink, devlink_sb,
1422 NETLINK_CB(cb->skb).portid,
1423 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001424 if (err && err != -EOPNOTSUPP) {
1425 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001426 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001427 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001428 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001429 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001430 }
1431out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001432 mutex_unlock(&devlink_mutex);
1433
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001434 if (err != -EMSGSIZE)
1435 return err;
1436
Jiri Pirkobf797472016-04-14 18:19:13 +02001437 cb->args[0] = idx;
1438 return msg->len;
1439}
1440
1441static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1442 unsigned int sb_index, u16 pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001443 u32 threshold,
1444 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001445
1446{
1447 const struct devlink_ops *ops = devlink_port->devlink->ops;
1448
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001449 if (ops->sb_port_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001450 return ops->sb_port_pool_set(devlink_port, sb_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001451 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001452 return -EOPNOTSUPP;
1453}
1454
1455static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1456 struct genl_info *info)
1457{
1458 struct devlink_port *devlink_port = info->user_ptr[0];
1459 struct devlink_sb *devlink_sb = info->user_ptr[1];
1460 u16 pool_index;
1461 u32 threshold;
1462 int err;
1463
1464 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1465 &pool_index);
1466 if (err)
1467 return err;
1468
1469 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1470 return -EINVAL;
1471
1472 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1473 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001474 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001475}
1476
1477static int
1478devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1479 struct devlink_port *devlink_port,
1480 struct devlink_sb *devlink_sb, u16 tc_index,
1481 enum devlink_sb_pool_type pool_type,
1482 enum devlink_command cmd,
1483 u32 portid, u32 seq, int flags)
1484{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001485 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001486 u16 pool_index;
1487 u32 threshold;
1488 void *hdr;
1489 int err;
1490
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001491 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1492 tc_index, pool_type,
1493 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001494 if (err)
1495 return err;
1496
1497 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1498 if (!hdr)
1499 return -EMSGSIZE;
1500
1501 if (devlink_nl_put_handle(msg, devlink))
1502 goto nla_put_failure;
1503 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1504 goto nla_put_failure;
1505 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1506 goto nla_put_failure;
1507 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1508 goto nla_put_failure;
1509 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1510 goto nla_put_failure;
1511 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1512 goto nla_put_failure;
1513 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1514 goto nla_put_failure;
1515
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001516 if (ops->sb_occ_tc_port_bind_get) {
1517 u32 cur;
1518 u32 max;
1519
1520 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1521 devlink_sb->index,
1522 tc_index, pool_type,
1523 &cur, &max);
1524 if (err && err != -EOPNOTSUPP)
1525 return err;
1526 if (!err) {
1527 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1528 goto nla_put_failure;
1529 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1530 goto nla_put_failure;
1531 }
1532 }
1533
Jiri Pirkobf797472016-04-14 18:19:13 +02001534 genlmsg_end(msg, hdr);
1535 return 0;
1536
1537nla_put_failure:
1538 genlmsg_cancel(msg, hdr);
1539 return -EMSGSIZE;
1540}
1541
1542static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1543 struct genl_info *info)
1544{
1545 struct devlink_port *devlink_port = info->user_ptr[0];
1546 struct devlink *devlink = devlink_port->devlink;
1547 struct devlink_sb *devlink_sb = info->user_ptr[1];
1548 struct sk_buff *msg;
1549 enum devlink_sb_pool_type pool_type;
1550 u16 tc_index;
1551 int err;
1552
1553 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1554 if (err)
1555 return err;
1556
1557 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1558 pool_type, &tc_index);
1559 if (err)
1560 return err;
1561
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001562 if (!devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001563 return -EOPNOTSUPP;
1564
1565 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1566 if (!msg)
1567 return -ENOMEM;
1568
1569 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1570 devlink_sb, tc_index, pool_type,
1571 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1572 info->snd_portid,
1573 info->snd_seq, 0);
1574 if (err) {
1575 nlmsg_free(msg);
1576 return err;
1577 }
1578
1579 return genlmsg_reply(msg, info);
1580}
1581
1582static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1583 int start, int *p_idx,
1584 struct devlink *devlink,
1585 struct devlink_sb *devlink_sb,
1586 u32 portid, u32 seq)
1587{
1588 struct devlink_port *devlink_port;
1589 u16 tc_index;
1590 int err;
1591
1592 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1593 for (tc_index = 0;
1594 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1595 if (*p_idx < start) {
1596 (*p_idx)++;
1597 continue;
1598 }
1599 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1600 devlink_port,
1601 devlink_sb,
1602 tc_index,
1603 DEVLINK_SB_POOL_TYPE_INGRESS,
1604 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1605 portid, seq,
1606 NLM_F_MULTI);
1607 if (err)
1608 return err;
1609 (*p_idx)++;
1610 }
1611 for (tc_index = 0;
1612 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1613 if (*p_idx < start) {
1614 (*p_idx)++;
1615 continue;
1616 }
1617 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1618 devlink_port,
1619 devlink_sb,
1620 tc_index,
1621 DEVLINK_SB_POOL_TYPE_EGRESS,
1622 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1623 portid, seq,
1624 NLM_F_MULTI);
1625 if (err)
1626 return err;
1627 (*p_idx)++;
1628 }
1629 }
1630 return 0;
1631}
1632
1633static int
1634devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1635 struct netlink_callback *cb)
1636{
1637 struct devlink *devlink;
1638 struct devlink_sb *devlink_sb;
1639 int start = cb->args[0];
1640 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001641 int err = 0;
Jiri Pirkobf797472016-04-14 18:19:13 +02001642
1643 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001644 list_for_each_entry(devlink, &devlink_list, list) {
1645 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001646 !devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001647 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001648
1649 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001650 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1651 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1652 devlink,
1653 devlink_sb,
1654 NETLINK_CB(cb->skb).portid,
1655 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001656 if (err && err != -EOPNOTSUPP) {
1657 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001658 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001659 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001660 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001661 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001662 }
1663out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001664 mutex_unlock(&devlink_mutex);
1665
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02001666 if (err != -EMSGSIZE)
1667 return err;
1668
Jiri Pirkobf797472016-04-14 18:19:13 +02001669 cb->args[0] = idx;
1670 return msg->len;
1671}
1672
1673static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1674 unsigned int sb_index, u16 tc_index,
1675 enum devlink_sb_pool_type pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001676 u16 pool_index, u32 threshold,
1677 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001678
1679{
1680 const struct devlink_ops *ops = devlink_port->devlink->ops;
1681
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001682 if (ops->sb_tc_pool_bind_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001683 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1684 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001685 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001686 return -EOPNOTSUPP;
1687}
1688
1689static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1690 struct genl_info *info)
1691{
1692 struct devlink_port *devlink_port = info->user_ptr[0];
1693 struct devlink_sb *devlink_sb = info->user_ptr[1];
1694 enum devlink_sb_pool_type pool_type;
1695 u16 tc_index;
1696 u16 pool_index;
1697 u32 threshold;
1698 int err;
1699
1700 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1701 if (err)
1702 return err;
1703
1704 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1705 pool_type, &tc_index);
1706 if (err)
1707 return err;
1708
1709 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1710 &pool_index);
1711 if (err)
1712 return err;
1713
1714 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1715 return -EINVAL;
1716
1717 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1718 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1719 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001720 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001721}
1722
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001723static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1724 struct genl_info *info)
1725{
1726 struct devlink *devlink = info->user_ptr[0];
1727 struct devlink_sb *devlink_sb = info->user_ptr[1];
1728 const struct devlink_ops *ops = devlink->ops;
1729
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001730 if (ops->sb_occ_snapshot)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001731 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1732 return -EOPNOTSUPP;
1733}
1734
1735static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1736 struct genl_info *info)
1737{
1738 struct devlink *devlink = info->user_ptr[0];
1739 struct devlink_sb *devlink_sb = info->user_ptr[1];
1740 const struct devlink_ops *ops = devlink->ops;
1741
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001742 if (ops->sb_occ_max_clear)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001743 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1744 return -EOPNOTSUPP;
1745}
1746
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001747static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1748 enum devlink_command cmd, u32 portid,
1749 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001750{
Roi Dayan59bfde02016-11-22 23:09:57 +02001751 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001752 enum devlink_eswitch_encap_mode encap_mode;
1753 u8 inline_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001754 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001755 int err = 0;
1756 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001757
1758 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1759 if (!hdr)
1760 return -EMSGSIZE;
1761
Roi Dayan59bfde02016-11-22 23:09:57 +02001762 err = devlink_nl_put_handle(msg, devlink);
1763 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001764 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001765
Jiri Pirko4456f612017-02-09 15:54:36 +01001766 if (ops->eswitch_mode_get) {
1767 err = ops->eswitch_mode_get(devlink, &mode);
1768 if (err)
1769 goto nla_put_failure;
1770 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1771 if (err)
1772 goto nla_put_failure;
1773 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001774
1775 if (ops->eswitch_inline_mode_get) {
1776 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1777 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001778 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001779 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1780 inline_mode);
1781 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001782 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001783 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001784
Roi Dayanf43e9b02016-09-25 13:52:44 +03001785 if (ops->eswitch_encap_mode_get) {
1786 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1787 if (err)
1788 goto nla_put_failure;
1789 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1790 if (err)
1791 goto nla_put_failure;
1792 }
1793
Or Gerlitz08f4b592016-07-01 14:51:01 +03001794 genlmsg_end(msg, hdr);
1795 return 0;
1796
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001797nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001798 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001799 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001800}
1801
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001802static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1803 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001804{
1805 struct devlink *devlink = info->user_ptr[0];
Or Gerlitz08f4b592016-07-01 14:51:01 +03001806 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001807 int err;
1808
Or Gerlitz08f4b592016-07-01 14:51:01 +03001809 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1810 if (!msg)
1811 return -ENOMEM;
1812
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001813 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1814 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001815
1816 if (err) {
1817 nlmsg_free(msg);
1818 return err;
1819 }
1820
1821 return genlmsg_reply(msg, info);
1822}
1823
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001824static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1825 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001826{
1827 struct devlink *devlink = info->user_ptr[0];
1828 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001829 enum devlink_eswitch_encap_mode encap_mode;
1830 u8 inline_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001831 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001832 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001833
Roi Dayan59bfde02016-11-22 23:09:57 +02001834 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1835 if (!ops->eswitch_mode_set)
1836 return -EOPNOTSUPP;
1837 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001838 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001839 if (err)
1840 return err;
1841 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001842
Roi Dayan59bfde02016-11-22 23:09:57 +02001843 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1844 if (!ops->eswitch_inline_mode_set)
1845 return -EOPNOTSUPP;
1846 inline_mode = nla_get_u8(
1847 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001848 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1849 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001850 if (err)
1851 return err;
1852 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03001853
1854 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1855 if (!ops->eswitch_encap_mode_set)
1856 return -EOPNOTSUPP;
1857 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001858 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1859 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03001860 if (err)
1861 return err;
1862 }
1863
Roi Dayan59bfde02016-11-22 23:09:57 +02001864 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001865}
1866
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001867int devlink_dpipe_match_put(struct sk_buff *skb,
1868 struct devlink_dpipe_match *match)
1869{
1870 struct devlink_dpipe_header *header = match->header;
1871 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1872 struct nlattr *match_attr;
1873
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001874 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001875 if (!match_attr)
1876 return -EMSGSIZE;
1877
1878 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1879 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1880 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1881 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1882 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1883 goto nla_put_failure;
1884
1885 nla_nest_end(skb, match_attr);
1886 return 0;
1887
1888nla_put_failure:
1889 nla_nest_cancel(skb, match_attr);
1890 return -EMSGSIZE;
1891}
1892EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1893
1894static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1895 struct sk_buff *skb)
1896{
1897 struct nlattr *matches_attr;
1898
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001899 matches_attr = nla_nest_start_noflag(skb,
1900 DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001901 if (!matches_attr)
1902 return -EMSGSIZE;
1903
1904 if (table->table_ops->matches_dump(table->priv, skb))
1905 goto nla_put_failure;
1906
1907 nla_nest_end(skb, matches_attr);
1908 return 0;
1909
1910nla_put_failure:
1911 nla_nest_cancel(skb, matches_attr);
1912 return -EMSGSIZE;
1913}
1914
1915int devlink_dpipe_action_put(struct sk_buff *skb,
1916 struct devlink_dpipe_action *action)
1917{
1918 struct devlink_dpipe_header *header = action->header;
1919 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1920 struct nlattr *action_attr;
1921
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001922 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001923 if (!action_attr)
1924 return -EMSGSIZE;
1925
1926 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1927 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1928 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1929 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1930 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1931 goto nla_put_failure;
1932
1933 nla_nest_end(skb, action_attr);
1934 return 0;
1935
1936nla_put_failure:
1937 nla_nest_cancel(skb, action_attr);
1938 return -EMSGSIZE;
1939}
1940EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1941
1942static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1943 struct sk_buff *skb)
1944{
1945 struct nlattr *actions_attr;
1946
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001947 actions_attr = nla_nest_start_noflag(skb,
1948 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001949 if (!actions_attr)
1950 return -EMSGSIZE;
1951
1952 if (table->table_ops->actions_dump(table->priv, skb))
1953 goto nla_put_failure;
1954
1955 nla_nest_end(skb, actions_attr);
1956 return 0;
1957
1958nla_put_failure:
1959 nla_nest_cancel(skb, actions_attr);
1960 return -EMSGSIZE;
1961}
1962
1963static int devlink_dpipe_table_put(struct sk_buff *skb,
1964 struct devlink_dpipe_table *table)
1965{
1966 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001967 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001968
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001969 table_size = table->table_ops->size_get(table->priv);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001970 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001971 if (!table_attr)
1972 return -EMSGSIZE;
1973
1974 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001975 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001976 DEVLINK_ATTR_PAD))
1977 goto nla_put_failure;
1978 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1979 table->counters_enabled))
1980 goto nla_put_failure;
1981
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001982 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02001983 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1984 table->resource_id, DEVLINK_ATTR_PAD) ||
1985 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1986 table->resource_units, DEVLINK_ATTR_PAD))
1987 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001988 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001989 if (devlink_dpipe_matches_put(table, skb))
1990 goto nla_put_failure;
1991
1992 if (devlink_dpipe_actions_put(table, skb))
1993 goto nla_put_failure;
1994
1995 nla_nest_end(skb, table_attr);
1996 return 0;
1997
1998nla_put_failure:
1999 nla_nest_cancel(skb, table_attr);
2000 return -EMSGSIZE;
2001}
2002
2003static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
2004 struct genl_info *info)
2005{
2006 int err;
2007
2008 if (*pskb) {
2009 err = genlmsg_reply(*pskb, info);
2010 if (err)
2011 return err;
2012 }
2013 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
2014 if (!*pskb)
2015 return -ENOMEM;
2016 return 0;
2017}
2018
2019static int devlink_dpipe_tables_fill(struct genl_info *info,
2020 enum devlink_command cmd, int flags,
2021 struct list_head *dpipe_tables,
2022 const char *table_name)
2023{
2024 struct devlink *devlink = info->user_ptr[0];
2025 struct devlink_dpipe_table *table;
2026 struct nlattr *tables_attr;
2027 struct sk_buff *skb = NULL;
2028 struct nlmsghdr *nlh;
2029 bool incomplete;
2030 void *hdr;
2031 int i;
2032 int err;
2033
2034 table = list_first_entry(dpipe_tables,
2035 struct devlink_dpipe_table, list);
2036start_again:
2037 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2038 if (err)
2039 return err;
2040
2041 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2042 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002043 if (!hdr) {
2044 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002045 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002046 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002047
2048 if (devlink_nl_put_handle(skb, devlink))
2049 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002050 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002051 if (!tables_attr)
2052 goto nla_put_failure;
2053
2054 i = 0;
2055 incomplete = false;
2056 list_for_each_entry_from(table, dpipe_tables, list) {
2057 if (!table_name) {
2058 err = devlink_dpipe_table_put(skb, table);
2059 if (err) {
2060 if (!i)
2061 goto err_table_put;
2062 incomplete = true;
2063 break;
2064 }
2065 } else {
2066 if (!strcmp(table->name, table_name)) {
2067 err = devlink_dpipe_table_put(skb, table);
2068 if (err)
2069 break;
2070 }
2071 }
2072 i++;
2073 }
2074
2075 nla_nest_end(skb, tables_attr);
2076 genlmsg_end(skb, hdr);
2077 if (incomplete)
2078 goto start_again;
2079
2080send_done:
2081 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2082 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2083 if (!nlh) {
2084 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2085 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002086 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002087 goto send_done;
2088 }
2089
2090 return genlmsg_reply(skb, info);
2091
2092nla_put_failure:
2093 err = -EMSGSIZE;
2094err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002095 nlmsg_free(skb);
2096 return err;
2097}
2098
2099static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
2100 struct genl_info *info)
2101{
2102 struct devlink *devlink = info->user_ptr[0];
2103 const char *table_name = NULL;
2104
2105 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2106 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2107
2108 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
2109 &devlink->dpipe_table_list,
2110 table_name);
2111}
2112
2113static int devlink_dpipe_value_put(struct sk_buff *skb,
2114 struct devlink_dpipe_value *value)
2115{
2116 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
2117 value->value_size, value->value))
2118 return -EMSGSIZE;
2119 if (value->mask)
2120 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
2121 value->value_size, value->mask))
2122 return -EMSGSIZE;
2123 if (value->mapping_valid)
2124 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
2125 value->mapping_value))
2126 return -EMSGSIZE;
2127 return 0;
2128}
2129
2130static int devlink_dpipe_action_value_put(struct sk_buff *skb,
2131 struct devlink_dpipe_value *value)
2132{
2133 if (!value->action)
2134 return -EINVAL;
2135 if (devlink_dpipe_action_put(skb, value->action))
2136 return -EMSGSIZE;
2137 if (devlink_dpipe_value_put(skb, value))
2138 return -EMSGSIZE;
2139 return 0;
2140}
2141
2142static int devlink_dpipe_action_values_put(struct sk_buff *skb,
2143 struct devlink_dpipe_value *values,
2144 unsigned int values_count)
2145{
2146 struct nlattr *action_attr;
2147 int i;
2148 int err;
2149
2150 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002151 action_attr = nla_nest_start_noflag(skb,
2152 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002153 if (!action_attr)
2154 return -EMSGSIZE;
2155 err = devlink_dpipe_action_value_put(skb, &values[i]);
2156 if (err)
2157 goto err_action_value_put;
2158 nla_nest_end(skb, action_attr);
2159 }
2160 return 0;
2161
2162err_action_value_put:
2163 nla_nest_cancel(skb, action_attr);
2164 return err;
2165}
2166
2167static int devlink_dpipe_match_value_put(struct sk_buff *skb,
2168 struct devlink_dpipe_value *value)
2169{
2170 if (!value->match)
2171 return -EINVAL;
2172 if (devlink_dpipe_match_put(skb, value->match))
2173 return -EMSGSIZE;
2174 if (devlink_dpipe_value_put(skb, value))
2175 return -EMSGSIZE;
2176 return 0;
2177}
2178
2179static int devlink_dpipe_match_values_put(struct sk_buff *skb,
2180 struct devlink_dpipe_value *values,
2181 unsigned int values_count)
2182{
2183 struct nlattr *match_attr;
2184 int i;
2185 int err;
2186
2187 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002188 match_attr = nla_nest_start_noflag(skb,
2189 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002190 if (!match_attr)
2191 return -EMSGSIZE;
2192 err = devlink_dpipe_match_value_put(skb, &values[i]);
2193 if (err)
2194 goto err_match_value_put;
2195 nla_nest_end(skb, match_attr);
2196 }
2197 return 0;
2198
2199err_match_value_put:
2200 nla_nest_cancel(skb, match_attr);
2201 return err;
2202}
2203
2204static int devlink_dpipe_entry_put(struct sk_buff *skb,
2205 struct devlink_dpipe_entry *entry)
2206{
2207 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2208 int err;
2209
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002210 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002211 if (!entry_attr)
2212 return -EMSGSIZE;
2213
2214 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2215 DEVLINK_ATTR_PAD))
2216 goto nla_put_failure;
2217 if (entry->counter_valid)
2218 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2219 entry->counter, DEVLINK_ATTR_PAD))
2220 goto nla_put_failure;
2221
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002222 matches_attr = nla_nest_start_noflag(skb,
2223 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002224 if (!matches_attr)
2225 goto nla_put_failure;
2226
2227 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2228 entry->match_values_count);
2229 if (err) {
2230 nla_nest_cancel(skb, matches_attr);
2231 goto err_match_values_put;
2232 }
2233 nla_nest_end(skb, matches_attr);
2234
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002235 actions_attr = nla_nest_start_noflag(skb,
2236 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002237 if (!actions_attr)
2238 goto nla_put_failure;
2239
2240 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2241 entry->action_values_count);
2242 if (err) {
2243 nla_nest_cancel(skb, actions_attr);
2244 goto err_action_values_put;
2245 }
2246 nla_nest_end(skb, actions_attr);
2247
2248 nla_nest_end(skb, entry_attr);
2249 return 0;
2250
2251nla_put_failure:
2252 err = -EMSGSIZE;
2253err_match_values_put:
2254err_action_values_put:
2255 nla_nest_cancel(skb, entry_attr);
2256 return err;
2257}
2258
2259static struct devlink_dpipe_table *
2260devlink_dpipe_table_find(struct list_head *dpipe_tables,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302261 const char *table_name, struct devlink *devlink)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002262{
2263 struct devlink_dpipe_table *table;
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302264 list_for_each_entry_rcu(table, dpipe_tables, list,
2265 lockdep_is_held(&devlink->lock)) {
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002266 if (!strcmp(table->name, table_name))
2267 return table;
2268 }
2269 return NULL;
2270}
2271
2272int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2273{
2274 struct devlink *devlink;
2275 int err;
2276
2277 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2278 dump_ctx->info);
2279 if (err)
2280 return err;
2281
2282 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2283 dump_ctx->info->snd_portid,
2284 dump_ctx->info->snd_seq,
2285 &devlink_nl_family, NLM_F_MULTI,
2286 dump_ctx->cmd);
2287 if (!dump_ctx->hdr)
2288 goto nla_put_failure;
2289
2290 devlink = dump_ctx->info->user_ptr[0];
2291 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2292 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002293 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2294 DEVLINK_ATTR_DPIPE_ENTRIES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002295 if (!dump_ctx->nest)
2296 goto nla_put_failure;
2297 return 0;
2298
2299nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002300 nlmsg_free(dump_ctx->skb);
2301 return -EMSGSIZE;
2302}
2303EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2304
2305int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2306 struct devlink_dpipe_entry *entry)
2307{
2308 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2309}
2310EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2311
2312int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2313{
2314 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2315 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2316 return 0;
2317}
2318EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2319
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002320void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2321
2322{
2323 unsigned int value_count, value_index;
2324 struct devlink_dpipe_value *value;
2325
2326 value = entry->action_values;
2327 value_count = entry->action_values_count;
2328 for (value_index = 0; value_index < value_count; value_index++) {
2329 kfree(value[value_index].value);
2330 kfree(value[value_index].mask);
2331 }
2332
2333 value = entry->match_values;
2334 value_count = entry->match_values_count;
2335 for (value_index = 0; value_index < value_count; value_index++) {
2336 kfree(value[value_index].value);
2337 kfree(value[value_index].mask);
2338 }
2339}
2340EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2341
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002342static int devlink_dpipe_entries_fill(struct genl_info *info,
2343 enum devlink_command cmd, int flags,
2344 struct devlink_dpipe_table *table)
2345{
2346 struct devlink_dpipe_dump_ctx dump_ctx;
2347 struct nlmsghdr *nlh;
2348 int err;
2349
2350 dump_ctx.skb = NULL;
2351 dump_ctx.cmd = cmd;
2352 dump_ctx.info = info;
2353
2354 err = table->table_ops->entries_dump(table->priv,
2355 table->counters_enabled,
2356 &dump_ctx);
2357 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002358 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002359
2360send_done:
2361 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2362 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2363 if (!nlh) {
2364 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2365 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002366 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002367 goto send_done;
2368 }
2369 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002370}
2371
2372static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2373 struct genl_info *info)
2374{
2375 struct devlink *devlink = info->user_ptr[0];
2376 struct devlink_dpipe_table *table;
2377 const char *table_name;
2378
2379 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2380 return -EINVAL;
2381
2382 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2383 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302384 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002385 if (!table)
2386 return -EINVAL;
2387
2388 if (!table->table_ops->entries_dump)
2389 return -EINVAL;
2390
2391 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2392 0, table);
2393}
2394
2395static int devlink_dpipe_fields_put(struct sk_buff *skb,
2396 const struct devlink_dpipe_header *header)
2397{
2398 struct devlink_dpipe_field *field;
2399 struct nlattr *field_attr;
2400 int i;
2401
2402 for (i = 0; i < header->fields_count; i++) {
2403 field = &header->fields[i];
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002404 field_attr = nla_nest_start_noflag(skb,
2405 DEVLINK_ATTR_DPIPE_FIELD);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002406 if (!field_attr)
2407 return -EMSGSIZE;
2408 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2409 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2410 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2411 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2412 goto nla_put_failure;
2413 nla_nest_end(skb, field_attr);
2414 }
2415 return 0;
2416
2417nla_put_failure:
2418 nla_nest_cancel(skb, field_attr);
2419 return -EMSGSIZE;
2420}
2421
2422static int devlink_dpipe_header_put(struct sk_buff *skb,
2423 struct devlink_dpipe_header *header)
2424{
2425 struct nlattr *fields_attr, *header_attr;
2426 int err;
2427
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002428 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002429 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002430 return -EMSGSIZE;
2431
2432 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2433 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2434 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2435 goto nla_put_failure;
2436
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002437 fields_attr = nla_nest_start_noflag(skb,
2438 DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002439 if (!fields_attr)
2440 goto nla_put_failure;
2441
2442 err = devlink_dpipe_fields_put(skb, header);
2443 if (err) {
2444 nla_nest_cancel(skb, fields_attr);
2445 goto nla_put_failure;
2446 }
2447 nla_nest_end(skb, fields_attr);
2448 nla_nest_end(skb, header_attr);
2449 return 0;
2450
2451nla_put_failure:
2452 err = -EMSGSIZE;
2453 nla_nest_cancel(skb, header_attr);
2454 return err;
2455}
2456
2457static int devlink_dpipe_headers_fill(struct genl_info *info,
2458 enum devlink_command cmd, int flags,
2459 struct devlink_dpipe_headers *
2460 dpipe_headers)
2461{
2462 struct devlink *devlink = info->user_ptr[0];
2463 struct nlattr *headers_attr;
2464 struct sk_buff *skb = NULL;
2465 struct nlmsghdr *nlh;
2466 void *hdr;
2467 int i, j;
2468 int err;
2469
2470 i = 0;
2471start_again:
2472 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2473 if (err)
2474 return err;
2475
2476 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2477 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002478 if (!hdr) {
2479 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002480 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002481 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002482
2483 if (devlink_nl_put_handle(skb, devlink))
2484 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002485 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002486 if (!headers_attr)
2487 goto nla_put_failure;
2488
2489 j = 0;
2490 for (; i < dpipe_headers->headers_count; i++) {
2491 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2492 if (err) {
2493 if (!j)
2494 goto err_table_put;
2495 break;
2496 }
2497 j++;
2498 }
2499 nla_nest_end(skb, headers_attr);
2500 genlmsg_end(skb, hdr);
2501 if (i != dpipe_headers->headers_count)
2502 goto start_again;
2503
2504send_done:
2505 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2506 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2507 if (!nlh) {
2508 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2509 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002510 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002511 goto send_done;
2512 }
2513 return genlmsg_reply(skb, info);
2514
2515nla_put_failure:
2516 err = -EMSGSIZE;
2517err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002518 nlmsg_free(skb);
2519 return err;
2520}
2521
2522static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2523 struct genl_info *info)
2524{
2525 struct devlink *devlink = info->user_ptr[0];
2526
2527 if (!devlink->dpipe_headers)
2528 return -EOPNOTSUPP;
2529 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2530 0, devlink->dpipe_headers);
2531}
2532
2533static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2534 const char *table_name,
2535 bool enable)
2536{
2537 struct devlink_dpipe_table *table;
2538
2539 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05302540 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002541 if (!table)
2542 return -EINVAL;
2543
2544 if (table->counter_control_extern)
2545 return -EOPNOTSUPP;
2546
2547 if (!(table->counters_enabled ^ enable))
2548 return 0;
2549
2550 table->counters_enabled = enable;
2551 if (table->table_ops->counters_set_update)
2552 table->table_ops->counters_set_update(table->priv, enable);
2553 return 0;
2554}
2555
2556static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2557 struct genl_info *info)
2558{
2559 struct devlink *devlink = info->user_ptr[0];
2560 const char *table_name;
2561 bool counters_enable;
2562
2563 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2564 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2565 return -EINVAL;
2566
2567 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2568 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2569
2570 return devlink_dpipe_table_counters_set(devlink, table_name,
2571 counters_enable);
2572}
2573
Wei Yongjun43dd7512018-01-17 03:27:42 +00002574static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002575devlink_resource_find(struct devlink *devlink,
2576 struct devlink_resource *resource, u64 resource_id)
2577{
2578 struct list_head *resource_list;
2579
2580 if (resource)
2581 resource_list = &resource->resource_list;
2582 else
2583 resource_list = &devlink->resource_list;
2584
2585 list_for_each_entry(resource, resource_list, list) {
2586 struct devlink_resource *child_resource;
2587
2588 if (resource->id == resource_id)
2589 return resource;
2590
2591 child_resource = devlink_resource_find(devlink, resource,
2592 resource_id);
2593 if (child_resource)
2594 return child_resource;
2595 }
2596 return NULL;
2597}
2598
Wei Yongjun43dd7512018-01-17 03:27:42 +00002599static void
2600devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002601{
2602 struct devlink_resource *child_resource;
2603 bool size_valid = true;
2604 u64 parts_size = 0;
2605
2606 if (list_empty(&resource->resource_list))
2607 goto out;
2608
2609 list_for_each_entry(child_resource, &resource->resource_list, list)
2610 parts_size += child_resource->size_new;
2611
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002612 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002613 size_valid = false;
2614out:
2615 resource->size_valid = size_valid;
2616}
2617
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002618static int
2619devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2620 struct netlink_ext_ack *extack)
2621{
2622 u64 reminder;
2623 int err = 0;
2624
David S. Miller0f3e9c92018-03-06 00:53:44 -05002625 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002626 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2627 err = -EINVAL;
2628 }
2629
David S. Miller0f3e9c92018-03-06 00:53:44 -05002630 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002631 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2632 err = -EINVAL;
2633 }
2634
David S. Miller0f3e9c92018-03-06 00:53:44 -05002635 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002636 if (reminder) {
2637 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2638 err = -EINVAL;
2639 }
2640
2641 return err;
2642}
2643
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002644static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2645 struct genl_info *info)
2646{
2647 struct devlink *devlink = info->user_ptr[0];
2648 struct devlink_resource *resource;
2649 u64 resource_id;
2650 u64 size;
2651 int err;
2652
2653 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2654 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2655 return -EINVAL;
2656 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2657
2658 resource = devlink_resource_find(devlink, NULL, resource_id);
2659 if (!resource)
2660 return -EINVAL;
2661
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002662 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002663 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002664 if (err)
2665 return err;
2666
2667 resource->size_new = size;
2668 devlink_resource_validate_children(resource);
2669 if (resource->parent)
2670 devlink_resource_validate_children(resource->parent);
2671 return 0;
2672}
2673
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002674static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002675devlink_resource_size_params_put(struct devlink_resource *resource,
2676 struct sk_buff *skb)
2677{
2678 struct devlink_resource_size_params *size_params;
2679
Jiri Pirko77d27092018-02-28 13:12:09 +01002680 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002681 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2682 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2683 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2684 size_params->size_max, DEVLINK_ATTR_PAD) ||
2685 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2686 size_params->size_min, DEVLINK_ATTR_PAD) ||
2687 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2688 return -EMSGSIZE;
2689 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002690}
2691
Jiri Pirkofc56be42018-04-05 22:13:21 +02002692static int devlink_resource_occ_put(struct devlink_resource *resource,
2693 struct sk_buff *skb)
2694{
2695 if (!resource->occ_get)
2696 return 0;
2697 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2698 resource->occ_get(resource->occ_get_priv),
2699 DEVLINK_ATTR_PAD);
2700}
2701
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002702static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2703 struct devlink_resource *resource)
2704{
2705 struct devlink_resource *child_resource;
2706 struct nlattr *child_resource_attr;
2707 struct nlattr *resource_attr;
2708
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002709 resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002710 if (!resource_attr)
2711 return -EMSGSIZE;
2712
2713 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2714 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2715 DEVLINK_ATTR_PAD) ||
2716 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2717 DEVLINK_ATTR_PAD))
2718 goto nla_put_failure;
2719 if (resource->size != resource->size_new)
2720 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2721 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002722 if (devlink_resource_occ_put(resource, skb))
2723 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002724 if (devlink_resource_size_params_put(resource, skb))
2725 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002726 if (list_empty(&resource->resource_list))
2727 goto out;
2728
2729 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2730 resource->size_valid))
2731 goto nla_put_failure;
2732
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002733 child_resource_attr = nla_nest_start_noflag(skb,
2734 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002735 if (!child_resource_attr)
2736 goto nla_put_failure;
2737
2738 list_for_each_entry(child_resource, &resource->resource_list, list) {
2739 if (devlink_resource_put(devlink, skb, child_resource))
2740 goto resource_put_failure;
2741 }
2742
2743 nla_nest_end(skb, child_resource_attr);
2744out:
2745 nla_nest_end(skb, resource_attr);
2746 return 0;
2747
2748resource_put_failure:
2749 nla_nest_cancel(skb, child_resource_attr);
2750nla_put_failure:
2751 nla_nest_cancel(skb, resource_attr);
2752 return -EMSGSIZE;
2753}
2754
2755static int devlink_resource_fill(struct genl_info *info,
2756 enum devlink_command cmd, int flags)
2757{
2758 struct devlink *devlink = info->user_ptr[0];
2759 struct devlink_resource *resource;
2760 struct nlattr *resources_attr;
2761 struct sk_buff *skb = NULL;
2762 struct nlmsghdr *nlh;
2763 bool incomplete;
2764 void *hdr;
2765 int i;
2766 int err;
2767
2768 resource = list_first_entry(&devlink->resource_list,
2769 struct devlink_resource, list);
2770start_again:
2771 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2772 if (err)
2773 return err;
2774
2775 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2776 &devlink_nl_family, NLM_F_MULTI, cmd);
2777 if (!hdr) {
2778 nlmsg_free(skb);
2779 return -EMSGSIZE;
2780 }
2781
2782 if (devlink_nl_put_handle(skb, devlink))
2783 goto nla_put_failure;
2784
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002785 resources_attr = nla_nest_start_noflag(skb,
2786 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002787 if (!resources_attr)
2788 goto nla_put_failure;
2789
2790 incomplete = false;
2791 i = 0;
2792 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2793 err = devlink_resource_put(devlink, skb, resource);
2794 if (err) {
2795 if (!i)
2796 goto err_resource_put;
2797 incomplete = true;
2798 break;
2799 }
2800 i++;
2801 }
2802 nla_nest_end(skb, resources_attr);
2803 genlmsg_end(skb, hdr);
2804 if (incomplete)
2805 goto start_again;
2806send_done:
2807 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2808 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2809 if (!nlh) {
2810 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2811 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002812 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002813 goto send_done;
2814 }
2815 return genlmsg_reply(skb, info);
2816
2817nla_put_failure:
2818 err = -EMSGSIZE;
2819err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002820 nlmsg_free(skb);
2821 return err;
2822}
2823
2824static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2825 struct genl_info *info)
2826{
2827 struct devlink *devlink = info->user_ptr[0];
2828
2829 if (list_empty(&devlink->resource_list))
2830 return -EOPNOTSUPP;
2831
2832 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2833}
2834
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002835static int
2836devlink_resources_validate(struct devlink *devlink,
2837 struct devlink_resource *resource,
2838 struct genl_info *info)
2839{
2840 struct list_head *resource_list;
2841 int err = 0;
2842
2843 if (resource)
2844 resource_list = &resource->resource_list;
2845 else
2846 resource_list = &devlink->resource_list;
2847
2848 list_for_each_entry(resource, resource_list, list) {
2849 if (!resource->size_valid)
2850 return -EINVAL;
2851 err = devlink_resources_validate(devlink, resource, info);
2852 if (err)
2853 return err;
2854 }
2855 return err;
2856}
2857
Jiri Pirko070c63f2019-10-03 11:49:39 +02002858static struct net *devlink_netns_get(struct sk_buff *skb,
2859 struct genl_info *info)
2860{
2861 struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID];
2862 struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD];
2863 struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID];
2864 struct net *net;
2865
2866 if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) {
Jiri Pirko054eae82020-03-28 19:25:29 +01002867 NL_SET_ERR_MSG_MOD(info->extack, "multiple netns identifying attributes specified");
Jiri Pirko070c63f2019-10-03 11:49:39 +02002868 return ERR_PTR(-EINVAL);
2869 }
2870
2871 if (netns_pid_attr) {
2872 net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr));
2873 } else if (netns_fd_attr) {
2874 net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr));
2875 } else if (netns_id_attr) {
2876 net = get_net_ns_by_id(sock_net(skb->sk),
2877 nla_get_u32(netns_id_attr));
2878 if (!net)
2879 net = ERR_PTR(-EINVAL);
2880 } else {
2881 WARN_ON(1);
2882 net = ERR_PTR(-EINVAL);
2883 }
2884 if (IS_ERR(net)) {
Jiri Pirko054eae82020-03-28 19:25:29 +01002885 NL_SET_ERR_MSG_MOD(info->extack, "Unknown network namespace");
Jiri Pirko070c63f2019-10-03 11:49:39 +02002886 return ERR_PTR(-EINVAL);
2887 }
2888 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
2889 put_net(net);
2890 return ERR_PTR(-EPERM);
2891 }
2892 return net;
2893}
2894
2895static void devlink_param_notify(struct devlink *devlink,
2896 unsigned int port_index,
2897 struct devlink_param_item *param_item,
2898 enum devlink_command cmd);
2899
2900static void devlink_reload_netns_change(struct devlink *devlink,
2901 struct net *dest_net)
2902{
2903 struct devlink_param_item *param_item;
2904
2905 /* Userspace needs to be notified about devlink objects
2906 * removed from original and entering new network namespace.
2907 * The rest of the devlink objects are re-created during
2908 * reload process so the notifications are generated separatelly.
2909 */
2910
2911 list_for_each_entry(param_item, &devlink->param_list, list)
2912 devlink_param_notify(devlink, 0, param_item,
2913 DEVLINK_CMD_PARAM_DEL);
2914 devlink_notify(devlink, DEVLINK_CMD_DEL);
2915
Jiri Pirko8273fd82019-10-05 08:10:31 +02002916 __devlink_net_set(devlink, dest_net);
Jiri Pirko070c63f2019-10-03 11:49:39 +02002917
2918 devlink_notify(devlink, DEVLINK_CMD_NEW);
2919 list_for_each_entry(param_item, &devlink->param_list, list)
2920 devlink_param_notify(devlink, 0, param_item,
2921 DEVLINK_CMD_PARAM_NEW);
2922}
2923
Jiri Pirko97691062019-09-12 10:49:45 +02002924static bool devlink_reload_supported(struct devlink *devlink)
2925{
2926 return devlink->ops->reload_down && devlink->ops->reload_up;
2927}
2928
Jiri Pirko2670ac22019-09-12 10:49:46 +02002929static void devlink_reload_failed_set(struct devlink *devlink,
2930 bool reload_failed)
2931{
2932 if (devlink->reload_failed == reload_failed)
2933 return;
2934 devlink->reload_failed = reload_failed;
2935 devlink_notify(devlink, DEVLINK_CMD_NEW);
2936}
2937
2938bool devlink_is_reload_failed(const struct devlink *devlink)
2939{
2940 return devlink->reload_failed;
2941}
2942EXPORT_SYMBOL_GPL(devlink_is_reload_failed);
2943
Jiri Pirko070c63f2019-10-03 11:49:39 +02002944static int devlink_reload(struct devlink *devlink, struct net *dest_net,
2945 struct netlink_ext_ack *extack)
2946{
2947 int err;
2948
Jiri Pirkoa0c76342019-11-08 21:42:43 +01002949 if (!devlink->reload_enabled)
2950 return -EOPNOTSUPP;
2951
Jiri Pirko070c63f2019-10-03 11:49:39 +02002952 err = devlink->ops->reload_down(devlink, !!dest_net, extack);
2953 if (err)
2954 return err;
2955
2956 if (dest_net && !net_eq(dest_net, devlink_net(devlink)))
2957 devlink_reload_netns_change(devlink, dest_net);
2958
2959 err = devlink->ops->reload_up(devlink, extack);
2960 devlink_reload_failed_set(devlink, !!err);
2961 return err;
2962}
2963
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002964static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2965{
2966 struct devlink *devlink = info->user_ptr[0];
Jiri Pirko070c63f2019-10-03 11:49:39 +02002967 struct net *dest_net = NULL;
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002968 int err;
2969
Jiri Pirko5a508a22019-11-09 11:29:46 +01002970 if (!devlink_reload_supported(devlink) || !devlink->reload_enabled)
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002971 return -EOPNOTSUPP;
2972
2973 err = devlink_resources_validate(devlink, NULL, info);
2974 if (err) {
2975 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2976 return err;
2977 }
Jiri Pirko070c63f2019-10-03 11:49:39 +02002978
2979 if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
2980 info->attrs[DEVLINK_ATTR_NETNS_FD] ||
2981 info->attrs[DEVLINK_ATTR_NETNS_ID]) {
2982 dest_net = devlink_netns_get(skb, info);
2983 if (IS_ERR(dest_net))
2984 return PTR_ERR(dest_net);
2985 }
2986
2987 err = devlink_reload(devlink, dest_net, info->extack);
2988
2989 if (dest_net)
2990 put_net(dest_net);
2991
Jiri Pirko2670ac22019-09-12 10:49:46 +02002992 return err;
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002993}
2994
Jiri Pirko191ed202019-06-04 15:40:40 +02002995static int devlink_nl_flash_update_fill(struct sk_buff *msg,
2996 struct devlink *devlink,
2997 enum devlink_command cmd,
2998 const char *status_msg,
2999 const char *component,
3000 unsigned long done, unsigned long total)
3001{
3002 void *hdr;
3003
3004 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3005 if (!hdr)
3006 return -EMSGSIZE;
3007
3008 if (devlink_nl_put_handle(msg, devlink))
3009 goto nla_put_failure;
3010
3011 if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
3012 goto out;
3013
3014 if (status_msg &&
3015 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
3016 status_msg))
3017 goto nla_put_failure;
3018 if (component &&
3019 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
3020 component))
3021 goto nla_put_failure;
3022 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
3023 done, DEVLINK_ATTR_PAD))
3024 goto nla_put_failure;
3025 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
3026 total, DEVLINK_ATTR_PAD))
3027 goto nla_put_failure;
3028
3029out:
3030 genlmsg_end(msg, hdr);
3031 return 0;
3032
3033nla_put_failure:
3034 genlmsg_cancel(msg, hdr);
3035 return -EMSGSIZE;
3036}
3037
3038static void __devlink_flash_update_notify(struct devlink *devlink,
3039 enum devlink_command cmd,
3040 const char *status_msg,
3041 const char *component,
3042 unsigned long done,
3043 unsigned long total)
3044{
3045 struct sk_buff *msg;
3046 int err;
3047
3048 WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
3049 cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
3050 cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
3051
3052 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3053 if (!msg)
3054 return;
3055
3056 err = devlink_nl_flash_update_fill(msg, devlink, cmd, status_msg,
3057 component, done, total);
3058 if (err)
3059 goto out_free_msg;
3060
3061 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3062 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3063 return;
3064
3065out_free_msg:
3066 nlmsg_free(msg);
3067}
3068
3069void devlink_flash_update_begin_notify(struct devlink *devlink)
3070{
3071 __devlink_flash_update_notify(devlink,
3072 DEVLINK_CMD_FLASH_UPDATE,
3073 NULL, NULL, 0, 0);
3074}
3075EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
3076
3077void devlink_flash_update_end_notify(struct devlink *devlink)
3078{
3079 __devlink_flash_update_notify(devlink,
3080 DEVLINK_CMD_FLASH_UPDATE_END,
3081 NULL, NULL, 0, 0);
3082}
3083EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
3084
3085void devlink_flash_update_status_notify(struct devlink *devlink,
3086 const char *status_msg,
3087 const char *component,
3088 unsigned long done,
3089 unsigned long total)
3090{
3091 __devlink_flash_update_notify(devlink,
3092 DEVLINK_CMD_FLASH_UPDATE_STATUS,
3093 status_msg, component, done, total);
3094}
3095EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
3096
Jakub Kicinski76726cc2019-02-14 13:40:44 -08003097static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
3098 struct genl_info *info)
3099{
3100 struct devlink *devlink = info->user_ptr[0];
3101 const char *file_name, *component;
3102 struct nlattr *nla_component;
3103
3104 if (!devlink->ops->flash_update)
3105 return -EOPNOTSUPP;
3106
3107 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
3108 return -EINVAL;
3109 file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
3110
3111 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
3112 component = nla_component ? nla_data(nla_component) : NULL;
3113
3114 return devlink->ops->flash_update(devlink, file_name, component,
3115 info->extack);
3116}
3117
Moshe Shemesh036467c2018-07-04 14:30:33 +03003118static const struct devlink_param devlink_param_generic[] = {
3119 {
3120 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
3121 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
3122 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
3123 },
3124 {
3125 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
3126 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
3127 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
3128 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03003129 {
3130 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
3131 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
3132 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
3133 },
Alex Veskerf6a698852018-07-12 15:13:17 +03003134 {
3135 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
3136 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
3137 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
3138 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05303139 {
3140 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
3141 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
3142 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
3143 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05303144 {
3145 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
3146 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
3147 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
3148 },
Vasundhara Volam16511782018-10-04 11:13:46 +05303149 {
3150 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
3151 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
3152 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
3153 },
Shalom Toledo846e9802018-12-03 07:58:59 +00003154 {
3155 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
3156 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
3157 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
3158 },
Dirk van der Merwe5bbd21d2019-09-09 00:54:18 +01003159 {
3160 .id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
3161 .name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
3162 .type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
3163 },
Michael Guralnik6c7295e2019-11-08 23:45:20 +00003164 {
3165 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
3166 .name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
3167 .type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
3168 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03003169};
Moshe Shemesheabaef12018-07-04 14:30:28 +03003170
3171static int devlink_param_generic_verify(const struct devlink_param *param)
3172{
3173 /* verify it match generic parameter by id and name */
3174 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
3175 return -EINVAL;
3176 if (strcmp(param->name, devlink_param_generic[param->id].name))
3177 return -ENOENT;
3178
3179 WARN_ON(param->type != devlink_param_generic[param->id].type);
3180
3181 return 0;
3182}
3183
3184static int devlink_param_driver_verify(const struct devlink_param *param)
3185{
3186 int i;
3187
3188 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
3189 return -EINVAL;
3190 /* verify no such name in generic params */
3191 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
3192 if (!strcmp(param->name, devlink_param_generic[i].name))
3193 return -EEXIST;
3194
3195 return 0;
3196}
3197
3198static struct devlink_param_item *
3199devlink_param_find_by_name(struct list_head *param_list,
3200 const char *param_name)
3201{
3202 struct devlink_param_item *param_item;
3203
3204 list_for_each_entry(param_item, param_list, list)
3205 if (!strcmp(param_item->param->name, param_name))
3206 return param_item;
3207 return NULL;
3208}
3209
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03003210static struct devlink_param_item *
3211devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
3212{
3213 struct devlink_param_item *param_item;
3214
3215 list_for_each_entry(param_item, param_list, list)
3216 if (param_item->param->id == param_id)
3217 return param_item;
3218 return NULL;
3219}
3220
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003221static bool
3222devlink_param_cmode_is_supported(const struct devlink_param *param,
3223 enum devlink_param_cmode cmode)
3224{
3225 return test_bit(cmode, &param->supported_cmodes);
3226}
3227
3228static int devlink_param_get(struct devlink *devlink,
3229 const struct devlink_param *param,
3230 struct devlink_param_gset_ctx *ctx)
3231{
3232 if (!param->get)
3233 return -EOPNOTSUPP;
3234 return param->get(devlink, param->id, ctx);
3235}
3236
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003237static int devlink_param_set(struct devlink *devlink,
3238 const struct devlink_param *param,
3239 struct devlink_param_gset_ctx *ctx)
3240{
3241 if (!param->set)
3242 return -EOPNOTSUPP;
3243 return param->set(devlink, param->id, ctx);
3244}
3245
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003246static int
3247devlink_param_type_to_nla_type(enum devlink_param_type param_type)
3248{
3249 switch (param_type) {
3250 case DEVLINK_PARAM_TYPE_U8:
3251 return NLA_U8;
3252 case DEVLINK_PARAM_TYPE_U16:
3253 return NLA_U16;
3254 case DEVLINK_PARAM_TYPE_U32:
3255 return NLA_U32;
3256 case DEVLINK_PARAM_TYPE_STRING:
3257 return NLA_STRING;
3258 case DEVLINK_PARAM_TYPE_BOOL:
3259 return NLA_FLAG;
3260 default:
3261 return -EINVAL;
3262 }
3263}
3264
3265static int
3266devlink_nl_param_value_fill_one(struct sk_buff *msg,
3267 enum devlink_param_type type,
3268 enum devlink_param_cmode cmode,
3269 union devlink_param_value val)
3270{
3271 struct nlattr *param_value_attr;
3272
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003273 param_value_attr = nla_nest_start_noflag(msg,
3274 DEVLINK_ATTR_PARAM_VALUE);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003275 if (!param_value_attr)
3276 goto nla_put_failure;
3277
3278 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
3279 goto value_nest_cancel;
3280
3281 switch (type) {
3282 case DEVLINK_PARAM_TYPE_U8:
3283 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
3284 goto value_nest_cancel;
3285 break;
3286 case DEVLINK_PARAM_TYPE_U16:
3287 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
3288 goto value_nest_cancel;
3289 break;
3290 case DEVLINK_PARAM_TYPE_U32:
3291 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
3292 goto value_nest_cancel;
3293 break;
3294 case DEVLINK_PARAM_TYPE_STRING:
3295 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
3296 val.vstr))
3297 goto value_nest_cancel;
3298 break;
3299 case DEVLINK_PARAM_TYPE_BOOL:
3300 if (val.vbool &&
3301 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
3302 goto value_nest_cancel;
3303 break;
3304 }
3305
3306 nla_nest_end(msg, param_value_attr);
3307 return 0;
3308
3309value_nest_cancel:
3310 nla_nest_cancel(msg, param_value_attr);
3311nla_put_failure:
3312 return -EMSGSIZE;
3313}
3314
3315static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303316 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003317 struct devlink_param_item *param_item,
3318 enum devlink_command cmd,
3319 u32 portid, u32 seq, int flags)
3320{
3321 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003322 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003323 const struct devlink_param *param = param_item->param;
3324 struct devlink_param_gset_ctx ctx;
3325 struct nlattr *param_values_list;
3326 struct nlattr *param_attr;
3327 int nla_type;
3328 void *hdr;
3329 int err;
3330 int i;
3331
3332 /* Get value from driver part to driverinit configuration mode */
3333 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3334 if (!devlink_param_cmode_is_supported(param, i))
3335 continue;
3336 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3337 if (!param_item->driverinit_value_valid)
3338 return -EOPNOTSUPP;
3339 param_value[i] = param_item->driverinit_value;
3340 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003341 if (!param_item->published)
3342 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003343 ctx.cmode = i;
3344 err = devlink_param_get(devlink, param, &ctx);
3345 if (err)
3346 return err;
3347 param_value[i] = ctx.val;
3348 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003349 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003350 }
3351
3352 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3353 if (!hdr)
3354 return -EMSGSIZE;
3355
3356 if (devlink_nl_put_handle(msg, devlink))
3357 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303358
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303359 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3360 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3361 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303362 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3363 goto genlmsg_cancel;
3364
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003365 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003366 if (!param_attr)
3367 goto genlmsg_cancel;
3368 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3369 goto param_nest_cancel;
3370 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3371 goto param_nest_cancel;
3372
3373 nla_type = devlink_param_type_to_nla_type(param->type);
3374 if (nla_type < 0)
3375 goto param_nest_cancel;
3376 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3377 goto param_nest_cancel;
3378
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003379 param_values_list = nla_nest_start_noflag(msg,
3380 DEVLINK_ATTR_PARAM_VALUES_LIST);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003381 if (!param_values_list)
3382 goto param_nest_cancel;
3383
3384 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003385 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003386 continue;
3387 err = devlink_nl_param_value_fill_one(msg, param->type,
3388 i, param_value[i]);
3389 if (err)
3390 goto values_list_nest_cancel;
3391 }
3392
3393 nla_nest_end(msg, param_values_list);
3394 nla_nest_end(msg, param_attr);
3395 genlmsg_end(msg, hdr);
3396 return 0;
3397
3398values_list_nest_cancel:
3399 nla_nest_end(msg, param_values_list);
3400param_nest_cancel:
3401 nla_nest_cancel(msg, param_attr);
3402genlmsg_cancel:
3403 genlmsg_cancel(msg, hdr);
3404 return -EMSGSIZE;
3405}
3406
Moshe Shemeshea601e12018-07-04 14:30:32 +03003407static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303408 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03003409 struct devlink_param_item *param_item,
3410 enum devlink_command cmd)
3411{
3412 struct sk_buff *msg;
3413 int err;
3414
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303415 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3416 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3417 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003418
3419 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3420 if (!msg)
3421 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303422 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3423 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003424 if (err) {
3425 nlmsg_free(msg);
3426 return;
3427 }
3428
3429 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3430 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3431}
3432
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003433static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3434 struct netlink_callback *cb)
3435{
3436 struct devlink_param_item *param_item;
3437 struct devlink *devlink;
3438 int start = cb->args[0];
3439 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003440 int err = 0;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003441
3442 mutex_lock(&devlink_mutex);
3443 list_for_each_entry(devlink, &devlink_list, list) {
3444 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3445 continue;
3446 mutex_lock(&devlink->lock);
3447 list_for_each_entry(param_item, &devlink->param_list, list) {
3448 if (idx < start) {
3449 idx++;
3450 continue;
3451 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303452 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003453 DEVLINK_CMD_PARAM_GET,
3454 NETLINK_CB(cb->skb).portid,
3455 cb->nlh->nlmsg_seq,
3456 NLM_F_MULTI);
Vasundhara Volam93c2fcb2019-09-30 11:52:21 +05303457 if (err && err != -EOPNOTSUPP) {
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003458 mutex_unlock(&devlink->lock);
3459 goto out;
3460 }
3461 idx++;
3462 }
3463 mutex_unlock(&devlink->lock);
3464 }
3465out:
3466 mutex_unlock(&devlink_mutex);
3467
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003468 if (err != -EMSGSIZE)
3469 return err;
3470
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003471 cb->args[0] = idx;
3472 return msg->len;
3473}
3474
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003475static int
3476devlink_param_type_get_from_info(struct genl_info *info,
3477 enum devlink_param_type *param_type)
3478{
3479 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3480 return -EINVAL;
3481
3482 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3483 case NLA_U8:
3484 *param_type = DEVLINK_PARAM_TYPE_U8;
3485 break;
3486 case NLA_U16:
3487 *param_type = DEVLINK_PARAM_TYPE_U16;
3488 break;
3489 case NLA_U32:
3490 *param_type = DEVLINK_PARAM_TYPE_U32;
3491 break;
3492 case NLA_STRING:
3493 *param_type = DEVLINK_PARAM_TYPE_STRING;
3494 break;
3495 case NLA_FLAG:
3496 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3497 break;
3498 default:
3499 return -EINVAL;
3500 }
3501
3502 return 0;
3503}
3504
3505static int
3506devlink_param_value_get_from_info(const struct devlink_param *param,
3507 struct genl_info *info,
3508 union devlink_param_value *value)
3509{
Jakub Kicinski87509392020-03-02 21:05:11 -08003510 struct nlattr *param_data;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003511 int len;
3512
Jakub Kicinski87509392020-03-02 21:05:11 -08003513 param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
3514
3515 if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003516 return -EINVAL;
3517
3518 switch (param->type) {
3519 case DEVLINK_PARAM_TYPE_U8:
Jakub Kicinski87509392020-03-02 21:05:11 -08003520 if (nla_len(param_data) != sizeof(u8))
3521 return -EINVAL;
3522 value->vu8 = nla_get_u8(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003523 break;
3524 case DEVLINK_PARAM_TYPE_U16:
Jakub Kicinski87509392020-03-02 21:05:11 -08003525 if (nla_len(param_data) != sizeof(u16))
3526 return -EINVAL;
3527 value->vu16 = nla_get_u16(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003528 break;
3529 case DEVLINK_PARAM_TYPE_U32:
Jakub Kicinski87509392020-03-02 21:05:11 -08003530 if (nla_len(param_data) != sizeof(u32))
3531 return -EINVAL;
3532 value->vu32 = nla_get_u32(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003533 break;
3534 case DEVLINK_PARAM_TYPE_STRING:
Jakub Kicinski87509392020-03-02 21:05:11 -08003535 len = strnlen(nla_data(param_data), nla_len(param_data));
3536 if (len == nla_len(param_data) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003537 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003538 return -EINVAL;
Jakub Kicinski87509392020-03-02 21:05:11 -08003539 strcpy(value->vstr, nla_data(param_data));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003540 break;
3541 case DEVLINK_PARAM_TYPE_BOOL:
Jakub Kicinski87509392020-03-02 21:05:11 -08003542 if (param_data && nla_len(param_data))
3543 return -EINVAL;
3544 value->vbool = nla_get_flag(param_data);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003545 break;
3546 }
3547 return 0;
3548}
3549
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003550static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303551devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003552 struct genl_info *info)
3553{
3554 char *param_name;
3555
3556 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3557 return NULL;
3558
3559 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303560 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003561}
3562
3563static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3564 struct genl_info *info)
3565{
3566 struct devlink *devlink = info->user_ptr[0];
3567 struct devlink_param_item *param_item;
3568 struct sk_buff *msg;
3569 int err;
3570
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303571 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003572 if (!param_item)
3573 return -EINVAL;
3574
3575 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3576 if (!msg)
3577 return -ENOMEM;
3578
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303579 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003580 DEVLINK_CMD_PARAM_GET,
3581 info->snd_portid, info->snd_seq, 0);
3582 if (err) {
3583 nlmsg_free(msg);
3584 return err;
3585 }
3586
3587 return genlmsg_reply(msg, info);
3588}
3589
Vasundhara Volam9c548732019-01-28 18:00:22 +05303590static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303591 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303592 struct list_head *param_list,
3593 struct genl_info *info,
3594 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003595{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003596 enum devlink_param_type param_type;
3597 struct devlink_param_gset_ctx ctx;
3598 enum devlink_param_cmode cmode;
3599 struct devlink_param_item *param_item;
3600 const struct devlink_param *param;
3601 union devlink_param_value value;
3602 int err = 0;
3603
Vasundhara Volam9c548732019-01-28 18:00:22 +05303604 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003605 if (!param_item)
3606 return -EINVAL;
3607 param = param_item->param;
3608 err = devlink_param_type_get_from_info(info, &param_type);
3609 if (err)
3610 return err;
3611 if (param_type != param->type)
3612 return -EINVAL;
3613 err = devlink_param_value_get_from_info(param, info, &value);
3614 if (err)
3615 return err;
3616 if (param->validate) {
3617 err = param->validate(devlink, param->id, value, info->extack);
3618 if (err)
3619 return err;
3620 }
3621
3622 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3623 return -EINVAL;
3624 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3625 if (!devlink_param_cmode_is_supported(param, cmode))
3626 return -EOPNOTSUPP;
3627
3628 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003629 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3630 strcpy(param_item->driverinit_value.vstr, value.vstr);
3631 else
3632 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003633 param_item->driverinit_value_valid = true;
3634 } else {
3635 if (!param->set)
3636 return -EOPNOTSUPP;
3637 ctx.val = value;
3638 ctx.cmode = cmode;
3639 err = devlink_param_set(devlink, param, &ctx);
3640 if (err)
3641 return err;
3642 }
3643
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303644 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003645 return 0;
3646}
3647
Vasundhara Volam9c548732019-01-28 18:00:22 +05303648static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3649 struct genl_info *info)
3650{
3651 struct devlink *devlink = info->user_ptr[0];
3652
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303653 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303654 info, DEVLINK_CMD_PARAM_NEW);
3655}
3656
Moshe Shemesheabaef12018-07-04 14:30:28 +03003657static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303658 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303659 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303660 const struct devlink_param *param,
3661 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003662{
3663 struct devlink_param_item *param_item;
3664
Vasundhara Volam39e61602019-01-28 18:00:20 +05303665 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03003666 return -EEXIST;
3667
3668 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3669 WARN_ON(param->get || param->set);
3670 else
3671 WARN_ON(!param->get || !param->set);
3672
3673 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3674 if (!param_item)
3675 return -ENOMEM;
3676 param_item->param = param;
3677
Vasundhara Volam39e61602019-01-28 18:00:20 +05303678 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303679 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003680 return 0;
3681}
3682
3683static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303684 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303685 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303686 const struct devlink_param *param,
3687 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003688{
3689 struct devlink_param_item *param_item;
3690
Vasundhara Volam39e61602019-01-28 18:00:20 +05303691 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003692 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303693 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003694 list_del(&param_item->list);
3695 kfree(param_item);
3696}
3697
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303698static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3699 struct netlink_callback *cb)
3700{
3701 struct devlink_param_item *param_item;
3702 struct devlink_port *devlink_port;
3703 struct devlink *devlink;
3704 int start = cb->args[0];
3705 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003706 int err = 0;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303707
3708 mutex_lock(&devlink_mutex);
3709 list_for_each_entry(devlink, &devlink_list, list) {
3710 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3711 continue;
3712 mutex_lock(&devlink->lock);
3713 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3714 list_for_each_entry(param_item,
3715 &devlink_port->param_list, list) {
3716 if (idx < start) {
3717 idx++;
3718 continue;
3719 }
3720 err = devlink_nl_param_fill(msg,
3721 devlink_port->devlink,
3722 devlink_port->index, param_item,
3723 DEVLINK_CMD_PORT_PARAM_GET,
3724 NETLINK_CB(cb->skb).portid,
3725 cb->nlh->nlmsg_seq,
3726 NLM_F_MULTI);
Vasundhara Volam93c2fcb2019-09-30 11:52:21 +05303727 if (err && err != -EOPNOTSUPP) {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303728 mutex_unlock(&devlink->lock);
3729 goto out;
3730 }
3731 idx++;
3732 }
3733 }
3734 mutex_unlock(&devlink->lock);
3735 }
3736out:
3737 mutex_unlock(&devlink_mutex);
3738
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02003739 if (err != -EMSGSIZE)
3740 return err;
3741
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303742 cb->args[0] = idx;
3743 return msg->len;
3744}
3745
3746static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3747 struct genl_info *info)
3748{
3749 struct devlink_port *devlink_port = info->user_ptr[0];
3750 struct devlink_param_item *param_item;
3751 struct sk_buff *msg;
3752 int err;
3753
3754 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3755 info);
3756 if (!param_item)
3757 return -EINVAL;
3758
3759 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3760 if (!msg)
3761 return -ENOMEM;
3762
3763 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3764 devlink_port->index, param_item,
3765 DEVLINK_CMD_PORT_PARAM_GET,
3766 info->snd_portid, info->snd_seq, 0);
3767 if (err) {
3768 nlmsg_free(msg);
3769 return err;
3770 }
3771
3772 return genlmsg_reply(msg, info);
3773}
3774
Vasundhara Volam9c548732019-01-28 18:00:22 +05303775static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3776 struct genl_info *info)
3777{
3778 struct devlink_port *devlink_port = info->user_ptr[0];
3779
3780 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303781 devlink_port->index,
3782 &devlink_port->param_list, info,
3783 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05303784}
3785
Alex Veskera006d462018-07-12 15:13:12 +03003786static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3787 struct devlink *devlink,
3788 struct devlink_snapshot *snapshot)
3789{
3790 struct nlattr *snap_attr;
3791 int err;
3792
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003793 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
Alex Veskera006d462018-07-12 15:13:12 +03003794 if (!snap_attr)
3795 return -EINVAL;
3796
3797 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3798 if (err)
3799 goto nla_put_failure;
3800
3801 nla_nest_end(msg, snap_attr);
3802 return 0;
3803
3804nla_put_failure:
3805 nla_nest_cancel(msg, snap_attr);
3806 return err;
3807}
3808
3809static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3810 struct devlink *devlink,
3811 struct devlink_region *region)
3812{
3813 struct devlink_snapshot *snapshot;
3814 struct nlattr *snapshots_attr;
3815 int err;
3816
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003817 snapshots_attr = nla_nest_start_noflag(msg,
3818 DEVLINK_ATTR_REGION_SNAPSHOTS);
Alex Veskera006d462018-07-12 15:13:12 +03003819 if (!snapshots_attr)
3820 return -EINVAL;
3821
3822 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3823 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3824 if (err)
3825 goto nla_put_failure;
3826 }
3827
3828 nla_nest_end(msg, snapshots_attr);
3829 return 0;
3830
3831nla_put_failure:
3832 nla_nest_cancel(msg, snapshots_attr);
3833 return err;
3834}
3835
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003836static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3837 enum devlink_command cmd, u32 portid,
3838 u32 seq, int flags,
3839 struct devlink_region *region)
3840{
3841 void *hdr;
3842 int err;
3843
3844 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3845 if (!hdr)
3846 return -EMSGSIZE;
3847
3848 err = devlink_nl_put_handle(msg, devlink);
3849 if (err)
3850 goto nla_put_failure;
3851
Jacob Kellere8937682020-03-26 11:37:08 -07003852 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003853 if (err)
3854 goto nla_put_failure;
3855
3856 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3857 region->size,
3858 DEVLINK_ATTR_PAD);
3859 if (err)
3860 goto nla_put_failure;
3861
Alex Veskera006d462018-07-12 15:13:12 +03003862 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3863 if (err)
3864 goto nla_put_failure;
3865
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003866 genlmsg_end(msg, hdr);
3867 return 0;
3868
3869nla_put_failure:
3870 genlmsg_cancel(msg, hdr);
3871 return err;
3872}
3873
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003874static struct sk_buff *
3875devlink_nl_region_notify_build(struct devlink_region *region,
3876 struct devlink_snapshot *snapshot,
3877 enum devlink_command cmd, u32 portid, u32 seq)
Alex Vesker866319b2018-07-12 15:13:13 +03003878{
3879 struct devlink *devlink = region->devlink;
3880 struct sk_buff *msg;
3881 void *hdr;
3882 int err;
3883
Alex Vesker866319b2018-07-12 15:13:13 +03003884
3885 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3886 if (!msg)
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003887 return ERR_PTR(-ENOMEM);
Alex Vesker866319b2018-07-12 15:13:13 +03003888
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003889 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
3890 if (!hdr) {
3891 err = -EMSGSIZE;
Alex Vesker866319b2018-07-12 15:13:13 +03003892 goto out_free_msg;
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003893 }
Alex Vesker866319b2018-07-12 15:13:13 +03003894
3895 err = devlink_nl_put_handle(msg, devlink);
3896 if (err)
3897 goto out_cancel_msg;
3898
3899 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
Jacob Kellere8937682020-03-26 11:37:08 -07003900 region->ops->name);
Alex Vesker866319b2018-07-12 15:13:13 +03003901 if (err)
3902 goto out_cancel_msg;
3903
3904 if (snapshot) {
3905 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3906 snapshot->id);
3907 if (err)
3908 goto out_cancel_msg;
3909 } else {
3910 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3911 region->size, DEVLINK_ATTR_PAD);
3912 if (err)
3913 goto out_cancel_msg;
3914 }
3915 genlmsg_end(msg, hdr);
3916
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003917 return msg;
Alex Vesker866319b2018-07-12 15:13:13 +03003918
3919out_cancel_msg:
3920 genlmsg_cancel(msg, hdr);
3921out_free_msg:
3922 nlmsg_free(msg);
Jakub Kicinskidd86fec2020-05-01 09:40:40 -07003923 return ERR_PTR(err);
3924}
3925
3926static void devlink_nl_region_notify(struct devlink_region *region,
3927 struct devlink_snapshot *snapshot,
3928 enum devlink_command cmd)
3929{
3930 struct devlink *devlink = region->devlink;
3931 struct sk_buff *msg;
3932
3933 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3934
3935 msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
3936 if (IS_ERR(msg))
3937 return;
3938
3939 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3940 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
Alex Vesker866319b2018-07-12 15:13:13 +03003941}
3942
Jacob Kellercf80fae2020-03-26 11:37:11 -07003943/**
Jacob Keller12102432020-03-26 11:37:15 -07003944 * __devlink_snapshot_id_increment - Increment number of snapshots using an id
3945 * @devlink: devlink instance
3946 * @id: the snapshot id
3947 *
3948 * Track when a new snapshot begins using an id. Load the count for the
3949 * given id from the snapshot xarray, increment it, and store it back.
3950 *
3951 * Called when a new snapshot is created with the given id.
3952 *
3953 * The id *must* have been previously allocated by
3954 * devlink_region_snapshot_id_get().
3955 *
3956 * Returns 0 on success, or an error on failure.
3957 */
3958static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
3959{
3960 unsigned long count;
3961 void *p;
3962
3963 lockdep_assert_held(&devlink->lock);
3964
3965 p = xa_load(&devlink->snapshot_ids, id);
3966 if (WARN_ON(!p))
3967 return -EINVAL;
3968
3969 if (WARN_ON(!xa_is_value(p)))
3970 return -EINVAL;
3971
3972 count = xa_to_value(p);
3973 count++;
3974
3975 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
3976 GFP_KERNEL));
3977}
3978
3979/**
3980 * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
3981 * @devlink: devlink instance
3982 * @id: the snapshot id
3983 *
3984 * Track when a snapshot is deleted and stops using an id. Load the count
3985 * for the given id from the snapshot xarray, decrement it, and store it
3986 * back.
3987 *
3988 * If the count reaches zero, erase this id from the xarray, freeing it
3989 * up for future re-use by devlink_region_snapshot_id_get().
3990 *
3991 * Called when a snapshot using the given id is deleted, and when the
3992 * initial allocator of the id is finished using it.
3993 */
3994static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
3995{
3996 unsigned long count;
3997 void *p;
3998
3999 lockdep_assert_held(&devlink->lock);
4000
4001 p = xa_load(&devlink->snapshot_ids, id);
4002 if (WARN_ON(!p))
4003 return;
4004
4005 if (WARN_ON(!xa_is_value(p)))
4006 return;
4007
4008 count = xa_to_value(p);
4009
4010 if (count > 1) {
4011 count--;
4012 xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
4013 GFP_KERNEL);
4014 } else {
4015 /* If this was the last user, we can erase this id */
4016 xa_erase(&devlink->snapshot_ids, id);
4017 }
4018}
4019
4020/**
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004021 * __devlink_snapshot_id_insert - Insert a specific snapshot ID
4022 * @devlink: devlink instance
4023 * @id: the snapshot id
4024 *
4025 * Mark the given snapshot id as used by inserting a zero value into the
4026 * snapshot xarray.
4027 *
4028 * This must be called while holding the devlink instance lock. Unlike
4029 * devlink_snapshot_id_get, the initial reference count is zero, not one.
4030 * It is expected that the id will immediately be used before
4031 * releasing the devlink instance lock.
4032 *
4033 * Returns zero on success, or an error code if the snapshot id could not
4034 * be inserted.
4035 */
4036static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
4037{
4038 lockdep_assert_held(&devlink->lock);
4039
4040 if (WARN_ON(xa_load(&devlink->snapshot_ids, id)))
4041 return -EEXIST;
4042
4043 return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
4044 GFP_KERNEL));
4045}
4046
4047/**
Jacob Keller70001082020-03-26 11:37:13 -07004048 * __devlink_region_snapshot_id_get - get snapshot ID
4049 * @devlink: devlink instance
Jacob Keller7ef19d32020-03-26 11:37:14 -07004050 * @id: storage to return snapshot id
Jacob Keller70001082020-03-26 11:37:13 -07004051 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07004052 * Allocates a new snapshot id. Returns zero on success, or a negative
4053 * error on failure. Must be called while holding the devlink instance
4054 * lock.
Jacob Keller12102432020-03-26 11:37:15 -07004055 *
4056 * Snapshot IDs are tracked using an xarray which stores the number of
4057 * users of the snapshot id.
4058 *
4059 * Note that the caller of this function counts as a 'user', in order to
4060 * avoid race conditions. The caller must release its hold on the
4061 * snapshot by using devlink_region_snapshot_id_put.
Jacob Keller70001082020-03-26 11:37:13 -07004062 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07004063static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Jacob Keller70001082020-03-26 11:37:13 -07004064{
4065 lockdep_assert_held(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07004066
Jacob Keller12102432020-03-26 11:37:15 -07004067 return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
4068 xa_limit_32b, GFP_KERNEL);
Jacob Keller70001082020-03-26 11:37:13 -07004069}
4070
4071/**
Jacob Kellercf80fae2020-03-26 11:37:11 -07004072 * __devlink_region_snapshot_create - create a new snapshot
4073 * This will add a new snapshot of a region. The snapshot
4074 * will be stored on the region struct and can be accessed
4075 * from devlink. This is useful for future analyses of snapshots.
4076 * Multiple snapshots can be created on a region.
4077 * The @snapshot_id should be obtained using the getter function.
4078 *
4079 * Must be called only while holding the devlink instance lock.
4080 *
4081 * @region: devlink region of the snapshot
4082 * @data: snapshot data
4083 * @snapshot_id: snapshot id to be created
4084 */
4085static int
4086__devlink_region_snapshot_create(struct devlink_region *region,
4087 u8 *data, u32 snapshot_id)
4088{
4089 struct devlink *devlink = region->devlink;
4090 struct devlink_snapshot *snapshot;
Jacob Keller12102432020-03-26 11:37:15 -07004091 int err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004092
4093 lockdep_assert_held(&devlink->lock);
4094
4095 /* check if region can hold one more snapshot */
4096 if (region->cur_snapshots == region->max_snapshots)
Jacob Keller47a39f62020-03-26 11:37:12 -07004097 return -ENOSPC;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004098
4099 if (devlink_region_snapshot_get_by_id(region, snapshot_id))
4100 return -EEXIST;
4101
4102 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
4103 if (!snapshot)
4104 return -ENOMEM;
4105
Jacob Keller12102432020-03-26 11:37:15 -07004106 err = __devlink_snapshot_id_increment(devlink, snapshot_id);
4107 if (err)
4108 goto err_snapshot_id_increment;
4109
Jacob Kellercf80fae2020-03-26 11:37:11 -07004110 snapshot->id = snapshot_id;
4111 snapshot->region = region;
4112 snapshot->data = data;
4113
4114 list_add_tail(&snapshot->list, &region->snapshot_list);
4115
4116 region->cur_snapshots++;
4117
4118 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
4119 return 0;
Jacob Keller12102432020-03-26 11:37:15 -07004120
4121err_snapshot_id_increment:
4122 kfree(snapshot);
4123 return err;
Jacob Kellercf80fae2020-03-26 11:37:11 -07004124}
4125
Jiri Pirko92b49822019-08-12 14:28:31 +02004126static void devlink_region_snapshot_del(struct devlink_region *region,
4127 struct devlink_snapshot *snapshot)
4128{
Jacob Keller12102432020-03-26 11:37:15 -07004129 struct devlink *devlink = region->devlink;
4130
4131 lockdep_assert_held(&devlink->lock);
4132
Jiri Pirko92b49822019-08-12 14:28:31 +02004133 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
4134 region->cur_snapshots--;
4135 list_del(&snapshot->list);
Jacob Kellera0a09f62020-03-26 11:37:09 -07004136 region->ops->destructor(snapshot->data);
Jacob Keller12102432020-03-26 11:37:15 -07004137 __devlink_snapshot_id_decrement(devlink, snapshot->id);
Jiri Pirko92b49822019-08-12 14:28:31 +02004138 kfree(snapshot);
4139}
4140
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004141static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
4142 struct genl_info *info)
4143{
4144 struct devlink *devlink = info->user_ptr[0];
4145 struct devlink_region *region;
4146 const char *region_name;
4147 struct sk_buff *msg;
4148 int err;
4149
4150 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
4151 return -EINVAL;
4152
4153 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4154 region = devlink_region_get_by_name(devlink, region_name);
4155 if (!region)
4156 return -EINVAL;
4157
4158 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4159 if (!msg)
4160 return -ENOMEM;
4161
4162 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
4163 info->snd_portid, info->snd_seq, 0,
4164 region);
4165 if (err) {
4166 nlmsg_free(msg);
4167 return err;
4168 }
4169
4170 return genlmsg_reply(msg, info);
4171}
4172
4173static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
4174 struct netlink_callback *cb)
4175{
4176 struct devlink_region *region;
4177 struct devlink *devlink;
4178 int start = cb->args[0];
4179 int idx = 0;
4180 int err;
4181
4182 mutex_lock(&devlink_mutex);
4183 list_for_each_entry(devlink, &devlink_list, list) {
4184 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4185 continue;
4186
4187 mutex_lock(&devlink->lock);
4188 list_for_each_entry(region, &devlink->region_list, list) {
4189 if (idx < start) {
4190 idx++;
4191 continue;
4192 }
4193 err = devlink_nl_region_fill(msg, devlink,
4194 DEVLINK_CMD_REGION_GET,
4195 NETLINK_CB(cb->skb).portid,
4196 cb->nlh->nlmsg_seq,
4197 NLM_F_MULTI, region);
4198 if (err) {
4199 mutex_unlock(&devlink->lock);
4200 goto out;
4201 }
4202 idx++;
4203 }
4204 mutex_unlock(&devlink->lock);
4205 }
4206out:
4207 mutex_unlock(&devlink_mutex);
4208 cb->args[0] = idx;
4209 return msg->len;
4210}
4211
Alex Vesker866319b2018-07-12 15:13:13 +03004212static int devlink_nl_cmd_region_del(struct sk_buff *skb,
4213 struct genl_info *info)
4214{
4215 struct devlink *devlink = info->user_ptr[0];
4216 struct devlink_snapshot *snapshot;
4217 struct devlink_region *region;
4218 const char *region_name;
4219 u32 snapshot_id;
4220
4221 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
4222 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
4223 return -EINVAL;
4224
4225 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4226 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4227
4228 region = devlink_region_get_by_name(devlink, region_name);
4229 if (!region)
4230 return -EINVAL;
4231
4232 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4233 if (!snapshot)
4234 return -EINVAL;
4235
Jiri Pirko92b49822019-08-12 14:28:31 +02004236 devlink_region_snapshot_del(region, snapshot);
Alex Vesker866319b2018-07-12 15:13:13 +03004237 return 0;
4238}
4239
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004240static int
4241devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
4242{
4243 struct devlink *devlink = info->user_ptr[0];
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004244 struct devlink_snapshot *snapshot;
4245 struct nlattr *snapshot_id_attr;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004246 struct devlink_region *region;
4247 const char *region_name;
4248 u32 snapshot_id;
4249 u8 *data;
4250 int err;
4251
4252 if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) {
4253 NL_SET_ERR_MSG_MOD(info->extack, "No region name provided");
4254 return -EINVAL;
4255 }
4256
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004257 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
4258 region = devlink_region_get_by_name(devlink, region_name);
4259 if (!region) {
4260 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist");
4261 return -EINVAL;
4262 }
4263
4264 if (!region->ops->snapshot) {
4265 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not support taking an immediate snapshot");
4266 return -EOPNOTSUPP;
4267 }
4268
4269 if (region->cur_snapshots == region->max_snapshots) {
4270 NL_SET_ERR_MSG_MOD(info->extack, "The region has reached the maximum number of stored snapshots");
4271 return -ENOSPC;
4272 }
4273
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004274 snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
4275 if (snapshot_id_attr) {
4276 snapshot_id = nla_get_u32(snapshot_id_attr);
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004277
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004278 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
4279 NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
4280 return -EEXIST;
4281 }
4282
4283 err = __devlink_snapshot_id_insert(devlink, snapshot_id);
4284 if (err)
4285 return err;
4286 } else {
4287 err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
4288 if (err) {
4289 NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
4290 return err;
4291 }
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004292 }
4293
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004294 err = region->ops->snapshot(devlink, info->extack, &data);
4295 if (err)
4296 goto err_snapshot_capture;
4297
4298 err = __devlink_region_snapshot_create(region, data, snapshot_id);
4299 if (err)
4300 goto err_snapshot_create;
4301
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004302 if (!snapshot_id_attr) {
4303 struct sk_buff *msg;
4304
4305 snapshot = devlink_region_snapshot_get_by_id(region,
4306 snapshot_id);
4307 if (WARN_ON(!snapshot))
4308 return -EINVAL;
4309
4310 msg = devlink_nl_region_notify_build(region, snapshot,
4311 DEVLINK_CMD_REGION_NEW,
4312 info->snd_portid,
4313 info->snd_seq);
4314 err = PTR_ERR_OR_ZERO(msg);
4315 if (err)
4316 goto err_notify;
4317
4318 err = genlmsg_reply(msg, info);
4319 if (err)
4320 goto err_notify;
4321 }
4322
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004323 return 0;
4324
4325err_snapshot_create:
4326 region->ops->destructor(data);
4327err_snapshot_capture:
4328 __devlink_snapshot_id_decrement(devlink, snapshot_id);
4329 return err;
Jakub Kicinski043b3e22020-05-01 09:40:41 -07004330
4331err_notify:
4332 devlink_region_snapshot_del(region, snapshot);
4333 return err;
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07004334}
4335
Alex Vesker4e547952018-07-12 15:13:14 +03004336static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
4337 struct devlink *devlink,
4338 u8 *chunk, u32 chunk_size,
4339 u64 addr)
4340{
4341 struct nlattr *chunk_attr;
4342 int err;
4343
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004344 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
Alex Vesker4e547952018-07-12 15:13:14 +03004345 if (!chunk_attr)
4346 return -EINVAL;
4347
4348 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
4349 if (err)
4350 goto nla_put_failure;
4351
4352 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
4353 DEVLINK_ATTR_PAD);
4354 if (err)
4355 goto nla_put_failure;
4356
4357 nla_nest_end(msg, chunk_attr);
4358 return 0;
4359
4360nla_put_failure:
4361 nla_nest_cancel(msg, chunk_attr);
4362 return err;
4363}
4364
4365#define DEVLINK_REGION_READ_CHUNK_SIZE 256
4366
4367static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
4368 struct devlink *devlink,
4369 struct devlink_region *region,
4370 struct nlattr **attrs,
4371 u64 start_offset,
4372 u64 end_offset,
Alex Vesker4e547952018-07-12 15:13:14 +03004373 u64 *new_offset)
4374{
4375 struct devlink_snapshot *snapshot;
4376 u64 curr_offset = start_offset;
4377 u32 snapshot_id;
4378 int err = 0;
4379
4380 *new_offset = start_offset;
4381
4382 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
4383 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
4384 if (!snapshot)
4385 return -EINVAL;
4386
Alex Vesker4e547952018-07-12 15:13:14 +03004387 while (curr_offset < end_offset) {
4388 u32 data_size;
4389 u8 *data;
4390
4391 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
4392 data_size = end_offset - curr_offset;
4393 else
4394 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
4395
4396 data = &snapshot->data[curr_offset];
4397 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
4398 data, data_size,
4399 curr_offset);
4400 if (err)
4401 break;
4402
4403 curr_offset += data_size;
4404 }
4405 *new_offset = curr_offset;
4406
4407 return err;
4408}
4409
4410static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
4411 struct netlink_callback *cb)
4412{
Jiri Pirkoee85da52019-10-05 20:04:42 +02004413 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004414 u64 ret_offset, start_offset, end_offset = U64_MAX;
Jiri Pirkoee85da52019-10-05 20:04:42 +02004415 struct nlattr **attrs = info->attrs;
Alex Vesker4e547952018-07-12 15:13:14 +03004416 struct devlink_region *region;
4417 struct nlattr *chunks_attr;
4418 const char *region_name;
4419 struct devlink *devlink;
Alex Vesker4e547952018-07-12 15:13:14 +03004420 void *hdr;
4421 int err;
4422
4423 start_offset = *((u64 *)&cb->args[0]);
4424
Parav Panditdac7c082019-02-12 14:24:08 -06004425 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03004426 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004427 if (IS_ERR(devlink)) {
4428 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06004429 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004430 }
Alex Vesker4e547952018-07-12 15:13:14 +03004431
Alex Vesker4e547952018-07-12 15:13:14 +03004432 mutex_lock(&devlink->lock);
4433
4434 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06004435 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
4436 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004437 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004438 }
Alex Vesker4e547952018-07-12 15:13:14 +03004439
4440 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
4441 region = devlink_region_get_by_name(devlink, region_name);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004442 if (!region) {
4443 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004444 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004445 }
Alex Vesker4e547952018-07-12 15:13:14 +03004446
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004447 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
4448 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
4449 if (!start_offset)
4450 start_offset =
4451 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4452
4453 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
4454 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
4455 }
4456
4457 if (end_offset > region->size)
4458 end_offset = region->size;
4459
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004460 /* return 0 if there is no further data to read */
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004461 if (start_offset == end_offset) {
Jacob Kellerd5b90e92020-02-04 15:59:50 -08004462 err = 0;
4463 goto out_unlock;
4464 }
4465
Alex Vesker4e547952018-07-12 15:13:14 +03004466 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4467 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
4468 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004469 if (!hdr) {
4470 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004471 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004472 }
Alex Vesker4e547952018-07-12 15:13:14 +03004473
4474 err = devlink_nl_put_handle(skb, devlink);
4475 if (err)
4476 goto nla_put_failure;
4477
4478 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
4479 if (err)
4480 goto nla_put_failure;
4481
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004482 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004483 if (!chunks_attr) {
4484 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03004485 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004486 }
Alex Vesker4e547952018-07-12 15:13:14 +03004487
Alex Vesker4e547952018-07-12 15:13:14 +03004488 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
4489 region, attrs,
4490 start_offset,
Jakub Kicinski5a46b062020-05-13 10:28:22 -07004491 end_offset, &ret_offset);
Alex Vesker4e547952018-07-12 15:13:14 +03004492
4493 if (err && err != -EMSGSIZE)
4494 goto nla_put_failure;
4495
4496 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06004497 if (ret_offset == start_offset) {
4498 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03004499 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06004500 }
Alex Vesker4e547952018-07-12 15:13:14 +03004501
4502 *((u64 *)&cb->args[0]) = ret_offset;
4503
4504 nla_nest_end(skb, chunks_attr);
4505 genlmsg_end(skb, hdr);
4506 mutex_unlock(&devlink->lock);
4507 mutex_unlock(&devlink_mutex);
4508
4509 return skb->len;
4510
4511nla_put_failure:
4512 genlmsg_cancel(skb, hdr);
4513out_unlock:
4514 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06004515out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03004516 mutex_unlock(&devlink_mutex);
Parav Panditfdd41ec2019-02-12 14:23:58 -06004517 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03004518}
4519
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004520struct devlink_info_req {
4521 struct sk_buff *msg;
4522};
4523
4524int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
4525{
4526 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
4527}
4528EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
4529
4530int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
4531{
4532 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
4533}
4534EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
4535
Vasundhara Volamb5872cd2020-06-20 22:01:56 +05304536int devlink_info_board_serial_number_put(struct devlink_info_req *req,
4537 const char *bsn)
4538{
4539 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER,
4540 bsn);
4541}
4542EXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put);
4543
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08004544static int devlink_info_version_put(struct devlink_info_req *req, int attr,
4545 const char *version_name,
4546 const char *version_value)
4547{
4548 struct nlattr *nest;
4549 int err;
4550
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004551 nest = nla_nest_start_noflag(req->msg, attr);
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08004552 if (!nest)
4553 return -EMSGSIZE;
4554
4555 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
4556 version_name);
4557 if (err)
4558 goto nla_put_failure;
4559
4560 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
4561 version_value);
4562 if (err)
4563 goto nla_put_failure;
4564
4565 nla_nest_end(req->msg, nest);
4566
4567 return 0;
4568
4569nla_put_failure:
4570 nla_nest_cancel(req->msg, nest);
4571 return err;
4572}
4573
4574int devlink_info_version_fixed_put(struct devlink_info_req *req,
4575 const char *version_name,
4576 const char *version_value)
4577{
4578 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
4579 version_name, version_value);
4580}
4581EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
4582
4583int devlink_info_version_stored_put(struct devlink_info_req *req,
4584 const char *version_name,
4585 const char *version_value)
4586{
4587 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
4588 version_name, version_value);
4589}
4590EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
4591
4592int devlink_info_version_running_put(struct devlink_info_req *req,
4593 const char *version_name,
4594 const char *version_value)
4595{
4596 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
4597 version_name, version_value);
4598}
4599EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
4600
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004601static int
4602devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
4603 enum devlink_command cmd, u32 portid,
4604 u32 seq, int flags, struct netlink_ext_ack *extack)
4605{
4606 struct devlink_info_req req;
4607 void *hdr;
4608 int err;
4609
4610 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4611 if (!hdr)
4612 return -EMSGSIZE;
4613
4614 err = -EMSGSIZE;
4615 if (devlink_nl_put_handle(msg, devlink))
4616 goto err_cancel_msg;
4617
4618 req.msg = msg;
4619 err = devlink->ops->info_get(devlink, &req, extack);
4620 if (err)
4621 goto err_cancel_msg;
4622
4623 genlmsg_end(msg, hdr);
4624 return 0;
4625
4626err_cancel_msg:
4627 genlmsg_cancel(msg, hdr);
4628 return err;
4629}
4630
4631static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
4632 struct genl_info *info)
4633{
4634 struct devlink *devlink = info->user_ptr[0];
4635 struct sk_buff *msg;
4636 int err;
4637
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08004638 if (!devlink->ops->info_get)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004639 return -EOPNOTSUPP;
4640
4641 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4642 if (!msg)
4643 return -ENOMEM;
4644
4645 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4646 info->snd_portid, info->snd_seq, 0,
4647 info->extack);
4648 if (err) {
4649 nlmsg_free(msg);
4650 return err;
4651 }
4652
4653 return genlmsg_reply(msg, info);
4654}
4655
4656static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
4657 struct netlink_callback *cb)
4658{
4659 struct devlink *devlink;
4660 int start = cb->args[0];
4661 int idx = 0;
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004662 int err = 0;
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004663
4664 mutex_lock(&devlink_mutex);
4665 list_for_each_entry(devlink, &devlink_list, list) {
4666 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4667 continue;
4668 if (idx < start) {
4669 idx++;
4670 continue;
4671 }
4672
Jiri Pirkoc493b09b2019-03-24 00:21:03 +01004673 if (!devlink->ops->info_get) {
4674 idx++;
4675 continue;
4676 }
4677
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004678 mutex_lock(&devlink->lock);
4679 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4680 NETLINK_CB(cb->skb).portid,
4681 cb->nlh->nlmsg_seq, NLM_F_MULTI,
4682 cb->extack);
4683 mutex_unlock(&devlink->lock);
Vasundhara Volam93c2fcb2019-09-30 11:52:21 +05304684 if (err && err != -EOPNOTSUPP)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004685 break;
4686 idx++;
4687 }
4688 mutex_unlock(&devlink_mutex);
4689
Jiri Pirkoc62c2cf2019-10-04 11:50:12 +02004690 if (err != -EMSGSIZE)
4691 return err;
4692
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004693 cb->args[0] = idx;
4694 return msg->len;
4695}
4696
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004697struct devlink_fmsg_item {
4698 struct list_head list;
4699 int attrtype;
4700 u8 nla_type;
4701 u16 len;
Gustavo A. R. Silvad2afb412020-02-28 07:43:24 -06004702 int value[];
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004703};
4704
4705struct devlink_fmsg {
4706 struct list_head item_list;
Aya Levin573ed902020-02-11 14:32:42 -08004707 bool putting_binary; /* This flag forces enclosing of binary data
4708 * in an array brackets. It forces using
4709 * of designated API:
4710 * devlink_fmsg_binary_pair_nest_start()
4711 * devlink_fmsg_binary_pair_nest_end()
4712 */
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004713};
4714
4715static struct devlink_fmsg *devlink_fmsg_alloc(void)
4716{
4717 struct devlink_fmsg *fmsg;
4718
4719 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
4720 if (!fmsg)
4721 return NULL;
4722
4723 INIT_LIST_HEAD(&fmsg->item_list);
4724
4725 return fmsg;
4726}
4727
4728static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
4729{
4730 struct devlink_fmsg_item *item, *tmp;
4731
4732 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
4733 list_del(&item->list);
4734 kfree(item);
4735 }
4736 kfree(fmsg);
4737}
4738
4739static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
4740 int attrtype)
4741{
4742 struct devlink_fmsg_item *item;
4743
4744 item = kzalloc(sizeof(*item), GFP_KERNEL);
4745 if (!item)
4746 return -ENOMEM;
4747
4748 item->attrtype = attrtype;
4749 list_add_tail(&item->list, &fmsg->item_list);
4750
4751 return 0;
4752}
4753
4754int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
4755{
Aya Levin573ed902020-02-11 14:32:42 -08004756 if (fmsg->putting_binary)
4757 return -EINVAL;
4758
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004759 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
4760}
4761EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
4762
4763static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
4764{
Aya Levin573ed902020-02-11 14:32:42 -08004765 if (fmsg->putting_binary)
4766 return -EINVAL;
4767
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004768 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
4769}
4770
4771int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
4772{
Aya Levin573ed902020-02-11 14:32:42 -08004773 if (fmsg->putting_binary)
4774 return -EINVAL;
4775
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004776 return devlink_fmsg_nest_end(fmsg);
4777}
4778EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
4779
4780#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
4781
4782static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
4783{
4784 struct devlink_fmsg_item *item;
4785
Aya Levin573ed902020-02-11 14:32:42 -08004786 if (fmsg->putting_binary)
4787 return -EINVAL;
4788
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004789 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4790 return -EMSGSIZE;
4791
4792 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4793 if (!item)
4794 return -ENOMEM;
4795
4796 item->nla_type = NLA_NUL_STRING;
4797 item->len = strlen(name) + 1;
4798 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4799 memcpy(&item->value, name, item->len);
4800 list_add_tail(&item->list, &fmsg->item_list);
4801
4802 return 0;
4803}
4804
4805int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4806{
4807 int err;
4808
Aya Levin573ed902020-02-11 14:32:42 -08004809 if (fmsg->putting_binary)
4810 return -EINVAL;
4811
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004812 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4813 if (err)
4814 return err;
4815
4816 err = devlink_fmsg_put_name(fmsg, name);
4817 if (err)
4818 return err;
4819
4820 return 0;
4821}
4822EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4823
4824int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4825{
Aya Levin573ed902020-02-11 14:32:42 -08004826 if (fmsg->putting_binary)
4827 return -EINVAL;
4828
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004829 return devlink_fmsg_nest_end(fmsg);
4830}
4831EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4832
4833int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4834 const char *name)
4835{
4836 int err;
4837
Aya Levin573ed902020-02-11 14:32:42 -08004838 if (fmsg->putting_binary)
4839 return -EINVAL;
4840
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004841 err = devlink_fmsg_pair_nest_start(fmsg, name);
4842 if (err)
4843 return err;
4844
4845 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4846 if (err)
4847 return err;
4848
4849 return 0;
4850}
4851EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4852
4853int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4854{
4855 int err;
4856
Aya Levin573ed902020-02-11 14:32:42 -08004857 if (fmsg->putting_binary)
4858 return -EINVAL;
4859
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004860 err = devlink_fmsg_nest_end(fmsg);
4861 if (err)
4862 return err;
4863
4864 err = devlink_fmsg_nest_end(fmsg);
4865 if (err)
4866 return err;
4867
4868 return 0;
4869}
4870EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4871
Aya Levin573ed902020-02-11 14:32:42 -08004872int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
4873 const char *name)
4874{
4875 int err;
4876
4877 err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
4878 if (err)
4879 return err;
4880
4881 fmsg->putting_binary = true;
4882 return err;
4883}
4884EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
4885
4886int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
4887{
4888 if (!fmsg->putting_binary)
4889 return -EINVAL;
4890
4891 fmsg->putting_binary = false;
4892 return devlink_fmsg_arr_pair_nest_end(fmsg);
4893}
4894EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
4895
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004896static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4897 const void *value, u16 value_len,
4898 u8 value_nla_type)
4899{
4900 struct devlink_fmsg_item *item;
4901
4902 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4903 return -EMSGSIZE;
4904
4905 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4906 if (!item)
4907 return -ENOMEM;
4908
4909 item->nla_type = value_nla_type;
4910 item->len = value_len;
4911 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4912 memcpy(&item->value, value, item->len);
4913 list_add_tail(&item->list, &fmsg->item_list);
4914
4915 return 0;
4916}
4917
4918int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4919{
Aya Levin573ed902020-02-11 14:32:42 -08004920 if (fmsg->putting_binary)
4921 return -EINVAL;
4922
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004923 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4924}
4925EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4926
4927int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4928{
Aya Levin573ed902020-02-11 14:32:42 -08004929 if (fmsg->putting_binary)
4930 return -EINVAL;
4931
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004932 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4933}
4934EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4935
4936int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4937{
Aya Levin573ed902020-02-11 14:32:42 -08004938 if (fmsg->putting_binary)
4939 return -EINVAL;
4940
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004941 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4942}
4943EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4944
4945int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4946{
Aya Levin573ed902020-02-11 14:32:42 -08004947 if (fmsg->putting_binary)
4948 return -EINVAL;
4949
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004950 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4951}
4952EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4953
4954int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4955{
Aya Levin573ed902020-02-11 14:32:42 -08004956 if (fmsg->putting_binary)
4957 return -EINVAL;
4958
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004959 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4960 NLA_NUL_STRING);
4961}
4962EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4963
Aya Levin573ed902020-02-11 14:32:42 -08004964int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4965 u16 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004966{
Aya Levin573ed902020-02-11 14:32:42 -08004967 if (!fmsg->putting_binary)
4968 return -EINVAL;
4969
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004970 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4971}
Aya Levin573ed902020-02-11 14:32:42 -08004972EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004973
4974int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4975 bool value)
4976{
4977 int err;
4978
4979 err = devlink_fmsg_pair_nest_start(fmsg, name);
4980 if (err)
4981 return err;
4982
4983 err = devlink_fmsg_bool_put(fmsg, value);
4984 if (err)
4985 return err;
4986
4987 err = devlink_fmsg_pair_nest_end(fmsg);
4988 if (err)
4989 return err;
4990
4991 return 0;
4992}
4993EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4994
4995int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4996 u8 value)
4997{
4998 int err;
4999
5000 err = devlink_fmsg_pair_nest_start(fmsg, name);
5001 if (err)
5002 return err;
5003
5004 err = devlink_fmsg_u8_put(fmsg, value);
5005 if (err)
5006 return err;
5007
5008 err = devlink_fmsg_pair_nest_end(fmsg);
5009 if (err)
5010 return err;
5011
5012 return 0;
5013}
5014EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
5015
5016int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
5017 u32 value)
5018{
5019 int err;
5020
5021 err = devlink_fmsg_pair_nest_start(fmsg, name);
5022 if (err)
5023 return err;
5024
5025 err = devlink_fmsg_u32_put(fmsg, value);
5026 if (err)
5027 return err;
5028
5029 err = devlink_fmsg_pair_nest_end(fmsg);
5030 if (err)
5031 return err;
5032
5033 return 0;
5034}
5035EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
5036
5037int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
5038 u64 value)
5039{
5040 int err;
5041
5042 err = devlink_fmsg_pair_nest_start(fmsg, name);
5043 if (err)
5044 return err;
5045
5046 err = devlink_fmsg_u64_put(fmsg, value);
5047 if (err)
5048 return err;
5049
5050 err = devlink_fmsg_pair_nest_end(fmsg);
5051 if (err)
5052 return err;
5053
5054 return 0;
5055}
5056EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
5057
5058int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
5059 const char *value)
5060{
5061 int err;
5062
5063 err = devlink_fmsg_pair_nest_start(fmsg, name);
5064 if (err)
5065 return err;
5066
5067 err = devlink_fmsg_string_put(fmsg, value);
5068 if (err)
5069 return err;
5070
5071 err = devlink_fmsg_pair_nest_end(fmsg);
5072 if (err)
5073 return err;
5074
5075 return 0;
5076}
5077EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
5078
5079int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
Aya Levine2cde862019-11-12 14:07:49 +02005080 const void *value, u32 value_len)
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005081{
Aya Levine2cde862019-11-12 14:07:49 +02005082 u32 data_size;
Aya Levin573ed902020-02-11 14:32:42 -08005083 int end_err;
Aya Levine2cde862019-11-12 14:07:49 +02005084 u32 offset;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005085 int err;
5086
Aya Levin573ed902020-02-11 14:32:42 -08005087 err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005088 if (err)
5089 return err;
5090
Aya Levine2cde862019-11-12 14:07:49 +02005091 for (offset = 0; offset < value_len; offset += data_size) {
5092 data_size = value_len - offset;
5093 if (data_size > DEVLINK_FMSG_MAX_SIZE)
5094 data_size = DEVLINK_FMSG_MAX_SIZE;
5095 err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
5096 if (err)
Aya Levin573ed902020-02-11 14:32:42 -08005097 break;
5098 /* Exit from loop with a break (instead of
5099 * return) to make sure putting_binary is turned off in
5100 * devlink_fmsg_binary_pair_nest_end
5101 */
Aya Levine2cde862019-11-12 14:07:49 +02005102 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005103
Aya Levin573ed902020-02-11 14:32:42 -08005104 end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
5105 if (end_err)
5106 err = end_err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005107
Aya Levin573ed902020-02-11 14:32:42 -08005108 return err;
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005109}
5110EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
5111
5112static int
5113devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5114{
5115 switch (msg->nla_type) {
5116 case NLA_FLAG:
5117 case NLA_U8:
5118 case NLA_U32:
5119 case NLA_U64:
5120 case NLA_NUL_STRING:
5121 case NLA_BINARY:
5122 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
5123 msg->nla_type);
5124 default:
5125 return -EINVAL;
5126 }
5127}
5128
5129static int
5130devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
5131{
5132 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
5133 u8 tmp;
5134
5135 switch (msg->nla_type) {
5136 case NLA_FLAG:
5137 /* Always provide flag data, regardless of its value */
5138 tmp = *(bool *) msg->value;
5139
5140 return nla_put_u8(skb, attrtype, tmp);
5141 case NLA_U8:
5142 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
5143 case NLA_U32:
5144 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
5145 case NLA_U64:
5146 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
5147 DEVLINK_ATTR_PAD);
5148 case NLA_NUL_STRING:
5149 return nla_put_string(skb, attrtype, (char *) &msg->value);
5150 case NLA_BINARY:
5151 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
5152 default:
5153 return -EINVAL;
5154 }
5155}
5156
5157static int
5158devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5159 int *start)
5160{
5161 struct devlink_fmsg_item *item;
5162 struct nlattr *fmsg_nlattr;
5163 int i = 0;
5164 int err;
5165
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005166 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005167 if (!fmsg_nlattr)
5168 return -EMSGSIZE;
5169
5170 list_for_each_entry(item, &fmsg->item_list, list) {
5171 if (i < *start) {
5172 i++;
5173 continue;
5174 }
5175
5176 switch (item->attrtype) {
5177 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
5178 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
5179 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
5180 case DEVLINK_ATTR_FMSG_NEST_END:
5181 err = nla_put_flag(skb, item->attrtype);
5182 break;
5183 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
5184 err = devlink_fmsg_item_fill_type(item, skb);
5185 if (err)
5186 break;
5187 err = devlink_fmsg_item_fill_data(item, skb);
5188 break;
5189 case DEVLINK_ATTR_FMSG_OBJ_NAME:
5190 err = nla_put_string(skb, item->attrtype,
5191 (char *) &item->value);
5192 break;
5193 default:
5194 err = -EINVAL;
5195 break;
5196 }
5197 if (!err)
5198 *start = ++i;
5199 else
5200 break;
5201 }
5202
5203 nla_nest_end(skb, fmsg_nlattr);
5204 return err;
5205}
5206
5207static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
5208 struct genl_info *info,
5209 enum devlink_command cmd, int flags)
5210{
5211 struct nlmsghdr *nlh;
5212 struct sk_buff *skb;
5213 bool last = false;
5214 int index = 0;
5215 void *hdr;
5216 int err;
5217
5218 while (!last) {
5219 int tmp_index = index;
5220
5221 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5222 if (!skb)
5223 return -ENOMEM;
5224
5225 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
5226 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
5227 if (!hdr) {
5228 err = -EMSGSIZE;
5229 goto nla_put_failure;
5230 }
5231
5232 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5233 if (!err)
5234 last = true;
5235 else if (err != -EMSGSIZE || tmp_index == index)
5236 goto nla_put_failure;
5237
5238 genlmsg_end(skb, hdr);
5239 err = genlmsg_reply(skb, info);
5240 if (err)
5241 return err;
5242 }
5243
5244 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
5245 if (!skb)
5246 return -ENOMEM;
5247 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
5248 NLMSG_DONE, 0, flags | NLM_F_MULTI);
5249 if (!nlh) {
5250 err = -EMSGSIZE;
5251 goto nla_put_failure;
5252 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005253
Li RongQingfde55ea2019-02-11 19:09:07 +08005254 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02005255
5256nla_put_failure:
5257 nlmsg_free(skb);
5258 return err;
5259}
5260
Aya Levine44ef4e2019-05-16 09:49:20 +03005261static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
5262 struct netlink_callback *cb,
5263 enum devlink_command cmd)
5264{
5265 int index = cb->args[0];
5266 int tmp_index = index;
5267 void *hdr;
5268 int err;
5269
5270 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
5271 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
5272 if (!hdr) {
5273 err = -EMSGSIZE;
5274 goto nla_put_failure;
5275 }
5276
5277 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
5278 if ((err && err != -EMSGSIZE) || tmp_index == index)
5279 goto nla_put_failure;
5280
5281 cb->args[0] = index;
5282 genlmsg_end(skb, hdr);
5283 return skb->len;
5284
5285nla_put_failure:
5286 genlmsg_cancel(skb, hdr);
5287 return err;
5288}
5289
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005290struct devlink_health_reporter {
5291 struct list_head list;
5292 void *priv;
5293 const struct devlink_health_reporter_ops *ops;
5294 struct devlink *devlink;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005295 struct devlink_port *devlink_port;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005296 struct devlink_fmsg *dump_fmsg;
5297 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005298 u64 graceful_period;
5299 bool auto_recover;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005300 bool auto_dump;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005301 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005302 u64 dump_ts;
Aya Levind2795052019-11-10 14:11:56 +02005303 u64 dump_real_ts;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005304 u64 error_count;
5305 u64 recovery_count;
5306 u64 last_recovery_ts;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005307 refcount_t refcount;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02005308};
5309
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005310void *
5311devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
5312{
5313 return reporter->priv;
5314}
5315EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
5316
5317static struct devlink_health_reporter *
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005318__devlink_health_reporter_find_by_name(struct list_head *reporter_list,
5319 struct mutex *list_lock,
5320 const char *reporter_name)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005321{
5322 struct devlink_health_reporter *reporter;
5323
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005324 lockdep_assert_held(list_lock);
5325 list_for_each_entry(reporter, reporter_list, list)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005326 if (!strcmp(reporter->ops->name, reporter_name))
5327 return reporter;
5328 return NULL;
5329}
5330
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005331static struct devlink_health_reporter *
Vladyslav Tarasiukbd821002020-07-10 15:25:09 +03005332devlink_health_reporter_find_by_name(struct devlink *devlink,
5333 const char *reporter_name)
5334{
5335 return __devlink_health_reporter_find_by_name(&devlink->reporter_list,
5336 &devlink->reporters_lock,
5337 reporter_name);
5338}
5339
5340static struct devlink_health_reporter *
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005341devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
5342 const char *reporter_name)
5343{
5344 return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
5345 &devlink_port->reporters_lock,
5346 reporter_name);
5347}
5348
5349static struct devlink_health_reporter *
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005350__devlink_health_reporter_create(struct devlink *devlink,
5351 const struct devlink_health_reporter_ops *ops,
5352 u64 graceful_period, void *priv)
5353{
5354 struct devlink_health_reporter *reporter;
5355
5356 if (WARN_ON(graceful_period && !ops->recover))
5357 return ERR_PTR(-EINVAL);
5358
5359 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
5360 if (!reporter)
5361 return ERR_PTR(-ENOMEM);
5362
5363 reporter->priv = priv;
5364 reporter->ops = ops;
5365 reporter->devlink = devlink;
5366 reporter->graceful_period = graceful_period;
5367 reporter->auto_recover = !!ops->recover;
5368 reporter->auto_dump = !!ops->dump;
5369 mutex_init(&reporter->dump_lock);
5370 refcount_set(&reporter->refcount, 1);
5371 return reporter;
5372}
5373
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005374/**
5375 * devlink_health_reporter_create - create devlink health reporter
5376 *
5377 * @devlink: devlink
5378 * @ops: ops
5379 * @graceful_period: to avoid recovery loops, in msecs
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005380 * @priv: priv
5381 */
5382struct devlink_health_reporter *
5383devlink_health_reporter_create(struct devlink *devlink,
5384 const struct devlink_health_reporter_ops *ops,
Eran Ben Elishaba7d16c2020-03-29 14:05:54 +03005385 u64 graceful_period, void *priv)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005386{
5387 struct devlink_health_reporter *reporter;
5388
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005389 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005390 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
5391 reporter = ERR_PTR(-EEXIST);
5392 goto unlock;
5393 }
5394
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005395 reporter = __devlink_health_reporter_create(devlink, ops,
5396 graceful_period, priv);
5397 if (IS_ERR(reporter))
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005398 goto unlock;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005399
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005400 list_add_tail(&reporter->list, &devlink->reporter_list);
5401unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005402 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005403 return reporter;
5404}
5405EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
5406
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005407static void
5408devlink_health_reporter_free(struct devlink_health_reporter *reporter)
5409{
5410 mutex_destroy(&reporter->dump_lock);
5411 if (reporter->dump_fmsg)
5412 devlink_fmsg_free(reporter->dump_fmsg);
5413 kfree(reporter);
5414}
5415
5416static void
5417devlink_health_reporter_put(struct devlink_health_reporter *reporter)
5418{
5419 if (refcount_dec_and_test(&reporter->refcount))
5420 devlink_health_reporter_free(reporter);
5421}
5422
5423static void
5424__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5425{
5426 list_del(&reporter->list);
5427 devlink_health_reporter_put(reporter);
5428}
5429
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005430/**
5431 * devlink_health_reporter_destroy - destroy devlink health reporter
5432 *
5433 * @reporter: devlink health reporter to destroy
5434 */
5435void
5436devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5437{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005438 mutex_lock(&reporter->devlink->reporters_lock);
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005439 __devlink_health_reporter_destroy(reporter);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005440 mutex_unlock(&reporter->devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005441}
5442EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
5443
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005444static int
5445devlink_nl_health_reporter_fill(struct sk_buff *msg,
5446 struct devlink *devlink,
5447 struct devlink_health_reporter *reporter,
5448 enum devlink_command cmd, u32 portid,
5449 u32 seq, int flags)
5450{
5451 struct nlattr *reporter_attr;
5452 void *hdr;
5453
5454 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5455 if (!hdr)
5456 return -EMSGSIZE;
5457
5458 if (devlink_nl_put_handle(msg, devlink))
5459 goto genlmsg_cancel;
5460
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005461 if (reporter->devlink_port) {
5462 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
5463 goto genlmsg_cancel;
5464 }
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005465 reporter_attr = nla_nest_start_noflag(msg,
5466 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005467 if (!reporter_attr)
5468 goto genlmsg_cancel;
5469 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
5470 reporter->ops->name))
5471 goto reporter_nest_cancel;
5472 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
5473 reporter->health_state))
5474 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005475 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005476 reporter->error_count, DEVLINK_ATTR_PAD))
5477 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005478 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005479 reporter->recovery_count, DEVLINK_ATTR_PAD))
5480 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005481 if (reporter->ops->recover &&
5482 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005483 reporter->graceful_period,
5484 DEVLINK_ATTR_PAD))
5485 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005486 if (reporter->ops->recover &&
5487 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005488 reporter->auto_recover))
5489 goto reporter_nest_cancel;
5490 if (reporter->dump_fmsg &&
5491 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
5492 jiffies_to_msecs(reporter->dump_ts),
5493 DEVLINK_ATTR_PAD))
5494 goto reporter_nest_cancel;
Aya Levind2795052019-11-10 14:11:56 +02005495 if (reporter->dump_fmsg &&
5496 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
5497 reporter->dump_real_ts, DEVLINK_ATTR_PAD))
5498 goto reporter_nest_cancel;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005499 if (reporter->ops->dump &&
5500 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
5501 reporter->auto_dump))
5502 goto reporter_nest_cancel;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005503
5504 nla_nest_end(msg, reporter_attr);
5505 genlmsg_end(msg, hdr);
5506 return 0;
5507
5508reporter_nest_cancel:
5509 nla_nest_end(msg, reporter_attr);
5510genlmsg_cancel:
5511 genlmsg_cancel(msg, hdr);
5512 return -EMSGSIZE;
5513}
5514
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305515static void devlink_recover_notify(struct devlink_health_reporter *reporter,
5516 enum devlink_command cmd)
5517{
5518 struct sk_buff *msg;
5519 int err;
5520
5521 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5522
5523 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5524 if (!msg)
5525 return;
5526
5527 err = devlink_nl_health_reporter_fill(msg, reporter->devlink,
5528 reporter, cmd, 0, 0, 0);
5529 if (err) {
5530 nlmsg_free(msg);
5531 return;
5532 }
5533
5534 genlmsg_multicast_netns(&devlink_nl_family,
5535 devlink_net(reporter->devlink),
5536 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
5537}
5538
5539void
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005540devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
5541{
5542 reporter->recovery_count++;
5543 reporter->last_recovery_ts = jiffies;
5544}
5545EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
5546
5547static int
5548devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
5549 void *priv_ctx, struct netlink_ext_ack *extack)
5550{
5551 int err;
5552
5553 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
5554 return 0;
5555
5556 if (!reporter->ops->recover)
5557 return -EOPNOTSUPP;
5558
5559 err = reporter->ops->recover(reporter, priv_ctx, extack);
5560 if (err)
5561 return err;
5562
5563 devlink_health_reporter_recovery_done(reporter);
5564 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
5565 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5566
5567 return 0;
5568}
5569
5570static void
5571devlink_health_dump_clear(struct devlink_health_reporter *reporter)
5572{
5573 if (!reporter->dump_fmsg)
5574 return;
5575 devlink_fmsg_free(reporter->dump_fmsg);
5576 reporter->dump_fmsg = NULL;
5577}
5578
5579static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
5580 void *priv_ctx,
5581 struct netlink_ext_ack *extack)
5582{
5583 int err;
5584
5585 if (!reporter->ops->dump)
5586 return 0;
5587
5588 if (reporter->dump_fmsg)
5589 return 0;
5590
5591 reporter->dump_fmsg = devlink_fmsg_alloc();
5592 if (!reporter->dump_fmsg) {
5593 err = -ENOMEM;
5594 return err;
5595 }
5596
5597 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
5598 if (err)
5599 goto dump_err;
5600
5601 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
5602 priv_ctx, extack);
5603 if (err)
5604 goto dump_err;
5605
5606 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
5607 if (err)
5608 goto dump_err;
5609
5610 reporter->dump_ts = jiffies;
5611 reporter->dump_real_ts = ktime_get_real_ns();
5612
5613 return 0;
5614
5615dump_err:
5616 devlink_health_dump_clear(reporter);
5617 return err;
5618}
5619
5620int devlink_health_report(struct devlink_health_reporter *reporter,
5621 const char *msg, void *priv_ctx)
5622{
5623 enum devlink_health_reporter_state prev_health_state;
5624 struct devlink *devlink = reporter->devlink;
Aya Levinbea0c5c2020-05-04 11:27:46 +03005625 unsigned long recover_ts_threshold;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005626
5627 /* write a log message of the current error */
5628 WARN_ON(!msg);
5629 trace_devlink_health_report(devlink, reporter->ops->name, msg);
5630 reporter->error_count++;
5631 prev_health_state = reporter->health_state;
5632 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5633 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5634
5635 /* abort if the previous error wasn't recovered */
Aya Levinbea0c5c2020-05-04 11:27:46 +03005636 recover_ts_threshold = reporter->last_recovery_ts +
5637 msecs_to_jiffies(reporter->graceful_period);
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005638 if (reporter->auto_recover &&
5639 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Aya Levinbea0c5c2020-05-04 11:27:46 +03005640 (reporter->last_recovery_ts && reporter->recovery_count &&
5641 time_is_after_jiffies(recover_ts_threshold)))) {
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005642 trace_devlink_health_recover_aborted(devlink,
5643 reporter->ops->name,
5644 reporter->health_state,
5645 jiffies -
5646 reporter->last_recovery_ts);
5647 return -ECANCELED;
5648 }
5649
5650 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5651
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005652 if (reporter->auto_dump) {
5653 mutex_lock(&reporter->dump_lock);
5654 /* store current dump of current error, for later analysis */
5655 devlink_health_do_dump(reporter, priv_ctx, NULL);
5656 mutex_unlock(&reporter->dump_lock);
5657 }
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005658
5659 if (reporter->auto_recover)
5660 return devlink_health_reporter_recover(reporter,
5661 priv_ctx, NULL);
5662
5663 return 0;
5664}
5665EXPORT_SYMBOL_GPL(devlink_health_report);
5666
5667static struct devlink_health_reporter *
5668devlink_health_reporter_get_from_attrs(struct devlink *devlink,
5669 struct nlattr **attrs)
5670{
5671 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005672 struct devlink_port *devlink_port;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005673 char *reporter_name;
5674
5675 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
5676 return NULL;
5677
5678 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005679 devlink_port = devlink_port_get_from_attrs(devlink, attrs);
5680 if (IS_ERR(devlink_port)) {
5681 mutex_lock(&devlink->reporters_lock);
5682 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
5683 if (reporter)
5684 refcount_inc(&reporter->refcount);
5685 mutex_unlock(&devlink->reporters_lock);
5686 } else {
5687 mutex_lock(&devlink_port->reporters_lock);
5688 reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name);
5689 if (reporter)
5690 refcount_inc(&reporter->refcount);
5691 mutex_unlock(&devlink_port->reporters_lock);
5692 }
5693
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005694 return reporter;
5695}
5696
5697static struct devlink_health_reporter *
5698devlink_health_reporter_get_from_info(struct devlink *devlink,
5699 struct genl_info *info)
5700{
5701 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
5702}
5703
5704static struct devlink_health_reporter *
5705devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
5706{
5707 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
5708 struct devlink_health_reporter *reporter;
5709 struct nlattr **attrs = info->attrs;
5710 struct devlink *devlink;
5711
5712 mutex_lock(&devlink_mutex);
5713 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
5714 if (IS_ERR(devlink))
5715 goto unlock;
5716
5717 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
5718 mutex_unlock(&devlink_mutex);
5719 return reporter;
5720unlock:
5721 mutex_unlock(&devlink_mutex);
5722 return NULL;
5723}
5724
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005725void
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305726devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
5727 enum devlink_health_reporter_state state)
5728{
5729 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
5730 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
5731 return;
5732
5733 if (reporter->health_state == state)
5734 return;
5735
5736 reporter->health_state = state;
5737 trace_devlink_health_reporter_state_update(reporter->devlink,
5738 reporter->ops->name, state);
5739 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5740}
5741EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
5742
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005743static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
5744 struct genl_info *info)
5745{
5746 struct devlink *devlink = info->user_ptr[0];
5747 struct devlink_health_reporter *reporter;
5748 struct sk_buff *msg;
5749 int err;
5750
5751 reporter = devlink_health_reporter_get_from_info(devlink, info);
5752 if (!reporter)
5753 return -EINVAL;
5754
5755 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005756 if (!msg) {
5757 err = -ENOMEM;
5758 goto out;
5759 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005760
5761 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
5762 DEVLINK_CMD_HEALTH_REPORTER_GET,
5763 info->snd_portid, info->snd_seq,
5764 0);
5765 if (err) {
5766 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005767 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005768 }
5769
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005770 err = genlmsg_reply(msg, info);
5771out:
5772 devlink_health_reporter_put(reporter);
5773 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005774}
5775
5776static int
5777devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
5778 struct netlink_callback *cb)
5779{
5780 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005781 struct devlink_port *port;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005782 struct devlink *devlink;
5783 int start = cb->args[0];
5784 int idx = 0;
5785 int err;
5786
5787 mutex_lock(&devlink_mutex);
5788 list_for_each_entry(devlink, &devlink_list, list) {
5789 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5790 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005791 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005792 list_for_each_entry(reporter, &devlink->reporter_list,
5793 list) {
5794 if (idx < start) {
5795 idx++;
5796 continue;
5797 }
5798 err = devlink_nl_health_reporter_fill(msg, devlink,
5799 reporter,
5800 DEVLINK_CMD_HEALTH_REPORTER_GET,
5801 NETLINK_CB(cb->skb).portid,
5802 cb->nlh->nlmsg_seq,
5803 NLM_F_MULTI);
5804 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005805 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005806 goto out;
5807 }
5808 idx++;
5809 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005810 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005811 }
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005812
5813 list_for_each_entry(devlink, &devlink_list, list) {
5814 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5815 continue;
5816 list_for_each_entry(port, &devlink->port_list, list) {
5817 mutex_lock(&port->reporters_lock);
5818 list_for_each_entry(reporter, &port->reporter_list, list) {
5819 if (idx < start) {
5820 idx++;
5821 continue;
5822 }
5823 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
5824 DEVLINK_CMD_HEALTH_REPORTER_GET,
5825 NETLINK_CB(cb->skb).portid,
5826 cb->nlh->nlmsg_seq,
5827 NLM_F_MULTI);
5828 if (err) {
5829 mutex_unlock(&port->reporters_lock);
5830 goto out;
5831 }
5832 idx++;
5833 }
5834 mutex_unlock(&port->reporters_lock);
5835 }
5836 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005837out:
5838 mutex_unlock(&devlink_mutex);
5839
5840 cb->args[0] = idx;
5841 return msg->len;
5842}
5843
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005844static int
5845devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
5846 struct genl_info *info)
5847{
5848 struct devlink *devlink = info->user_ptr[0];
5849 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005850 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005851
5852 reporter = devlink_health_reporter_get_from_info(devlink, info);
5853 if (!reporter)
5854 return -EINVAL;
5855
5856 if (!reporter->ops->recover &&
5857 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005858 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
5859 err = -EOPNOTSUPP;
5860 goto out;
5861 }
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005862 if (!reporter->ops->dump &&
5863 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
5864 err = -EOPNOTSUPP;
5865 goto out;
5866 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005867
5868 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
5869 reporter->graceful_period =
5870 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
5871
5872 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
5873 reporter->auto_recover =
5874 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
5875
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005876 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
5877 reporter->auto_dump =
5878 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
5879
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005880 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005881 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005882out:
5883 devlink_health_reporter_put(reporter);
5884 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005885}
5886
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005887static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
5888 struct genl_info *info)
5889{
5890 struct devlink *devlink = info->user_ptr[0];
5891 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005892 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005893
5894 reporter = devlink_health_reporter_get_from_info(devlink, info);
5895 if (!reporter)
5896 return -EINVAL;
5897
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005898 err = devlink_health_reporter_recover(reporter, NULL, info->extack);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005899
5900 devlink_health_reporter_put(reporter);
5901 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005902}
5903
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005904static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
5905 struct genl_info *info)
5906{
5907 struct devlink *devlink = info->user_ptr[0];
5908 struct devlink_health_reporter *reporter;
5909 struct devlink_fmsg *fmsg;
5910 int err;
5911
5912 reporter = devlink_health_reporter_get_from_info(devlink, info);
5913 if (!reporter)
5914 return -EINVAL;
5915
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005916 if (!reporter->ops->diagnose) {
5917 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005918 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005919 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005920
5921 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005922 if (!fmsg) {
5923 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005924 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005925 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005926
5927 err = devlink_fmsg_obj_nest_start(fmsg);
5928 if (err)
5929 goto out;
5930
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005931 err = reporter->ops->diagnose(reporter, fmsg, info->extack);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005932 if (err)
5933 goto out;
5934
5935 err = devlink_fmsg_obj_nest_end(fmsg);
5936 if (err)
5937 goto out;
5938
5939 err = devlink_fmsg_snd(fmsg, info,
5940 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
5941
5942out:
5943 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005944 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005945 return err;
5946}
5947
Aya Levine44ef4e2019-05-16 09:49:20 +03005948static int
5949devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
5950 struct netlink_callback *cb)
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005951{
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005952 struct devlink_health_reporter *reporter;
Aya Levine44ef4e2019-05-16 09:49:20 +03005953 u64 start = cb->args[0];
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005954 int err;
5955
Aya Levine44ef4e2019-05-16 09:49:20 +03005956 reporter = devlink_health_reporter_get_from_cb(cb);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005957 if (!reporter)
5958 return -EINVAL;
5959
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005960 if (!reporter->ops->dump) {
Aya Levine44ef4e2019-05-16 09:49:20 +03005961 err = -EOPNOTSUPP;
5962 goto out;
5963 }
5964 mutex_lock(&reporter->dump_lock);
5965 if (!start) {
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005966 err = devlink_health_do_dump(reporter, NULL, cb->extack);
Aya Levine44ef4e2019-05-16 09:49:20 +03005967 if (err)
5968 goto unlock;
5969 cb->args[1] = reporter->dump_ts;
5970 }
5971 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
5972 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
5973 err = -EAGAIN;
5974 goto unlock;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005975 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005976
Aya Levine44ef4e2019-05-16 09:49:20 +03005977 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
5978 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
5979unlock:
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005980 mutex_unlock(&reporter->dump_lock);
Aya Levine44ef4e2019-05-16 09:49:20 +03005981out:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005982 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005983 return err;
5984}
5985
5986static int
5987devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
5988 struct genl_info *info)
5989{
5990 struct devlink *devlink = info->user_ptr[0];
5991 struct devlink_health_reporter *reporter;
5992
5993 reporter = devlink_health_reporter_get_from_info(devlink, info);
5994 if (!reporter)
5995 return -EINVAL;
5996
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005997 if (!reporter->ops->dump) {
5998 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005999 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006000 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006001
6002 mutex_lock(&reporter->dump_lock);
6003 devlink_health_dump_clear(reporter);
6004 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006005 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006006 return 0;
6007}
6008
Ido Schimmel0f420b62019-08-17 16:28:17 +03006009struct devlink_stats {
6010 u64 rx_bytes;
6011 u64 rx_packets;
6012 struct u64_stats_sync syncp;
6013};
6014
6015/**
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006016 * struct devlink_trap_policer_item - Packet trap policer attributes.
6017 * @policer: Immutable packet trap policer attributes.
6018 * @rate: Rate in packets / sec.
6019 * @burst: Burst size in packets.
6020 * @list: trap_policer_list member.
6021 *
6022 * Describes packet trap policer attributes. Created by devlink during trap
6023 * policer registration.
6024 */
6025struct devlink_trap_policer_item {
6026 const struct devlink_trap_policer *policer;
6027 u64 rate;
6028 u64 burst;
6029 struct list_head list;
6030};
6031
6032/**
Ido Schimmel0f420b62019-08-17 16:28:17 +03006033 * struct devlink_trap_group_item - Packet trap group attributes.
6034 * @group: Immutable packet trap group attributes.
Ido Schimmelf9f54392020-03-30 22:38:21 +03006035 * @policer_item: Associated policer item. Can be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006036 * @list: trap_group_list member.
6037 * @stats: Trap group statistics.
6038 *
6039 * Describes packet trap group attributes. Created by devlink during trap
Ido Schimmela09b37f2020-03-22 20:48:29 +02006040 * group registration.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006041 */
6042struct devlink_trap_group_item {
6043 const struct devlink_trap_group *group;
Ido Schimmelf9f54392020-03-30 22:38:21 +03006044 struct devlink_trap_policer_item *policer_item;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006045 struct list_head list;
6046 struct devlink_stats __percpu *stats;
6047};
6048
6049/**
6050 * struct devlink_trap_item - Packet trap attributes.
6051 * @trap: Immutable packet trap attributes.
6052 * @group_item: Associated group item.
6053 * @list: trap_list member.
6054 * @action: Trap action.
6055 * @stats: Trap statistics.
6056 * @priv: Driver private information.
6057 *
6058 * Describes both mutable and immutable packet trap attributes. Created by
6059 * devlink during trap registration and used for all trap related operations.
6060 */
6061struct devlink_trap_item {
6062 const struct devlink_trap *trap;
6063 struct devlink_trap_group_item *group_item;
6064 struct list_head list;
6065 enum devlink_trap_action action;
6066 struct devlink_stats __percpu *stats;
6067 void *priv;
6068};
6069
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006070static struct devlink_trap_policer_item *
6071devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
6072{
6073 struct devlink_trap_policer_item *policer_item;
6074
6075 list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
6076 if (policer_item->policer->id == id)
6077 return policer_item;
6078 }
6079
6080 return NULL;
6081}
6082
Ido Schimmel0f420b62019-08-17 16:28:17 +03006083static struct devlink_trap_item *
6084devlink_trap_item_lookup(struct devlink *devlink, const char *name)
6085{
6086 struct devlink_trap_item *trap_item;
6087
6088 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6089 if (!strcmp(trap_item->trap->name, name))
6090 return trap_item;
6091 }
6092
6093 return NULL;
6094}
6095
6096static struct devlink_trap_item *
6097devlink_trap_item_get_from_info(struct devlink *devlink,
6098 struct genl_info *info)
6099{
6100 struct nlattr *attr;
6101
6102 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
6103 return NULL;
6104 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
6105
6106 return devlink_trap_item_lookup(devlink, nla_data(attr));
6107}
6108
6109static int
6110devlink_trap_action_get_from_info(struct genl_info *info,
6111 enum devlink_trap_action *p_trap_action)
6112{
6113 u8 val;
6114
6115 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
6116 switch (val) {
6117 case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
Ido Schimmel9eefeab2020-05-29 21:36:39 +03006118 case DEVLINK_TRAP_ACTION_TRAP: /* fall-through */
6119 case DEVLINK_TRAP_ACTION_MIRROR:
Ido Schimmel0f420b62019-08-17 16:28:17 +03006120 *p_trap_action = val;
6121 break;
6122 default:
6123 return -EINVAL;
6124 }
6125
6126 return 0;
6127}
6128
6129static int devlink_trap_metadata_put(struct sk_buff *msg,
6130 const struct devlink_trap *trap)
6131{
6132 struct nlattr *attr;
6133
6134 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
6135 if (!attr)
6136 return -EMSGSIZE;
6137
6138 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
6139 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
6140 goto nla_put_failure;
Jiri Pirko85b05892020-02-25 11:45:19 +01006141 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
6142 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
6143 goto nla_put_failure;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006144
6145 nla_nest_end(msg, attr);
6146
6147 return 0;
6148
6149nla_put_failure:
6150 nla_nest_cancel(msg, attr);
6151 return -EMSGSIZE;
6152}
6153
6154static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
6155 struct devlink_stats *stats)
6156{
6157 int i;
6158
6159 memset(stats, 0, sizeof(*stats));
6160 for_each_possible_cpu(i) {
6161 struct devlink_stats *cpu_stats;
6162 u64 rx_packets, rx_bytes;
6163 unsigned int start;
6164
6165 cpu_stats = per_cpu_ptr(trap_stats, i);
6166 do {
6167 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
6168 rx_packets = cpu_stats->rx_packets;
6169 rx_bytes = cpu_stats->rx_bytes;
6170 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
6171
6172 stats->rx_packets += rx_packets;
6173 stats->rx_bytes += rx_bytes;
6174 }
6175}
6176
6177static int devlink_trap_stats_put(struct sk_buff *msg,
6178 struct devlink_stats __percpu *trap_stats)
6179{
6180 struct devlink_stats stats;
6181 struct nlattr *attr;
6182
6183 devlink_trap_stats_read(trap_stats, &stats);
6184
6185 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6186 if (!attr)
6187 return -EMSGSIZE;
6188
6189 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
6190 stats.rx_packets, DEVLINK_ATTR_PAD))
6191 goto nla_put_failure;
6192
6193 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
6194 stats.rx_bytes, DEVLINK_ATTR_PAD))
6195 goto nla_put_failure;
6196
6197 nla_nest_end(msg, attr);
6198
6199 return 0;
6200
6201nla_put_failure:
6202 nla_nest_cancel(msg, attr);
6203 return -EMSGSIZE;
6204}
6205
6206static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
6207 const struct devlink_trap_item *trap_item,
6208 enum devlink_command cmd, u32 portid, u32 seq,
6209 int flags)
6210{
6211 struct devlink_trap_group_item *group_item = trap_item->group_item;
6212 void *hdr;
6213 int err;
6214
6215 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6216 if (!hdr)
6217 return -EMSGSIZE;
6218
6219 if (devlink_nl_put_handle(msg, devlink))
6220 goto nla_put_failure;
6221
6222 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6223 group_item->group->name))
6224 goto nla_put_failure;
6225
6226 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
6227 goto nla_put_failure;
6228
6229 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
6230 goto nla_put_failure;
6231
6232 if (trap_item->trap->generic &&
6233 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6234 goto nla_put_failure;
6235
6236 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
6237 goto nla_put_failure;
6238
6239 err = devlink_trap_metadata_put(msg, trap_item->trap);
6240 if (err)
6241 goto nla_put_failure;
6242
6243 err = devlink_trap_stats_put(msg, trap_item->stats);
6244 if (err)
6245 goto nla_put_failure;
6246
6247 genlmsg_end(msg, hdr);
6248
6249 return 0;
6250
6251nla_put_failure:
6252 genlmsg_cancel(msg, hdr);
6253 return -EMSGSIZE;
6254}
6255
6256static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
6257 struct genl_info *info)
6258{
6259 struct netlink_ext_ack *extack = info->extack;
6260 struct devlink *devlink = info->user_ptr[0];
6261 struct devlink_trap_item *trap_item;
6262 struct sk_buff *msg;
6263 int err;
6264
6265 if (list_empty(&devlink->trap_list))
6266 return -EOPNOTSUPP;
6267
6268 trap_item = devlink_trap_item_get_from_info(devlink, info);
6269 if (!trap_item) {
6270 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6271 return -ENOENT;
6272 }
6273
6274 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6275 if (!msg)
6276 return -ENOMEM;
6277
6278 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6279 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
6280 info->snd_seq, 0);
6281 if (err)
6282 goto err_trap_fill;
6283
6284 return genlmsg_reply(msg, info);
6285
6286err_trap_fill:
6287 nlmsg_free(msg);
6288 return err;
6289}
6290
6291static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
6292 struct netlink_callback *cb)
6293{
6294 struct devlink_trap_item *trap_item;
6295 struct devlink *devlink;
6296 int start = cb->args[0];
6297 int idx = 0;
6298 int err;
6299
6300 mutex_lock(&devlink_mutex);
6301 list_for_each_entry(devlink, &devlink_list, list) {
6302 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6303 continue;
6304 mutex_lock(&devlink->lock);
6305 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6306 if (idx < start) {
6307 idx++;
6308 continue;
6309 }
6310 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6311 DEVLINK_CMD_TRAP_NEW,
6312 NETLINK_CB(cb->skb).portid,
6313 cb->nlh->nlmsg_seq,
6314 NLM_F_MULTI);
6315 if (err) {
6316 mutex_unlock(&devlink->lock);
6317 goto out;
6318 }
6319 idx++;
6320 }
6321 mutex_unlock(&devlink->lock);
6322 }
6323out:
6324 mutex_unlock(&devlink_mutex);
6325
6326 cb->args[0] = idx;
6327 return msg->len;
6328}
6329
6330static int __devlink_trap_action_set(struct devlink *devlink,
6331 struct devlink_trap_item *trap_item,
6332 enum devlink_trap_action trap_action,
6333 struct netlink_ext_ack *extack)
6334{
6335 int err;
6336
6337 if (trap_item->action != trap_action &&
6338 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
6339 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
6340 return 0;
6341 }
6342
6343 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
6344 trap_action);
6345 if (err)
6346 return err;
6347
6348 trap_item->action = trap_action;
6349
6350 return 0;
6351}
6352
6353static int devlink_trap_action_set(struct devlink *devlink,
6354 struct devlink_trap_item *trap_item,
6355 struct genl_info *info)
6356{
6357 enum devlink_trap_action trap_action;
6358 int err;
6359
6360 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6361 return 0;
6362
6363 err = devlink_trap_action_get_from_info(info, &trap_action);
6364 if (err) {
6365 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6366 return -EINVAL;
6367 }
6368
6369 return __devlink_trap_action_set(devlink, trap_item, trap_action,
6370 info->extack);
6371}
6372
6373static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
6374 struct genl_info *info)
6375{
6376 struct netlink_ext_ack *extack = info->extack;
6377 struct devlink *devlink = info->user_ptr[0];
6378 struct devlink_trap_item *trap_item;
6379 int err;
6380
6381 if (list_empty(&devlink->trap_list))
6382 return -EOPNOTSUPP;
6383
6384 trap_item = devlink_trap_item_get_from_info(devlink, info);
6385 if (!trap_item) {
6386 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6387 return -ENOENT;
6388 }
6389
6390 err = devlink_trap_action_set(devlink, trap_item, info);
6391 if (err)
6392 return err;
6393
6394 return 0;
6395}
6396
6397static struct devlink_trap_group_item *
6398devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
6399{
6400 struct devlink_trap_group_item *group_item;
6401
6402 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6403 if (!strcmp(group_item->group->name, name))
6404 return group_item;
6405 }
6406
6407 return NULL;
6408}
6409
6410static struct devlink_trap_group_item *
Ido Schimmel107f1672020-03-22 20:48:30 +02006411devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
6412{
6413 struct devlink_trap_group_item *group_item;
6414
6415 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6416 if (group_item->group->id == id)
6417 return group_item;
6418 }
6419
6420 return NULL;
6421}
6422
6423static struct devlink_trap_group_item *
Ido Schimmel0f420b62019-08-17 16:28:17 +03006424devlink_trap_group_item_get_from_info(struct devlink *devlink,
6425 struct genl_info *info)
6426{
6427 char *name;
6428
6429 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
6430 return NULL;
6431 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
6432
6433 return devlink_trap_group_item_lookup(devlink, name);
6434}
6435
6436static int
6437devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
6438 const struct devlink_trap_group_item *group_item,
6439 enum devlink_command cmd, u32 portid, u32 seq,
6440 int flags)
6441{
6442 void *hdr;
6443 int err;
6444
6445 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6446 if (!hdr)
6447 return -EMSGSIZE;
6448
6449 if (devlink_nl_put_handle(msg, devlink))
6450 goto nla_put_failure;
6451
6452 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6453 group_item->group->name))
6454 goto nla_put_failure;
6455
6456 if (group_item->group->generic &&
6457 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6458 goto nla_put_failure;
6459
Ido Schimmelf9f54392020-03-30 22:38:21 +03006460 if (group_item->policer_item &&
6461 nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6462 group_item->policer_item->policer->id))
6463 goto nla_put_failure;
6464
Ido Schimmel0f420b62019-08-17 16:28:17 +03006465 err = devlink_trap_stats_put(msg, group_item->stats);
6466 if (err)
6467 goto nla_put_failure;
6468
6469 genlmsg_end(msg, hdr);
6470
6471 return 0;
6472
6473nla_put_failure:
6474 genlmsg_cancel(msg, hdr);
6475 return -EMSGSIZE;
6476}
6477
6478static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
6479 struct genl_info *info)
6480{
6481 struct netlink_ext_ack *extack = info->extack;
6482 struct devlink *devlink = info->user_ptr[0];
6483 struct devlink_trap_group_item *group_item;
6484 struct sk_buff *msg;
6485 int err;
6486
6487 if (list_empty(&devlink->trap_group_list))
6488 return -EOPNOTSUPP;
6489
6490 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6491 if (!group_item) {
6492 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6493 return -ENOENT;
6494 }
6495
6496 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6497 if (!msg)
6498 return -ENOMEM;
6499
6500 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
6501 DEVLINK_CMD_TRAP_GROUP_NEW,
6502 info->snd_portid, info->snd_seq, 0);
6503 if (err)
6504 goto err_trap_group_fill;
6505
6506 return genlmsg_reply(msg, info);
6507
6508err_trap_group_fill:
6509 nlmsg_free(msg);
6510 return err;
6511}
6512
6513static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
6514 struct netlink_callback *cb)
6515{
6516 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
6517 struct devlink_trap_group_item *group_item;
6518 u32 portid = NETLINK_CB(cb->skb).portid;
6519 struct devlink *devlink;
6520 int start = cb->args[0];
6521 int idx = 0;
6522 int err;
6523
6524 mutex_lock(&devlink_mutex);
6525 list_for_each_entry(devlink, &devlink_list, list) {
6526 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6527 continue;
6528 mutex_lock(&devlink->lock);
6529 list_for_each_entry(group_item, &devlink->trap_group_list,
6530 list) {
6531 if (idx < start) {
6532 idx++;
6533 continue;
6534 }
6535 err = devlink_nl_trap_group_fill(msg, devlink,
6536 group_item, cmd,
6537 portid,
6538 cb->nlh->nlmsg_seq,
6539 NLM_F_MULTI);
6540 if (err) {
6541 mutex_unlock(&devlink->lock);
6542 goto out;
6543 }
6544 idx++;
6545 }
6546 mutex_unlock(&devlink->lock);
6547 }
6548out:
6549 mutex_unlock(&devlink_mutex);
6550
6551 cb->args[0] = idx;
6552 return msg->len;
6553}
6554
6555static int
6556__devlink_trap_group_action_set(struct devlink *devlink,
6557 struct devlink_trap_group_item *group_item,
6558 enum devlink_trap_action trap_action,
6559 struct netlink_ext_ack *extack)
6560{
6561 const char *group_name = group_item->group->name;
6562 struct devlink_trap_item *trap_item;
6563 int err;
6564
6565 list_for_each_entry(trap_item, &devlink->trap_list, list) {
Ido Schimmel107f1672020-03-22 20:48:30 +02006566 if (strcmp(trap_item->group_item->group->name, group_name))
Ido Schimmel0f420b62019-08-17 16:28:17 +03006567 continue;
6568 err = __devlink_trap_action_set(devlink, trap_item,
6569 trap_action, extack);
6570 if (err)
6571 return err;
6572 }
6573
6574 return 0;
6575}
6576
6577static int
6578devlink_trap_group_action_set(struct devlink *devlink,
6579 struct devlink_trap_group_item *group_item,
Ido Schimmelc0648752020-03-30 22:38:22 +03006580 struct genl_info *info, bool *p_modified)
Ido Schimmel0f420b62019-08-17 16:28:17 +03006581{
6582 enum devlink_trap_action trap_action;
6583 int err;
6584
6585 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6586 return 0;
6587
6588 err = devlink_trap_action_get_from_info(info, &trap_action);
6589 if (err) {
6590 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6591 return -EINVAL;
6592 }
6593
6594 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
6595 info->extack);
6596 if (err)
6597 return err;
6598
Ido Schimmelc0648752020-03-30 22:38:22 +03006599 *p_modified = true;
6600
6601 return 0;
6602}
6603
6604static int devlink_trap_group_set(struct devlink *devlink,
6605 struct devlink_trap_group_item *group_item,
6606 struct genl_info *info)
6607{
6608 struct devlink_trap_policer_item *policer_item;
6609 struct netlink_ext_ack *extack = info->extack;
6610 const struct devlink_trap_policer *policer;
6611 struct nlattr **attrs = info->attrs;
6612 int err;
6613
6614 if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6615 return 0;
6616
6617 if (!devlink->ops->trap_group_set)
6618 return -EOPNOTSUPP;
6619
6620 policer_item = group_item->policer_item;
6621 if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) {
6622 u32 policer_id;
6623
6624 policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6625 policer_item = devlink_trap_policer_item_lookup(devlink,
6626 policer_id);
6627 if (policer_id && !policer_item) {
6628 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6629 return -ENOENT;
6630 }
6631 }
6632 policer = policer_item ? policer_item->policer : NULL;
6633
6634 err = devlink->ops->trap_group_set(devlink, group_item->group, policer);
6635 if (err)
6636 return err;
6637
6638 group_item->policer_item = policer_item;
6639
Ido Schimmel0f420b62019-08-17 16:28:17 +03006640 return 0;
6641}
6642
6643static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
6644 struct genl_info *info)
6645{
6646 struct netlink_ext_ack *extack = info->extack;
6647 struct devlink *devlink = info->user_ptr[0];
6648 struct devlink_trap_group_item *group_item;
Ido Schimmelc0648752020-03-30 22:38:22 +03006649 bool modified = false;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006650 int err;
6651
6652 if (list_empty(&devlink->trap_group_list))
6653 return -EOPNOTSUPP;
6654
6655 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6656 if (!group_item) {
6657 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6658 return -ENOENT;
6659 }
6660
Ido Schimmelc0648752020-03-30 22:38:22 +03006661 err = devlink_trap_group_action_set(devlink, group_item, info,
6662 &modified);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006663 if (err)
6664 return err;
6665
Ido Schimmelc0648752020-03-30 22:38:22 +03006666 err = devlink_trap_group_set(devlink, group_item, info);
6667 if (err)
6668 goto err_trap_group_set;
6669
Ido Schimmel0f420b62019-08-17 16:28:17 +03006670 return 0;
Ido Schimmelc0648752020-03-30 22:38:22 +03006671
6672err_trap_group_set:
6673 if (modified)
6674 NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already");
6675 return err;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006676}
6677
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006678static struct devlink_trap_policer_item *
6679devlink_trap_policer_item_get_from_info(struct devlink *devlink,
6680 struct genl_info *info)
6681{
6682 u32 id;
6683
6684 if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6685 return NULL;
6686 id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6687
6688 return devlink_trap_policer_item_lookup(devlink, id);
6689}
6690
6691static int
6692devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
6693 const struct devlink_trap_policer *policer)
6694{
6695 struct nlattr *attr;
6696 u64 drops;
6697 int err;
6698
6699 if (!devlink->ops->trap_policer_counter_get)
6700 return 0;
6701
6702 err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
6703 if (err)
6704 return err;
6705
6706 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6707 if (!attr)
6708 return -EMSGSIZE;
6709
6710 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
6711 DEVLINK_ATTR_PAD))
6712 goto nla_put_failure;
6713
6714 nla_nest_end(msg, attr);
6715
6716 return 0;
6717
6718nla_put_failure:
6719 nla_nest_cancel(msg, attr);
6720 return -EMSGSIZE;
6721}
6722
6723static int
6724devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
6725 const struct devlink_trap_policer_item *policer_item,
6726 enum devlink_command cmd, u32 portid, u32 seq,
6727 int flags)
6728{
6729 void *hdr;
6730 int err;
6731
6732 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6733 if (!hdr)
6734 return -EMSGSIZE;
6735
6736 if (devlink_nl_put_handle(msg, devlink))
6737 goto nla_put_failure;
6738
6739 if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6740 policer_item->policer->id))
6741 goto nla_put_failure;
6742
6743 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
6744 policer_item->rate, DEVLINK_ATTR_PAD))
6745 goto nla_put_failure;
6746
6747 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
6748 policer_item->burst, DEVLINK_ATTR_PAD))
6749 goto nla_put_failure;
6750
6751 err = devlink_trap_policer_stats_put(msg, devlink,
6752 policer_item->policer);
6753 if (err)
6754 goto nla_put_failure;
6755
6756 genlmsg_end(msg, hdr);
6757
6758 return 0;
6759
6760nla_put_failure:
6761 genlmsg_cancel(msg, hdr);
6762 return -EMSGSIZE;
6763}
6764
6765static int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
6766 struct genl_info *info)
6767{
6768 struct devlink_trap_policer_item *policer_item;
6769 struct netlink_ext_ack *extack = info->extack;
6770 struct devlink *devlink = info->user_ptr[0];
6771 struct sk_buff *msg;
6772 int err;
6773
6774 if (list_empty(&devlink->trap_policer_list))
6775 return -EOPNOTSUPP;
6776
6777 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
6778 if (!policer_item) {
6779 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6780 return -ENOENT;
6781 }
6782
6783 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6784 if (!msg)
6785 return -ENOMEM;
6786
6787 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
6788 DEVLINK_CMD_TRAP_POLICER_NEW,
6789 info->snd_portid, info->snd_seq, 0);
6790 if (err)
6791 goto err_trap_policer_fill;
6792
6793 return genlmsg_reply(msg, info);
6794
6795err_trap_policer_fill:
6796 nlmsg_free(msg);
6797 return err;
6798}
6799
6800static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,
6801 struct netlink_callback *cb)
6802{
6803 enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW;
6804 struct devlink_trap_policer_item *policer_item;
6805 u32 portid = NETLINK_CB(cb->skb).portid;
6806 struct devlink *devlink;
6807 int start = cb->args[0];
6808 int idx = 0;
6809 int err;
6810
6811 mutex_lock(&devlink_mutex);
6812 list_for_each_entry(devlink, &devlink_list, list) {
6813 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6814 continue;
6815 mutex_lock(&devlink->lock);
6816 list_for_each_entry(policer_item, &devlink->trap_policer_list,
6817 list) {
6818 if (idx < start) {
6819 idx++;
6820 continue;
6821 }
6822 err = devlink_nl_trap_policer_fill(msg, devlink,
6823 policer_item, cmd,
6824 portid,
6825 cb->nlh->nlmsg_seq,
6826 NLM_F_MULTI);
6827 if (err) {
6828 mutex_unlock(&devlink->lock);
6829 goto out;
6830 }
6831 idx++;
6832 }
6833 mutex_unlock(&devlink->lock);
6834 }
6835out:
6836 mutex_unlock(&devlink_mutex);
6837
6838 cb->args[0] = idx;
6839 return msg->len;
6840}
6841
6842static int
6843devlink_trap_policer_set(struct devlink *devlink,
6844 struct devlink_trap_policer_item *policer_item,
6845 struct genl_info *info)
6846{
6847 struct netlink_ext_ack *extack = info->extack;
6848 struct nlattr **attrs = info->attrs;
6849 u64 rate, burst;
6850 int err;
6851
6852 rate = policer_item->rate;
6853 burst = policer_item->burst;
6854
6855 if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
6856 rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
6857
6858 if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
6859 burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
6860
6861 if (rate < policer_item->policer->min_rate) {
6862 NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
6863 return -EINVAL;
6864 }
6865
6866 if (rate > policer_item->policer->max_rate) {
6867 NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
6868 return -EINVAL;
6869 }
6870
6871 if (burst < policer_item->policer->min_burst) {
6872 NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
6873 return -EINVAL;
6874 }
6875
6876 if (burst > policer_item->policer->max_burst) {
6877 NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
6878 return -EINVAL;
6879 }
6880
6881 err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
6882 rate, burst, info->extack);
6883 if (err)
6884 return err;
6885
6886 policer_item->rate = rate;
6887 policer_item->burst = burst;
6888
6889 return 0;
6890}
6891
6892static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
6893 struct genl_info *info)
6894{
6895 struct devlink_trap_policer_item *policer_item;
6896 struct netlink_ext_ack *extack = info->extack;
6897 struct devlink *devlink = info->user_ptr[0];
6898
6899 if (list_empty(&devlink->trap_policer_list))
6900 return -EOPNOTSUPP;
6901
6902 if (!devlink->ops->trap_policer_set)
6903 return -EOPNOTSUPP;
6904
6905 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
6906 if (!policer_item) {
6907 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6908 return -ENOENT;
6909 }
6910
6911 return devlink_trap_policer_set(devlink, policer_item, info);
6912}
6913
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006914static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006915 [DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
6916 DEVLINK_ATTR_TRAP_POLICER_ID },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006917 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
6918 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
6919 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
6920 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
6921 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02006922 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
6923 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
6924 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
6925 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
6926 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
6927 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
6928 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03006929 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
Roi Dayan59bfde02016-11-22 23:09:57 +02006930 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03006931 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006932 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
6933 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006934 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
6935 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03006936 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
6937 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
6938 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03006939 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03006940 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Jakub Kicinskiff3b63b2020-03-02 21:05:12 -08006941 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
6942 [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006943 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006944 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
6945 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08006946 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
6947 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Ido Schimmel0f420b62019-08-17 16:28:17 +03006948 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
6949 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
6950 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
Jiri Pirko070c63f2019-10-03 11:49:39 +02006951 [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
6952 [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
6953 [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03006954 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006955 [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
6956 [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
6957 [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
Parav Pandita1e8ae92020-06-19 03:32:49 +00006958 [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006959};
6960
6961static const struct genl_ops devlink_nl_ops[] = {
6962 {
6963 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006964 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006965 .doit = devlink_nl_cmd_get_doit,
6966 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirko1fc22572016-04-08 19:12:48 +02006967 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006968 /* can be retrieved by unprivileged users */
6969 },
6970 {
6971 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006972 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006973 .doit = devlink_nl_cmd_port_get_doit,
6974 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006975 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
6976 /* can be retrieved by unprivileged users */
6977 },
6978 {
6979 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006980 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006981 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006982 .flags = GENL_ADMIN_PERM,
6983 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
6984 },
6985 {
6986 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02006987 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006988 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006989 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006990 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6991 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006992 },
6993 {
6994 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02006995 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006996 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006997 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006998 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6999 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007000 },
Jiri Pirkobf797472016-04-14 18:19:13 +02007001 {
7002 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007003 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007004 .doit = devlink_nl_cmd_sb_get_doit,
7005 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007006 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7007 DEVLINK_NL_FLAG_NEED_SB,
7008 /* can be retrieved by unprivileged users */
7009 },
7010 {
7011 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007012 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007013 .doit = devlink_nl_cmd_sb_pool_get_doit,
7014 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007015 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7016 DEVLINK_NL_FLAG_NEED_SB,
7017 /* can be retrieved by unprivileged users */
7018 },
7019 {
7020 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007021 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007022 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007023 .flags = GENL_ADMIN_PERM,
7024 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7025 DEVLINK_NL_FLAG_NEED_SB,
7026 },
7027 {
7028 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007029 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007030 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
7031 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007032 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
7033 DEVLINK_NL_FLAG_NEED_SB,
7034 /* can be retrieved by unprivileged users */
7035 },
7036 {
7037 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007038 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007039 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007040 .flags = GENL_ADMIN_PERM,
7041 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
7042 DEVLINK_NL_FLAG_NEED_SB,
7043 },
7044 {
7045 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007046 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007047 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
7048 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007049 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
7050 DEVLINK_NL_FLAG_NEED_SB,
7051 /* can be retrieved by unprivileged users */
7052 },
7053 {
7054 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007055 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007056 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007057 .flags = GENL_ADMIN_PERM,
7058 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
7059 DEVLINK_NL_FLAG_NEED_SB,
7060 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007061 {
7062 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007063 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007064 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007065 .flags = GENL_ADMIN_PERM,
7066 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007067 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007068 },
7069 {
7070 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007071 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007072 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007073 .flags = GENL_ADMIN_PERM,
7074 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007075 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007076 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03007077 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007078 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007079 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007080 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007081 .flags = GENL_ADMIN_PERM,
Parav Pandit98fed6e2020-02-23 19:06:56 -06007082 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7083 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007084 },
7085 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007086 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007087 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007088 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007089 .flags = GENL_ADMIN_PERM,
Jakub Kicinski7ac1cc92018-05-21 22:12:50 -07007090 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7091 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007092 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007093 {
7094 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007095 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007096 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007097 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007098 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007099 },
7100 {
7101 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007102 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007103 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007104 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007105 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007106 },
7107 {
7108 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007109 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007110 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007111 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007112 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007113 },
7114 {
7115 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007116 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007117 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007118 .flags = GENL_ADMIN_PERM,
7119 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7120 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007121 {
7122 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007123 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007124 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007125 .flags = GENL_ADMIN_PERM,
7126 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7127 },
7128 {
7129 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02007130 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007131 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007132 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007133 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007134 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007135 {
7136 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02007137 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007138 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007139 .flags = GENL_ADMIN_PERM,
7140 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7141 DEVLINK_NL_FLAG_NO_LOCK,
7142 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007143 {
7144 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007145 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007146 .doit = devlink_nl_cmd_param_get_doit,
7147 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007148 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7149 /* can be retrieved by unprivileged users */
7150 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007151 {
7152 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007153 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007154 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007155 .flags = GENL_ADMIN_PERM,
7156 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7157 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007158 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307159 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007160 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307161 .doit = devlink_nl_cmd_port_param_get_doit,
7162 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307163 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7164 /* can be retrieved by unprivileged users */
7165 },
7166 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05307167 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007168 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307169 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307170 .flags = GENL_ADMIN_PERM,
7171 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7172 },
7173 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007174 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007175 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007176 .doit = devlink_nl_cmd_region_get_doit,
7177 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007178 .flags = GENL_ADMIN_PERM,
7179 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7180 },
Alex Vesker866319b2018-07-12 15:13:13 +03007181 {
Jacob Kellerb9a17abf2020-03-26 11:37:16 -07007182 .cmd = DEVLINK_CMD_REGION_NEW,
7183 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7184 .doit = devlink_nl_cmd_region_new,
7185 .flags = GENL_ADMIN_PERM,
7186 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7187 },
7188 {
Alex Vesker866319b2018-07-12 15:13:13 +03007189 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02007190 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03007191 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03007192 .flags = GENL_ADMIN_PERM,
7193 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7194 },
Alex Vesker4e547952018-07-12 15:13:14 +03007195 {
7196 .cmd = DEVLINK_CMD_REGION_READ,
Jiri Pirkoee85da52019-10-05 20:04:42 +02007197 .validate = GENL_DONT_VALIDATE_STRICT |
7198 GENL_DONT_VALIDATE_DUMP_STRICT,
Alex Vesker4e547952018-07-12 15:13:14 +03007199 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03007200 .flags = GENL_ADMIN_PERM,
7201 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7202 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007203 {
7204 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007205 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007206 .doit = devlink_nl_cmd_info_get_doit,
7207 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007208 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7209 /* can be retrieved by unprivileged users */
7210 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007211 {
7212 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007213 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007214 .doit = devlink_nl_cmd_health_reporter_get_doit,
7215 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007216 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007217 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007218 /* can be retrieved by unprivileged users */
7219 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007220 {
7221 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007222 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007223 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007224 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007225 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007226 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007227 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007228 {
7229 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02007230 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007231 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007232 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007233 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007234 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007235 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007236 {
7237 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007238 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007239 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007240 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007241 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007242 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007243 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007244 {
7245 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Jiri Pirko82a843d2019-10-07 09:28:31 +02007246 .validate = GENL_DONT_VALIDATE_STRICT |
7247 GENL_DONT_VALIDATE_DUMP_STRICT,
Aya Levine44ef4e2019-05-16 09:49:20 +03007248 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007249 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007250 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007251 DEVLINK_NL_FLAG_NO_LOCK,
7252 },
7253 {
7254 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007255 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007256 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007257 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007258 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007259 DEVLINK_NL_FLAG_NO_LOCK,
7260 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007261 {
7262 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007263 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007264 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007265 .flags = GENL_ADMIN_PERM,
7266 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7267 },
Ido Schimmel0f420b62019-08-17 16:28:17 +03007268 {
7269 .cmd = DEVLINK_CMD_TRAP_GET,
7270 .doit = devlink_nl_cmd_trap_get_doit,
7271 .dumpit = devlink_nl_cmd_trap_get_dumpit,
7272 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7273 /* can be retrieved by unprivileged users */
7274 },
7275 {
7276 .cmd = DEVLINK_CMD_TRAP_SET,
7277 .doit = devlink_nl_cmd_trap_set_doit,
7278 .flags = GENL_ADMIN_PERM,
7279 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7280 },
7281 {
7282 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
7283 .doit = devlink_nl_cmd_trap_group_get_doit,
7284 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
7285 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7286 /* can be retrieved by unprivileged users */
7287 },
7288 {
7289 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
7290 .doit = devlink_nl_cmd_trap_group_set_doit,
7291 .flags = GENL_ADMIN_PERM,
7292 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7293 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007294 {
7295 .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
7296 .doit = devlink_nl_cmd_trap_policer_get_doit,
7297 .dumpit = devlink_nl_cmd_trap_policer_get_dumpit,
7298 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7299 /* can be retrieved by unprivileged users */
7300 },
7301 {
7302 .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
7303 .doit = devlink_nl_cmd_trap_policer_set_doit,
7304 .flags = GENL_ADMIN_PERM,
7305 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7306 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007307};
7308
Johannes Berg56989f62016-10-24 14:40:05 +02007309static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02007310 .name = DEVLINK_GENL_NAME,
7311 .version = DEVLINK_GENL_VERSION,
7312 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01007313 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02007314 .netnsok = true,
7315 .pre_doit = devlink_nl_pre_doit,
7316 .post_doit = devlink_nl_post_doit,
7317 .module = THIS_MODULE,
7318 .ops = devlink_nl_ops,
7319 .n_ops = ARRAY_SIZE(devlink_nl_ops),
7320 .mcgrps = devlink_nl_mcgrps,
7321 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
7322};
7323
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007324/**
7325 * devlink_alloc - Allocate new devlink instance resources
7326 *
7327 * @ops: ops
7328 * @priv_size: size of user private data
7329 *
7330 * Allocate new devlink instance resources, including devlink index
7331 * and name.
7332 */
7333struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
7334{
7335 struct devlink *devlink;
7336
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007337 if (WARN_ON(!ops))
7338 return NULL;
7339
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007340 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
7341 if (!devlink)
7342 return NULL;
7343 devlink->ops = ops;
Jacob Keller12102432020-03-26 11:37:15 -07007344 xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
Jiri Pirko8273fd82019-10-05 08:10:31 +02007345 __devlink_net_set(devlink, &init_net);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007346 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02007347 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007348 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007349 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03007350 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03007351 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02007352 INIT_LIST_HEAD(&devlink->reporter_list);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007353 INIT_LIST_HEAD(&devlink->trap_list);
7354 INIT_LIST_HEAD(&devlink->trap_group_list);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007355 INIT_LIST_HEAD(&devlink->trap_policer_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007356 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007357 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007358 return devlink;
7359}
7360EXPORT_SYMBOL_GPL(devlink_alloc);
7361
7362/**
7363 * devlink_register - Register devlink instance
7364 *
7365 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007366 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007367 */
7368int devlink_register(struct devlink *devlink, struct device *dev)
7369{
7370 mutex_lock(&devlink_mutex);
7371 devlink->dev = dev;
Jiri Pirko8273fd82019-10-05 08:10:31 +02007372 devlink->registered = true;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007373 list_add_tail(&devlink->list, &devlink_list);
7374 devlink_notify(devlink, DEVLINK_CMD_NEW);
7375 mutex_unlock(&devlink_mutex);
7376 return 0;
7377}
7378EXPORT_SYMBOL_GPL(devlink_register);
7379
7380/**
7381 * devlink_unregister - Unregister devlink instance
7382 *
7383 * @devlink: devlink
7384 */
7385void devlink_unregister(struct devlink *devlink)
7386{
7387 mutex_lock(&devlink_mutex);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007388 WARN_ON(devlink_reload_supported(devlink) &&
7389 devlink->reload_enabled);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007390 devlink_notify(devlink, DEVLINK_CMD_DEL);
7391 list_del(&devlink->list);
7392 mutex_unlock(&devlink_mutex);
7393}
7394EXPORT_SYMBOL_GPL(devlink_unregister);
7395
7396/**
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007397 * devlink_reload_enable - Enable reload of devlink instance
7398 *
7399 * @devlink: devlink
7400 *
7401 * Should be called at end of device initialization
7402 * process when reload operation is supported.
7403 */
7404void devlink_reload_enable(struct devlink *devlink)
7405{
7406 mutex_lock(&devlink_mutex);
7407 devlink->reload_enabled = true;
7408 mutex_unlock(&devlink_mutex);
7409}
7410EXPORT_SYMBOL_GPL(devlink_reload_enable);
7411
7412/**
7413 * devlink_reload_disable - Disable reload of devlink instance
7414 *
7415 * @devlink: devlink
7416 *
7417 * Should be called at the beginning of device cleanup
7418 * process when reload operation is supported.
7419 */
7420void devlink_reload_disable(struct devlink *devlink)
7421{
7422 mutex_lock(&devlink_mutex);
7423 /* Mutex is taken which ensures that no reload operation is in
7424 * progress while setting up forbidded flag.
7425 */
7426 devlink->reload_enabled = false;
7427 mutex_unlock(&devlink_mutex);
7428}
7429EXPORT_SYMBOL_GPL(devlink_reload_disable);
7430
7431/**
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007432 * devlink_free - Free devlink instance resources
7433 *
7434 * @devlink: devlink
7435 */
7436void devlink_free(struct devlink *devlink)
7437{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007438 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01007439 mutex_destroy(&devlink->lock);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007440 WARN_ON(!list_empty(&devlink->trap_policer_list));
Ido Schimmel0f420b62019-08-17 16:28:17 +03007441 WARN_ON(!list_empty(&devlink->trap_group_list));
7442 WARN_ON(!list_empty(&devlink->trap_list));
Parav Panditb904aad2019-02-08 15:15:00 -06007443 WARN_ON(!list_empty(&devlink->reporter_list));
7444 WARN_ON(!list_empty(&devlink->region_list));
7445 WARN_ON(!list_empty(&devlink->param_list));
7446 WARN_ON(!list_empty(&devlink->resource_list));
7447 WARN_ON(!list_empty(&devlink->dpipe_table_list));
7448 WARN_ON(!list_empty(&devlink->sb_list));
7449 WARN_ON(!list_empty(&devlink->port_list));
7450
Jacob Keller12102432020-03-26 11:37:15 -07007451 xa_destroy(&devlink->snapshot_ids);
7452
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007453 kfree(devlink);
7454}
7455EXPORT_SYMBOL_GPL(devlink_free);
7456
Jiri Pirko136bf272019-05-23 10:43:35 +02007457static void devlink_port_type_warn(struct work_struct *work)
7458{
7459 WARN(true, "Type was not set for devlink port.");
7460}
7461
7462static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
7463{
7464 /* Ignore CPU and DSA flavours. */
7465 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
7466 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
7467}
7468
Ido Schimmel4c582232020-01-09 19:57:41 +02007469#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
Jiri Pirko136bf272019-05-23 10:43:35 +02007470
7471static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
7472{
7473 if (!devlink_port_type_should_warn(devlink_port))
7474 return;
7475 /* Schedule a work to WARN in case driver does not set port
7476 * type within timeout.
7477 */
7478 schedule_delayed_work(&devlink_port->type_warn_dw,
7479 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
7480}
7481
7482static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
7483{
7484 if (!devlink_port_type_should_warn(devlink_port))
7485 return;
7486 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
7487}
7488
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007489/**
7490 * devlink_port_register - Register devlink port
7491 *
7492 * @devlink: devlink
7493 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007494 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007495 *
7496 * Register devlink port with provided port index. User can use
7497 * any indexing, even hw-related one. devlink_port structure
7498 * is convenient to be embedded inside user driver private structure.
7499 * Note that the caller should take care of zeroing the devlink_port
7500 * structure.
7501 */
7502int devlink_port_register(struct devlink *devlink,
7503 struct devlink_port *devlink_port,
7504 unsigned int port_index)
7505{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007506 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007507 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007508 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007509 return -EEXIST;
7510 }
7511 devlink_port->devlink = devlink;
7512 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007513 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01007514 spin_lock_init(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007515 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05307516 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007517 mutex_unlock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007518 INIT_LIST_HEAD(&devlink_port->reporter_list);
7519 mutex_init(&devlink_port->reporters_lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02007520 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
7521 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007522 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7523 return 0;
7524}
7525EXPORT_SYMBOL_GPL(devlink_port_register);
7526
7527/**
7528 * devlink_port_unregister - Unregister devlink port
7529 *
7530 * @devlink_port: devlink port
7531 */
7532void devlink_port_unregister(struct devlink_port *devlink_port)
7533{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007534 struct devlink *devlink = devlink_port->devlink;
7535
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007536 WARN_ON(!list_empty(&devlink_port->reporter_list));
7537 mutex_destroy(&devlink_port->reporters_lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02007538 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007539 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007540 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007541 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007542 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007543}
7544EXPORT_SYMBOL_GPL(devlink_port_unregister);
7545
7546static void __devlink_port_type_set(struct devlink_port *devlink_port,
7547 enum devlink_port_type type,
7548 void *type_dev)
7549{
Jiri Pirko2b239e72019-03-24 11:14:36 +01007550 if (WARN_ON(!devlink_port->registered))
7551 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02007552 devlink_port_type_warn_cancel(devlink_port);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007553 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007554 devlink_port->type = type;
7555 devlink_port->type_dev = type_dev;
Ido Schimmel0f420b62019-08-17 16:28:17 +03007556 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007557 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7558}
7559
7560/**
7561 * devlink_port_type_eth_set - Set port type to Ethernet
7562 *
7563 * @devlink_port: devlink port
7564 * @netdev: related netdevice
7565 */
7566void devlink_port_type_eth_set(struct devlink_port *devlink_port,
7567 struct net_device *netdev)
7568{
Jiri Pirko119c0b52019-04-03 14:24:27 +02007569 const struct net_device_ops *ops = netdev->netdev_ops;
7570
Jiri Pirko746364f2019-03-28 13:56:46 +01007571 /* If driver registers devlink port, it should set devlink port
7572 * attributes accordingly so the compat functions are called
7573 * and the original ops are not used.
7574 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02007575 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01007576 /* Some drivers use the same set of ndos for netdevs
7577 * that have devlink_port registered and also for
7578 * those who don't. Make sure that ndo_get_phys_port_name
7579 * returns -EOPNOTSUPP here in case it is defined.
7580 * Warn if not.
7581 */
Jiri Pirko746364f2019-03-28 13:56:46 +01007582 char name[IFNAMSIZ];
7583 int err;
7584
7585 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
7586 WARN_ON(err != -EOPNOTSUPP);
7587 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02007588 if (ops->ndo_get_port_parent_id) {
7589 /* Some drivers use the same set of ndos for netdevs
7590 * that have devlink_port registered and also for
7591 * those who don't. Make sure that ndo_get_port_parent_id
7592 * returns -EOPNOTSUPP here in case it is defined.
7593 * Warn if not.
7594 */
7595 struct netdev_phys_item_id ppid;
7596 int err;
7597
7598 err = ops->ndo_get_port_parent_id(netdev, &ppid);
7599 WARN_ON(err != -EOPNOTSUPP);
7600 }
Jiri Pirko773b1f32019-03-24 11:14:30 +01007601 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007602}
7603EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
7604
7605/**
7606 * devlink_port_type_ib_set - Set port type to InfiniBand
7607 *
7608 * @devlink_port: devlink port
7609 * @ibdev: related IB device
7610 */
7611void devlink_port_type_ib_set(struct devlink_port *devlink_port,
7612 struct ib_device *ibdev)
7613{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007614 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007615}
7616EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
7617
7618/**
7619 * devlink_port_type_clear - Clear port type
7620 *
7621 * @devlink_port: devlink port
7622 */
7623void devlink_port_type_clear(struct devlink_port *devlink_port)
7624{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007625 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02007626 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007627}
7628EXPORT_SYMBOL_GPL(devlink_port_type_clear);
7629
Parav Pandit378ef012019-07-08 23:17:35 -05007630static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007631 enum devlink_port_flavour flavour)
Parav Pandit378ef012019-07-08 23:17:35 -05007632{
7633 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7634
7635 if (WARN_ON(devlink_port->registered))
7636 return -EEXIST;
Danielle Ratson10a429b2020-07-09 16:18:14 +03007637 devlink_port->attrs_set = true;
Parav Pandit378ef012019-07-08 23:17:35 -05007638 attrs->flavour = flavour;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007639 if (attrs->switch_id.id_len) {
Danielle Ratson46737a12020-07-09 16:18:15 +03007640 devlink_port->switch_port = true;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007641 if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
7642 attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
Parav Pandit378ef012019-07-08 23:17:35 -05007643 } else {
Danielle Ratson46737a12020-07-09 16:18:15 +03007644 devlink_port->switch_port = false;
Parav Pandit378ef012019-07-08 23:17:35 -05007645 }
7646 return 0;
7647}
7648
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007649/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007650 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007651 *
7652 * @devlink_port: devlink port
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007653 * @attrs: devlink port attrs
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007654 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007655void devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007656 struct devlink_port_attrs *attrs)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007657{
Parav Pandit378ef012019-07-08 23:17:35 -05007658 int ret;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007659
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007660 devlink_port->attrs = *attrs;
7661 ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
Parav Pandit378ef012019-07-08 23:17:35 -05007662 if (ret)
Jiri Pirko45b86112019-03-24 11:14:33 +01007663 return;
Danielle Ratsona0f49b52020-07-09 16:18:20 +03007664 WARN_ON(attrs->splittable && attrs->split);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007665}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007666EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007667
Parav Pandit98fd2d62019-07-08 23:17:37 -05007668/**
7669 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
7670 *
7671 * @devlink_port: devlink port
7672 * @pf: associated PF for the devlink port instance
Parav Pandit98fd2d62019-07-08 23:17:37 -05007673 */
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007674void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u16 pf)
Parav Pandit98fd2d62019-07-08 23:17:37 -05007675{
7676 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7677 int ret;
7678
7679 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007680 DEVLINK_PORT_FLAVOUR_PCI_PF);
Parav Pandit98fd2d62019-07-08 23:17:37 -05007681 if (ret)
7682 return;
7683
7684 attrs->pci_pf.pf = pf;
7685}
7686EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
7687
Parav Pandite41b6bf2019-07-08 23:17:38 -05007688/**
7689 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
7690 *
7691 * @devlink_port: devlink port
7692 * @pf: associated PF for the devlink port instance
7693 * @vf: associated VF of a PF for the devlink port instance
Parav Pandite41b6bf2019-07-08 23:17:38 -05007694 */
7695void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
Parav Pandite41b6bf2019-07-08 23:17:38 -05007696 u16 pf, u16 vf)
7697{
7698 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7699 int ret;
7700
7701 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007702 DEVLINK_PORT_FLAVOUR_PCI_VF);
Parav Pandite41b6bf2019-07-08 23:17:38 -05007703 if (ret)
7704 return;
7705 attrs->pci_vf.pf = pf;
7706 attrs->pci_vf.vf = vf;
7707}
7708EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
7709
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007710static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
7711 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02007712{
7713 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7714 int n = 0;
7715
Danielle Ratson10a429b2020-07-09 16:18:14 +03007716 if (!devlink_port->attrs_set)
Jiri Pirko08474c12018-05-18 09:29:02 +02007717 return -EOPNOTSUPP;
7718
7719 switch (attrs->flavour) {
7720 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
Parav Panditacf1ee42020-03-03 08:12:42 -06007721 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Jiri Pirko08474c12018-05-18 09:29:02 +02007722 if (!attrs->split)
Parav Pandit378ef012019-07-08 23:17:35 -05007723 n = snprintf(name, len, "p%u", attrs->phys.port_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007724 else
Parav Pandit378ef012019-07-08 23:17:35 -05007725 n = snprintf(name, len, "p%us%u",
7726 attrs->phys.port_number,
7727 attrs->phys.split_subport_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007728 break;
7729 case DEVLINK_PORT_FLAVOUR_CPU:
7730 case DEVLINK_PORT_FLAVOUR_DSA:
7731 /* As CPU and DSA ports do not have a netdevice associated
7732 * case should not ever happen.
7733 */
7734 WARN_ON(1);
7735 return -EINVAL;
Parav Pandit98fd2d62019-07-08 23:17:37 -05007736 case DEVLINK_PORT_FLAVOUR_PCI_PF:
7737 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
7738 break;
Parav Pandite41b6bf2019-07-08 23:17:38 -05007739 case DEVLINK_PORT_FLAVOUR_PCI_VF:
7740 n = snprintf(name, len, "pf%uvf%u",
7741 attrs->pci_vf.pf, attrs->pci_vf.vf);
7742 break;
Jiri Pirko08474c12018-05-18 09:29:02 +02007743 }
7744
7745 if (n >= len)
7746 return -EINVAL;
7747
7748 return 0;
7749}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007750
Jiri Pirkobf797472016-04-14 18:19:13 +02007751int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
7752 u32 size, u16 ingress_pools_count,
7753 u16 egress_pools_count, u16 ingress_tc_count,
7754 u16 egress_tc_count)
7755{
7756 struct devlink_sb *devlink_sb;
7757 int err = 0;
7758
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007759 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007760 if (devlink_sb_index_exists(devlink, sb_index)) {
7761 err = -EEXIST;
7762 goto unlock;
7763 }
7764
7765 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
7766 if (!devlink_sb) {
7767 err = -ENOMEM;
7768 goto unlock;
7769 }
7770 devlink_sb->index = sb_index;
7771 devlink_sb->size = size;
7772 devlink_sb->ingress_pools_count = ingress_pools_count;
7773 devlink_sb->egress_pools_count = egress_pools_count;
7774 devlink_sb->ingress_tc_count = ingress_tc_count;
7775 devlink_sb->egress_tc_count = egress_tc_count;
7776 list_add_tail(&devlink_sb->list, &devlink->sb_list);
7777unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007778 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007779 return err;
7780}
7781EXPORT_SYMBOL_GPL(devlink_sb_register);
7782
7783void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
7784{
7785 struct devlink_sb *devlink_sb;
7786
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007787 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007788 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
7789 WARN_ON(!devlink_sb);
7790 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007791 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007792 kfree(devlink_sb);
7793}
7794EXPORT_SYMBOL_GPL(devlink_sb_unregister);
7795
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007796/**
7797 * devlink_dpipe_headers_register - register dpipe headers
7798 *
7799 * @devlink: devlink
7800 * @dpipe_headers: dpipe header array
7801 *
7802 * Register the headers supported by hardware.
7803 */
7804int devlink_dpipe_headers_register(struct devlink *devlink,
7805 struct devlink_dpipe_headers *dpipe_headers)
7806{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007807 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007808 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007809 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007810 return 0;
7811}
7812EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
7813
7814/**
7815 * devlink_dpipe_headers_unregister - unregister dpipe headers
7816 *
7817 * @devlink: devlink
7818 *
7819 * Unregister the headers supported by hardware.
7820 */
7821void devlink_dpipe_headers_unregister(struct devlink *devlink)
7822{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007823 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007824 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007825 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007826}
7827EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
7828
7829/**
7830 * devlink_dpipe_table_counter_enabled - check if counter allocation
7831 * required
7832 * @devlink: devlink
7833 * @table_name: tables name
7834 *
7835 * Used by driver to check if counter allocation is required.
7836 * After counter allocation is turned on the table entries
7837 * are updated to include counter statistics.
7838 *
7839 * After that point on the driver must respect the counter
7840 * state so that each entry added to the table is added
7841 * with a counter.
7842 */
7843bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
7844 const char *table_name)
7845{
7846 struct devlink_dpipe_table *table;
7847 bool enabled;
7848
7849 rcu_read_lock();
7850 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307851 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007852 enabled = false;
7853 if (table)
7854 enabled = table->counters_enabled;
7855 rcu_read_unlock();
7856 return enabled;
7857}
7858EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
7859
7860/**
7861 * devlink_dpipe_table_register - register dpipe table
7862 *
7863 * @devlink: devlink
7864 * @table_name: table name
7865 * @table_ops: table ops
7866 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007867 * @counter_control_extern: external control for counters
7868 */
7869int devlink_dpipe_table_register(struct devlink *devlink,
7870 const char *table_name,
7871 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02007872 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007873{
7874 struct devlink_dpipe_table *table;
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307875 int err = 0;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007876
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02007877 if (WARN_ON(!table_ops->size_get))
7878 return -EINVAL;
7879
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307880 mutex_lock(&devlink->lock);
7881
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307882 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
7883 devlink)) {
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307884 err = -EEXIST;
7885 goto unlock;
7886 }
7887
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007888 table = kzalloc(sizeof(*table), GFP_KERNEL);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307889 if (!table) {
7890 err = -ENOMEM;
7891 goto unlock;
7892 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007893
7894 table->name = table_name;
7895 table->table_ops = table_ops;
7896 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007897 table->counter_control_extern = counter_control_extern;
7898
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007899 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307900unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007901 mutex_unlock(&devlink->lock);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307902 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007903}
7904EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
7905
7906/**
7907 * devlink_dpipe_table_unregister - unregister dpipe table
7908 *
7909 * @devlink: devlink
7910 * @table_name: table name
7911 */
7912void devlink_dpipe_table_unregister(struct devlink *devlink,
7913 const char *table_name)
7914{
7915 struct devlink_dpipe_table *table;
7916
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007917 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007918 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307919 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007920 if (!table)
7921 goto unlock;
7922 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007923 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007924 kfree_rcu(table, rcu);
7925 return;
7926unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007927 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007928}
7929EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
7930
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007931/**
7932 * devlink_resource_register - devlink resource register
7933 *
7934 * @devlink: devlink
7935 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007936 * @resource_size: resource's size
7937 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007938 * @parent_resource_id: resource's parent id
7939 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007940 */
7941int devlink_resource_register(struct devlink *devlink,
7942 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007943 u64 resource_size,
7944 u64 resource_id,
7945 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02007946 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007947{
7948 struct devlink_resource *resource;
7949 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07007950 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007951 int err = 0;
7952
David Ahern14530742018-03-20 19:31:14 -07007953 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
7954
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007955 mutex_lock(&devlink->lock);
7956 resource = devlink_resource_find(devlink, NULL, resource_id);
7957 if (resource) {
7958 err = -EINVAL;
7959 goto out;
7960 }
7961
7962 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
7963 if (!resource) {
7964 err = -ENOMEM;
7965 goto out;
7966 }
7967
7968 if (top_hierarchy) {
7969 resource_list = &devlink->resource_list;
7970 } else {
7971 struct devlink_resource *parent_resource;
7972
7973 parent_resource = devlink_resource_find(devlink, NULL,
7974 parent_resource_id);
7975 if (parent_resource) {
7976 resource_list = &parent_resource->resource_list;
7977 resource->parent = parent_resource;
7978 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00007979 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007980 err = -EINVAL;
7981 goto out;
7982 }
7983 }
7984
7985 resource->name = resource_name;
7986 resource->size = resource_size;
7987 resource->size_new = resource_size;
7988 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007989 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01007990 memcpy(&resource->size_params, size_params,
7991 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007992 INIT_LIST_HEAD(&resource->resource_list);
7993 list_add_tail(&resource->list, resource_list);
7994out:
7995 mutex_unlock(&devlink->lock);
7996 return err;
7997}
7998EXPORT_SYMBOL_GPL(devlink_resource_register);
7999
8000/**
8001 * devlink_resources_unregister - free all resources
8002 *
8003 * @devlink: devlink
8004 * @resource: resource
8005 */
8006void devlink_resources_unregister(struct devlink *devlink,
8007 struct devlink_resource *resource)
8008{
8009 struct devlink_resource *tmp, *child_resource;
8010 struct list_head *resource_list;
8011
8012 if (resource)
8013 resource_list = &resource->resource_list;
8014 else
8015 resource_list = &devlink->resource_list;
8016
8017 if (!resource)
8018 mutex_lock(&devlink->lock);
8019
8020 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
8021 devlink_resources_unregister(devlink, child_resource);
8022 list_del(&child_resource->list);
8023 kfree(child_resource);
8024 }
8025
8026 if (!resource)
8027 mutex_unlock(&devlink->lock);
8028}
8029EXPORT_SYMBOL_GPL(devlink_resources_unregister);
8030
8031/**
8032 * devlink_resource_size_get - get and update size
8033 *
8034 * @devlink: devlink
8035 * @resource_id: the requested resource id
8036 * @p_resource_size: ptr to update
8037 */
8038int devlink_resource_size_get(struct devlink *devlink,
8039 u64 resource_id,
8040 u64 *p_resource_size)
8041{
8042 struct devlink_resource *resource;
8043 int err = 0;
8044
8045 mutex_lock(&devlink->lock);
8046 resource = devlink_resource_find(devlink, NULL, resource_id);
8047 if (!resource) {
8048 err = -EINVAL;
8049 goto out;
8050 }
8051 *p_resource_size = resource->size_new;
8052 resource->size = resource->size_new;
8053out:
8054 mutex_unlock(&devlink->lock);
8055 return err;
8056}
8057EXPORT_SYMBOL_GPL(devlink_resource_size_get);
8058
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008059/**
8060 * devlink_dpipe_table_resource_set - set the resource id
8061 *
8062 * @devlink: devlink
8063 * @table_name: table name
8064 * @resource_id: resource id
8065 * @resource_units: number of resource's units consumed per table's entry
8066 */
8067int devlink_dpipe_table_resource_set(struct devlink *devlink,
8068 const char *table_name, u64 resource_id,
8069 u64 resource_units)
8070{
8071 struct devlink_dpipe_table *table;
8072 int err = 0;
8073
8074 mutex_lock(&devlink->lock);
8075 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308076 table_name, devlink);
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008077 if (!table) {
8078 err = -EINVAL;
8079 goto out;
8080 }
8081 table->resource_id = resource_id;
8082 table->resource_units = resource_units;
8083 table->resource_valid = true;
8084out:
8085 mutex_unlock(&devlink->lock);
8086 return err;
8087}
8088EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
8089
Jiri Pirkofc56be42018-04-05 22:13:21 +02008090/**
8091 * devlink_resource_occ_get_register - register occupancy getter
8092 *
8093 * @devlink: devlink
8094 * @resource_id: resource id
8095 * @occ_get: occupancy getter callback
8096 * @occ_get_priv: occupancy getter callback priv
8097 */
8098void devlink_resource_occ_get_register(struct devlink *devlink,
8099 u64 resource_id,
8100 devlink_resource_occ_get_t *occ_get,
8101 void *occ_get_priv)
8102{
8103 struct devlink_resource *resource;
8104
8105 mutex_lock(&devlink->lock);
8106 resource = devlink_resource_find(devlink, NULL, resource_id);
8107 if (WARN_ON(!resource))
8108 goto out;
8109 WARN_ON(resource->occ_get);
8110
8111 resource->occ_get = occ_get;
8112 resource->occ_get_priv = occ_get_priv;
8113out:
8114 mutex_unlock(&devlink->lock);
8115}
8116EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
8117
8118/**
8119 * devlink_resource_occ_get_unregister - unregister occupancy getter
8120 *
8121 * @devlink: devlink
8122 * @resource_id: resource id
8123 */
8124void devlink_resource_occ_get_unregister(struct devlink *devlink,
8125 u64 resource_id)
8126{
8127 struct devlink_resource *resource;
8128
8129 mutex_lock(&devlink->lock);
8130 resource = devlink_resource_find(devlink, NULL, resource_id);
8131 if (WARN_ON(!resource))
8132 goto out;
8133 WARN_ON(!resource->occ_get);
8134
8135 resource->occ_get = NULL;
8136 resource->occ_get_priv = NULL;
8137out:
8138 mutex_unlock(&devlink->lock);
8139}
8140EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
8141
Vasundhara Volam39e61602019-01-28 18:00:20 +05308142static int devlink_param_verify(const struct devlink_param *param)
8143{
8144 if (!param || !param->name || !param->supported_cmodes)
8145 return -EINVAL;
8146 if (param->generic)
8147 return devlink_param_generic_verify(param);
8148 else
8149 return devlink_param_driver_verify(param);
8150}
8151
8152static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308153 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308154 struct list_head *param_list,
8155 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308156 size_t params_count,
8157 enum devlink_command reg_cmd,
8158 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308159{
8160 const struct devlink_param *param = params;
8161 int i;
8162 int err;
8163
8164 mutex_lock(&devlink->lock);
8165 for (i = 0; i < params_count; i++, param++) {
8166 err = devlink_param_verify(param);
8167 if (err)
8168 goto rollback;
8169
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308170 err = devlink_param_register_one(devlink, port_index,
8171 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308172 if (err)
8173 goto rollback;
8174 }
8175
8176 mutex_unlock(&devlink->lock);
8177 return 0;
8178
8179rollback:
8180 if (!i)
8181 goto unlock;
8182 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308183 devlink_param_unregister_one(devlink, port_index, param_list,
8184 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308185unlock:
8186 mutex_unlock(&devlink->lock);
8187 return err;
8188}
8189
8190static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308191 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308192 struct list_head *param_list,
8193 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308194 size_t params_count,
8195 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308196{
8197 const struct devlink_param *param = params;
8198 int i;
8199
8200 mutex_lock(&devlink->lock);
8201 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308202 devlink_param_unregister_one(devlink, 0, param_list, param,
8203 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308204 mutex_unlock(&devlink->lock);
8205}
8206
Moshe Shemesheabaef12018-07-04 14:30:28 +03008207/**
8208 * devlink_params_register - register configuration parameters
8209 *
8210 * @devlink: devlink
8211 * @params: configuration parameters array
8212 * @params_count: number of parameters provided
8213 *
8214 * Register the configuration parameters supported by the driver.
8215 */
8216int devlink_params_register(struct devlink *devlink,
8217 const struct devlink_param *params,
8218 size_t params_count)
8219{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308220 return __devlink_params_register(devlink, 0, &devlink->param_list,
8221 params, params_count,
8222 DEVLINK_CMD_PARAM_NEW,
8223 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008224}
8225EXPORT_SYMBOL_GPL(devlink_params_register);
8226
8227/**
8228 * devlink_params_unregister - unregister configuration parameters
8229 * @devlink: devlink
8230 * @params: configuration parameters to unregister
8231 * @params_count: number of parameters provided
8232 */
8233void devlink_params_unregister(struct devlink *devlink,
8234 const struct devlink_param *params,
8235 size_t params_count)
8236{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308237 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
8238 params, params_count,
8239 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008240}
8241EXPORT_SYMBOL_GPL(devlink_params_unregister);
8242
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008243/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00008244 * devlink_params_publish - publish configuration parameters
8245 *
8246 * @devlink: devlink
8247 *
8248 * Publish previously registered configuration parameters.
8249 */
8250void devlink_params_publish(struct devlink *devlink)
8251{
8252 struct devlink_param_item *param_item;
8253
8254 list_for_each_entry(param_item, &devlink->param_list, list) {
8255 if (param_item->published)
8256 continue;
8257 param_item->published = true;
8258 devlink_param_notify(devlink, 0, param_item,
8259 DEVLINK_CMD_PARAM_NEW);
8260 }
8261}
8262EXPORT_SYMBOL_GPL(devlink_params_publish);
8263
8264/**
8265 * devlink_params_unpublish - unpublish configuration parameters
8266 *
8267 * @devlink: devlink
8268 *
8269 * Unpublish previously registered configuration parameters.
8270 */
8271void devlink_params_unpublish(struct devlink *devlink)
8272{
8273 struct devlink_param_item *param_item;
8274
8275 list_for_each_entry(param_item, &devlink->param_list, list) {
8276 if (!param_item->published)
8277 continue;
8278 param_item->published = false;
8279 devlink_param_notify(devlink, 0, param_item,
8280 DEVLINK_CMD_PARAM_DEL);
8281 }
8282}
8283EXPORT_SYMBOL_GPL(devlink_params_unpublish);
8284
8285/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05308286 * devlink_port_params_register - register port configuration parameters
8287 *
8288 * @devlink_port: devlink port
8289 * @params: configuration parameters array
8290 * @params_count: number of parameters provided
8291 *
8292 * Register the configuration parameters supported by the port.
8293 */
8294int devlink_port_params_register(struct devlink_port *devlink_port,
8295 const struct devlink_param *params,
8296 size_t params_count)
8297{
8298 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308299 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308300 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308301 params_count,
8302 DEVLINK_CMD_PORT_PARAM_NEW,
8303 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308304}
8305EXPORT_SYMBOL_GPL(devlink_port_params_register);
8306
8307/**
8308 * devlink_port_params_unregister - unregister port configuration
8309 * parameters
8310 *
8311 * @devlink_port: devlink port
8312 * @params: configuration parameters array
8313 * @params_count: number of parameters provided
8314 */
8315void devlink_port_params_unregister(struct devlink_port *devlink_port,
8316 const struct devlink_param *params,
8317 size_t params_count)
8318{
8319 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308320 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308321 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308322 params, params_count,
8323 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308324}
8325EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
8326
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308327static int
8328__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
8329 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008330{
8331 struct devlink_param_item *param_item;
8332
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308333 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008334 if (!param_item)
8335 return -EINVAL;
8336
8337 if (!param_item->driverinit_value_valid ||
8338 !devlink_param_cmode_is_supported(param_item->param,
8339 DEVLINK_PARAM_CMODE_DRIVERINIT))
8340 return -EOPNOTSUPP;
8341
Moshe Shemesh12765342018-10-10 16:09:26 +03008342 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8343 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
8344 else
8345 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008346
8347 return 0;
8348}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308349
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308350static int
8351__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308352 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308353 struct list_head *param_list, u32 param_id,
8354 union devlink_param_value init_val,
8355 enum devlink_command cmd)
8356{
8357 struct devlink_param_item *param_item;
8358
8359 param_item = devlink_param_find_by_id(param_list, param_id);
8360 if (!param_item)
8361 return -EINVAL;
8362
8363 if (!devlink_param_cmode_is_supported(param_item->param,
8364 DEVLINK_PARAM_CMODE_DRIVERINIT))
8365 return -EOPNOTSUPP;
8366
8367 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8368 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
8369 else
8370 param_item->driverinit_value = init_val;
8371 param_item->driverinit_value_valid = true;
8372
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308373 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308374 return 0;
8375}
8376
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308377/**
8378 * devlink_param_driverinit_value_get - get configuration parameter
8379 * value for driver initializing
8380 *
8381 * @devlink: devlink
8382 * @param_id: parameter ID
8383 * @init_val: value of parameter in driverinit configuration mode
8384 *
8385 * This function should be used by the driver to get driverinit
8386 * configuration for initialization after reload command.
8387 */
8388int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
8389 union devlink_param_value *init_val)
8390{
Jiri Pirko97691062019-09-12 10:49:45 +02008391 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308392 return -EOPNOTSUPP;
8393
8394 return __devlink_param_driverinit_value_get(&devlink->param_list,
8395 param_id, init_val);
8396}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008397EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
8398
8399/**
8400 * devlink_param_driverinit_value_set - set value of configuration
8401 * parameter for driverinit
8402 * configuration mode
8403 *
8404 * @devlink: devlink
8405 * @param_id: parameter ID
8406 * @init_val: value of parameter to set for driverinit configuration mode
8407 *
8408 * This function should be used by the driver to set driverinit
8409 * configuration mode default value.
8410 */
8411int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
8412 union devlink_param_value init_val)
8413{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308414 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308415 &devlink->param_list,
8416 param_id, init_val,
8417 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008418}
8419EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
8420
Moshe Shemeshea601e12018-07-04 14:30:32 +03008421/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308422 * devlink_port_param_driverinit_value_get - get configuration parameter
8423 * value for driver initializing
8424 *
8425 * @devlink_port: devlink_port
8426 * @param_id: parameter ID
8427 * @init_val: value of parameter in driverinit configuration mode
8428 *
8429 * This function should be used by the driver to get driverinit
8430 * configuration for initialization after reload command.
8431 */
8432int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
8433 u32 param_id,
8434 union devlink_param_value *init_val)
8435{
8436 struct devlink *devlink = devlink_port->devlink;
8437
Jiri Pirko97691062019-09-12 10:49:45 +02008438 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308439 return -EOPNOTSUPP;
8440
8441 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
8442 param_id, init_val);
8443}
8444EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
8445
8446/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308447 * devlink_port_param_driverinit_value_set - set value of configuration
8448 * parameter for driverinit
8449 * configuration mode
8450 *
8451 * @devlink_port: devlink_port
8452 * @param_id: parameter ID
8453 * @init_val: value of parameter to set for driverinit configuration mode
8454 *
8455 * This function should be used by the driver to set driverinit
8456 * configuration mode default value.
8457 */
8458int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
8459 u32 param_id,
8460 union devlink_param_value init_val)
8461{
8462 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308463 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308464 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308465 param_id, init_val,
8466 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308467}
8468EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
8469
8470/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03008471 * devlink_param_value_changed - notify devlink on a parameter's value
8472 * change. Should be called by the driver
8473 * right after the change.
8474 *
8475 * @devlink: devlink
8476 * @param_id: parameter ID
8477 *
8478 * This function should be used by the driver to notify devlink on value
8479 * change, excluding driverinit configuration mode.
8480 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03008481 */
8482void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
8483{
8484 struct devlink_param_item *param_item;
8485
8486 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
8487 WARN_ON(!param_item);
8488
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308489 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03008490}
8491EXPORT_SYMBOL_GPL(devlink_param_value_changed);
8492
Alex Veskerb16ebe92018-07-12 15:13:08 +03008493/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308494 * devlink_port_param_value_changed - notify devlink on a parameter's value
8495 * change. Should be called by the driver
8496 * right after the change.
8497 *
8498 * @devlink_port: devlink_port
8499 * @param_id: parameter ID
8500 *
8501 * This function should be used by the driver to notify devlink on value
8502 * change, excluding driverinit configuration mode.
8503 * For driverinit configuration mode driver should use the function
8504 * devlink_port_param_driverinit_value_set() instead.
8505 */
8506void devlink_port_param_value_changed(struct devlink_port *devlink_port,
8507 u32 param_id)
8508{
8509 struct devlink_param_item *param_item;
8510
8511 param_item = devlink_param_find_by_id(&devlink_port->param_list,
8512 param_id);
8513 WARN_ON(!param_item);
8514
8515 devlink_param_notify(devlink_port->devlink, devlink_port->index,
8516 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
8517}
8518EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
8519
8520/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03008521 * devlink_param_value_str_fill - Safely fill-up the string preventing
8522 * from overflow of the preallocated buffer
8523 *
8524 * @dst_val: destination devlink_param_value
8525 * @src: source buffer
8526 */
8527void devlink_param_value_str_fill(union devlink_param_value *dst_val,
8528 const char *src)
8529{
8530 size_t len;
8531
8532 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
8533 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
8534}
8535EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
8536
8537/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03008538 * devlink_region_create - create a new address region
8539 *
8540 * @devlink: devlink
Jacob Kellere8937682020-03-26 11:37:08 -07008541 * @ops: region operations and name
Alex Veskerb16ebe92018-07-12 15:13:08 +03008542 * @region_max_snapshots: Maximum supported number of snapshots for region
8543 * @region_size: size of region
8544 */
Jacob Kellere8937682020-03-26 11:37:08 -07008545struct devlink_region *
8546devlink_region_create(struct devlink *devlink,
8547 const struct devlink_region_ops *ops,
8548 u32 region_max_snapshots, u64 region_size)
Alex Veskerb16ebe92018-07-12 15:13:08 +03008549{
8550 struct devlink_region *region;
8551 int err = 0;
8552
Jacob Kellera0a09f62020-03-26 11:37:09 -07008553 if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
8554 return ERR_PTR(-EINVAL);
8555
Alex Veskerb16ebe92018-07-12 15:13:08 +03008556 mutex_lock(&devlink->lock);
8557
Jacob Kellere8937682020-03-26 11:37:08 -07008558 if (devlink_region_get_by_name(devlink, ops->name)) {
Alex Veskerb16ebe92018-07-12 15:13:08 +03008559 err = -EEXIST;
8560 goto unlock;
8561 }
8562
8563 region = kzalloc(sizeof(*region), GFP_KERNEL);
8564 if (!region) {
8565 err = -ENOMEM;
8566 goto unlock;
8567 }
8568
8569 region->devlink = devlink;
8570 region->max_snapshots = region_max_snapshots;
Jacob Kellere8937682020-03-26 11:37:08 -07008571 region->ops = ops;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008572 region->size = region_size;
8573 INIT_LIST_HEAD(&region->snapshot_list);
8574 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03008575 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008576
8577 mutex_unlock(&devlink->lock);
8578 return region;
8579
8580unlock:
8581 mutex_unlock(&devlink->lock);
8582 return ERR_PTR(err);
8583}
8584EXPORT_SYMBOL_GPL(devlink_region_create);
8585
8586/**
8587 * devlink_region_destroy - destroy address region
8588 *
8589 * @region: devlink region to destroy
8590 */
8591void devlink_region_destroy(struct devlink_region *region)
8592{
8593 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008594 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008595
8596 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008597
8598 /* Free all snapshots of region */
8599 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
Jiri Pirko92b49822019-08-12 14:28:31 +02008600 devlink_region_snapshot_del(region, snapshot);
Alex Veskerd7e52722018-07-12 15:13:10 +03008601
Alex Veskerb16ebe92018-07-12 15:13:08 +03008602 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03008603
8604 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008605 mutex_unlock(&devlink->lock);
8606 kfree(region);
8607}
8608EXPORT_SYMBOL_GPL(devlink_region_destroy);
8609
Alex Veskerccadfa42018-07-12 15:13:09 +03008610/**
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008611 * devlink_region_snapshot_id_get - get snapshot ID
Alex Veskerccadfa42018-07-12 15:13:09 +03008612 *
8613 * This callback should be called when adding a new snapshot,
8614 * Driver should use the same id for multiple snapshots taken
8615 * on multiple regions at the same time/by the same trigger.
8616 *
Jacob Keller12102432020-03-26 11:37:15 -07008617 * The caller of this function must use devlink_region_snapshot_id_put
8618 * when finished creating regions using this id.
8619 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07008620 * Returns zero on success, or a negative error code on failure.
8621 *
Alex Veskerccadfa42018-07-12 15:13:09 +03008622 * @devlink: devlink
Jacob Keller7ef19d32020-03-26 11:37:14 -07008623 * @id: storage to return id
Alex Veskerccadfa42018-07-12 15:13:09 +03008624 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07008625int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Alex Veskerccadfa42018-07-12 15:13:09 +03008626{
Jacob Keller7ef19d32020-03-26 11:37:14 -07008627 int err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008628
8629 mutex_lock(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07008630 err = __devlink_region_snapshot_id_get(devlink, id);
Alex Veskerccadfa42018-07-12 15:13:09 +03008631 mutex_unlock(&devlink->lock);
8632
Jacob Keller7ef19d32020-03-26 11:37:14 -07008633 return err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008634}
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008635EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
Alex Veskerccadfa42018-07-12 15:13:09 +03008636
Alex Veskerd7e52722018-07-12 15:13:10 +03008637/**
Jacob Keller12102432020-03-26 11:37:15 -07008638 * devlink_region_snapshot_id_put - put snapshot ID reference
8639 *
8640 * This should be called by a driver after finishing creating snapshots
8641 * with an id. Doing so ensures that the ID can later be released in the
8642 * event that all snapshots using it have been destroyed.
8643 *
8644 * @devlink: devlink
8645 * @id: id to release reference on
8646 */
8647void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
8648{
8649 mutex_lock(&devlink->lock);
8650 __devlink_snapshot_id_decrement(devlink, id);
8651 mutex_unlock(&devlink->lock);
8652}
8653EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
8654
8655/**
Alex Veskerd7e52722018-07-12 15:13:10 +03008656 * devlink_region_snapshot_create - create a new snapshot
8657 * This will add a new snapshot of a region. The snapshot
8658 * will be stored on the region struct and can be accessed
Jacob Keller6d82f672020-03-26 11:37:10 -07008659 * from devlink. This is useful for future analyses of snapshots.
Alex Veskerd7e52722018-07-12 15:13:10 +03008660 * Multiple snapshots can be created on a region.
8661 * The @snapshot_id should be obtained using the getter function.
8662 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008663 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03008664 * @data: snapshot data
8665 * @snapshot_id: snapshot id to be created
Alex Veskerd7e52722018-07-12 15:13:10 +03008666 */
Jiri Pirko3a5e5232019-08-09 15:27:15 +02008667int devlink_region_snapshot_create(struct devlink_region *region,
Jacob Kellera0a09f62020-03-26 11:37:09 -07008668 u8 *data, u32 snapshot_id)
Alex Veskerd7e52722018-07-12 15:13:10 +03008669{
8670 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008671 int err;
8672
8673 mutex_lock(&devlink->lock);
Jacob Kellercf80fae2020-03-26 11:37:11 -07008674 err = __devlink_region_snapshot_create(region, data, snapshot_id);
Alex Veskerd7e52722018-07-12 15:13:10 +03008675 mutex_unlock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008676
Alex Veskerd7e52722018-07-12 15:13:10 +03008677 return err;
8678}
8679EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
8680
Ido Schimmel0f420b62019-08-17 16:28:17 +03008681#define DEVLINK_TRAP(_id, _type) \
8682 { \
8683 .type = DEVLINK_TRAP_TYPE_##_type, \
8684 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
8685 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
8686 }
8687
8688static const struct devlink_trap devlink_trap_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008689 DEVLINK_TRAP(SMAC_MC, DROP),
8690 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
8691 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
8692 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
8693 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
8694 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
8695 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
8696 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
8697 DEVLINK_TRAP(TAIL_DROP, DROP),
Amit Cohen6896cc42019-11-07 18:42:09 +02008698 DEVLINK_TRAP(NON_IP_PACKET, DROP),
8699 DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
8700 DEVLINK_TRAP(DIP_LB, DROP),
8701 DEVLINK_TRAP(SIP_MC, DROP),
8702 DEVLINK_TRAP(SIP_LB, DROP),
8703 DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
8704 DEVLINK_TRAP(IPV4_SIP_BC, DROP),
8705 DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
8706 DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
Amit Cohen3b063ae2019-11-07 18:42:14 +02008707 DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
8708 DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
8709 DEVLINK_TRAP(RPF, EXCEPTION),
8710 DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
8711 DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
8712 DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
Amit Cohen95f0ead2020-01-19 15:00:48 +02008713 DEVLINK_TRAP(NON_ROUTABLE, DROP),
Amit Cohen13c056e2020-01-19 15:00:54 +02008714 DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
Amit Cohenc3cae492020-01-19 15:00:58 +02008715 DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008716 DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
8717 DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
Ido Schimmel515eac62020-05-29 21:36:41 +03008718 DEVLINK_TRAP(STP, CONTROL),
8719 DEVLINK_TRAP(LACP, CONTROL),
8720 DEVLINK_TRAP(LLDP, CONTROL),
8721 DEVLINK_TRAP(IGMP_QUERY, CONTROL),
8722 DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
8723 DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
8724 DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
8725 DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
8726 DEVLINK_TRAP(MLD_QUERY, CONTROL),
8727 DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
8728 DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
8729 DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008730 DEVLINK_TRAP(IPV4_DHCP, CONTROL),
8731 DEVLINK_TRAP(IPV6_DHCP, CONTROL),
8732 DEVLINK_TRAP(ARP_REQUEST, CONTROL),
8733 DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
8734 DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
8735 DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
8736 DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
8737 DEVLINK_TRAP(IPV4_BFD, CONTROL),
8738 DEVLINK_TRAP(IPV6_BFD, CONTROL),
8739 DEVLINK_TRAP(IPV4_OSPF, CONTROL),
8740 DEVLINK_TRAP(IPV6_OSPF, CONTROL),
8741 DEVLINK_TRAP(IPV4_BGP, CONTROL),
8742 DEVLINK_TRAP(IPV6_BGP, CONTROL),
8743 DEVLINK_TRAP(IPV4_VRRP, CONTROL),
8744 DEVLINK_TRAP(IPV6_VRRP, CONTROL),
8745 DEVLINK_TRAP(IPV4_PIM, CONTROL),
8746 DEVLINK_TRAP(IPV6_PIM, CONTROL),
8747 DEVLINK_TRAP(UC_LB, CONTROL),
8748 DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
8749 DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
8750 DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
8751 DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
8752 DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
8753 DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
8754 DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
8755 DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
8756 DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
8757 DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
8758 DEVLINK_TRAP(PTP_EVENT, CONTROL),
8759 DEVLINK_TRAP(PTP_GENERAL, CONTROL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008760 DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
8761 DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008762};
8763
8764#define DEVLINK_TRAP_GROUP(_id) \
8765 { \
8766 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
8767 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
8768 }
8769
8770static const struct devlink_trap_group devlink_trap_group_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008771 DEVLINK_TRAP_GROUP(L2_DROPS),
8772 DEVLINK_TRAP_GROUP(L3_DROPS),
Ido Schimmel678eb192020-05-29 21:36:36 +03008773 DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
Ido Schimmel391203a2019-08-17 16:28:18 +03008774 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
Amit Cohen13c056e2020-01-19 15:00:54 +02008775 DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008776 DEVLINK_TRAP_GROUP(ACL_DROPS),
Ido Schimmel515eac62020-05-29 21:36:41 +03008777 DEVLINK_TRAP_GROUP(STP),
8778 DEVLINK_TRAP_GROUP(LACP),
8779 DEVLINK_TRAP_GROUP(LLDP),
8780 DEVLINK_TRAP_GROUP(MC_SNOOPING),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008781 DEVLINK_TRAP_GROUP(DHCP),
8782 DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
8783 DEVLINK_TRAP_GROUP(BFD),
8784 DEVLINK_TRAP_GROUP(OSPF),
8785 DEVLINK_TRAP_GROUP(BGP),
8786 DEVLINK_TRAP_GROUP(VRRP),
8787 DEVLINK_TRAP_GROUP(PIM),
8788 DEVLINK_TRAP_GROUP(UC_LB),
8789 DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
8790 DEVLINK_TRAP_GROUP(IPV6),
8791 DEVLINK_TRAP_GROUP(PTP_EVENT),
8792 DEVLINK_TRAP_GROUP(PTP_GENERAL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008793 DEVLINK_TRAP_GROUP(ACL_SAMPLE),
8794 DEVLINK_TRAP_GROUP(ACL_TRAP),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008795};
8796
8797static int devlink_trap_generic_verify(const struct devlink_trap *trap)
8798{
8799 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
8800 return -EINVAL;
8801
8802 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
8803 return -EINVAL;
8804
8805 if (trap->type != devlink_trap_generic[trap->id].type)
8806 return -EINVAL;
8807
8808 return 0;
8809}
8810
8811static int devlink_trap_driver_verify(const struct devlink_trap *trap)
8812{
8813 int i;
8814
8815 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
8816 return -EINVAL;
8817
8818 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
8819 if (!strcmp(trap->name, devlink_trap_generic[i].name))
8820 return -EEXIST;
8821 }
8822
8823 return 0;
8824}
8825
8826static int devlink_trap_verify(const struct devlink_trap *trap)
8827{
Ido Schimmel107f1672020-03-22 20:48:30 +02008828 if (!trap || !trap->name)
Ido Schimmel0f420b62019-08-17 16:28:17 +03008829 return -EINVAL;
8830
8831 if (trap->generic)
8832 return devlink_trap_generic_verify(trap);
8833 else
8834 return devlink_trap_driver_verify(trap);
8835}
8836
8837static int
8838devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
8839{
8840 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
8841 return -EINVAL;
8842
8843 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
8844 return -EINVAL;
8845
8846 return 0;
8847}
8848
8849static int
8850devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
8851{
8852 int i;
8853
8854 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
8855 return -EINVAL;
8856
8857 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
8858 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
8859 return -EEXIST;
8860 }
8861
8862 return 0;
8863}
8864
8865static int devlink_trap_group_verify(const struct devlink_trap_group *group)
8866{
8867 if (group->generic)
8868 return devlink_trap_group_generic_verify(group);
8869 else
8870 return devlink_trap_group_driver_verify(group);
8871}
8872
8873static void
8874devlink_trap_group_notify(struct devlink *devlink,
8875 const struct devlink_trap_group_item *group_item,
8876 enum devlink_command cmd)
8877{
8878 struct sk_buff *msg;
8879 int err;
8880
8881 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
8882 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
8883
8884 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8885 if (!msg)
8886 return;
8887
8888 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
8889 0);
8890 if (err) {
8891 nlmsg_free(msg);
8892 return;
8893 }
8894
8895 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
8896 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
8897}
8898
Ido Schimmel0f420b62019-08-17 16:28:17 +03008899static int
8900devlink_trap_item_group_link(struct devlink *devlink,
8901 struct devlink_trap_item *trap_item)
8902{
Ido Schimmel107f1672020-03-22 20:48:30 +02008903 u16 group_id = trap_item->trap->init_group_id;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008904 struct devlink_trap_group_item *group_item;
8905
Ido Schimmel107f1672020-03-22 20:48:30 +02008906 group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
Ido Schimmela09b37f2020-03-22 20:48:29 +02008907 if (WARN_ON_ONCE(!group_item))
8908 return -EINVAL;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008909
8910 trap_item->group_item = group_item;
8911
8912 return 0;
8913}
8914
Ido Schimmel0f420b62019-08-17 16:28:17 +03008915static void devlink_trap_notify(struct devlink *devlink,
8916 const struct devlink_trap_item *trap_item,
8917 enum devlink_command cmd)
8918{
8919 struct sk_buff *msg;
8920 int err;
8921
8922 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
8923 cmd != DEVLINK_CMD_TRAP_DEL);
8924
8925 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8926 if (!msg)
8927 return;
8928
8929 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
8930 if (err) {
8931 nlmsg_free(msg);
8932 return;
8933 }
8934
8935 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
8936 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
8937}
8938
8939static int
8940devlink_trap_register(struct devlink *devlink,
8941 const struct devlink_trap *trap, void *priv)
8942{
8943 struct devlink_trap_item *trap_item;
8944 int err;
8945
8946 if (devlink_trap_item_lookup(devlink, trap->name))
8947 return -EEXIST;
8948
8949 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
8950 if (!trap_item)
8951 return -ENOMEM;
8952
8953 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
8954 if (!trap_item->stats) {
8955 err = -ENOMEM;
8956 goto err_stats_alloc;
8957 }
8958
8959 trap_item->trap = trap;
8960 trap_item->action = trap->init_action;
8961 trap_item->priv = priv;
8962
8963 err = devlink_trap_item_group_link(devlink, trap_item);
8964 if (err)
8965 goto err_group_link;
8966
8967 err = devlink->ops->trap_init(devlink, trap, trap_item);
8968 if (err)
8969 goto err_trap_init;
8970
8971 list_add_tail(&trap_item->list, &devlink->trap_list);
8972 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
8973
8974 return 0;
8975
8976err_trap_init:
Ido Schimmel0f420b62019-08-17 16:28:17 +03008977err_group_link:
8978 free_percpu(trap_item->stats);
8979err_stats_alloc:
8980 kfree(trap_item);
8981 return err;
8982}
8983
8984static void devlink_trap_unregister(struct devlink *devlink,
8985 const struct devlink_trap *trap)
8986{
8987 struct devlink_trap_item *trap_item;
8988
8989 trap_item = devlink_trap_item_lookup(devlink, trap->name);
8990 if (WARN_ON_ONCE(!trap_item))
8991 return;
8992
8993 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
8994 list_del(&trap_item->list);
8995 if (devlink->ops->trap_fini)
8996 devlink->ops->trap_fini(devlink, trap, trap_item);
Ido Schimmel0f420b62019-08-17 16:28:17 +03008997 free_percpu(trap_item->stats);
8998 kfree(trap_item);
8999}
9000
9001static void devlink_trap_disable(struct devlink *devlink,
9002 const struct devlink_trap *trap)
9003{
9004 struct devlink_trap_item *trap_item;
9005
9006 trap_item = devlink_trap_item_lookup(devlink, trap->name);
9007 if (WARN_ON_ONCE(!trap_item))
9008 return;
9009
9010 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP);
9011 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
9012}
9013
9014/**
9015 * devlink_traps_register - Register packet traps with devlink.
9016 * @devlink: devlink.
9017 * @traps: Packet traps.
9018 * @traps_count: Count of provided packet traps.
9019 * @priv: Driver private information.
9020 *
9021 * Return: Non-zero value on failure.
9022 */
9023int devlink_traps_register(struct devlink *devlink,
9024 const struct devlink_trap *traps,
9025 size_t traps_count, void *priv)
9026{
9027 int i, err;
9028
9029 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
9030 return -EINVAL;
9031
9032 mutex_lock(&devlink->lock);
9033 for (i = 0; i < traps_count; i++) {
9034 const struct devlink_trap *trap = &traps[i];
9035
9036 err = devlink_trap_verify(trap);
9037 if (err)
9038 goto err_trap_verify;
9039
9040 err = devlink_trap_register(devlink, trap, priv);
9041 if (err)
9042 goto err_trap_register;
9043 }
9044 mutex_unlock(&devlink->lock);
9045
9046 return 0;
9047
9048err_trap_register:
9049err_trap_verify:
9050 for (i--; i >= 0; i--)
9051 devlink_trap_unregister(devlink, &traps[i]);
9052 mutex_unlock(&devlink->lock);
9053 return err;
9054}
9055EXPORT_SYMBOL_GPL(devlink_traps_register);
9056
9057/**
9058 * devlink_traps_unregister - Unregister packet traps from devlink.
9059 * @devlink: devlink.
9060 * @traps: Packet traps.
9061 * @traps_count: Count of provided packet traps.
9062 */
9063void devlink_traps_unregister(struct devlink *devlink,
9064 const struct devlink_trap *traps,
9065 size_t traps_count)
9066{
9067 int i;
9068
9069 mutex_lock(&devlink->lock);
9070 /* Make sure we do not have any packets in-flight while unregistering
9071 * traps by disabling all of them and waiting for a grace period.
9072 */
9073 for (i = traps_count - 1; i >= 0; i--)
9074 devlink_trap_disable(devlink, &traps[i]);
9075 synchronize_rcu();
9076 for (i = traps_count - 1; i >= 0; i--)
9077 devlink_trap_unregister(devlink, &traps[i]);
9078 mutex_unlock(&devlink->lock);
9079}
9080EXPORT_SYMBOL_GPL(devlink_traps_unregister);
9081
9082static void
9083devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
9084 size_t skb_len)
9085{
9086 struct devlink_stats *stats;
9087
9088 stats = this_cpu_ptr(trap_stats);
9089 u64_stats_update_begin(&stats->syncp);
9090 stats->rx_bytes += skb_len;
9091 stats->rx_packets++;
9092 u64_stats_update_end(&stats->syncp);
9093}
9094
9095static void
9096devlink_trap_report_metadata_fill(struct net_dm_hw_metadata *hw_metadata,
9097 const struct devlink_trap_item *trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009098 struct devlink_port *in_devlink_port,
9099 const struct flow_action_cookie *fa_cookie)
Ido Schimmel0f420b62019-08-17 16:28:17 +03009100{
9101 struct devlink_trap_group_item *group_item = trap_item->group_item;
9102
9103 hw_metadata->trap_group_name = group_item->group->name;
9104 hw_metadata->trap_name = trap_item->trap->name;
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009105 hw_metadata->fa_cookie = fa_cookie;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009106
9107 spin_lock(&in_devlink_port->type_lock);
9108 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
9109 hw_metadata->input_dev = in_devlink_port->type_dev;
9110 spin_unlock(&in_devlink_port->type_lock);
9111}
9112
9113/**
9114 * devlink_trap_report - Report trapped packet to drop monitor.
9115 * @devlink: devlink.
9116 * @skb: Trapped packet.
9117 * @trap_ctx: Trap context.
9118 * @in_devlink_port: Input devlink port.
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009119 * @fa_cookie: Flow action cookie. Could be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03009120 */
9121void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009122 void *trap_ctx, struct devlink_port *in_devlink_port,
9123 const struct flow_action_cookie *fa_cookie)
9124
Ido Schimmel0f420b62019-08-17 16:28:17 +03009125{
9126 struct devlink_trap_item *trap_item = trap_ctx;
9127 struct net_dm_hw_metadata hw_metadata = {};
9128
9129 devlink_trap_stats_update(trap_item->stats, skb->len);
9130 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
9131
Ido Schimmel30a4e9a2020-05-29 21:36:40 +03009132 /* Control packets were not dropped by the device or encountered an
9133 * exception during forwarding and therefore should not be reported to
9134 * the kernel's drop monitor.
9135 */
9136 if (trap_item->trap->type == DEVLINK_TRAP_TYPE_CONTROL)
9137 return;
9138
Ido Schimmel0f420b62019-08-17 16:28:17 +03009139 devlink_trap_report_metadata_fill(&hw_metadata, trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009140 in_devlink_port, fa_cookie);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009141 net_dm_hw_report(skb, &hw_metadata);
9142}
9143EXPORT_SYMBOL_GPL(devlink_trap_report);
9144
9145/**
9146 * devlink_trap_ctx_priv - Trap context to driver private information.
9147 * @trap_ctx: Trap context.
9148 *
9149 * Return: Driver private information passed during registration.
9150 */
9151void *devlink_trap_ctx_priv(void *trap_ctx)
9152{
9153 struct devlink_trap_item *trap_item = trap_ctx;
9154
9155 return trap_item->priv;
9156}
9157EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
9158
Ido Schimmel95ad9552020-03-22 20:48:26 +02009159static int
Ido Schimmelf9f54392020-03-30 22:38:21 +03009160devlink_trap_group_item_policer_link(struct devlink *devlink,
9161 struct devlink_trap_group_item *group_item)
9162{
9163 u32 policer_id = group_item->group->init_policer_id;
9164 struct devlink_trap_policer_item *policer_item;
9165
9166 if (policer_id == 0)
9167 return 0;
9168
9169 policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
9170 if (WARN_ON_ONCE(!policer_item))
9171 return -EINVAL;
9172
9173 group_item->policer_item = policer_item;
9174
9175 return 0;
9176}
9177
9178static int
Ido Schimmel95ad9552020-03-22 20:48:26 +02009179devlink_trap_group_register(struct devlink *devlink,
9180 const struct devlink_trap_group *group)
9181{
9182 struct devlink_trap_group_item *group_item;
9183 int err;
9184
9185 if (devlink_trap_group_item_lookup(devlink, group->name))
9186 return -EEXIST;
9187
9188 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
9189 if (!group_item)
9190 return -ENOMEM;
9191
9192 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9193 if (!group_item->stats) {
9194 err = -ENOMEM;
9195 goto err_stats_alloc;
9196 }
9197
9198 group_item->group = group;
Ido Schimmel95ad9552020-03-22 20:48:26 +02009199
Ido Schimmelf9f54392020-03-30 22:38:21 +03009200 err = devlink_trap_group_item_policer_link(devlink, group_item);
9201 if (err)
9202 goto err_policer_link;
9203
Ido Schimmel95ad9552020-03-22 20:48:26 +02009204 if (devlink->ops->trap_group_init) {
9205 err = devlink->ops->trap_group_init(devlink, group);
9206 if (err)
9207 goto err_group_init;
9208 }
9209
9210 list_add_tail(&group_item->list, &devlink->trap_group_list);
9211 devlink_trap_group_notify(devlink, group_item,
9212 DEVLINK_CMD_TRAP_GROUP_NEW);
9213
9214 return 0;
9215
9216err_group_init:
Ido Schimmelf9f54392020-03-30 22:38:21 +03009217err_policer_link:
Ido Schimmel95ad9552020-03-22 20:48:26 +02009218 free_percpu(group_item->stats);
9219err_stats_alloc:
9220 kfree(group_item);
9221 return err;
9222}
9223
9224static void
9225devlink_trap_group_unregister(struct devlink *devlink,
9226 const struct devlink_trap_group *group)
9227{
9228 struct devlink_trap_group_item *group_item;
9229
9230 group_item = devlink_trap_group_item_lookup(devlink, group->name);
9231 if (WARN_ON_ONCE(!group_item))
9232 return;
9233
9234 devlink_trap_group_notify(devlink, group_item,
9235 DEVLINK_CMD_TRAP_GROUP_DEL);
9236 list_del(&group_item->list);
9237 free_percpu(group_item->stats);
9238 kfree(group_item);
9239}
9240
9241/**
9242 * devlink_trap_groups_register - Register packet trap groups with devlink.
9243 * @devlink: devlink.
9244 * @groups: Packet trap groups.
9245 * @groups_count: Count of provided packet trap groups.
9246 *
9247 * Return: Non-zero value on failure.
9248 */
9249int devlink_trap_groups_register(struct devlink *devlink,
9250 const struct devlink_trap_group *groups,
9251 size_t groups_count)
9252{
9253 int i, err;
9254
9255 mutex_lock(&devlink->lock);
9256 for (i = 0; i < groups_count; i++) {
9257 const struct devlink_trap_group *group = &groups[i];
9258
9259 err = devlink_trap_group_verify(group);
9260 if (err)
9261 goto err_trap_group_verify;
9262
9263 err = devlink_trap_group_register(devlink, group);
9264 if (err)
9265 goto err_trap_group_register;
9266 }
9267 mutex_unlock(&devlink->lock);
9268
9269 return 0;
9270
9271err_trap_group_register:
9272err_trap_group_verify:
9273 for (i--; i >= 0; i--)
9274 devlink_trap_group_unregister(devlink, &groups[i]);
9275 mutex_unlock(&devlink->lock);
9276 return err;
9277}
9278EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
9279
9280/**
9281 * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
9282 * @devlink: devlink.
9283 * @groups: Packet trap groups.
9284 * @groups_count: Count of provided packet trap groups.
9285 */
9286void devlink_trap_groups_unregister(struct devlink *devlink,
9287 const struct devlink_trap_group *groups,
9288 size_t groups_count)
9289{
9290 int i;
9291
9292 mutex_lock(&devlink->lock);
9293 for (i = groups_count - 1; i >= 0; i--)
9294 devlink_trap_group_unregister(devlink, &groups[i]);
9295 mutex_unlock(&devlink->lock);
9296}
9297EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
9298
Ido Schimmel1e8c6612020-03-30 22:38:18 +03009299static void
9300devlink_trap_policer_notify(struct devlink *devlink,
9301 const struct devlink_trap_policer_item *policer_item,
9302 enum devlink_command cmd)
9303{
9304 struct sk_buff *msg;
9305 int err;
9306
9307 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
9308 cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
9309
9310 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9311 if (!msg)
9312 return;
9313
9314 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
9315 0, 0);
9316 if (err) {
9317 nlmsg_free(msg);
9318 return;
9319 }
9320
9321 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9322 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9323}
9324
9325static int
9326devlink_trap_policer_register(struct devlink *devlink,
9327 const struct devlink_trap_policer *policer)
9328{
9329 struct devlink_trap_policer_item *policer_item;
9330 int err;
9331
9332 if (devlink_trap_policer_item_lookup(devlink, policer->id))
9333 return -EEXIST;
9334
9335 policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
9336 if (!policer_item)
9337 return -ENOMEM;
9338
9339 policer_item->policer = policer;
9340 policer_item->rate = policer->init_rate;
9341 policer_item->burst = policer->init_burst;
9342
9343 if (devlink->ops->trap_policer_init) {
9344 err = devlink->ops->trap_policer_init(devlink, policer);
9345 if (err)
9346 goto err_policer_init;
9347 }
9348
9349 list_add_tail(&policer_item->list, &devlink->trap_policer_list);
9350 devlink_trap_policer_notify(devlink, policer_item,
9351 DEVLINK_CMD_TRAP_POLICER_NEW);
9352
9353 return 0;
9354
9355err_policer_init:
9356 kfree(policer_item);
9357 return err;
9358}
9359
9360static void
9361devlink_trap_policer_unregister(struct devlink *devlink,
9362 const struct devlink_trap_policer *policer)
9363{
9364 struct devlink_trap_policer_item *policer_item;
9365
9366 policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
9367 if (WARN_ON_ONCE(!policer_item))
9368 return;
9369
9370 devlink_trap_policer_notify(devlink, policer_item,
9371 DEVLINK_CMD_TRAP_POLICER_DEL);
9372 list_del(&policer_item->list);
9373 if (devlink->ops->trap_policer_fini)
9374 devlink->ops->trap_policer_fini(devlink, policer);
9375 kfree(policer_item);
9376}
9377
9378/**
9379 * devlink_trap_policers_register - Register packet trap policers with devlink.
9380 * @devlink: devlink.
9381 * @policers: Packet trap policers.
9382 * @policers_count: Count of provided packet trap policers.
9383 *
9384 * Return: Non-zero value on failure.
9385 */
9386int
9387devlink_trap_policers_register(struct devlink *devlink,
9388 const struct devlink_trap_policer *policers,
9389 size_t policers_count)
9390{
9391 int i, err;
9392
9393 mutex_lock(&devlink->lock);
9394 for (i = 0; i < policers_count; i++) {
9395 const struct devlink_trap_policer *policer = &policers[i];
9396
9397 if (WARN_ON(policer->id == 0 ||
9398 policer->max_rate < policer->min_rate ||
9399 policer->max_burst < policer->min_burst)) {
9400 err = -EINVAL;
9401 goto err_trap_policer_verify;
9402 }
9403
9404 err = devlink_trap_policer_register(devlink, policer);
9405 if (err)
9406 goto err_trap_policer_register;
9407 }
9408 mutex_unlock(&devlink->lock);
9409
9410 return 0;
9411
9412err_trap_policer_register:
9413err_trap_policer_verify:
9414 for (i--; i >= 0; i--)
9415 devlink_trap_policer_unregister(devlink, &policers[i]);
9416 mutex_unlock(&devlink->lock);
9417 return err;
9418}
9419EXPORT_SYMBOL_GPL(devlink_trap_policers_register);
9420
9421/**
9422 * devlink_trap_policers_unregister - Unregister packet trap policers from devlink.
9423 * @devlink: devlink.
9424 * @policers: Packet trap policers.
9425 * @policers_count: Count of provided packet trap policers.
9426 */
9427void
9428devlink_trap_policers_unregister(struct devlink *devlink,
9429 const struct devlink_trap_policer *policers,
9430 size_t policers_count)
9431{
9432 int i;
9433
9434 mutex_lock(&devlink->lock);
9435 for (i = policers_count - 1; i >= 0; i--)
9436 devlink_trap_policer_unregister(devlink, &policers[i]);
9437 mutex_unlock(&devlink->lock);
9438}
9439EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister);
9440
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009441static void __devlink_compat_running_version(struct devlink *devlink,
9442 char *buf, size_t len)
9443{
9444 const struct nlattr *nlattr;
9445 struct devlink_info_req req;
9446 struct sk_buff *msg;
9447 int rem, err;
9448
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009449 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9450 if (!msg)
9451 return;
9452
9453 req.msg = msg;
9454 err = devlink->ops->info_get(devlink, &req, NULL);
9455 if (err)
9456 goto free_msg;
9457
9458 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
9459 const struct nlattr *kv;
9460 int rem_kv;
9461
9462 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
9463 continue;
9464
9465 nla_for_each_nested(kv, nlattr, rem_kv) {
9466 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
9467 continue;
9468
9469 strlcat(buf, nla_data(kv), len);
9470 strlcat(buf, " ", len);
9471 }
9472 }
9473free_msg:
9474 nlmsg_free(msg);
9475}
9476
9477void devlink_compat_running_version(struct net_device *dev,
9478 char *buf, size_t len)
9479{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009480 struct devlink *devlink;
9481
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009482 dev_hold(dev);
9483 rtnl_unlock();
9484
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009485 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08009486 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009487 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009488
9489 mutex_lock(&devlink->lock);
9490 __devlink_compat_running_version(devlink, buf, len);
9491 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009492
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009493out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009494 rtnl_lock();
9495 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009496}
9497
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009498int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
9499{
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009500 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009501 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009502
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009503 dev_hold(dev);
9504 rtnl_unlock();
9505
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009506 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009507 if (!devlink || !devlink->ops->flash_update) {
9508 ret = -EOPNOTSUPP;
9509 goto out;
9510 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009511
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009512 mutex_lock(&devlink->lock);
9513 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
9514 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009515
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009516out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009517 rtnl_lock();
9518 dev_put(dev);
9519
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009520 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009521}
9522
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01009523int devlink_compat_phys_port_name_get(struct net_device *dev,
9524 char *name, size_t len)
9525{
9526 struct devlink_port *devlink_port;
9527
9528 /* RTNL mutex is held here which ensures that devlink_port
9529 * instance cannot disappear in the middle. No need to take
9530 * any devlink lock as only permanent values are accessed.
9531 */
9532 ASSERT_RTNL();
9533
9534 devlink_port = netdev_to_devlink_port(dev);
9535 if (!devlink_port)
9536 return -EOPNOTSUPP;
9537
9538 return __devlink_port_phys_port_name_get(devlink_port, name, len);
9539}
9540
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009541int devlink_compat_switch_id_get(struct net_device *dev,
9542 struct netdev_phys_item_id *ppid)
9543{
9544 struct devlink_port *devlink_port;
9545
Vlad Buslov043b8412019-08-12 20:02:02 +03009546 /* Caller must hold RTNL mutex or reference to dev, which ensures that
9547 * devlink_port instance cannot disappear in the middle. No need to take
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009548 * any devlink lock as only permanent values are accessed.
9549 */
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009550 devlink_port = netdev_to_devlink_port(dev);
Danielle Ratson46737a12020-07-09 16:18:15 +03009551 if (!devlink_port || !devlink_port->switch_port)
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009552 return -EOPNOTSUPP;
9553
9554 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
9555
9556 return 0;
9557}
9558
Jiri Pirko070c63f2019-10-03 11:49:39 +02009559static void __net_exit devlink_pernet_pre_exit(struct net *net)
9560{
9561 struct devlink *devlink;
9562 int err;
9563
9564 /* In case network namespace is getting destroyed, reload
9565 * all devlink instances from this namespace into init_net.
9566 */
9567 mutex_lock(&devlink_mutex);
9568 list_for_each_entry(devlink, &devlink_list, list) {
9569 if (net_eq(devlink_net(devlink), net)) {
9570 if (WARN_ON(!devlink_reload_supported(devlink)))
9571 continue;
9572 err = devlink_reload(devlink, &init_net, NULL);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01009573 if (err && err != -EOPNOTSUPP)
Jiri Pirko070c63f2019-10-03 11:49:39 +02009574 pr_warn("Failed to reload devlink instance into init_net\n");
9575 }
9576 }
9577 mutex_unlock(&devlink_mutex);
9578}
9579
9580static struct pernet_operations devlink_pernet_ops __net_initdata = {
9581 .pre_exit = devlink_pernet_pre_exit,
9582};
9583
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009584static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009585{
Jiri Pirko070c63f2019-10-03 11:49:39 +02009586 int err;
9587
9588 err = genl_register_family(&devlink_nl_family);
9589 if (err)
9590 goto out;
9591 err = register_pernet_subsys(&devlink_pernet_ops);
9592
9593out:
9594 WARN_ON(err);
9595 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009596}
9597
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009598subsys_initcall(devlink_init);