blob: b7091329987a546a78299c82c9ee0a870403ef39 [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
88static LIST_HEAD(devlink_list);
89
90/* devlink_mutex
91 *
92 * An overall lock guarding every operation coming from userspace.
93 * It also guards devlink devices list and it is taken when
94 * driver registers/unregisters it.
95 */
96static DEFINE_MUTEX(devlink_mutex);
97
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010098static struct net *devlink_net(const struct devlink *devlink)
99{
100 return read_pnet(&devlink->_net);
101}
102
103static void devlink_net_set(struct devlink *devlink, struct net *net)
104{
105 write_pnet(&devlink->_net, net);
106}
107
108static struct devlink *devlink_get_from_attrs(struct net *net,
109 struct nlattr **attrs)
110{
111 struct devlink *devlink;
112 char *busname;
113 char *devname;
114
115 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
116 return ERR_PTR(-EINVAL);
117
118 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
119 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
120
Parav Panditdac7c082019-02-12 14:24:08 -0600121 lockdep_assert_held(&devlink_mutex);
122
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100123 list_for_each_entry(devlink, &devlink_list, list) {
124 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
125 strcmp(dev_name(devlink->dev), devname) == 0 &&
126 net_eq(devlink_net(devlink), net))
127 return devlink;
128 }
129
130 return ERR_PTR(-ENODEV);
131}
132
133static struct devlink *devlink_get_from_info(struct genl_info *info)
134{
135 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
136}
137
138static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
Parav Panditc7282b52019-08-30 05:39:44 -0500139 unsigned int port_index)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100140{
141 struct devlink_port *devlink_port;
142
143 list_for_each_entry(devlink_port, &devlink->port_list, list) {
144 if (devlink_port->index == port_index)
145 return devlink_port;
146 }
147 return NULL;
148}
149
Parav Panditc7282b52019-08-30 05:39:44 -0500150static bool devlink_port_index_exists(struct devlink *devlink,
151 unsigned int port_index)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100152{
153 return devlink_port_get_by_index(devlink, port_index);
154}
155
156static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
157 struct nlattr **attrs)
158{
159 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
160 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
161 struct devlink_port *devlink_port;
162
163 devlink_port = devlink_port_get_by_index(devlink, port_index);
164 if (!devlink_port)
165 return ERR_PTR(-ENODEV);
166 return devlink_port;
167 }
168 return ERR_PTR(-EINVAL);
169}
170
171static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
172 struct genl_info *info)
173{
174 return devlink_port_get_from_attrs(devlink, info->attrs);
175}
176
Jiri Pirkobf797472016-04-14 18:19:13 +0200177struct devlink_sb {
178 struct list_head list;
179 unsigned int index;
180 u32 size;
181 u16 ingress_pools_count;
182 u16 egress_pools_count;
183 u16 ingress_tc_count;
184 u16 egress_tc_count;
185};
186
187static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
188{
189 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
190}
191
192static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
193 unsigned int sb_index)
194{
195 struct devlink_sb *devlink_sb;
196
197 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
198 if (devlink_sb->index == sb_index)
199 return devlink_sb;
200 }
201 return NULL;
202}
203
204static bool devlink_sb_index_exists(struct devlink *devlink,
205 unsigned int sb_index)
206{
207 return devlink_sb_get_by_index(devlink, sb_index);
208}
209
210static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
211 struct nlattr **attrs)
212{
213 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
214 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
215 struct devlink_sb *devlink_sb;
216
217 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
218 if (!devlink_sb)
219 return ERR_PTR(-ENODEV);
220 return devlink_sb;
221 }
222 return ERR_PTR(-EINVAL);
223}
224
225static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
226 struct genl_info *info)
227{
228 return devlink_sb_get_from_attrs(devlink, info->attrs);
229}
230
231static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
232 struct nlattr **attrs,
233 u16 *p_pool_index)
234{
235 u16 val;
236
237 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
238 return -EINVAL;
239
240 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
241 if (val >= devlink_sb_pool_count(devlink_sb))
242 return -EINVAL;
243 *p_pool_index = val;
244 return 0;
245}
246
247static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
248 struct genl_info *info,
249 u16 *p_pool_index)
250{
251 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
252 p_pool_index);
253}
254
255static int
256devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
257 enum devlink_sb_pool_type *p_pool_type)
258{
259 u8 val;
260
261 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
262 return -EINVAL;
263
264 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
265 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
266 val != DEVLINK_SB_POOL_TYPE_EGRESS)
267 return -EINVAL;
268 *p_pool_type = val;
269 return 0;
270}
271
272static int
273devlink_sb_pool_type_get_from_info(struct genl_info *info,
274 enum devlink_sb_pool_type *p_pool_type)
275{
276 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
277}
278
279static int
280devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
281 enum devlink_sb_threshold_type *p_th_type)
282{
283 u8 val;
284
285 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
286 return -EINVAL;
287
288 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
289 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
290 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
291 return -EINVAL;
292 *p_th_type = val;
293 return 0;
294}
295
296static int
297devlink_sb_th_type_get_from_info(struct genl_info *info,
298 enum devlink_sb_threshold_type *p_th_type)
299{
300 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
301}
302
303static int
304devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
305 struct nlattr **attrs,
306 enum devlink_sb_pool_type pool_type,
307 u16 *p_tc_index)
308{
309 u16 val;
310
311 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
312 return -EINVAL;
313
314 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
315 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
316 val >= devlink_sb->ingress_tc_count)
317 return -EINVAL;
318 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
319 val >= devlink_sb->egress_tc_count)
320 return -EINVAL;
321 *p_tc_index = val;
322 return 0;
323}
324
325static int
326devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
327 struct genl_info *info,
328 enum devlink_sb_pool_type pool_type,
329 u16 *p_tc_index)
330{
331 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
332 pool_type, p_tc_index);
333}
334
Alex Veskerb16ebe92018-07-12 15:13:08 +0300335struct devlink_region {
336 struct devlink *devlink;
337 struct list_head list;
338 const char *name;
339 struct list_head snapshot_list;
340 u32 max_snapshots;
341 u32 cur_snapshots;
342 u64 size;
343};
344
Alex Veskerd7e52722018-07-12 15:13:10 +0300345struct devlink_snapshot {
346 struct list_head list;
347 struct devlink_region *region;
348 devlink_snapshot_data_dest_t *data_destructor;
Alex Veskerd7e52722018-07-12 15:13:10 +0300349 u8 *data;
350 u32 id;
351};
352
Alex Veskerb16ebe92018-07-12 15:13:08 +0300353static struct devlink_region *
354devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
355{
356 struct devlink_region *region;
357
358 list_for_each_entry(region, &devlink->region_list, list)
359 if (!strcmp(region->name, region_name))
360 return region;
361
362 return NULL;
363}
364
Alex Veskerd7e52722018-07-12 15:13:10 +0300365static struct devlink_snapshot *
366devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
367{
368 struct devlink_snapshot *snapshot;
369
370 list_for_each_entry(snapshot, &region->snapshot_list, list)
371 if (snapshot->id == id)
372 return snapshot;
373
374 return NULL;
375}
376
Jiri Pirko1fc22572016-04-08 19:12:48 +0200377#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
378#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
Jiri Pirkobf797472016-04-14 18:19:13 +0200379#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100380
381/* The per devlink instance lock is taken by default in the pre-doit
382 * operation, yet several commands do not require this. The global
383 * devlink lock is taken and protects from disruption by user-calls.
384 */
385#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100386
387static int devlink_nl_pre_doit(const struct genl_ops *ops,
388 struct sk_buff *skb, struct genl_info *info)
389{
390 struct devlink *devlink;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100391 int err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100392
393 mutex_lock(&devlink_mutex);
394 devlink = devlink_get_from_info(info);
395 if (IS_ERR(devlink)) {
396 mutex_unlock(&devlink_mutex);
397 return PTR_ERR(devlink);
398 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100399 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
400 mutex_lock(&devlink->lock);
Jiri Pirko1fc22572016-04-08 19:12:48 +0200401 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
402 info->user_ptr[0] = devlink;
403 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100404 struct devlink_port *devlink_port;
405
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100406 devlink_port = devlink_port_get_from_info(devlink, info);
407 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100408 err = PTR_ERR(devlink_port);
409 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100410 }
Jiri Pirko1fc22572016-04-08 19:12:48 +0200411 info->user_ptr[0] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100412 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200413 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
414 struct devlink_sb *devlink_sb;
415
416 devlink_sb = devlink_sb_get_from_info(devlink, info);
417 if (IS_ERR(devlink_sb)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100418 err = PTR_ERR(devlink_sb);
419 goto unlock;
Jiri Pirkobf797472016-04-14 18:19:13 +0200420 }
421 info->user_ptr[1] = devlink_sb;
422 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100423 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100424
425unlock:
426 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
427 mutex_unlock(&devlink->lock);
428 mutex_unlock(&devlink_mutex);
429 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100430}
431
432static void devlink_nl_post_doit(const struct genl_ops *ops,
433 struct sk_buff *skb, struct genl_info *info)
434{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100435 struct devlink *devlink;
436
437 devlink = devlink_get_from_info(info);
438 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
439 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100440 mutex_unlock(&devlink_mutex);
441}
442
Johannes Berg489111e2016-10-24 14:40:03 +0200443static struct genl_family devlink_nl_family;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100444
445enum devlink_multicast_groups {
446 DEVLINK_MCGRP_CONFIG,
447};
448
449static const struct genl_multicast_group devlink_nl_mcgrps[] = {
450 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
451};
452
453static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
454{
455 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
456 return -EMSGSIZE;
457 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
458 return -EMSGSIZE;
459 return 0;
460}
461
462static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
463 enum devlink_command cmd, u32 portid,
464 u32 seq, int flags)
465{
466 void *hdr;
467
468 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
469 if (!hdr)
470 return -EMSGSIZE;
471
472 if (devlink_nl_put_handle(msg, devlink))
473 goto nla_put_failure;
474
475 genlmsg_end(msg, hdr);
476 return 0;
477
478nla_put_failure:
479 genlmsg_cancel(msg, hdr);
480 return -EMSGSIZE;
481}
482
483static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
484{
485 struct sk_buff *msg;
486 int err;
487
488 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
489
490 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
491 if (!msg)
492 return;
493
494 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
495 if (err) {
496 nlmsg_free(msg);
497 return;
498 }
499
500 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
501 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
502}
503
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200504static int devlink_nl_port_attrs_put(struct sk_buff *msg,
505 struct devlink_port *devlink_port)
506{
507 struct devlink_port_attrs *attrs = &devlink_port->attrs;
508
509 if (!attrs->set)
510 return 0;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200511 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
512 return -EMSGSIZE;
Parav Pandit98fd2d62019-07-08 23:17:37 -0500513 if (devlink_port->attrs.flavour == DEVLINK_PORT_FLAVOUR_PCI_PF) {
514 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
515 attrs->pci_pf.pf))
516 return -EMSGSIZE;
Parav Pandite41b6bf2019-07-08 23:17:38 -0500517 } else if (devlink_port->attrs.flavour == DEVLINK_PORT_FLAVOUR_PCI_VF) {
518 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
519 attrs->pci_vf.pf) ||
520 nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER,
521 attrs->pci_vf.vf))
522 return -EMSGSIZE;
Parav Pandit98fd2d62019-07-08 23:17:37 -0500523 }
Parav Pandita2c6b872019-07-08 23:17:36 -0500524 if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PHYSICAL &&
525 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
526 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA)
527 return 0;
Parav Pandit378ef012019-07-08 23:17:35 -0500528 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
529 attrs->phys.port_number))
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200530 return -EMSGSIZE;
531 if (!attrs->split)
532 return 0;
Parav Pandit378ef012019-07-08 23:17:35 -0500533 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
534 attrs->phys.port_number))
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200535 return -EMSGSIZE;
536 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
Parav Pandit378ef012019-07-08 23:17:35 -0500537 attrs->phys.split_subport_number))
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200538 return -EMSGSIZE;
539 return 0;
540}
541
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100542static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
543 struct devlink_port *devlink_port,
544 enum devlink_command cmd, u32 portid,
545 u32 seq, int flags)
546{
547 void *hdr;
548
549 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
550 if (!hdr)
551 return -EMSGSIZE;
552
553 if (devlink_nl_put_handle(msg, devlink))
554 goto nla_put_failure;
555 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
556 goto nla_put_failure;
Jiri Pirkob8f97552019-03-24 11:14:37 +0100557
Ido Schimmel0f420b62019-08-17 16:28:17 +0300558 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100559 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100560 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100561 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
562 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
563 devlink_port->desired_type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100564 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100565 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
566 struct net_device *netdev = devlink_port->type_dev;
567
568 if (netdev &&
569 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
570 netdev->ifindex) ||
571 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
572 netdev->name)))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100573 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100574 }
575 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
576 struct ib_device *ibdev = devlink_port->type_dev;
577
578 if (ibdev &&
579 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
580 ibdev->name))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100581 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100582 }
Ido Schimmel0f420b62019-08-17 16:28:17 +0300583 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200584 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100585 goto nla_put_failure;
586
587 genlmsg_end(msg, hdr);
588 return 0;
589
Jiri Pirkob8f97552019-03-24 11:14:37 +0100590nla_put_failure_type_locked:
Ido Schimmel0f420b62019-08-17 16:28:17 +0300591 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100592nla_put_failure:
593 genlmsg_cancel(msg, hdr);
594 return -EMSGSIZE;
595}
596
597static void devlink_port_notify(struct devlink_port *devlink_port,
598 enum devlink_command cmd)
599{
600 struct devlink *devlink = devlink_port->devlink;
601 struct sk_buff *msg;
602 int err;
603
604 if (!devlink_port->registered)
605 return;
606
607 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
608
609 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
610 if (!msg)
611 return;
612
613 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
614 if (err) {
615 nlmsg_free(msg);
616 return;
617 }
618
619 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
620 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
621}
622
623static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
624{
625 struct devlink *devlink = info->user_ptr[0];
626 struct sk_buff *msg;
627 int err;
628
629 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
630 if (!msg)
631 return -ENOMEM;
632
633 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
634 info->snd_portid, info->snd_seq, 0);
635 if (err) {
636 nlmsg_free(msg);
637 return err;
638 }
639
640 return genlmsg_reply(msg, info);
641}
642
643static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
644 struct netlink_callback *cb)
645{
646 struct devlink *devlink;
647 int start = cb->args[0];
648 int idx = 0;
649 int err;
650
651 mutex_lock(&devlink_mutex);
652 list_for_each_entry(devlink, &devlink_list, list) {
653 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
654 continue;
655 if (idx < start) {
656 idx++;
657 continue;
658 }
659 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
660 NETLINK_CB(cb->skb).portid,
661 cb->nlh->nlmsg_seq, NLM_F_MULTI);
662 if (err)
663 goto out;
664 idx++;
665 }
666out:
667 mutex_unlock(&devlink_mutex);
668
669 cb->args[0] = idx;
670 return msg->len;
671}
672
673static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
674 struct genl_info *info)
675{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200676 struct devlink_port *devlink_port = info->user_ptr[0];
677 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100678 struct sk_buff *msg;
679 int err;
680
681 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
682 if (!msg)
683 return -ENOMEM;
684
685 err = devlink_nl_port_fill(msg, devlink, devlink_port,
686 DEVLINK_CMD_PORT_NEW,
687 info->snd_portid, info->snd_seq, 0);
688 if (err) {
689 nlmsg_free(msg);
690 return err;
691 }
692
693 return genlmsg_reply(msg, info);
694}
695
696static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
697 struct netlink_callback *cb)
698{
699 struct devlink *devlink;
700 struct devlink_port *devlink_port;
701 int start = cb->args[0];
702 int idx = 0;
703 int err;
704
705 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100706 list_for_each_entry(devlink, &devlink_list, list) {
707 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
708 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100709 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100710 list_for_each_entry(devlink_port, &devlink->port_list, list) {
711 if (idx < start) {
712 idx++;
713 continue;
714 }
715 err = devlink_nl_port_fill(msg, devlink, devlink_port,
716 DEVLINK_CMD_NEW,
717 NETLINK_CB(cb->skb).portid,
718 cb->nlh->nlmsg_seq,
719 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100720 if (err) {
721 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100722 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100723 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100724 idx++;
725 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100726 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100727 }
728out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100729 mutex_unlock(&devlink_mutex);
730
731 cb->args[0] = idx;
732 return msg->len;
733}
734
735static int devlink_port_type_set(struct devlink *devlink,
736 struct devlink_port *devlink_port,
737 enum devlink_port_type port_type)
738
739{
740 int err;
741
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800742 if (devlink->ops->port_type_set) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100743 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
744 return -EINVAL;
Elad Raz6edf1012016-10-23 17:43:05 +0200745 if (port_type == devlink_port->type)
746 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100747 err = devlink->ops->port_type_set(devlink_port, port_type);
748 if (err)
749 return err;
750 devlink_port->desired_type = port_type;
751 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
752 return 0;
753 }
754 return -EOPNOTSUPP;
755}
756
757static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
758 struct genl_info *info)
759{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200760 struct devlink_port *devlink_port = info->user_ptr[0];
761 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100762 int err;
763
764 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
765 enum devlink_port_type port_type;
766
767 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
768 err = devlink_port_type_set(devlink, devlink_port, port_type);
769 if (err)
770 return err;
771 }
772 return 0;
773}
774
David Ahernac0fc8a2018-06-05 08:14:09 -0700775static int devlink_port_split(struct devlink *devlink, u32 port_index,
776 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100777
778{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800779 if (devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -0700780 return devlink->ops->port_split(devlink, port_index, count,
781 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100782 return -EOPNOTSUPP;
783}
784
785static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
786 struct genl_info *info)
787{
788 struct devlink *devlink = info->user_ptr[0];
789 u32 port_index;
790 u32 count;
791
792 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
793 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
794 return -EINVAL;
795
796 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
797 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700798 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100799}
800
David Ahernac0fc8a2018-06-05 08:14:09 -0700801static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
802 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100803
804{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800805 if (devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -0700806 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100807 return -EOPNOTSUPP;
808}
809
810static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
811 struct genl_info *info)
812{
813 struct devlink *devlink = info->user_ptr[0];
814 u32 port_index;
815
816 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
817 return -EINVAL;
818
819 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700820 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100821}
822
Jiri Pirkobf797472016-04-14 18:19:13 +0200823static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
824 struct devlink_sb *devlink_sb,
825 enum devlink_command cmd, u32 portid,
826 u32 seq, int flags)
827{
828 void *hdr;
829
830 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
831 if (!hdr)
832 return -EMSGSIZE;
833
834 if (devlink_nl_put_handle(msg, devlink))
835 goto nla_put_failure;
836 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
837 goto nla_put_failure;
838 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
839 goto nla_put_failure;
840 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
841 devlink_sb->ingress_pools_count))
842 goto nla_put_failure;
843 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
844 devlink_sb->egress_pools_count))
845 goto nla_put_failure;
846 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
847 devlink_sb->ingress_tc_count))
848 goto nla_put_failure;
849 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
850 devlink_sb->egress_tc_count))
851 goto nla_put_failure;
852
853 genlmsg_end(msg, hdr);
854 return 0;
855
856nla_put_failure:
857 genlmsg_cancel(msg, hdr);
858 return -EMSGSIZE;
859}
860
861static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
862 struct genl_info *info)
863{
864 struct devlink *devlink = info->user_ptr[0];
865 struct devlink_sb *devlink_sb = info->user_ptr[1];
866 struct sk_buff *msg;
867 int err;
868
869 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
870 if (!msg)
871 return -ENOMEM;
872
873 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
874 DEVLINK_CMD_SB_NEW,
875 info->snd_portid, info->snd_seq, 0);
876 if (err) {
877 nlmsg_free(msg);
878 return err;
879 }
880
881 return genlmsg_reply(msg, info);
882}
883
884static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
885 struct netlink_callback *cb)
886{
887 struct devlink *devlink;
888 struct devlink_sb *devlink_sb;
889 int start = cb->args[0];
890 int idx = 0;
891 int err;
892
893 mutex_lock(&devlink_mutex);
894 list_for_each_entry(devlink, &devlink_list, list) {
895 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
896 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100897 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200898 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
899 if (idx < start) {
900 idx++;
901 continue;
902 }
903 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
904 DEVLINK_CMD_SB_NEW,
905 NETLINK_CB(cb->skb).portid,
906 cb->nlh->nlmsg_seq,
907 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100908 if (err) {
909 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200910 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100911 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200912 idx++;
913 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100914 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200915 }
916out:
917 mutex_unlock(&devlink_mutex);
918
919 cb->args[0] = idx;
920 return msg->len;
921}
922
923static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
924 struct devlink_sb *devlink_sb,
925 u16 pool_index, enum devlink_command cmd,
926 u32 portid, u32 seq, int flags)
927{
928 struct devlink_sb_pool_info pool_info;
929 void *hdr;
930 int err;
931
932 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
933 pool_index, &pool_info);
934 if (err)
935 return err;
936
937 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
938 if (!hdr)
939 return -EMSGSIZE;
940
941 if (devlink_nl_put_handle(msg, devlink))
942 goto nla_put_failure;
943 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
944 goto nla_put_failure;
945 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
946 goto nla_put_failure;
947 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
948 goto nla_put_failure;
949 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
950 goto nla_put_failure;
951 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
952 pool_info.threshold_type))
953 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -0800954 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
955 pool_info.cell_size))
956 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +0200957
958 genlmsg_end(msg, hdr);
959 return 0;
960
961nla_put_failure:
962 genlmsg_cancel(msg, hdr);
963 return -EMSGSIZE;
964}
965
966static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
967 struct genl_info *info)
968{
969 struct devlink *devlink = info->user_ptr[0];
970 struct devlink_sb *devlink_sb = info->user_ptr[1];
971 struct sk_buff *msg;
972 u16 pool_index;
973 int err;
974
975 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
976 &pool_index);
977 if (err)
978 return err;
979
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800980 if (!devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +0200981 return -EOPNOTSUPP;
982
983 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
984 if (!msg)
985 return -ENOMEM;
986
987 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
988 DEVLINK_CMD_SB_POOL_NEW,
989 info->snd_portid, info->snd_seq, 0);
990 if (err) {
991 nlmsg_free(msg);
992 return err;
993 }
994
995 return genlmsg_reply(msg, info);
996}
997
998static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
999 struct devlink *devlink,
1000 struct devlink_sb *devlink_sb,
1001 u32 portid, u32 seq)
1002{
1003 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1004 u16 pool_index;
1005 int err;
1006
1007 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1008 if (*p_idx < start) {
1009 (*p_idx)++;
1010 continue;
1011 }
1012 err = devlink_nl_sb_pool_fill(msg, devlink,
1013 devlink_sb,
1014 pool_index,
1015 DEVLINK_CMD_SB_POOL_NEW,
1016 portid, seq, NLM_F_MULTI);
1017 if (err)
1018 return err;
1019 (*p_idx)++;
1020 }
1021 return 0;
1022}
1023
1024static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1025 struct netlink_callback *cb)
1026{
1027 struct devlink *devlink;
1028 struct devlink_sb *devlink_sb;
1029 int start = cb->args[0];
1030 int idx = 0;
1031 int err;
1032
1033 mutex_lock(&devlink_mutex);
1034 list_for_each_entry(devlink, &devlink_list, list) {
1035 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001036 !devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001037 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001038 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001039 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1040 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1041 devlink_sb,
1042 NETLINK_CB(cb->skb).portid,
1043 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001044 if (err && err != -EOPNOTSUPP) {
1045 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001046 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001047 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001048 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001049 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001050 }
1051out:
1052 mutex_unlock(&devlink_mutex);
1053
1054 cb->args[0] = idx;
1055 return msg->len;
1056}
1057
1058static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1059 u16 pool_index, u32 size,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001060 enum devlink_sb_threshold_type threshold_type,
1061 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001062
1063{
1064 const struct devlink_ops *ops = devlink->ops;
1065
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001066 if (ops->sb_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001067 return ops->sb_pool_set(devlink, sb_index, pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001068 size, threshold_type, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001069 return -EOPNOTSUPP;
1070}
1071
1072static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1073 struct genl_info *info)
1074{
1075 struct devlink *devlink = info->user_ptr[0];
1076 struct devlink_sb *devlink_sb = info->user_ptr[1];
1077 enum devlink_sb_threshold_type threshold_type;
1078 u16 pool_index;
1079 u32 size;
1080 int err;
1081
1082 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1083 &pool_index);
1084 if (err)
1085 return err;
1086
1087 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1088 if (err)
1089 return err;
1090
1091 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1092 return -EINVAL;
1093
1094 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1095 return devlink_sb_pool_set(devlink, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001096 pool_index, size, threshold_type,
1097 info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001098}
1099
1100static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1101 struct devlink *devlink,
1102 struct devlink_port *devlink_port,
1103 struct devlink_sb *devlink_sb,
1104 u16 pool_index,
1105 enum devlink_command cmd,
1106 u32 portid, u32 seq, int flags)
1107{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001108 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001109 u32 threshold;
1110 void *hdr;
1111 int err;
1112
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001113 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1114 pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001115 if (err)
1116 return err;
1117
1118 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1119 if (!hdr)
1120 return -EMSGSIZE;
1121
1122 if (devlink_nl_put_handle(msg, devlink))
1123 goto nla_put_failure;
1124 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1125 goto nla_put_failure;
1126 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1127 goto nla_put_failure;
1128 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1129 goto nla_put_failure;
1130 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1131 goto nla_put_failure;
1132
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001133 if (ops->sb_occ_port_pool_get) {
1134 u32 cur;
1135 u32 max;
1136
1137 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1138 pool_index, &cur, &max);
1139 if (err && err != -EOPNOTSUPP)
1140 return err;
1141 if (!err) {
1142 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1143 goto nla_put_failure;
1144 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1145 goto nla_put_failure;
1146 }
1147 }
1148
Jiri Pirkobf797472016-04-14 18:19:13 +02001149 genlmsg_end(msg, hdr);
1150 return 0;
1151
1152nla_put_failure:
1153 genlmsg_cancel(msg, hdr);
1154 return -EMSGSIZE;
1155}
1156
1157static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1158 struct genl_info *info)
1159{
1160 struct devlink_port *devlink_port = info->user_ptr[0];
1161 struct devlink *devlink = devlink_port->devlink;
1162 struct devlink_sb *devlink_sb = info->user_ptr[1];
1163 struct sk_buff *msg;
1164 u16 pool_index;
1165 int err;
1166
1167 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1168 &pool_index);
1169 if (err)
1170 return err;
1171
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001172 if (!devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001173 return -EOPNOTSUPP;
1174
1175 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1176 if (!msg)
1177 return -ENOMEM;
1178
1179 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1180 devlink_sb, pool_index,
1181 DEVLINK_CMD_SB_PORT_POOL_NEW,
1182 info->snd_portid, info->snd_seq, 0);
1183 if (err) {
1184 nlmsg_free(msg);
1185 return err;
1186 }
1187
1188 return genlmsg_reply(msg, info);
1189}
1190
1191static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1192 struct devlink *devlink,
1193 struct devlink_sb *devlink_sb,
1194 u32 portid, u32 seq)
1195{
1196 struct devlink_port *devlink_port;
1197 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1198 u16 pool_index;
1199 int err;
1200
1201 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1202 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1203 if (*p_idx < start) {
1204 (*p_idx)++;
1205 continue;
1206 }
1207 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1208 devlink_port,
1209 devlink_sb,
1210 pool_index,
1211 DEVLINK_CMD_SB_PORT_POOL_NEW,
1212 portid, seq,
1213 NLM_F_MULTI);
1214 if (err)
1215 return err;
1216 (*p_idx)++;
1217 }
1218 }
1219 return 0;
1220}
1221
1222static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1223 struct netlink_callback *cb)
1224{
1225 struct devlink *devlink;
1226 struct devlink_sb *devlink_sb;
1227 int start = cb->args[0];
1228 int idx = 0;
1229 int err;
1230
1231 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001232 list_for_each_entry(devlink, &devlink_list, list) {
1233 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001234 !devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001235 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001236 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001237 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1238 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1239 devlink, devlink_sb,
1240 NETLINK_CB(cb->skb).portid,
1241 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001242 if (err && err != -EOPNOTSUPP) {
1243 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001244 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001245 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001246 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001247 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001248 }
1249out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001250 mutex_unlock(&devlink_mutex);
1251
1252 cb->args[0] = idx;
1253 return msg->len;
1254}
1255
1256static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1257 unsigned int sb_index, u16 pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001258 u32 threshold,
1259 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001260
1261{
1262 const struct devlink_ops *ops = devlink_port->devlink->ops;
1263
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001264 if (ops->sb_port_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001265 return ops->sb_port_pool_set(devlink_port, sb_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001266 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001267 return -EOPNOTSUPP;
1268}
1269
1270static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1271 struct genl_info *info)
1272{
1273 struct devlink_port *devlink_port = info->user_ptr[0];
1274 struct devlink_sb *devlink_sb = info->user_ptr[1];
1275 u16 pool_index;
1276 u32 threshold;
1277 int err;
1278
1279 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1280 &pool_index);
1281 if (err)
1282 return err;
1283
1284 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1285 return -EINVAL;
1286
1287 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1288 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001289 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001290}
1291
1292static int
1293devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1294 struct devlink_port *devlink_port,
1295 struct devlink_sb *devlink_sb, u16 tc_index,
1296 enum devlink_sb_pool_type pool_type,
1297 enum devlink_command cmd,
1298 u32 portid, u32 seq, int flags)
1299{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001300 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001301 u16 pool_index;
1302 u32 threshold;
1303 void *hdr;
1304 int err;
1305
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001306 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1307 tc_index, pool_type,
1308 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001309 if (err)
1310 return err;
1311
1312 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1313 if (!hdr)
1314 return -EMSGSIZE;
1315
1316 if (devlink_nl_put_handle(msg, devlink))
1317 goto nla_put_failure;
1318 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1319 goto nla_put_failure;
1320 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1321 goto nla_put_failure;
1322 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1323 goto nla_put_failure;
1324 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1325 goto nla_put_failure;
1326 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1327 goto nla_put_failure;
1328 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1329 goto nla_put_failure;
1330
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001331 if (ops->sb_occ_tc_port_bind_get) {
1332 u32 cur;
1333 u32 max;
1334
1335 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1336 devlink_sb->index,
1337 tc_index, pool_type,
1338 &cur, &max);
1339 if (err && err != -EOPNOTSUPP)
1340 return err;
1341 if (!err) {
1342 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1343 goto nla_put_failure;
1344 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1345 goto nla_put_failure;
1346 }
1347 }
1348
Jiri Pirkobf797472016-04-14 18:19:13 +02001349 genlmsg_end(msg, hdr);
1350 return 0;
1351
1352nla_put_failure:
1353 genlmsg_cancel(msg, hdr);
1354 return -EMSGSIZE;
1355}
1356
1357static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1358 struct genl_info *info)
1359{
1360 struct devlink_port *devlink_port = info->user_ptr[0];
1361 struct devlink *devlink = devlink_port->devlink;
1362 struct devlink_sb *devlink_sb = info->user_ptr[1];
1363 struct sk_buff *msg;
1364 enum devlink_sb_pool_type pool_type;
1365 u16 tc_index;
1366 int err;
1367
1368 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1369 if (err)
1370 return err;
1371
1372 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1373 pool_type, &tc_index);
1374 if (err)
1375 return err;
1376
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001377 if (!devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001378 return -EOPNOTSUPP;
1379
1380 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1381 if (!msg)
1382 return -ENOMEM;
1383
1384 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1385 devlink_sb, tc_index, pool_type,
1386 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1387 info->snd_portid,
1388 info->snd_seq, 0);
1389 if (err) {
1390 nlmsg_free(msg);
1391 return err;
1392 }
1393
1394 return genlmsg_reply(msg, info);
1395}
1396
1397static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1398 int start, int *p_idx,
1399 struct devlink *devlink,
1400 struct devlink_sb *devlink_sb,
1401 u32 portid, u32 seq)
1402{
1403 struct devlink_port *devlink_port;
1404 u16 tc_index;
1405 int err;
1406
1407 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1408 for (tc_index = 0;
1409 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1410 if (*p_idx < start) {
1411 (*p_idx)++;
1412 continue;
1413 }
1414 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1415 devlink_port,
1416 devlink_sb,
1417 tc_index,
1418 DEVLINK_SB_POOL_TYPE_INGRESS,
1419 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1420 portid, seq,
1421 NLM_F_MULTI);
1422 if (err)
1423 return err;
1424 (*p_idx)++;
1425 }
1426 for (tc_index = 0;
1427 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1428 if (*p_idx < start) {
1429 (*p_idx)++;
1430 continue;
1431 }
1432 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1433 devlink_port,
1434 devlink_sb,
1435 tc_index,
1436 DEVLINK_SB_POOL_TYPE_EGRESS,
1437 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1438 portid, seq,
1439 NLM_F_MULTI);
1440 if (err)
1441 return err;
1442 (*p_idx)++;
1443 }
1444 }
1445 return 0;
1446}
1447
1448static int
1449devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1450 struct netlink_callback *cb)
1451{
1452 struct devlink *devlink;
1453 struct devlink_sb *devlink_sb;
1454 int start = cb->args[0];
1455 int idx = 0;
1456 int err;
1457
1458 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001459 list_for_each_entry(devlink, &devlink_list, list) {
1460 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001461 !devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001462 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001463
1464 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001465 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1466 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1467 devlink,
1468 devlink_sb,
1469 NETLINK_CB(cb->skb).portid,
1470 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001471 if (err && err != -EOPNOTSUPP) {
1472 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001473 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001474 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001475 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001476 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001477 }
1478out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001479 mutex_unlock(&devlink_mutex);
1480
1481 cb->args[0] = idx;
1482 return msg->len;
1483}
1484
1485static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1486 unsigned int sb_index, u16 tc_index,
1487 enum devlink_sb_pool_type pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001488 u16 pool_index, u32 threshold,
1489 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001490
1491{
1492 const struct devlink_ops *ops = devlink_port->devlink->ops;
1493
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001494 if (ops->sb_tc_pool_bind_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001495 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1496 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001497 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001498 return -EOPNOTSUPP;
1499}
1500
1501static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1502 struct genl_info *info)
1503{
1504 struct devlink_port *devlink_port = info->user_ptr[0];
1505 struct devlink_sb *devlink_sb = info->user_ptr[1];
1506 enum devlink_sb_pool_type pool_type;
1507 u16 tc_index;
1508 u16 pool_index;
1509 u32 threshold;
1510 int err;
1511
1512 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1513 if (err)
1514 return err;
1515
1516 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1517 pool_type, &tc_index);
1518 if (err)
1519 return err;
1520
1521 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1522 &pool_index);
1523 if (err)
1524 return err;
1525
1526 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1527 return -EINVAL;
1528
1529 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1530 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1531 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001532 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001533}
1534
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001535static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1536 struct genl_info *info)
1537{
1538 struct devlink *devlink = info->user_ptr[0];
1539 struct devlink_sb *devlink_sb = info->user_ptr[1];
1540 const struct devlink_ops *ops = devlink->ops;
1541
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001542 if (ops->sb_occ_snapshot)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001543 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1544 return -EOPNOTSUPP;
1545}
1546
1547static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1548 struct genl_info *info)
1549{
1550 struct devlink *devlink = info->user_ptr[0];
1551 struct devlink_sb *devlink_sb = info->user_ptr[1];
1552 const struct devlink_ops *ops = devlink->ops;
1553
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001554 if (ops->sb_occ_max_clear)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001555 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1556 return -EOPNOTSUPP;
1557}
1558
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001559static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1560 enum devlink_command cmd, u32 portid,
1561 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001562{
Roi Dayan59bfde02016-11-22 23:09:57 +02001563 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001564 enum devlink_eswitch_encap_mode encap_mode;
1565 u8 inline_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001566 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001567 int err = 0;
1568 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001569
1570 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1571 if (!hdr)
1572 return -EMSGSIZE;
1573
Roi Dayan59bfde02016-11-22 23:09:57 +02001574 err = devlink_nl_put_handle(msg, devlink);
1575 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001576 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001577
Jiri Pirko4456f612017-02-09 15:54:36 +01001578 if (ops->eswitch_mode_get) {
1579 err = ops->eswitch_mode_get(devlink, &mode);
1580 if (err)
1581 goto nla_put_failure;
1582 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1583 if (err)
1584 goto nla_put_failure;
1585 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001586
1587 if (ops->eswitch_inline_mode_get) {
1588 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1589 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001590 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001591 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1592 inline_mode);
1593 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001594 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001595 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001596
Roi Dayanf43e9b02016-09-25 13:52:44 +03001597 if (ops->eswitch_encap_mode_get) {
1598 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1599 if (err)
1600 goto nla_put_failure;
1601 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1602 if (err)
1603 goto nla_put_failure;
1604 }
1605
Or Gerlitz08f4b592016-07-01 14:51:01 +03001606 genlmsg_end(msg, hdr);
1607 return 0;
1608
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001609nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001610 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001611 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001612}
1613
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001614static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1615 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001616{
1617 struct devlink *devlink = info->user_ptr[0];
Or Gerlitz08f4b592016-07-01 14:51:01 +03001618 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001619 int err;
1620
Or Gerlitz08f4b592016-07-01 14:51:01 +03001621 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1622 if (!msg)
1623 return -ENOMEM;
1624
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001625 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1626 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001627
1628 if (err) {
1629 nlmsg_free(msg);
1630 return err;
1631 }
1632
1633 return genlmsg_reply(msg, info);
1634}
1635
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001636static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1637 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001638{
1639 struct devlink *devlink = info->user_ptr[0];
1640 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001641 enum devlink_eswitch_encap_mode encap_mode;
1642 u8 inline_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001643 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001644 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001645
Roi Dayan59bfde02016-11-22 23:09:57 +02001646 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1647 if (!ops->eswitch_mode_set)
1648 return -EOPNOTSUPP;
1649 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001650 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001651 if (err)
1652 return err;
1653 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001654
Roi Dayan59bfde02016-11-22 23:09:57 +02001655 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1656 if (!ops->eswitch_inline_mode_set)
1657 return -EOPNOTSUPP;
1658 inline_mode = nla_get_u8(
1659 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001660 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1661 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001662 if (err)
1663 return err;
1664 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03001665
1666 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1667 if (!ops->eswitch_encap_mode_set)
1668 return -EOPNOTSUPP;
1669 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001670 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1671 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03001672 if (err)
1673 return err;
1674 }
1675
Roi Dayan59bfde02016-11-22 23:09:57 +02001676 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001677}
1678
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001679int devlink_dpipe_match_put(struct sk_buff *skb,
1680 struct devlink_dpipe_match *match)
1681{
1682 struct devlink_dpipe_header *header = match->header;
1683 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1684 struct nlattr *match_attr;
1685
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001686 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001687 if (!match_attr)
1688 return -EMSGSIZE;
1689
1690 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1691 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1692 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1693 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1694 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1695 goto nla_put_failure;
1696
1697 nla_nest_end(skb, match_attr);
1698 return 0;
1699
1700nla_put_failure:
1701 nla_nest_cancel(skb, match_attr);
1702 return -EMSGSIZE;
1703}
1704EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1705
1706static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1707 struct sk_buff *skb)
1708{
1709 struct nlattr *matches_attr;
1710
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001711 matches_attr = nla_nest_start_noflag(skb,
1712 DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001713 if (!matches_attr)
1714 return -EMSGSIZE;
1715
1716 if (table->table_ops->matches_dump(table->priv, skb))
1717 goto nla_put_failure;
1718
1719 nla_nest_end(skb, matches_attr);
1720 return 0;
1721
1722nla_put_failure:
1723 nla_nest_cancel(skb, matches_attr);
1724 return -EMSGSIZE;
1725}
1726
1727int devlink_dpipe_action_put(struct sk_buff *skb,
1728 struct devlink_dpipe_action *action)
1729{
1730 struct devlink_dpipe_header *header = action->header;
1731 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1732 struct nlattr *action_attr;
1733
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001734 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001735 if (!action_attr)
1736 return -EMSGSIZE;
1737
1738 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1739 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1740 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1741 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1742 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1743 goto nla_put_failure;
1744
1745 nla_nest_end(skb, action_attr);
1746 return 0;
1747
1748nla_put_failure:
1749 nla_nest_cancel(skb, action_attr);
1750 return -EMSGSIZE;
1751}
1752EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1753
1754static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1755 struct sk_buff *skb)
1756{
1757 struct nlattr *actions_attr;
1758
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001759 actions_attr = nla_nest_start_noflag(skb,
1760 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001761 if (!actions_attr)
1762 return -EMSGSIZE;
1763
1764 if (table->table_ops->actions_dump(table->priv, skb))
1765 goto nla_put_failure;
1766
1767 nla_nest_end(skb, actions_attr);
1768 return 0;
1769
1770nla_put_failure:
1771 nla_nest_cancel(skb, actions_attr);
1772 return -EMSGSIZE;
1773}
1774
1775static int devlink_dpipe_table_put(struct sk_buff *skb,
1776 struct devlink_dpipe_table *table)
1777{
1778 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001779 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001780
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001781 table_size = table->table_ops->size_get(table->priv);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001782 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001783 if (!table_attr)
1784 return -EMSGSIZE;
1785
1786 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001787 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001788 DEVLINK_ATTR_PAD))
1789 goto nla_put_failure;
1790 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1791 table->counters_enabled))
1792 goto nla_put_failure;
1793
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001794 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02001795 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1796 table->resource_id, DEVLINK_ATTR_PAD) ||
1797 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1798 table->resource_units, DEVLINK_ATTR_PAD))
1799 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001800 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001801 if (devlink_dpipe_matches_put(table, skb))
1802 goto nla_put_failure;
1803
1804 if (devlink_dpipe_actions_put(table, skb))
1805 goto nla_put_failure;
1806
1807 nla_nest_end(skb, table_attr);
1808 return 0;
1809
1810nla_put_failure:
1811 nla_nest_cancel(skb, table_attr);
1812 return -EMSGSIZE;
1813}
1814
1815static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1816 struct genl_info *info)
1817{
1818 int err;
1819
1820 if (*pskb) {
1821 err = genlmsg_reply(*pskb, info);
1822 if (err)
1823 return err;
1824 }
1825 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1826 if (!*pskb)
1827 return -ENOMEM;
1828 return 0;
1829}
1830
1831static int devlink_dpipe_tables_fill(struct genl_info *info,
1832 enum devlink_command cmd, int flags,
1833 struct list_head *dpipe_tables,
1834 const char *table_name)
1835{
1836 struct devlink *devlink = info->user_ptr[0];
1837 struct devlink_dpipe_table *table;
1838 struct nlattr *tables_attr;
1839 struct sk_buff *skb = NULL;
1840 struct nlmsghdr *nlh;
1841 bool incomplete;
1842 void *hdr;
1843 int i;
1844 int err;
1845
1846 table = list_first_entry(dpipe_tables,
1847 struct devlink_dpipe_table, list);
1848start_again:
1849 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1850 if (err)
1851 return err;
1852
1853 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1854 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08001855 if (!hdr) {
1856 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001857 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08001858 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001859
1860 if (devlink_nl_put_handle(skb, devlink))
1861 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001862 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001863 if (!tables_attr)
1864 goto nla_put_failure;
1865
1866 i = 0;
1867 incomplete = false;
1868 list_for_each_entry_from(table, dpipe_tables, list) {
1869 if (!table_name) {
1870 err = devlink_dpipe_table_put(skb, table);
1871 if (err) {
1872 if (!i)
1873 goto err_table_put;
1874 incomplete = true;
1875 break;
1876 }
1877 } else {
1878 if (!strcmp(table->name, table_name)) {
1879 err = devlink_dpipe_table_put(skb, table);
1880 if (err)
1881 break;
1882 }
1883 }
1884 i++;
1885 }
1886
1887 nla_nest_end(skb, tables_attr);
1888 genlmsg_end(skb, hdr);
1889 if (incomplete)
1890 goto start_again;
1891
1892send_done:
1893 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1894 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1895 if (!nlh) {
1896 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1897 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02001898 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001899 goto send_done;
1900 }
1901
1902 return genlmsg_reply(skb, info);
1903
1904nla_put_failure:
1905 err = -EMSGSIZE;
1906err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001907 nlmsg_free(skb);
1908 return err;
1909}
1910
1911static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
1912 struct genl_info *info)
1913{
1914 struct devlink *devlink = info->user_ptr[0];
1915 const char *table_name = NULL;
1916
1917 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
1918 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
1919
1920 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
1921 &devlink->dpipe_table_list,
1922 table_name);
1923}
1924
1925static int devlink_dpipe_value_put(struct sk_buff *skb,
1926 struct devlink_dpipe_value *value)
1927{
1928 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
1929 value->value_size, value->value))
1930 return -EMSGSIZE;
1931 if (value->mask)
1932 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
1933 value->value_size, value->mask))
1934 return -EMSGSIZE;
1935 if (value->mapping_valid)
1936 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
1937 value->mapping_value))
1938 return -EMSGSIZE;
1939 return 0;
1940}
1941
1942static int devlink_dpipe_action_value_put(struct sk_buff *skb,
1943 struct devlink_dpipe_value *value)
1944{
1945 if (!value->action)
1946 return -EINVAL;
1947 if (devlink_dpipe_action_put(skb, value->action))
1948 return -EMSGSIZE;
1949 if (devlink_dpipe_value_put(skb, value))
1950 return -EMSGSIZE;
1951 return 0;
1952}
1953
1954static int devlink_dpipe_action_values_put(struct sk_buff *skb,
1955 struct devlink_dpipe_value *values,
1956 unsigned int values_count)
1957{
1958 struct nlattr *action_attr;
1959 int i;
1960 int err;
1961
1962 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001963 action_attr = nla_nest_start_noflag(skb,
1964 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001965 if (!action_attr)
1966 return -EMSGSIZE;
1967 err = devlink_dpipe_action_value_put(skb, &values[i]);
1968 if (err)
1969 goto err_action_value_put;
1970 nla_nest_end(skb, action_attr);
1971 }
1972 return 0;
1973
1974err_action_value_put:
1975 nla_nest_cancel(skb, action_attr);
1976 return err;
1977}
1978
1979static int devlink_dpipe_match_value_put(struct sk_buff *skb,
1980 struct devlink_dpipe_value *value)
1981{
1982 if (!value->match)
1983 return -EINVAL;
1984 if (devlink_dpipe_match_put(skb, value->match))
1985 return -EMSGSIZE;
1986 if (devlink_dpipe_value_put(skb, value))
1987 return -EMSGSIZE;
1988 return 0;
1989}
1990
1991static int devlink_dpipe_match_values_put(struct sk_buff *skb,
1992 struct devlink_dpipe_value *values,
1993 unsigned int values_count)
1994{
1995 struct nlattr *match_attr;
1996 int i;
1997 int err;
1998
1999 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002000 match_attr = nla_nest_start_noflag(skb,
2001 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002002 if (!match_attr)
2003 return -EMSGSIZE;
2004 err = devlink_dpipe_match_value_put(skb, &values[i]);
2005 if (err)
2006 goto err_match_value_put;
2007 nla_nest_end(skb, match_attr);
2008 }
2009 return 0;
2010
2011err_match_value_put:
2012 nla_nest_cancel(skb, match_attr);
2013 return err;
2014}
2015
2016static int devlink_dpipe_entry_put(struct sk_buff *skb,
2017 struct devlink_dpipe_entry *entry)
2018{
2019 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2020 int err;
2021
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002022 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002023 if (!entry_attr)
2024 return -EMSGSIZE;
2025
2026 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2027 DEVLINK_ATTR_PAD))
2028 goto nla_put_failure;
2029 if (entry->counter_valid)
2030 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2031 entry->counter, DEVLINK_ATTR_PAD))
2032 goto nla_put_failure;
2033
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002034 matches_attr = nla_nest_start_noflag(skb,
2035 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002036 if (!matches_attr)
2037 goto nla_put_failure;
2038
2039 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2040 entry->match_values_count);
2041 if (err) {
2042 nla_nest_cancel(skb, matches_attr);
2043 goto err_match_values_put;
2044 }
2045 nla_nest_end(skb, matches_attr);
2046
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002047 actions_attr = nla_nest_start_noflag(skb,
2048 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002049 if (!actions_attr)
2050 goto nla_put_failure;
2051
2052 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2053 entry->action_values_count);
2054 if (err) {
2055 nla_nest_cancel(skb, actions_attr);
2056 goto err_action_values_put;
2057 }
2058 nla_nest_end(skb, actions_attr);
2059
2060 nla_nest_end(skb, entry_attr);
2061 return 0;
2062
2063nla_put_failure:
2064 err = -EMSGSIZE;
2065err_match_values_put:
2066err_action_values_put:
2067 nla_nest_cancel(skb, entry_attr);
2068 return err;
2069}
2070
2071static struct devlink_dpipe_table *
2072devlink_dpipe_table_find(struct list_head *dpipe_tables,
2073 const char *table_name)
2074{
2075 struct devlink_dpipe_table *table;
2076
2077 list_for_each_entry_rcu(table, dpipe_tables, list) {
2078 if (!strcmp(table->name, table_name))
2079 return table;
2080 }
2081 return NULL;
2082}
2083
2084int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2085{
2086 struct devlink *devlink;
2087 int err;
2088
2089 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2090 dump_ctx->info);
2091 if (err)
2092 return err;
2093
2094 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2095 dump_ctx->info->snd_portid,
2096 dump_ctx->info->snd_seq,
2097 &devlink_nl_family, NLM_F_MULTI,
2098 dump_ctx->cmd);
2099 if (!dump_ctx->hdr)
2100 goto nla_put_failure;
2101
2102 devlink = dump_ctx->info->user_ptr[0];
2103 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2104 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002105 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2106 DEVLINK_ATTR_DPIPE_ENTRIES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002107 if (!dump_ctx->nest)
2108 goto nla_put_failure;
2109 return 0;
2110
2111nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002112 nlmsg_free(dump_ctx->skb);
2113 return -EMSGSIZE;
2114}
2115EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2116
2117int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2118 struct devlink_dpipe_entry *entry)
2119{
2120 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2121}
2122EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2123
2124int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2125{
2126 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2127 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2128 return 0;
2129}
2130EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2131
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002132void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2133
2134{
2135 unsigned int value_count, value_index;
2136 struct devlink_dpipe_value *value;
2137
2138 value = entry->action_values;
2139 value_count = entry->action_values_count;
2140 for (value_index = 0; value_index < value_count; value_index++) {
2141 kfree(value[value_index].value);
2142 kfree(value[value_index].mask);
2143 }
2144
2145 value = entry->match_values;
2146 value_count = entry->match_values_count;
2147 for (value_index = 0; value_index < value_count; value_index++) {
2148 kfree(value[value_index].value);
2149 kfree(value[value_index].mask);
2150 }
2151}
2152EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2153
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002154static int devlink_dpipe_entries_fill(struct genl_info *info,
2155 enum devlink_command cmd, int flags,
2156 struct devlink_dpipe_table *table)
2157{
2158 struct devlink_dpipe_dump_ctx dump_ctx;
2159 struct nlmsghdr *nlh;
2160 int err;
2161
2162 dump_ctx.skb = NULL;
2163 dump_ctx.cmd = cmd;
2164 dump_ctx.info = info;
2165
2166 err = table->table_ops->entries_dump(table->priv,
2167 table->counters_enabled,
2168 &dump_ctx);
2169 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002170 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002171
2172send_done:
2173 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2174 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2175 if (!nlh) {
2176 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2177 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002178 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002179 goto send_done;
2180 }
2181 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002182}
2183
2184static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2185 struct genl_info *info)
2186{
2187 struct devlink *devlink = info->user_ptr[0];
2188 struct devlink_dpipe_table *table;
2189 const char *table_name;
2190
2191 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2192 return -EINVAL;
2193
2194 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2195 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2196 table_name);
2197 if (!table)
2198 return -EINVAL;
2199
2200 if (!table->table_ops->entries_dump)
2201 return -EINVAL;
2202
2203 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2204 0, table);
2205}
2206
2207static int devlink_dpipe_fields_put(struct sk_buff *skb,
2208 const struct devlink_dpipe_header *header)
2209{
2210 struct devlink_dpipe_field *field;
2211 struct nlattr *field_attr;
2212 int i;
2213
2214 for (i = 0; i < header->fields_count; i++) {
2215 field = &header->fields[i];
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002216 field_attr = nla_nest_start_noflag(skb,
2217 DEVLINK_ATTR_DPIPE_FIELD);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002218 if (!field_attr)
2219 return -EMSGSIZE;
2220 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2221 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2222 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2223 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2224 goto nla_put_failure;
2225 nla_nest_end(skb, field_attr);
2226 }
2227 return 0;
2228
2229nla_put_failure:
2230 nla_nest_cancel(skb, field_attr);
2231 return -EMSGSIZE;
2232}
2233
2234static int devlink_dpipe_header_put(struct sk_buff *skb,
2235 struct devlink_dpipe_header *header)
2236{
2237 struct nlattr *fields_attr, *header_attr;
2238 int err;
2239
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002240 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002241 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002242 return -EMSGSIZE;
2243
2244 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2245 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2246 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2247 goto nla_put_failure;
2248
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002249 fields_attr = nla_nest_start_noflag(skb,
2250 DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002251 if (!fields_attr)
2252 goto nla_put_failure;
2253
2254 err = devlink_dpipe_fields_put(skb, header);
2255 if (err) {
2256 nla_nest_cancel(skb, fields_attr);
2257 goto nla_put_failure;
2258 }
2259 nla_nest_end(skb, fields_attr);
2260 nla_nest_end(skb, header_attr);
2261 return 0;
2262
2263nla_put_failure:
2264 err = -EMSGSIZE;
2265 nla_nest_cancel(skb, header_attr);
2266 return err;
2267}
2268
2269static int devlink_dpipe_headers_fill(struct genl_info *info,
2270 enum devlink_command cmd, int flags,
2271 struct devlink_dpipe_headers *
2272 dpipe_headers)
2273{
2274 struct devlink *devlink = info->user_ptr[0];
2275 struct nlattr *headers_attr;
2276 struct sk_buff *skb = NULL;
2277 struct nlmsghdr *nlh;
2278 void *hdr;
2279 int i, j;
2280 int err;
2281
2282 i = 0;
2283start_again:
2284 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2285 if (err)
2286 return err;
2287
2288 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2289 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002290 if (!hdr) {
2291 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002292 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002293 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002294
2295 if (devlink_nl_put_handle(skb, devlink))
2296 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002297 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002298 if (!headers_attr)
2299 goto nla_put_failure;
2300
2301 j = 0;
2302 for (; i < dpipe_headers->headers_count; i++) {
2303 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2304 if (err) {
2305 if (!j)
2306 goto err_table_put;
2307 break;
2308 }
2309 j++;
2310 }
2311 nla_nest_end(skb, headers_attr);
2312 genlmsg_end(skb, hdr);
2313 if (i != dpipe_headers->headers_count)
2314 goto start_again;
2315
2316send_done:
2317 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2318 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2319 if (!nlh) {
2320 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2321 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002322 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002323 goto send_done;
2324 }
2325 return genlmsg_reply(skb, info);
2326
2327nla_put_failure:
2328 err = -EMSGSIZE;
2329err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002330 nlmsg_free(skb);
2331 return err;
2332}
2333
2334static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2335 struct genl_info *info)
2336{
2337 struct devlink *devlink = info->user_ptr[0];
2338
2339 if (!devlink->dpipe_headers)
2340 return -EOPNOTSUPP;
2341 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2342 0, devlink->dpipe_headers);
2343}
2344
2345static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2346 const char *table_name,
2347 bool enable)
2348{
2349 struct devlink_dpipe_table *table;
2350
2351 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2352 table_name);
2353 if (!table)
2354 return -EINVAL;
2355
2356 if (table->counter_control_extern)
2357 return -EOPNOTSUPP;
2358
2359 if (!(table->counters_enabled ^ enable))
2360 return 0;
2361
2362 table->counters_enabled = enable;
2363 if (table->table_ops->counters_set_update)
2364 table->table_ops->counters_set_update(table->priv, enable);
2365 return 0;
2366}
2367
2368static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2369 struct genl_info *info)
2370{
2371 struct devlink *devlink = info->user_ptr[0];
2372 const char *table_name;
2373 bool counters_enable;
2374
2375 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2376 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2377 return -EINVAL;
2378
2379 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2380 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2381
2382 return devlink_dpipe_table_counters_set(devlink, table_name,
2383 counters_enable);
2384}
2385
Wei Yongjun43dd7512018-01-17 03:27:42 +00002386static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002387devlink_resource_find(struct devlink *devlink,
2388 struct devlink_resource *resource, u64 resource_id)
2389{
2390 struct list_head *resource_list;
2391
2392 if (resource)
2393 resource_list = &resource->resource_list;
2394 else
2395 resource_list = &devlink->resource_list;
2396
2397 list_for_each_entry(resource, resource_list, list) {
2398 struct devlink_resource *child_resource;
2399
2400 if (resource->id == resource_id)
2401 return resource;
2402
2403 child_resource = devlink_resource_find(devlink, resource,
2404 resource_id);
2405 if (child_resource)
2406 return child_resource;
2407 }
2408 return NULL;
2409}
2410
Wei Yongjun43dd7512018-01-17 03:27:42 +00002411static void
2412devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002413{
2414 struct devlink_resource *child_resource;
2415 bool size_valid = true;
2416 u64 parts_size = 0;
2417
2418 if (list_empty(&resource->resource_list))
2419 goto out;
2420
2421 list_for_each_entry(child_resource, &resource->resource_list, list)
2422 parts_size += child_resource->size_new;
2423
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002424 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002425 size_valid = false;
2426out:
2427 resource->size_valid = size_valid;
2428}
2429
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002430static int
2431devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2432 struct netlink_ext_ack *extack)
2433{
2434 u64 reminder;
2435 int err = 0;
2436
David S. Miller0f3e9c92018-03-06 00:53:44 -05002437 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002438 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2439 err = -EINVAL;
2440 }
2441
David S. Miller0f3e9c92018-03-06 00:53:44 -05002442 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002443 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2444 err = -EINVAL;
2445 }
2446
David S. Miller0f3e9c92018-03-06 00:53:44 -05002447 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002448 if (reminder) {
2449 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2450 err = -EINVAL;
2451 }
2452
2453 return err;
2454}
2455
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002456static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2457 struct genl_info *info)
2458{
2459 struct devlink *devlink = info->user_ptr[0];
2460 struct devlink_resource *resource;
2461 u64 resource_id;
2462 u64 size;
2463 int err;
2464
2465 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2466 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2467 return -EINVAL;
2468 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2469
2470 resource = devlink_resource_find(devlink, NULL, resource_id);
2471 if (!resource)
2472 return -EINVAL;
2473
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002474 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002475 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002476 if (err)
2477 return err;
2478
2479 resource->size_new = size;
2480 devlink_resource_validate_children(resource);
2481 if (resource->parent)
2482 devlink_resource_validate_children(resource->parent);
2483 return 0;
2484}
2485
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002486static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002487devlink_resource_size_params_put(struct devlink_resource *resource,
2488 struct sk_buff *skb)
2489{
2490 struct devlink_resource_size_params *size_params;
2491
Jiri Pirko77d27092018-02-28 13:12:09 +01002492 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002493 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2494 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2495 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2496 size_params->size_max, DEVLINK_ATTR_PAD) ||
2497 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2498 size_params->size_min, DEVLINK_ATTR_PAD) ||
2499 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2500 return -EMSGSIZE;
2501 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002502}
2503
Jiri Pirkofc56be42018-04-05 22:13:21 +02002504static int devlink_resource_occ_put(struct devlink_resource *resource,
2505 struct sk_buff *skb)
2506{
2507 if (!resource->occ_get)
2508 return 0;
2509 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2510 resource->occ_get(resource->occ_get_priv),
2511 DEVLINK_ATTR_PAD);
2512}
2513
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002514static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2515 struct devlink_resource *resource)
2516{
2517 struct devlink_resource *child_resource;
2518 struct nlattr *child_resource_attr;
2519 struct nlattr *resource_attr;
2520
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002521 resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002522 if (!resource_attr)
2523 return -EMSGSIZE;
2524
2525 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2526 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2527 DEVLINK_ATTR_PAD) ||
2528 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2529 DEVLINK_ATTR_PAD))
2530 goto nla_put_failure;
2531 if (resource->size != resource->size_new)
2532 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2533 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002534 if (devlink_resource_occ_put(resource, skb))
2535 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002536 if (devlink_resource_size_params_put(resource, skb))
2537 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002538 if (list_empty(&resource->resource_list))
2539 goto out;
2540
2541 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2542 resource->size_valid))
2543 goto nla_put_failure;
2544
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002545 child_resource_attr = nla_nest_start_noflag(skb,
2546 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002547 if (!child_resource_attr)
2548 goto nla_put_failure;
2549
2550 list_for_each_entry(child_resource, &resource->resource_list, list) {
2551 if (devlink_resource_put(devlink, skb, child_resource))
2552 goto resource_put_failure;
2553 }
2554
2555 nla_nest_end(skb, child_resource_attr);
2556out:
2557 nla_nest_end(skb, resource_attr);
2558 return 0;
2559
2560resource_put_failure:
2561 nla_nest_cancel(skb, child_resource_attr);
2562nla_put_failure:
2563 nla_nest_cancel(skb, resource_attr);
2564 return -EMSGSIZE;
2565}
2566
2567static int devlink_resource_fill(struct genl_info *info,
2568 enum devlink_command cmd, int flags)
2569{
2570 struct devlink *devlink = info->user_ptr[0];
2571 struct devlink_resource *resource;
2572 struct nlattr *resources_attr;
2573 struct sk_buff *skb = NULL;
2574 struct nlmsghdr *nlh;
2575 bool incomplete;
2576 void *hdr;
2577 int i;
2578 int err;
2579
2580 resource = list_first_entry(&devlink->resource_list,
2581 struct devlink_resource, list);
2582start_again:
2583 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2584 if (err)
2585 return err;
2586
2587 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2588 &devlink_nl_family, NLM_F_MULTI, cmd);
2589 if (!hdr) {
2590 nlmsg_free(skb);
2591 return -EMSGSIZE;
2592 }
2593
2594 if (devlink_nl_put_handle(skb, devlink))
2595 goto nla_put_failure;
2596
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002597 resources_attr = nla_nest_start_noflag(skb,
2598 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002599 if (!resources_attr)
2600 goto nla_put_failure;
2601
2602 incomplete = false;
2603 i = 0;
2604 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2605 err = devlink_resource_put(devlink, skb, resource);
2606 if (err) {
2607 if (!i)
2608 goto err_resource_put;
2609 incomplete = true;
2610 break;
2611 }
2612 i++;
2613 }
2614 nla_nest_end(skb, resources_attr);
2615 genlmsg_end(skb, hdr);
2616 if (incomplete)
2617 goto start_again;
2618send_done:
2619 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2620 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2621 if (!nlh) {
2622 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2623 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002624 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002625 goto send_done;
2626 }
2627 return genlmsg_reply(skb, info);
2628
2629nla_put_failure:
2630 err = -EMSGSIZE;
2631err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002632 nlmsg_free(skb);
2633 return err;
2634}
2635
2636static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2637 struct genl_info *info)
2638{
2639 struct devlink *devlink = info->user_ptr[0];
2640
2641 if (list_empty(&devlink->resource_list))
2642 return -EOPNOTSUPP;
2643
2644 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2645}
2646
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002647static int
2648devlink_resources_validate(struct devlink *devlink,
2649 struct devlink_resource *resource,
2650 struct genl_info *info)
2651{
2652 struct list_head *resource_list;
2653 int err = 0;
2654
2655 if (resource)
2656 resource_list = &resource->resource_list;
2657 else
2658 resource_list = &devlink->resource_list;
2659
2660 list_for_each_entry(resource, resource_list, list) {
2661 if (!resource->size_valid)
2662 return -EINVAL;
2663 err = devlink_resources_validate(devlink, resource, info);
2664 if (err)
2665 return err;
2666 }
2667 return err;
2668}
2669
2670static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2671{
2672 struct devlink *devlink = info->user_ptr[0];
2673 int err;
2674
2675 if (!devlink->ops->reload)
2676 return -EOPNOTSUPP;
2677
2678 err = devlink_resources_validate(devlink, NULL, info);
2679 if (err) {
2680 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2681 return err;
2682 }
David Ahernac0fc8a2018-06-05 08:14:09 -07002683 return devlink->ops->reload(devlink, info->extack);
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002684}
2685
Jiri Pirko191ed202019-06-04 15:40:40 +02002686static int devlink_nl_flash_update_fill(struct sk_buff *msg,
2687 struct devlink *devlink,
2688 enum devlink_command cmd,
2689 const char *status_msg,
2690 const char *component,
2691 unsigned long done, unsigned long total)
2692{
2693 void *hdr;
2694
2695 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
2696 if (!hdr)
2697 return -EMSGSIZE;
2698
2699 if (devlink_nl_put_handle(msg, devlink))
2700 goto nla_put_failure;
2701
2702 if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
2703 goto out;
2704
2705 if (status_msg &&
2706 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
2707 status_msg))
2708 goto nla_put_failure;
2709 if (component &&
2710 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
2711 component))
2712 goto nla_put_failure;
2713 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
2714 done, DEVLINK_ATTR_PAD))
2715 goto nla_put_failure;
2716 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
2717 total, DEVLINK_ATTR_PAD))
2718 goto nla_put_failure;
2719
2720out:
2721 genlmsg_end(msg, hdr);
2722 return 0;
2723
2724nla_put_failure:
2725 genlmsg_cancel(msg, hdr);
2726 return -EMSGSIZE;
2727}
2728
2729static void __devlink_flash_update_notify(struct devlink *devlink,
2730 enum devlink_command cmd,
2731 const char *status_msg,
2732 const char *component,
2733 unsigned long done,
2734 unsigned long total)
2735{
2736 struct sk_buff *msg;
2737 int err;
2738
2739 WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
2740 cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
2741 cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
2742
2743 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2744 if (!msg)
2745 return;
2746
2747 err = devlink_nl_flash_update_fill(msg, devlink, cmd, status_msg,
2748 component, done, total);
2749 if (err)
2750 goto out_free_msg;
2751
2752 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
2753 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
2754 return;
2755
2756out_free_msg:
2757 nlmsg_free(msg);
2758}
2759
2760void devlink_flash_update_begin_notify(struct devlink *devlink)
2761{
2762 __devlink_flash_update_notify(devlink,
2763 DEVLINK_CMD_FLASH_UPDATE,
2764 NULL, NULL, 0, 0);
2765}
2766EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
2767
2768void devlink_flash_update_end_notify(struct devlink *devlink)
2769{
2770 __devlink_flash_update_notify(devlink,
2771 DEVLINK_CMD_FLASH_UPDATE_END,
2772 NULL, NULL, 0, 0);
2773}
2774EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
2775
2776void devlink_flash_update_status_notify(struct devlink *devlink,
2777 const char *status_msg,
2778 const char *component,
2779 unsigned long done,
2780 unsigned long total)
2781{
2782 __devlink_flash_update_notify(devlink,
2783 DEVLINK_CMD_FLASH_UPDATE_STATUS,
2784 status_msg, component, done, total);
2785}
2786EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
2787
Jakub Kicinski76726cc2019-02-14 13:40:44 -08002788static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
2789 struct genl_info *info)
2790{
2791 struct devlink *devlink = info->user_ptr[0];
2792 const char *file_name, *component;
2793 struct nlattr *nla_component;
2794
2795 if (!devlink->ops->flash_update)
2796 return -EOPNOTSUPP;
2797
2798 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
2799 return -EINVAL;
2800 file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
2801
2802 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
2803 component = nla_component ? nla_data(nla_component) : NULL;
2804
2805 return devlink->ops->flash_update(devlink, file_name, component,
2806 info->extack);
2807}
2808
Moshe Shemesh036467c2018-07-04 14:30:33 +03002809static const struct devlink_param devlink_param_generic[] = {
2810 {
2811 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
2812 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
2813 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
2814 },
2815 {
2816 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
2817 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
2818 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
2819 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03002820 {
2821 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
2822 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
2823 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
2824 },
Alex Veskerf6a698852018-07-12 15:13:17 +03002825 {
2826 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
2827 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
2828 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
2829 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05302830 {
2831 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
2832 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
2833 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
2834 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05302835 {
2836 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
2837 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
2838 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
2839 },
Vasundhara Volam16511782018-10-04 11:13:46 +05302840 {
2841 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
2842 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
2843 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
2844 },
Shalom Toledo846e9802018-12-03 07:58:59 +00002845 {
2846 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
2847 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
2848 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
2849 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03002850};
Moshe Shemesheabaef12018-07-04 14:30:28 +03002851
2852static int devlink_param_generic_verify(const struct devlink_param *param)
2853{
2854 /* verify it match generic parameter by id and name */
2855 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
2856 return -EINVAL;
2857 if (strcmp(param->name, devlink_param_generic[param->id].name))
2858 return -ENOENT;
2859
2860 WARN_ON(param->type != devlink_param_generic[param->id].type);
2861
2862 return 0;
2863}
2864
2865static int devlink_param_driver_verify(const struct devlink_param *param)
2866{
2867 int i;
2868
2869 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
2870 return -EINVAL;
2871 /* verify no such name in generic params */
2872 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
2873 if (!strcmp(param->name, devlink_param_generic[i].name))
2874 return -EEXIST;
2875
2876 return 0;
2877}
2878
2879static struct devlink_param_item *
2880devlink_param_find_by_name(struct list_head *param_list,
2881 const char *param_name)
2882{
2883 struct devlink_param_item *param_item;
2884
2885 list_for_each_entry(param_item, param_list, list)
2886 if (!strcmp(param_item->param->name, param_name))
2887 return param_item;
2888 return NULL;
2889}
2890
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03002891static struct devlink_param_item *
2892devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
2893{
2894 struct devlink_param_item *param_item;
2895
2896 list_for_each_entry(param_item, param_list, list)
2897 if (param_item->param->id == param_id)
2898 return param_item;
2899 return NULL;
2900}
2901
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002902static bool
2903devlink_param_cmode_is_supported(const struct devlink_param *param,
2904 enum devlink_param_cmode cmode)
2905{
2906 return test_bit(cmode, &param->supported_cmodes);
2907}
2908
2909static int devlink_param_get(struct devlink *devlink,
2910 const struct devlink_param *param,
2911 struct devlink_param_gset_ctx *ctx)
2912{
2913 if (!param->get)
2914 return -EOPNOTSUPP;
2915 return param->get(devlink, param->id, ctx);
2916}
2917
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03002918static int devlink_param_set(struct devlink *devlink,
2919 const struct devlink_param *param,
2920 struct devlink_param_gset_ctx *ctx)
2921{
2922 if (!param->set)
2923 return -EOPNOTSUPP;
2924 return param->set(devlink, param->id, ctx);
2925}
2926
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002927static int
2928devlink_param_type_to_nla_type(enum devlink_param_type param_type)
2929{
2930 switch (param_type) {
2931 case DEVLINK_PARAM_TYPE_U8:
2932 return NLA_U8;
2933 case DEVLINK_PARAM_TYPE_U16:
2934 return NLA_U16;
2935 case DEVLINK_PARAM_TYPE_U32:
2936 return NLA_U32;
2937 case DEVLINK_PARAM_TYPE_STRING:
2938 return NLA_STRING;
2939 case DEVLINK_PARAM_TYPE_BOOL:
2940 return NLA_FLAG;
2941 default:
2942 return -EINVAL;
2943 }
2944}
2945
2946static int
2947devlink_nl_param_value_fill_one(struct sk_buff *msg,
2948 enum devlink_param_type type,
2949 enum devlink_param_cmode cmode,
2950 union devlink_param_value val)
2951{
2952 struct nlattr *param_value_attr;
2953
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002954 param_value_attr = nla_nest_start_noflag(msg,
2955 DEVLINK_ATTR_PARAM_VALUE);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002956 if (!param_value_attr)
2957 goto nla_put_failure;
2958
2959 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
2960 goto value_nest_cancel;
2961
2962 switch (type) {
2963 case DEVLINK_PARAM_TYPE_U8:
2964 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
2965 goto value_nest_cancel;
2966 break;
2967 case DEVLINK_PARAM_TYPE_U16:
2968 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
2969 goto value_nest_cancel;
2970 break;
2971 case DEVLINK_PARAM_TYPE_U32:
2972 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
2973 goto value_nest_cancel;
2974 break;
2975 case DEVLINK_PARAM_TYPE_STRING:
2976 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
2977 val.vstr))
2978 goto value_nest_cancel;
2979 break;
2980 case DEVLINK_PARAM_TYPE_BOOL:
2981 if (val.vbool &&
2982 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
2983 goto value_nest_cancel;
2984 break;
2985 }
2986
2987 nla_nest_end(msg, param_value_attr);
2988 return 0;
2989
2990value_nest_cancel:
2991 nla_nest_cancel(msg, param_value_attr);
2992nla_put_failure:
2993 return -EMSGSIZE;
2994}
2995
2996static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302997 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002998 struct devlink_param_item *param_item,
2999 enum devlink_command cmd,
3000 u32 portid, u32 seq, int flags)
3001{
3002 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003003 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003004 const struct devlink_param *param = param_item->param;
3005 struct devlink_param_gset_ctx ctx;
3006 struct nlattr *param_values_list;
3007 struct nlattr *param_attr;
3008 int nla_type;
3009 void *hdr;
3010 int err;
3011 int i;
3012
3013 /* Get value from driver part to driverinit configuration mode */
3014 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3015 if (!devlink_param_cmode_is_supported(param, i))
3016 continue;
3017 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3018 if (!param_item->driverinit_value_valid)
3019 return -EOPNOTSUPP;
3020 param_value[i] = param_item->driverinit_value;
3021 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003022 if (!param_item->published)
3023 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003024 ctx.cmode = i;
3025 err = devlink_param_get(devlink, param, &ctx);
3026 if (err)
3027 return err;
3028 param_value[i] = ctx.val;
3029 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003030 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003031 }
3032
3033 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3034 if (!hdr)
3035 return -EMSGSIZE;
3036
3037 if (devlink_nl_put_handle(msg, devlink))
3038 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303039
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303040 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3041 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3042 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303043 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3044 goto genlmsg_cancel;
3045
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003046 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003047 if (!param_attr)
3048 goto genlmsg_cancel;
3049 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3050 goto param_nest_cancel;
3051 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3052 goto param_nest_cancel;
3053
3054 nla_type = devlink_param_type_to_nla_type(param->type);
3055 if (nla_type < 0)
3056 goto param_nest_cancel;
3057 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3058 goto param_nest_cancel;
3059
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003060 param_values_list = nla_nest_start_noflag(msg,
3061 DEVLINK_ATTR_PARAM_VALUES_LIST);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003062 if (!param_values_list)
3063 goto param_nest_cancel;
3064
3065 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003066 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003067 continue;
3068 err = devlink_nl_param_value_fill_one(msg, param->type,
3069 i, param_value[i]);
3070 if (err)
3071 goto values_list_nest_cancel;
3072 }
3073
3074 nla_nest_end(msg, param_values_list);
3075 nla_nest_end(msg, param_attr);
3076 genlmsg_end(msg, hdr);
3077 return 0;
3078
3079values_list_nest_cancel:
3080 nla_nest_end(msg, param_values_list);
3081param_nest_cancel:
3082 nla_nest_cancel(msg, param_attr);
3083genlmsg_cancel:
3084 genlmsg_cancel(msg, hdr);
3085 return -EMSGSIZE;
3086}
3087
Moshe Shemeshea601e12018-07-04 14:30:32 +03003088static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303089 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03003090 struct devlink_param_item *param_item,
3091 enum devlink_command cmd)
3092{
3093 struct sk_buff *msg;
3094 int err;
3095
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303096 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3097 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3098 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003099
3100 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3101 if (!msg)
3102 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303103 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3104 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003105 if (err) {
3106 nlmsg_free(msg);
3107 return;
3108 }
3109
3110 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3111 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3112}
3113
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003114static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3115 struct netlink_callback *cb)
3116{
3117 struct devlink_param_item *param_item;
3118 struct devlink *devlink;
3119 int start = cb->args[0];
3120 int idx = 0;
3121 int err;
3122
3123 mutex_lock(&devlink_mutex);
3124 list_for_each_entry(devlink, &devlink_list, list) {
3125 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3126 continue;
3127 mutex_lock(&devlink->lock);
3128 list_for_each_entry(param_item, &devlink->param_list, list) {
3129 if (idx < start) {
3130 idx++;
3131 continue;
3132 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303133 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003134 DEVLINK_CMD_PARAM_GET,
3135 NETLINK_CB(cb->skb).portid,
3136 cb->nlh->nlmsg_seq,
3137 NLM_F_MULTI);
3138 if (err) {
3139 mutex_unlock(&devlink->lock);
3140 goto out;
3141 }
3142 idx++;
3143 }
3144 mutex_unlock(&devlink->lock);
3145 }
3146out:
3147 mutex_unlock(&devlink_mutex);
3148
3149 cb->args[0] = idx;
3150 return msg->len;
3151}
3152
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003153static int
3154devlink_param_type_get_from_info(struct genl_info *info,
3155 enum devlink_param_type *param_type)
3156{
3157 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3158 return -EINVAL;
3159
3160 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3161 case NLA_U8:
3162 *param_type = DEVLINK_PARAM_TYPE_U8;
3163 break;
3164 case NLA_U16:
3165 *param_type = DEVLINK_PARAM_TYPE_U16;
3166 break;
3167 case NLA_U32:
3168 *param_type = DEVLINK_PARAM_TYPE_U32;
3169 break;
3170 case NLA_STRING:
3171 *param_type = DEVLINK_PARAM_TYPE_STRING;
3172 break;
3173 case NLA_FLAG:
3174 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3175 break;
3176 default:
3177 return -EINVAL;
3178 }
3179
3180 return 0;
3181}
3182
3183static int
3184devlink_param_value_get_from_info(const struct devlink_param *param,
3185 struct genl_info *info,
3186 union devlink_param_value *value)
3187{
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003188 int len;
3189
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003190 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3191 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3192 return -EINVAL;
3193
3194 switch (param->type) {
3195 case DEVLINK_PARAM_TYPE_U8:
3196 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3197 break;
3198 case DEVLINK_PARAM_TYPE_U16:
3199 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3200 break;
3201 case DEVLINK_PARAM_TYPE_U32:
3202 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3203 break;
3204 case DEVLINK_PARAM_TYPE_STRING:
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003205 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3206 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3207 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003208 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003209 return -EINVAL;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003210 strcpy(value->vstr,
3211 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003212 break;
3213 case DEVLINK_PARAM_TYPE_BOOL:
3214 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3215 true : false;
3216 break;
3217 }
3218 return 0;
3219}
3220
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003221static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303222devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003223 struct genl_info *info)
3224{
3225 char *param_name;
3226
3227 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3228 return NULL;
3229
3230 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303231 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003232}
3233
3234static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3235 struct genl_info *info)
3236{
3237 struct devlink *devlink = info->user_ptr[0];
3238 struct devlink_param_item *param_item;
3239 struct sk_buff *msg;
3240 int err;
3241
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303242 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003243 if (!param_item)
3244 return -EINVAL;
3245
3246 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3247 if (!msg)
3248 return -ENOMEM;
3249
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303250 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003251 DEVLINK_CMD_PARAM_GET,
3252 info->snd_portid, info->snd_seq, 0);
3253 if (err) {
3254 nlmsg_free(msg);
3255 return err;
3256 }
3257
3258 return genlmsg_reply(msg, info);
3259}
3260
Vasundhara Volam9c548732019-01-28 18:00:22 +05303261static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303262 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303263 struct list_head *param_list,
3264 struct genl_info *info,
3265 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003266{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003267 enum devlink_param_type param_type;
3268 struct devlink_param_gset_ctx ctx;
3269 enum devlink_param_cmode cmode;
3270 struct devlink_param_item *param_item;
3271 const struct devlink_param *param;
3272 union devlink_param_value value;
3273 int err = 0;
3274
Vasundhara Volam9c548732019-01-28 18:00:22 +05303275 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003276 if (!param_item)
3277 return -EINVAL;
3278 param = param_item->param;
3279 err = devlink_param_type_get_from_info(info, &param_type);
3280 if (err)
3281 return err;
3282 if (param_type != param->type)
3283 return -EINVAL;
3284 err = devlink_param_value_get_from_info(param, info, &value);
3285 if (err)
3286 return err;
3287 if (param->validate) {
3288 err = param->validate(devlink, param->id, value, info->extack);
3289 if (err)
3290 return err;
3291 }
3292
3293 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3294 return -EINVAL;
3295 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3296 if (!devlink_param_cmode_is_supported(param, cmode))
3297 return -EOPNOTSUPP;
3298
3299 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003300 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3301 strcpy(param_item->driverinit_value.vstr, value.vstr);
3302 else
3303 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003304 param_item->driverinit_value_valid = true;
3305 } else {
3306 if (!param->set)
3307 return -EOPNOTSUPP;
3308 ctx.val = value;
3309 ctx.cmode = cmode;
3310 err = devlink_param_set(devlink, param, &ctx);
3311 if (err)
3312 return err;
3313 }
3314
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303315 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003316 return 0;
3317}
3318
Vasundhara Volam9c548732019-01-28 18:00:22 +05303319static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3320 struct genl_info *info)
3321{
3322 struct devlink *devlink = info->user_ptr[0];
3323
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303324 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303325 info, DEVLINK_CMD_PARAM_NEW);
3326}
3327
Moshe Shemesheabaef12018-07-04 14:30:28 +03003328static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303329 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303330 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303331 const struct devlink_param *param,
3332 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003333{
3334 struct devlink_param_item *param_item;
3335
Vasundhara Volam39e61602019-01-28 18:00:20 +05303336 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03003337 return -EEXIST;
3338
3339 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3340 WARN_ON(param->get || param->set);
3341 else
3342 WARN_ON(!param->get || !param->set);
3343
3344 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3345 if (!param_item)
3346 return -ENOMEM;
3347 param_item->param = param;
3348
Vasundhara Volam39e61602019-01-28 18:00:20 +05303349 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303350 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003351 return 0;
3352}
3353
3354static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303355 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303356 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303357 const struct devlink_param *param,
3358 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003359{
3360 struct devlink_param_item *param_item;
3361
Vasundhara Volam39e61602019-01-28 18:00:20 +05303362 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003363 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303364 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003365 list_del(&param_item->list);
3366 kfree(param_item);
3367}
3368
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303369static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3370 struct netlink_callback *cb)
3371{
3372 struct devlink_param_item *param_item;
3373 struct devlink_port *devlink_port;
3374 struct devlink *devlink;
3375 int start = cb->args[0];
3376 int idx = 0;
3377 int err;
3378
3379 mutex_lock(&devlink_mutex);
3380 list_for_each_entry(devlink, &devlink_list, list) {
3381 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3382 continue;
3383 mutex_lock(&devlink->lock);
3384 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3385 list_for_each_entry(param_item,
3386 &devlink_port->param_list, list) {
3387 if (idx < start) {
3388 idx++;
3389 continue;
3390 }
3391 err = devlink_nl_param_fill(msg,
3392 devlink_port->devlink,
3393 devlink_port->index, param_item,
3394 DEVLINK_CMD_PORT_PARAM_GET,
3395 NETLINK_CB(cb->skb).portid,
3396 cb->nlh->nlmsg_seq,
3397 NLM_F_MULTI);
3398 if (err) {
3399 mutex_unlock(&devlink->lock);
3400 goto out;
3401 }
3402 idx++;
3403 }
3404 }
3405 mutex_unlock(&devlink->lock);
3406 }
3407out:
3408 mutex_unlock(&devlink_mutex);
3409
3410 cb->args[0] = idx;
3411 return msg->len;
3412}
3413
3414static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3415 struct genl_info *info)
3416{
3417 struct devlink_port *devlink_port = info->user_ptr[0];
3418 struct devlink_param_item *param_item;
3419 struct sk_buff *msg;
3420 int err;
3421
3422 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3423 info);
3424 if (!param_item)
3425 return -EINVAL;
3426
3427 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3428 if (!msg)
3429 return -ENOMEM;
3430
3431 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3432 devlink_port->index, param_item,
3433 DEVLINK_CMD_PORT_PARAM_GET,
3434 info->snd_portid, info->snd_seq, 0);
3435 if (err) {
3436 nlmsg_free(msg);
3437 return err;
3438 }
3439
3440 return genlmsg_reply(msg, info);
3441}
3442
Vasundhara Volam9c548732019-01-28 18:00:22 +05303443static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3444 struct genl_info *info)
3445{
3446 struct devlink_port *devlink_port = info->user_ptr[0];
3447
3448 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303449 devlink_port->index,
3450 &devlink_port->param_list, info,
3451 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05303452}
3453
Alex Veskera006d462018-07-12 15:13:12 +03003454static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3455 struct devlink *devlink,
3456 struct devlink_snapshot *snapshot)
3457{
3458 struct nlattr *snap_attr;
3459 int err;
3460
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003461 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
Alex Veskera006d462018-07-12 15:13:12 +03003462 if (!snap_attr)
3463 return -EINVAL;
3464
3465 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3466 if (err)
3467 goto nla_put_failure;
3468
3469 nla_nest_end(msg, snap_attr);
3470 return 0;
3471
3472nla_put_failure:
3473 nla_nest_cancel(msg, snap_attr);
3474 return err;
3475}
3476
3477static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3478 struct devlink *devlink,
3479 struct devlink_region *region)
3480{
3481 struct devlink_snapshot *snapshot;
3482 struct nlattr *snapshots_attr;
3483 int err;
3484
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003485 snapshots_attr = nla_nest_start_noflag(msg,
3486 DEVLINK_ATTR_REGION_SNAPSHOTS);
Alex Veskera006d462018-07-12 15:13:12 +03003487 if (!snapshots_attr)
3488 return -EINVAL;
3489
3490 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3491 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3492 if (err)
3493 goto nla_put_failure;
3494 }
3495
3496 nla_nest_end(msg, snapshots_attr);
3497 return 0;
3498
3499nla_put_failure:
3500 nla_nest_cancel(msg, snapshots_attr);
3501 return err;
3502}
3503
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003504static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3505 enum devlink_command cmd, u32 portid,
3506 u32 seq, int flags,
3507 struct devlink_region *region)
3508{
3509 void *hdr;
3510 int err;
3511
3512 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3513 if (!hdr)
3514 return -EMSGSIZE;
3515
3516 err = devlink_nl_put_handle(msg, devlink);
3517 if (err)
3518 goto nla_put_failure;
3519
3520 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3521 if (err)
3522 goto nla_put_failure;
3523
3524 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3525 region->size,
3526 DEVLINK_ATTR_PAD);
3527 if (err)
3528 goto nla_put_failure;
3529
Alex Veskera006d462018-07-12 15:13:12 +03003530 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3531 if (err)
3532 goto nla_put_failure;
3533
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003534 genlmsg_end(msg, hdr);
3535 return 0;
3536
3537nla_put_failure:
3538 genlmsg_cancel(msg, hdr);
3539 return err;
3540}
3541
Alex Vesker866319b2018-07-12 15:13:13 +03003542static void devlink_nl_region_notify(struct devlink_region *region,
3543 struct devlink_snapshot *snapshot,
3544 enum devlink_command cmd)
3545{
3546 struct devlink *devlink = region->devlink;
3547 struct sk_buff *msg;
3548 void *hdr;
3549 int err;
3550
3551 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3552
3553 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3554 if (!msg)
3555 return;
3556
3557 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3558 if (!hdr)
3559 goto out_free_msg;
3560
3561 err = devlink_nl_put_handle(msg, devlink);
3562 if (err)
3563 goto out_cancel_msg;
3564
3565 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3566 region->name);
3567 if (err)
3568 goto out_cancel_msg;
3569
3570 if (snapshot) {
3571 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3572 snapshot->id);
3573 if (err)
3574 goto out_cancel_msg;
3575 } else {
3576 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3577 region->size, DEVLINK_ATTR_PAD);
3578 if (err)
3579 goto out_cancel_msg;
3580 }
3581 genlmsg_end(msg, hdr);
3582
3583 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3584 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3585
3586 return;
3587
3588out_cancel_msg:
3589 genlmsg_cancel(msg, hdr);
3590out_free_msg:
3591 nlmsg_free(msg);
3592}
3593
Jiri Pirko92b49822019-08-12 14:28:31 +02003594static void devlink_region_snapshot_del(struct devlink_region *region,
3595 struct devlink_snapshot *snapshot)
3596{
3597 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3598 region->cur_snapshots--;
3599 list_del(&snapshot->list);
3600 (*snapshot->data_destructor)(snapshot->data);
3601 kfree(snapshot);
3602}
3603
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003604static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3605 struct genl_info *info)
3606{
3607 struct devlink *devlink = info->user_ptr[0];
3608 struct devlink_region *region;
3609 const char *region_name;
3610 struct sk_buff *msg;
3611 int err;
3612
3613 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3614 return -EINVAL;
3615
3616 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3617 region = devlink_region_get_by_name(devlink, region_name);
3618 if (!region)
3619 return -EINVAL;
3620
3621 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3622 if (!msg)
3623 return -ENOMEM;
3624
3625 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3626 info->snd_portid, info->snd_seq, 0,
3627 region);
3628 if (err) {
3629 nlmsg_free(msg);
3630 return err;
3631 }
3632
3633 return genlmsg_reply(msg, info);
3634}
3635
3636static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3637 struct netlink_callback *cb)
3638{
3639 struct devlink_region *region;
3640 struct devlink *devlink;
3641 int start = cb->args[0];
3642 int idx = 0;
3643 int err;
3644
3645 mutex_lock(&devlink_mutex);
3646 list_for_each_entry(devlink, &devlink_list, list) {
3647 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3648 continue;
3649
3650 mutex_lock(&devlink->lock);
3651 list_for_each_entry(region, &devlink->region_list, list) {
3652 if (idx < start) {
3653 idx++;
3654 continue;
3655 }
3656 err = devlink_nl_region_fill(msg, devlink,
3657 DEVLINK_CMD_REGION_GET,
3658 NETLINK_CB(cb->skb).portid,
3659 cb->nlh->nlmsg_seq,
3660 NLM_F_MULTI, region);
3661 if (err) {
3662 mutex_unlock(&devlink->lock);
3663 goto out;
3664 }
3665 idx++;
3666 }
3667 mutex_unlock(&devlink->lock);
3668 }
3669out:
3670 mutex_unlock(&devlink_mutex);
3671 cb->args[0] = idx;
3672 return msg->len;
3673}
3674
Alex Vesker866319b2018-07-12 15:13:13 +03003675static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3676 struct genl_info *info)
3677{
3678 struct devlink *devlink = info->user_ptr[0];
3679 struct devlink_snapshot *snapshot;
3680 struct devlink_region *region;
3681 const char *region_name;
3682 u32 snapshot_id;
3683
3684 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3685 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3686 return -EINVAL;
3687
3688 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3689 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3690
3691 region = devlink_region_get_by_name(devlink, region_name);
3692 if (!region)
3693 return -EINVAL;
3694
3695 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3696 if (!snapshot)
3697 return -EINVAL;
3698
Jiri Pirko92b49822019-08-12 14:28:31 +02003699 devlink_region_snapshot_del(region, snapshot);
Alex Vesker866319b2018-07-12 15:13:13 +03003700 return 0;
3701}
3702
Alex Vesker4e547952018-07-12 15:13:14 +03003703static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3704 struct devlink *devlink,
3705 u8 *chunk, u32 chunk_size,
3706 u64 addr)
3707{
3708 struct nlattr *chunk_attr;
3709 int err;
3710
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003711 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
Alex Vesker4e547952018-07-12 15:13:14 +03003712 if (!chunk_attr)
3713 return -EINVAL;
3714
3715 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3716 if (err)
3717 goto nla_put_failure;
3718
3719 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3720 DEVLINK_ATTR_PAD);
3721 if (err)
3722 goto nla_put_failure;
3723
3724 nla_nest_end(msg, chunk_attr);
3725 return 0;
3726
3727nla_put_failure:
3728 nla_nest_cancel(msg, chunk_attr);
3729 return err;
3730}
3731
3732#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3733
3734static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3735 struct devlink *devlink,
3736 struct devlink_region *region,
3737 struct nlattr **attrs,
3738 u64 start_offset,
3739 u64 end_offset,
3740 bool dump,
3741 u64 *new_offset)
3742{
3743 struct devlink_snapshot *snapshot;
3744 u64 curr_offset = start_offset;
3745 u32 snapshot_id;
3746 int err = 0;
3747
3748 *new_offset = start_offset;
3749
3750 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3751 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3752 if (!snapshot)
3753 return -EINVAL;
3754
Jiri Pirko3a5e5232019-08-09 15:27:15 +02003755 if (end_offset > region->size || dump)
3756 end_offset = region->size;
Alex Vesker4e547952018-07-12 15:13:14 +03003757
3758 while (curr_offset < end_offset) {
3759 u32 data_size;
3760 u8 *data;
3761
3762 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3763 data_size = end_offset - curr_offset;
3764 else
3765 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3766
3767 data = &snapshot->data[curr_offset];
3768 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3769 data, data_size,
3770 curr_offset);
3771 if (err)
3772 break;
3773
3774 curr_offset += data_size;
3775 }
3776 *new_offset = curr_offset;
3777
3778 return err;
3779}
3780
3781static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3782 struct netlink_callback *cb)
3783{
3784 u64 ret_offset, start_offset, end_offset = 0;
Alex Vesker4e547952018-07-12 15:13:14 +03003785 struct devlink_region *region;
3786 struct nlattr *chunks_attr;
3787 const char *region_name;
3788 struct devlink *devlink;
Jakub Kicinski68750562019-02-10 19:35:28 -08003789 struct nlattr **attrs;
Alex Vesker4e547952018-07-12 15:13:14 +03003790 bool dump = true;
3791 void *hdr;
3792 int err;
3793
3794 start_offset = *((u64 *)&cb->args[0]);
3795
Jakub Kicinski68750562019-02-10 19:35:28 -08003796 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
3797 if (!attrs)
3798 return -ENOMEM;
3799
Johannes Berg8cb08172019-04-26 14:07:28 +02003800 err = nlmsg_parse_deprecated(cb->nlh,
3801 GENL_HDRLEN + devlink_nl_family.hdrsize,
3802 attrs, DEVLINK_ATTR_MAX,
3803 devlink_nl_family.policy, cb->extack);
Alex Vesker4e547952018-07-12 15:13:14 +03003804 if (err)
Jakub Kicinski68750562019-02-10 19:35:28 -08003805 goto out_free;
Alex Vesker4e547952018-07-12 15:13:14 +03003806
Parav Panditdac7c082019-02-12 14:24:08 -06003807 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03003808 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003809 if (IS_ERR(devlink)) {
3810 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06003811 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003812 }
Alex Vesker4e547952018-07-12 15:13:14 +03003813
Alex Vesker4e547952018-07-12 15:13:14 +03003814 mutex_lock(&devlink->lock);
3815
3816 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06003817 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
3818 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003819 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003820 }
Alex Vesker4e547952018-07-12 15:13:14 +03003821
3822 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3823 region = devlink_region_get_by_name(devlink, region_name);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003824 if (!region) {
3825 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003826 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003827 }
Alex Vesker4e547952018-07-12 15:13:14 +03003828
3829 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3830 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3831 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003832 if (!hdr) {
3833 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03003834 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003835 }
Alex Vesker4e547952018-07-12 15:13:14 +03003836
3837 err = devlink_nl_put_handle(skb, devlink);
3838 if (err)
3839 goto nla_put_failure;
3840
3841 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3842 if (err)
3843 goto nla_put_failure;
3844
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003845 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003846 if (!chunks_attr) {
3847 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03003848 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003849 }
Alex Vesker4e547952018-07-12 15:13:14 +03003850
3851 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3852 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3853 if (!start_offset)
3854 start_offset =
3855 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3856
3857 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3858 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3859 dump = false;
3860 }
3861
3862 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3863 region, attrs,
3864 start_offset,
3865 end_offset, dump,
3866 &ret_offset);
3867
3868 if (err && err != -EMSGSIZE)
3869 goto nla_put_failure;
3870
3871 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06003872 if (ret_offset == start_offset) {
3873 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003874 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003875 }
Alex Vesker4e547952018-07-12 15:13:14 +03003876
3877 *((u64 *)&cb->args[0]) = ret_offset;
3878
3879 nla_nest_end(skb, chunks_attr);
3880 genlmsg_end(skb, hdr);
3881 mutex_unlock(&devlink->lock);
3882 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003883 kfree(attrs);
Alex Vesker4e547952018-07-12 15:13:14 +03003884
3885 return skb->len;
3886
3887nla_put_failure:
3888 genlmsg_cancel(skb, hdr);
3889out_unlock:
3890 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06003891out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03003892 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003893out_free:
3894 kfree(attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003895 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03003896}
3897
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003898struct devlink_info_req {
3899 struct sk_buff *msg;
3900};
3901
3902int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3903{
3904 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3905}
3906EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3907
3908int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3909{
3910 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3911}
3912EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3913
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08003914static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3915 const char *version_name,
3916 const char *version_value)
3917{
3918 struct nlattr *nest;
3919 int err;
3920
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003921 nest = nla_nest_start_noflag(req->msg, attr);
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08003922 if (!nest)
3923 return -EMSGSIZE;
3924
3925 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3926 version_name);
3927 if (err)
3928 goto nla_put_failure;
3929
3930 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3931 version_value);
3932 if (err)
3933 goto nla_put_failure;
3934
3935 nla_nest_end(req->msg, nest);
3936
3937 return 0;
3938
3939nla_put_failure:
3940 nla_nest_cancel(req->msg, nest);
3941 return err;
3942}
3943
3944int devlink_info_version_fixed_put(struct devlink_info_req *req,
3945 const char *version_name,
3946 const char *version_value)
3947{
3948 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3949 version_name, version_value);
3950}
3951EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3952
3953int devlink_info_version_stored_put(struct devlink_info_req *req,
3954 const char *version_name,
3955 const char *version_value)
3956{
3957 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3958 version_name, version_value);
3959}
3960EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3961
3962int devlink_info_version_running_put(struct devlink_info_req *req,
3963 const char *version_name,
3964 const char *version_value)
3965{
3966 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3967 version_name, version_value);
3968}
3969EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3970
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003971static int
3972devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3973 enum devlink_command cmd, u32 portid,
3974 u32 seq, int flags, struct netlink_ext_ack *extack)
3975{
3976 struct devlink_info_req req;
3977 void *hdr;
3978 int err;
3979
3980 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3981 if (!hdr)
3982 return -EMSGSIZE;
3983
3984 err = -EMSGSIZE;
3985 if (devlink_nl_put_handle(msg, devlink))
3986 goto err_cancel_msg;
3987
3988 req.msg = msg;
3989 err = devlink->ops->info_get(devlink, &req, extack);
3990 if (err)
3991 goto err_cancel_msg;
3992
3993 genlmsg_end(msg, hdr);
3994 return 0;
3995
3996err_cancel_msg:
3997 genlmsg_cancel(msg, hdr);
3998 return err;
3999}
4000
4001static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
4002 struct genl_info *info)
4003{
4004 struct devlink *devlink = info->user_ptr[0];
4005 struct sk_buff *msg;
4006 int err;
4007
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08004008 if (!devlink->ops->info_get)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004009 return -EOPNOTSUPP;
4010
4011 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4012 if (!msg)
4013 return -ENOMEM;
4014
4015 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4016 info->snd_portid, info->snd_seq, 0,
4017 info->extack);
4018 if (err) {
4019 nlmsg_free(msg);
4020 return err;
4021 }
4022
4023 return genlmsg_reply(msg, info);
4024}
4025
4026static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
4027 struct netlink_callback *cb)
4028{
4029 struct devlink *devlink;
4030 int start = cb->args[0];
4031 int idx = 0;
4032 int err;
4033
4034 mutex_lock(&devlink_mutex);
4035 list_for_each_entry(devlink, &devlink_list, list) {
4036 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4037 continue;
4038 if (idx < start) {
4039 idx++;
4040 continue;
4041 }
4042
Jiri Pirkoc493b09b2019-03-24 00:21:03 +01004043 if (!devlink->ops->info_get) {
4044 idx++;
4045 continue;
4046 }
4047
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004048 mutex_lock(&devlink->lock);
4049 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4050 NETLINK_CB(cb->skb).portid,
4051 cb->nlh->nlmsg_seq, NLM_F_MULTI,
4052 cb->extack);
4053 mutex_unlock(&devlink->lock);
4054 if (err)
4055 break;
4056 idx++;
4057 }
4058 mutex_unlock(&devlink_mutex);
4059
4060 cb->args[0] = idx;
4061 return msg->len;
4062}
4063
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004064struct devlink_fmsg_item {
4065 struct list_head list;
4066 int attrtype;
4067 u8 nla_type;
4068 u16 len;
4069 int value[0];
4070};
4071
4072struct devlink_fmsg {
4073 struct list_head item_list;
4074};
4075
4076static struct devlink_fmsg *devlink_fmsg_alloc(void)
4077{
4078 struct devlink_fmsg *fmsg;
4079
4080 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
4081 if (!fmsg)
4082 return NULL;
4083
4084 INIT_LIST_HEAD(&fmsg->item_list);
4085
4086 return fmsg;
4087}
4088
4089static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
4090{
4091 struct devlink_fmsg_item *item, *tmp;
4092
4093 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
4094 list_del(&item->list);
4095 kfree(item);
4096 }
4097 kfree(fmsg);
4098}
4099
4100static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
4101 int attrtype)
4102{
4103 struct devlink_fmsg_item *item;
4104
4105 item = kzalloc(sizeof(*item), GFP_KERNEL);
4106 if (!item)
4107 return -ENOMEM;
4108
4109 item->attrtype = attrtype;
4110 list_add_tail(&item->list, &fmsg->item_list);
4111
4112 return 0;
4113}
4114
4115int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
4116{
4117 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
4118}
4119EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
4120
4121static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
4122{
4123 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
4124}
4125
4126int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
4127{
4128 return devlink_fmsg_nest_end(fmsg);
4129}
4130EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
4131
4132#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
4133
4134static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
4135{
4136 struct devlink_fmsg_item *item;
4137
4138 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4139 return -EMSGSIZE;
4140
4141 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4142 if (!item)
4143 return -ENOMEM;
4144
4145 item->nla_type = NLA_NUL_STRING;
4146 item->len = strlen(name) + 1;
4147 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4148 memcpy(&item->value, name, item->len);
4149 list_add_tail(&item->list, &fmsg->item_list);
4150
4151 return 0;
4152}
4153
4154int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4155{
4156 int err;
4157
4158 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4159 if (err)
4160 return err;
4161
4162 err = devlink_fmsg_put_name(fmsg, name);
4163 if (err)
4164 return err;
4165
4166 return 0;
4167}
4168EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4169
4170int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4171{
4172 return devlink_fmsg_nest_end(fmsg);
4173}
4174EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4175
4176int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4177 const char *name)
4178{
4179 int err;
4180
4181 err = devlink_fmsg_pair_nest_start(fmsg, name);
4182 if (err)
4183 return err;
4184
4185 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4186 if (err)
4187 return err;
4188
4189 return 0;
4190}
4191EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4192
4193int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4194{
4195 int err;
4196
4197 err = devlink_fmsg_nest_end(fmsg);
4198 if (err)
4199 return err;
4200
4201 err = devlink_fmsg_nest_end(fmsg);
4202 if (err)
4203 return err;
4204
4205 return 0;
4206}
4207EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4208
4209static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4210 const void *value, u16 value_len,
4211 u8 value_nla_type)
4212{
4213 struct devlink_fmsg_item *item;
4214
4215 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4216 return -EMSGSIZE;
4217
4218 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4219 if (!item)
4220 return -ENOMEM;
4221
4222 item->nla_type = value_nla_type;
4223 item->len = value_len;
4224 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4225 memcpy(&item->value, value, item->len);
4226 list_add_tail(&item->list, &fmsg->item_list);
4227
4228 return 0;
4229}
4230
4231int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4232{
4233 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4234}
4235EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4236
4237int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4238{
4239 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4240}
4241EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4242
4243int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4244{
4245 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4246}
4247EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4248
4249int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4250{
4251 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4252}
4253EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4254
4255int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4256{
4257 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4258 NLA_NUL_STRING);
4259}
4260EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4261
4262int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4263 u16 value_len)
4264{
4265 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4266}
4267EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4268
4269int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4270 bool value)
4271{
4272 int err;
4273
4274 err = devlink_fmsg_pair_nest_start(fmsg, name);
4275 if (err)
4276 return err;
4277
4278 err = devlink_fmsg_bool_put(fmsg, value);
4279 if (err)
4280 return err;
4281
4282 err = devlink_fmsg_pair_nest_end(fmsg);
4283 if (err)
4284 return err;
4285
4286 return 0;
4287}
4288EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4289
4290int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4291 u8 value)
4292{
4293 int err;
4294
4295 err = devlink_fmsg_pair_nest_start(fmsg, name);
4296 if (err)
4297 return err;
4298
4299 err = devlink_fmsg_u8_put(fmsg, value);
4300 if (err)
4301 return err;
4302
4303 err = devlink_fmsg_pair_nest_end(fmsg);
4304 if (err)
4305 return err;
4306
4307 return 0;
4308}
4309EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4310
4311int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4312 u32 value)
4313{
4314 int err;
4315
4316 err = devlink_fmsg_pair_nest_start(fmsg, name);
4317 if (err)
4318 return err;
4319
4320 err = devlink_fmsg_u32_put(fmsg, value);
4321 if (err)
4322 return err;
4323
4324 err = devlink_fmsg_pair_nest_end(fmsg);
4325 if (err)
4326 return err;
4327
4328 return 0;
4329}
4330EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4331
4332int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4333 u64 value)
4334{
4335 int err;
4336
4337 err = devlink_fmsg_pair_nest_start(fmsg, name);
4338 if (err)
4339 return err;
4340
4341 err = devlink_fmsg_u64_put(fmsg, value);
4342 if (err)
4343 return err;
4344
4345 err = devlink_fmsg_pair_nest_end(fmsg);
4346 if (err)
4347 return err;
4348
4349 return 0;
4350}
4351EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4352
4353int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4354 const char *value)
4355{
4356 int err;
4357
4358 err = devlink_fmsg_pair_nest_start(fmsg, name);
4359 if (err)
4360 return err;
4361
4362 err = devlink_fmsg_string_put(fmsg, value);
4363 if (err)
4364 return err;
4365
4366 err = devlink_fmsg_pair_nest_end(fmsg);
4367 if (err)
4368 return err;
4369
4370 return 0;
4371}
4372EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4373
4374int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4375 const void *value, u16 value_len)
4376{
4377 int err;
4378
4379 err = devlink_fmsg_pair_nest_start(fmsg, name);
4380 if (err)
4381 return err;
4382
4383 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4384 if (err)
4385 return err;
4386
4387 err = devlink_fmsg_pair_nest_end(fmsg);
4388 if (err)
4389 return err;
4390
4391 return 0;
4392}
4393EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4394
4395static int
4396devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4397{
4398 switch (msg->nla_type) {
4399 case NLA_FLAG:
4400 case NLA_U8:
4401 case NLA_U32:
4402 case NLA_U64:
4403 case NLA_NUL_STRING:
4404 case NLA_BINARY:
4405 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4406 msg->nla_type);
4407 default:
4408 return -EINVAL;
4409 }
4410}
4411
4412static int
4413devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4414{
4415 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4416 u8 tmp;
4417
4418 switch (msg->nla_type) {
4419 case NLA_FLAG:
4420 /* Always provide flag data, regardless of its value */
4421 tmp = *(bool *) msg->value;
4422
4423 return nla_put_u8(skb, attrtype, tmp);
4424 case NLA_U8:
4425 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4426 case NLA_U32:
4427 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4428 case NLA_U64:
4429 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4430 DEVLINK_ATTR_PAD);
4431 case NLA_NUL_STRING:
4432 return nla_put_string(skb, attrtype, (char *) &msg->value);
4433 case NLA_BINARY:
4434 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4435 default:
4436 return -EINVAL;
4437 }
4438}
4439
4440static int
4441devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4442 int *start)
4443{
4444 struct devlink_fmsg_item *item;
4445 struct nlattr *fmsg_nlattr;
4446 int i = 0;
4447 int err;
4448
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004449 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004450 if (!fmsg_nlattr)
4451 return -EMSGSIZE;
4452
4453 list_for_each_entry(item, &fmsg->item_list, list) {
4454 if (i < *start) {
4455 i++;
4456 continue;
4457 }
4458
4459 switch (item->attrtype) {
4460 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4461 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4462 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4463 case DEVLINK_ATTR_FMSG_NEST_END:
4464 err = nla_put_flag(skb, item->attrtype);
4465 break;
4466 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4467 err = devlink_fmsg_item_fill_type(item, skb);
4468 if (err)
4469 break;
4470 err = devlink_fmsg_item_fill_data(item, skb);
4471 break;
4472 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4473 err = nla_put_string(skb, item->attrtype,
4474 (char *) &item->value);
4475 break;
4476 default:
4477 err = -EINVAL;
4478 break;
4479 }
4480 if (!err)
4481 *start = ++i;
4482 else
4483 break;
4484 }
4485
4486 nla_nest_end(skb, fmsg_nlattr);
4487 return err;
4488}
4489
4490static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4491 struct genl_info *info,
4492 enum devlink_command cmd, int flags)
4493{
4494 struct nlmsghdr *nlh;
4495 struct sk_buff *skb;
4496 bool last = false;
4497 int index = 0;
4498 void *hdr;
4499 int err;
4500
4501 while (!last) {
4502 int tmp_index = index;
4503
4504 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4505 if (!skb)
4506 return -ENOMEM;
4507
4508 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4509 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4510 if (!hdr) {
4511 err = -EMSGSIZE;
4512 goto nla_put_failure;
4513 }
4514
4515 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4516 if (!err)
4517 last = true;
4518 else if (err != -EMSGSIZE || tmp_index == index)
4519 goto nla_put_failure;
4520
4521 genlmsg_end(skb, hdr);
4522 err = genlmsg_reply(skb, info);
4523 if (err)
4524 return err;
4525 }
4526
4527 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4528 if (!skb)
4529 return -ENOMEM;
4530 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4531 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4532 if (!nlh) {
4533 err = -EMSGSIZE;
4534 goto nla_put_failure;
4535 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004536
Li RongQingfde55ea2019-02-11 19:09:07 +08004537 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004538
4539nla_put_failure:
4540 nlmsg_free(skb);
4541 return err;
4542}
4543
Aya Levine44ef4e2019-05-16 09:49:20 +03004544static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4545 struct netlink_callback *cb,
4546 enum devlink_command cmd)
4547{
4548 int index = cb->args[0];
4549 int tmp_index = index;
4550 void *hdr;
4551 int err;
4552
4553 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4554 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
4555 if (!hdr) {
4556 err = -EMSGSIZE;
4557 goto nla_put_failure;
4558 }
4559
4560 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4561 if ((err && err != -EMSGSIZE) || tmp_index == index)
4562 goto nla_put_failure;
4563
4564 cb->args[0] = index;
4565 genlmsg_end(skb, hdr);
4566 return skb->len;
4567
4568nla_put_failure:
4569 genlmsg_cancel(skb, hdr);
4570 return err;
4571}
4572
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004573struct devlink_health_reporter {
4574 struct list_head list;
4575 void *priv;
4576 const struct devlink_health_reporter_ops *ops;
4577 struct devlink *devlink;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004578 struct devlink_fmsg *dump_fmsg;
4579 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004580 u64 graceful_period;
4581 bool auto_recover;
4582 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004583 u64 dump_ts;
4584 u64 error_count;
4585 u64 recovery_count;
4586 u64 last_recovery_ts;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004587 refcount_t refcount;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004588};
4589
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004590void *
4591devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4592{
4593 return reporter->priv;
4594}
4595EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4596
4597static struct devlink_health_reporter *
4598devlink_health_reporter_find_by_name(struct devlink *devlink,
4599 const char *reporter_name)
4600{
4601 struct devlink_health_reporter *reporter;
4602
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004603 lockdep_assert_held(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004604 list_for_each_entry(reporter, &devlink->reporter_list, list)
4605 if (!strcmp(reporter->ops->name, reporter_name))
4606 return reporter;
4607 return NULL;
4608}
4609
4610/**
4611 * devlink_health_reporter_create - create devlink health reporter
4612 *
4613 * @devlink: devlink
4614 * @ops: ops
4615 * @graceful_period: to avoid recovery loops, in msecs
4616 * @auto_recover: auto recover when error occurs
4617 * @priv: priv
4618 */
4619struct devlink_health_reporter *
4620devlink_health_reporter_create(struct devlink *devlink,
4621 const struct devlink_health_reporter_ops *ops,
4622 u64 graceful_period, bool auto_recover,
4623 void *priv)
4624{
4625 struct devlink_health_reporter *reporter;
4626
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004627 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004628 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4629 reporter = ERR_PTR(-EEXIST);
4630 goto unlock;
4631 }
4632
4633 if (WARN_ON(auto_recover && !ops->recover) ||
4634 WARN_ON(graceful_period && !ops->recover)) {
4635 reporter = ERR_PTR(-EINVAL);
4636 goto unlock;
4637 }
4638
4639 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4640 if (!reporter) {
4641 reporter = ERR_PTR(-ENOMEM);
4642 goto unlock;
4643 }
4644
4645 reporter->priv = priv;
4646 reporter->ops = ops;
4647 reporter->devlink = devlink;
4648 reporter->graceful_period = graceful_period;
4649 reporter->auto_recover = auto_recover;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004650 mutex_init(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004651 refcount_set(&reporter->refcount, 1);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004652 list_add_tail(&reporter->list, &devlink->reporter_list);
4653unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004654 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004655 return reporter;
4656}
4657EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4658
4659/**
4660 * devlink_health_reporter_destroy - destroy devlink health reporter
4661 *
4662 * @reporter: devlink health reporter to destroy
4663 */
4664void
4665devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4666{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004667 mutex_lock(&reporter->devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004668 list_del(&reporter->list);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004669 mutex_unlock(&reporter->devlink->reporters_lock);
4670 while (refcount_read(&reporter->refcount) > 1)
4671 msleep(100);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01004672 mutex_destroy(&reporter->dump_lock);
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004673 if (reporter->dump_fmsg)
4674 devlink_fmsg_free(reporter->dump_fmsg);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004675 kfree(reporter);
4676}
4677EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4678
Eran Ben Elisha3167b272019-03-03 10:57:30 +02004679void
4680devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
4681 enum devlink_health_reporter_state state)
4682{
4683 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
4684 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
4685 return;
4686
4687 if (reporter->health_state == state)
4688 return;
4689
4690 reporter->health_state = state;
4691 trace_devlink_health_reporter_state_update(reporter->devlink,
4692 reporter->ops->name, state);
4693}
4694EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
4695
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004696static int
4697devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4698 void *priv_ctx)
4699{
4700 int err;
4701
4702 if (!reporter->ops->recover)
4703 return -EOPNOTSUPP;
4704
4705 err = reporter->ops->recover(reporter, priv_ctx);
4706 if (err)
4707 return err;
4708
4709 reporter->recovery_count++;
4710 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4711 reporter->last_recovery_ts = jiffies;
4712
4713 return 0;
4714}
4715
4716static void
4717devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4718{
4719 if (!reporter->dump_fmsg)
4720 return;
4721 devlink_fmsg_free(reporter->dump_fmsg);
4722 reporter->dump_fmsg = NULL;
4723}
4724
4725static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4726 void *priv_ctx)
4727{
4728 int err;
4729
4730 if (!reporter->ops->dump)
4731 return 0;
4732
4733 if (reporter->dump_fmsg)
4734 return 0;
4735
4736 reporter->dump_fmsg = devlink_fmsg_alloc();
4737 if (!reporter->dump_fmsg) {
4738 err = -ENOMEM;
4739 return err;
4740 }
4741
4742 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4743 if (err)
4744 goto dump_err;
4745
4746 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4747 priv_ctx);
4748 if (err)
4749 goto dump_err;
4750
4751 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4752 if (err)
4753 goto dump_err;
4754
4755 reporter->dump_ts = jiffies;
4756
4757 return 0;
4758
4759dump_err:
4760 devlink_health_dump_clear(reporter);
4761 return err;
4762}
4763
4764int devlink_health_report(struct devlink_health_reporter *reporter,
4765 const char *msg, void *priv_ctx)
4766{
Eran Ben Elishaa0a21ad2019-03-03 10:57:29 +02004767 enum devlink_health_reporter_state prev_health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004768 struct devlink *devlink = reporter->devlink;
4769
4770 /* write a log message of the current error */
4771 WARN_ON(!msg);
4772 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4773 reporter->error_count++;
Eran Ben Elishaa0a21ad2019-03-03 10:57:29 +02004774 prev_health_state = reporter->health_state;
4775 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004776
4777 /* abort if the previous error wasn't recovered */
4778 if (reporter->auto_recover &&
Eran Ben Elishaa0a21ad2019-03-03 10:57:29 +02004779 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004780 jiffies - reporter->last_recovery_ts <
4781 msecs_to_jiffies(reporter->graceful_period))) {
4782 trace_devlink_health_recover_aborted(devlink,
4783 reporter->ops->name,
4784 reporter->health_state,
4785 jiffies -
4786 reporter->last_recovery_ts);
4787 return -ECANCELED;
4788 }
4789
4790 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4791
4792 mutex_lock(&reporter->dump_lock);
4793 /* store current dump of current error, for later analysis */
4794 devlink_health_do_dump(reporter, priv_ctx);
4795 mutex_unlock(&reporter->dump_lock);
4796
4797 if (reporter->auto_recover)
4798 return devlink_health_reporter_recover(reporter, priv_ctx);
4799
4800 return 0;
4801}
4802EXPORT_SYMBOL_GPL(devlink_health_report);
4803
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004804static struct devlink_health_reporter *
Aya Levine44ef4e2019-05-16 09:49:20 +03004805devlink_health_reporter_get_from_attrs(struct devlink *devlink,
4806 struct nlattr **attrs)
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004807{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004808 struct devlink_health_reporter *reporter;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004809 char *reporter_name;
4810
Aya Levine44ef4e2019-05-16 09:49:20 +03004811 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004812 return NULL;
4813
Aya Levine44ef4e2019-05-16 09:49:20 +03004814 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004815 mutex_lock(&devlink->reporters_lock);
4816 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
4817 if (reporter)
4818 refcount_inc(&reporter->refcount);
4819 mutex_unlock(&devlink->reporters_lock);
4820 return reporter;
4821}
4822
Aya Levine44ef4e2019-05-16 09:49:20 +03004823static struct devlink_health_reporter *
4824devlink_health_reporter_get_from_info(struct devlink *devlink,
4825 struct genl_info *info)
4826{
4827 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
4828}
4829
4830static struct devlink_health_reporter *
4831devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
4832{
4833 struct devlink_health_reporter *reporter;
4834 struct devlink *devlink;
4835 struct nlattr **attrs;
4836 int err;
4837
4838 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
4839 if (!attrs)
4840 return NULL;
4841
4842 err = nlmsg_parse_deprecated(cb->nlh,
4843 GENL_HDRLEN + devlink_nl_family.hdrsize,
4844 attrs, DEVLINK_ATTR_MAX,
4845 devlink_nl_family.policy, cb->extack);
4846 if (err)
4847 goto free;
4848
4849 mutex_lock(&devlink_mutex);
4850 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
4851 if (IS_ERR(devlink))
4852 goto unlock;
4853
4854 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
4855 mutex_unlock(&devlink_mutex);
4856 kfree(attrs);
4857 return reporter;
4858unlock:
4859 mutex_unlock(&devlink_mutex);
4860free:
4861 kfree(attrs);
4862 return NULL;
4863}
4864
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004865static void
4866devlink_health_reporter_put(struct devlink_health_reporter *reporter)
4867{
4868 refcount_dec(&reporter->refcount);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004869}
4870
4871static int
4872devlink_nl_health_reporter_fill(struct sk_buff *msg,
4873 struct devlink *devlink,
4874 struct devlink_health_reporter *reporter,
4875 enum devlink_command cmd, u32 portid,
4876 u32 seq, int flags)
4877{
4878 struct nlattr *reporter_attr;
4879 void *hdr;
4880
4881 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4882 if (!hdr)
4883 return -EMSGSIZE;
4884
4885 if (devlink_nl_put_handle(msg, devlink))
4886 goto genlmsg_cancel;
4887
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004888 reporter_attr = nla_nest_start_noflag(msg,
4889 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004890 if (!reporter_attr)
4891 goto genlmsg_cancel;
4892 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4893 reporter->ops->name))
4894 goto reporter_nest_cancel;
4895 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4896 reporter->health_state))
4897 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02004898 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004899 reporter->error_count, DEVLINK_ATTR_PAD))
4900 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02004901 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004902 reporter->recovery_count, DEVLINK_ATTR_PAD))
4903 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02004904 if (reporter->ops->recover &&
4905 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004906 reporter->graceful_period,
4907 DEVLINK_ATTR_PAD))
4908 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02004909 if (reporter->ops->recover &&
4910 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004911 reporter->auto_recover))
4912 goto reporter_nest_cancel;
4913 if (reporter->dump_fmsg &&
4914 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4915 jiffies_to_msecs(reporter->dump_ts),
4916 DEVLINK_ATTR_PAD))
4917 goto reporter_nest_cancel;
4918
4919 nla_nest_end(msg, reporter_attr);
4920 genlmsg_end(msg, hdr);
4921 return 0;
4922
4923reporter_nest_cancel:
4924 nla_nest_end(msg, reporter_attr);
4925genlmsg_cancel:
4926 genlmsg_cancel(msg, hdr);
4927 return -EMSGSIZE;
4928}
4929
4930static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4931 struct genl_info *info)
4932{
4933 struct devlink *devlink = info->user_ptr[0];
4934 struct devlink_health_reporter *reporter;
4935 struct sk_buff *msg;
4936 int err;
4937
4938 reporter = devlink_health_reporter_get_from_info(devlink, info);
4939 if (!reporter)
4940 return -EINVAL;
4941
4942 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004943 if (!msg) {
4944 err = -ENOMEM;
4945 goto out;
4946 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004947
4948 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4949 DEVLINK_CMD_HEALTH_REPORTER_GET,
4950 info->snd_portid, info->snd_seq,
4951 0);
4952 if (err) {
4953 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004954 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004955 }
4956
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004957 err = genlmsg_reply(msg, info);
4958out:
4959 devlink_health_reporter_put(reporter);
4960 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004961}
4962
4963static int
4964devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4965 struct netlink_callback *cb)
4966{
4967 struct devlink_health_reporter *reporter;
4968 struct devlink *devlink;
4969 int start = cb->args[0];
4970 int idx = 0;
4971 int err;
4972
4973 mutex_lock(&devlink_mutex);
4974 list_for_each_entry(devlink, &devlink_list, list) {
4975 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4976 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004977 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004978 list_for_each_entry(reporter, &devlink->reporter_list,
4979 list) {
4980 if (idx < start) {
4981 idx++;
4982 continue;
4983 }
4984 err = devlink_nl_health_reporter_fill(msg, devlink,
4985 reporter,
4986 DEVLINK_CMD_HEALTH_REPORTER_GET,
4987 NETLINK_CB(cb->skb).portid,
4988 cb->nlh->nlmsg_seq,
4989 NLM_F_MULTI);
4990 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004991 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004992 goto out;
4993 }
4994 idx++;
4995 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004996 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004997 }
4998out:
4999 mutex_unlock(&devlink_mutex);
5000
5001 cb->args[0] = idx;
5002 return msg->len;
5003}
5004
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005005static int
5006devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
5007 struct genl_info *info)
5008{
5009 struct devlink *devlink = info->user_ptr[0];
5010 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005011 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005012
5013 reporter = devlink_health_reporter_get_from_info(devlink, info);
5014 if (!reporter)
5015 return -EINVAL;
5016
5017 if (!reporter->ops->recover &&
5018 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005019 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
5020 err = -EOPNOTSUPP;
5021 goto out;
5022 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005023
5024 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
5025 reporter->graceful_period =
5026 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
5027
5028 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
5029 reporter->auto_recover =
5030 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
5031
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005032 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005033 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005034out:
5035 devlink_health_reporter_put(reporter);
5036 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005037}
5038
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005039static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
5040 struct genl_info *info)
5041{
5042 struct devlink *devlink = info->user_ptr[0];
5043 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005044 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005045
5046 reporter = devlink_health_reporter_get_from_info(devlink, info);
5047 if (!reporter)
5048 return -EINVAL;
5049
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005050 err = devlink_health_reporter_recover(reporter, NULL);
5051
5052 devlink_health_reporter_put(reporter);
5053 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005054}
5055
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005056static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
5057 struct genl_info *info)
5058{
5059 struct devlink *devlink = info->user_ptr[0];
5060 struct devlink_health_reporter *reporter;
5061 struct devlink_fmsg *fmsg;
5062 int err;
5063
5064 reporter = devlink_health_reporter_get_from_info(devlink, info);
5065 if (!reporter)
5066 return -EINVAL;
5067
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005068 if (!reporter->ops->diagnose) {
5069 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005070 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005071 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005072
5073 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005074 if (!fmsg) {
5075 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005076 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005077 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005078
5079 err = devlink_fmsg_obj_nest_start(fmsg);
5080 if (err)
5081 goto out;
5082
5083 err = reporter->ops->diagnose(reporter, fmsg);
5084 if (err)
5085 goto out;
5086
5087 err = devlink_fmsg_obj_nest_end(fmsg);
5088 if (err)
5089 goto out;
5090
5091 err = devlink_fmsg_snd(fmsg, info,
5092 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
5093
5094out:
5095 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005096 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005097 return err;
5098}
5099
Aya Levine44ef4e2019-05-16 09:49:20 +03005100static int
5101devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
5102 struct netlink_callback *cb)
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005103{
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005104 struct devlink_health_reporter *reporter;
Aya Levine44ef4e2019-05-16 09:49:20 +03005105 u64 start = cb->args[0];
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005106 int err;
5107
Aya Levine44ef4e2019-05-16 09:49:20 +03005108 reporter = devlink_health_reporter_get_from_cb(cb);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005109 if (!reporter)
5110 return -EINVAL;
5111
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005112 if (!reporter->ops->dump) {
Aya Levine44ef4e2019-05-16 09:49:20 +03005113 err = -EOPNOTSUPP;
5114 goto out;
5115 }
5116 mutex_lock(&reporter->dump_lock);
5117 if (!start) {
5118 err = devlink_health_do_dump(reporter, NULL);
5119 if (err)
5120 goto unlock;
5121 cb->args[1] = reporter->dump_ts;
5122 }
5123 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
5124 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
5125 err = -EAGAIN;
5126 goto unlock;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005127 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005128
Aya Levine44ef4e2019-05-16 09:49:20 +03005129 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
5130 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
5131unlock:
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005132 mutex_unlock(&reporter->dump_lock);
Aya Levine44ef4e2019-05-16 09:49:20 +03005133out:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005134 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005135 return err;
5136}
5137
5138static int
5139devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
5140 struct genl_info *info)
5141{
5142 struct devlink *devlink = info->user_ptr[0];
5143 struct devlink_health_reporter *reporter;
5144
5145 reporter = devlink_health_reporter_get_from_info(devlink, info);
5146 if (!reporter)
5147 return -EINVAL;
5148
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005149 if (!reporter->ops->dump) {
5150 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005151 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005152 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005153
5154 mutex_lock(&reporter->dump_lock);
5155 devlink_health_dump_clear(reporter);
5156 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005157 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005158 return 0;
5159}
5160
Ido Schimmel0f420b62019-08-17 16:28:17 +03005161struct devlink_stats {
5162 u64 rx_bytes;
5163 u64 rx_packets;
5164 struct u64_stats_sync syncp;
5165};
5166
5167/**
5168 * struct devlink_trap_group_item - Packet trap group attributes.
5169 * @group: Immutable packet trap group attributes.
5170 * @refcount: Number of trap items using the group.
5171 * @list: trap_group_list member.
5172 * @stats: Trap group statistics.
5173 *
5174 * Describes packet trap group attributes. Created by devlink during trap
5175 * registration.
5176 */
5177struct devlink_trap_group_item {
5178 const struct devlink_trap_group *group;
5179 refcount_t refcount;
5180 struct list_head list;
5181 struct devlink_stats __percpu *stats;
5182};
5183
5184/**
5185 * struct devlink_trap_item - Packet trap attributes.
5186 * @trap: Immutable packet trap attributes.
5187 * @group_item: Associated group item.
5188 * @list: trap_list member.
5189 * @action: Trap action.
5190 * @stats: Trap statistics.
5191 * @priv: Driver private information.
5192 *
5193 * Describes both mutable and immutable packet trap attributes. Created by
5194 * devlink during trap registration and used for all trap related operations.
5195 */
5196struct devlink_trap_item {
5197 const struct devlink_trap *trap;
5198 struct devlink_trap_group_item *group_item;
5199 struct list_head list;
5200 enum devlink_trap_action action;
5201 struct devlink_stats __percpu *stats;
5202 void *priv;
5203};
5204
5205static struct devlink_trap_item *
5206devlink_trap_item_lookup(struct devlink *devlink, const char *name)
5207{
5208 struct devlink_trap_item *trap_item;
5209
5210 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5211 if (!strcmp(trap_item->trap->name, name))
5212 return trap_item;
5213 }
5214
5215 return NULL;
5216}
5217
5218static struct devlink_trap_item *
5219devlink_trap_item_get_from_info(struct devlink *devlink,
5220 struct genl_info *info)
5221{
5222 struct nlattr *attr;
5223
5224 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
5225 return NULL;
5226 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
5227
5228 return devlink_trap_item_lookup(devlink, nla_data(attr));
5229}
5230
5231static int
5232devlink_trap_action_get_from_info(struct genl_info *info,
5233 enum devlink_trap_action *p_trap_action)
5234{
5235 u8 val;
5236
5237 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
5238 switch (val) {
5239 case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
5240 case DEVLINK_TRAP_ACTION_TRAP:
5241 *p_trap_action = val;
5242 break;
5243 default:
5244 return -EINVAL;
5245 }
5246
5247 return 0;
5248}
5249
5250static int devlink_trap_metadata_put(struct sk_buff *msg,
5251 const struct devlink_trap *trap)
5252{
5253 struct nlattr *attr;
5254
5255 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
5256 if (!attr)
5257 return -EMSGSIZE;
5258
5259 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
5260 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
5261 goto nla_put_failure;
5262
5263 nla_nest_end(msg, attr);
5264
5265 return 0;
5266
5267nla_put_failure:
5268 nla_nest_cancel(msg, attr);
5269 return -EMSGSIZE;
5270}
5271
5272static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
5273 struct devlink_stats *stats)
5274{
5275 int i;
5276
5277 memset(stats, 0, sizeof(*stats));
5278 for_each_possible_cpu(i) {
5279 struct devlink_stats *cpu_stats;
5280 u64 rx_packets, rx_bytes;
5281 unsigned int start;
5282
5283 cpu_stats = per_cpu_ptr(trap_stats, i);
5284 do {
5285 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
5286 rx_packets = cpu_stats->rx_packets;
5287 rx_bytes = cpu_stats->rx_bytes;
5288 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
5289
5290 stats->rx_packets += rx_packets;
5291 stats->rx_bytes += rx_bytes;
5292 }
5293}
5294
5295static int devlink_trap_stats_put(struct sk_buff *msg,
5296 struct devlink_stats __percpu *trap_stats)
5297{
5298 struct devlink_stats stats;
5299 struct nlattr *attr;
5300
5301 devlink_trap_stats_read(trap_stats, &stats);
5302
5303 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
5304 if (!attr)
5305 return -EMSGSIZE;
5306
5307 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
5308 stats.rx_packets, DEVLINK_ATTR_PAD))
5309 goto nla_put_failure;
5310
5311 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
5312 stats.rx_bytes, DEVLINK_ATTR_PAD))
5313 goto nla_put_failure;
5314
5315 nla_nest_end(msg, attr);
5316
5317 return 0;
5318
5319nla_put_failure:
5320 nla_nest_cancel(msg, attr);
5321 return -EMSGSIZE;
5322}
5323
5324static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
5325 const struct devlink_trap_item *trap_item,
5326 enum devlink_command cmd, u32 portid, u32 seq,
5327 int flags)
5328{
5329 struct devlink_trap_group_item *group_item = trap_item->group_item;
5330 void *hdr;
5331 int err;
5332
5333 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5334 if (!hdr)
5335 return -EMSGSIZE;
5336
5337 if (devlink_nl_put_handle(msg, devlink))
5338 goto nla_put_failure;
5339
5340 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
5341 group_item->group->name))
5342 goto nla_put_failure;
5343
5344 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
5345 goto nla_put_failure;
5346
5347 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
5348 goto nla_put_failure;
5349
5350 if (trap_item->trap->generic &&
5351 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
5352 goto nla_put_failure;
5353
5354 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
5355 goto nla_put_failure;
5356
5357 err = devlink_trap_metadata_put(msg, trap_item->trap);
5358 if (err)
5359 goto nla_put_failure;
5360
5361 err = devlink_trap_stats_put(msg, trap_item->stats);
5362 if (err)
5363 goto nla_put_failure;
5364
5365 genlmsg_end(msg, hdr);
5366
5367 return 0;
5368
5369nla_put_failure:
5370 genlmsg_cancel(msg, hdr);
5371 return -EMSGSIZE;
5372}
5373
5374static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
5375 struct genl_info *info)
5376{
5377 struct netlink_ext_ack *extack = info->extack;
5378 struct devlink *devlink = info->user_ptr[0];
5379 struct devlink_trap_item *trap_item;
5380 struct sk_buff *msg;
5381 int err;
5382
5383 if (list_empty(&devlink->trap_list))
5384 return -EOPNOTSUPP;
5385
5386 trap_item = devlink_trap_item_get_from_info(devlink, info);
5387 if (!trap_item) {
5388 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
5389 return -ENOENT;
5390 }
5391
5392 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5393 if (!msg)
5394 return -ENOMEM;
5395
5396 err = devlink_nl_trap_fill(msg, devlink, trap_item,
5397 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
5398 info->snd_seq, 0);
5399 if (err)
5400 goto err_trap_fill;
5401
5402 return genlmsg_reply(msg, info);
5403
5404err_trap_fill:
5405 nlmsg_free(msg);
5406 return err;
5407}
5408
5409static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
5410 struct netlink_callback *cb)
5411{
5412 struct devlink_trap_item *trap_item;
5413 struct devlink *devlink;
5414 int start = cb->args[0];
5415 int idx = 0;
5416 int err;
5417
5418 mutex_lock(&devlink_mutex);
5419 list_for_each_entry(devlink, &devlink_list, list) {
5420 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5421 continue;
5422 mutex_lock(&devlink->lock);
5423 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5424 if (idx < start) {
5425 idx++;
5426 continue;
5427 }
5428 err = devlink_nl_trap_fill(msg, devlink, trap_item,
5429 DEVLINK_CMD_TRAP_NEW,
5430 NETLINK_CB(cb->skb).portid,
5431 cb->nlh->nlmsg_seq,
5432 NLM_F_MULTI);
5433 if (err) {
5434 mutex_unlock(&devlink->lock);
5435 goto out;
5436 }
5437 idx++;
5438 }
5439 mutex_unlock(&devlink->lock);
5440 }
5441out:
5442 mutex_unlock(&devlink_mutex);
5443
5444 cb->args[0] = idx;
5445 return msg->len;
5446}
5447
5448static int __devlink_trap_action_set(struct devlink *devlink,
5449 struct devlink_trap_item *trap_item,
5450 enum devlink_trap_action trap_action,
5451 struct netlink_ext_ack *extack)
5452{
5453 int err;
5454
5455 if (trap_item->action != trap_action &&
5456 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
5457 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
5458 return 0;
5459 }
5460
5461 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
5462 trap_action);
5463 if (err)
5464 return err;
5465
5466 trap_item->action = trap_action;
5467
5468 return 0;
5469}
5470
5471static int devlink_trap_action_set(struct devlink *devlink,
5472 struct devlink_trap_item *trap_item,
5473 struct genl_info *info)
5474{
5475 enum devlink_trap_action trap_action;
5476 int err;
5477
5478 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
5479 return 0;
5480
5481 err = devlink_trap_action_get_from_info(info, &trap_action);
5482 if (err) {
5483 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
5484 return -EINVAL;
5485 }
5486
5487 return __devlink_trap_action_set(devlink, trap_item, trap_action,
5488 info->extack);
5489}
5490
5491static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
5492 struct genl_info *info)
5493{
5494 struct netlink_ext_ack *extack = info->extack;
5495 struct devlink *devlink = info->user_ptr[0];
5496 struct devlink_trap_item *trap_item;
5497 int err;
5498
5499 if (list_empty(&devlink->trap_list))
5500 return -EOPNOTSUPP;
5501
5502 trap_item = devlink_trap_item_get_from_info(devlink, info);
5503 if (!trap_item) {
5504 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
5505 return -ENOENT;
5506 }
5507
5508 err = devlink_trap_action_set(devlink, trap_item, info);
5509 if (err)
5510 return err;
5511
5512 return 0;
5513}
5514
5515static struct devlink_trap_group_item *
5516devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
5517{
5518 struct devlink_trap_group_item *group_item;
5519
5520 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
5521 if (!strcmp(group_item->group->name, name))
5522 return group_item;
5523 }
5524
5525 return NULL;
5526}
5527
5528static struct devlink_trap_group_item *
5529devlink_trap_group_item_get_from_info(struct devlink *devlink,
5530 struct genl_info *info)
5531{
5532 char *name;
5533
5534 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
5535 return NULL;
5536 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
5537
5538 return devlink_trap_group_item_lookup(devlink, name);
5539}
5540
5541static int
5542devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
5543 const struct devlink_trap_group_item *group_item,
5544 enum devlink_command cmd, u32 portid, u32 seq,
5545 int flags)
5546{
5547 void *hdr;
5548 int err;
5549
5550 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5551 if (!hdr)
5552 return -EMSGSIZE;
5553
5554 if (devlink_nl_put_handle(msg, devlink))
5555 goto nla_put_failure;
5556
5557 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
5558 group_item->group->name))
5559 goto nla_put_failure;
5560
5561 if (group_item->group->generic &&
5562 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
5563 goto nla_put_failure;
5564
5565 err = devlink_trap_stats_put(msg, group_item->stats);
5566 if (err)
5567 goto nla_put_failure;
5568
5569 genlmsg_end(msg, hdr);
5570
5571 return 0;
5572
5573nla_put_failure:
5574 genlmsg_cancel(msg, hdr);
5575 return -EMSGSIZE;
5576}
5577
5578static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
5579 struct genl_info *info)
5580{
5581 struct netlink_ext_ack *extack = info->extack;
5582 struct devlink *devlink = info->user_ptr[0];
5583 struct devlink_trap_group_item *group_item;
5584 struct sk_buff *msg;
5585 int err;
5586
5587 if (list_empty(&devlink->trap_group_list))
5588 return -EOPNOTSUPP;
5589
5590 group_item = devlink_trap_group_item_get_from_info(devlink, info);
5591 if (!group_item) {
5592 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
5593 return -ENOENT;
5594 }
5595
5596 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5597 if (!msg)
5598 return -ENOMEM;
5599
5600 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
5601 DEVLINK_CMD_TRAP_GROUP_NEW,
5602 info->snd_portid, info->snd_seq, 0);
5603 if (err)
5604 goto err_trap_group_fill;
5605
5606 return genlmsg_reply(msg, info);
5607
5608err_trap_group_fill:
5609 nlmsg_free(msg);
5610 return err;
5611}
5612
5613static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
5614 struct netlink_callback *cb)
5615{
5616 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
5617 struct devlink_trap_group_item *group_item;
5618 u32 portid = NETLINK_CB(cb->skb).portid;
5619 struct devlink *devlink;
5620 int start = cb->args[0];
5621 int idx = 0;
5622 int err;
5623
5624 mutex_lock(&devlink_mutex);
5625 list_for_each_entry(devlink, &devlink_list, list) {
5626 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5627 continue;
5628 mutex_lock(&devlink->lock);
5629 list_for_each_entry(group_item, &devlink->trap_group_list,
5630 list) {
5631 if (idx < start) {
5632 idx++;
5633 continue;
5634 }
5635 err = devlink_nl_trap_group_fill(msg, devlink,
5636 group_item, cmd,
5637 portid,
5638 cb->nlh->nlmsg_seq,
5639 NLM_F_MULTI);
5640 if (err) {
5641 mutex_unlock(&devlink->lock);
5642 goto out;
5643 }
5644 idx++;
5645 }
5646 mutex_unlock(&devlink->lock);
5647 }
5648out:
5649 mutex_unlock(&devlink_mutex);
5650
5651 cb->args[0] = idx;
5652 return msg->len;
5653}
5654
5655static int
5656__devlink_trap_group_action_set(struct devlink *devlink,
5657 struct devlink_trap_group_item *group_item,
5658 enum devlink_trap_action trap_action,
5659 struct netlink_ext_ack *extack)
5660{
5661 const char *group_name = group_item->group->name;
5662 struct devlink_trap_item *trap_item;
5663 int err;
5664
5665 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5666 if (strcmp(trap_item->trap->group.name, group_name))
5667 continue;
5668 err = __devlink_trap_action_set(devlink, trap_item,
5669 trap_action, extack);
5670 if (err)
5671 return err;
5672 }
5673
5674 return 0;
5675}
5676
5677static int
5678devlink_trap_group_action_set(struct devlink *devlink,
5679 struct devlink_trap_group_item *group_item,
5680 struct genl_info *info)
5681{
5682 enum devlink_trap_action trap_action;
5683 int err;
5684
5685 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
5686 return 0;
5687
5688 err = devlink_trap_action_get_from_info(info, &trap_action);
5689 if (err) {
5690 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
5691 return -EINVAL;
5692 }
5693
5694 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
5695 info->extack);
5696 if (err)
5697 return err;
5698
5699 return 0;
5700}
5701
5702static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
5703 struct genl_info *info)
5704{
5705 struct netlink_ext_ack *extack = info->extack;
5706 struct devlink *devlink = info->user_ptr[0];
5707 struct devlink_trap_group_item *group_item;
5708 int err;
5709
5710 if (list_empty(&devlink->trap_group_list))
5711 return -EOPNOTSUPP;
5712
5713 group_item = devlink_trap_group_item_get_from_info(devlink, info);
5714 if (!group_item) {
5715 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
5716 return -ENOENT;
5717 }
5718
5719 err = devlink_trap_group_action_set(devlink, group_item, info);
5720 if (err)
5721 return err;
5722
5723 return 0;
5724}
5725
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005726static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
5727 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
5728 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
5729 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
5730 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
5731 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02005732 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
5733 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
5734 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
5735 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
5736 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
5737 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
5738 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03005739 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
Roi Dayan59bfde02016-11-22 23:09:57 +02005740 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03005741 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005742 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
5743 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005744 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
5745 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005746 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
5747 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
5748 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005749 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03005750 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005751 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005752 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
5753 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08005754 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
5755 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Ido Schimmel0f420b62019-08-17 16:28:17 +03005756 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
5757 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
5758 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005759};
5760
5761static const struct genl_ops devlink_nl_ops[] = {
5762 {
5763 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005764 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005765 .doit = devlink_nl_cmd_get_doit,
5766 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirko1fc22572016-04-08 19:12:48 +02005767 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005768 /* can be retrieved by unprivileged users */
5769 },
5770 {
5771 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005772 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005773 .doit = devlink_nl_cmd_port_get_doit,
5774 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005775 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5776 /* can be retrieved by unprivileged users */
5777 },
5778 {
5779 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005780 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005781 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005782 .flags = GENL_ADMIN_PERM,
5783 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5784 },
5785 {
5786 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02005787 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005788 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005789 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005790 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5791 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005792 },
5793 {
5794 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02005795 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005796 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005797 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005798 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5799 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005800 },
Jiri Pirkobf797472016-04-14 18:19:13 +02005801 {
5802 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005803 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005804 .doit = devlink_nl_cmd_sb_get_doit,
5805 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005806 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5807 DEVLINK_NL_FLAG_NEED_SB,
5808 /* can be retrieved by unprivileged users */
5809 },
5810 {
5811 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005812 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005813 .doit = devlink_nl_cmd_sb_pool_get_doit,
5814 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005815 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5816 DEVLINK_NL_FLAG_NEED_SB,
5817 /* can be retrieved by unprivileged users */
5818 },
5819 {
5820 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005821 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005822 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005823 .flags = GENL_ADMIN_PERM,
5824 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5825 DEVLINK_NL_FLAG_NEED_SB,
5826 },
5827 {
5828 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005829 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005830 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
5831 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005832 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5833 DEVLINK_NL_FLAG_NEED_SB,
5834 /* can be retrieved by unprivileged users */
5835 },
5836 {
5837 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005838 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005839 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005840 .flags = GENL_ADMIN_PERM,
5841 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5842 DEVLINK_NL_FLAG_NEED_SB,
5843 },
5844 {
5845 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005846 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005847 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
5848 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005849 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5850 DEVLINK_NL_FLAG_NEED_SB,
5851 /* can be retrieved by unprivileged users */
5852 },
5853 {
5854 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005855 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005856 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005857 .flags = GENL_ADMIN_PERM,
5858 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5859 DEVLINK_NL_FLAG_NEED_SB,
5860 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005861 {
5862 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02005863 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005864 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005865 .flags = GENL_ADMIN_PERM,
5866 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005867 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005868 },
5869 {
5870 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02005871 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005872 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005873 .flags = GENL_ADMIN_PERM,
5874 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005875 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005876 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03005877 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005878 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005879 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005880 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005881 .flags = GENL_ADMIN_PERM,
5882 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5883 },
5884 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005885 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005886 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005887 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005888 .flags = GENL_ADMIN_PERM,
Jakub Kicinski7ac1cc92018-05-21 22:12:50 -07005889 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5890 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005891 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005892 {
5893 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005894 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005895 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005896 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005897 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005898 },
5899 {
5900 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005901 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005902 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005903 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005904 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005905 },
5906 {
5907 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005908 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005909 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005910 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005911 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005912 },
5913 {
5914 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005915 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005916 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005917 .flags = GENL_ADMIN_PERM,
5918 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5919 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005920 {
5921 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005922 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005923 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005924 .flags = GENL_ADMIN_PERM,
5925 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5926 },
5927 {
5928 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02005929 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005930 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005931 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005932 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005933 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005934 {
5935 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02005936 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005937 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005938 .flags = GENL_ADMIN_PERM,
5939 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5940 DEVLINK_NL_FLAG_NO_LOCK,
5941 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005942 {
5943 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005944 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005945 .doit = devlink_nl_cmd_param_get_doit,
5946 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005947 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5948 /* can be retrieved by unprivileged users */
5949 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005950 {
5951 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005952 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005953 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005954 .flags = GENL_ADMIN_PERM,
5955 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5956 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005957 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305958 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005959 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305960 .doit = devlink_nl_cmd_port_param_get_doit,
5961 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305962 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5963 /* can be retrieved by unprivileged users */
5964 },
5965 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05305966 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005967 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05305968 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05305969 .flags = GENL_ADMIN_PERM,
5970 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5971 },
5972 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005973 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005974 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005975 .doit = devlink_nl_cmd_region_get_doit,
5976 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005977 .flags = GENL_ADMIN_PERM,
5978 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5979 },
Alex Vesker866319b2018-07-12 15:13:13 +03005980 {
5981 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02005982 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03005983 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03005984 .flags = GENL_ADMIN_PERM,
5985 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5986 },
Alex Vesker4e547952018-07-12 15:13:14 +03005987 {
5988 .cmd = DEVLINK_CMD_REGION_READ,
Johannes Bergef6243a2019-04-26 14:07:31 +02005989 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker4e547952018-07-12 15:13:14 +03005990 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03005991 .flags = GENL_ADMIN_PERM,
5992 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5993 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005994 {
5995 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005996 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005997 .doit = devlink_nl_cmd_info_get_doit,
5998 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005999 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6000 /* can be retrieved by unprivileged users */
6001 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006002 {
6003 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006004 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006005 .doit = devlink_nl_cmd_health_reporter_get_doit,
6006 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006007 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6008 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02006009 /* can be retrieved by unprivileged users */
6010 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006011 {
6012 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006013 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006014 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006015 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006016 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6017 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02006018 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006019 {
6020 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02006021 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006022 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006023 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006024 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6025 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02006026 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006027 {
6028 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02006029 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006030 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006031 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006032 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6033 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02006034 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006035 {
6036 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02006037 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Aya Levine44ef4e2019-05-16 09:49:20 +03006038 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006039 .flags = GENL_ADMIN_PERM,
6040 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6041 DEVLINK_NL_FLAG_NO_LOCK,
6042 },
6043 {
6044 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02006045 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006046 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02006047 .flags = GENL_ADMIN_PERM,
6048 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
6049 DEVLINK_NL_FLAG_NO_LOCK,
6050 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08006051 {
6052 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02006053 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08006054 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08006055 .flags = GENL_ADMIN_PERM,
6056 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6057 },
Ido Schimmel0f420b62019-08-17 16:28:17 +03006058 {
6059 .cmd = DEVLINK_CMD_TRAP_GET,
6060 .doit = devlink_nl_cmd_trap_get_doit,
6061 .dumpit = devlink_nl_cmd_trap_get_dumpit,
6062 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6063 /* can be retrieved by unprivileged users */
6064 },
6065 {
6066 .cmd = DEVLINK_CMD_TRAP_SET,
6067 .doit = devlink_nl_cmd_trap_set_doit,
6068 .flags = GENL_ADMIN_PERM,
6069 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6070 },
6071 {
6072 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
6073 .doit = devlink_nl_cmd_trap_group_get_doit,
6074 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
6075 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6076 /* can be retrieved by unprivileged users */
6077 },
6078 {
6079 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
6080 .doit = devlink_nl_cmd_trap_group_set_doit,
6081 .flags = GENL_ADMIN_PERM,
6082 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6083 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006084};
6085
Johannes Berg56989f62016-10-24 14:40:05 +02006086static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02006087 .name = DEVLINK_GENL_NAME,
6088 .version = DEVLINK_GENL_VERSION,
6089 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01006090 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02006091 .netnsok = true,
6092 .pre_doit = devlink_nl_pre_doit,
6093 .post_doit = devlink_nl_post_doit,
6094 .module = THIS_MODULE,
6095 .ops = devlink_nl_ops,
6096 .n_ops = ARRAY_SIZE(devlink_nl_ops),
6097 .mcgrps = devlink_nl_mcgrps,
6098 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
6099};
6100
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006101/**
6102 * devlink_alloc - Allocate new devlink instance resources
6103 *
6104 * @ops: ops
6105 * @priv_size: size of user private data
6106 *
6107 * Allocate new devlink instance resources, including devlink index
6108 * and name.
6109 */
6110struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
6111{
6112 struct devlink *devlink;
6113
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08006114 if (WARN_ON(!ops))
6115 return NULL;
6116
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006117 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
6118 if (!devlink)
6119 return NULL;
6120 devlink->ops = ops;
6121 devlink_net_set(devlink, &init_net);
6122 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02006123 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006124 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006125 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03006126 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03006127 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02006128 INIT_LIST_HEAD(&devlink->reporter_list);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006129 INIT_LIST_HEAD(&devlink->trap_list);
6130 INIT_LIST_HEAD(&devlink->trap_group_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006131 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006132 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006133 return devlink;
6134}
6135EXPORT_SYMBOL_GPL(devlink_alloc);
6136
6137/**
6138 * devlink_register - Register devlink instance
6139 *
6140 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08006141 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006142 */
6143int devlink_register(struct devlink *devlink, struct device *dev)
6144{
6145 mutex_lock(&devlink_mutex);
6146 devlink->dev = dev;
6147 list_add_tail(&devlink->list, &devlink_list);
6148 devlink_notify(devlink, DEVLINK_CMD_NEW);
6149 mutex_unlock(&devlink_mutex);
6150 return 0;
6151}
6152EXPORT_SYMBOL_GPL(devlink_register);
6153
6154/**
6155 * devlink_unregister - Unregister devlink instance
6156 *
6157 * @devlink: devlink
6158 */
6159void devlink_unregister(struct devlink *devlink)
6160{
6161 mutex_lock(&devlink_mutex);
6162 devlink_notify(devlink, DEVLINK_CMD_DEL);
6163 list_del(&devlink->list);
6164 mutex_unlock(&devlink_mutex);
6165}
6166EXPORT_SYMBOL_GPL(devlink_unregister);
6167
6168/**
6169 * devlink_free - Free devlink instance resources
6170 *
6171 * @devlink: devlink
6172 */
6173void devlink_free(struct devlink *devlink)
6174{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03006175 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01006176 mutex_destroy(&devlink->lock);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006177 WARN_ON(!list_empty(&devlink->trap_group_list));
6178 WARN_ON(!list_empty(&devlink->trap_list));
Parav Panditb904aad2019-02-08 15:15:00 -06006179 WARN_ON(!list_empty(&devlink->reporter_list));
6180 WARN_ON(!list_empty(&devlink->region_list));
6181 WARN_ON(!list_empty(&devlink->param_list));
6182 WARN_ON(!list_empty(&devlink->resource_list));
6183 WARN_ON(!list_empty(&devlink->dpipe_table_list));
6184 WARN_ON(!list_empty(&devlink->sb_list));
6185 WARN_ON(!list_empty(&devlink->port_list));
6186
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006187 kfree(devlink);
6188}
6189EXPORT_SYMBOL_GPL(devlink_free);
6190
Jiri Pirko136bf272019-05-23 10:43:35 +02006191static void devlink_port_type_warn(struct work_struct *work)
6192{
6193 WARN(true, "Type was not set for devlink port.");
6194}
6195
6196static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
6197{
6198 /* Ignore CPU and DSA flavours. */
6199 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
6200 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
6201}
6202
6203#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 30)
6204
6205static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
6206{
6207 if (!devlink_port_type_should_warn(devlink_port))
6208 return;
6209 /* Schedule a work to WARN in case driver does not set port
6210 * type within timeout.
6211 */
6212 schedule_delayed_work(&devlink_port->type_warn_dw,
6213 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
6214}
6215
6216static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
6217{
6218 if (!devlink_port_type_should_warn(devlink_port))
6219 return;
6220 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
6221}
6222
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006223/**
6224 * devlink_port_register - Register devlink port
6225 *
6226 * @devlink: devlink
6227 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08006228 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006229 *
6230 * Register devlink port with provided port index. User can use
6231 * any indexing, even hw-related one. devlink_port structure
6232 * is convenient to be embedded inside user driver private structure.
6233 * Note that the caller should take care of zeroing the devlink_port
6234 * structure.
6235 */
6236int devlink_port_register(struct devlink *devlink,
6237 struct devlink_port *devlink_port,
6238 unsigned int port_index)
6239{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006240 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006241 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006242 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006243 return -EEXIST;
6244 }
6245 devlink_port->devlink = devlink;
6246 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006247 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01006248 spin_lock_init(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006249 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306250 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006251 mutex_unlock(&devlink->lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02006252 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
6253 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006254 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
6255 return 0;
6256}
6257EXPORT_SYMBOL_GPL(devlink_port_register);
6258
6259/**
6260 * devlink_port_unregister - Unregister devlink port
6261 *
6262 * @devlink_port: devlink port
6263 */
6264void devlink_port_unregister(struct devlink_port *devlink_port)
6265{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006266 struct devlink *devlink = devlink_port->devlink;
6267
Jiri Pirko136bf272019-05-23 10:43:35 +02006268 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006269 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006270 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006271 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006272 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006273}
6274EXPORT_SYMBOL_GPL(devlink_port_unregister);
6275
6276static void __devlink_port_type_set(struct devlink_port *devlink_port,
6277 enum devlink_port_type type,
6278 void *type_dev)
6279{
Jiri Pirko2b239e72019-03-24 11:14:36 +01006280 if (WARN_ON(!devlink_port->registered))
6281 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02006282 devlink_port_type_warn_cancel(devlink_port);
Ido Schimmel0f420b62019-08-17 16:28:17 +03006283 spin_lock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006284 devlink_port->type = type;
6285 devlink_port->type_dev = type_dev;
Ido Schimmel0f420b62019-08-17 16:28:17 +03006286 spin_unlock_bh(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006287 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
6288}
6289
6290/**
6291 * devlink_port_type_eth_set - Set port type to Ethernet
6292 *
6293 * @devlink_port: devlink port
6294 * @netdev: related netdevice
6295 */
6296void devlink_port_type_eth_set(struct devlink_port *devlink_port,
6297 struct net_device *netdev)
6298{
Jiri Pirko119c0b52019-04-03 14:24:27 +02006299 const struct net_device_ops *ops = netdev->netdev_ops;
6300
Jiri Pirko746364f2019-03-28 13:56:46 +01006301 /* If driver registers devlink port, it should set devlink port
6302 * attributes accordingly so the compat functions are called
6303 * and the original ops are not used.
6304 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02006305 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01006306 /* Some drivers use the same set of ndos for netdevs
6307 * that have devlink_port registered and also for
6308 * those who don't. Make sure that ndo_get_phys_port_name
6309 * returns -EOPNOTSUPP here in case it is defined.
6310 * Warn if not.
6311 */
Jiri Pirko746364f2019-03-28 13:56:46 +01006312 char name[IFNAMSIZ];
6313 int err;
6314
6315 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
6316 WARN_ON(err != -EOPNOTSUPP);
6317 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02006318 if (ops->ndo_get_port_parent_id) {
6319 /* Some drivers use the same set of ndos for netdevs
6320 * that have devlink_port registered and also for
6321 * those who don't. Make sure that ndo_get_port_parent_id
6322 * returns -EOPNOTSUPP here in case it is defined.
6323 * Warn if not.
6324 */
6325 struct netdev_phys_item_id ppid;
6326 int err;
6327
6328 err = ops->ndo_get_port_parent_id(netdev, &ppid);
6329 WARN_ON(err != -EOPNOTSUPP);
6330 }
Jiri Pirko773b1f32019-03-24 11:14:30 +01006331 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006332}
6333EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
6334
6335/**
6336 * devlink_port_type_ib_set - Set port type to InfiniBand
6337 *
6338 * @devlink_port: devlink port
6339 * @ibdev: related IB device
6340 */
6341void devlink_port_type_ib_set(struct devlink_port *devlink_port,
6342 struct ib_device *ibdev)
6343{
Jiri Pirko773b1f32019-03-24 11:14:30 +01006344 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006345}
6346EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
6347
6348/**
6349 * devlink_port_type_clear - Clear port type
6350 *
6351 * @devlink_port: devlink port
6352 */
6353void devlink_port_type_clear(struct devlink_port *devlink_port)
6354{
Jiri Pirko773b1f32019-03-24 11:14:30 +01006355 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02006356 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006357}
6358EXPORT_SYMBOL_GPL(devlink_port_type_clear);
6359
Parav Pandit378ef012019-07-08 23:17:35 -05006360static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
6361 enum devlink_port_flavour flavour,
6362 const unsigned char *switch_id,
6363 unsigned char switch_id_len)
6364{
6365 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6366
6367 if (WARN_ON(devlink_port->registered))
6368 return -EEXIST;
6369 attrs->set = true;
6370 attrs->flavour = flavour;
6371 if (switch_id) {
6372 attrs->switch_port = true;
6373 if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
6374 switch_id_len = MAX_PHYS_ITEM_ID_LEN;
6375 memcpy(attrs->switch_id.id, switch_id, switch_id_len);
6376 attrs->switch_id.id_len = switch_id_len;
6377 } else {
6378 attrs->switch_port = false;
6379 }
6380 return 0;
6381}
6382
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006383/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02006384 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006385 *
6386 * @devlink_port: devlink port
Jiri Pirko5ec13802018-05-18 09:29:01 +02006387 * @flavour: flavour of the port
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02006388 * @port_number: number of the port that is facing user, for example
6389 * the front panel port number
6390 * @split: indicates if this is split port
6391 * @split_subport_number: if the port is split, this is the number
6392 * of subport.
Jiri Pirkobec52672019-04-03 14:24:16 +02006393 * @switch_id: if the port is part of switch, this is buffer with ID,
6394 * otwerwise this is NULL
6395 * @switch_id_len: length of the switch_id buffer
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006396 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02006397void devlink_port_attrs_set(struct devlink_port *devlink_port,
Jiri Pirko5ec13802018-05-18 09:29:01 +02006398 enum devlink_port_flavour flavour,
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02006399 u32 port_number, bool split,
Jiri Pirkobec52672019-04-03 14:24:16 +02006400 u32 split_subport_number,
6401 const unsigned char *switch_id,
6402 unsigned char switch_id_len)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006403{
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02006404 struct devlink_port_attrs *attrs = &devlink_port->attrs;
Parav Pandit378ef012019-07-08 23:17:35 -05006405 int ret;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02006406
Parav Pandit378ef012019-07-08 23:17:35 -05006407 ret = __devlink_port_attrs_set(devlink_port, flavour,
6408 switch_id, switch_id_len);
6409 if (ret)
Jiri Pirko45b86112019-03-24 11:14:33 +01006410 return;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02006411 attrs->split = split;
Parav Pandit378ef012019-07-08 23:17:35 -05006412 attrs->phys.port_number = port_number;
6413 attrs->phys.split_subport_number = split_subport_number;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006414}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02006415EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006416
Parav Pandit98fd2d62019-07-08 23:17:37 -05006417/**
6418 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
6419 *
6420 * @devlink_port: devlink port
6421 * @pf: associated PF for the devlink port instance
6422 * @switch_id: if the port is part of switch, this is buffer with ID,
6423 * otherwise this is NULL
6424 * @switch_id_len: length of the switch_id buffer
6425 */
6426void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port,
6427 const unsigned char *switch_id,
6428 unsigned char switch_id_len, u16 pf)
6429{
6430 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6431 int ret;
6432
6433 ret = __devlink_port_attrs_set(devlink_port,
6434 DEVLINK_PORT_FLAVOUR_PCI_PF,
6435 switch_id, switch_id_len);
6436 if (ret)
6437 return;
6438
6439 attrs->pci_pf.pf = pf;
6440}
6441EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
6442
Parav Pandite41b6bf2019-07-08 23:17:38 -05006443/**
6444 * devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
6445 *
6446 * @devlink_port: devlink port
6447 * @pf: associated PF for the devlink port instance
6448 * @vf: associated VF of a PF for the devlink port instance
6449 * @switch_id: if the port is part of switch, this is buffer with ID,
6450 * otherwise this is NULL
6451 * @switch_id_len: length of the switch_id buffer
6452 */
6453void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
6454 const unsigned char *switch_id,
6455 unsigned char switch_id_len,
6456 u16 pf, u16 vf)
6457{
6458 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6459 int ret;
6460
6461 ret = __devlink_port_attrs_set(devlink_port,
6462 DEVLINK_PORT_FLAVOUR_PCI_VF,
6463 switch_id, switch_id_len);
6464 if (ret)
6465 return;
6466 attrs->pci_vf.pf = pf;
6467 attrs->pci_vf.vf = vf;
6468}
6469EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
6470
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01006471static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
6472 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02006473{
6474 struct devlink_port_attrs *attrs = &devlink_port->attrs;
6475 int n = 0;
6476
6477 if (!attrs->set)
6478 return -EOPNOTSUPP;
6479
6480 switch (attrs->flavour) {
6481 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
6482 if (!attrs->split)
Parav Pandit378ef012019-07-08 23:17:35 -05006483 n = snprintf(name, len, "p%u", attrs->phys.port_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02006484 else
Parav Pandit378ef012019-07-08 23:17:35 -05006485 n = snprintf(name, len, "p%us%u",
6486 attrs->phys.port_number,
6487 attrs->phys.split_subport_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02006488 break;
6489 case DEVLINK_PORT_FLAVOUR_CPU:
6490 case DEVLINK_PORT_FLAVOUR_DSA:
6491 /* As CPU and DSA ports do not have a netdevice associated
6492 * case should not ever happen.
6493 */
6494 WARN_ON(1);
6495 return -EINVAL;
Parav Pandit98fd2d62019-07-08 23:17:37 -05006496 case DEVLINK_PORT_FLAVOUR_PCI_PF:
6497 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
6498 break;
Parav Pandite41b6bf2019-07-08 23:17:38 -05006499 case DEVLINK_PORT_FLAVOUR_PCI_VF:
6500 n = snprintf(name, len, "pf%uvf%u",
6501 attrs->pci_vf.pf, attrs->pci_vf.vf);
6502 break;
Jiri Pirko08474c12018-05-18 09:29:02 +02006503 }
6504
6505 if (n >= len)
6506 return -EINVAL;
6507
6508 return 0;
6509}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01006510
Jiri Pirkobf797472016-04-14 18:19:13 +02006511int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
6512 u32 size, u16 ingress_pools_count,
6513 u16 egress_pools_count, u16 ingress_tc_count,
6514 u16 egress_tc_count)
6515{
6516 struct devlink_sb *devlink_sb;
6517 int err = 0;
6518
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006519 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02006520 if (devlink_sb_index_exists(devlink, sb_index)) {
6521 err = -EEXIST;
6522 goto unlock;
6523 }
6524
6525 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
6526 if (!devlink_sb) {
6527 err = -ENOMEM;
6528 goto unlock;
6529 }
6530 devlink_sb->index = sb_index;
6531 devlink_sb->size = size;
6532 devlink_sb->ingress_pools_count = ingress_pools_count;
6533 devlink_sb->egress_pools_count = egress_pools_count;
6534 devlink_sb->ingress_tc_count = ingress_tc_count;
6535 devlink_sb->egress_tc_count = egress_tc_count;
6536 list_add_tail(&devlink_sb->list, &devlink->sb_list);
6537unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006538 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02006539 return err;
6540}
6541EXPORT_SYMBOL_GPL(devlink_sb_register);
6542
6543void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
6544{
6545 struct devlink_sb *devlink_sb;
6546
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006547 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02006548 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
6549 WARN_ON(!devlink_sb);
6550 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006551 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02006552 kfree(devlink_sb);
6553}
6554EXPORT_SYMBOL_GPL(devlink_sb_unregister);
6555
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006556/**
6557 * devlink_dpipe_headers_register - register dpipe headers
6558 *
6559 * @devlink: devlink
6560 * @dpipe_headers: dpipe header array
6561 *
6562 * Register the headers supported by hardware.
6563 */
6564int devlink_dpipe_headers_register(struct devlink *devlink,
6565 struct devlink_dpipe_headers *dpipe_headers)
6566{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006567 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006568 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006569 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006570 return 0;
6571}
6572EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
6573
6574/**
6575 * devlink_dpipe_headers_unregister - unregister dpipe headers
6576 *
6577 * @devlink: devlink
6578 *
6579 * Unregister the headers supported by hardware.
6580 */
6581void devlink_dpipe_headers_unregister(struct devlink *devlink)
6582{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006583 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006584 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006585 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006586}
6587EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
6588
6589/**
6590 * devlink_dpipe_table_counter_enabled - check if counter allocation
6591 * required
6592 * @devlink: devlink
6593 * @table_name: tables name
6594 *
6595 * Used by driver to check if counter allocation is required.
6596 * After counter allocation is turned on the table entries
6597 * are updated to include counter statistics.
6598 *
6599 * After that point on the driver must respect the counter
6600 * state so that each entry added to the table is added
6601 * with a counter.
6602 */
6603bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
6604 const char *table_name)
6605{
6606 struct devlink_dpipe_table *table;
6607 bool enabled;
6608
6609 rcu_read_lock();
6610 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6611 table_name);
6612 enabled = false;
6613 if (table)
6614 enabled = table->counters_enabled;
6615 rcu_read_unlock();
6616 return enabled;
6617}
6618EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
6619
6620/**
6621 * devlink_dpipe_table_register - register dpipe table
6622 *
6623 * @devlink: devlink
6624 * @table_name: table name
6625 * @table_ops: table ops
6626 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006627 * @counter_control_extern: external control for counters
6628 */
6629int devlink_dpipe_table_register(struct devlink *devlink,
6630 const char *table_name,
6631 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02006632 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006633{
6634 struct devlink_dpipe_table *table;
6635
6636 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
6637 return -EEXIST;
6638
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02006639 if (WARN_ON(!table_ops->size_get))
6640 return -EINVAL;
6641
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006642 table = kzalloc(sizeof(*table), GFP_KERNEL);
6643 if (!table)
6644 return -ENOMEM;
6645
6646 table->name = table_name;
6647 table->table_ops = table_ops;
6648 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006649 table->counter_control_extern = counter_control_extern;
6650
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006651 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006652 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006653 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006654 return 0;
6655}
6656EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
6657
6658/**
6659 * devlink_dpipe_table_unregister - unregister dpipe table
6660 *
6661 * @devlink: devlink
6662 * @table_name: table name
6663 */
6664void devlink_dpipe_table_unregister(struct devlink *devlink,
6665 const char *table_name)
6666{
6667 struct devlink_dpipe_table *table;
6668
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006669 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006670 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6671 table_name);
6672 if (!table)
6673 goto unlock;
6674 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006675 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006676 kfree_rcu(table, rcu);
6677 return;
6678unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006679 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006680}
6681EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
6682
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006683/**
6684 * devlink_resource_register - devlink resource register
6685 *
6686 * @devlink: devlink
6687 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006688 * @resource_size: resource's size
6689 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08006690 * @parent_resource_id: resource's parent id
6691 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006692 */
6693int devlink_resource_register(struct devlink *devlink,
6694 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006695 u64 resource_size,
6696 u64 resource_id,
6697 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02006698 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006699{
6700 struct devlink_resource *resource;
6701 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07006702 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006703 int err = 0;
6704
David Ahern14530742018-03-20 19:31:14 -07006705 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
6706
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006707 mutex_lock(&devlink->lock);
6708 resource = devlink_resource_find(devlink, NULL, resource_id);
6709 if (resource) {
6710 err = -EINVAL;
6711 goto out;
6712 }
6713
6714 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
6715 if (!resource) {
6716 err = -ENOMEM;
6717 goto out;
6718 }
6719
6720 if (top_hierarchy) {
6721 resource_list = &devlink->resource_list;
6722 } else {
6723 struct devlink_resource *parent_resource;
6724
6725 parent_resource = devlink_resource_find(devlink, NULL,
6726 parent_resource_id);
6727 if (parent_resource) {
6728 resource_list = &parent_resource->resource_list;
6729 resource->parent = parent_resource;
6730 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00006731 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006732 err = -EINVAL;
6733 goto out;
6734 }
6735 }
6736
6737 resource->name = resource_name;
6738 resource->size = resource_size;
6739 resource->size_new = resource_size;
6740 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006741 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01006742 memcpy(&resource->size_params, size_params,
6743 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006744 INIT_LIST_HEAD(&resource->resource_list);
6745 list_add_tail(&resource->list, resource_list);
6746out:
6747 mutex_unlock(&devlink->lock);
6748 return err;
6749}
6750EXPORT_SYMBOL_GPL(devlink_resource_register);
6751
6752/**
6753 * devlink_resources_unregister - free all resources
6754 *
6755 * @devlink: devlink
6756 * @resource: resource
6757 */
6758void devlink_resources_unregister(struct devlink *devlink,
6759 struct devlink_resource *resource)
6760{
6761 struct devlink_resource *tmp, *child_resource;
6762 struct list_head *resource_list;
6763
6764 if (resource)
6765 resource_list = &resource->resource_list;
6766 else
6767 resource_list = &devlink->resource_list;
6768
6769 if (!resource)
6770 mutex_lock(&devlink->lock);
6771
6772 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
6773 devlink_resources_unregister(devlink, child_resource);
6774 list_del(&child_resource->list);
6775 kfree(child_resource);
6776 }
6777
6778 if (!resource)
6779 mutex_unlock(&devlink->lock);
6780}
6781EXPORT_SYMBOL_GPL(devlink_resources_unregister);
6782
6783/**
6784 * devlink_resource_size_get - get and update size
6785 *
6786 * @devlink: devlink
6787 * @resource_id: the requested resource id
6788 * @p_resource_size: ptr to update
6789 */
6790int devlink_resource_size_get(struct devlink *devlink,
6791 u64 resource_id,
6792 u64 *p_resource_size)
6793{
6794 struct devlink_resource *resource;
6795 int err = 0;
6796
6797 mutex_lock(&devlink->lock);
6798 resource = devlink_resource_find(devlink, NULL, resource_id);
6799 if (!resource) {
6800 err = -EINVAL;
6801 goto out;
6802 }
6803 *p_resource_size = resource->size_new;
6804 resource->size = resource->size_new;
6805out:
6806 mutex_unlock(&devlink->lock);
6807 return err;
6808}
6809EXPORT_SYMBOL_GPL(devlink_resource_size_get);
6810
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01006811/**
6812 * devlink_dpipe_table_resource_set - set the resource id
6813 *
6814 * @devlink: devlink
6815 * @table_name: table name
6816 * @resource_id: resource id
6817 * @resource_units: number of resource's units consumed per table's entry
6818 */
6819int devlink_dpipe_table_resource_set(struct devlink *devlink,
6820 const char *table_name, u64 resource_id,
6821 u64 resource_units)
6822{
6823 struct devlink_dpipe_table *table;
6824 int err = 0;
6825
6826 mutex_lock(&devlink->lock);
6827 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6828 table_name);
6829 if (!table) {
6830 err = -EINVAL;
6831 goto out;
6832 }
6833 table->resource_id = resource_id;
6834 table->resource_units = resource_units;
6835 table->resource_valid = true;
6836out:
6837 mutex_unlock(&devlink->lock);
6838 return err;
6839}
6840EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
6841
Jiri Pirkofc56be42018-04-05 22:13:21 +02006842/**
6843 * devlink_resource_occ_get_register - register occupancy getter
6844 *
6845 * @devlink: devlink
6846 * @resource_id: resource id
6847 * @occ_get: occupancy getter callback
6848 * @occ_get_priv: occupancy getter callback priv
6849 */
6850void devlink_resource_occ_get_register(struct devlink *devlink,
6851 u64 resource_id,
6852 devlink_resource_occ_get_t *occ_get,
6853 void *occ_get_priv)
6854{
6855 struct devlink_resource *resource;
6856
6857 mutex_lock(&devlink->lock);
6858 resource = devlink_resource_find(devlink, NULL, resource_id);
6859 if (WARN_ON(!resource))
6860 goto out;
6861 WARN_ON(resource->occ_get);
6862
6863 resource->occ_get = occ_get;
6864 resource->occ_get_priv = occ_get_priv;
6865out:
6866 mutex_unlock(&devlink->lock);
6867}
6868EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
6869
6870/**
6871 * devlink_resource_occ_get_unregister - unregister occupancy getter
6872 *
6873 * @devlink: devlink
6874 * @resource_id: resource id
6875 */
6876void devlink_resource_occ_get_unregister(struct devlink *devlink,
6877 u64 resource_id)
6878{
6879 struct devlink_resource *resource;
6880
6881 mutex_lock(&devlink->lock);
6882 resource = devlink_resource_find(devlink, NULL, resource_id);
6883 if (WARN_ON(!resource))
6884 goto out;
6885 WARN_ON(!resource->occ_get);
6886
6887 resource->occ_get = NULL;
6888 resource->occ_get_priv = NULL;
6889out:
6890 mutex_unlock(&devlink->lock);
6891}
6892EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
6893
Vasundhara Volam39e61602019-01-28 18:00:20 +05306894static int devlink_param_verify(const struct devlink_param *param)
6895{
6896 if (!param || !param->name || !param->supported_cmodes)
6897 return -EINVAL;
6898 if (param->generic)
6899 return devlink_param_generic_verify(param);
6900 else
6901 return devlink_param_driver_verify(param);
6902}
6903
6904static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306905 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306906 struct list_head *param_list,
6907 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306908 size_t params_count,
6909 enum devlink_command reg_cmd,
6910 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05306911{
6912 const struct devlink_param *param = params;
6913 int i;
6914 int err;
6915
6916 mutex_lock(&devlink->lock);
6917 for (i = 0; i < params_count; i++, param++) {
6918 err = devlink_param_verify(param);
6919 if (err)
6920 goto rollback;
6921
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306922 err = devlink_param_register_one(devlink, port_index,
6923 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306924 if (err)
6925 goto rollback;
6926 }
6927
6928 mutex_unlock(&devlink->lock);
6929 return 0;
6930
6931rollback:
6932 if (!i)
6933 goto unlock;
6934 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306935 devlink_param_unregister_one(devlink, port_index, param_list,
6936 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306937unlock:
6938 mutex_unlock(&devlink->lock);
6939 return err;
6940}
6941
6942static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306943 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306944 struct list_head *param_list,
6945 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306946 size_t params_count,
6947 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05306948{
6949 const struct devlink_param *param = params;
6950 int i;
6951
6952 mutex_lock(&devlink->lock);
6953 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306954 devlink_param_unregister_one(devlink, 0, param_list, param,
6955 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306956 mutex_unlock(&devlink->lock);
6957}
6958
Moshe Shemesheabaef12018-07-04 14:30:28 +03006959/**
6960 * devlink_params_register - register configuration parameters
6961 *
6962 * @devlink: devlink
6963 * @params: configuration parameters array
6964 * @params_count: number of parameters provided
6965 *
6966 * Register the configuration parameters supported by the driver.
6967 */
6968int devlink_params_register(struct devlink *devlink,
6969 const struct devlink_param *params,
6970 size_t params_count)
6971{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306972 return __devlink_params_register(devlink, 0, &devlink->param_list,
6973 params, params_count,
6974 DEVLINK_CMD_PARAM_NEW,
6975 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03006976}
6977EXPORT_SYMBOL_GPL(devlink_params_register);
6978
6979/**
6980 * devlink_params_unregister - unregister configuration parameters
6981 * @devlink: devlink
6982 * @params: configuration parameters to unregister
6983 * @params_count: number of parameters provided
6984 */
6985void devlink_params_unregister(struct devlink *devlink,
6986 const struct devlink_param *params,
6987 size_t params_count)
6988{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306989 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
6990 params, params_count,
6991 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03006992}
6993EXPORT_SYMBOL_GPL(devlink_params_unregister);
6994
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006995/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00006996 * devlink_params_publish - publish configuration parameters
6997 *
6998 * @devlink: devlink
6999 *
7000 * Publish previously registered configuration parameters.
7001 */
7002void devlink_params_publish(struct devlink *devlink)
7003{
7004 struct devlink_param_item *param_item;
7005
7006 list_for_each_entry(param_item, &devlink->param_list, list) {
7007 if (param_item->published)
7008 continue;
7009 param_item->published = true;
7010 devlink_param_notify(devlink, 0, param_item,
7011 DEVLINK_CMD_PARAM_NEW);
7012 }
7013}
7014EXPORT_SYMBOL_GPL(devlink_params_publish);
7015
7016/**
7017 * devlink_params_unpublish - unpublish configuration parameters
7018 *
7019 * @devlink: devlink
7020 *
7021 * Unpublish previously registered configuration parameters.
7022 */
7023void devlink_params_unpublish(struct devlink *devlink)
7024{
7025 struct devlink_param_item *param_item;
7026
7027 list_for_each_entry(param_item, &devlink->param_list, list) {
7028 if (!param_item->published)
7029 continue;
7030 param_item->published = false;
7031 devlink_param_notify(devlink, 0, param_item,
7032 DEVLINK_CMD_PARAM_DEL);
7033 }
7034}
7035EXPORT_SYMBOL_GPL(devlink_params_unpublish);
7036
7037/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05307038 * devlink_port_params_register - register port configuration parameters
7039 *
7040 * @devlink_port: devlink port
7041 * @params: configuration parameters array
7042 * @params_count: number of parameters provided
7043 *
7044 * Register the configuration parameters supported by the port.
7045 */
7046int devlink_port_params_register(struct devlink_port *devlink_port,
7047 const struct devlink_param *params,
7048 size_t params_count)
7049{
7050 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307051 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05307052 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307053 params_count,
7054 DEVLINK_CMD_PORT_PARAM_NEW,
7055 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05307056}
7057EXPORT_SYMBOL_GPL(devlink_port_params_register);
7058
7059/**
7060 * devlink_port_params_unregister - unregister port configuration
7061 * parameters
7062 *
7063 * @devlink_port: devlink port
7064 * @params: configuration parameters array
7065 * @params_count: number of parameters provided
7066 */
7067void devlink_port_params_unregister(struct devlink_port *devlink_port,
7068 const struct devlink_param *params,
7069 size_t params_count)
7070{
7071 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307072 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05307073 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307074 params, params_count,
7075 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05307076}
7077EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
7078
Vasundhara Volamffd19b92019-01-28 18:00:23 +05307079static int
7080__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
7081 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03007082{
7083 struct devlink_param_item *param_item;
7084
Vasundhara Volamffd19b92019-01-28 18:00:23 +05307085 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03007086 if (!param_item)
7087 return -EINVAL;
7088
7089 if (!param_item->driverinit_value_valid ||
7090 !devlink_param_cmode_is_supported(param_item->param,
7091 DEVLINK_PARAM_CMODE_DRIVERINIT))
7092 return -EOPNOTSUPP;
7093
Moshe Shemesh12765342018-10-10 16:09:26 +03007094 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
7095 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
7096 else
7097 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03007098
7099 return 0;
7100}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05307101
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05307102static int
7103__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307104 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05307105 struct list_head *param_list, u32 param_id,
7106 union devlink_param_value init_val,
7107 enum devlink_command cmd)
7108{
7109 struct devlink_param_item *param_item;
7110
7111 param_item = devlink_param_find_by_id(param_list, param_id);
7112 if (!param_item)
7113 return -EINVAL;
7114
7115 if (!devlink_param_cmode_is_supported(param_item->param,
7116 DEVLINK_PARAM_CMODE_DRIVERINIT))
7117 return -EOPNOTSUPP;
7118
7119 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
7120 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
7121 else
7122 param_item->driverinit_value = init_val;
7123 param_item->driverinit_value_valid = true;
7124
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307125 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05307126 return 0;
7127}
7128
Vasundhara Volamffd19b92019-01-28 18:00:23 +05307129/**
7130 * devlink_param_driverinit_value_get - get configuration parameter
7131 * value for driver initializing
7132 *
7133 * @devlink: devlink
7134 * @param_id: parameter ID
7135 * @init_val: value of parameter in driverinit configuration mode
7136 *
7137 * This function should be used by the driver to get driverinit
7138 * configuration for initialization after reload command.
7139 */
7140int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
7141 union devlink_param_value *init_val)
7142{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007143 if (!devlink->ops->reload)
Vasundhara Volamffd19b92019-01-28 18:00:23 +05307144 return -EOPNOTSUPP;
7145
7146 return __devlink_param_driverinit_value_get(&devlink->param_list,
7147 param_id, init_val);
7148}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03007149EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
7150
7151/**
7152 * devlink_param_driverinit_value_set - set value of configuration
7153 * parameter for driverinit
7154 * configuration mode
7155 *
7156 * @devlink: devlink
7157 * @param_id: parameter ID
7158 * @init_val: value of parameter to set for driverinit configuration mode
7159 *
7160 * This function should be used by the driver to set driverinit
7161 * configuration mode default value.
7162 */
7163int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
7164 union devlink_param_value init_val)
7165{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307166 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05307167 &devlink->param_list,
7168 param_id, init_val,
7169 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03007170}
7171EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
7172
Moshe Shemeshea601e12018-07-04 14:30:32 +03007173/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05307174 * devlink_port_param_driverinit_value_get - get configuration parameter
7175 * value for driver initializing
7176 *
7177 * @devlink_port: devlink_port
7178 * @param_id: parameter ID
7179 * @init_val: value of parameter in driverinit configuration mode
7180 *
7181 * This function should be used by the driver to get driverinit
7182 * configuration for initialization after reload command.
7183 */
7184int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
7185 u32 param_id,
7186 union devlink_param_value *init_val)
7187{
7188 struct devlink *devlink = devlink_port->devlink;
7189
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007190 if (!devlink->ops->reload)
Vasundhara Volamffd19b92019-01-28 18:00:23 +05307191 return -EOPNOTSUPP;
7192
7193 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
7194 param_id, init_val);
7195}
7196EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
7197
7198/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05307199 * devlink_port_param_driverinit_value_set - set value of configuration
7200 * parameter for driverinit
7201 * configuration mode
7202 *
7203 * @devlink_port: devlink_port
7204 * @param_id: parameter ID
7205 * @init_val: value of parameter to set for driverinit configuration mode
7206 *
7207 * This function should be used by the driver to set driverinit
7208 * configuration mode default value.
7209 */
7210int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
7211 u32 param_id,
7212 union devlink_param_value init_val)
7213{
7214 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307215 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05307216 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307217 param_id, init_val,
7218 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05307219}
7220EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
7221
7222/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03007223 * devlink_param_value_changed - notify devlink on a parameter's value
7224 * change. Should be called by the driver
7225 * right after the change.
7226 *
7227 * @devlink: devlink
7228 * @param_id: parameter ID
7229 *
7230 * This function should be used by the driver to notify devlink on value
7231 * change, excluding driverinit configuration mode.
7232 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03007233 */
7234void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
7235{
7236 struct devlink_param_item *param_item;
7237
7238 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
7239 WARN_ON(!param_item);
7240
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307241 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03007242}
7243EXPORT_SYMBOL_GPL(devlink_param_value_changed);
7244
Alex Veskerb16ebe92018-07-12 15:13:08 +03007245/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05307246 * devlink_port_param_value_changed - notify devlink on a parameter's value
7247 * change. Should be called by the driver
7248 * right after the change.
7249 *
7250 * @devlink_port: devlink_port
7251 * @param_id: parameter ID
7252 *
7253 * This function should be used by the driver to notify devlink on value
7254 * change, excluding driverinit configuration mode.
7255 * For driverinit configuration mode driver should use the function
7256 * devlink_port_param_driverinit_value_set() instead.
7257 */
7258void devlink_port_param_value_changed(struct devlink_port *devlink_port,
7259 u32 param_id)
7260{
7261 struct devlink_param_item *param_item;
7262
7263 param_item = devlink_param_find_by_id(&devlink_port->param_list,
7264 param_id);
7265 WARN_ON(!param_item);
7266
7267 devlink_param_notify(devlink_port->devlink, devlink_port->index,
7268 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
7269}
7270EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
7271
7272/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03007273 * devlink_param_value_str_fill - Safely fill-up the string preventing
7274 * from overflow of the preallocated buffer
7275 *
7276 * @dst_val: destination devlink_param_value
7277 * @src: source buffer
7278 */
7279void devlink_param_value_str_fill(union devlink_param_value *dst_val,
7280 const char *src)
7281{
7282 size_t len;
7283
7284 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
7285 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
7286}
7287EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
7288
7289/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03007290 * devlink_region_create - create a new address region
7291 *
7292 * @devlink: devlink
7293 * @region_name: region name
7294 * @region_max_snapshots: Maximum supported number of snapshots for region
7295 * @region_size: size of region
7296 */
7297struct devlink_region *devlink_region_create(struct devlink *devlink,
7298 const char *region_name,
7299 u32 region_max_snapshots,
7300 u64 region_size)
7301{
7302 struct devlink_region *region;
7303 int err = 0;
7304
7305 mutex_lock(&devlink->lock);
7306
7307 if (devlink_region_get_by_name(devlink, region_name)) {
7308 err = -EEXIST;
7309 goto unlock;
7310 }
7311
7312 region = kzalloc(sizeof(*region), GFP_KERNEL);
7313 if (!region) {
7314 err = -ENOMEM;
7315 goto unlock;
7316 }
7317
7318 region->devlink = devlink;
7319 region->max_snapshots = region_max_snapshots;
7320 region->name = region_name;
7321 region->size = region_size;
7322 INIT_LIST_HEAD(&region->snapshot_list);
7323 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03007324 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03007325
7326 mutex_unlock(&devlink->lock);
7327 return region;
7328
7329unlock:
7330 mutex_unlock(&devlink->lock);
7331 return ERR_PTR(err);
7332}
7333EXPORT_SYMBOL_GPL(devlink_region_create);
7334
7335/**
7336 * devlink_region_destroy - destroy address region
7337 *
7338 * @region: devlink region to destroy
7339 */
7340void devlink_region_destroy(struct devlink_region *region)
7341{
7342 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03007343 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03007344
7345 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03007346
7347 /* Free all snapshots of region */
7348 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
Jiri Pirko92b49822019-08-12 14:28:31 +02007349 devlink_region_snapshot_del(region, snapshot);
Alex Veskerd7e52722018-07-12 15:13:10 +03007350
Alex Veskerb16ebe92018-07-12 15:13:08 +03007351 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03007352
7353 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03007354 mutex_unlock(&devlink->lock);
7355 kfree(region);
7356}
7357EXPORT_SYMBOL_GPL(devlink_region_destroy);
7358
Alex Veskerccadfa42018-07-12 15:13:09 +03007359/**
7360 * devlink_region_shapshot_id_get - get snapshot ID
7361 *
7362 * This callback should be called when adding a new snapshot,
7363 * Driver should use the same id for multiple snapshots taken
7364 * on multiple regions at the same time/by the same trigger.
7365 *
7366 * @devlink: devlink
7367 */
7368u32 devlink_region_shapshot_id_get(struct devlink *devlink)
7369{
7370 u32 id;
7371
7372 mutex_lock(&devlink->lock);
7373 id = ++devlink->snapshot_id;
7374 mutex_unlock(&devlink->lock);
7375
7376 return id;
7377}
7378EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
7379
Alex Veskerd7e52722018-07-12 15:13:10 +03007380/**
7381 * devlink_region_snapshot_create - create a new snapshot
7382 * This will add a new snapshot of a region. The snapshot
7383 * will be stored on the region struct and can be accessed
7384 * from devlink. This is useful for future analyses of snapshots.
7385 * Multiple snapshots can be created on a region.
7386 * The @snapshot_id should be obtained using the getter function.
7387 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08007388 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03007389 * @data: snapshot data
7390 * @snapshot_id: snapshot id to be created
7391 * @data_destructor: pointer to destructor function to free data
7392 */
Jiri Pirko3a5e5232019-08-09 15:27:15 +02007393int devlink_region_snapshot_create(struct devlink_region *region,
Alex Veskerd7e52722018-07-12 15:13:10 +03007394 u8 *data, u32 snapshot_id,
7395 devlink_snapshot_data_dest_t *data_destructor)
7396{
7397 struct devlink *devlink = region->devlink;
7398 struct devlink_snapshot *snapshot;
7399 int err;
7400
7401 mutex_lock(&devlink->lock);
7402
7403 /* check if region can hold one more snapshot */
7404 if (region->cur_snapshots == region->max_snapshots) {
7405 err = -ENOMEM;
7406 goto unlock;
7407 }
7408
7409 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
7410 err = -EEXIST;
7411 goto unlock;
7412 }
7413
7414 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
7415 if (!snapshot) {
7416 err = -ENOMEM;
7417 goto unlock;
7418 }
7419
7420 snapshot->id = snapshot_id;
7421 snapshot->region = region;
7422 snapshot->data = data;
Alex Veskerd7e52722018-07-12 15:13:10 +03007423 snapshot->data_destructor = data_destructor;
7424
7425 list_add_tail(&snapshot->list, &region->snapshot_list);
7426
7427 region->cur_snapshots++;
7428
Alex Vesker866319b2018-07-12 15:13:13 +03007429 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
Alex Veskerd7e52722018-07-12 15:13:10 +03007430 mutex_unlock(&devlink->lock);
7431 return 0;
7432
7433unlock:
7434 mutex_unlock(&devlink->lock);
7435 return err;
7436}
7437EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
7438
Ido Schimmel0f420b62019-08-17 16:28:17 +03007439#define DEVLINK_TRAP(_id, _type) \
7440 { \
7441 .type = DEVLINK_TRAP_TYPE_##_type, \
7442 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
7443 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
7444 }
7445
7446static const struct devlink_trap devlink_trap_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03007447 DEVLINK_TRAP(SMAC_MC, DROP),
7448 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
7449 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
7450 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
7451 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
7452 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
7453 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
7454 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
7455 DEVLINK_TRAP(TAIL_DROP, DROP),
Ido Schimmel0f420b62019-08-17 16:28:17 +03007456};
7457
7458#define DEVLINK_TRAP_GROUP(_id) \
7459 { \
7460 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
7461 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
7462 }
7463
7464static const struct devlink_trap_group devlink_trap_group_generic[] = {
Ido Schimmel391203a2019-08-17 16:28:18 +03007465 DEVLINK_TRAP_GROUP(L2_DROPS),
7466 DEVLINK_TRAP_GROUP(L3_DROPS),
7467 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
Ido Schimmel0f420b62019-08-17 16:28:17 +03007468};
7469
7470static int devlink_trap_generic_verify(const struct devlink_trap *trap)
7471{
7472 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
7473 return -EINVAL;
7474
7475 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
7476 return -EINVAL;
7477
7478 if (trap->type != devlink_trap_generic[trap->id].type)
7479 return -EINVAL;
7480
7481 return 0;
7482}
7483
7484static int devlink_trap_driver_verify(const struct devlink_trap *trap)
7485{
7486 int i;
7487
7488 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
7489 return -EINVAL;
7490
7491 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
7492 if (!strcmp(trap->name, devlink_trap_generic[i].name))
7493 return -EEXIST;
7494 }
7495
7496 return 0;
7497}
7498
7499static int devlink_trap_verify(const struct devlink_trap *trap)
7500{
7501 if (!trap || !trap->name || !trap->group.name)
7502 return -EINVAL;
7503
7504 if (trap->generic)
7505 return devlink_trap_generic_verify(trap);
7506 else
7507 return devlink_trap_driver_verify(trap);
7508}
7509
7510static int
7511devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
7512{
7513 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
7514 return -EINVAL;
7515
7516 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
7517 return -EINVAL;
7518
7519 return 0;
7520}
7521
7522static int
7523devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
7524{
7525 int i;
7526
7527 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
7528 return -EINVAL;
7529
7530 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
7531 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
7532 return -EEXIST;
7533 }
7534
7535 return 0;
7536}
7537
7538static int devlink_trap_group_verify(const struct devlink_trap_group *group)
7539{
7540 if (group->generic)
7541 return devlink_trap_group_generic_verify(group);
7542 else
7543 return devlink_trap_group_driver_verify(group);
7544}
7545
7546static void
7547devlink_trap_group_notify(struct devlink *devlink,
7548 const struct devlink_trap_group_item *group_item,
7549 enum devlink_command cmd)
7550{
7551 struct sk_buff *msg;
7552 int err;
7553
7554 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
7555 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
7556
7557 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7558 if (!msg)
7559 return;
7560
7561 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
7562 0);
7563 if (err) {
7564 nlmsg_free(msg);
7565 return;
7566 }
7567
7568 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
7569 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
7570}
7571
7572static struct devlink_trap_group_item *
7573devlink_trap_group_item_create(struct devlink *devlink,
7574 const struct devlink_trap_group *group)
7575{
7576 struct devlink_trap_group_item *group_item;
7577 int err;
7578
7579 err = devlink_trap_group_verify(group);
7580 if (err)
7581 return ERR_PTR(err);
7582
7583 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
7584 if (!group_item)
7585 return ERR_PTR(-ENOMEM);
7586
7587 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
7588 if (!group_item->stats) {
7589 err = -ENOMEM;
7590 goto err_stats_alloc;
7591 }
7592
7593 group_item->group = group;
7594 refcount_set(&group_item->refcount, 1);
7595
7596 if (devlink->ops->trap_group_init) {
7597 err = devlink->ops->trap_group_init(devlink, group);
7598 if (err)
7599 goto err_group_init;
7600 }
7601
7602 list_add_tail(&group_item->list, &devlink->trap_group_list);
7603 devlink_trap_group_notify(devlink, group_item,
7604 DEVLINK_CMD_TRAP_GROUP_NEW);
7605
7606 return group_item;
7607
7608err_group_init:
7609 free_percpu(group_item->stats);
7610err_stats_alloc:
7611 kfree(group_item);
7612 return ERR_PTR(err);
7613}
7614
7615static void
7616devlink_trap_group_item_destroy(struct devlink *devlink,
7617 struct devlink_trap_group_item *group_item)
7618{
7619 devlink_trap_group_notify(devlink, group_item,
7620 DEVLINK_CMD_TRAP_GROUP_DEL);
7621 list_del(&group_item->list);
7622 free_percpu(group_item->stats);
7623 kfree(group_item);
7624}
7625
7626static struct devlink_trap_group_item *
7627devlink_trap_group_item_get(struct devlink *devlink,
7628 const struct devlink_trap_group *group)
7629{
7630 struct devlink_trap_group_item *group_item;
7631
7632 group_item = devlink_trap_group_item_lookup(devlink, group->name);
7633 if (group_item) {
7634 refcount_inc(&group_item->refcount);
7635 return group_item;
7636 }
7637
7638 return devlink_trap_group_item_create(devlink, group);
7639}
7640
7641static void
7642devlink_trap_group_item_put(struct devlink *devlink,
7643 struct devlink_trap_group_item *group_item)
7644{
7645 if (!refcount_dec_and_test(&group_item->refcount))
7646 return;
7647
7648 devlink_trap_group_item_destroy(devlink, group_item);
7649}
7650
7651static int
7652devlink_trap_item_group_link(struct devlink *devlink,
7653 struct devlink_trap_item *trap_item)
7654{
7655 struct devlink_trap_group_item *group_item;
7656
7657 group_item = devlink_trap_group_item_get(devlink,
7658 &trap_item->trap->group);
7659 if (IS_ERR(group_item))
7660 return PTR_ERR(group_item);
7661
7662 trap_item->group_item = group_item;
7663
7664 return 0;
7665}
7666
7667static void
7668devlink_trap_item_group_unlink(struct devlink *devlink,
7669 struct devlink_trap_item *trap_item)
7670{
7671 devlink_trap_group_item_put(devlink, trap_item->group_item);
7672}
7673
7674static void devlink_trap_notify(struct devlink *devlink,
7675 const struct devlink_trap_item *trap_item,
7676 enum devlink_command cmd)
7677{
7678 struct sk_buff *msg;
7679 int err;
7680
7681 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
7682 cmd != DEVLINK_CMD_TRAP_DEL);
7683
7684 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7685 if (!msg)
7686 return;
7687
7688 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
7689 if (err) {
7690 nlmsg_free(msg);
7691 return;
7692 }
7693
7694 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
7695 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
7696}
7697
7698static int
7699devlink_trap_register(struct devlink *devlink,
7700 const struct devlink_trap *trap, void *priv)
7701{
7702 struct devlink_trap_item *trap_item;
7703 int err;
7704
7705 if (devlink_trap_item_lookup(devlink, trap->name))
7706 return -EEXIST;
7707
7708 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
7709 if (!trap_item)
7710 return -ENOMEM;
7711
7712 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
7713 if (!trap_item->stats) {
7714 err = -ENOMEM;
7715 goto err_stats_alloc;
7716 }
7717
7718 trap_item->trap = trap;
7719 trap_item->action = trap->init_action;
7720 trap_item->priv = priv;
7721
7722 err = devlink_trap_item_group_link(devlink, trap_item);
7723 if (err)
7724 goto err_group_link;
7725
7726 err = devlink->ops->trap_init(devlink, trap, trap_item);
7727 if (err)
7728 goto err_trap_init;
7729
7730 list_add_tail(&trap_item->list, &devlink->trap_list);
7731 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
7732
7733 return 0;
7734
7735err_trap_init:
7736 devlink_trap_item_group_unlink(devlink, trap_item);
7737err_group_link:
7738 free_percpu(trap_item->stats);
7739err_stats_alloc:
7740 kfree(trap_item);
7741 return err;
7742}
7743
7744static void devlink_trap_unregister(struct devlink *devlink,
7745 const struct devlink_trap *trap)
7746{
7747 struct devlink_trap_item *trap_item;
7748
7749 trap_item = devlink_trap_item_lookup(devlink, trap->name);
7750 if (WARN_ON_ONCE(!trap_item))
7751 return;
7752
7753 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
7754 list_del(&trap_item->list);
7755 if (devlink->ops->trap_fini)
7756 devlink->ops->trap_fini(devlink, trap, trap_item);
7757 devlink_trap_item_group_unlink(devlink, trap_item);
7758 free_percpu(trap_item->stats);
7759 kfree(trap_item);
7760}
7761
7762static void devlink_trap_disable(struct devlink *devlink,
7763 const struct devlink_trap *trap)
7764{
7765 struct devlink_trap_item *trap_item;
7766
7767 trap_item = devlink_trap_item_lookup(devlink, trap->name);
7768 if (WARN_ON_ONCE(!trap_item))
7769 return;
7770
7771 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP);
7772 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
7773}
7774
7775/**
7776 * devlink_traps_register - Register packet traps with devlink.
7777 * @devlink: devlink.
7778 * @traps: Packet traps.
7779 * @traps_count: Count of provided packet traps.
7780 * @priv: Driver private information.
7781 *
7782 * Return: Non-zero value on failure.
7783 */
7784int devlink_traps_register(struct devlink *devlink,
7785 const struct devlink_trap *traps,
7786 size_t traps_count, void *priv)
7787{
7788 int i, err;
7789
7790 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
7791 return -EINVAL;
7792
7793 mutex_lock(&devlink->lock);
7794 for (i = 0; i < traps_count; i++) {
7795 const struct devlink_trap *trap = &traps[i];
7796
7797 err = devlink_trap_verify(trap);
7798 if (err)
7799 goto err_trap_verify;
7800
7801 err = devlink_trap_register(devlink, trap, priv);
7802 if (err)
7803 goto err_trap_register;
7804 }
7805 mutex_unlock(&devlink->lock);
7806
7807 return 0;
7808
7809err_trap_register:
7810err_trap_verify:
7811 for (i--; i >= 0; i--)
7812 devlink_trap_unregister(devlink, &traps[i]);
7813 mutex_unlock(&devlink->lock);
7814 return err;
7815}
7816EXPORT_SYMBOL_GPL(devlink_traps_register);
7817
7818/**
7819 * devlink_traps_unregister - Unregister packet traps from devlink.
7820 * @devlink: devlink.
7821 * @traps: Packet traps.
7822 * @traps_count: Count of provided packet traps.
7823 */
7824void devlink_traps_unregister(struct devlink *devlink,
7825 const struct devlink_trap *traps,
7826 size_t traps_count)
7827{
7828 int i;
7829
7830 mutex_lock(&devlink->lock);
7831 /* Make sure we do not have any packets in-flight while unregistering
7832 * traps by disabling all of them and waiting for a grace period.
7833 */
7834 for (i = traps_count - 1; i >= 0; i--)
7835 devlink_trap_disable(devlink, &traps[i]);
7836 synchronize_rcu();
7837 for (i = traps_count - 1; i >= 0; i--)
7838 devlink_trap_unregister(devlink, &traps[i]);
7839 mutex_unlock(&devlink->lock);
7840}
7841EXPORT_SYMBOL_GPL(devlink_traps_unregister);
7842
7843static void
7844devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
7845 size_t skb_len)
7846{
7847 struct devlink_stats *stats;
7848
7849 stats = this_cpu_ptr(trap_stats);
7850 u64_stats_update_begin(&stats->syncp);
7851 stats->rx_bytes += skb_len;
7852 stats->rx_packets++;
7853 u64_stats_update_end(&stats->syncp);
7854}
7855
7856static void
7857devlink_trap_report_metadata_fill(struct net_dm_hw_metadata *hw_metadata,
7858 const struct devlink_trap_item *trap_item,
7859 struct devlink_port *in_devlink_port)
7860{
7861 struct devlink_trap_group_item *group_item = trap_item->group_item;
7862
7863 hw_metadata->trap_group_name = group_item->group->name;
7864 hw_metadata->trap_name = trap_item->trap->name;
7865
7866 spin_lock(&in_devlink_port->type_lock);
7867 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
7868 hw_metadata->input_dev = in_devlink_port->type_dev;
7869 spin_unlock(&in_devlink_port->type_lock);
7870}
7871
7872/**
7873 * devlink_trap_report - Report trapped packet to drop monitor.
7874 * @devlink: devlink.
7875 * @skb: Trapped packet.
7876 * @trap_ctx: Trap context.
7877 * @in_devlink_port: Input devlink port.
7878 */
7879void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
7880 void *trap_ctx, struct devlink_port *in_devlink_port)
7881{
7882 struct devlink_trap_item *trap_item = trap_ctx;
7883 struct net_dm_hw_metadata hw_metadata = {};
7884
7885 devlink_trap_stats_update(trap_item->stats, skb->len);
7886 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
7887
7888 devlink_trap_report_metadata_fill(&hw_metadata, trap_item,
7889 in_devlink_port);
7890 net_dm_hw_report(skb, &hw_metadata);
7891}
7892EXPORT_SYMBOL_GPL(devlink_trap_report);
7893
7894/**
7895 * devlink_trap_ctx_priv - Trap context to driver private information.
7896 * @trap_ctx: Trap context.
7897 *
7898 * Return: Driver private information passed during registration.
7899 */
7900void *devlink_trap_ctx_priv(void *trap_ctx)
7901{
7902 struct devlink_trap_item *trap_item = trap_ctx;
7903
7904 return trap_item->priv;
7905}
7906EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
7907
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08007908static void __devlink_compat_running_version(struct devlink *devlink,
7909 char *buf, size_t len)
7910{
7911 const struct nlattr *nlattr;
7912 struct devlink_info_req req;
7913 struct sk_buff *msg;
7914 int rem, err;
7915
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08007916 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7917 if (!msg)
7918 return;
7919
7920 req.msg = msg;
7921 err = devlink->ops->info_get(devlink, &req, NULL);
7922 if (err)
7923 goto free_msg;
7924
7925 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
7926 const struct nlattr *kv;
7927 int rem_kv;
7928
7929 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
7930 continue;
7931
7932 nla_for_each_nested(kv, nlattr, rem_kv) {
7933 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
7934 continue;
7935
7936 strlcat(buf, nla_data(kv), len);
7937 strlcat(buf, " ", len);
7938 }
7939 }
7940free_msg:
7941 nlmsg_free(msg);
7942}
7943
7944void devlink_compat_running_version(struct net_device *dev,
7945 char *buf, size_t len)
7946{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08007947 struct devlink *devlink;
7948
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08007949 dev_hold(dev);
7950 rtnl_unlock();
7951
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08007952 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08007953 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01007954 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08007955
7956 mutex_lock(&devlink->lock);
7957 __devlink_compat_running_version(devlink, buf, len);
7958 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08007959
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01007960out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08007961 rtnl_lock();
7962 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08007963}
7964
Jakub Kicinski4eceba12019-02-14 13:40:45 -08007965int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
7966{
Jakub Kicinski4eceba12019-02-14 13:40:45 -08007967 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01007968 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08007969
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08007970 dev_hold(dev);
7971 rtnl_unlock();
7972
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08007973 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01007974 if (!devlink || !devlink->ops->flash_update) {
7975 ret = -EOPNOTSUPP;
7976 goto out;
7977 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -08007978
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08007979 mutex_lock(&devlink->lock);
7980 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
7981 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08007982
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01007983out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08007984 rtnl_lock();
7985 dev_put(dev);
7986
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08007987 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08007988}
7989
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01007990int devlink_compat_phys_port_name_get(struct net_device *dev,
7991 char *name, size_t len)
7992{
7993 struct devlink_port *devlink_port;
7994
7995 /* RTNL mutex is held here which ensures that devlink_port
7996 * instance cannot disappear in the middle. No need to take
7997 * any devlink lock as only permanent values are accessed.
7998 */
7999 ASSERT_RTNL();
8000
8001 devlink_port = netdev_to_devlink_port(dev);
8002 if (!devlink_port)
8003 return -EOPNOTSUPP;
8004
8005 return __devlink_port_phys_port_name_get(devlink_port, name, len);
8006}
8007
Jiri Pirko7e1146e2019-04-03 14:24:17 +02008008int devlink_compat_switch_id_get(struct net_device *dev,
8009 struct netdev_phys_item_id *ppid)
8010{
8011 struct devlink_port *devlink_port;
8012
Vlad Buslov043b8412019-08-12 20:02:02 +03008013 /* Caller must hold RTNL mutex or reference to dev, which ensures that
8014 * devlink_port instance cannot disappear in the middle. No need to take
Jiri Pirko7e1146e2019-04-03 14:24:17 +02008015 * any devlink lock as only permanent values are accessed.
8016 */
Jiri Pirko7e1146e2019-04-03 14:24:17 +02008017 devlink_port = netdev_to_devlink_port(dev);
8018 if (!devlink_port || !devlink_port->attrs.switch_port)
8019 return -EOPNOTSUPP;
8020
8021 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
8022
8023 return 0;
8024}
8025
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08008026static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008027{
Johannes Berg489111e2016-10-24 14:40:03 +02008028 return genl_register_family(&devlink_nl_family);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01008029}
8030
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08008031subsys_initcall(devlink_init);