blob: 7df918a5899e4b110f3c56d7e4b35d34443348d4 [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 Kellerb9a17ab2020-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 Kellerb9a17ab2020-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 Kellerb9a17ab2020-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 Kellerb9a17ab2020-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 Kellerb9a17ab2020-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 Kellerb9a17ab2020-03-26 11:37:16 -07004292 }
4293
Jacob Kellerb9a17ab2020-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 Kellerb9a17ab2020-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 Kellerb9a17ab2020-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/**
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005375 * devlink_port_health_reporter_create - create devlink health reporter for
5376 * specified port instance
5377 *
5378 * @port: devlink_port which should contain the new reporter
5379 * @ops: ops
5380 * @graceful_period: to avoid recovery loops, in msecs
5381 * @priv: priv
5382 */
5383struct devlink_health_reporter *
5384devlink_port_health_reporter_create(struct devlink_port *port,
5385 const struct devlink_health_reporter_ops *ops,
5386 u64 graceful_period, void *priv)
5387{
5388 struct devlink_health_reporter *reporter;
5389
5390 mutex_lock(&port->reporters_lock);
5391 if (__devlink_health_reporter_find_by_name(&port->reporter_list,
5392 &port->reporters_lock, ops->name)) {
5393 reporter = ERR_PTR(-EEXIST);
5394 goto unlock;
5395 }
5396
5397 reporter = __devlink_health_reporter_create(port->devlink, ops,
5398 graceful_period, priv);
5399 if (IS_ERR(reporter))
5400 goto unlock;
5401
5402 reporter->devlink_port = port;
5403 list_add_tail(&reporter->list, &port->reporter_list);
5404unlock:
5405 mutex_unlock(&port->reporters_lock);
5406 return reporter;
5407}
5408EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
5409
5410/**
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005411 * devlink_health_reporter_create - create devlink health reporter
5412 *
5413 * @devlink: devlink
5414 * @ops: ops
5415 * @graceful_period: to avoid recovery loops, in msecs
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005416 * @priv: priv
5417 */
5418struct devlink_health_reporter *
5419devlink_health_reporter_create(struct devlink *devlink,
5420 const struct devlink_health_reporter_ops *ops,
Eran Ben Elishaba7d16c2020-03-29 14:05:54 +03005421 u64 graceful_period, void *priv)
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005422{
5423 struct devlink_health_reporter *reporter;
5424
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005425 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005426 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
5427 reporter = ERR_PTR(-EEXIST);
5428 goto unlock;
5429 }
5430
Vladyslav Tarasiukc57544b2020-07-10 15:25:07 +03005431 reporter = __devlink_health_reporter_create(devlink, ops,
5432 graceful_period, priv);
5433 if (IS_ERR(reporter))
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005434 goto unlock;
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005435
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005436 list_add_tail(&reporter->list, &devlink->reporter_list);
5437unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005438 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005439 return reporter;
5440}
5441EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
5442
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005443static void
5444devlink_health_reporter_free(struct devlink_health_reporter *reporter)
5445{
5446 mutex_destroy(&reporter->dump_lock);
5447 if (reporter->dump_fmsg)
5448 devlink_fmsg_free(reporter->dump_fmsg);
5449 kfree(reporter);
5450}
5451
5452static void
5453devlink_health_reporter_put(struct devlink_health_reporter *reporter)
5454{
5455 if (refcount_dec_and_test(&reporter->refcount))
5456 devlink_health_reporter_free(reporter);
5457}
5458
5459static void
5460__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5461{
5462 list_del(&reporter->list);
5463 devlink_health_reporter_put(reporter);
5464}
5465
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005466/**
5467 * devlink_health_reporter_destroy - destroy devlink health reporter
5468 *
5469 * @reporter: devlink health reporter to destroy
5470 */
5471void
5472devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
5473{
Ido Schimmel5d037b42020-07-13 18:20:14 +03005474 struct mutex *lock = &reporter->devlink->reporters_lock;
5475
5476 mutex_lock(lock);
Vladyslav Tarasiuk3c5584b2020-07-10 15:25:08 +03005477 __devlink_health_reporter_destroy(reporter);
Ido Schimmel5d037b42020-07-13 18:20:14 +03005478 mutex_unlock(lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005479}
5480EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
5481
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005482/**
5483 * devlink_port_health_reporter_destroy - destroy devlink port health reporter
5484 *
5485 * @reporter: devlink health reporter to destroy
5486 */
5487void
5488devlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter)
5489{
Ido Schimmel5d037b42020-07-13 18:20:14 +03005490 struct mutex *lock = &reporter->devlink_port->reporters_lock;
5491
5492 mutex_lock(lock);
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005493 __devlink_health_reporter_destroy(reporter);
Ido Schimmel5d037b42020-07-13 18:20:14 +03005494 mutex_unlock(lock);
Vladyslav Tarasiuk15c724b2020-07-10 15:25:11 +03005495}
5496EXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy);
5497
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005498static int
5499devlink_nl_health_reporter_fill(struct sk_buff *msg,
5500 struct devlink *devlink,
5501 struct devlink_health_reporter *reporter,
5502 enum devlink_command cmd, u32 portid,
5503 u32 seq, int flags)
5504{
5505 struct nlattr *reporter_attr;
5506 void *hdr;
5507
5508 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5509 if (!hdr)
5510 return -EMSGSIZE;
5511
5512 if (devlink_nl_put_handle(msg, devlink))
5513 goto genlmsg_cancel;
5514
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005515 if (reporter->devlink_port) {
5516 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
5517 goto genlmsg_cancel;
5518 }
Michal Kubecekae0be8d2019-04-26 11:13:06 +02005519 reporter_attr = nla_nest_start_noflag(msg,
5520 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005521 if (!reporter_attr)
5522 goto genlmsg_cancel;
5523 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
5524 reporter->ops->name))
5525 goto reporter_nest_cancel;
5526 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
5527 reporter->health_state))
5528 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005529 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005530 reporter->error_count, DEVLINK_ATTR_PAD))
5531 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02005532 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005533 reporter->recovery_count, DEVLINK_ATTR_PAD))
5534 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005535 if (reporter->ops->recover &&
5536 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005537 reporter->graceful_period,
5538 DEVLINK_ATTR_PAD))
5539 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02005540 if (reporter->ops->recover &&
5541 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005542 reporter->auto_recover))
5543 goto reporter_nest_cancel;
5544 if (reporter->dump_fmsg &&
5545 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
5546 jiffies_to_msecs(reporter->dump_ts),
5547 DEVLINK_ATTR_PAD))
5548 goto reporter_nest_cancel;
Aya Levind2795052019-11-10 14:11:56 +02005549 if (reporter->dump_fmsg &&
5550 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
5551 reporter->dump_real_ts, DEVLINK_ATTR_PAD))
5552 goto reporter_nest_cancel;
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005553 if (reporter->ops->dump &&
5554 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
5555 reporter->auto_dump))
5556 goto reporter_nest_cancel;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005557
5558 nla_nest_end(msg, reporter_attr);
5559 genlmsg_end(msg, hdr);
5560 return 0;
5561
5562reporter_nest_cancel:
5563 nla_nest_end(msg, reporter_attr);
5564genlmsg_cancel:
5565 genlmsg_cancel(msg, hdr);
5566 return -EMSGSIZE;
5567}
5568
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305569static void devlink_recover_notify(struct devlink_health_reporter *reporter,
5570 enum devlink_command cmd)
5571{
5572 struct sk_buff *msg;
5573 int err;
5574
5575 WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5576
5577 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5578 if (!msg)
5579 return;
5580
5581 err = devlink_nl_health_reporter_fill(msg, reporter->devlink,
5582 reporter, cmd, 0, 0, 0);
5583 if (err) {
5584 nlmsg_free(msg);
5585 return;
5586 }
5587
5588 genlmsg_multicast_netns(&devlink_nl_family,
5589 devlink_net(reporter->devlink),
5590 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
5591}
5592
5593void
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005594devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
5595{
5596 reporter->recovery_count++;
5597 reporter->last_recovery_ts = jiffies;
5598}
5599EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
5600
5601static int
5602devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
5603 void *priv_ctx, struct netlink_ext_ack *extack)
5604{
5605 int err;
5606
5607 if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
5608 return 0;
5609
5610 if (!reporter->ops->recover)
5611 return -EOPNOTSUPP;
5612
5613 err = reporter->ops->recover(reporter, priv_ctx, extack);
5614 if (err)
5615 return err;
5616
5617 devlink_health_reporter_recovery_done(reporter);
5618 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
5619 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5620
5621 return 0;
5622}
5623
5624static void
5625devlink_health_dump_clear(struct devlink_health_reporter *reporter)
5626{
5627 if (!reporter->dump_fmsg)
5628 return;
5629 devlink_fmsg_free(reporter->dump_fmsg);
5630 reporter->dump_fmsg = NULL;
5631}
5632
5633static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
5634 void *priv_ctx,
5635 struct netlink_ext_ack *extack)
5636{
5637 int err;
5638
5639 if (!reporter->ops->dump)
5640 return 0;
5641
5642 if (reporter->dump_fmsg)
5643 return 0;
5644
5645 reporter->dump_fmsg = devlink_fmsg_alloc();
5646 if (!reporter->dump_fmsg) {
5647 err = -ENOMEM;
5648 return err;
5649 }
5650
5651 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
5652 if (err)
5653 goto dump_err;
5654
5655 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
5656 priv_ctx, extack);
5657 if (err)
5658 goto dump_err;
5659
5660 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
5661 if (err)
5662 goto dump_err;
5663
5664 reporter->dump_ts = jiffies;
5665 reporter->dump_real_ts = ktime_get_real_ns();
5666
5667 return 0;
5668
5669dump_err:
5670 devlink_health_dump_clear(reporter);
5671 return err;
5672}
5673
5674int devlink_health_report(struct devlink_health_reporter *reporter,
5675 const char *msg, void *priv_ctx)
5676{
5677 enum devlink_health_reporter_state prev_health_state;
5678 struct devlink *devlink = reporter->devlink;
Aya Levinbea0c5c2020-05-04 11:27:46 +03005679 unsigned long recover_ts_threshold;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005680
5681 /* write a log message of the current error */
5682 WARN_ON(!msg);
5683 trace_devlink_health_report(devlink, reporter->ops->name, msg);
5684 reporter->error_count++;
5685 prev_health_state = reporter->health_state;
5686 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5687 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5688
5689 /* abort if the previous error wasn't recovered */
Aya Levinbea0c5c2020-05-04 11:27:46 +03005690 recover_ts_threshold = reporter->last_recovery_ts +
5691 msecs_to_jiffies(reporter->graceful_period);
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005692 if (reporter->auto_recover &&
5693 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Aya Levinbea0c5c2020-05-04 11:27:46 +03005694 (reporter->last_recovery_ts && reporter->recovery_count &&
5695 time_is_after_jiffies(recover_ts_threshold)))) {
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005696 trace_devlink_health_recover_aborted(devlink,
5697 reporter->ops->name,
5698 reporter->health_state,
5699 jiffies -
5700 reporter->last_recovery_ts);
5701 return -ECANCELED;
5702 }
5703
5704 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
5705
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005706 if (reporter->auto_dump) {
5707 mutex_lock(&reporter->dump_lock);
5708 /* store current dump of current error, for later analysis */
5709 devlink_health_do_dump(reporter, priv_ctx, NULL);
5710 mutex_unlock(&reporter->dump_lock);
5711 }
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005712
5713 if (reporter->auto_recover)
5714 return devlink_health_reporter_recover(reporter,
5715 priv_ctx, NULL);
5716
5717 return 0;
5718}
5719EXPORT_SYMBOL_GPL(devlink_health_report);
5720
5721static struct devlink_health_reporter *
5722devlink_health_reporter_get_from_attrs(struct devlink *devlink,
5723 struct nlattr **attrs)
5724{
5725 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005726 struct devlink_port *devlink_port;
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005727 char *reporter_name;
5728
5729 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
5730 return NULL;
5731
5732 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005733 devlink_port = devlink_port_get_from_attrs(devlink, attrs);
5734 if (IS_ERR(devlink_port)) {
5735 mutex_lock(&devlink->reporters_lock);
5736 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
5737 if (reporter)
5738 refcount_inc(&reporter->refcount);
5739 mutex_unlock(&devlink->reporters_lock);
5740 } else {
5741 mutex_lock(&devlink_port->reporters_lock);
5742 reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name);
5743 if (reporter)
5744 refcount_inc(&reporter->refcount);
5745 mutex_unlock(&devlink_port->reporters_lock);
5746 }
5747
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005748 return reporter;
5749}
5750
5751static struct devlink_health_reporter *
5752devlink_health_reporter_get_from_info(struct devlink *devlink,
5753 struct genl_info *info)
5754{
5755 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
5756}
5757
5758static struct devlink_health_reporter *
5759devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
5760{
5761 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
5762 struct devlink_health_reporter *reporter;
5763 struct nlattr **attrs = info->attrs;
5764 struct devlink *devlink;
5765
5766 mutex_lock(&devlink_mutex);
5767 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
5768 if (IS_ERR(devlink))
5769 goto unlock;
5770
5771 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
5772 mutex_unlock(&devlink_mutex);
5773 return reporter;
5774unlock:
5775 mutex_unlock(&devlink_mutex);
5776 return NULL;
5777}
5778
Moshe Shemesh6ec8b6c2020-01-23 19:57:13 +02005779void
Vikas Gupta97ff3bd2020-01-02 21:18:10 +05305780devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
5781 enum devlink_health_reporter_state state)
5782{
5783 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
5784 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
5785 return;
5786
5787 if (reporter->health_state == state)
5788 return;
5789
5790 reporter->health_state = state;
5791 trace_devlink_health_reporter_state_update(reporter->devlink,
5792 reporter->ops->name, state);
5793 devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
5794}
5795EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
5796
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005797static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
5798 struct genl_info *info)
5799{
5800 struct devlink *devlink = info->user_ptr[0];
5801 struct devlink_health_reporter *reporter;
5802 struct sk_buff *msg;
5803 int err;
5804
5805 reporter = devlink_health_reporter_get_from_info(devlink, info);
5806 if (!reporter)
5807 return -EINVAL;
5808
5809 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005810 if (!msg) {
5811 err = -ENOMEM;
5812 goto out;
5813 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005814
5815 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
5816 DEVLINK_CMD_HEALTH_REPORTER_GET,
5817 info->snd_portid, info->snd_seq,
5818 0);
5819 if (err) {
5820 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005821 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005822 }
5823
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005824 err = genlmsg_reply(msg, info);
5825out:
5826 devlink_health_reporter_put(reporter);
5827 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005828}
5829
5830static int
5831devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
5832 struct netlink_callback *cb)
5833{
5834 struct devlink_health_reporter *reporter;
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005835 struct devlink_port *port;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005836 struct devlink *devlink;
5837 int start = cb->args[0];
5838 int idx = 0;
5839 int err;
5840
5841 mutex_lock(&devlink_mutex);
5842 list_for_each_entry(devlink, &devlink_list, list) {
5843 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5844 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005845 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005846 list_for_each_entry(reporter, &devlink->reporter_list,
5847 list) {
5848 if (idx < start) {
5849 idx++;
5850 continue;
5851 }
5852 err = devlink_nl_health_reporter_fill(msg, devlink,
5853 reporter,
5854 DEVLINK_CMD_HEALTH_REPORTER_GET,
5855 NETLINK_CB(cb->skb).portid,
5856 cb->nlh->nlmsg_seq,
5857 NLM_F_MULTI);
5858 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005859 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005860 goto out;
5861 }
5862 idx++;
5863 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005864 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005865 }
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03005866
5867 list_for_each_entry(devlink, &devlink_list, list) {
5868 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5869 continue;
5870 list_for_each_entry(port, &devlink->port_list, list) {
5871 mutex_lock(&port->reporters_lock);
5872 list_for_each_entry(reporter, &port->reporter_list, list) {
5873 if (idx < start) {
5874 idx++;
5875 continue;
5876 }
5877 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
5878 DEVLINK_CMD_HEALTH_REPORTER_GET,
5879 NETLINK_CB(cb->skb).portid,
5880 cb->nlh->nlmsg_seq,
5881 NLM_F_MULTI);
5882 if (err) {
5883 mutex_unlock(&port->reporters_lock);
5884 goto out;
5885 }
5886 idx++;
5887 }
5888 mutex_unlock(&port->reporters_lock);
5889 }
5890 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005891out:
5892 mutex_unlock(&devlink_mutex);
5893
5894 cb->args[0] = idx;
5895 return msg->len;
5896}
5897
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005898static int
5899devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
5900 struct genl_info *info)
5901{
5902 struct devlink *devlink = info->user_ptr[0];
5903 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005904 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005905
5906 reporter = devlink_health_reporter_get_from_info(devlink, info);
5907 if (!reporter)
5908 return -EINVAL;
5909
5910 if (!reporter->ops->recover &&
5911 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005912 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
5913 err = -EOPNOTSUPP;
5914 goto out;
5915 }
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005916 if (!reporter->ops->dump &&
5917 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
5918 err = -EOPNOTSUPP;
5919 goto out;
5920 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005921
5922 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
5923 reporter->graceful_period =
5924 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
5925
5926 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
5927 reporter->auto_recover =
5928 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
5929
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03005930 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
5931 reporter->auto_dump =
5932 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
5933
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005934 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005935 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005936out:
5937 devlink_health_reporter_put(reporter);
5938 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005939}
5940
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005941static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
5942 struct genl_info *info)
5943{
5944 struct devlink *devlink = info->user_ptr[0];
5945 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005946 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005947
5948 reporter = devlink_health_reporter_get_from_info(devlink, info);
5949 if (!reporter)
5950 return -EINVAL;
5951
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005952 err = devlink_health_reporter_recover(reporter, NULL, info->extack);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005953
5954 devlink_health_reporter_put(reporter);
5955 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005956}
5957
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005958static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
5959 struct genl_info *info)
5960{
5961 struct devlink *devlink = info->user_ptr[0];
5962 struct devlink_health_reporter *reporter;
5963 struct devlink_fmsg *fmsg;
5964 int err;
5965
5966 reporter = devlink_health_reporter_get_from_info(devlink, info);
5967 if (!reporter)
5968 return -EINVAL;
5969
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005970 if (!reporter->ops->diagnose) {
5971 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005972 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005973 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005974
5975 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005976 if (!fmsg) {
5977 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005978 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005979 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005980
5981 err = devlink_fmsg_obj_nest_start(fmsg);
5982 if (err)
5983 goto out;
5984
Jiri Pirkoe7a98102019-10-10 15:18:49 +02005985 err = reporter->ops->diagnose(reporter, fmsg, info->extack);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005986 if (err)
5987 goto out;
5988
5989 err = devlink_fmsg_obj_nest_end(fmsg);
5990 if (err)
5991 goto out;
5992
5993 err = devlink_fmsg_snd(fmsg, info,
5994 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
5995
5996out:
5997 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005998 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005999 return err;
6000}
6001
Aya Levine44ef4e2019-05-16 09:49:20 +03006002static int
6003devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
6004 struct netlink_callback *cb)
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006005{
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006006 struct devlink_health_reporter *reporter;
Aya Levine44ef4e2019-05-16 09:49:20 +03006007 u64 start = cb->args[0];
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006008 int err;
6009
Aya Levine44ef4e2019-05-16 09:49:20 +03006010 reporter = devlink_health_reporter_get_from_cb(cb);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006011 if (!reporter)
6012 return -EINVAL;
6013
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006014 if (!reporter->ops->dump) {
Aya Levine44ef4e2019-05-16 09:49:20 +03006015 err = -EOPNOTSUPP;
6016 goto out;
6017 }
6018 mutex_lock(&reporter->dump_lock);
6019 if (!start) {
Jiri Pirkoe7a98102019-10-10 15:18:49 +02006020 err = devlink_health_do_dump(reporter, NULL, cb->extack);
Aya Levine44ef4e2019-05-16 09:49:20 +03006021 if (err)
6022 goto unlock;
6023 cb->args[1] = reporter->dump_ts;
6024 }
6025 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
6026 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
6027 err = -EAGAIN;
6028 goto unlock;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006029 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006030
Aya Levine44ef4e2019-05-16 09:49:20 +03006031 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
6032 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
6033unlock:
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006034 mutex_unlock(&reporter->dump_lock);
Aya Levine44ef4e2019-05-16 09:49:20 +03006035out:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006036 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006037 return err;
6038}
6039
6040static int
6041devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
6042 struct genl_info *info)
6043{
6044 struct devlink *devlink = info->user_ptr[0];
6045 struct devlink_health_reporter *reporter;
6046
6047 reporter = devlink_health_reporter_get_from_info(devlink, info);
6048 if (!reporter)
6049 return -EINVAL;
6050
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006051 if (!reporter->ops->dump) {
6052 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006053 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006054 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006055
6056 mutex_lock(&reporter->dump_lock);
6057 devlink_health_dump_clear(reporter);
6058 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006059 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006060 return 0;
6061}
6062
Ido Schimmel0f420b62019-08-17 16:28:17 +03006063struct devlink_stats {
6064 u64 rx_bytes;
6065 u64 rx_packets;
6066 struct u64_stats_sync syncp;
6067};
6068
6069/**
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006070 * struct devlink_trap_policer_item - Packet trap policer attributes.
6071 * @policer: Immutable packet trap policer attributes.
6072 * @rate: Rate in packets / sec.
6073 * @burst: Burst size in packets.
6074 * @list: trap_policer_list member.
6075 *
6076 * Describes packet trap policer attributes. Created by devlink during trap
6077 * policer registration.
6078 */
6079struct devlink_trap_policer_item {
6080 const struct devlink_trap_policer *policer;
6081 u64 rate;
6082 u64 burst;
6083 struct list_head list;
6084};
6085
6086/**
Ido Schimmel0f420b62019-08-17 16:28:17 +03006087 * struct devlink_trap_group_item - Packet trap group attributes.
6088 * @group: Immutable packet trap group attributes.
Ido Schimmelf9f54392020-03-30 22:38:21 +03006089 * @policer_item: Associated policer item. Can be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006090 * @list: trap_group_list member.
6091 * @stats: Trap group statistics.
6092 *
6093 * Describes packet trap group attributes. Created by devlink during trap
Ido Schimmela09b37f2020-03-22 20:48:29 +02006094 * group registration.
Ido Schimmel0f420b62019-08-17 16:28:17 +03006095 */
6096struct devlink_trap_group_item {
6097 const struct devlink_trap_group *group;
Ido Schimmelf9f54392020-03-30 22:38:21 +03006098 struct devlink_trap_policer_item *policer_item;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006099 struct list_head list;
6100 struct devlink_stats __percpu *stats;
6101};
6102
6103/**
6104 * struct devlink_trap_item - Packet trap attributes.
6105 * @trap: Immutable packet trap attributes.
6106 * @group_item: Associated group item.
6107 * @list: trap_list member.
6108 * @action: Trap action.
6109 * @stats: Trap statistics.
6110 * @priv: Driver private information.
6111 *
6112 * Describes both mutable and immutable packet trap attributes. Created by
6113 * devlink during trap registration and used for all trap related operations.
6114 */
6115struct devlink_trap_item {
6116 const struct devlink_trap *trap;
6117 struct devlink_trap_group_item *group_item;
6118 struct list_head list;
6119 enum devlink_trap_action action;
6120 struct devlink_stats __percpu *stats;
6121 void *priv;
6122};
6123
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006124static struct devlink_trap_policer_item *
6125devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
6126{
6127 struct devlink_trap_policer_item *policer_item;
6128
6129 list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
6130 if (policer_item->policer->id == id)
6131 return policer_item;
6132 }
6133
6134 return NULL;
6135}
6136
Ido Schimmel0f420b62019-08-17 16:28:17 +03006137static struct devlink_trap_item *
6138devlink_trap_item_lookup(struct devlink *devlink, const char *name)
6139{
6140 struct devlink_trap_item *trap_item;
6141
6142 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6143 if (!strcmp(trap_item->trap->name, name))
6144 return trap_item;
6145 }
6146
6147 return NULL;
6148}
6149
6150static struct devlink_trap_item *
6151devlink_trap_item_get_from_info(struct devlink *devlink,
6152 struct genl_info *info)
6153{
6154 struct nlattr *attr;
6155
6156 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
6157 return NULL;
6158 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
6159
6160 return devlink_trap_item_lookup(devlink, nla_data(attr));
6161}
6162
6163static int
6164devlink_trap_action_get_from_info(struct genl_info *info,
6165 enum devlink_trap_action *p_trap_action)
6166{
6167 u8 val;
6168
6169 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
6170 switch (val) {
6171 case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
Ido Schimmel9eefeab2020-05-29 21:36:39 +03006172 case DEVLINK_TRAP_ACTION_TRAP: /* fall-through */
6173 case DEVLINK_TRAP_ACTION_MIRROR:
Ido Schimmel0f420b62019-08-17 16:28:17 +03006174 *p_trap_action = val;
6175 break;
6176 default:
6177 return -EINVAL;
6178 }
6179
6180 return 0;
6181}
6182
6183static int devlink_trap_metadata_put(struct sk_buff *msg,
6184 const struct devlink_trap *trap)
6185{
6186 struct nlattr *attr;
6187
6188 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
6189 if (!attr)
6190 return -EMSGSIZE;
6191
6192 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
6193 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
6194 goto nla_put_failure;
Jiri Pirko85b05892020-02-25 11:45:19 +01006195 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
6196 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
6197 goto nla_put_failure;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006198
6199 nla_nest_end(msg, attr);
6200
6201 return 0;
6202
6203nla_put_failure:
6204 nla_nest_cancel(msg, attr);
6205 return -EMSGSIZE;
6206}
6207
6208static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
6209 struct devlink_stats *stats)
6210{
6211 int i;
6212
6213 memset(stats, 0, sizeof(*stats));
6214 for_each_possible_cpu(i) {
6215 struct devlink_stats *cpu_stats;
6216 u64 rx_packets, rx_bytes;
6217 unsigned int start;
6218
6219 cpu_stats = per_cpu_ptr(trap_stats, i);
6220 do {
6221 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
6222 rx_packets = cpu_stats->rx_packets;
6223 rx_bytes = cpu_stats->rx_bytes;
6224 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
6225
6226 stats->rx_packets += rx_packets;
6227 stats->rx_bytes += rx_bytes;
6228 }
6229}
6230
6231static int devlink_trap_stats_put(struct sk_buff *msg,
6232 struct devlink_stats __percpu *trap_stats)
6233{
6234 struct devlink_stats stats;
6235 struct nlattr *attr;
6236
6237 devlink_trap_stats_read(trap_stats, &stats);
6238
6239 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6240 if (!attr)
6241 return -EMSGSIZE;
6242
6243 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
6244 stats.rx_packets, DEVLINK_ATTR_PAD))
6245 goto nla_put_failure;
6246
6247 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
6248 stats.rx_bytes, DEVLINK_ATTR_PAD))
6249 goto nla_put_failure;
6250
6251 nla_nest_end(msg, attr);
6252
6253 return 0;
6254
6255nla_put_failure:
6256 nla_nest_cancel(msg, attr);
6257 return -EMSGSIZE;
6258}
6259
6260static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
6261 const struct devlink_trap_item *trap_item,
6262 enum devlink_command cmd, u32 portid, u32 seq,
6263 int flags)
6264{
6265 struct devlink_trap_group_item *group_item = trap_item->group_item;
6266 void *hdr;
6267 int err;
6268
6269 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6270 if (!hdr)
6271 return -EMSGSIZE;
6272
6273 if (devlink_nl_put_handle(msg, devlink))
6274 goto nla_put_failure;
6275
6276 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6277 group_item->group->name))
6278 goto nla_put_failure;
6279
6280 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
6281 goto nla_put_failure;
6282
6283 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
6284 goto nla_put_failure;
6285
6286 if (trap_item->trap->generic &&
6287 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6288 goto nla_put_failure;
6289
6290 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
6291 goto nla_put_failure;
6292
6293 err = devlink_trap_metadata_put(msg, trap_item->trap);
6294 if (err)
6295 goto nla_put_failure;
6296
6297 err = devlink_trap_stats_put(msg, trap_item->stats);
6298 if (err)
6299 goto nla_put_failure;
6300
6301 genlmsg_end(msg, hdr);
6302
6303 return 0;
6304
6305nla_put_failure:
6306 genlmsg_cancel(msg, hdr);
6307 return -EMSGSIZE;
6308}
6309
6310static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
6311 struct genl_info *info)
6312{
6313 struct netlink_ext_ack *extack = info->extack;
6314 struct devlink *devlink = info->user_ptr[0];
6315 struct devlink_trap_item *trap_item;
6316 struct sk_buff *msg;
6317 int err;
6318
6319 if (list_empty(&devlink->trap_list))
6320 return -EOPNOTSUPP;
6321
6322 trap_item = devlink_trap_item_get_from_info(devlink, info);
6323 if (!trap_item) {
6324 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6325 return -ENOENT;
6326 }
6327
6328 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6329 if (!msg)
6330 return -ENOMEM;
6331
6332 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6333 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
6334 info->snd_seq, 0);
6335 if (err)
6336 goto err_trap_fill;
6337
6338 return genlmsg_reply(msg, info);
6339
6340err_trap_fill:
6341 nlmsg_free(msg);
6342 return err;
6343}
6344
6345static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
6346 struct netlink_callback *cb)
6347{
6348 struct devlink_trap_item *trap_item;
6349 struct devlink *devlink;
6350 int start = cb->args[0];
6351 int idx = 0;
6352 int err;
6353
6354 mutex_lock(&devlink_mutex);
6355 list_for_each_entry(devlink, &devlink_list, list) {
6356 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6357 continue;
6358 mutex_lock(&devlink->lock);
6359 list_for_each_entry(trap_item, &devlink->trap_list, list) {
6360 if (idx < start) {
6361 idx++;
6362 continue;
6363 }
6364 err = devlink_nl_trap_fill(msg, devlink, trap_item,
6365 DEVLINK_CMD_TRAP_NEW,
6366 NETLINK_CB(cb->skb).portid,
6367 cb->nlh->nlmsg_seq,
6368 NLM_F_MULTI);
6369 if (err) {
6370 mutex_unlock(&devlink->lock);
6371 goto out;
6372 }
6373 idx++;
6374 }
6375 mutex_unlock(&devlink->lock);
6376 }
6377out:
6378 mutex_unlock(&devlink_mutex);
6379
6380 cb->args[0] = idx;
6381 return msg->len;
6382}
6383
6384static int __devlink_trap_action_set(struct devlink *devlink,
6385 struct devlink_trap_item *trap_item,
6386 enum devlink_trap_action trap_action,
6387 struct netlink_ext_ack *extack)
6388{
6389 int err;
6390
6391 if (trap_item->action != trap_action &&
6392 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
6393 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
6394 return 0;
6395 }
6396
6397 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
6398 trap_action);
6399 if (err)
6400 return err;
6401
6402 trap_item->action = trap_action;
6403
6404 return 0;
6405}
6406
6407static int devlink_trap_action_set(struct devlink *devlink,
6408 struct devlink_trap_item *trap_item,
6409 struct genl_info *info)
6410{
6411 enum devlink_trap_action trap_action;
6412 int err;
6413
6414 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6415 return 0;
6416
6417 err = devlink_trap_action_get_from_info(info, &trap_action);
6418 if (err) {
6419 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6420 return -EINVAL;
6421 }
6422
6423 return __devlink_trap_action_set(devlink, trap_item, trap_action,
6424 info->extack);
6425}
6426
6427static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
6428 struct genl_info *info)
6429{
6430 struct netlink_ext_ack *extack = info->extack;
6431 struct devlink *devlink = info->user_ptr[0];
6432 struct devlink_trap_item *trap_item;
6433 int err;
6434
6435 if (list_empty(&devlink->trap_list))
6436 return -EOPNOTSUPP;
6437
6438 trap_item = devlink_trap_item_get_from_info(devlink, info);
6439 if (!trap_item) {
6440 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
6441 return -ENOENT;
6442 }
6443
6444 err = devlink_trap_action_set(devlink, trap_item, info);
6445 if (err)
6446 return err;
6447
6448 return 0;
6449}
6450
6451static struct devlink_trap_group_item *
6452devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
6453{
6454 struct devlink_trap_group_item *group_item;
6455
6456 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6457 if (!strcmp(group_item->group->name, name))
6458 return group_item;
6459 }
6460
6461 return NULL;
6462}
6463
6464static struct devlink_trap_group_item *
Ido Schimmel107f1672020-03-22 20:48:30 +02006465devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
6466{
6467 struct devlink_trap_group_item *group_item;
6468
6469 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
6470 if (group_item->group->id == id)
6471 return group_item;
6472 }
6473
6474 return NULL;
6475}
6476
6477static struct devlink_trap_group_item *
Ido Schimmel0f420b62019-08-17 16:28:17 +03006478devlink_trap_group_item_get_from_info(struct devlink *devlink,
6479 struct genl_info *info)
6480{
6481 char *name;
6482
6483 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
6484 return NULL;
6485 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
6486
6487 return devlink_trap_group_item_lookup(devlink, name);
6488}
6489
6490static int
6491devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
6492 const struct devlink_trap_group_item *group_item,
6493 enum devlink_command cmd, u32 portid, u32 seq,
6494 int flags)
6495{
6496 void *hdr;
6497 int err;
6498
6499 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6500 if (!hdr)
6501 return -EMSGSIZE;
6502
6503 if (devlink_nl_put_handle(msg, devlink))
6504 goto nla_put_failure;
6505
6506 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
6507 group_item->group->name))
6508 goto nla_put_failure;
6509
6510 if (group_item->group->generic &&
6511 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
6512 goto nla_put_failure;
6513
Ido Schimmelf9f54392020-03-30 22:38:21 +03006514 if (group_item->policer_item &&
6515 nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6516 group_item->policer_item->policer->id))
6517 goto nla_put_failure;
6518
Ido Schimmel0f420b62019-08-17 16:28:17 +03006519 err = devlink_trap_stats_put(msg, group_item->stats);
6520 if (err)
6521 goto nla_put_failure;
6522
6523 genlmsg_end(msg, hdr);
6524
6525 return 0;
6526
6527nla_put_failure:
6528 genlmsg_cancel(msg, hdr);
6529 return -EMSGSIZE;
6530}
6531
6532static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
6533 struct genl_info *info)
6534{
6535 struct netlink_ext_ack *extack = info->extack;
6536 struct devlink *devlink = info->user_ptr[0];
6537 struct devlink_trap_group_item *group_item;
6538 struct sk_buff *msg;
6539 int err;
6540
6541 if (list_empty(&devlink->trap_group_list))
6542 return -EOPNOTSUPP;
6543
6544 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6545 if (!group_item) {
6546 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6547 return -ENOENT;
6548 }
6549
6550 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6551 if (!msg)
6552 return -ENOMEM;
6553
6554 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
6555 DEVLINK_CMD_TRAP_GROUP_NEW,
6556 info->snd_portid, info->snd_seq, 0);
6557 if (err)
6558 goto err_trap_group_fill;
6559
6560 return genlmsg_reply(msg, info);
6561
6562err_trap_group_fill:
6563 nlmsg_free(msg);
6564 return err;
6565}
6566
6567static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
6568 struct netlink_callback *cb)
6569{
6570 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
6571 struct devlink_trap_group_item *group_item;
6572 u32 portid = NETLINK_CB(cb->skb).portid;
6573 struct devlink *devlink;
6574 int start = cb->args[0];
6575 int idx = 0;
6576 int err;
6577
6578 mutex_lock(&devlink_mutex);
6579 list_for_each_entry(devlink, &devlink_list, list) {
6580 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6581 continue;
6582 mutex_lock(&devlink->lock);
6583 list_for_each_entry(group_item, &devlink->trap_group_list,
6584 list) {
6585 if (idx < start) {
6586 idx++;
6587 continue;
6588 }
6589 err = devlink_nl_trap_group_fill(msg, devlink,
6590 group_item, cmd,
6591 portid,
6592 cb->nlh->nlmsg_seq,
6593 NLM_F_MULTI);
6594 if (err) {
6595 mutex_unlock(&devlink->lock);
6596 goto out;
6597 }
6598 idx++;
6599 }
6600 mutex_unlock(&devlink->lock);
6601 }
6602out:
6603 mutex_unlock(&devlink_mutex);
6604
6605 cb->args[0] = idx;
6606 return msg->len;
6607}
6608
6609static int
6610__devlink_trap_group_action_set(struct devlink *devlink,
6611 struct devlink_trap_group_item *group_item,
6612 enum devlink_trap_action trap_action,
6613 struct netlink_ext_ack *extack)
6614{
6615 const char *group_name = group_item->group->name;
6616 struct devlink_trap_item *trap_item;
6617 int err;
6618
6619 list_for_each_entry(trap_item, &devlink->trap_list, list) {
Ido Schimmel107f1672020-03-22 20:48:30 +02006620 if (strcmp(trap_item->group_item->group->name, group_name))
Ido Schimmel0f420b62019-08-17 16:28:17 +03006621 continue;
6622 err = __devlink_trap_action_set(devlink, trap_item,
6623 trap_action, extack);
6624 if (err)
6625 return err;
6626 }
6627
6628 return 0;
6629}
6630
6631static int
6632devlink_trap_group_action_set(struct devlink *devlink,
6633 struct devlink_trap_group_item *group_item,
Ido Schimmelc0648752020-03-30 22:38:22 +03006634 struct genl_info *info, bool *p_modified)
Ido Schimmel0f420b62019-08-17 16:28:17 +03006635{
6636 enum devlink_trap_action trap_action;
6637 int err;
6638
6639 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
6640 return 0;
6641
6642 err = devlink_trap_action_get_from_info(info, &trap_action);
6643 if (err) {
6644 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
6645 return -EINVAL;
6646 }
6647
6648 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
6649 info->extack);
6650 if (err)
6651 return err;
6652
Ido Schimmelc0648752020-03-30 22:38:22 +03006653 *p_modified = true;
6654
6655 return 0;
6656}
6657
6658static int devlink_trap_group_set(struct devlink *devlink,
6659 struct devlink_trap_group_item *group_item,
6660 struct genl_info *info)
6661{
6662 struct devlink_trap_policer_item *policer_item;
6663 struct netlink_ext_ack *extack = info->extack;
6664 const struct devlink_trap_policer *policer;
6665 struct nlattr **attrs = info->attrs;
6666 int err;
6667
6668 if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6669 return 0;
6670
6671 if (!devlink->ops->trap_group_set)
6672 return -EOPNOTSUPP;
6673
6674 policer_item = group_item->policer_item;
6675 if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) {
6676 u32 policer_id;
6677
6678 policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6679 policer_item = devlink_trap_policer_item_lookup(devlink,
6680 policer_id);
6681 if (policer_id && !policer_item) {
6682 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6683 return -ENOENT;
6684 }
6685 }
6686 policer = policer_item ? policer_item->policer : NULL;
6687
6688 err = devlink->ops->trap_group_set(devlink, group_item->group, policer);
6689 if (err)
6690 return err;
6691
6692 group_item->policer_item = policer_item;
6693
Ido Schimmel0f420b62019-08-17 16:28:17 +03006694 return 0;
6695}
6696
6697static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
6698 struct genl_info *info)
6699{
6700 struct netlink_ext_ack *extack = info->extack;
6701 struct devlink *devlink = info->user_ptr[0];
6702 struct devlink_trap_group_item *group_item;
Ido Schimmelc0648752020-03-30 22:38:22 +03006703 bool modified = false;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006704 int err;
6705
6706 if (list_empty(&devlink->trap_group_list))
6707 return -EOPNOTSUPP;
6708
6709 group_item = devlink_trap_group_item_get_from_info(devlink, info);
6710 if (!group_item) {
6711 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
6712 return -ENOENT;
6713 }
6714
Ido Schimmelc0648752020-03-30 22:38:22 +03006715 err = devlink_trap_group_action_set(devlink, group_item, info,
6716 &modified);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006717 if (err)
6718 return err;
6719
Ido Schimmelc0648752020-03-30 22:38:22 +03006720 err = devlink_trap_group_set(devlink, group_item, info);
6721 if (err)
6722 goto err_trap_group_set;
6723
Ido Schimmel0f420b62019-08-17 16:28:17 +03006724 return 0;
Ido Schimmelc0648752020-03-30 22:38:22 +03006725
6726err_trap_group_set:
6727 if (modified)
6728 NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already");
6729 return err;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006730}
6731
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006732static struct devlink_trap_policer_item *
6733devlink_trap_policer_item_get_from_info(struct devlink *devlink,
6734 struct genl_info *info)
6735{
6736 u32 id;
6737
6738 if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
6739 return NULL;
6740 id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
6741
6742 return devlink_trap_policer_item_lookup(devlink, id);
6743}
6744
6745static int
6746devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
6747 const struct devlink_trap_policer *policer)
6748{
6749 struct nlattr *attr;
6750 u64 drops;
6751 int err;
6752
6753 if (!devlink->ops->trap_policer_counter_get)
6754 return 0;
6755
6756 err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
6757 if (err)
6758 return err;
6759
6760 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
6761 if (!attr)
6762 return -EMSGSIZE;
6763
6764 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
6765 DEVLINK_ATTR_PAD))
6766 goto nla_put_failure;
6767
6768 nla_nest_end(msg, attr);
6769
6770 return 0;
6771
6772nla_put_failure:
6773 nla_nest_cancel(msg, attr);
6774 return -EMSGSIZE;
6775}
6776
6777static int
6778devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
6779 const struct devlink_trap_policer_item *policer_item,
6780 enum devlink_command cmd, u32 portid, u32 seq,
6781 int flags)
6782{
6783 void *hdr;
6784 int err;
6785
6786 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6787 if (!hdr)
6788 return -EMSGSIZE;
6789
6790 if (devlink_nl_put_handle(msg, devlink))
6791 goto nla_put_failure;
6792
6793 if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
6794 policer_item->policer->id))
6795 goto nla_put_failure;
6796
6797 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
6798 policer_item->rate, DEVLINK_ATTR_PAD))
6799 goto nla_put_failure;
6800
6801 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
6802 policer_item->burst, DEVLINK_ATTR_PAD))
6803 goto nla_put_failure;
6804
6805 err = devlink_trap_policer_stats_put(msg, devlink,
6806 policer_item->policer);
6807 if (err)
6808 goto nla_put_failure;
6809
6810 genlmsg_end(msg, hdr);
6811
6812 return 0;
6813
6814nla_put_failure:
6815 genlmsg_cancel(msg, hdr);
6816 return -EMSGSIZE;
6817}
6818
6819static int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
6820 struct genl_info *info)
6821{
6822 struct devlink_trap_policer_item *policer_item;
6823 struct netlink_ext_ack *extack = info->extack;
6824 struct devlink *devlink = info->user_ptr[0];
6825 struct sk_buff *msg;
6826 int err;
6827
6828 if (list_empty(&devlink->trap_policer_list))
6829 return -EOPNOTSUPP;
6830
6831 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
6832 if (!policer_item) {
6833 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6834 return -ENOENT;
6835 }
6836
6837 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6838 if (!msg)
6839 return -ENOMEM;
6840
6841 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
6842 DEVLINK_CMD_TRAP_POLICER_NEW,
6843 info->snd_portid, info->snd_seq, 0);
6844 if (err)
6845 goto err_trap_policer_fill;
6846
6847 return genlmsg_reply(msg, info);
6848
6849err_trap_policer_fill:
6850 nlmsg_free(msg);
6851 return err;
6852}
6853
6854static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,
6855 struct netlink_callback *cb)
6856{
6857 enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW;
6858 struct devlink_trap_policer_item *policer_item;
6859 u32 portid = NETLINK_CB(cb->skb).portid;
6860 struct devlink *devlink;
6861 int start = cb->args[0];
6862 int idx = 0;
6863 int err;
6864
6865 mutex_lock(&devlink_mutex);
6866 list_for_each_entry(devlink, &devlink_list, list) {
6867 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
6868 continue;
6869 mutex_lock(&devlink->lock);
6870 list_for_each_entry(policer_item, &devlink->trap_policer_list,
6871 list) {
6872 if (idx < start) {
6873 idx++;
6874 continue;
6875 }
6876 err = devlink_nl_trap_policer_fill(msg, devlink,
6877 policer_item, cmd,
6878 portid,
6879 cb->nlh->nlmsg_seq,
6880 NLM_F_MULTI);
6881 if (err) {
6882 mutex_unlock(&devlink->lock);
6883 goto out;
6884 }
6885 idx++;
6886 }
6887 mutex_unlock(&devlink->lock);
6888 }
6889out:
6890 mutex_unlock(&devlink_mutex);
6891
6892 cb->args[0] = idx;
6893 return msg->len;
6894}
6895
6896static int
6897devlink_trap_policer_set(struct devlink *devlink,
6898 struct devlink_trap_policer_item *policer_item,
6899 struct genl_info *info)
6900{
6901 struct netlink_ext_ack *extack = info->extack;
6902 struct nlattr **attrs = info->attrs;
6903 u64 rate, burst;
6904 int err;
6905
6906 rate = policer_item->rate;
6907 burst = policer_item->burst;
6908
6909 if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
6910 rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
6911
6912 if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
6913 burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
6914
6915 if (rate < policer_item->policer->min_rate) {
6916 NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
6917 return -EINVAL;
6918 }
6919
6920 if (rate > policer_item->policer->max_rate) {
6921 NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
6922 return -EINVAL;
6923 }
6924
6925 if (burst < policer_item->policer->min_burst) {
6926 NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
6927 return -EINVAL;
6928 }
6929
6930 if (burst > policer_item->policer->max_burst) {
6931 NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
6932 return -EINVAL;
6933 }
6934
6935 err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
6936 rate, burst, info->extack);
6937 if (err)
6938 return err;
6939
6940 policer_item->rate = rate;
6941 policer_item->burst = burst;
6942
6943 return 0;
6944}
6945
6946static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
6947 struct genl_info *info)
6948{
6949 struct devlink_trap_policer_item *policer_item;
6950 struct netlink_ext_ack *extack = info->extack;
6951 struct devlink *devlink = info->user_ptr[0];
6952
6953 if (list_empty(&devlink->trap_policer_list))
6954 return -EOPNOTSUPP;
6955
6956 if (!devlink->ops->trap_policer_set)
6957 return -EOPNOTSUPP;
6958
6959 policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
6960 if (!policer_item) {
6961 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
6962 return -ENOENT;
6963 }
6964
6965 return devlink_trap_policer_set(devlink, policer_item, info);
6966}
6967
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006968static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
Ido Schimmel1e8c6612020-03-30 22:38:18 +03006969 [DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
6970 DEVLINK_ATTR_TRAP_POLICER_ID },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006971 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
6972 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
6973 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
6974 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
6975 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02006976 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
6977 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
6978 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
6979 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
6980 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
6981 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
6982 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03006983 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
Roi Dayan59bfde02016-11-22 23:09:57 +02006984 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03006985 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006986 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
6987 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006988 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
6989 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03006990 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
6991 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
6992 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03006993 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03006994 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Jakub Kicinskiff3b63b2020-03-02 21:05:12 -08006995 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
6996 [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006997 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006998 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
6999 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007000 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
7001 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Ido Schimmel0f420b62019-08-17 16:28:17 +03007002 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
7003 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
7004 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
Jiri Pirko070c63f2019-10-03 11:49:39 +02007005 [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
7006 [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
7007 [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
Eran Ben Elisha48bb52c2020-03-29 14:05:55 +03007008 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007009 [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
7010 [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
7011 [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
Parav Pandita1e8ae92020-06-19 03:32:49 +00007012 [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007013};
7014
7015static const struct genl_ops devlink_nl_ops[] = {
7016 {
7017 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007018 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007019 .doit = devlink_nl_cmd_get_doit,
7020 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirko1fc22572016-04-08 19:12:48 +02007021 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007022 /* can be retrieved by unprivileged users */
7023 },
7024 {
7025 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007026 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007027 .doit = devlink_nl_cmd_port_get_doit,
7028 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007029 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7030 /* can be retrieved by unprivileged users */
7031 },
7032 {
7033 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007034 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007035 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007036 .flags = GENL_ADMIN_PERM,
7037 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7038 },
7039 {
7040 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007041 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007042 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007043 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007044 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7045 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007046 },
7047 {
7048 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007049 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007050 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007051 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007052 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7053 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007054 },
Jiri Pirkobf797472016-04-14 18:19:13 +02007055 {
7056 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007057 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007058 .doit = devlink_nl_cmd_sb_get_doit,
7059 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007060 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7061 DEVLINK_NL_FLAG_NEED_SB,
7062 /* can be retrieved by unprivileged users */
7063 },
7064 {
7065 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007066 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007067 .doit = devlink_nl_cmd_sb_pool_get_doit,
7068 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007069 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7070 DEVLINK_NL_FLAG_NEED_SB,
7071 /* can be retrieved by unprivileged users */
7072 },
7073 {
7074 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007075 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007076 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007077 .flags = GENL_ADMIN_PERM,
7078 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7079 DEVLINK_NL_FLAG_NEED_SB,
7080 },
7081 {
7082 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007083 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007084 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
7085 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007086 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
7087 DEVLINK_NL_FLAG_NEED_SB,
7088 /* can be retrieved by unprivileged users */
7089 },
7090 {
7091 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007092 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007093 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007094 .flags = GENL_ADMIN_PERM,
7095 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
7096 DEVLINK_NL_FLAG_NEED_SB,
7097 },
7098 {
7099 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007100 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007101 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
7102 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007103 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
7104 DEVLINK_NL_FLAG_NEED_SB,
7105 /* can be retrieved by unprivileged users */
7106 },
7107 {
7108 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007109 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02007110 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02007111 .flags = GENL_ADMIN_PERM,
7112 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
7113 DEVLINK_NL_FLAG_NEED_SB,
7114 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007115 {
7116 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02007117 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007118 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007119 .flags = GENL_ADMIN_PERM,
7120 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007121 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007122 },
7123 {
7124 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007125 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007126 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007127 .flags = GENL_ADMIN_PERM,
7128 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007129 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02007130 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03007131 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007132 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007133 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007134 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007135 .flags = GENL_ADMIN_PERM,
Parav Pandit98fed6e2020-02-23 19:06:56 -06007136 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7137 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007138 },
7139 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007140 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007141 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01007142 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007143 .flags = GENL_ADMIN_PERM,
Jakub Kicinski7ac1cc92018-05-21 22:12:50 -07007144 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7145 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03007146 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007147 {
7148 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007149 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007150 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007151 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007152 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007153 },
7154 {
7155 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007156 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007157 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007158 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007159 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007160 },
7161 {
7162 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007163 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007164 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007165 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007166 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007167 },
7168 {
7169 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007170 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007171 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007172 .flags = GENL_ADMIN_PERM,
7173 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7174 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007175 {
7176 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007177 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007178 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007179 .flags = GENL_ADMIN_PERM,
7180 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7181 },
7182 {
7183 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02007184 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007185 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007186 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02007187 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007188 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007189 {
7190 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02007191 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007192 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01007193 .flags = GENL_ADMIN_PERM,
7194 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
7195 DEVLINK_NL_FLAG_NO_LOCK,
7196 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007197 {
7198 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007199 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007200 .doit = devlink_nl_cmd_param_get_doit,
7201 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03007202 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7203 /* can be retrieved by unprivileged users */
7204 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007205 {
7206 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007207 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007208 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03007209 .flags = GENL_ADMIN_PERM,
7210 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7211 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007212 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307213 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007214 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307215 .doit = devlink_nl_cmd_port_param_get_doit,
7216 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05307217 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7218 /* can be retrieved by unprivileged users */
7219 },
7220 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05307221 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007222 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307223 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05307224 .flags = GENL_ADMIN_PERM,
7225 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
7226 },
7227 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007228 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007229 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007230 .doit = devlink_nl_cmd_region_get_doit,
7231 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03007232 .flags = GENL_ADMIN_PERM,
7233 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7234 },
Alex Vesker866319b2018-07-12 15:13:13 +03007235 {
Jacob Kellerb9a17ab2020-03-26 11:37:16 -07007236 .cmd = DEVLINK_CMD_REGION_NEW,
7237 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
7238 .doit = devlink_nl_cmd_region_new,
7239 .flags = GENL_ADMIN_PERM,
7240 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7241 },
7242 {
Alex Vesker866319b2018-07-12 15:13:13 +03007243 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02007244 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03007245 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03007246 .flags = GENL_ADMIN_PERM,
7247 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7248 },
Alex Vesker4e547952018-07-12 15:13:14 +03007249 {
7250 .cmd = DEVLINK_CMD_REGION_READ,
Jiri Pirkoee85da52019-10-05 20:04:42 +02007251 .validate = GENL_DONT_VALIDATE_STRICT |
7252 GENL_DONT_VALIDATE_DUMP_STRICT,
Alex Vesker4e547952018-07-12 15:13:14 +03007253 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03007254 .flags = GENL_ADMIN_PERM,
7255 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7256 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007257 {
7258 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007259 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007260 .doit = devlink_nl_cmd_info_get_doit,
7261 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08007262 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7263 /* can be retrieved by unprivileged users */
7264 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007265 {
7266 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007267 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007268 .doit = devlink_nl_cmd_health_reporter_get_doit,
7269 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007270 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007271 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02007272 /* can be retrieved by unprivileged users */
7273 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007274 {
7275 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02007276 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007277 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007278 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007279 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007280 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02007281 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007282 {
7283 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02007284 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007285 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007286 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007287 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007288 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02007289 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007290 {
7291 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007292 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007293 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007294 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007295 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007296 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02007297 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007298 {
7299 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Jiri Pirko82a843d2019-10-07 09:28:31 +02007300 .validate = GENL_DONT_VALIDATE_STRICT |
7301 GENL_DONT_VALIDATE_DUMP_STRICT,
Aya Levine44ef4e2019-05-16 09:49:20 +03007302 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007303 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007304 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007305 DEVLINK_NL_FLAG_NO_LOCK,
7306 },
7307 {
7308 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02007309 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007310 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007311 .flags = GENL_ADMIN_PERM,
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007312 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
Eran Ben Elisha35455e22019-02-07 11:36:39 +02007313 DEVLINK_NL_FLAG_NO_LOCK,
7314 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007315 {
7316 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02007317 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007318 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08007319 .flags = GENL_ADMIN_PERM,
7320 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7321 },
Ido Schimmel0f420b62019-08-17 16:28:17 +03007322 {
7323 .cmd = DEVLINK_CMD_TRAP_GET,
7324 .doit = devlink_nl_cmd_trap_get_doit,
7325 .dumpit = devlink_nl_cmd_trap_get_dumpit,
7326 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7327 /* can be retrieved by unprivileged users */
7328 },
7329 {
7330 .cmd = DEVLINK_CMD_TRAP_SET,
7331 .doit = devlink_nl_cmd_trap_set_doit,
7332 .flags = GENL_ADMIN_PERM,
7333 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7334 },
7335 {
7336 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
7337 .doit = devlink_nl_cmd_trap_group_get_doit,
7338 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
7339 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7340 /* can be retrieved by unprivileged users */
7341 },
7342 {
7343 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
7344 .doit = devlink_nl_cmd_trap_group_set_doit,
7345 .flags = GENL_ADMIN_PERM,
7346 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7347 },
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007348 {
7349 .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
7350 .doit = devlink_nl_cmd_trap_policer_get_doit,
7351 .dumpit = devlink_nl_cmd_trap_policer_get_dumpit,
7352 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7353 /* can be retrieved by unprivileged users */
7354 },
7355 {
7356 .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
7357 .doit = devlink_nl_cmd_trap_policer_set_doit,
7358 .flags = GENL_ADMIN_PERM,
7359 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
7360 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007361};
7362
Johannes Berg56989f62016-10-24 14:40:05 +02007363static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02007364 .name = DEVLINK_GENL_NAME,
7365 .version = DEVLINK_GENL_VERSION,
7366 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01007367 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02007368 .netnsok = true,
7369 .pre_doit = devlink_nl_pre_doit,
7370 .post_doit = devlink_nl_post_doit,
7371 .module = THIS_MODULE,
7372 .ops = devlink_nl_ops,
7373 .n_ops = ARRAY_SIZE(devlink_nl_ops),
7374 .mcgrps = devlink_nl_mcgrps,
7375 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
7376};
7377
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007378/**
7379 * devlink_alloc - Allocate new devlink instance resources
7380 *
7381 * @ops: ops
7382 * @priv_size: size of user private data
7383 *
7384 * Allocate new devlink instance resources, including devlink index
7385 * and name.
7386 */
7387struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
7388{
7389 struct devlink *devlink;
7390
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007391 if (WARN_ON(!ops))
7392 return NULL;
7393
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007394 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
7395 if (!devlink)
7396 return NULL;
7397 devlink->ops = ops;
Jacob Keller12102432020-03-26 11:37:15 -07007398 xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
Jiri Pirko8273fd82019-10-05 08:10:31 +02007399 __devlink_net_set(devlink, &init_net);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007400 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02007401 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007402 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007403 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03007404 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03007405 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02007406 INIT_LIST_HEAD(&devlink->reporter_list);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007407 INIT_LIST_HEAD(&devlink->trap_list);
7408 INIT_LIST_HEAD(&devlink->trap_group_list);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007409 INIT_LIST_HEAD(&devlink->trap_policer_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007410 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007411 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007412 return devlink;
7413}
7414EXPORT_SYMBOL_GPL(devlink_alloc);
7415
7416/**
7417 * devlink_register - Register devlink instance
7418 *
7419 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007420 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007421 */
7422int devlink_register(struct devlink *devlink, struct device *dev)
7423{
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007424 devlink->dev = dev;
Jiri Pirko8273fd82019-10-05 08:10:31 +02007425 devlink->registered = true;
Parav Pandit6553e562020-07-21 19:53:51 +03007426 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007427 list_add_tail(&devlink->list, &devlink_list);
7428 devlink_notify(devlink, DEVLINK_CMD_NEW);
7429 mutex_unlock(&devlink_mutex);
7430 return 0;
7431}
7432EXPORT_SYMBOL_GPL(devlink_register);
7433
7434/**
7435 * devlink_unregister - Unregister devlink instance
7436 *
7437 * @devlink: devlink
7438 */
7439void devlink_unregister(struct devlink *devlink)
7440{
7441 mutex_lock(&devlink_mutex);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007442 WARN_ON(devlink_reload_supported(devlink) &&
7443 devlink->reload_enabled);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007444 devlink_notify(devlink, DEVLINK_CMD_DEL);
7445 list_del(&devlink->list);
7446 mutex_unlock(&devlink_mutex);
7447}
7448EXPORT_SYMBOL_GPL(devlink_unregister);
7449
7450/**
Jiri Pirkoa0c76342019-11-08 21:42:43 +01007451 * devlink_reload_enable - Enable reload of devlink instance
7452 *
7453 * @devlink: devlink
7454 *
7455 * Should be called at end of device initialization
7456 * process when reload operation is supported.
7457 */
7458void devlink_reload_enable(struct devlink *devlink)
7459{
7460 mutex_lock(&devlink_mutex);
7461 devlink->reload_enabled = true;
7462 mutex_unlock(&devlink_mutex);
7463}
7464EXPORT_SYMBOL_GPL(devlink_reload_enable);
7465
7466/**
7467 * devlink_reload_disable - Disable reload of devlink instance
7468 *
7469 * @devlink: devlink
7470 *
7471 * Should be called at the beginning of device cleanup
7472 * process when reload operation is supported.
7473 */
7474void devlink_reload_disable(struct devlink *devlink)
7475{
7476 mutex_lock(&devlink_mutex);
7477 /* Mutex is taken which ensures that no reload operation is in
7478 * progress while setting up forbidded flag.
7479 */
7480 devlink->reload_enabled = false;
7481 mutex_unlock(&devlink_mutex);
7482}
7483EXPORT_SYMBOL_GPL(devlink_reload_disable);
7484
7485/**
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007486 * devlink_free - Free devlink instance resources
7487 *
7488 * @devlink: devlink
7489 */
7490void devlink_free(struct devlink *devlink)
7491{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03007492 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01007493 mutex_destroy(&devlink->lock);
Ido Schimmel1e8c6612020-03-30 22:38:18 +03007494 WARN_ON(!list_empty(&devlink->trap_policer_list));
Ido Schimmel0f420b62019-08-17 16:28:17 +03007495 WARN_ON(!list_empty(&devlink->trap_group_list));
7496 WARN_ON(!list_empty(&devlink->trap_list));
Parav Panditb904aad2019-02-08 15:15:00 -06007497 WARN_ON(!list_empty(&devlink->reporter_list));
7498 WARN_ON(!list_empty(&devlink->region_list));
7499 WARN_ON(!list_empty(&devlink->param_list));
7500 WARN_ON(!list_empty(&devlink->resource_list));
7501 WARN_ON(!list_empty(&devlink->dpipe_table_list));
7502 WARN_ON(!list_empty(&devlink->sb_list));
7503 WARN_ON(!list_empty(&devlink->port_list));
7504
Jacob Keller12102432020-03-26 11:37:15 -07007505 xa_destroy(&devlink->snapshot_ids);
7506
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007507 kfree(devlink);
7508}
7509EXPORT_SYMBOL_GPL(devlink_free);
7510
Jiri Pirko136bf272019-05-23 10:43:35 +02007511static void devlink_port_type_warn(struct work_struct *work)
7512{
7513 WARN(true, "Type was not set for devlink port.");
7514}
7515
7516static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
7517{
7518 /* Ignore CPU and DSA flavours. */
7519 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
7520 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
7521}
7522
Ido Schimmel4c582232020-01-09 19:57:41 +02007523#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
Jiri Pirko136bf272019-05-23 10:43:35 +02007524
7525static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
7526{
7527 if (!devlink_port_type_should_warn(devlink_port))
7528 return;
7529 /* Schedule a work to WARN in case driver does not set port
7530 * type within timeout.
7531 */
7532 schedule_delayed_work(&devlink_port->type_warn_dw,
7533 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
7534}
7535
7536static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
7537{
7538 if (!devlink_port_type_should_warn(devlink_port))
7539 return;
7540 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
7541}
7542
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007543/**
7544 * devlink_port_register - Register devlink port
7545 *
7546 * @devlink: devlink
7547 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007548 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007549 *
7550 * Register devlink port with provided port index. User can use
7551 * any indexing, even hw-related one. devlink_port structure
7552 * is convenient to be embedded inside user driver private structure.
7553 * Note that the caller should take care of zeroing the devlink_port
7554 * structure.
7555 */
7556int devlink_port_register(struct devlink *devlink,
7557 struct devlink_port *devlink_port,
7558 unsigned int port_index)
7559{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007560 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007561 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007562 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007563 return -EEXIST;
7564 }
7565 devlink_port->devlink = devlink;
7566 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007567 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01007568 spin_lock_init(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007569 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05307570 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007571 mutex_unlock(&devlink->lock);
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007572 INIT_LIST_HEAD(&devlink_port->reporter_list);
7573 mutex_init(&devlink_port->reporters_lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02007574 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
7575 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007576 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7577 return 0;
7578}
7579EXPORT_SYMBOL_GPL(devlink_port_register);
7580
7581/**
7582 * devlink_port_unregister - Unregister devlink port
7583 *
7584 * @devlink_port: devlink port
7585 */
7586void devlink_port_unregister(struct devlink_port *devlink_port)
7587{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007588 struct devlink *devlink = devlink_port->devlink;
7589
Vladyslav Tarasiukf4f54162020-07-10 15:25:10 +03007590 WARN_ON(!list_empty(&devlink_port->reporter_list));
7591 mutex_destroy(&devlink_port->reporters_lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02007592 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007593 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007594 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007595 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007596 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007597}
7598EXPORT_SYMBOL_GPL(devlink_port_unregister);
7599
7600static void __devlink_port_type_set(struct devlink_port *devlink_port,
7601 enum devlink_port_type type,
7602 void *type_dev)
7603{
Jiri Pirko2b239e72019-03-24 11:14:36 +01007604 if (WARN_ON(!devlink_port->registered))
7605 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02007606 devlink_port_type_warn_cancel(devlink_port);
Ido Schimmel0f420b62019-08-17 16:28:17 +03007607 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007608 devlink_port->type = type;
7609 devlink_port->type_dev = type_dev;
Ido Schimmel0f420b62019-08-17 16:28:17 +03007610 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007611 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
7612}
7613
7614/**
7615 * devlink_port_type_eth_set - Set port type to Ethernet
7616 *
7617 * @devlink_port: devlink port
7618 * @netdev: related netdevice
7619 */
7620void devlink_port_type_eth_set(struct devlink_port *devlink_port,
7621 struct net_device *netdev)
7622{
Jiri Pirko119c0b52019-04-03 14:24:27 +02007623 const struct net_device_ops *ops = netdev->netdev_ops;
7624
Jiri Pirko746364f2019-03-28 13:56:46 +01007625 /* If driver registers devlink port, it should set devlink port
7626 * attributes accordingly so the compat functions are called
7627 * and the original ops are not used.
7628 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02007629 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01007630 /* Some drivers use the same set of ndos for netdevs
7631 * that have devlink_port registered and also for
7632 * those who don't. Make sure that ndo_get_phys_port_name
7633 * returns -EOPNOTSUPP here in case it is defined.
7634 * Warn if not.
7635 */
Jiri Pirko746364f2019-03-28 13:56:46 +01007636 char name[IFNAMSIZ];
7637 int err;
7638
7639 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
7640 WARN_ON(err != -EOPNOTSUPP);
7641 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02007642 if (ops->ndo_get_port_parent_id) {
7643 /* Some drivers use the same set of ndos for netdevs
7644 * that have devlink_port registered and also for
7645 * those who don't. Make sure that ndo_get_port_parent_id
7646 * returns -EOPNOTSUPP here in case it is defined.
7647 * Warn if not.
7648 */
7649 struct netdev_phys_item_id ppid;
7650 int err;
7651
7652 err = ops->ndo_get_port_parent_id(netdev, &ppid);
7653 WARN_ON(err != -EOPNOTSUPP);
7654 }
Jiri Pirko773b1f32019-03-24 11:14:30 +01007655 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007656}
7657EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
7658
7659/**
7660 * devlink_port_type_ib_set - Set port type to InfiniBand
7661 *
7662 * @devlink_port: devlink port
7663 * @ibdev: related IB device
7664 */
7665void devlink_port_type_ib_set(struct devlink_port *devlink_port,
7666 struct ib_device *ibdev)
7667{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007668 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007669}
7670EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
7671
7672/**
7673 * devlink_port_type_clear - Clear port type
7674 *
7675 * @devlink_port: devlink port
7676 */
7677void devlink_port_type_clear(struct devlink_port *devlink_port)
7678{
Jiri Pirko773b1f32019-03-24 11:14:30 +01007679 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02007680 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007681}
7682EXPORT_SYMBOL_GPL(devlink_port_type_clear);
7683
Parav Pandit378ef012019-07-08 23:17:35 -05007684static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007685 enum devlink_port_flavour flavour)
Parav Pandit378ef012019-07-08 23:17:35 -05007686{
7687 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7688
7689 if (WARN_ON(devlink_port->registered))
7690 return -EEXIST;
Danielle Ratson10a429b2020-07-09 16:18:14 +03007691 devlink_port->attrs_set = true;
Parav Pandit378ef012019-07-08 23:17:35 -05007692 attrs->flavour = flavour;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007693 if (attrs->switch_id.id_len) {
Danielle Ratson46737a12020-07-09 16:18:15 +03007694 devlink_port->switch_port = true;
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007695 if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
7696 attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
Parav Pandit378ef012019-07-08 23:17:35 -05007697 } else {
Danielle Ratson46737a12020-07-09 16:18:15 +03007698 devlink_port->switch_port = false;
Parav Pandit378ef012019-07-08 23:17:35 -05007699 }
7700 return 0;
7701}
7702
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007703/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007704 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007705 *
7706 * @devlink_port: devlink port
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007707 * @attrs: devlink port attrs
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007708 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007709void devlink_port_attrs_set(struct devlink_port *devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007710 struct devlink_port_attrs *attrs)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007711{
Parav Pandit378ef012019-07-08 23:17:35 -05007712 int ret;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007713
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007714 devlink_port->attrs = *attrs;
7715 ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
Parav Pandit378ef012019-07-08 23:17:35 -05007716 if (ret)
Jiri Pirko45b86112019-03-24 11:14:33 +01007717 return;
Danielle Ratsona0f49b52020-07-09 16:18:20 +03007718 WARN_ON(attrs->splittable && attrs->split);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007719}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02007720EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01007721
Parav Pandit98fd2d62019-07-08 23:17:37 -05007722/**
7723 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
7724 *
7725 * @devlink_port: devlink port
7726 * @pf: associated PF for the devlink port instance
Parav Pandit98fd2d62019-07-08 23:17:37 -05007727 */
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007728void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u16 pf)
Parav Pandit98fd2d62019-07-08 23:17:37 -05007729{
7730 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7731 int ret;
7732
7733 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007734 DEVLINK_PORT_FLAVOUR_PCI_PF);
Parav Pandit98fd2d62019-07-08 23:17:37 -05007735 if (ret)
7736 return;
7737
7738 attrs->pci_pf.pf = pf;
7739}
7740EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
7741
Parav Pandite41b6bf2019-07-08 23:17:38 -05007742/**
7743 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
7744 *
7745 * @devlink_port: devlink port
7746 * @pf: associated PF for the devlink port instance
7747 * @vf: associated VF of a PF for the devlink port instance
Parav Pandite41b6bf2019-07-08 23:17:38 -05007748 */
7749void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
Parav Pandite41b6bf2019-07-08 23:17:38 -05007750 u16 pf, u16 vf)
7751{
7752 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7753 int ret;
7754
7755 ret = __devlink_port_attrs_set(devlink_port,
Danielle Ratson71ad8d52020-07-09 16:18:16 +03007756 DEVLINK_PORT_FLAVOUR_PCI_VF);
Parav Pandite41b6bf2019-07-08 23:17:38 -05007757 if (ret)
7758 return;
7759 attrs->pci_vf.pf = pf;
7760 attrs->pci_vf.vf = vf;
7761}
7762EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
7763
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007764static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
7765 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02007766{
7767 struct devlink_port_attrs *attrs = &devlink_port->attrs;
7768 int n = 0;
7769
Danielle Ratson10a429b2020-07-09 16:18:14 +03007770 if (!devlink_port->attrs_set)
Jiri Pirko08474c12018-05-18 09:29:02 +02007771 return -EOPNOTSUPP;
7772
7773 switch (attrs->flavour) {
7774 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
Parav Panditacf1ee42020-03-03 08:12:42 -06007775 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
Jiri Pirko08474c12018-05-18 09:29:02 +02007776 if (!attrs->split)
Parav Pandit378ef012019-07-08 23:17:35 -05007777 n = snprintf(name, len, "p%u", attrs->phys.port_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007778 else
Parav Pandit378ef012019-07-08 23:17:35 -05007779 n = snprintf(name, len, "p%us%u",
7780 attrs->phys.port_number,
7781 attrs->phys.split_subport_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02007782 break;
7783 case DEVLINK_PORT_FLAVOUR_CPU:
7784 case DEVLINK_PORT_FLAVOUR_DSA:
7785 /* As CPU and DSA ports do not have a netdevice associated
7786 * case should not ever happen.
7787 */
7788 WARN_ON(1);
7789 return -EINVAL;
Parav Pandit98fd2d62019-07-08 23:17:37 -05007790 case DEVLINK_PORT_FLAVOUR_PCI_PF:
7791 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
7792 break;
Parav Pandite41b6bf2019-07-08 23:17:38 -05007793 case DEVLINK_PORT_FLAVOUR_PCI_VF:
7794 n = snprintf(name, len, "pf%uvf%u",
7795 attrs->pci_vf.pf, attrs->pci_vf.vf);
7796 break;
Jiri Pirko08474c12018-05-18 09:29:02 +02007797 }
7798
7799 if (n >= len)
7800 return -EINVAL;
7801
7802 return 0;
7803}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007804
Jiri Pirkobf797472016-04-14 18:19:13 +02007805int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
7806 u32 size, u16 ingress_pools_count,
7807 u16 egress_pools_count, u16 ingress_tc_count,
7808 u16 egress_tc_count)
7809{
7810 struct devlink_sb *devlink_sb;
7811 int err = 0;
7812
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007813 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007814 if (devlink_sb_index_exists(devlink, sb_index)) {
7815 err = -EEXIST;
7816 goto unlock;
7817 }
7818
7819 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
7820 if (!devlink_sb) {
7821 err = -ENOMEM;
7822 goto unlock;
7823 }
7824 devlink_sb->index = sb_index;
7825 devlink_sb->size = size;
7826 devlink_sb->ingress_pools_count = ingress_pools_count;
7827 devlink_sb->egress_pools_count = egress_pools_count;
7828 devlink_sb->ingress_tc_count = ingress_tc_count;
7829 devlink_sb->egress_tc_count = egress_tc_count;
7830 list_add_tail(&devlink_sb->list, &devlink->sb_list);
7831unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007832 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007833 return err;
7834}
7835EXPORT_SYMBOL_GPL(devlink_sb_register);
7836
7837void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
7838{
7839 struct devlink_sb *devlink_sb;
7840
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007841 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007842 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
7843 WARN_ON(!devlink_sb);
7844 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007845 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02007846 kfree(devlink_sb);
7847}
7848EXPORT_SYMBOL_GPL(devlink_sb_unregister);
7849
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007850/**
7851 * devlink_dpipe_headers_register - register dpipe headers
7852 *
7853 * @devlink: devlink
7854 * @dpipe_headers: dpipe header array
7855 *
7856 * Register the headers supported by hardware.
7857 */
7858int devlink_dpipe_headers_register(struct devlink *devlink,
7859 struct devlink_dpipe_headers *dpipe_headers)
7860{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007861 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007862 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007863 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007864 return 0;
7865}
7866EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
7867
7868/**
7869 * devlink_dpipe_headers_unregister - unregister dpipe headers
7870 *
7871 * @devlink: devlink
7872 *
7873 * Unregister the headers supported by hardware.
7874 */
7875void devlink_dpipe_headers_unregister(struct devlink *devlink)
7876{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007877 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007878 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007879 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007880}
7881EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
7882
7883/**
7884 * devlink_dpipe_table_counter_enabled - check if counter allocation
7885 * required
7886 * @devlink: devlink
7887 * @table_name: tables name
7888 *
7889 * Used by driver to check if counter allocation is required.
7890 * After counter allocation is turned on the table entries
7891 * are updated to include counter statistics.
7892 *
7893 * After that point on the driver must respect the counter
7894 * state so that each entry added to the table is added
7895 * with a counter.
7896 */
7897bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
7898 const char *table_name)
7899{
7900 struct devlink_dpipe_table *table;
7901 bool enabled;
7902
7903 rcu_read_lock();
7904 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307905 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007906 enabled = false;
7907 if (table)
7908 enabled = table->counters_enabled;
7909 rcu_read_unlock();
7910 return enabled;
7911}
7912EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
7913
7914/**
7915 * devlink_dpipe_table_register - register dpipe table
7916 *
7917 * @devlink: devlink
7918 * @table_name: table name
7919 * @table_ops: table ops
7920 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007921 * @counter_control_extern: external control for counters
7922 */
7923int devlink_dpipe_table_register(struct devlink *devlink,
7924 const char *table_name,
7925 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02007926 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007927{
7928 struct devlink_dpipe_table *table;
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307929 int err = 0;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007930
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02007931 if (WARN_ON(!table_ops->size_get))
7932 return -EINVAL;
7933
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307934 mutex_lock(&devlink->lock);
7935
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307936 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
7937 devlink)) {
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307938 err = -EEXIST;
7939 goto unlock;
7940 }
7941
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007942 table = kzalloc(sizeof(*table), GFP_KERNEL);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307943 if (!table) {
7944 err = -ENOMEM;
7945 goto unlock;
7946 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007947
7948 table->name = table_name;
7949 table->table_ops = table_ops;
7950 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007951 table->counter_control_extern = counter_control_extern;
7952
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007953 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307954unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007955 mutex_unlock(&devlink->lock);
Madhuparna Bhowmik6132c1d2020-02-23 16:52:33 +05307956 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007957}
7958EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
7959
7960/**
7961 * devlink_dpipe_table_unregister - unregister dpipe table
7962 *
7963 * @devlink: devlink
7964 * @table_name: table name
7965 */
7966void devlink_dpipe_table_unregister(struct devlink *devlink,
7967 const char *table_name)
7968{
7969 struct devlink_dpipe_table *table;
7970
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007971 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007972 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05307973 table_name, devlink);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007974 if (!table)
7975 goto unlock;
7976 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007977 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007978 kfree_rcu(table, rcu);
7979 return;
7980unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01007981 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02007982}
7983EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
7984
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007985/**
7986 * devlink_resource_register - devlink resource register
7987 *
7988 * @devlink: devlink
7989 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007990 * @resource_size: resource's size
7991 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007992 * @parent_resource_id: resource's parent id
7993 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007994 */
7995int devlink_resource_register(struct devlink *devlink,
7996 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01007997 u64 resource_size,
7998 u64 resource_id,
7999 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02008000 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008001{
8002 struct devlink_resource *resource;
8003 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07008004 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008005 int err = 0;
8006
David Ahern14530742018-03-20 19:31:14 -07008007 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
8008
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008009 mutex_lock(&devlink->lock);
8010 resource = devlink_resource_find(devlink, NULL, resource_id);
8011 if (resource) {
8012 err = -EINVAL;
8013 goto out;
8014 }
8015
8016 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
8017 if (!resource) {
8018 err = -ENOMEM;
8019 goto out;
8020 }
8021
8022 if (top_hierarchy) {
8023 resource_list = &devlink->resource_list;
8024 } else {
8025 struct devlink_resource *parent_resource;
8026
8027 parent_resource = devlink_resource_find(devlink, NULL,
8028 parent_resource_id);
8029 if (parent_resource) {
8030 resource_list = &parent_resource->resource_list;
8031 resource->parent = parent_resource;
8032 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00008033 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008034 err = -EINVAL;
8035 goto out;
8036 }
8037 }
8038
8039 resource->name = resource_name;
8040 resource->size = resource_size;
8041 resource->size_new = resource_size;
8042 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008043 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01008044 memcpy(&resource->size_params, size_params,
8045 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01008046 INIT_LIST_HEAD(&resource->resource_list);
8047 list_add_tail(&resource->list, resource_list);
8048out:
8049 mutex_unlock(&devlink->lock);
8050 return err;
8051}
8052EXPORT_SYMBOL_GPL(devlink_resource_register);
8053
8054/**
8055 * devlink_resources_unregister - free all resources
8056 *
8057 * @devlink: devlink
8058 * @resource: resource
8059 */
8060void devlink_resources_unregister(struct devlink *devlink,
8061 struct devlink_resource *resource)
8062{
8063 struct devlink_resource *tmp, *child_resource;
8064 struct list_head *resource_list;
8065
8066 if (resource)
8067 resource_list = &resource->resource_list;
8068 else
8069 resource_list = &devlink->resource_list;
8070
8071 if (!resource)
8072 mutex_lock(&devlink->lock);
8073
8074 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
8075 devlink_resources_unregister(devlink, child_resource);
8076 list_del(&child_resource->list);
8077 kfree(child_resource);
8078 }
8079
8080 if (!resource)
8081 mutex_unlock(&devlink->lock);
8082}
8083EXPORT_SYMBOL_GPL(devlink_resources_unregister);
8084
8085/**
8086 * devlink_resource_size_get - get and update size
8087 *
8088 * @devlink: devlink
8089 * @resource_id: the requested resource id
8090 * @p_resource_size: ptr to update
8091 */
8092int devlink_resource_size_get(struct devlink *devlink,
8093 u64 resource_id,
8094 u64 *p_resource_size)
8095{
8096 struct devlink_resource *resource;
8097 int err = 0;
8098
8099 mutex_lock(&devlink->lock);
8100 resource = devlink_resource_find(devlink, NULL, resource_id);
8101 if (!resource) {
8102 err = -EINVAL;
8103 goto out;
8104 }
8105 *p_resource_size = resource->size_new;
8106 resource->size = resource->size_new;
8107out:
8108 mutex_unlock(&devlink->lock);
8109 return err;
8110}
8111EXPORT_SYMBOL_GPL(devlink_resource_size_get);
8112
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008113/**
8114 * devlink_dpipe_table_resource_set - set the resource id
8115 *
8116 * @devlink: devlink
8117 * @table_name: table name
8118 * @resource_id: resource id
8119 * @resource_units: number of resource's units consumed per table's entry
8120 */
8121int devlink_dpipe_table_resource_set(struct devlink *devlink,
8122 const char *table_name, u64 resource_id,
8123 u64 resource_units)
8124{
8125 struct devlink_dpipe_table *table;
8126 int err = 0;
8127
8128 mutex_lock(&devlink->lock);
8129 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
Madhuparna Bhowmik2eb51c72020-02-25 17:57:45 +05308130 table_name, devlink);
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01008131 if (!table) {
8132 err = -EINVAL;
8133 goto out;
8134 }
8135 table->resource_id = resource_id;
8136 table->resource_units = resource_units;
8137 table->resource_valid = true;
8138out:
8139 mutex_unlock(&devlink->lock);
8140 return err;
8141}
8142EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
8143
Jiri Pirkofc56be42018-04-05 22:13:21 +02008144/**
8145 * devlink_resource_occ_get_register - register occupancy getter
8146 *
8147 * @devlink: devlink
8148 * @resource_id: resource id
8149 * @occ_get: occupancy getter callback
8150 * @occ_get_priv: occupancy getter callback priv
8151 */
8152void devlink_resource_occ_get_register(struct devlink *devlink,
8153 u64 resource_id,
8154 devlink_resource_occ_get_t *occ_get,
8155 void *occ_get_priv)
8156{
8157 struct devlink_resource *resource;
8158
8159 mutex_lock(&devlink->lock);
8160 resource = devlink_resource_find(devlink, NULL, resource_id);
8161 if (WARN_ON(!resource))
8162 goto out;
8163 WARN_ON(resource->occ_get);
8164
8165 resource->occ_get = occ_get;
8166 resource->occ_get_priv = occ_get_priv;
8167out:
8168 mutex_unlock(&devlink->lock);
8169}
8170EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
8171
8172/**
8173 * devlink_resource_occ_get_unregister - unregister occupancy getter
8174 *
8175 * @devlink: devlink
8176 * @resource_id: resource id
8177 */
8178void devlink_resource_occ_get_unregister(struct devlink *devlink,
8179 u64 resource_id)
8180{
8181 struct devlink_resource *resource;
8182
8183 mutex_lock(&devlink->lock);
8184 resource = devlink_resource_find(devlink, NULL, resource_id);
8185 if (WARN_ON(!resource))
8186 goto out;
8187 WARN_ON(!resource->occ_get);
8188
8189 resource->occ_get = NULL;
8190 resource->occ_get_priv = NULL;
8191out:
8192 mutex_unlock(&devlink->lock);
8193}
8194EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
8195
Vasundhara Volam39e61602019-01-28 18:00:20 +05308196static int devlink_param_verify(const struct devlink_param *param)
8197{
8198 if (!param || !param->name || !param->supported_cmodes)
8199 return -EINVAL;
8200 if (param->generic)
8201 return devlink_param_generic_verify(param);
8202 else
8203 return devlink_param_driver_verify(param);
8204}
8205
8206static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308207 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308208 struct list_head *param_list,
8209 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308210 size_t params_count,
8211 enum devlink_command reg_cmd,
8212 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308213{
8214 const struct devlink_param *param = params;
8215 int i;
8216 int err;
8217
8218 mutex_lock(&devlink->lock);
8219 for (i = 0; i < params_count; i++, param++) {
8220 err = devlink_param_verify(param);
8221 if (err)
8222 goto rollback;
8223
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308224 err = devlink_param_register_one(devlink, port_index,
8225 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308226 if (err)
8227 goto rollback;
8228 }
8229
8230 mutex_unlock(&devlink->lock);
8231 return 0;
8232
8233rollback:
8234 if (!i)
8235 goto unlock;
8236 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308237 devlink_param_unregister_one(devlink, port_index, param_list,
8238 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308239unlock:
8240 mutex_unlock(&devlink->lock);
8241 return err;
8242}
8243
8244static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308245 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308246 struct list_head *param_list,
8247 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308248 size_t params_count,
8249 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05308250{
8251 const struct devlink_param *param = params;
8252 int i;
8253
8254 mutex_lock(&devlink->lock);
8255 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308256 devlink_param_unregister_one(devlink, 0, param_list, param,
8257 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308258 mutex_unlock(&devlink->lock);
8259}
8260
Moshe Shemesheabaef12018-07-04 14:30:28 +03008261/**
8262 * devlink_params_register - register configuration parameters
8263 *
8264 * @devlink: devlink
8265 * @params: configuration parameters array
8266 * @params_count: number of parameters provided
8267 *
8268 * Register the configuration parameters supported by the driver.
8269 */
8270int devlink_params_register(struct devlink *devlink,
8271 const struct devlink_param *params,
8272 size_t params_count)
8273{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308274 return __devlink_params_register(devlink, 0, &devlink->param_list,
8275 params, params_count,
8276 DEVLINK_CMD_PARAM_NEW,
8277 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008278}
8279EXPORT_SYMBOL_GPL(devlink_params_register);
8280
8281/**
8282 * devlink_params_unregister - unregister configuration parameters
8283 * @devlink: devlink
8284 * @params: configuration parameters to unregister
8285 * @params_count: number of parameters provided
8286 */
8287void devlink_params_unregister(struct devlink *devlink,
8288 const struct devlink_param *params,
8289 size_t params_count)
8290{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308291 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
8292 params, params_count,
8293 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03008294}
8295EXPORT_SYMBOL_GPL(devlink_params_unregister);
8296
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008297/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00008298 * devlink_params_publish - publish configuration parameters
8299 *
8300 * @devlink: devlink
8301 *
8302 * Publish previously registered configuration parameters.
8303 */
8304void devlink_params_publish(struct devlink *devlink)
8305{
8306 struct devlink_param_item *param_item;
8307
8308 list_for_each_entry(param_item, &devlink->param_list, list) {
8309 if (param_item->published)
8310 continue;
8311 param_item->published = true;
8312 devlink_param_notify(devlink, 0, param_item,
8313 DEVLINK_CMD_PARAM_NEW);
8314 }
8315}
8316EXPORT_SYMBOL_GPL(devlink_params_publish);
8317
8318/**
8319 * devlink_params_unpublish - unpublish configuration parameters
8320 *
8321 * @devlink: devlink
8322 *
8323 * Unpublish previously registered configuration parameters.
8324 */
8325void devlink_params_unpublish(struct devlink *devlink)
8326{
8327 struct devlink_param_item *param_item;
8328
8329 list_for_each_entry(param_item, &devlink->param_list, list) {
8330 if (!param_item->published)
8331 continue;
8332 param_item->published = false;
8333 devlink_param_notify(devlink, 0, param_item,
8334 DEVLINK_CMD_PARAM_DEL);
8335 }
8336}
8337EXPORT_SYMBOL_GPL(devlink_params_unpublish);
8338
8339/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05308340 * devlink_port_params_register - register port configuration parameters
8341 *
8342 * @devlink_port: devlink port
8343 * @params: configuration parameters array
8344 * @params_count: number of parameters provided
8345 *
8346 * Register the configuration parameters supported by the port.
8347 */
8348int devlink_port_params_register(struct devlink_port *devlink_port,
8349 const struct devlink_param *params,
8350 size_t params_count)
8351{
8352 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308353 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308354 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308355 params_count,
8356 DEVLINK_CMD_PORT_PARAM_NEW,
8357 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308358}
8359EXPORT_SYMBOL_GPL(devlink_port_params_register);
8360
8361/**
8362 * devlink_port_params_unregister - unregister port configuration
8363 * parameters
8364 *
8365 * @devlink_port: devlink port
8366 * @params: configuration parameters array
8367 * @params_count: number of parameters provided
8368 */
8369void devlink_port_params_unregister(struct devlink_port *devlink_port,
8370 const struct devlink_param *params,
8371 size_t params_count)
8372{
8373 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308374 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05308375 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308376 params, params_count,
8377 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05308378}
8379EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
8380
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308381static int
8382__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
8383 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008384{
8385 struct devlink_param_item *param_item;
8386
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308387 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008388 if (!param_item)
8389 return -EINVAL;
8390
8391 if (!param_item->driverinit_value_valid ||
8392 !devlink_param_cmode_is_supported(param_item->param,
8393 DEVLINK_PARAM_CMODE_DRIVERINIT))
8394 return -EOPNOTSUPP;
8395
Moshe Shemesh12765342018-10-10 16:09:26 +03008396 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8397 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
8398 else
8399 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008400
8401 return 0;
8402}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308403
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308404static int
8405__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308406 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308407 struct list_head *param_list, u32 param_id,
8408 union devlink_param_value init_val,
8409 enum devlink_command cmd)
8410{
8411 struct devlink_param_item *param_item;
8412
8413 param_item = devlink_param_find_by_id(param_list, param_id);
8414 if (!param_item)
8415 return -EINVAL;
8416
8417 if (!devlink_param_cmode_is_supported(param_item->param,
8418 DEVLINK_PARAM_CMODE_DRIVERINIT))
8419 return -EOPNOTSUPP;
8420
8421 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
8422 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
8423 else
8424 param_item->driverinit_value = init_val;
8425 param_item->driverinit_value_valid = true;
8426
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308427 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308428 return 0;
8429}
8430
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308431/**
8432 * devlink_param_driverinit_value_get - get configuration parameter
8433 * value for driver initializing
8434 *
8435 * @devlink: devlink
8436 * @param_id: parameter ID
8437 * @init_val: value of parameter in driverinit configuration mode
8438 *
8439 * This function should be used by the driver to get driverinit
8440 * configuration for initialization after reload command.
8441 */
8442int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
8443 union devlink_param_value *init_val)
8444{
Jiri Pirko97691062019-09-12 10:49:45 +02008445 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308446 return -EOPNOTSUPP;
8447
8448 return __devlink_param_driverinit_value_get(&devlink->param_list,
8449 param_id, init_val);
8450}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008451EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
8452
8453/**
8454 * devlink_param_driverinit_value_set - set value of configuration
8455 * parameter for driverinit
8456 * configuration mode
8457 *
8458 * @devlink: devlink
8459 * @param_id: parameter ID
8460 * @init_val: value of parameter to set for driverinit configuration mode
8461 *
8462 * This function should be used by the driver to set driverinit
8463 * configuration mode default value.
8464 */
8465int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
8466 union devlink_param_value init_val)
8467{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308468 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308469 &devlink->param_list,
8470 param_id, init_val,
8471 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03008472}
8473EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
8474
Moshe Shemeshea601e12018-07-04 14:30:32 +03008475/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308476 * devlink_port_param_driverinit_value_get - get configuration parameter
8477 * value for driver initializing
8478 *
8479 * @devlink_port: devlink_port
8480 * @param_id: parameter ID
8481 * @init_val: value of parameter in driverinit configuration mode
8482 *
8483 * This function should be used by the driver to get driverinit
8484 * configuration for initialization after reload command.
8485 */
8486int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
8487 u32 param_id,
8488 union devlink_param_value *init_val)
8489{
8490 struct devlink *devlink = devlink_port->devlink;
8491
Jiri Pirko97691062019-09-12 10:49:45 +02008492 if (!devlink_reload_supported(devlink))
Vasundhara Volamffd19b92019-01-28 18:00:23 +05308493 return -EOPNOTSUPP;
8494
8495 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
8496 param_id, init_val);
8497}
8498EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
8499
8500/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308501 * devlink_port_param_driverinit_value_set - set value of configuration
8502 * parameter for driverinit
8503 * configuration mode
8504 *
8505 * @devlink_port: devlink_port
8506 * @param_id: parameter ID
8507 * @init_val: value of parameter to set for driverinit configuration mode
8508 *
8509 * This function should be used by the driver to set driverinit
8510 * configuration mode default value.
8511 */
8512int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
8513 u32 param_id,
8514 union devlink_param_value init_val)
8515{
8516 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308517 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308518 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308519 param_id, init_val,
8520 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05308521}
8522EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
8523
8524/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03008525 * devlink_param_value_changed - notify devlink on a parameter's value
8526 * change. Should be called by the driver
8527 * right after the change.
8528 *
8529 * @devlink: devlink
8530 * @param_id: parameter ID
8531 *
8532 * This function should be used by the driver to notify devlink on value
8533 * change, excluding driverinit configuration mode.
8534 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03008535 */
8536void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
8537{
8538 struct devlink_param_item *param_item;
8539
8540 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
8541 WARN_ON(!param_item);
8542
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308543 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03008544}
8545EXPORT_SYMBOL_GPL(devlink_param_value_changed);
8546
Alex Veskerb16ebe92018-07-12 15:13:08 +03008547/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05308548 * devlink_port_param_value_changed - notify devlink on a parameter's value
8549 * change. Should be called by the driver
8550 * right after the change.
8551 *
8552 * @devlink_port: devlink_port
8553 * @param_id: parameter ID
8554 *
8555 * This function should be used by the driver to notify devlink on value
8556 * change, excluding driverinit configuration mode.
8557 * For driverinit configuration mode driver should use the function
8558 * devlink_port_param_driverinit_value_set() instead.
8559 */
8560void devlink_port_param_value_changed(struct devlink_port *devlink_port,
8561 u32 param_id)
8562{
8563 struct devlink_param_item *param_item;
8564
8565 param_item = devlink_param_find_by_id(&devlink_port->param_list,
8566 param_id);
8567 WARN_ON(!param_item);
8568
8569 devlink_param_notify(devlink_port->devlink, devlink_port->index,
8570 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
8571}
8572EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
8573
8574/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03008575 * devlink_param_value_str_fill - Safely fill-up the string preventing
8576 * from overflow of the preallocated buffer
8577 *
8578 * @dst_val: destination devlink_param_value
8579 * @src: source buffer
8580 */
8581void devlink_param_value_str_fill(union devlink_param_value *dst_val,
8582 const char *src)
8583{
8584 size_t len;
8585
8586 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
8587 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
8588}
8589EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
8590
8591/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03008592 * devlink_region_create - create a new address region
8593 *
8594 * @devlink: devlink
Jacob Kellere8937682020-03-26 11:37:08 -07008595 * @ops: region operations and name
Alex Veskerb16ebe92018-07-12 15:13:08 +03008596 * @region_max_snapshots: Maximum supported number of snapshots for region
8597 * @region_size: size of region
8598 */
Jacob Kellere8937682020-03-26 11:37:08 -07008599struct devlink_region *
8600devlink_region_create(struct devlink *devlink,
8601 const struct devlink_region_ops *ops,
8602 u32 region_max_snapshots, u64 region_size)
Alex Veskerb16ebe92018-07-12 15:13:08 +03008603{
8604 struct devlink_region *region;
8605 int err = 0;
8606
Jacob Kellera0a09f62020-03-26 11:37:09 -07008607 if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
8608 return ERR_PTR(-EINVAL);
8609
Alex Veskerb16ebe92018-07-12 15:13:08 +03008610 mutex_lock(&devlink->lock);
8611
Jacob Kellere8937682020-03-26 11:37:08 -07008612 if (devlink_region_get_by_name(devlink, ops->name)) {
Alex Veskerb16ebe92018-07-12 15:13:08 +03008613 err = -EEXIST;
8614 goto unlock;
8615 }
8616
8617 region = kzalloc(sizeof(*region), GFP_KERNEL);
8618 if (!region) {
8619 err = -ENOMEM;
8620 goto unlock;
8621 }
8622
8623 region->devlink = devlink;
8624 region->max_snapshots = region_max_snapshots;
Jacob Kellere8937682020-03-26 11:37:08 -07008625 region->ops = ops;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008626 region->size = region_size;
8627 INIT_LIST_HEAD(&region->snapshot_list);
8628 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03008629 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008630
8631 mutex_unlock(&devlink->lock);
8632 return region;
8633
8634unlock:
8635 mutex_unlock(&devlink->lock);
8636 return ERR_PTR(err);
8637}
8638EXPORT_SYMBOL_GPL(devlink_region_create);
8639
8640/**
8641 * devlink_region_destroy - destroy address region
8642 *
8643 * @region: devlink region to destroy
8644 */
8645void devlink_region_destroy(struct devlink_region *region)
8646{
8647 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008648 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03008649
8650 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008651
8652 /* Free all snapshots of region */
8653 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
Jiri Pirko92b49822019-08-12 14:28:31 +02008654 devlink_region_snapshot_del(region, snapshot);
Alex Veskerd7e52722018-07-12 15:13:10 +03008655
Alex Veskerb16ebe92018-07-12 15:13:08 +03008656 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03008657
8658 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03008659 mutex_unlock(&devlink->lock);
8660 kfree(region);
8661}
8662EXPORT_SYMBOL_GPL(devlink_region_destroy);
8663
Alex Veskerccadfa42018-07-12 15:13:09 +03008664/**
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008665 * devlink_region_snapshot_id_get - get snapshot ID
Alex Veskerccadfa42018-07-12 15:13:09 +03008666 *
8667 * This callback should be called when adding a new snapshot,
8668 * Driver should use the same id for multiple snapshots taken
8669 * on multiple regions at the same time/by the same trigger.
8670 *
Jacob Keller12102432020-03-26 11:37:15 -07008671 * The caller of this function must use devlink_region_snapshot_id_put
8672 * when finished creating regions using this id.
8673 *
Jacob Keller7ef19d32020-03-26 11:37:14 -07008674 * Returns zero on success, or a negative error code on failure.
8675 *
Alex Veskerccadfa42018-07-12 15:13:09 +03008676 * @devlink: devlink
Jacob Keller7ef19d32020-03-26 11:37:14 -07008677 * @id: storage to return id
Alex Veskerccadfa42018-07-12 15:13:09 +03008678 */
Jacob Keller7ef19d32020-03-26 11:37:14 -07008679int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
Alex Veskerccadfa42018-07-12 15:13:09 +03008680{
Jacob Keller7ef19d32020-03-26 11:37:14 -07008681 int err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008682
8683 mutex_lock(&devlink->lock);
Jacob Keller7ef19d32020-03-26 11:37:14 -07008684 err = __devlink_region_snapshot_id_get(devlink, id);
Alex Veskerccadfa42018-07-12 15:13:09 +03008685 mutex_unlock(&devlink->lock);
8686
Jacob Keller7ef19d32020-03-26 11:37:14 -07008687 return err;
Alex Veskerccadfa42018-07-12 15:13:09 +03008688}
Jacob Kellerb0efcae2020-01-09 11:08:20 -08008689EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
Alex Veskerccadfa42018-07-12 15:13:09 +03008690
Alex Veskerd7e52722018-07-12 15:13:10 +03008691/**
Jacob Keller12102432020-03-26 11:37:15 -07008692 * devlink_region_snapshot_id_put - put snapshot ID reference
8693 *
8694 * This should be called by a driver after finishing creating snapshots
8695 * with an id. Doing so ensures that the ID can later be released in the
8696 * event that all snapshots using it have been destroyed.
8697 *
8698 * @devlink: devlink
8699 * @id: id to release reference on
8700 */
8701void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
8702{
8703 mutex_lock(&devlink->lock);
8704 __devlink_snapshot_id_decrement(devlink, id);
8705 mutex_unlock(&devlink->lock);
8706}
8707EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
8708
8709/**
Alex Veskerd7e52722018-07-12 15:13:10 +03008710 * devlink_region_snapshot_create - create a new snapshot
8711 * This will add a new snapshot of a region. The snapshot
8712 * will be stored on the region struct and can be accessed
Jacob Keller6d82f672020-03-26 11:37:10 -07008713 * from devlink. This is useful for future analyses of snapshots.
Alex Veskerd7e52722018-07-12 15:13:10 +03008714 * Multiple snapshots can be created on a region.
8715 * The @snapshot_id should be obtained using the getter function.
8716 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08008717 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03008718 * @data: snapshot data
8719 * @snapshot_id: snapshot id to be created
Alex Veskerd7e52722018-07-12 15:13:10 +03008720 */
Jiri Pirko3a5e5232019-08-09 15:27:15 +02008721int devlink_region_snapshot_create(struct devlink_region *region,
Jacob Kellera0a09f62020-03-26 11:37:09 -07008722 u8 *data, u32 snapshot_id)
Alex Veskerd7e52722018-07-12 15:13:10 +03008723{
8724 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03008725 int err;
8726
8727 mutex_lock(&devlink->lock);
Jacob Kellercf80fae2020-03-26 11:37:11 -07008728 err = __devlink_region_snapshot_create(region, data, snapshot_id);
Alex Veskerd7e52722018-07-12 15:13:10 +03008729 mutex_unlock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03008730
Alex Veskerd7e52722018-07-12 15:13:10 +03008731 return err;
8732}
8733EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
8734
Ido Schimmel0f420b62019-08-17 16:28:17 +03008735#define DEVLINK_TRAP(_id, _type) \
8736 { \
8737 .type = DEVLINK_TRAP_TYPE_##_type, \
8738 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
8739 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
8740 }
8741
8742static const struct devlink_trap devlink_trap_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008743 DEVLINK_TRAP(SMAC_MC, DROP),
8744 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
8745 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
8746 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
8747 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
8748 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
8749 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
8750 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
8751 DEVLINK_TRAP(TAIL_DROP, DROP),
Amit Cohen6896cc42019-11-07 18:42:09 +02008752 DEVLINK_TRAP(NON_IP_PACKET, DROP),
8753 DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
8754 DEVLINK_TRAP(DIP_LB, DROP),
8755 DEVLINK_TRAP(SIP_MC, DROP),
8756 DEVLINK_TRAP(SIP_LB, DROP),
8757 DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
8758 DEVLINK_TRAP(IPV4_SIP_BC, DROP),
8759 DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
8760 DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
Amit Cohen3b063ae2019-11-07 18:42:14 +02008761 DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
8762 DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
8763 DEVLINK_TRAP(RPF, EXCEPTION),
8764 DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
8765 DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
8766 DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
Amit Cohen95f0ead2020-01-19 15:00:48 +02008767 DEVLINK_TRAP(NON_ROUTABLE, DROP),
Amit Cohen13c056e2020-01-19 15:00:54 +02008768 DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
Amit Cohenc3cae492020-01-19 15:00:58 +02008769 DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008770 DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
8771 DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
Ido Schimmel515eac62020-05-29 21:36:41 +03008772 DEVLINK_TRAP(STP, CONTROL),
8773 DEVLINK_TRAP(LACP, CONTROL),
8774 DEVLINK_TRAP(LLDP, CONTROL),
8775 DEVLINK_TRAP(IGMP_QUERY, CONTROL),
8776 DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
8777 DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
8778 DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
8779 DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
8780 DEVLINK_TRAP(MLD_QUERY, CONTROL),
8781 DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
8782 DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
8783 DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008784 DEVLINK_TRAP(IPV4_DHCP, CONTROL),
8785 DEVLINK_TRAP(IPV6_DHCP, CONTROL),
8786 DEVLINK_TRAP(ARP_REQUEST, CONTROL),
8787 DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
8788 DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
8789 DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
8790 DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
8791 DEVLINK_TRAP(IPV4_BFD, CONTROL),
8792 DEVLINK_TRAP(IPV6_BFD, CONTROL),
8793 DEVLINK_TRAP(IPV4_OSPF, CONTROL),
8794 DEVLINK_TRAP(IPV6_OSPF, CONTROL),
8795 DEVLINK_TRAP(IPV4_BGP, CONTROL),
8796 DEVLINK_TRAP(IPV6_BGP, CONTROL),
8797 DEVLINK_TRAP(IPV4_VRRP, CONTROL),
8798 DEVLINK_TRAP(IPV6_VRRP, CONTROL),
8799 DEVLINK_TRAP(IPV4_PIM, CONTROL),
8800 DEVLINK_TRAP(IPV6_PIM, CONTROL),
8801 DEVLINK_TRAP(UC_LB, CONTROL),
8802 DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
8803 DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
8804 DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
8805 DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
8806 DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
8807 DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
8808 DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
8809 DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
8810 DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
8811 DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
8812 DEVLINK_TRAP(PTP_EVENT, CONTROL),
8813 DEVLINK_TRAP(PTP_GENERAL, CONTROL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008814 DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
8815 DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008816};
8817
8818#define DEVLINK_TRAP_GROUP(_id) \
8819 { \
8820 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
8821 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
8822 }
8823
8824static const struct devlink_trap_group devlink_trap_group_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03008825 DEVLINK_TRAP_GROUP(L2_DROPS),
8826 DEVLINK_TRAP_GROUP(L3_DROPS),
Ido Schimmel678eb192020-05-29 21:36:36 +03008827 DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
Ido Schimmel391203a2019-08-17 16:28:18 +03008828 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
Amit Cohen13c056e2020-01-19 15:00:54 +02008829 DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
Jiri Pirkoecd942a2020-02-24 08:35:47 +01008830 DEVLINK_TRAP_GROUP(ACL_DROPS),
Ido Schimmel515eac62020-05-29 21:36:41 +03008831 DEVLINK_TRAP_GROUP(STP),
8832 DEVLINK_TRAP_GROUP(LACP),
8833 DEVLINK_TRAP_GROUP(LLDP),
8834 DEVLINK_TRAP_GROUP(MC_SNOOPING),
Ido Schimmeld77cfd12020-05-29 21:36:42 +03008835 DEVLINK_TRAP_GROUP(DHCP),
8836 DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
8837 DEVLINK_TRAP_GROUP(BFD),
8838 DEVLINK_TRAP_GROUP(OSPF),
8839 DEVLINK_TRAP_GROUP(BGP),
8840 DEVLINK_TRAP_GROUP(VRRP),
8841 DEVLINK_TRAP_GROUP(PIM),
8842 DEVLINK_TRAP_GROUP(UC_LB),
8843 DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
8844 DEVLINK_TRAP_GROUP(IPV6),
8845 DEVLINK_TRAP_GROUP(PTP_EVENT),
8846 DEVLINK_TRAP_GROUP(PTP_GENERAL),
Ido Schimmel5eb18a22020-05-29 21:36:43 +03008847 DEVLINK_TRAP_GROUP(ACL_SAMPLE),
8848 DEVLINK_TRAP_GROUP(ACL_TRAP),
Ido Schimmel0f420b62019-08-17 16:28:17 +03008849};
8850
8851static int devlink_trap_generic_verify(const struct devlink_trap *trap)
8852{
8853 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
8854 return -EINVAL;
8855
8856 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
8857 return -EINVAL;
8858
8859 if (trap->type != devlink_trap_generic[trap->id].type)
8860 return -EINVAL;
8861
8862 return 0;
8863}
8864
8865static int devlink_trap_driver_verify(const struct devlink_trap *trap)
8866{
8867 int i;
8868
8869 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
8870 return -EINVAL;
8871
8872 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
8873 if (!strcmp(trap->name, devlink_trap_generic[i].name))
8874 return -EEXIST;
8875 }
8876
8877 return 0;
8878}
8879
8880static int devlink_trap_verify(const struct devlink_trap *trap)
8881{
Ido Schimmel107f1672020-03-22 20:48:30 +02008882 if (!trap || !trap->name)
Ido Schimmel0f420b62019-08-17 16:28:17 +03008883 return -EINVAL;
8884
8885 if (trap->generic)
8886 return devlink_trap_generic_verify(trap);
8887 else
8888 return devlink_trap_driver_verify(trap);
8889}
8890
8891static int
8892devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
8893{
8894 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
8895 return -EINVAL;
8896
8897 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
8898 return -EINVAL;
8899
8900 return 0;
8901}
8902
8903static int
8904devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
8905{
8906 int i;
8907
8908 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
8909 return -EINVAL;
8910
8911 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
8912 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
8913 return -EEXIST;
8914 }
8915
8916 return 0;
8917}
8918
8919static int devlink_trap_group_verify(const struct devlink_trap_group *group)
8920{
8921 if (group->generic)
8922 return devlink_trap_group_generic_verify(group);
8923 else
8924 return devlink_trap_group_driver_verify(group);
8925}
8926
8927static void
8928devlink_trap_group_notify(struct devlink *devlink,
8929 const struct devlink_trap_group_item *group_item,
8930 enum devlink_command cmd)
8931{
8932 struct sk_buff *msg;
8933 int err;
8934
8935 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
8936 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
8937
8938 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8939 if (!msg)
8940 return;
8941
8942 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
8943 0);
8944 if (err) {
8945 nlmsg_free(msg);
8946 return;
8947 }
8948
8949 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
8950 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
8951}
8952
Ido Schimmel0f420b62019-08-17 16:28:17 +03008953static int
8954devlink_trap_item_group_link(struct devlink *devlink,
8955 struct devlink_trap_item *trap_item)
8956{
Ido Schimmel107f1672020-03-22 20:48:30 +02008957 u16 group_id = trap_item->trap->init_group_id;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008958 struct devlink_trap_group_item *group_item;
8959
Ido Schimmel107f1672020-03-22 20:48:30 +02008960 group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
Ido Schimmela09b37f2020-03-22 20:48:29 +02008961 if (WARN_ON_ONCE(!group_item))
8962 return -EINVAL;
Ido Schimmel0f420b62019-08-17 16:28:17 +03008963
8964 trap_item->group_item = group_item;
8965
8966 return 0;
8967}
8968
Ido Schimmel0f420b62019-08-17 16:28:17 +03008969static void devlink_trap_notify(struct devlink *devlink,
8970 const struct devlink_trap_item *trap_item,
8971 enum devlink_command cmd)
8972{
8973 struct sk_buff *msg;
8974 int err;
8975
8976 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
8977 cmd != DEVLINK_CMD_TRAP_DEL);
8978
8979 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8980 if (!msg)
8981 return;
8982
8983 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
8984 if (err) {
8985 nlmsg_free(msg);
8986 return;
8987 }
8988
8989 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
8990 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
8991}
8992
8993static int
8994devlink_trap_register(struct devlink *devlink,
8995 const struct devlink_trap *trap, void *priv)
8996{
8997 struct devlink_trap_item *trap_item;
8998 int err;
8999
9000 if (devlink_trap_item_lookup(devlink, trap->name))
9001 return -EEXIST;
9002
9003 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
9004 if (!trap_item)
9005 return -ENOMEM;
9006
9007 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9008 if (!trap_item->stats) {
9009 err = -ENOMEM;
9010 goto err_stats_alloc;
9011 }
9012
9013 trap_item->trap = trap;
9014 trap_item->action = trap->init_action;
9015 trap_item->priv = priv;
9016
9017 err = devlink_trap_item_group_link(devlink, trap_item);
9018 if (err)
9019 goto err_group_link;
9020
9021 err = devlink->ops->trap_init(devlink, trap, trap_item);
9022 if (err)
9023 goto err_trap_init;
9024
9025 list_add_tail(&trap_item->list, &devlink->trap_list);
9026 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
9027
9028 return 0;
9029
9030err_trap_init:
Ido Schimmel0f420b62019-08-17 16:28:17 +03009031err_group_link:
9032 free_percpu(trap_item->stats);
9033err_stats_alloc:
9034 kfree(trap_item);
9035 return err;
9036}
9037
9038static void devlink_trap_unregister(struct devlink *devlink,
9039 const struct devlink_trap *trap)
9040{
9041 struct devlink_trap_item *trap_item;
9042
9043 trap_item = devlink_trap_item_lookup(devlink, trap->name);
9044 if (WARN_ON_ONCE(!trap_item))
9045 return;
9046
9047 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
9048 list_del(&trap_item->list);
9049 if (devlink->ops->trap_fini)
9050 devlink->ops->trap_fini(devlink, trap, trap_item);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009051 free_percpu(trap_item->stats);
9052 kfree(trap_item);
9053}
9054
9055static void devlink_trap_disable(struct devlink *devlink,
9056 const struct devlink_trap *trap)
9057{
9058 struct devlink_trap_item *trap_item;
9059
9060 trap_item = devlink_trap_item_lookup(devlink, trap->name);
9061 if (WARN_ON_ONCE(!trap_item))
9062 return;
9063
9064 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP);
9065 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
9066}
9067
9068/**
9069 * devlink_traps_register - Register packet traps with devlink.
9070 * @devlink: devlink.
9071 * @traps: Packet traps.
9072 * @traps_count: Count of provided packet traps.
9073 * @priv: Driver private information.
9074 *
9075 * Return: Non-zero value on failure.
9076 */
9077int devlink_traps_register(struct devlink *devlink,
9078 const struct devlink_trap *traps,
9079 size_t traps_count, void *priv)
9080{
9081 int i, err;
9082
9083 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
9084 return -EINVAL;
9085
9086 mutex_lock(&devlink->lock);
9087 for (i = 0; i < traps_count; i++) {
9088 const struct devlink_trap *trap = &traps[i];
9089
9090 err = devlink_trap_verify(trap);
9091 if (err)
9092 goto err_trap_verify;
9093
9094 err = devlink_trap_register(devlink, trap, priv);
9095 if (err)
9096 goto err_trap_register;
9097 }
9098 mutex_unlock(&devlink->lock);
9099
9100 return 0;
9101
9102err_trap_register:
9103err_trap_verify:
9104 for (i--; i >= 0; i--)
9105 devlink_trap_unregister(devlink, &traps[i]);
9106 mutex_unlock(&devlink->lock);
9107 return err;
9108}
9109EXPORT_SYMBOL_GPL(devlink_traps_register);
9110
9111/**
9112 * devlink_traps_unregister - Unregister packet traps from devlink.
9113 * @devlink: devlink.
9114 * @traps: Packet traps.
9115 * @traps_count: Count of provided packet traps.
9116 */
9117void devlink_traps_unregister(struct devlink *devlink,
9118 const struct devlink_trap *traps,
9119 size_t traps_count)
9120{
9121 int i;
9122
9123 mutex_lock(&devlink->lock);
9124 /* Make sure we do not have any packets in-flight while unregistering
9125 * traps by disabling all of them and waiting for a grace period.
9126 */
9127 for (i = traps_count - 1; i >= 0; i--)
9128 devlink_trap_disable(devlink, &traps[i]);
9129 synchronize_rcu();
9130 for (i = traps_count - 1; i >= 0; i--)
9131 devlink_trap_unregister(devlink, &traps[i]);
9132 mutex_unlock(&devlink->lock);
9133}
9134EXPORT_SYMBOL_GPL(devlink_traps_unregister);
9135
9136static void
9137devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
9138 size_t skb_len)
9139{
9140 struct devlink_stats *stats;
9141
9142 stats = this_cpu_ptr(trap_stats);
9143 u64_stats_update_begin(&stats->syncp);
9144 stats->rx_bytes += skb_len;
9145 stats->rx_packets++;
9146 u64_stats_update_end(&stats->syncp);
9147}
9148
9149static void
9150devlink_trap_report_metadata_fill(struct net_dm_hw_metadata *hw_metadata,
9151 const struct devlink_trap_item *trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009152 struct devlink_port *in_devlink_port,
9153 const struct flow_action_cookie *fa_cookie)
Ido Schimmel0f420b62019-08-17 16:28:17 +03009154{
9155 struct devlink_trap_group_item *group_item = trap_item->group_item;
9156
9157 hw_metadata->trap_group_name = group_item->group->name;
9158 hw_metadata->trap_name = trap_item->trap->name;
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009159 hw_metadata->fa_cookie = fa_cookie;
Ido Schimmel0f420b62019-08-17 16:28:17 +03009160
9161 spin_lock(&in_devlink_port->type_lock);
9162 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
9163 hw_metadata->input_dev = in_devlink_port->type_dev;
9164 spin_unlock(&in_devlink_port->type_lock);
9165}
9166
9167/**
9168 * devlink_trap_report - Report trapped packet to drop monitor.
9169 * @devlink: devlink.
9170 * @skb: Trapped packet.
9171 * @trap_ctx: Trap context.
9172 * @in_devlink_port: Input devlink port.
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009173 * @fa_cookie: Flow action cookie. Could be NULL.
Ido Schimmel0f420b62019-08-17 16:28:17 +03009174 */
9175void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009176 void *trap_ctx, struct devlink_port *in_devlink_port,
9177 const struct flow_action_cookie *fa_cookie)
9178
Ido Schimmel0f420b62019-08-17 16:28:17 +03009179{
9180 struct devlink_trap_item *trap_item = trap_ctx;
9181 struct net_dm_hw_metadata hw_metadata = {};
9182
9183 devlink_trap_stats_update(trap_item->stats, skb->len);
9184 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
9185
Ido Schimmel30a4e9a2020-05-29 21:36:40 +03009186 /* Control packets were not dropped by the device or encountered an
9187 * exception during forwarding and therefore should not be reported to
9188 * the kernel's drop monitor.
9189 */
9190 if (trap_item->trap->type == DEVLINK_TRAP_TYPE_CONTROL)
9191 return;
9192
Ido Schimmel0f420b62019-08-17 16:28:17 +03009193 devlink_trap_report_metadata_fill(&hw_metadata, trap_item,
Jiri Pirko5a2e1062020-02-25 11:45:21 +01009194 in_devlink_port, fa_cookie);
Ido Schimmel0f420b62019-08-17 16:28:17 +03009195 net_dm_hw_report(skb, &hw_metadata);
9196}
9197EXPORT_SYMBOL_GPL(devlink_trap_report);
9198
9199/**
9200 * devlink_trap_ctx_priv - Trap context to driver private information.
9201 * @trap_ctx: Trap context.
9202 *
9203 * Return: Driver private information passed during registration.
9204 */
9205void *devlink_trap_ctx_priv(void *trap_ctx)
9206{
9207 struct devlink_trap_item *trap_item = trap_ctx;
9208
9209 return trap_item->priv;
9210}
9211EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
9212
Ido Schimmel95ad9552020-03-22 20:48:26 +02009213static int
Ido Schimmelf9f54392020-03-30 22:38:21 +03009214devlink_trap_group_item_policer_link(struct devlink *devlink,
9215 struct devlink_trap_group_item *group_item)
9216{
9217 u32 policer_id = group_item->group->init_policer_id;
9218 struct devlink_trap_policer_item *policer_item;
9219
9220 if (policer_id == 0)
9221 return 0;
9222
9223 policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
9224 if (WARN_ON_ONCE(!policer_item))
9225 return -EINVAL;
9226
9227 group_item->policer_item = policer_item;
9228
9229 return 0;
9230}
9231
9232static int
Ido Schimmel95ad9552020-03-22 20:48:26 +02009233devlink_trap_group_register(struct devlink *devlink,
9234 const struct devlink_trap_group *group)
9235{
9236 struct devlink_trap_group_item *group_item;
9237 int err;
9238
9239 if (devlink_trap_group_item_lookup(devlink, group->name))
9240 return -EEXIST;
9241
9242 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
9243 if (!group_item)
9244 return -ENOMEM;
9245
9246 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
9247 if (!group_item->stats) {
9248 err = -ENOMEM;
9249 goto err_stats_alloc;
9250 }
9251
9252 group_item->group = group;
Ido Schimmel95ad9552020-03-22 20:48:26 +02009253
Ido Schimmelf9f54392020-03-30 22:38:21 +03009254 err = devlink_trap_group_item_policer_link(devlink, group_item);
9255 if (err)
9256 goto err_policer_link;
9257
Ido Schimmel95ad9552020-03-22 20:48:26 +02009258 if (devlink->ops->trap_group_init) {
9259 err = devlink->ops->trap_group_init(devlink, group);
9260 if (err)
9261 goto err_group_init;
9262 }
9263
9264 list_add_tail(&group_item->list, &devlink->trap_group_list);
9265 devlink_trap_group_notify(devlink, group_item,
9266 DEVLINK_CMD_TRAP_GROUP_NEW);
9267
9268 return 0;
9269
9270err_group_init:
Ido Schimmelf9f54392020-03-30 22:38:21 +03009271err_policer_link:
Ido Schimmel95ad9552020-03-22 20:48:26 +02009272 free_percpu(group_item->stats);
9273err_stats_alloc:
9274 kfree(group_item);
9275 return err;
9276}
9277
9278static void
9279devlink_trap_group_unregister(struct devlink *devlink,
9280 const struct devlink_trap_group *group)
9281{
9282 struct devlink_trap_group_item *group_item;
9283
9284 group_item = devlink_trap_group_item_lookup(devlink, group->name);
9285 if (WARN_ON_ONCE(!group_item))
9286 return;
9287
9288 devlink_trap_group_notify(devlink, group_item,
9289 DEVLINK_CMD_TRAP_GROUP_DEL);
9290 list_del(&group_item->list);
9291 free_percpu(group_item->stats);
9292 kfree(group_item);
9293}
9294
9295/**
9296 * devlink_trap_groups_register - Register packet trap groups with devlink.
9297 * @devlink: devlink.
9298 * @groups: Packet trap groups.
9299 * @groups_count: Count of provided packet trap groups.
9300 *
9301 * Return: Non-zero value on failure.
9302 */
9303int devlink_trap_groups_register(struct devlink *devlink,
9304 const struct devlink_trap_group *groups,
9305 size_t groups_count)
9306{
9307 int i, err;
9308
9309 mutex_lock(&devlink->lock);
9310 for (i = 0; i < groups_count; i++) {
9311 const struct devlink_trap_group *group = &groups[i];
9312
9313 err = devlink_trap_group_verify(group);
9314 if (err)
9315 goto err_trap_group_verify;
9316
9317 err = devlink_trap_group_register(devlink, group);
9318 if (err)
9319 goto err_trap_group_register;
9320 }
9321 mutex_unlock(&devlink->lock);
9322
9323 return 0;
9324
9325err_trap_group_register:
9326err_trap_group_verify:
9327 for (i--; i >= 0; i--)
9328 devlink_trap_group_unregister(devlink, &groups[i]);
9329 mutex_unlock(&devlink->lock);
9330 return err;
9331}
9332EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
9333
9334/**
9335 * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
9336 * @devlink: devlink.
9337 * @groups: Packet trap groups.
9338 * @groups_count: Count of provided packet trap groups.
9339 */
9340void devlink_trap_groups_unregister(struct devlink *devlink,
9341 const struct devlink_trap_group *groups,
9342 size_t groups_count)
9343{
9344 int i;
9345
9346 mutex_lock(&devlink->lock);
9347 for (i = groups_count - 1; i >= 0; i--)
9348 devlink_trap_group_unregister(devlink, &groups[i]);
9349 mutex_unlock(&devlink->lock);
9350}
9351EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
9352
Ido Schimmel1e8c6612020-03-30 22:38:18 +03009353static void
9354devlink_trap_policer_notify(struct devlink *devlink,
9355 const struct devlink_trap_policer_item *policer_item,
9356 enum devlink_command cmd)
9357{
9358 struct sk_buff *msg;
9359 int err;
9360
9361 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
9362 cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
9363
9364 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9365 if (!msg)
9366 return;
9367
9368 err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
9369 0, 0);
9370 if (err) {
9371 nlmsg_free(msg);
9372 return;
9373 }
9374
9375 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
9376 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
9377}
9378
9379static int
9380devlink_trap_policer_register(struct devlink *devlink,
9381 const struct devlink_trap_policer *policer)
9382{
9383 struct devlink_trap_policer_item *policer_item;
9384 int err;
9385
9386 if (devlink_trap_policer_item_lookup(devlink, policer->id))
9387 return -EEXIST;
9388
9389 policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
9390 if (!policer_item)
9391 return -ENOMEM;
9392
9393 policer_item->policer = policer;
9394 policer_item->rate = policer->init_rate;
9395 policer_item->burst = policer->init_burst;
9396
9397 if (devlink->ops->trap_policer_init) {
9398 err = devlink->ops->trap_policer_init(devlink, policer);
9399 if (err)
9400 goto err_policer_init;
9401 }
9402
9403 list_add_tail(&policer_item->list, &devlink->trap_policer_list);
9404 devlink_trap_policer_notify(devlink, policer_item,
9405 DEVLINK_CMD_TRAP_POLICER_NEW);
9406
9407 return 0;
9408
9409err_policer_init:
9410 kfree(policer_item);
9411 return err;
9412}
9413
9414static void
9415devlink_trap_policer_unregister(struct devlink *devlink,
9416 const struct devlink_trap_policer *policer)
9417{
9418 struct devlink_trap_policer_item *policer_item;
9419
9420 policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
9421 if (WARN_ON_ONCE(!policer_item))
9422 return;
9423
9424 devlink_trap_policer_notify(devlink, policer_item,
9425 DEVLINK_CMD_TRAP_POLICER_DEL);
9426 list_del(&policer_item->list);
9427 if (devlink->ops->trap_policer_fini)
9428 devlink->ops->trap_policer_fini(devlink, policer);
9429 kfree(policer_item);
9430}
9431
9432/**
9433 * devlink_trap_policers_register - Register packet trap policers with devlink.
9434 * @devlink: devlink.
9435 * @policers: Packet trap policers.
9436 * @policers_count: Count of provided packet trap policers.
9437 *
9438 * Return: Non-zero value on failure.
9439 */
9440int
9441devlink_trap_policers_register(struct devlink *devlink,
9442 const struct devlink_trap_policer *policers,
9443 size_t policers_count)
9444{
9445 int i, err;
9446
9447 mutex_lock(&devlink->lock);
9448 for (i = 0; i < policers_count; i++) {
9449 const struct devlink_trap_policer *policer = &policers[i];
9450
9451 if (WARN_ON(policer->id == 0 ||
9452 policer->max_rate < policer->min_rate ||
9453 policer->max_burst < policer->min_burst)) {
9454 err = -EINVAL;
9455 goto err_trap_policer_verify;
9456 }
9457
9458 err = devlink_trap_policer_register(devlink, policer);
9459 if (err)
9460 goto err_trap_policer_register;
9461 }
9462 mutex_unlock(&devlink->lock);
9463
9464 return 0;
9465
9466err_trap_policer_register:
9467err_trap_policer_verify:
9468 for (i--; i >= 0; i--)
9469 devlink_trap_policer_unregister(devlink, &policers[i]);
9470 mutex_unlock(&devlink->lock);
9471 return err;
9472}
9473EXPORT_SYMBOL_GPL(devlink_trap_policers_register);
9474
9475/**
9476 * devlink_trap_policers_unregister - Unregister packet trap policers from devlink.
9477 * @devlink: devlink.
9478 * @policers: Packet trap policers.
9479 * @policers_count: Count of provided packet trap policers.
9480 */
9481void
9482devlink_trap_policers_unregister(struct devlink *devlink,
9483 const struct devlink_trap_policer *policers,
9484 size_t policers_count)
9485{
9486 int i;
9487
9488 mutex_lock(&devlink->lock);
9489 for (i = policers_count - 1; i >= 0; i--)
9490 devlink_trap_policer_unregister(devlink, &policers[i]);
9491 mutex_unlock(&devlink->lock);
9492}
9493EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister);
9494
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009495static void __devlink_compat_running_version(struct devlink *devlink,
9496 char *buf, size_t len)
9497{
9498 const struct nlattr *nlattr;
9499 struct devlink_info_req req;
9500 struct sk_buff *msg;
9501 int rem, err;
9502
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009503 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9504 if (!msg)
9505 return;
9506
9507 req.msg = msg;
9508 err = devlink->ops->info_get(devlink, &req, NULL);
9509 if (err)
9510 goto free_msg;
9511
9512 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
9513 const struct nlattr *kv;
9514 int rem_kv;
9515
9516 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
9517 continue;
9518
9519 nla_for_each_nested(kv, nlattr, rem_kv) {
9520 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
9521 continue;
9522
9523 strlcat(buf, nla_data(kv), len);
9524 strlcat(buf, " ", len);
9525 }
9526 }
9527free_msg:
9528 nlmsg_free(msg);
9529}
9530
9531void devlink_compat_running_version(struct net_device *dev,
9532 char *buf, size_t len)
9533{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009534 struct devlink *devlink;
9535
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009536 dev_hold(dev);
9537 rtnl_unlock();
9538
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009539 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08009540 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009541 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009542
9543 mutex_lock(&devlink->lock);
9544 __devlink_compat_running_version(devlink, buf, len);
9545 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009546
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009547out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009548 rtnl_lock();
9549 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08009550}
9551
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009552int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
9553{
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009554 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009555 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009556
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009557 dev_hold(dev);
9558 rtnl_unlock();
9559
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009560 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009561 if (!devlink || !devlink->ops->flash_update) {
9562 ret = -EOPNOTSUPP;
9563 goto out;
9564 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009565
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009566 mutex_lock(&devlink->lock);
9567 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
9568 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009569
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01009570out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08009571 rtnl_lock();
9572 dev_put(dev);
9573
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08009574 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08009575}
9576
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01009577int devlink_compat_phys_port_name_get(struct net_device *dev,
9578 char *name, size_t len)
9579{
9580 struct devlink_port *devlink_port;
9581
9582 /* RTNL mutex is held here which ensures that devlink_port
9583 * instance cannot disappear in the middle. No need to take
9584 * any devlink lock as only permanent values are accessed.
9585 */
9586 ASSERT_RTNL();
9587
9588 devlink_port = netdev_to_devlink_port(dev);
9589 if (!devlink_port)
9590 return -EOPNOTSUPP;
9591
9592 return __devlink_port_phys_port_name_get(devlink_port, name, len);
9593}
9594
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009595int devlink_compat_switch_id_get(struct net_device *dev,
9596 struct netdev_phys_item_id *ppid)
9597{
9598 struct devlink_port *devlink_port;
9599
Vlad Buslov043b8412019-08-12 20:02:02 +03009600 /* Caller must hold RTNL mutex or reference to dev, which ensures that
9601 * devlink_port instance cannot disappear in the middle. No need to take
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009602 * any devlink lock as only permanent values are accessed.
9603 */
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009604 devlink_port = netdev_to_devlink_port(dev);
Danielle Ratson46737a12020-07-09 16:18:15 +03009605 if (!devlink_port || !devlink_port->switch_port)
Jiri Pirko7e1146e2019-04-03 14:24:17 +02009606 return -EOPNOTSUPP;
9607
9608 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
9609
9610 return 0;
9611}
9612
Jiri Pirko070c63f2019-10-03 11:49:39 +02009613static void __net_exit devlink_pernet_pre_exit(struct net *net)
9614{
9615 struct devlink *devlink;
9616 int err;
9617
9618 /* In case network namespace is getting destroyed, reload
9619 * all devlink instances from this namespace into init_net.
9620 */
9621 mutex_lock(&devlink_mutex);
9622 list_for_each_entry(devlink, &devlink_list, list) {
9623 if (net_eq(devlink_net(devlink), net)) {
9624 if (WARN_ON(!devlink_reload_supported(devlink)))
9625 continue;
9626 err = devlink_reload(devlink, &init_net, NULL);
Jiri Pirkoa0c76342019-11-08 21:42:43 +01009627 if (err && err != -EOPNOTSUPP)
Jiri Pirko070c63f2019-10-03 11:49:39 +02009628 pr_warn("Failed to reload devlink instance into init_net\n");
9629 }
9630 }
9631 mutex_unlock(&devlink_mutex);
9632}
9633
9634static struct pernet_operations devlink_pernet_ops __net_initdata = {
9635 .pre_exit = devlink_pernet_pre_exit,
9636};
9637
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009638static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009639{
Jiri Pirko070c63f2019-10-03 11:49:39 +02009640 int err;
9641
9642 err = genl_register_family(&devlink_nl_family);
9643 if (err)
9644 goto out;
9645 err = register_pernet_subsys(&devlink_pernet_ops);
9646
9647out:
9648 WARN_ON(err);
9649 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01009650}
9651
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08009652subsys_initcall(devlink_init);