blob: d362652a5cc7dffb7483c20e295ae9b8891101ac [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>
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010021#include <rdma/ib_verbs.h>
22#include <net/netlink.h>
23#include <net/genetlink.h>
24#include <net/rtnetlink.h>
25#include <net/net_namespace.h>
26#include <net/sock.h>
27#include <net/devlink.h>
Jiri Pirkoe5224f02016-07-12 18:05:03 +020028#define CREATE_TRACE_POINTS
29#include <trace/events/devlink.h>
30
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020031static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
32 {
David Ahern12bdc5e2017-08-30 17:07:30 -070033 .name = "destination mac",
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020034 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
35 .bitwidth = 48,
36 },
37};
38
39struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
40 .name = "ethernet",
41 .id = DEVLINK_DPIPE_HEADER_ETHERNET,
42 .fields = devlink_dpipe_fields_ethernet,
43 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
44 .global = true,
45};
46EXPORT_SYMBOL(devlink_dpipe_header_ethernet);
47
Arkadi Sharshevsky3fb886e2017-08-24 08:40:00 +020048static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
49 {
50 .name = "destination ip",
51 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
52 .bitwidth = 32,
53 },
54};
55
56struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
57 .name = "ipv4",
58 .id = DEVLINK_DPIPE_HEADER_IPV4,
59 .fields = devlink_dpipe_fields_ipv4,
60 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
61 .global = true,
62};
63EXPORT_SYMBOL(devlink_dpipe_header_ipv4);
64
Arkadi Sharshevsky1797f5b2017-08-31 17:59:12 +020065static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
66 {
67 .name = "destination ip",
68 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
69 .bitwidth = 128,
70 },
71};
72
73struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
74 .name = "ipv6",
75 .id = DEVLINK_DPIPE_HEADER_IPV6,
76 .fields = devlink_dpipe_fields_ipv6,
77 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
78 .global = true,
79};
80EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
81
Jiri Pirkoe5224f02016-07-12 18:05:03 +020082EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
Nir Dotan57186a52019-02-04 18:47:45 +000083EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010084
85static LIST_HEAD(devlink_list);
86
87/* devlink_mutex
88 *
89 * An overall lock guarding every operation coming from userspace.
90 * It also guards devlink devices list and it is taken when
91 * driver registers/unregisters it.
92 */
93static DEFINE_MUTEX(devlink_mutex);
94
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010095static struct net *devlink_net(const struct devlink *devlink)
96{
97 return read_pnet(&devlink->_net);
98}
99
100static void devlink_net_set(struct devlink *devlink, struct net *net)
101{
102 write_pnet(&devlink->_net, net);
103}
104
105static struct devlink *devlink_get_from_attrs(struct net *net,
106 struct nlattr **attrs)
107{
108 struct devlink *devlink;
109 char *busname;
110 char *devname;
111
112 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
113 return ERR_PTR(-EINVAL);
114
115 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
116 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
117
Parav Panditdac7c082019-02-12 14:24:08 -0600118 lockdep_assert_held(&devlink_mutex);
119
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100120 list_for_each_entry(devlink, &devlink_list, list) {
121 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
122 strcmp(dev_name(devlink->dev), devname) == 0 &&
123 net_eq(devlink_net(devlink), net))
124 return devlink;
125 }
126
127 return ERR_PTR(-ENODEV);
128}
129
130static struct devlink *devlink_get_from_info(struct genl_info *info)
131{
132 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
133}
134
135static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
136 int port_index)
137{
138 struct devlink_port *devlink_port;
139
140 list_for_each_entry(devlink_port, &devlink->port_list, list) {
141 if (devlink_port->index == port_index)
142 return devlink_port;
143 }
144 return NULL;
145}
146
147static bool devlink_port_index_exists(struct devlink *devlink, int port_index)
148{
149 return devlink_port_get_by_index(devlink, port_index);
150}
151
152static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
153 struct nlattr **attrs)
154{
155 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
156 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
157 struct devlink_port *devlink_port;
158
159 devlink_port = devlink_port_get_by_index(devlink, port_index);
160 if (!devlink_port)
161 return ERR_PTR(-ENODEV);
162 return devlink_port;
163 }
164 return ERR_PTR(-EINVAL);
165}
166
167static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
168 struct genl_info *info)
169{
170 return devlink_port_get_from_attrs(devlink, info->attrs);
171}
172
Jiri Pirkobf797472016-04-14 18:19:13 +0200173struct devlink_sb {
174 struct list_head list;
175 unsigned int index;
176 u32 size;
177 u16 ingress_pools_count;
178 u16 egress_pools_count;
179 u16 ingress_tc_count;
180 u16 egress_tc_count;
181};
182
183static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
184{
185 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
186}
187
188static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
189 unsigned int sb_index)
190{
191 struct devlink_sb *devlink_sb;
192
193 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
194 if (devlink_sb->index == sb_index)
195 return devlink_sb;
196 }
197 return NULL;
198}
199
200static bool devlink_sb_index_exists(struct devlink *devlink,
201 unsigned int sb_index)
202{
203 return devlink_sb_get_by_index(devlink, sb_index);
204}
205
206static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
207 struct nlattr **attrs)
208{
209 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
210 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
211 struct devlink_sb *devlink_sb;
212
213 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
214 if (!devlink_sb)
215 return ERR_PTR(-ENODEV);
216 return devlink_sb;
217 }
218 return ERR_PTR(-EINVAL);
219}
220
221static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
222 struct genl_info *info)
223{
224 return devlink_sb_get_from_attrs(devlink, info->attrs);
225}
226
227static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
228 struct nlattr **attrs,
229 u16 *p_pool_index)
230{
231 u16 val;
232
233 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
234 return -EINVAL;
235
236 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
237 if (val >= devlink_sb_pool_count(devlink_sb))
238 return -EINVAL;
239 *p_pool_index = val;
240 return 0;
241}
242
243static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
244 struct genl_info *info,
245 u16 *p_pool_index)
246{
247 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
248 p_pool_index);
249}
250
251static int
252devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
253 enum devlink_sb_pool_type *p_pool_type)
254{
255 u8 val;
256
257 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
258 return -EINVAL;
259
260 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
261 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
262 val != DEVLINK_SB_POOL_TYPE_EGRESS)
263 return -EINVAL;
264 *p_pool_type = val;
265 return 0;
266}
267
268static int
269devlink_sb_pool_type_get_from_info(struct genl_info *info,
270 enum devlink_sb_pool_type *p_pool_type)
271{
272 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
273}
274
275static int
276devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
277 enum devlink_sb_threshold_type *p_th_type)
278{
279 u8 val;
280
281 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
282 return -EINVAL;
283
284 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
285 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
286 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
287 return -EINVAL;
288 *p_th_type = val;
289 return 0;
290}
291
292static int
293devlink_sb_th_type_get_from_info(struct genl_info *info,
294 enum devlink_sb_threshold_type *p_th_type)
295{
296 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
297}
298
299static int
300devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
301 struct nlattr **attrs,
302 enum devlink_sb_pool_type pool_type,
303 u16 *p_tc_index)
304{
305 u16 val;
306
307 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
308 return -EINVAL;
309
310 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
311 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
312 val >= devlink_sb->ingress_tc_count)
313 return -EINVAL;
314 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
315 val >= devlink_sb->egress_tc_count)
316 return -EINVAL;
317 *p_tc_index = val;
318 return 0;
319}
320
321static int
322devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
323 struct genl_info *info,
324 enum devlink_sb_pool_type pool_type,
325 u16 *p_tc_index)
326{
327 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
328 pool_type, p_tc_index);
329}
330
Alex Veskerb16ebe92018-07-12 15:13:08 +0300331struct devlink_region {
332 struct devlink *devlink;
333 struct list_head list;
334 const char *name;
335 struct list_head snapshot_list;
336 u32 max_snapshots;
337 u32 cur_snapshots;
338 u64 size;
339};
340
Alex Veskerd7e52722018-07-12 15:13:10 +0300341struct devlink_snapshot {
342 struct list_head list;
343 struct devlink_region *region;
344 devlink_snapshot_data_dest_t *data_destructor;
345 u64 data_len;
346 u8 *data;
347 u32 id;
348};
349
Alex Veskerb16ebe92018-07-12 15:13:08 +0300350static struct devlink_region *
351devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
352{
353 struct devlink_region *region;
354
355 list_for_each_entry(region, &devlink->region_list, list)
356 if (!strcmp(region->name, region_name))
357 return region;
358
359 return NULL;
360}
361
Alex Veskerd7e52722018-07-12 15:13:10 +0300362static struct devlink_snapshot *
363devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
364{
365 struct devlink_snapshot *snapshot;
366
367 list_for_each_entry(snapshot, &region->snapshot_list, list)
368 if (snapshot->id == id)
369 return snapshot;
370
371 return NULL;
372}
373
374static void devlink_region_snapshot_del(struct devlink_snapshot *snapshot)
375{
376 snapshot->region->cur_snapshots--;
377 list_del(&snapshot->list);
378 (*snapshot->data_destructor)(snapshot->data);
379 kfree(snapshot);
380}
381
Jiri Pirko1fc22572016-04-08 19:12:48 +0200382#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
383#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
Jiri Pirkobf797472016-04-14 18:19:13 +0200384#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100385
386/* The per devlink instance lock is taken by default in the pre-doit
387 * operation, yet several commands do not require this. The global
388 * devlink lock is taken and protects from disruption by user-calls.
389 */
390#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100391
392static int devlink_nl_pre_doit(const struct genl_ops *ops,
393 struct sk_buff *skb, struct genl_info *info)
394{
395 struct devlink *devlink;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100396 int err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100397
398 mutex_lock(&devlink_mutex);
399 devlink = devlink_get_from_info(info);
400 if (IS_ERR(devlink)) {
401 mutex_unlock(&devlink_mutex);
402 return PTR_ERR(devlink);
403 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100404 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
405 mutex_lock(&devlink->lock);
Jiri Pirko1fc22572016-04-08 19:12:48 +0200406 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
407 info->user_ptr[0] = devlink;
408 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100409 struct devlink_port *devlink_port;
410
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100411 devlink_port = devlink_port_get_from_info(devlink, info);
412 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100413 err = PTR_ERR(devlink_port);
414 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100415 }
Jiri Pirko1fc22572016-04-08 19:12:48 +0200416 info->user_ptr[0] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100417 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200418 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
419 struct devlink_sb *devlink_sb;
420
421 devlink_sb = devlink_sb_get_from_info(devlink, info);
422 if (IS_ERR(devlink_sb)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100423 err = PTR_ERR(devlink_sb);
424 goto unlock;
Jiri Pirkobf797472016-04-14 18:19:13 +0200425 }
426 info->user_ptr[1] = devlink_sb;
427 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100428 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100429
430unlock:
431 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
432 mutex_unlock(&devlink->lock);
433 mutex_unlock(&devlink_mutex);
434 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100435}
436
437static void devlink_nl_post_doit(const struct genl_ops *ops,
438 struct sk_buff *skb, struct genl_info *info)
439{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100440 struct devlink *devlink;
441
442 devlink = devlink_get_from_info(info);
443 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
444 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100445 mutex_unlock(&devlink_mutex);
446}
447
Johannes Berg489111e2016-10-24 14:40:03 +0200448static struct genl_family devlink_nl_family;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100449
450enum devlink_multicast_groups {
451 DEVLINK_MCGRP_CONFIG,
452};
453
454static const struct genl_multicast_group devlink_nl_mcgrps[] = {
455 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
456};
457
458static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
459{
460 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
461 return -EMSGSIZE;
462 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
463 return -EMSGSIZE;
464 return 0;
465}
466
467static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
468 enum devlink_command cmd, u32 portid,
469 u32 seq, int flags)
470{
471 void *hdr;
472
473 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
474 if (!hdr)
475 return -EMSGSIZE;
476
477 if (devlink_nl_put_handle(msg, devlink))
478 goto nla_put_failure;
479
480 genlmsg_end(msg, hdr);
481 return 0;
482
483nla_put_failure:
484 genlmsg_cancel(msg, hdr);
485 return -EMSGSIZE;
486}
487
488static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
489{
490 struct sk_buff *msg;
491 int err;
492
493 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
494
495 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
496 if (!msg)
497 return;
498
499 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
500 if (err) {
501 nlmsg_free(msg);
502 return;
503 }
504
505 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
506 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
507}
508
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200509static int devlink_nl_port_attrs_put(struct sk_buff *msg,
510 struct devlink_port *devlink_port)
511{
512 struct devlink_port_attrs *attrs = &devlink_port->attrs;
513
514 if (!attrs->set)
515 return 0;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200516 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
517 return -EMSGSIZE;
Parav Pandit98fd2d62019-07-08 23:17:37 -0500518 if (devlink_port->attrs.flavour == DEVLINK_PORT_FLAVOUR_PCI_PF) {
519 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
520 attrs->pci_pf.pf))
521 return -EMSGSIZE;
522 }
Parav Pandita2c6b872019-07-08 23:17:36 -0500523 if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PHYSICAL &&
524 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
525 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA)
526 return 0;
Parav Pandit378ef012019-07-08 23:17:35 -0500527 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
528 attrs->phys.port_number))
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200529 return -EMSGSIZE;
530 if (!attrs->split)
531 return 0;
Parav Pandit378ef012019-07-08 23:17:35 -0500532 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
533 attrs->phys.port_number))
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200534 return -EMSGSIZE;
535 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
Parav Pandit378ef012019-07-08 23:17:35 -0500536 attrs->phys.split_subport_number))
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200537 return -EMSGSIZE;
538 return 0;
539}
540
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100541static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
542 struct devlink_port *devlink_port,
543 enum devlink_command cmd, u32 portid,
544 u32 seq, int flags)
545{
546 void *hdr;
547
548 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
549 if (!hdr)
550 return -EMSGSIZE;
551
552 if (devlink_nl_put_handle(msg, devlink))
553 goto nla_put_failure;
554 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
555 goto nla_put_failure;
Jiri Pirkob8f97552019-03-24 11:14:37 +0100556
557 spin_lock(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100558 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100559 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100560 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
561 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
562 devlink_port->desired_type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100563 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100564 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
565 struct net_device *netdev = devlink_port->type_dev;
566
567 if (netdev &&
568 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
569 netdev->ifindex) ||
570 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
571 netdev->name)))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100572 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100573 }
574 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
575 struct ib_device *ibdev = devlink_port->type_dev;
576
577 if (ibdev &&
578 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
579 ibdev->name))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100580 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100581 }
Jiri Pirkob8f97552019-03-24 11:14:37 +0100582 spin_unlock(&devlink_port->type_lock);
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200583 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100584 goto nla_put_failure;
585
586 genlmsg_end(msg, hdr);
587 return 0;
588
Jiri Pirkob8f97552019-03-24 11:14:37 +0100589nla_put_failure_type_locked:
590 spin_unlock(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100591nla_put_failure:
592 genlmsg_cancel(msg, hdr);
593 return -EMSGSIZE;
594}
595
596static void devlink_port_notify(struct devlink_port *devlink_port,
597 enum devlink_command cmd)
598{
599 struct devlink *devlink = devlink_port->devlink;
600 struct sk_buff *msg;
601 int err;
602
603 if (!devlink_port->registered)
604 return;
605
606 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
607
608 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
609 if (!msg)
610 return;
611
612 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
613 if (err) {
614 nlmsg_free(msg);
615 return;
616 }
617
618 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
619 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
620}
621
622static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
623{
624 struct devlink *devlink = info->user_ptr[0];
625 struct sk_buff *msg;
626 int err;
627
628 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
629 if (!msg)
630 return -ENOMEM;
631
632 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
633 info->snd_portid, info->snd_seq, 0);
634 if (err) {
635 nlmsg_free(msg);
636 return err;
637 }
638
639 return genlmsg_reply(msg, info);
640}
641
642static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
643 struct netlink_callback *cb)
644{
645 struct devlink *devlink;
646 int start = cb->args[0];
647 int idx = 0;
648 int err;
649
650 mutex_lock(&devlink_mutex);
651 list_for_each_entry(devlink, &devlink_list, list) {
652 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
653 continue;
654 if (idx < start) {
655 idx++;
656 continue;
657 }
658 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
659 NETLINK_CB(cb->skb).portid,
660 cb->nlh->nlmsg_seq, NLM_F_MULTI);
661 if (err)
662 goto out;
663 idx++;
664 }
665out:
666 mutex_unlock(&devlink_mutex);
667
668 cb->args[0] = idx;
669 return msg->len;
670}
671
672static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
673 struct genl_info *info)
674{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200675 struct devlink_port *devlink_port = info->user_ptr[0];
676 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100677 struct sk_buff *msg;
678 int err;
679
680 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
681 if (!msg)
682 return -ENOMEM;
683
684 err = devlink_nl_port_fill(msg, devlink, devlink_port,
685 DEVLINK_CMD_PORT_NEW,
686 info->snd_portid, info->snd_seq, 0);
687 if (err) {
688 nlmsg_free(msg);
689 return err;
690 }
691
692 return genlmsg_reply(msg, info);
693}
694
695static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
696 struct netlink_callback *cb)
697{
698 struct devlink *devlink;
699 struct devlink_port *devlink_port;
700 int start = cb->args[0];
701 int idx = 0;
702 int err;
703
704 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100705 list_for_each_entry(devlink, &devlink_list, list) {
706 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
707 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100708 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100709 list_for_each_entry(devlink_port, &devlink->port_list, list) {
710 if (idx < start) {
711 idx++;
712 continue;
713 }
714 err = devlink_nl_port_fill(msg, devlink, devlink_port,
715 DEVLINK_CMD_NEW,
716 NETLINK_CB(cb->skb).portid,
717 cb->nlh->nlmsg_seq,
718 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100719 if (err) {
720 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100721 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100722 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100723 idx++;
724 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100725 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100726 }
727out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100728 mutex_unlock(&devlink_mutex);
729
730 cb->args[0] = idx;
731 return msg->len;
732}
733
734static int devlink_port_type_set(struct devlink *devlink,
735 struct devlink_port *devlink_port,
736 enum devlink_port_type port_type)
737
738{
739 int err;
740
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800741 if (devlink->ops->port_type_set) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100742 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
743 return -EINVAL;
Elad Raz6edf1012016-10-23 17:43:05 +0200744 if (port_type == devlink_port->type)
745 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100746 err = devlink->ops->port_type_set(devlink_port, port_type);
747 if (err)
748 return err;
749 devlink_port->desired_type = port_type;
750 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
751 return 0;
752 }
753 return -EOPNOTSUPP;
754}
755
756static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
757 struct genl_info *info)
758{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200759 struct devlink_port *devlink_port = info->user_ptr[0];
760 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100761 int err;
762
763 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
764 enum devlink_port_type port_type;
765
766 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
767 err = devlink_port_type_set(devlink, devlink_port, port_type);
768 if (err)
769 return err;
770 }
771 return 0;
772}
773
David Ahernac0fc8a2018-06-05 08:14:09 -0700774static int devlink_port_split(struct devlink *devlink, u32 port_index,
775 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100776
777{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800778 if (devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -0700779 return devlink->ops->port_split(devlink, port_index, count,
780 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100781 return -EOPNOTSUPP;
782}
783
784static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
785 struct genl_info *info)
786{
787 struct devlink *devlink = info->user_ptr[0];
788 u32 port_index;
789 u32 count;
790
791 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
792 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
793 return -EINVAL;
794
795 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
796 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700797 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100798}
799
David Ahernac0fc8a2018-06-05 08:14:09 -0700800static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
801 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100802
803{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800804 if (devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -0700805 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100806 return -EOPNOTSUPP;
807}
808
809static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
810 struct genl_info *info)
811{
812 struct devlink *devlink = info->user_ptr[0];
813 u32 port_index;
814
815 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
816 return -EINVAL;
817
818 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700819 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100820}
821
Jiri Pirkobf797472016-04-14 18:19:13 +0200822static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
823 struct devlink_sb *devlink_sb,
824 enum devlink_command cmd, u32 portid,
825 u32 seq, int flags)
826{
827 void *hdr;
828
829 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
830 if (!hdr)
831 return -EMSGSIZE;
832
833 if (devlink_nl_put_handle(msg, devlink))
834 goto nla_put_failure;
835 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
836 goto nla_put_failure;
837 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
838 goto nla_put_failure;
839 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
840 devlink_sb->ingress_pools_count))
841 goto nla_put_failure;
842 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
843 devlink_sb->egress_pools_count))
844 goto nla_put_failure;
845 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
846 devlink_sb->ingress_tc_count))
847 goto nla_put_failure;
848 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
849 devlink_sb->egress_tc_count))
850 goto nla_put_failure;
851
852 genlmsg_end(msg, hdr);
853 return 0;
854
855nla_put_failure:
856 genlmsg_cancel(msg, hdr);
857 return -EMSGSIZE;
858}
859
860static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
861 struct genl_info *info)
862{
863 struct devlink *devlink = info->user_ptr[0];
864 struct devlink_sb *devlink_sb = info->user_ptr[1];
865 struct sk_buff *msg;
866 int err;
867
868 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
869 if (!msg)
870 return -ENOMEM;
871
872 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
873 DEVLINK_CMD_SB_NEW,
874 info->snd_portid, info->snd_seq, 0);
875 if (err) {
876 nlmsg_free(msg);
877 return err;
878 }
879
880 return genlmsg_reply(msg, info);
881}
882
883static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
884 struct netlink_callback *cb)
885{
886 struct devlink *devlink;
887 struct devlink_sb *devlink_sb;
888 int start = cb->args[0];
889 int idx = 0;
890 int err;
891
892 mutex_lock(&devlink_mutex);
893 list_for_each_entry(devlink, &devlink_list, list) {
894 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
895 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100896 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200897 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
898 if (idx < start) {
899 idx++;
900 continue;
901 }
902 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
903 DEVLINK_CMD_SB_NEW,
904 NETLINK_CB(cb->skb).portid,
905 cb->nlh->nlmsg_seq,
906 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100907 if (err) {
908 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200909 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100910 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200911 idx++;
912 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100913 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200914 }
915out:
916 mutex_unlock(&devlink_mutex);
917
918 cb->args[0] = idx;
919 return msg->len;
920}
921
922static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
923 struct devlink_sb *devlink_sb,
924 u16 pool_index, enum devlink_command cmd,
925 u32 portid, u32 seq, int flags)
926{
927 struct devlink_sb_pool_info pool_info;
928 void *hdr;
929 int err;
930
931 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
932 pool_index, &pool_info);
933 if (err)
934 return err;
935
936 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
937 if (!hdr)
938 return -EMSGSIZE;
939
940 if (devlink_nl_put_handle(msg, devlink))
941 goto nla_put_failure;
942 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
943 goto nla_put_failure;
944 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
945 goto nla_put_failure;
946 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
947 goto nla_put_failure;
948 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
949 goto nla_put_failure;
950 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
951 pool_info.threshold_type))
952 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -0800953 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
954 pool_info.cell_size))
955 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +0200956
957 genlmsg_end(msg, hdr);
958 return 0;
959
960nla_put_failure:
961 genlmsg_cancel(msg, hdr);
962 return -EMSGSIZE;
963}
964
965static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
966 struct genl_info *info)
967{
968 struct devlink *devlink = info->user_ptr[0];
969 struct devlink_sb *devlink_sb = info->user_ptr[1];
970 struct sk_buff *msg;
971 u16 pool_index;
972 int err;
973
974 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
975 &pool_index);
976 if (err)
977 return err;
978
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800979 if (!devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +0200980 return -EOPNOTSUPP;
981
982 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
983 if (!msg)
984 return -ENOMEM;
985
986 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
987 DEVLINK_CMD_SB_POOL_NEW,
988 info->snd_portid, info->snd_seq, 0);
989 if (err) {
990 nlmsg_free(msg);
991 return err;
992 }
993
994 return genlmsg_reply(msg, info);
995}
996
997static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
998 struct devlink *devlink,
999 struct devlink_sb *devlink_sb,
1000 u32 portid, u32 seq)
1001{
1002 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1003 u16 pool_index;
1004 int err;
1005
1006 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1007 if (*p_idx < start) {
1008 (*p_idx)++;
1009 continue;
1010 }
1011 err = devlink_nl_sb_pool_fill(msg, devlink,
1012 devlink_sb,
1013 pool_index,
1014 DEVLINK_CMD_SB_POOL_NEW,
1015 portid, seq, NLM_F_MULTI);
1016 if (err)
1017 return err;
1018 (*p_idx)++;
1019 }
1020 return 0;
1021}
1022
1023static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1024 struct netlink_callback *cb)
1025{
1026 struct devlink *devlink;
1027 struct devlink_sb *devlink_sb;
1028 int start = cb->args[0];
1029 int idx = 0;
1030 int err;
1031
1032 mutex_lock(&devlink_mutex);
1033 list_for_each_entry(devlink, &devlink_list, list) {
1034 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001035 !devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001036 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001037 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001038 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1039 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1040 devlink_sb,
1041 NETLINK_CB(cb->skb).portid,
1042 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001043 if (err && err != -EOPNOTSUPP) {
1044 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001045 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001046 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001047 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001048 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001049 }
1050out:
1051 mutex_unlock(&devlink_mutex);
1052
1053 cb->args[0] = idx;
1054 return msg->len;
1055}
1056
1057static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1058 u16 pool_index, u32 size,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001059 enum devlink_sb_threshold_type threshold_type,
1060 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001061
1062{
1063 const struct devlink_ops *ops = devlink->ops;
1064
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001065 if (ops->sb_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001066 return ops->sb_pool_set(devlink, sb_index, pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001067 size, threshold_type, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001068 return -EOPNOTSUPP;
1069}
1070
1071static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1072 struct genl_info *info)
1073{
1074 struct devlink *devlink = info->user_ptr[0];
1075 struct devlink_sb *devlink_sb = info->user_ptr[1];
1076 enum devlink_sb_threshold_type threshold_type;
1077 u16 pool_index;
1078 u32 size;
1079 int err;
1080
1081 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1082 &pool_index);
1083 if (err)
1084 return err;
1085
1086 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1087 if (err)
1088 return err;
1089
1090 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1091 return -EINVAL;
1092
1093 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1094 return devlink_sb_pool_set(devlink, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001095 pool_index, size, threshold_type,
1096 info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001097}
1098
1099static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1100 struct devlink *devlink,
1101 struct devlink_port *devlink_port,
1102 struct devlink_sb *devlink_sb,
1103 u16 pool_index,
1104 enum devlink_command cmd,
1105 u32 portid, u32 seq, int flags)
1106{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001107 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001108 u32 threshold;
1109 void *hdr;
1110 int err;
1111
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001112 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1113 pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001114 if (err)
1115 return err;
1116
1117 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1118 if (!hdr)
1119 return -EMSGSIZE;
1120
1121 if (devlink_nl_put_handle(msg, devlink))
1122 goto nla_put_failure;
1123 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1124 goto nla_put_failure;
1125 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1126 goto nla_put_failure;
1127 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1128 goto nla_put_failure;
1129 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1130 goto nla_put_failure;
1131
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001132 if (ops->sb_occ_port_pool_get) {
1133 u32 cur;
1134 u32 max;
1135
1136 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1137 pool_index, &cur, &max);
1138 if (err && err != -EOPNOTSUPP)
1139 return err;
1140 if (!err) {
1141 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1142 goto nla_put_failure;
1143 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1144 goto nla_put_failure;
1145 }
1146 }
1147
Jiri Pirkobf797472016-04-14 18:19:13 +02001148 genlmsg_end(msg, hdr);
1149 return 0;
1150
1151nla_put_failure:
1152 genlmsg_cancel(msg, hdr);
1153 return -EMSGSIZE;
1154}
1155
1156static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1157 struct genl_info *info)
1158{
1159 struct devlink_port *devlink_port = info->user_ptr[0];
1160 struct devlink *devlink = devlink_port->devlink;
1161 struct devlink_sb *devlink_sb = info->user_ptr[1];
1162 struct sk_buff *msg;
1163 u16 pool_index;
1164 int err;
1165
1166 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1167 &pool_index);
1168 if (err)
1169 return err;
1170
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001171 if (!devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001172 return -EOPNOTSUPP;
1173
1174 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1175 if (!msg)
1176 return -ENOMEM;
1177
1178 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1179 devlink_sb, pool_index,
1180 DEVLINK_CMD_SB_PORT_POOL_NEW,
1181 info->snd_portid, info->snd_seq, 0);
1182 if (err) {
1183 nlmsg_free(msg);
1184 return err;
1185 }
1186
1187 return genlmsg_reply(msg, info);
1188}
1189
1190static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1191 struct devlink *devlink,
1192 struct devlink_sb *devlink_sb,
1193 u32 portid, u32 seq)
1194{
1195 struct devlink_port *devlink_port;
1196 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1197 u16 pool_index;
1198 int err;
1199
1200 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1201 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1202 if (*p_idx < start) {
1203 (*p_idx)++;
1204 continue;
1205 }
1206 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1207 devlink_port,
1208 devlink_sb,
1209 pool_index,
1210 DEVLINK_CMD_SB_PORT_POOL_NEW,
1211 portid, seq,
1212 NLM_F_MULTI);
1213 if (err)
1214 return err;
1215 (*p_idx)++;
1216 }
1217 }
1218 return 0;
1219}
1220
1221static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1222 struct netlink_callback *cb)
1223{
1224 struct devlink *devlink;
1225 struct devlink_sb *devlink_sb;
1226 int start = cb->args[0];
1227 int idx = 0;
1228 int err;
1229
1230 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001231 list_for_each_entry(devlink, &devlink_list, list) {
1232 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001233 !devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001234 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001235 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001236 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1237 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1238 devlink, devlink_sb,
1239 NETLINK_CB(cb->skb).portid,
1240 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001241 if (err && err != -EOPNOTSUPP) {
1242 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001243 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001244 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001245 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001246 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001247 }
1248out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001249 mutex_unlock(&devlink_mutex);
1250
1251 cb->args[0] = idx;
1252 return msg->len;
1253}
1254
1255static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1256 unsigned int sb_index, u16 pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001257 u32 threshold,
1258 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001259
1260{
1261 const struct devlink_ops *ops = devlink_port->devlink->ops;
1262
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001263 if (ops->sb_port_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001264 return ops->sb_port_pool_set(devlink_port, sb_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001265 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001266 return -EOPNOTSUPP;
1267}
1268
1269static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1270 struct genl_info *info)
1271{
1272 struct devlink_port *devlink_port = info->user_ptr[0];
1273 struct devlink_sb *devlink_sb = info->user_ptr[1];
1274 u16 pool_index;
1275 u32 threshold;
1276 int err;
1277
1278 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1279 &pool_index);
1280 if (err)
1281 return err;
1282
1283 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1284 return -EINVAL;
1285
1286 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1287 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001288 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001289}
1290
1291static int
1292devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1293 struct devlink_port *devlink_port,
1294 struct devlink_sb *devlink_sb, u16 tc_index,
1295 enum devlink_sb_pool_type pool_type,
1296 enum devlink_command cmd,
1297 u32 portid, u32 seq, int flags)
1298{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001299 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001300 u16 pool_index;
1301 u32 threshold;
1302 void *hdr;
1303 int err;
1304
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001305 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1306 tc_index, pool_type,
1307 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001308 if (err)
1309 return err;
1310
1311 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1312 if (!hdr)
1313 return -EMSGSIZE;
1314
1315 if (devlink_nl_put_handle(msg, devlink))
1316 goto nla_put_failure;
1317 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1318 goto nla_put_failure;
1319 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1320 goto nla_put_failure;
1321 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1322 goto nla_put_failure;
1323 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1324 goto nla_put_failure;
1325 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1326 goto nla_put_failure;
1327 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1328 goto nla_put_failure;
1329
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001330 if (ops->sb_occ_tc_port_bind_get) {
1331 u32 cur;
1332 u32 max;
1333
1334 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1335 devlink_sb->index,
1336 tc_index, pool_type,
1337 &cur, &max);
1338 if (err && err != -EOPNOTSUPP)
1339 return err;
1340 if (!err) {
1341 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1342 goto nla_put_failure;
1343 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1344 goto nla_put_failure;
1345 }
1346 }
1347
Jiri Pirkobf797472016-04-14 18:19:13 +02001348 genlmsg_end(msg, hdr);
1349 return 0;
1350
1351nla_put_failure:
1352 genlmsg_cancel(msg, hdr);
1353 return -EMSGSIZE;
1354}
1355
1356static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1357 struct genl_info *info)
1358{
1359 struct devlink_port *devlink_port = info->user_ptr[0];
1360 struct devlink *devlink = devlink_port->devlink;
1361 struct devlink_sb *devlink_sb = info->user_ptr[1];
1362 struct sk_buff *msg;
1363 enum devlink_sb_pool_type pool_type;
1364 u16 tc_index;
1365 int err;
1366
1367 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1368 if (err)
1369 return err;
1370
1371 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1372 pool_type, &tc_index);
1373 if (err)
1374 return err;
1375
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001376 if (!devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001377 return -EOPNOTSUPP;
1378
1379 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1380 if (!msg)
1381 return -ENOMEM;
1382
1383 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1384 devlink_sb, tc_index, pool_type,
1385 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1386 info->snd_portid,
1387 info->snd_seq, 0);
1388 if (err) {
1389 nlmsg_free(msg);
1390 return err;
1391 }
1392
1393 return genlmsg_reply(msg, info);
1394}
1395
1396static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1397 int start, int *p_idx,
1398 struct devlink *devlink,
1399 struct devlink_sb *devlink_sb,
1400 u32 portid, u32 seq)
1401{
1402 struct devlink_port *devlink_port;
1403 u16 tc_index;
1404 int err;
1405
1406 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1407 for (tc_index = 0;
1408 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1409 if (*p_idx < start) {
1410 (*p_idx)++;
1411 continue;
1412 }
1413 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1414 devlink_port,
1415 devlink_sb,
1416 tc_index,
1417 DEVLINK_SB_POOL_TYPE_INGRESS,
1418 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1419 portid, seq,
1420 NLM_F_MULTI);
1421 if (err)
1422 return err;
1423 (*p_idx)++;
1424 }
1425 for (tc_index = 0;
1426 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1427 if (*p_idx < start) {
1428 (*p_idx)++;
1429 continue;
1430 }
1431 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1432 devlink_port,
1433 devlink_sb,
1434 tc_index,
1435 DEVLINK_SB_POOL_TYPE_EGRESS,
1436 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1437 portid, seq,
1438 NLM_F_MULTI);
1439 if (err)
1440 return err;
1441 (*p_idx)++;
1442 }
1443 }
1444 return 0;
1445}
1446
1447static int
1448devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1449 struct netlink_callback *cb)
1450{
1451 struct devlink *devlink;
1452 struct devlink_sb *devlink_sb;
1453 int start = cb->args[0];
1454 int idx = 0;
1455 int err;
1456
1457 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001458 list_for_each_entry(devlink, &devlink_list, list) {
1459 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001460 !devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001461 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001462
1463 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001464 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1465 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1466 devlink,
1467 devlink_sb,
1468 NETLINK_CB(cb->skb).portid,
1469 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001470 if (err && err != -EOPNOTSUPP) {
1471 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001472 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001473 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001474 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001475 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001476 }
1477out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001478 mutex_unlock(&devlink_mutex);
1479
1480 cb->args[0] = idx;
1481 return msg->len;
1482}
1483
1484static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1485 unsigned int sb_index, u16 tc_index,
1486 enum devlink_sb_pool_type pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001487 u16 pool_index, u32 threshold,
1488 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001489
1490{
1491 const struct devlink_ops *ops = devlink_port->devlink->ops;
1492
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001493 if (ops->sb_tc_pool_bind_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001494 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1495 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001496 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001497 return -EOPNOTSUPP;
1498}
1499
1500static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1501 struct genl_info *info)
1502{
1503 struct devlink_port *devlink_port = info->user_ptr[0];
1504 struct devlink_sb *devlink_sb = info->user_ptr[1];
1505 enum devlink_sb_pool_type pool_type;
1506 u16 tc_index;
1507 u16 pool_index;
1508 u32 threshold;
1509 int err;
1510
1511 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1512 if (err)
1513 return err;
1514
1515 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1516 pool_type, &tc_index);
1517 if (err)
1518 return err;
1519
1520 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1521 &pool_index);
1522 if (err)
1523 return err;
1524
1525 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1526 return -EINVAL;
1527
1528 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1529 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1530 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001531 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001532}
1533
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001534static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1535 struct genl_info *info)
1536{
1537 struct devlink *devlink = info->user_ptr[0];
1538 struct devlink_sb *devlink_sb = info->user_ptr[1];
1539 const struct devlink_ops *ops = devlink->ops;
1540
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001541 if (ops->sb_occ_snapshot)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001542 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1543 return -EOPNOTSUPP;
1544}
1545
1546static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1547 struct genl_info *info)
1548{
1549 struct devlink *devlink = info->user_ptr[0];
1550 struct devlink_sb *devlink_sb = info->user_ptr[1];
1551 const struct devlink_ops *ops = devlink->ops;
1552
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001553 if (ops->sb_occ_max_clear)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001554 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1555 return -EOPNOTSUPP;
1556}
1557
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001558static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1559 enum devlink_command cmd, u32 portid,
1560 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001561{
Roi Dayan59bfde02016-11-22 23:09:57 +02001562 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001563 enum devlink_eswitch_encap_mode encap_mode;
1564 u8 inline_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001565 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001566 int err = 0;
1567 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001568
1569 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1570 if (!hdr)
1571 return -EMSGSIZE;
1572
Roi Dayan59bfde02016-11-22 23:09:57 +02001573 err = devlink_nl_put_handle(msg, devlink);
1574 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001575 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001576
Jiri Pirko4456f612017-02-09 15:54:36 +01001577 if (ops->eswitch_mode_get) {
1578 err = ops->eswitch_mode_get(devlink, &mode);
1579 if (err)
1580 goto nla_put_failure;
1581 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1582 if (err)
1583 goto nla_put_failure;
1584 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001585
1586 if (ops->eswitch_inline_mode_get) {
1587 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1588 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001589 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001590 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1591 inline_mode);
1592 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001593 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001594 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001595
Roi Dayanf43e9b02016-09-25 13:52:44 +03001596 if (ops->eswitch_encap_mode_get) {
1597 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1598 if (err)
1599 goto nla_put_failure;
1600 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1601 if (err)
1602 goto nla_put_failure;
1603 }
1604
Or Gerlitz08f4b592016-07-01 14:51:01 +03001605 genlmsg_end(msg, hdr);
1606 return 0;
1607
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001608nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001609 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001610 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001611}
1612
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001613static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1614 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001615{
1616 struct devlink *devlink = info->user_ptr[0];
Or Gerlitz08f4b592016-07-01 14:51:01 +03001617 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001618 int err;
1619
Or Gerlitz08f4b592016-07-01 14:51:01 +03001620 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1621 if (!msg)
1622 return -ENOMEM;
1623
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001624 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1625 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001626
1627 if (err) {
1628 nlmsg_free(msg);
1629 return err;
1630 }
1631
1632 return genlmsg_reply(msg, info);
1633}
1634
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001635static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1636 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001637{
1638 struct devlink *devlink = info->user_ptr[0];
1639 const struct devlink_ops *ops = devlink->ops;
Leon Romanovsky98fdbea2019-06-12 15:20:11 +03001640 enum devlink_eswitch_encap_mode encap_mode;
1641 u8 inline_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001642 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001643 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001644
Roi Dayan59bfde02016-11-22 23:09:57 +02001645 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1646 if (!ops->eswitch_mode_set)
1647 return -EOPNOTSUPP;
1648 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001649 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001650 if (err)
1651 return err;
1652 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001653
Roi Dayan59bfde02016-11-22 23:09:57 +02001654 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1655 if (!ops->eswitch_inline_mode_set)
1656 return -EOPNOTSUPP;
1657 inline_mode = nla_get_u8(
1658 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001659 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1660 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001661 if (err)
1662 return err;
1663 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03001664
1665 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1666 if (!ops->eswitch_encap_mode_set)
1667 return -EOPNOTSUPP;
1668 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001669 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1670 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03001671 if (err)
1672 return err;
1673 }
1674
Roi Dayan59bfde02016-11-22 23:09:57 +02001675 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001676}
1677
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001678int devlink_dpipe_match_put(struct sk_buff *skb,
1679 struct devlink_dpipe_match *match)
1680{
1681 struct devlink_dpipe_header *header = match->header;
1682 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1683 struct nlattr *match_attr;
1684
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001685 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001686 if (!match_attr)
1687 return -EMSGSIZE;
1688
1689 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1690 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1691 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1692 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1693 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1694 goto nla_put_failure;
1695
1696 nla_nest_end(skb, match_attr);
1697 return 0;
1698
1699nla_put_failure:
1700 nla_nest_cancel(skb, match_attr);
1701 return -EMSGSIZE;
1702}
1703EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1704
1705static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1706 struct sk_buff *skb)
1707{
1708 struct nlattr *matches_attr;
1709
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001710 matches_attr = nla_nest_start_noflag(skb,
1711 DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001712 if (!matches_attr)
1713 return -EMSGSIZE;
1714
1715 if (table->table_ops->matches_dump(table->priv, skb))
1716 goto nla_put_failure;
1717
1718 nla_nest_end(skb, matches_attr);
1719 return 0;
1720
1721nla_put_failure:
1722 nla_nest_cancel(skb, matches_attr);
1723 return -EMSGSIZE;
1724}
1725
1726int devlink_dpipe_action_put(struct sk_buff *skb,
1727 struct devlink_dpipe_action *action)
1728{
1729 struct devlink_dpipe_header *header = action->header;
1730 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1731 struct nlattr *action_attr;
1732
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001733 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001734 if (!action_attr)
1735 return -EMSGSIZE;
1736
1737 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1738 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1739 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1740 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1741 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1742 goto nla_put_failure;
1743
1744 nla_nest_end(skb, action_attr);
1745 return 0;
1746
1747nla_put_failure:
1748 nla_nest_cancel(skb, action_attr);
1749 return -EMSGSIZE;
1750}
1751EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1752
1753static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1754 struct sk_buff *skb)
1755{
1756 struct nlattr *actions_attr;
1757
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001758 actions_attr = nla_nest_start_noflag(skb,
1759 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001760 if (!actions_attr)
1761 return -EMSGSIZE;
1762
1763 if (table->table_ops->actions_dump(table->priv, skb))
1764 goto nla_put_failure;
1765
1766 nla_nest_end(skb, actions_attr);
1767 return 0;
1768
1769nla_put_failure:
1770 nla_nest_cancel(skb, actions_attr);
1771 return -EMSGSIZE;
1772}
1773
1774static int devlink_dpipe_table_put(struct sk_buff *skb,
1775 struct devlink_dpipe_table *table)
1776{
1777 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001778 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001779
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001780 table_size = table->table_ops->size_get(table->priv);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001781 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001782 if (!table_attr)
1783 return -EMSGSIZE;
1784
1785 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001786 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001787 DEVLINK_ATTR_PAD))
1788 goto nla_put_failure;
1789 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1790 table->counters_enabled))
1791 goto nla_put_failure;
1792
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001793 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02001794 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1795 table->resource_id, DEVLINK_ATTR_PAD) ||
1796 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1797 table->resource_units, DEVLINK_ATTR_PAD))
1798 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001799 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001800 if (devlink_dpipe_matches_put(table, skb))
1801 goto nla_put_failure;
1802
1803 if (devlink_dpipe_actions_put(table, skb))
1804 goto nla_put_failure;
1805
1806 nla_nest_end(skb, table_attr);
1807 return 0;
1808
1809nla_put_failure:
1810 nla_nest_cancel(skb, table_attr);
1811 return -EMSGSIZE;
1812}
1813
1814static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1815 struct genl_info *info)
1816{
1817 int err;
1818
1819 if (*pskb) {
1820 err = genlmsg_reply(*pskb, info);
1821 if (err)
1822 return err;
1823 }
1824 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1825 if (!*pskb)
1826 return -ENOMEM;
1827 return 0;
1828}
1829
1830static int devlink_dpipe_tables_fill(struct genl_info *info,
1831 enum devlink_command cmd, int flags,
1832 struct list_head *dpipe_tables,
1833 const char *table_name)
1834{
1835 struct devlink *devlink = info->user_ptr[0];
1836 struct devlink_dpipe_table *table;
1837 struct nlattr *tables_attr;
1838 struct sk_buff *skb = NULL;
1839 struct nlmsghdr *nlh;
1840 bool incomplete;
1841 void *hdr;
1842 int i;
1843 int err;
1844
1845 table = list_first_entry(dpipe_tables,
1846 struct devlink_dpipe_table, list);
1847start_again:
1848 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1849 if (err)
1850 return err;
1851
1852 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1853 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08001854 if (!hdr) {
1855 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001856 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08001857 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001858
1859 if (devlink_nl_put_handle(skb, devlink))
1860 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001861 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001862 if (!tables_attr)
1863 goto nla_put_failure;
1864
1865 i = 0;
1866 incomplete = false;
1867 list_for_each_entry_from(table, dpipe_tables, list) {
1868 if (!table_name) {
1869 err = devlink_dpipe_table_put(skb, table);
1870 if (err) {
1871 if (!i)
1872 goto err_table_put;
1873 incomplete = true;
1874 break;
1875 }
1876 } else {
1877 if (!strcmp(table->name, table_name)) {
1878 err = devlink_dpipe_table_put(skb, table);
1879 if (err)
1880 break;
1881 }
1882 }
1883 i++;
1884 }
1885
1886 nla_nest_end(skb, tables_attr);
1887 genlmsg_end(skb, hdr);
1888 if (incomplete)
1889 goto start_again;
1890
1891send_done:
1892 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1893 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1894 if (!nlh) {
1895 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1896 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02001897 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001898 goto send_done;
1899 }
1900
1901 return genlmsg_reply(skb, info);
1902
1903nla_put_failure:
1904 err = -EMSGSIZE;
1905err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001906 nlmsg_free(skb);
1907 return err;
1908}
1909
1910static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
1911 struct genl_info *info)
1912{
1913 struct devlink *devlink = info->user_ptr[0];
1914 const char *table_name = NULL;
1915
1916 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
1917 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
1918
1919 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
1920 &devlink->dpipe_table_list,
1921 table_name);
1922}
1923
1924static int devlink_dpipe_value_put(struct sk_buff *skb,
1925 struct devlink_dpipe_value *value)
1926{
1927 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
1928 value->value_size, value->value))
1929 return -EMSGSIZE;
1930 if (value->mask)
1931 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
1932 value->value_size, value->mask))
1933 return -EMSGSIZE;
1934 if (value->mapping_valid)
1935 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
1936 value->mapping_value))
1937 return -EMSGSIZE;
1938 return 0;
1939}
1940
1941static int devlink_dpipe_action_value_put(struct sk_buff *skb,
1942 struct devlink_dpipe_value *value)
1943{
1944 if (!value->action)
1945 return -EINVAL;
1946 if (devlink_dpipe_action_put(skb, value->action))
1947 return -EMSGSIZE;
1948 if (devlink_dpipe_value_put(skb, value))
1949 return -EMSGSIZE;
1950 return 0;
1951}
1952
1953static int devlink_dpipe_action_values_put(struct sk_buff *skb,
1954 struct devlink_dpipe_value *values,
1955 unsigned int values_count)
1956{
1957 struct nlattr *action_attr;
1958 int i;
1959 int err;
1960
1961 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001962 action_attr = nla_nest_start_noflag(skb,
1963 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001964 if (!action_attr)
1965 return -EMSGSIZE;
1966 err = devlink_dpipe_action_value_put(skb, &values[i]);
1967 if (err)
1968 goto err_action_value_put;
1969 nla_nest_end(skb, action_attr);
1970 }
1971 return 0;
1972
1973err_action_value_put:
1974 nla_nest_cancel(skb, action_attr);
1975 return err;
1976}
1977
1978static int devlink_dpipe_match_value_put(struct sk_buff *skb,
1979 struct devlink_dpipe_value *value)
1980{
1981 if (!value->match)
1982 return -EINVAL;
1983 if (devlink_dpipe_match_put(skb, value->match))
1984 return -EMSGSIZE;
1985 if (devlink_dpipe_value_put(skb, value))
1986 return -EMSGSIZE;
1987 return 0;
1988}
1989
1990static int devlink_dpipe_match_values_put(struct sk_buff *skb,
1991 struct devlink_dpipe_value *values,
1992 unsigned int values_count)
1993{
1994 struct nlattr *match_attr;
1995 int i;
1996 int err;
1997
1998 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001999 match_attr = nla_nest_start_noflag(skb,
2000 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002001 if (!match_attr)
2002 return -EMSGSIZE;
2003 err = devlink_dpipe_match_value_put(skb, &values[i]);
2004 if (err)
2005 goto err_match_value_put;
2006 nla_nest_end(skb, match_attr);
2007 }
2008 return 0;
2009
2010err_match_value_put:
2011 nla_nest_cancel(skb, match_attr);
2012 return err;
2013}
2014
2015static int devlink_dpipe_entry_put(struct sk_buff *skb,
2016 struct devlink_dpipe_entry *entry)
2017{
2018 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2019 int err;
2020
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002021 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002022 if (!entry_attr)
2023 return -EMSGSIZE;
2024
2025 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2026 DEVLINK_ATTR_PAD))
2027 goto nla_put_failure;
2028 if (entry->counter_valid)
2029 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2030 entry->counter, DEVLINK_ATTR_PAD))
2031 goto nla_put_failure;
2032
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002033 matches_attr = nla_nest_start_noflag(skb,
2034 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002035 if (!matches_attr)
2036 goto nla_put_failure;
2037
2038 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2039 entry->match_values_count);
2040 if (err) {
2041 nla_nest_cancel(skb, matches_attr);
2042 goto err_match_values_put;
2043 }
2044 nla_nest_end(skb, matches_attr);
2045
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002046 actions_attr = nla_nest_start_noflag(skb,
2047 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002048 if (!actions_attr)
2049 goto nla_put_failure;
2050
2051 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2052 entry->action_values_count);
2053 if (err) {
2054 nla_nest_cancel(skb, actions_attr);
2055 goto err_action_values_put;
2056 }
2057 nla_nest_end(skb, actions_attr);
2058
2059 nla_nest_end(skb, entry_attr);
2060 return 0;
2061
2062nla_put_failure:
2063 err = -EMSGSIZE;
2064err_match_values_put:
2065err_action_values_put:
2066 nla_nest_cancel(skb, entry_attr);
2067 return err;
2068}
2069
2070static struct devlink_dpipe_table *
2071devlink_dpipe_table_find(struct list_head *dpipe_tables,
2072 const char *table_name)
2073{
2074 struct devlink_dpipe_table *table;
2075
2076 list_for_each_entry_rcu(table, dpipe_tables, list) {
2077 if (!strcmp(table->name, table_name))
2078 return table;
2079 }
2080 return NULL;
2081}
2082
2083int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2084{
2085 struct devlink *devlink;
2086 int err;
2087
2088 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2089 dump_ctx->info);
2090 if (err)
2091 return err;
2092
2093 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2094 dump_ctx->info->snd_portid,
2095 dump_ctx->info->snd_seq,
2096 &devlink_nl_family, NLM_F_MULTI,
2097 dump_ctx->cmd);
2098 if (!dump_ctx->hdr)
2099 goto nla_put_failure;
2100
2101 devlink = dump_ctx->info->user_ptr[0];
2102 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2103 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002104 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2105 DEVLINK_ATTR_DPIPE_ENTRIES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002106 if (!dump_ctx->nest)
2107 goto nla_put_failure;
2108 return 0;
2109
2110nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002111 nlmsg_free(dump_ctx->skb);
2112 return -EMSGSIZE;
2113}
2114EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2115
2116int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2117 struct devlink_dpipe_entry *entry)
2118{
2119 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2120}
2121EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2122
2123int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2124{
2125 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2126 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2127 return 0;
2128}
2129EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2130
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002131void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2132
2133{
2134 unsigned int value_count, value_index;
2135 struct devlink_dpipe_value *value;
2136
2137 value = entry->action_values;
2138 value_count = entry->action_values_count;
2139 for (value_index = 0; value_index < value_count; value_index++) {
2140 kfree(value[value_index].value);
2141 kfree(value[value_index].mask);
2142 }
2143
2144 value = entry->match_values;
2145 value_count = entry->match_values_count;
2146 for (value_index = 0; value_index < value_count; value_index++) {
2147 kfree(value[value_index].value);
2148 kfree(value[value_index].mask);
2149 }
2150}
2151EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2152
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002153static int devlink_dpipe_entries_fill(struct genl_info *info,
2154 enum devlink_command cmd, int flags,
2155 struct devlink_dpipe_table *table)
2156{
2157 struct devlink_dpipe_dump_ctx dump_ctx;
2158 struct nlmsghdr *nlh;
2159 int err;
2160
2161 dump_ctx.skb = NULL;
2162 dump_ctx.cmd = cmd;
2163 dump_ctx.info = info;
2164
2165 err = table->table_ops->entries_dump(table->priv,
2166 table->counters_enabled,
2167 &dump_ctx);
2168 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002169 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002170
2171send_done:
2172 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2173 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2174 if (!nlh) {
2175 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2176 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002177 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002178 goto send_done;
2179 }
2180 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002181}
2182
2183static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2184 struct genl_info *info)
2185{
2186 struct devlink *devlink = info->user_ptr[0];
2187 struct devlink_dpipe_table *table;
2188 const char *table_name;
2189
2190 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2191 return -EINVAL;
2192
2193 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2194 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2195 table_name);
2196 if (!table)
2197 return -EINVAL;
2198
2199 if (!table->table_ops->entries_dump)
2200 return -EINVAL;
2201
2202 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2203 0, table);
2204}
2205
2206static int devlink_dpipe_fields_put(struct sk_buff *skb,
2207 const struct devlink_dpipe_header *header)
2208{
2209 struct devlink_dpipe_field *field;
2210 struct nlattr *field_attr;
2211 int i;
2212
2213 for (i = 0; i < header->fields_count; i++) {
2214 field = &header->fields[i];
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002215 field_attr = nla_nest_start_noflag(skb,
2216 DEVLINK_ATTR_DPIPE_FIELD);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002217 if (!field_attr)
2218 return -EMSGSIZE;
2219 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2220 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2221 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2222 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2223 goto nla_put_failure;
2224 nla_nest_end(skb, field_attr);
2225 }
2226 return 0;
2227
2228nla_put_failure:
2229 nla_nest_cancel(skb, field_attr);
2230 return -EMSGSIZE;
2231}
2232
2233static int devlink_dpipe_header_put(struct sk_buff *skb,
2234 struct devlink_dpipe_header *header)
2235{
2236 struct nlattr *fields_attr, *header_attr;
2237 int err;
2238
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002239 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002240 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002241 return -EMSGSIZE;
2242
2243 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2244 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2245 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2246 goto nla_put_failure;
2247
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002248 fields_attr = nla_nest_start_noflag(skb,
2249 DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002250 if (!fields_attr)
2251 goto nla_put_failure;
2252
2253 err = devlink_dpipe_fields_put(skb, header);
2254 if (err) {
2255 nla_nest_cancel(skb, fields_attr);
2256 goto nla_put_failure;
2257 }
2258 nla_nest_end(skb, fields_attr);
2259 nla_nest_end(skb, header_attr);
2260 return 0;
2261
2262nla_put_failure:
2263 err = -EMSGSIZE;
2264 nla_nest_cancel(skb, header_attr);
2265 return err;
2266}
2267
2268static int devlink_dpipe_headers_fill(struct genl_info *info,
2269 enum devlink_command cmd, int flags,
2270 struct devlink_dpipe_headers *
2271 dpipe_headers)
2272{
2273 struct devlink *devlink = info->user_ptr[0];
2274 struct nlattr *headers_attr;
2275 struct sk_buff *skb = NULL;
2276 struct nlmsghdr *nlh;
2277 void *hdr;
2278 int i, j;
2279 int err;
2280
2281 i = 0;
2282start_again:
2283 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2284 if (err)
2285 return err;
2286
2287 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2288 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002289 if (!hdr) {
2290 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002291 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002292 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002293
2294 if (devlink_nl_put_handle(skb, devlink))
2295 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002296 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002297 if (!headers_attr)
2298 goto nla_put_failure;
2299
2300 j = 0;
2301 for (; i < dpipe_headers->headers_count; i++) {
2302 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2303 if (err) {
2304 if (!j)
2305 goto err_table_put;
2306 break;
2307 }
2308 j++;
2309 }
2310 nla_nest_end(skb, headers_attr);
2311 genlmsg_end(skb, hdr);
2312 if (i != dpipe_headers->headers_count)
2313 goto start_again;
2314
2315send_done:
2316 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2317 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2318 if (!nlh) {
2319 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2320 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002321 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002322 goto send_done;
2323 }
2324 return genlmsg_reply(skb, info);
2325
2326nla_put_failure:
2327 err = -EMSGSIZE;
2328err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002329 nlmsg_free(skb);
2330 return err;
2331}
2332
2333static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2334 struct genl_info *info)
2335{
2336 struct devlink *devlink = info->user_ptr[0];
2337
2338 if (!devlink->dpipe_headers)
2339 return -EOPNOTSUPP;
2340 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2341 0, devlink->dpipe_headers);
2342}
2343
2344static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2345 const char *table_name,
2346 bool enable)
2347{
2348 struct devlink_dpipe_table *table;
2349
2350 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2351 table_name);
2352 if (!table)
2353 return -EINVAL;
2354
2355 if (table->counter_control_extern)
2356 return -EOPNOTSUPP;
2357
2358 if (!(table->counters_enabled ^ enable))
2359 return 0;
2360
2361 table->counters_enabled = enable;
2362 if (table->table_ops->counters_set_update)
2363 table->table_ops->counters_set_update(table->priv, enable);
2364 return 0;
2365}
2366
2367static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2368 struct genl_info *info)
2369{
2370 struct devlink *devlink = info->user_ptr[0];
2371 const char *table_name;
2372 bool counters_enable;
2373
2374 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2375 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2376 return -EINVAL;
2377
2378 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2379 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2380
2381 return devlink_dpipe_table_counters_set(devlink, table_name,
2382 counters_enable);
2383}
2384
Wei Yongjun43dd7512018-01-17 03:27:42 +00002385static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002386devlink_resource_find(struct devlink *devlink,
2387 struct devlink_resource *resource, u64 resource_id)
2388{
2389 struct list_head *resource_list;
2390
2391 if (resource)
2392 resource_list = &resource->resource_list;
2393 else
2394 resource_list = &devlink->resource_list;
2395
2396 list_for_each_entry(resource, resource_list, list) {
2397 struct devlink_resource *child_resource;
2398
2399 if (resource->id == resource_id)
2400 return resource;
2401
2402 child_resource = devlink_resource_find(devlink, resource,
2403 resource_id);
2404 if (child_resource)
2405 return child_resource;
2406 }
2407 return NULL;
2408}
2409
Wei Yongjun43dd7512018-01-17 03:27:42 +00002410static void
2411devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002412{
2413 struct devlink_resource *child_resource;
2414 bool size_valid = true;
2415 u64 parts_size = 0;
2416
2417 if (list_empty(&resource->resource_list))
2418 goto out;
2419
2420 list_for_each_entry(child_resource, &resource->resource_list, list)
2421 parts_size += child_resource->size_new;
2422
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002423 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002424 size_valid = false;
2425out:
2426 resource->size_valid = size_valid;
2427}
2428
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002429static int
2430devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2431 struct netlink_ext_ack *extack)
2432{
2433 u64 reminder;
2434 int err = 0;
2435
David S. Miller0f3e9c92018-03-06 00:53:44 -05002436 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002437 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2438 err = -EINVAL;
2439 }
2440
David S. Miller0f3e9c92018-03-06 00:53:44 -05002441 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002442 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2443 err = -EINVAL;
2444 }
2445
David S. Miller0f3e9c92018-03-06 00:53:44 -05002446 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002447 if (reminder) {
2448 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2449 err = -EINVAL;
2450 }
2451
2452 return err;
2453}
2454
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002455static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2456 struct genl_info *info)
2457{
2458 struct devlink *devlink = info->user_ptr[0];
2459 struct devlink_resource *resource;
2460 u64 resource_id;
2461 u64 size;
2462 int err;
2463
2464 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2465 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2466 return -EINVAL;
2467 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2468
2469 resource = devlink_resource_find(devlink, NULL, resource_id);
2470 if (!resource)
2471 return -EINVAL;
2472
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002473 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002474 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002475 if (err)
2476 return err;
2477
2478 resource->size_new = size;
2479 devlink_resource_validate_children(resource);
2480 if (resource->parent)
2481 devlink_resource_validate_children(resource->parent);
2482 return 0;
2483}
2484
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002485static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002486devlink_resource_size_params_put(struct devlink_resource *resource,
2487 struct sk_buff *skb)
2488{
2489 struct devlink_resource_size_params *size_params;
2490
Jiri Pirko77d27092018-02-28 13:12:09 +01002491 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002492 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2493 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2494 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2495 size_params->size_max, DEVLINK_ATTR_PAD) ||
2496 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2497 size_params->size_min, DEVLINK_ATTR_PAD) ||
2498 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2499 return -EMSGSIZE;
2500 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002501}
2502
Jiri Pirkofc56be42018-04-05 22:13:21 +02002503static int devlink_resource_occ_put(struct devlink_resource *resource,
2504 struct sk_buff *skb)
2505{
2506 if (!resource->occ_get)
2507 return 0;
2508 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2509 resource->occ_get(resource->occ_get_priv),
2510 DEVLINK_ATTR_PAD);
2511}
2512
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002513static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2514 struct devlink_resource *resource)
2515{
2516 struct devlink_resource *child_resource;
2517 struct nlattr *child_resource_attr;
2518 struct nlattr *resource_attr;
2519
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002520 resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002521 if (!resource_attr)
2522 return -EMSGSIZE;
2523
2524 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2525 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2526 DEVLINK_ATTR_PAD) ||
2527 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2528 DEVLINK_ATTR_PAD))
2529 goto nla_put_failure;
2530 if (resource->size != resource->size_new)
2531 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2532 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002533 if (devlink_resource_occ_put(resource, skb))
2534 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002535 if (devlink_resource_size_params_put(resource, skb))
2536 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002537 if (list_empty(&resource->resource_list))
2538 goto out;
2539
2540 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2541 resource->size_valid))
2542 goto nla_put_failure;
2543
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002544 child_resource_attr = nla_nest_start_noflag(skb,
2545 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002546 if (!child_resource_attr)
2547 goto nla_put_failure;
2548
2549 list_for_each_entry(child_resource, &resource->resource_list, list) {
2550 if (devlink_resource_put(devlink, skb, child_resource))
2551 goto resource_put_failure;
2552 }
2553
2554 nla_nest_end(skb, child_resource_attr);
2555out:
2556 nla_nest_end(skb, resource_attr);
2557 return 0;
2558
2559resource_put_failure:
2560 nla_nest_cancel(skb, child_resource_attr);
2561nla_put_failure:
2562 nla_nest_cancel(skb, resource_attr);
2563 return -EMSGSIZE;
2564}
2565
2566static int devlink_resource_fill(struct genl_info *info,
2567 enum devlink_command cmd, int flags)
2568{
2569 struct devlink *devlink = info->user_ptr[0];
2570 struct devlink_resource *resource;
2571 struct nlattr *resources_attr;
2572 struct sk_buff *skb = NULL;
2573 struct nlmsghdr *nlh;
2574 bool incomplete;
2575 void *hdr;
2576 int i;
2577 int err;
2578
2579 resource = list_first_entry(&devlink->resource_list,
2580 struct devlink_resource, list);
2581start_again:
2582 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2583 if (err)
2584 return err;
2585
2586 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2587 &devlink_nl_family, NLM_F_MULTI, cmd);
2588 if (!hdr) {
2589 nlmsg_free(skb);
2590 return -EMSGSIZE;
2591 }
2592
2593 if (devlink_nl_put_handle(skb, devlink))
2594 goto nla_put_failure;
2595
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002596 resources_attr = nla_nest_start_noflag(skb,
2597 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002598 if (!resources_attr)
2599 goto nla_put_failure;
2600
2601 incomplete = false;
2602 i = 0;
2603 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2604 err = devlink_resource_put(devlink, skb, resource);
2605 if (err) {
2606 if (!i)
2607 goto err_resource_put;
2608 incomplete = true;
2609 break;
2610 }
2611 i++;
2612 }
2613 nla_nest_end(skb, resources_attr);
2614 genlmsg_end(skb, hdr);
2615 if (incomplete)
2616 goto start_again;
2617send_done:
2618 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2619 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2620 if (!nlh) {
2621 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2622 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002623 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002624 goto send_done;
2625 }
2626 return genlmsg_reply(skb, info);
2627
2628nla_put_failure:
2629 err = -EMSGSIZE;
2630err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002631 nlmsg_free(skb);
2632 return err;
2633}
2634
2635static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2636 struct genl_info *info)
2637{
2638 struct devlink *devlink = info->user_ptr[0];
2639
2640 if (list_empty(&devlink->resource_list))
2641 return -EOPNOTSUPP;
2642
2643 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2644}
2645
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002646static int
2647devlink_resources_validate(struct devlink *devlink,
2648 struct devlink_resource *resource,
2649 struct genl_info *info)
2650{
2651 struct list_head *resource_list;
2652 int err = 0;
2653
2654 if (resource)
2655 resource_list = &resource->resource_list;
2656 else
2657 resource_list = &devlink->resource_list;
2658
2659 list_for_each_entry(resource, resource_list, list) {
2660 if (!resource->size_valid)
2661 return -EINVAL;
2662 err = devlink_resources_validate(devlink, resource, info);
2663 if (err)
2664 return err;
2665 }
2666 return err;
2667}
2668
2669static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2670{
2671 struct devlink *devlink = info->user_ptr[0];
2672 int err;
2673
2674 if (!devlink->ops->reload)
2675 return -EOPNOTSUPP;
2676
2677 err = devlink_resources_validate(devlink, NULL, info);
2678 if (err) {
2679 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2680 return err;
2681 }
David Ahernac0fc8a2018-06-05 08:14:09 -07002682 return devlink->ops->reload(devlink, info->extack);
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002683}
2684
Jiri Pirko191ed202019-06-04 15:40:40 +02002685static int devlink_nl_flash_update_fill(struct sk_buff *msg,
2686 struct devlink *devlink,
2687 enum devlink_command cmd,
2688 const char *status_msg,
2689 const char *component,
2690 unsigned long done, unsigned long total)
2691{
2692 void *hdr;
2693
2694 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
2695 if (!hdr)
2696 return -EMSGSIZE;
2697
2698 if (devlink_nl_put_handle(msg, devlink))
2699 goto nla_put_failure;
2700
2701 if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
2702 goto out;
2703
2704 if (status_msg &&
2705 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
2706 status_msg))
2707 goto nla_put_failure;
2708 if (component &&
2709 nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
2710 component))
2711 goto nla_put_failure;
2712 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
2713 done, DEVLINK_ATTR_PAD))
2714 goto nla_put_failure;
2715 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
2716 total, DEVLINK_ATTR_PAD))
2717 goto nla_put_failure;
2718
2719out:
2720 genlmsg_end(msg, hdr);
2721 return 0;
2722
2723nla_put_failure:
2724 genlmsg_cancel(msg, hdr);
2725 return -EMSGSIZE;
2726}
2727
2728static void __devlink_flash_update_notify(struct devlink *devlink,
2729 enum devlink_command cmd,
2730 const char *status_msg,
2731 const char *component,
2732 unsigned long done,
2733 unsigned long total)
2734{
2735 struct sk_buff *msg;
2736 int err;
2737
2738 WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
2739 cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
2740 cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
2741
2742 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2743 if (!msg)
2744 return;
2745
2746 err = devlink_nl_flash_update_fill(msg, devlink, cmd, status_msg,
2747 component, done, total);
2748 if (err)
2749 goto out_free_msg;
2750
2751 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
2752 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
2753 return;
2754
2755out_free_msg:
2756 nlmsg_free(msg);
2757}
2758
2759void devlink_flash_update_begin_notify(struct devlink *devlink)
2760{
2761 __devlink_flash_update_notify(devlink,
2762 DEVLINK_CMD_FLASH_UPDATE,
2763 NULL, NULL, 0, 0);
2764}
2765EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
2766
2767void devlink_flash_update_end_notify(struct devlink *devlink)
2768{
2769 __devlink_flash_update_notify(devlink,
2770 DEVLINK_CMD_FLASH_UPDATE_END,
2771 NULL, NULL, 0, 0);
2772}
2773EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
2774
2775void devlink_flash_update_status_notify(struct devlink *devlink,
2776 const char *status_msg,
2777 const char *component,
2778 unsigned long done,
2779 unsigned long total)
2780{
2781 __devlink_flash_update_notify(devlink,
2782 DEVLINK_CMD_FLASH_UPDATE_STATUS,
2783 status_msg, component, done, total);
2784}
2785EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
2786
Jakub Kicinski76726cc2019-02-14 13:40:44 -08002787static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
2788 struct genl_info *info)
2789{
2790 struct devlink *devlink = info->user_ptr[0];
2791 const char *file_name, *component;
2792 struct nlattr *nla_component;
2793
2794 if (!devlink->ops->flash_update)
2795 return -EOPNOTSUPP;
2796
2797 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
2798 return -EINVAL;
2799 file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
2800
2801 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
2802 component = nla_component ? nla_data(nla_component) : NULL;
2803
2804 return devlink->ops->flash_update(devlink, file_name, component,
2805 info->extack);
2806}
2807
Moshe Shemesh036467c2018-07-04 14:30:33 +03002808static const struct devlink_param devlink_param_generic[] = {
2809 {
2810 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
2811 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
2812 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
2813 },
2814 {
2815 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
2816 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
2817 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
2818 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03002819 {
2820 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
2821 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
2822 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
2823 },
Alex Veskerf6a698852018-07-12 15:13:17 +03002824 {
2825 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
2826 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
2827 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
2828 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05302829 {
2830 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
2831 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
2832 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
2833 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05302834 {
2835 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
2836 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
2837 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
2838 },
Vasundhara Volam16511782018-10-04 11:13:46 +05302839 {
2840 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
2841 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
2842 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
2843 },
Shalom Toledo846e9802018-12-03 07:58:59 +00002844 {
2845 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
2846 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
2847 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
2848 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03002849};
Moshe Shemesheabaef12018-07-04 14:30:28 +03002850
2851static int devlink_param_generic_verify(const struct devlink_param *param)
2852{
2853 /* verify it match generic parameter by id and name */
2854 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
2855 return -EINVAL;
2856 if (strcmp(param->name, devlink_param_generic[param->id].name))
2857 return -ENOENT;
2858
2859 WARN_ON(param->type != devlink_param_generic[param->id].type);
2860
2861 return 0;
2862}
2863
2864static int devlink_param_driver_verify(const struct devlink_param *param)
2865{
2866 int i;
2867
2868 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
2869 return -EINVAL;
2870 /* verify no such name in generic params */
2871 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
2872 if (!strcmp(param->name, devlink_param_generic[i].name))
2873 return -EEXIST;
2874
2875 return 0;
2876}
2877
2878static struct devlink_param_item *
2879devlink_param_find_by_name(struct list_head *param_list,
2880 const char *param_name)
2881{
2882 struct devlink_param_item *param_item;
2883
2884 list_for_each_entry(param_item, param_list, list)
2885 if (!strcmp(param_item->param->name, param_name))
2886 return param_item;
2887 return NULL;
2888}
2889
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03002890static struct devlink_param_item *
2891devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
2892{
2893 struct devlink_param_item *param_item;
2894
2895 list_for_each_entry(param_item, param_list, list)
2896 if (param_item->param->id == param_id)
2897 return param_item;
2898 return NULL;
2899}
2900
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002901static bool
2902devlink_param_cmode_is_supported(const struct devlink_param *param,
2903 enum devlink_param_cmode cmode)
2904{
2905 return test_bit(cmode, &param->supported_cmodes);
2906}
2907
2908static int devlink_param_get(struct devlink *devlink,
2909 const struct devlink_param *param,
2910 struct devlink_param_gset_ctx *ctx)
2911{
2912 if (!param->get)
2913 return -EOPNOTSUPP;
2914 return param->get(devlink, param->id, ctx);
2915}
2916
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03002917static int devlink_param_set(struct devlink *devlink,
2918 const struct devlink_param *param,
2919 struct devlink_param_gset_ctx *ctx)
2920{
2921 if (!param->set)
2922 return -EOPNOTSUPP;
2923 return param->set(devlink, param->id, ctx);
2924}
2925
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002926static int
2927devlink_param_type_to_nla_type(enum devlink_param_type param_type)
2928{
2929 switch (param_type) {
2930 case DEVLINK_PARAM_TYPE_U8:
2931 return NLA_U8;
2932 case DEVLINK_PARAM_TYPE_U16:
2933 return NLA_U16;
2934 case DEVLINK_PARAM_TYPE_U32:
2935 return NLA_U32;
2936 case DEVLINK_PARAM_TYPE_STRING:
2937 return NLA_STRING;
2938 case DEVLINK_PARAM_TYPE_BOOL:
2939 return NLA_FLAG;
2940 default:
2941 return -EINVAL;
2942 }
2943}
2944
2945static int
2946devlink_nl_param_value_fill_one(struct sk_buff *msg,
2947 enum devlink_param_type type,
2948 enum devlink_param_cmode cmode,
2949 union devlink_param_value val)
2950{
2951 struct nlattr *param_value_attr;
2952
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002953 param_value_attr = nla_nest_start_noflag(msg,
2954 DEVLINK_ATTR_PARAM_VALUE);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002955 if (!param_value_attr)
2956 goto nla_put_failure;
2957
2958 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
2959 goto value_nest_cancel;
2960
2961 switch (type) {
2962 case DEVLINK_PARAM_TYPE_U8:
2963 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
2964 goto value_nest_cancel;
2965 break;
2966 case DEVLINK_PARAM_TYPE_U16:
2967 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
2968 goto value_nest_cancel;
2969 break;
2970 case DEVLINK_PARAM_TYPE_U32:
2971 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
2972 goto value_nest_cancel;
2973 break;
2974 case DEVLINK_PARAM_TYPE_STRING:
2975 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
2976 val.vstr))
2977 goto value_nest_cancel;
2978 break;
2979 case DEVLINK_PARAM_TYPE_BOOL:
2980 if (val.vbool &&
2981 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
2982 goto value_nest_cancel;
2983 break;
2984 }
2985
2986 nla_nest_end(msg, param_value_attr);
2987 return 0;
2988
2989value_nest_cancel:
2990 nla_nest_cancel(msg, param_value_attr);
2991nla_put_failure:
2992 return -EMSGSIZE;
2993}
2994
2995static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302996 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002997 struct devlink_param_item *param_item,
2998 enum devlink_command cmd,
2999 u32 portid, u32 seq, int flags)
3000{
3001 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003002 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003003 const struct devlink_param *param = param_item->param;
3004 struct devlink_param_gset_ctx ctx;
3005 struct nlattr *param_values_list;
3006 struct nlattr *param_attr;
3007 int nla_type;
3008 void *hdr;
3009 int err;
3010 int i;
3011
3012 /* Get value from driver part to driverinit configuration mode */
3013 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
3014 if (!devlink_param_cmode_is_supported(param, i))
3015 continue;
3016 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
3017 if (!param_item->driverinit_value_valid)
3018 return -EOPNOTSUPP;
3019 param_value[i] = param_item->driverinit_value;
3020 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003021 if (!param_item->published)
3022 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003023 ctx.cmode = i;
3024 err = devlink_param_get(devlink, param, &ctx);
3025 if (err)
3026 return err;
3027 param_value[i] = ctx.val;
3028 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003029 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003030 }
3031
3032 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3033 if (!hdr)
3034 return -EMSGSIZE;
3035
3036 if (devlink_nl_put_handle(msg, devlink))
3037 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303038
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303039 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
3040 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
3041 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303042 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
3043 goto genlmsg_cancel;
3044
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003045 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003046 if (!param_attr)
3047 goto genlmsg_cancel;
3048 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
3049 goto param_nest_cancel;
3050 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
3051 goto param_nest_cancel;
3052
3053 nla_type = devlink_param_type_to_nla_type(param->type);
3054 if (nla_type < 0)
3055 goto param_nest_cancel;
3056 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
3057 goto param_nest_cancel;
3058
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003059 param_values_list = nla_nest_start_noflag(msg,
3060 DEVLINK_ATTR_PARAM_VALUES_LIST);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003061 if (!param_values_list)
3062 goto param_nest_cancel;
3063
3064 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00003065 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003066 continue;
3067 err = devlink_nl_param_value_fill_one(msg, param->type,
3068 i, param_value[i]);
3069 if (err)
3070 goto values_list_nest_cancel;
3071 }
3072
3073 nla_nest_end(msg, param_values_list);
3074 nla_nest_end(msg, param_attr);
3075 genlmsg_end(msg, hdr);
3076 return 0;
3077
3078values_list_nest_cancel:
3079 nla_nest_end(msg, param_values_list);
3080param_nest_cancel:
3081 nla_nest_cancel(msg, param_attr);
3082genlmsg_cancel:
3083 genlmsg_cancel(msg, hdr);
3084 return -EMSGSIZE;
3085}
3086
Moshe Shemeshea601e12018-07-04 14:30:32 +03003087static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303088 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03003089 struct devlink_param_item *param_item,
3090 enum devlink_command cmd)
3091{
3092 struct sk_buff *msg;
3093 int err;
3094
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303095 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
3096 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
3097 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003098
3099 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3100 if (!msg)
3101 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303102 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
3103 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03003104 if (err) {
3105 nlmsg_free(msg);
3106 return;
3107 }
3108
3109 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3110 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3111}
3112
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003113static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3114 struct netlink_callback *cb)
3115{
3116 struct devlink_param_item *param_item;
3117 struct devlink *devlink;
3118 int start = cb->args[0];
3119 int idx = 0;
3120 int err;
3121
3122 mutex_lock(&devlink_mutex);
3123 list_for_each_entry(devlink, &devlink_list, list) {
3124 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3125 continue;
3126 mutex_lock(&devlink->lock);
3127 list_for_each_entry(param_item, &devlink->param_list, list) {
3128 if (idx < start) {
3129 idx++;
3130 continue;
3131 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303132 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003133 DEVLINK_CMD_PARAM_GET,
3134 NETLINK_CB(cb->skb).portid,
3135 cb->nlh->nlmsg_seq,
3136 NLM_F_MULTI);
3137 if (err) {
3138 mutex_unlock(&devlink->lock);
3139 goto out;
3140 }
3141 idx++;
3142 }
3143 mutex_unlock(&devlink->lock);
3144 }
3145out:
3146 mutex_unlock(&devlink_mutex);
3147
3148 cb->args[0] = idx;
3149 return msg->len;
3150}
3151
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003152static int
3153devlink_param_type_get_from_info(struct genl_info *info,
3154 enum devlink_param_type *param_type)
3155{
3156 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3157 return -EINVAL;
3158
3159 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3160 case NLA_U8:
3161 *param_type = DEVLINK_PARAM_TYPE_U8;
3162 break;
3163 case NLA_U16:
3164 *param_type = DEVLINK_PARAM_TYPE_U16;
3165 break;
3166 case NLA_U32:
3167 *param_type = DEVLINK_PARAM_TYPE_U32;
3168 break;
3169 case NLA_STRING:
3170 *param_type = DEVLINK_PARAM_TYPE_STRING;
3171 break;
3172 case NLA_FLAG:
3173 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3174 break;
3175 default:
3176 return -EINVAL;
3177 }
3178
3179 return 0;
3180}
3181
3182static int
3183devlink_param_value_get_from_info(const struct devlink_param *param,
3184 struct genl_info *info,
3185 union devlink_param_value *value)
3186{
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003187 int len;
3188
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003189 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3190 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3191 return -EINVAL;
3192
3193 switch (param->type) {
3194 case DEVLINK_PARAM_TYPE_U8:
3195 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3196 break;
3197 case DEVLINK_PARAM_TYPE_U16:
3198 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3199 break;
3200 case DEVLINK_PARAM_TYPE_U32:
3201 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3202 break;
3203 case DEVLINK_PARAM_TYPE_STRING:
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003204 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3205 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3206 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003207 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003208 return -EINVAL;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003209 strcpy(value->vstr,
3210 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003211 break;
3212 case DEVLINK_PARAM_TYPE_BOOL:
3213 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3214 true : false;
3215 break;
3216 }
3217 return 0;
3218}
3219
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003220static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303221devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003222 struct genl_info *info)
3223{
3224 char *param_name;
3225
3226 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3227 return NULL;
3228
3229 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303230 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003231}
3232
3233static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3234 struct genl_info *info)
3235{
3236 struct devlink *devlink = info->user_ptr[0];
3237 struct devlink_param_item *param_item;
3238 struct sk_buff *msg;
3239 int err;
3240
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303241 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003242 if (!param_item)
3243 return -EINVAL;
3244
3245 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3246 if (!msg)
3247 return -ENOMEM;
3248
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303249 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003250 DEVLINK_CMD_PARAM_GET,
3251 info->snd_portid, info->snd_seq, 0);
3252 if (err) {
3253 nlmsg_free(msg);
3254 return err;
3255 }
3256
3257 return genlmsg_reply(msg, info);
3258}
3259
Vasundhara Volam9c548732019-01-28 18:00:22 +05303260static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303261 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303262 struct list_head *param_list,
3263 struct genl_info *info,
3264 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003265{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003266 enum devlink_param_type param_type;
3267 struct devlink_param_gset_ctx ctx;
3268 enum devlink_param_cmode cmode;
3269 struct devlink_param_item *param_item;
3270 const struct devlink_param *param;
3271 union devlink_param_value value;
3272 int err = 0;
3273
Vasundhara Volam9c548732019-01-28 18:00:22 +05303274 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003275 if (!param_item)
3276 return -EINVAL;
3277 param = param_item->param;
3278 err = devlink_param_type_get_from_info(info, &param_type);
3279 if (err)
3280 return err;
3281 if (param_type != param->type)
3282 return -EINVAL;
3283 err = devlink_param_value_get_from_info(param, info, &value);
3284 if (err)
3285 return err;
3286 if (param->validate) {
3287 err = param->validate(devlink, param->id, value, info->extack);
3288 if (err)
3289 return err;
3290 }
3291
3292 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3293 return -EINVAL;
3294 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3295 if (!devlink_param_cmode_is_supported(param, cmode))
3296 return -EOPNOTSUPP;
3297
3298 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003299 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3300 strcpy(param_item->driverinit_value.vstr, value.vstr);
3301 else
3302 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003303 param_item->driverinit_value_valid = true;
3304 } else {
3305 if (!param->set)
3306 return -EOPNOTSUPP;
3307 ctx.val = value;
3308 ctx.cmode = cmode;
3309 err = devlink_param_set(devlink, param, &ctx);
3310 if (err)
3311 return err;
3312 }
3313
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303314 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003315 return 0;
3316}
3317
Vasundhara Volam9c548732019-01-28 18:00:22 +05303318static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3319 struct genl_info *info)
3320{
3321 struct devlink *devlink = info->user_ptr[0];
3322
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303323 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303324 info, DEVLINK_CMD_PARAM_NEW);
3325}
3326
Moshe Shemesheabaef12018-07-04 14:30:28 +03003327static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303328 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303329 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303330 const struct devlink_param *param,
3331 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003332{
3333 struct devlink_param_item *param_item;
3334
Vasundhara Volam39e61602019-01-28 18:00:20 +05303335 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03003336 return -EEXIST;
3337
3338 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3339 WARN_ON(param->get || param->set);
3340 else
3341 WARN_ON(!param->get || !param->set);
3342
3343 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3344 if (!param_item)
3345 return -ENOMEM;
3346 param_item->param = param;
3347
Vasundhara Volam39e61602019-01-28 18:00:20 +05303348 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303349 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003350 return 0;
3351}
3352
3353static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303354 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303355 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303356 const struct devlink_param *param,
3357 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003358{
3359 struct devlink_param_item *param_item;
3360
Vasundhara Volam39e61602019-01-28 18:00:20 +05303361 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003362 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303363 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003364 list_del(&param_item->list);
3365 kfree(param_item);
3366}
3367
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303368static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3369 struct netlink_callback *cb)
3370{
3371 struct devlink_param_item *param_item;
3372 struct devlink_port *devlink_port;
3373 struct devlink *devlink;
3374 int start = cb->args[0];
3375 int idx = 0;
3376 int err;
3377
3378 mutex_lock(&devlink_mutex);
3379 list_for_each_entry(devlink, &devlink_list, list) {
3380 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3381 continue;
3382 mutex_lock(&devlink->lock);
3383 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3384 list_for_each_entry(param_item,
3385 &devlink_port->param_list, list) {
3386 if (idx < start) {
3387 idx++;
3388 continue;
3389 }
3390 err = devlink_nl_param_fill(msg,
3391 devlink_port->devlink,
3392 devlink_port->index, param_item,
3393 DEVLINK_CMD_PORT_PARAM_GET,
3394 NETLINK_CB(cb->skb).portid,
3395 cb->nlh->nlmsg_seq,
3396 NLM_F_MULTI);
3397 if (err) {
3398 mutex_unlock(&devlink->lock);
3399 goto out;
3400 }
3401 idx++;
3402 }
3403 }
3404 mutex_unlock(&devlink->lock);
3405 }
3406out:
3407 mutex_unlock(&devlink_mutex);
3408
3409 cb->args[0] = idx;
3410 return msg->len;
3411}
3412
3413static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3414 struct genl_info *info)
3415{
3416 struct devlink_port *devlink_port = info->user_ptr[0];
3417 struct devlink_param_item *param_item;
3418 struct sk_buff *msg;
3419 int err;
3420
3421 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3422 info);
3423 if (!param_item)
3424 return -EINVAL;
3425
3426 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3427 if (!msg)
3428 return -ENOMEM;
3429
3430 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3431 devlink_port->index, param_item,
3432 DEVLINK_CMD_PORT_PARAM_GET,
3433 info->snd_portid, info->snd_seq, 0);
3434 if (err) {
3435 nlmsg_free(msg);
3436 return err;
3437 }
3438
3439 return genlmsg_reply(msg, info);
3440}
3441
Vasundhara Volam9c548732019-01-28 18:00:22 +05303442static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3443 struct genl_info *info)
3444{
3445 struct devlink_port *devlink_port = info->user_ptr[0];
3446
3447 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303448 devlink_port->index,
3449 &devlink_port->param_list, info,
3450 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05303451}
3452
Alex Veskera006d462018-07-12 15:13:12 +03003453static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3454 struct devlink *devlink,
3455 struct devlink_snapshot *snapshot)
3456{
3457 struct nlattr *snap_attr;
3458 int err;
3459
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003460 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
Alex Veskera006d462018-07-12 15:13:12 +03003461 if (!snap_attr)
3462 return -EINVAL;
3463
3464 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3465 if (err)
3466 goto nla_put_failure;
3467
3468 nla_nest_end(msg, snap_attr);
3469 return 0;
3470
3471nla_put_failure:
3472 nla_nest_cancel(msg, snap_attr);
3473 return err;
3474}
3475
3476static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3477 struct devlink *devlink,
3478 struct devlink_region *region)
3479{
3480 struct devlink_snapshot *snapshot;
3481 struct nlattr *snapshots_attr;
3482 int err;
3483
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003484 snapshots_attr = nla_nest_start_noflag(msg,
3485 DEVLINK_ATTR_REGION_SNAPSHOTS);
Alex Veskera006d462018-07-12 15:13:12 +03003486 if (!snapshots_attr)
3487 return -EINVAL;
3488
3489 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3490 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3491 if (err)
3492 goto nla_put_failure;
3493 }
3494
3495 nla_nest_end(msg, snapshots_attr);
3496 return 0;
3497
3498nla_put_failure:
3499 nla_nest_cancel(msg, snapshots_attr);
3500 return err;
3501}
3502
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003503static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3504 enum devlink_command cmd, u32 portid,
3505 u32 seq, int flags,
3506 struct devlink_region *region)
3507{
3508 void *hdr;
3509 int err;
3510
3511 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3512 if (!hdr)
3513 return -EMSGSIZE;
3514
3515 err = devlink_nl_put_handle(msg, devlink);
3516 if (err)
3517 goto nla_put_failure;
3518
3519 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3520 if (err)
3521 goto nla_put_failure;
3522
3523 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3524 region->size,
3525 DEVLINK_ATTR_PAD);
3526 if (err)
3527 goto nla_put_failure;
3528
Alex Veskera006d462018-07-12 15:13:12 +03003529 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3530 if (err)
3531 goto nla_put_failure;
3532
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003533 genlmsg_end(msg, hdr);
3534 return 0;
3535
3536nla_put_failure:
3537 genlmsg_cancel(msg, hdr);
3538 return err;
3539}
3540
Alex Vesker866319b2018-07-12 15:13:13 +03003541static void devlink_nl_region_notify(struct devlink_region *region,
3542 struct devlink_snapshot *snapshot,
3543 enum devlink_command cmd)
3544{
3545 struct devlink *devlink = region->devlink;
3546 struct sk_buff *msg;
3547 void *hdr;
3548 int err;
3549
3550 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3551
3552 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3553 if (!msg)
3554 return;
3555
3556 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3557 if (!hdr)
3558 goto out_free_msg;
3559
3560 err = devlink_nl_put_handle(msg, devlink);
3561 if (err)
3562 goto out_cancel_msg;
3563
3564 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3565 region->name);
3566 if (err)
3567 goto out_cancel_msg;
3568
3569 if (snapshot) {
3570 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3571 snapshot->id);
3572 if (err)
3573 goto out_cancel_msg;
3574 } else {
3575 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3576 region->size, DEVLINK_ATTR_PAD);
3577 if (err)
3578 goto out_cancel_msg;
3579 }
3580 genlmsg_end(msg, hdr);
3581
3582 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3583 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3584
3585 return;
3586
3587out_cancel_msg:
3588 genlmsg_cancel(msg, hdr);
3589out_free_msg:
3590 nlmsg_free(msg);
3591}
3592
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003593static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3594 struct genl_info *info)
3595{
3596 struct devlink *devlink = info->user_ptr[0];
3597 struct devlink_region *region;
3598 const char *region_name;
3599 struct sk_buff *msg;
3600 int err;
3601
3602 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3603 return -EINVAL;
3604
3605 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3606 region = devlink_region_get_by_name(devlink, region_name);
3607 if (!region)
3608 return -EINVAL;
3609
3610 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3611 if (!msg)
3612 return -ENOMEM;
3613
3614 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3615 info->snd_portid, info->snd_seq, 0,
3616 region);
3617 if (err) {
3618 nlmsg_free(msg);
3619 return err;
3620 }
3621
3622 return genlmsg_reply(msg, info);
3623}
3624
3625static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3626 struct netlink_callback *cb)
3627{
3628 struct devlink_region *region;
3629 struct devlink *devlink;
3630 int start = cb->args[0];
3631 int idx = 0;
3632 int err;
3633
3634 mutex_lock(&devlink_mutex);
3635 list_for_each_entry(devlink, &devlink_list, list) {
3636 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3637 continue;
3638
3639 mutex_lock(&devlink->lock);
3640 list_for_each_entry(region, &devlink->region_list, list) {
3641 if (idx < start) {
3642 idx++;
3643 continue;
3644 }
3645 err = devlink_nl_region_fill(msg, devlink,
3646 DEVLINK_CMD_REGION_GET,
3647 NETLINK_CB(cb->skb).portid,
3648 cb->nlh->nlmsg_seq,
3649 NLM_F_MULTI, region);
3650 if (err) {
3651 mutex_unlock(&devlink->lock);
3652 goto out;
3653 }
3654 idx++;
3655 }
3656 mutex_unlock(&devlink->lock);
3657 }
3658out:
3659 mutex_unlock(&devlink_mutex);
3660 cb->args[0] = idx;
3661 return msg->len;
3662}
3663
Alex Vesker866319b2018-07-12 15:13:13 +03003664static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3665 struct genl_info *info)
3666{
3667 struct devlink *devlink = info->user_ptr[0];
3668 struct devlink_snapshot *snapshot;
3669 struct devlink_region *region;
3670 const char *region_name;
3671 u32 snapshot_id;
3672
3673 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3674 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3675 return -EINVAL;
3676
3677 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3678 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3679
3680 region = devlink_region_get_by_name(devlink, region_name);
3681 if (!region)
3682 return -EINVAL;
3683
3684 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3685 if (!snapshot)
3686 return -EINVAL;
3687
3688 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3689 devlink_region_snapshot_del(snapshot);
3690 return 0;
3691}
3692
Alex Vesker4e547952018-07-12 15:13:14 +03003693static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3694 struct devlink *devlink,
3695 u8 *chunk, u32 chunk_size,
3696 u64 addr)
3697{
3698 struct nlattr *chunk_attr;
3699 int err;
3700
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003701 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
Alex Vesker4e547952018-07-12 15:13:14 +03003702 if (!chunk_attr)
3703 return -EINVAL;
3704
3705 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3706 if (err)
3707 goto nla_put_failure;
3708
3709 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3710 DEVLINK_ATTR_PAD);
3711 if (err)
3712 goto nla_put_failure;
3713
3714 nla_nest_end(msg, chunk_attr);
3715 return 0;
3716
3717nla_put_failure:
3718 nla_nest_cancel(msg, chunk_attr);
3719 return err;
3720}
3721
3722#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3723
3724static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3725 struct devlink *devlink,
3726 struct devlink_region *region,
3727 struct nlattr **attrs,
3728 u64 start_offset,
3729 u64 end_offset,
3730 bool dump,
3731 u64 *new_offset)
3732{
3733 struct devlink_snapshot *snapshot;
3734 u64 curr_offset = start_offset;
3735 u32 snapshot_id;
3736 int err = 0;
3737
3738 *new_offset = start_offset;
3739
3740 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3741 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3742 if (!snapshot)
3743 return -EINVAL;
3744
3745 if (end_offset > snapshot->data_len || dump)
3746 end_offset = snapshot->data_len;
3747
3748 while (curr_offset < end_offset) {
3749 u32 data_size;
3750 u8 *data;
3751
3752 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3753 data_size = end_offset - curr_offset;
3754 else
3755 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3756
3757 data = &snapshot->data[curr_offset];
3758 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3759 data, data_size,
3760 curr_offset);
3761 if (err)
3762 break;
3763
3764 curr_offset += data_size;
3765 }
3766 *new_offset = curr_offset;
3767
3768 return err;
3769}
3770
3771static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3772 struct netlink_callback *cb)
3773{
3774 u64 ret_offset, start_offset, end_offset = 0;
Alex Vesker4e547952018-07-12 15:13:14 +03003775 struct devlink_region *region;
3776 struct nlattr *chunks_attr;
3777 const char *region_name;
3778 struct devlink *devlink;
Jakub Kicinski68750562019-02-10 19:35:28 -08003779 struct nlattr **attrs;
Alex Vesker4e547952018-07-12 15:13:14 +03003780 bool dump = true;
3781 void *hdr;
3782 int err;
3783
3784 start_offset = *((u64 *)&cb->args[0]);
3785
Jakub Kicinski68750562019-02-10 19:35:28 -08003786 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
3787 if (!attrs)
3788 return -ENOMEM;
3789
Johannes Berg8cb08172019-04-26 14:07:28 +02003790 err = nlmsg_parse_deprecated(cb->nlh,
3791 GENL_HDRLEN + devlink_nl_family.hdrsize,
3792 attrs, DEVLINK_ATTR_MAX,
3793 devlink_nl_family.policy, cb->extack);
Alex Vesker4e547952018-07-12 15:13:14 +03003794 if (err)
Jakub Kicinski68750562019-02-10 19:35:28 -08003795 goto out_free;
Alex Vesker4e547952018-07-12 15:13:14 +03003796
Parav Panditdac7c082019-02-12 14:24:08 -06003797 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03003798 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003799 if (IS_ERR(devlink)) {
3800 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06003801 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003802 }
Alex Vesker4e547952018-07-12 15:13:14 +03003803
Alex Vesker4e547952018-07-12 15:13:14 +03003804 mutex_lock(&devlink->lock);
3805
3806 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06003807 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
3808 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003809 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003810 }
Alex Vesker4e547952018-07-12 15:13:14 +03003811
3812 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3813 region = devlink_region_get_by_name(devlink, region_name);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003814 if (!region) {
3815 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003816 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003817 }
Alex Vesker4e547952018-07-12 15:13:14 +03003818
3819 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3820 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3821 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003822 if (!hdr) {
3823 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03003824 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003825 }
Alex Vesker4e547952018-07-12 15:13:14 +03003826
3827 err = devlink_nl_put_handle(skb, devlink);
3828 if (err)
3829 goto nla_put_failure;
3830
3831 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3832 if (err)
3833 goto nla_put_failure;
3834
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003835 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003836 if (!chunks_attr) {
3837 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03003838 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003839 }
Alex Vesker4e547952018-07-12 15:13:14 +03003840
3841 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3842 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3843 if (!start_offset)
3844 start_offset =
3845 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3846
3847 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3848 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3849 dump = false;
3850 }
3851
3852 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3853 region, attrs,
3854 start_offset,
3855 end_offset, dump,
3856 &ret_offset);
3857
3858 if (err && err != -EMSGSIZE)
3859 goto nla_put_failure;
3860
3861 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06003862 if (ret_offset == start_offset) {
3863 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003864 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003865 }
Alex Vesker4e547952018-07-12 15:13:14 +03003866
3867 *((u64 *)&cb->args[0]) = ret_offset;
3868
3869 nla_nest_end(skb, chunks_attr);
3870 genlmsg_end(skb, hdr);
3871 mutex_unlock(&devlink->lock);
3872 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003873 kfree(attrs);
Alex Vesker4e547952018-07-12 15:13:14 +03003874
3875 return skb->len;
3876
3877nla_put_failure:
3878 genlmsg_cancel(skb, hdr);
3879out_unlock:
3880 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06003881out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03003882 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003883out_free:
3884 kfree(attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003885 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03003886}
3887
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003888struct devlink_info_req {
3889 struct sk_buff *msg;
3890};
3891
3892int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3893{
3894 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3895}
3896EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3897
3898int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3899{
3900 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3901}
3902EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3903
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08003904static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3905 const char *version_name,
3906 const char *version_value)
3907{
3908 struct nlattr *nest;
3909 int err;
3910
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003911 nest = nla_nest_start_noflag(req->msg, attr);
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08003912 if (!nest)
3913 return -EMSGSIZE;
3914
3915 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3916 version_name);
3917 if (err)
3918 goto nla_put_failure;
3919
3920 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3921 version_value);
3922 if (err)
3923 goto nla_put_failure;
3924
3925 nla_nest_end(req->msg, nest);
3926
3927 return 0;
3928
3929nla_put_failure:
3930 nla_nest_cancel(req->msg, nest);
3931 return err;
3932}
3933
3934int devlink_info_version_fixed_put(struct devlink_info_req *req,
3935 const char *version_name,
3936 const char *version_value)
3937{
3938 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3939 version_name, version_value);
3940}
3941EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3942
3943int devlink_info_version_stored_put(struct devlink_info_req *req,
3944 const char *version_name,
3945 const char *version_value)
3946{
3947 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3948 version_name, version_value);
3949}
3950EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3951
3952int devlink_info_version_running_put(struct devlink_info_req *req,
3953 const char *version_name,
3954 const char *version_value)
3955{
3956 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3957 version_name, version_value);
3958}
3959EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3960
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003961static int
3962devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3963 enum devlink_command cmd, u32 portid,
3964 u32 seq, int flags, struct netlink_ext_ack *extack)
3965{
3966 struct devlink_info_req req;
3967 void *hdr;
3968 int err;
3969
3970 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3971 if (!hdr)
3972 return -EMSGSIZE;
3973
3974 err = -EMSGSIZE;
3975 if (devlink_nl_put_handle(msg, devlink))
3976 goto err_cancel_msg;
3977
3978 req.msg = msg;
3979 err = devlink->ops->info_get(devlink, &req, extack);
3980 if (err)
3981 goto err_cancel_msg;
3982
3983 genlmsg_end(msg, hdr);
3984 return 0;
3985
3986err_cancel_msg:
3987 genlmsg_cancel(msg, hdr);
3988 return err;
3989}
3990
3991static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
3992 struct genl_info *info)
3993{
3994 struct devlink *devlink = info->user_ptr[0];
3995 struct sk_buff *msg;
3996 int err;
3997
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08003998 if (!devlink->ops->info_get)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003999 return -EOPNOTSUPP;
4000
4001 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4002 if (!msg)
4003 return -ENOMEM;
4004
4005 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4006 info->snd_portid, info->snd_seq, 0,
4007 info->extack);
4008 if (err) {
4009 nlmsg_free(msg);
4010 return err;
4011 }
4012
4013 return genlmsg_reply(msg, info);
4014}
4015
4016static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
4017 struct netlink_callback *cb)
4018{
4019 struct devlink *devlink;
4020 int start = cb->args[0];
4021 int idx = 0;
4022 int err;
4023
4024 mutex_lock(&devlink_mutex);
4025 list_for_each_entry(devlink, &devlink_list, list) {
4026 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4027 continue;
4028 if (idx < start) {
4029 idx++;
4030 continue;
4031 }
4032
Jiri Pirkoc493b09b2019-03-24 00:21:03 +01004033 if (!devlink->ops->info_get) {
4034 idx++;
4035 continue;
4036 }
4037
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08004038 mutex_lock(&devlink->lock);
4039 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
4040 NETLINK_CB(cb->skb).portid,
4041 cb->nlh->nlmsg_seq, NLM_F_MULTI,
4042 cb->extack);
4043 mutex_unlock(&devlink->lock);
4044 if (err)
4045 break;
4046 idx++;
4047 }
4048 mutex_unlock(&devlink_mutex);
4049
4050 cb->args[0] = idx;
4051 return msg->len;
4052}
4053
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004054struct devlink_fmsg_item {
4055 struct list_head list;
4056 int attrtype;
4057 u8 nla_type;
4058 u16 len;
4059 int value[0];
4060};
4061
4062struct devlink_fmsg {
4063 struct list_head item_list;
4064};
4065
4066static struct devlink_fmsg *devlink_fmsg_alloc(void)
4067{
4068 struct devlink_fmsg *fmsg;
4069
4070 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
4071 if (!fmsg)
4072 return NULL;
4073
4074 INIT_LIST_HEAD(&fmsg->item_list);
4075
4076 return fmsg;
4077}
4078
4079static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
4080{
4081 struct devlink_fmsg_item *item, *tmp;
4082
4083 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
4084 list_del(&item->list);
4085 kfree(item);
4086 }
4087 kfree(fmsg);
4088}
4089
4090static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
4091 int attrtype)
4092{
4093 struct devlink_fmsg_item *item;
4094
4095 item = kzalloc(sizeof(*item), GFP_KERNEL);
4096 if (!item)
4097 return -ENOMEM;
4098
4099 item->attrtype = attrtype;
4100 list_add_tail(&item->list, &fmsg->item_list);
4101
4102 return 0;
4103}
4104
4105int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
4106{
4107 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
4108}
4109EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
4110
4111static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
4112{
4113 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
4114}
4115
4116int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
4117{
4118 return devlink_fmsg_nest_end(fmsg);
4119}
4120EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
4121
4122#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
4123
4124static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
4125{
4126 struct devlink_fmsg_item *item;
4127
4128 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4129 return -EMSGSIZE;
4130
4131 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4132 if (!item)
4133 return -ENOMEM;
4134
4135 item->nla_type = NLA_NUL_STRING;
4136 item->len = strlen(name) + 1;
4137 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4138 memcpy(&item->value, name, item->len);
4139 list_add_tail(&item->list, &fmsg->item_list);
4140
4141 return 0;
4142}
4143
4144int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4145{
4146 int err;
4147
4148 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4149 if (err)
4150 return err;
4151
4152 err = devlink_fmsg_put_name(fmsg, name);
4153 if (err)
4154 return err;
4155
4156 return 0;
4157}
4158EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4159
4160int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4161{
4162 return devlink_fmsg_nest_end(fmsg);
4163}
4164EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4165
4166int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4167 const char *name)
4168{
4169 int err;
4170
4171 err = devlink_fmsg_pair_nest_start(fmsg, name);
4172 if (err)
4173 return err;
4174
4175 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4176 if (err)
4177 return err;
4178
4179 return 0;
4180}
4181EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4182
4183int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4184{
4185 int err;
4186
4187 err = devlink_fmsg_nest_end(fmsg);
4188 if (err)
4189 return err;
4190
4191 err = devlink_fmsg_nest_end(fmsg);
4192 if (err)
4193 return err;
4194
4195 return 0;
4196}
4197EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4198
4199static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4200 const void *value, u16 value_len,
4201 u8 value_nla_type)
4202{
4203 struct devlink_fmsg_item *item;
4204
4205 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4206 return -EMSGSIZE;
4207
4208 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4209 if (!item)
4210 return -ENOMEM;
4211
4212 item->nla_type = value_nla_type;
4213 item->len = value_len;
4214 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4215 memcpy(&item->value, value, item->len);
4216 list_add_tail(&item->list, &fmsg->item_list);
4217
4218 return 0;
4219}
4220
4221int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4222{
4223 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4224}
4225EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4226
4227int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4228{
4229 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4230}
4231EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4232
4233int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4234{
4235 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4236}
4237EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4238
4239int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4240{
4241 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4242}
4243EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4244
4245int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4246{
4247 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4248 NLA_NUL_STRING);
4249}
4250EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4251
4252int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4253 u16 value_len)
4254{
4255 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4256}
4257EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4258
4259int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4260 bool value)
4261{
4262 int err;
4263
4264 err = devlink_fmsg_pair_nest_start(fmsg, name);
4265 if (err)
4266 return err;
4267
4268 err = devlink_fmsg_bool_put(fmsg, value);
4269 if (err)
4270 return err;
4271
4272 err = devlink_fmsg_pair_nest_end(fmsg);
4273 if (err)
4274 return err;
4275
4276 return 0;
4277}
4278EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4279
4280int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4281 u8 value)
4282{
4283 int err;
4284
4285 err = devlink_fmsg_pair_nest_start(fmsg, name);
4286 if (err)
4287 return err;
4288
4289 err = devlink_fmsg_u8_put(fmsg, value);
4290 if (err)
4291 return err;
4292
4293 err = devlink_fmsg_pair_nest_end(fmsg);
4294 if (err)
4295 return err;
4296
4297 return 0;
4298}
4299EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4300
4301int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4302 u32 value)
4303{
4304 int err;
4305
4306 err = devlink_fmsg_pair_nest_start(fmsg, name);
4307 if (err)
4308 return err;
4309
4310 err = devlink_fmsg_u32_put(fmsg, value);
4311 if (err)
4312 return err;
4313
4314 err = devlink_fmsg_pair_nest_end(fmsg);
4315 if (err)
4316 return err;
4317
4318 return 0;
4319}
4320EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4321
4322int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4323 u64 value)
4324{
4325 int err;
4326
4327 err = devlink_fmsg_pair_nest_start(fmsg, name);
4328 if (err)
4329 return err;
4330
4331 err = devlink_fmsg_u64_put(fmsg, value);
4332 if (err)
4333 return err;
4334
4335 err = devlink_fmsg_pair_nest_end(fmsg);
4336 if (err)
4337 return err;
4338
4339 return 0;
4340}
4341EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4342
4343int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4344 const char *value)
4345{
4346 int err;
4347
4348 err = devlink_fmsg_pair_nest_start(fmsg, name);
4349 if (err)
4350 return err;
4351
4352 err = devlink_fmsg_string_put(fmsg, value);
4353 if (err)
4354 return err;
4355
4356 err = devlink_fmsg_pair_nest_end(fmsg);
4357 if (err)
4358 return err;
4359
4360 return 0;
4361}
4362EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4363
4364int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4365 const void *value, u16 value_len)
4366{
4367 int err;
4368
4369 err = devlink_fmsg_pair_nest_start(fmsg, name);
4370 if (err)
4371 return err;
4372
4373 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4374 if (err)
4375 return err;
4376
4377 err = devlink_fmsg_pair_nest_end(fmsg);
4378 if (err)
4379 return err;
4380
4381 return 0;
4382}
4383EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4384
4385static int
4386devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4387{
4388 switch (msg->nla_type) {
4389 case NLA_FLAG:
4390 case NLA_U8:
4391 case NLA_U32:
4392 case NLA_U64:
4393 case NLA_NUL_STRING:
4394 case NLA_BINARY:
4395 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4396 msg->nla_type);
4397 default:
4398 return -EINVAL;
4399 }
4400}
4401
4402static int
4403devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4404{
4405 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4406 u8 tmp;
4407
4408 switch (msg->nla_type) {
4409 case NLA_FLAG:
4410 /* Always provide flag data, regardless of its value */
4411 tmp = *(bool *) msg->value;
4412
4413 return nla_put_u8(skb, attrtype, tmp);
4414 case NLA_U8:
4415 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4416 case NLA_U32:
4417 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4418 case NLA_U64:
4419 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4420 DEVLINK_ATTR_PAD);
4421 case NLA_NUL_STRING:
4422 return nla_put_string(skb, attrtype, (char *) &msg->value);
4423 case NLA_BINARY:
4424 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4425 default:
4426 return -EINVAL;
4427 }
4428}
4429
4430static int
4431devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4432 int *start)
4433{
4434 struct devlink_fmsg_item *item;
4435 struct nlattr *fmsg_nlattr;
4436 int i = 0;
4437 int err;
4438
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004439 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004440 if (!fmsg_nlattr)
4441 return -EMSGSIZE;
4442
4443 list_for_each_entry(item, &fmsg->item_list, list) {
4444 if (i < *start) {
4445 i++;
4446 continue;
4447 }
4448
4449 switch (item->attrtype) {
4450 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4451 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4452 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4453 case DEVLINK_ATTR_FMSG_NEST_END:
4454 err = nla_put_flag(skb, item->attrtype);
4455 break;
4456 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4457 err = devlink_fmsg_item_fill_type(item, skb);
4458 if (err)
4459 break;
4460 err = devlink_fmsg_item_fill_data(item, skb);
4461 break;
4462 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4463 err = nla_put_string(skb, item->attrtype,
4464 (char *) &item->value);
4465 break;
4466 default:
4467 err = -EINVAL;
4468 break;
4469 }
4470 if (!err)
4471 *start = ++i;
4472 else
4473 break;
4474 }
4475
4476 nla_nest_end(skb, fmsg_nlattr);
4477 return err;
4478}
4479
4480static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4481 struct genl_info *info,
4482 enum devlink_command cmd, int flags)
4483{
4484 struct nlmsghdr *nlh;
4485 struct sk_buff *skb;
4486 bool last = false;
4487 int index = 0;
4488 void *hdr;
4489 int err;
4490
4491 while (!last) {
4492 int tmp_index = index;
4493
4494 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4495 if (!skb)
4496 return -ENOMEM;
4497
4498 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4499 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4500 if (!hdr) {
4501 err = -EMSGSIZE;
4502 goto nla_put_failure;
4503 }
4504
4505 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4506 if (!err)
4507 last = true;
4508 else if (err != -EMSGSIZE || tmp_index == index)
4509 goto nla_put_failure;
4510
4511 genlmsg_end(skb, hdr);
4512 err = genlmsg_reply(skb, info);
4513 if (err)
4514 return err;
4515 }
4516
4517 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4518 if (!skb)
4519 return -ENOMEM;
4520 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4521 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4522 if (!nlh) {
4523 err = -EMSGSIZE;
4524 goto nla_put_failure;
4525 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004526
Li RongQingfde55ea2019-02-11 19:09:07 +08004527 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004528
4529nla_put_failure:
4530 nlmsg_free(skb);
4531 return err;
4532}
4533
Aya Levine44ef4e2019-05-16 09:49:20 +03004534static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4535 struct netlink_callback *cb,
4536 enum devlink_command cmd)
4537{
4538 int index = cb->args[0];
4539 int tmp_index = index;
4540 void *hdr;
4541 int err;
4542
4543 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4544 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
4545 if (!hdr) {
4546 err = -EMSGSIZE;
4547 goto nla_put_failure;
4548 }
4549
4550 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4551 if ((err && err != -EMSGSIZE) || tmp_index == index)
4552 goto nla_put_failure;
4553
4554 cb->args[0] = index;
4555 genlmsg_end(skb, hdr);
4556 return skb->len;
4557
4558nla_put_failure:
4559 genlmsg_cancel(skb, hdr);
4560 return err;
4561}
4562
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004563struct devlink_health_reporter {
4564 struct list_head list;
4565 void *priv;
4566 const struct devlink_health_reporter_ops *ops;
4567 struct devlink *devlink;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004568 struct devlink_fmsg *dump_fmsg;
4569 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004570 u64 graceful_period;
4571 bool auto_recover;
4572 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004573 u64 dump_ts;
4574 u64 error_count;
4575 u64 recovery_count;
4576 u64 last_recovery_ts;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004577 refcount_t refcount;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004578};
4579
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004580void *
4581devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4582{
4583 return reporter->priv;
4584}
4585EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4586
4587static struct devlink_health_reporter *
4588devlink_health_reporter_find_by_name(struct devlink *devlink,
4589 const char *reporter_name)
4590{
4591 struct devlink_health_reporter *reporter;
4592
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004593 lockdep_assert_held(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004594 list_for_each_entry(reporter, &devlink->reporter_list, list)
4595 if (!strcmp(reporter->ops->name, reporter_name))
4596 return reporter;
4597 return NULL;
4598}
4599
4600/**
4601 * devlink_health_reporter_create - create devlink health reporter
4602 *
4603 * @devlink: devlink
4604 * @ops: ops
4605 * @graceful_period: to avoid recovery loops, in msecs
4606 * @auto_recover: auto recover when error occurs
4607 * @priv: priv
4608 */
4609struct devlink_health_reporter *
4610devlink_health_reporter_create(struct devlink *devlink,
4611 const struct devlink_health_reporter_ops *ops,
4612 u64 graceful_period, bool auto_recover,
4613 void *priv)
4614{
4615 struct devlink_health_reporter *reporter;
4616
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004617 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004618 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4619 reporter = ERR_PTR(-EEXIST);
4620 goto unlock;
4621 }
4622
4623 if (WARN_ON(auto_recover && !ops->recover) ||
4624 WARN_ON(graceful_period && !ops->recover)) {
4625 reporter = ERR_PTR(-EINVAL);
4626 goto unlock;
4627 }
4628
4629 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4630 if (!reporter) {
4631 reporter = ERR_PTR(-ENOMEM);
4632 goto unlock;
4633 }
4634
4635 reporter->priv = priv;
4636 reporter->ops = ops;
4637 reporter->devlink = devlink;
4638 reporter->graceful_period = graceful_period;
4639 reporter->auto_recover = auto_recover;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004640 mutex_init(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004641 refcount_set(&reporter->refcount, 1);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004642 list_add_tail(&reporter->list, &devlink->reporter_list);
4643unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004644 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004645 return reporter;
4646}
4647EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4648
4649/**
4650 * devlink_health_reporter_destroy - destroy devlink health reporter
4651 *
4652 * @reporter: devlink health reporter to destroy
4653 */
4654void
4655devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4656{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004657 mutex_lock(&reporter->devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004658 list_del(&reporter->list);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004659 mutex_unlock(&reporter->devlink->reporters_lock);
4660 while (refcount_read(&reporter->refcount) > 1)
4661 msleep(100);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01004662 mutex_destroy(&reporter->dump_lock);
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004663 if (reporter->dump_fmsg)
4664 devlink_fmsg_free(reporter->dump_fmsg);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004665 kfree(reporter);
4666}
4667EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4668
Eran Ben Elisha3167b272019-03-03 10:57:30 +02004669void
4670devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
4671 enum devlink_health_reporter_state state)
4672{
4673 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
4674 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
4675 return;
4676
4677 if (reporter->health_state == state)
4678 return;
4679
4680 reporter->health_state = state;
4681 trace_devlink_health_reporter_state_update(reporter->devlink,
4682 reporter->ops->name, state);
4683}
4684EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
4685
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004686static int
4687devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4688 void *priv_ctx)
4689{
4690 int err;
4691
4692 if (!reporter->ops->recover)
4693 return -EOPNOTSUPP;
4694
4695 err = reporter->ops->recover(reporter, priv_ctx);
4696 if (err)
4697 return err;
4698
4699 reporter->recovery_count++;
4700 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4701 reporter->last_recovery_ts = jiffies;
4702
4703 return 0;
4704}
4705
4706static void
4707devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4708{
4709 if (!reporter->dump_fmsg)
4710 return;
4711 devlink_fmsg_free(reporter->dump_fmsg);
4712 reporter->dump_fmsg = NULL;
4713}
4714
4715static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4716 void *priv_ctx)
4717{
4718 int err;
4719
4720 if (!reporter->ops->dump)
4721 return 0;
4722
4723 if (reporter->dump_fmsg)
4724 return 0;
4725
4726 reporter->dump_fmsg = devlink_fmsg_alloc();
4727 if (!reporter->dump_fmsg) {
4728 err = -ENOMEM;
4729 return err;
4730 }
4731
4732 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4733 if (err)
4734 goto dump_err;
4735
4736 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4737 priv_ctx);
4738 if (err)
4739 goto dump_err;
4740
4741 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4742 if (err)
4743 goto dump_err;
4744
4745 reporter->dump_ts = jiffies;
4746
4747 return 0;
4748
4749dump_err:
4750 devlink_health_dump_clear(reporter);
4751 return err;
4752}
4753
4754int devlink_health_report(struct devlink_health_reporter *reporter,
4755 const char *msg, void *priv_ctx)
4756{
Eran Ben Elishaa0a21ad2019-03-03 10:57:29 +02004757 enum devlink_health_reporter_state prev_health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004758 struct devlink *devlink = reporter->devlink;
4759
4760 /* write a log message of the current error */
4761 WARN_ON(!msg);
4762 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4763 reporter->error_count++;
Eran Ben Elishaa0a21ad2019-03-03 10:57:29 +02004764 prev_health_state = reporter->health_state;
4765 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004766
4767 /* abort if the previous error wasn't recovered */
4768 if (reporter->auto_recover &&
Eran Ben Elishaa0a21ad2019-03-03 10:57:29 +02004769 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004770 jiffies - reporter->last_recovery_ts <
4771 msecs_to_jiffies(reporter->graceful_period))) {
4772 trace_devlink_health_recover_aborted(devlink,
4773 reporter->ops->name,
4774 reporter->health_state,
4775 jiffies -
4776 reporter->last_recovery_ts);
4777 return -ECANCELED;
4778 }
4779
4780 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4781
4782 mutex_lock(&reporter->dump_lock);
4783 /* store current dump of current error, for later analysis */
4784 devlink_health_do_dump(reporter, priv_ctx);
4785 mutex_unlock(&reporter->dump_lock);
4786
4787 if (reporter->auto_recover)
4788 return devlink_health_reporter_recover(reporter, priv_ctx);
4789
4790 return 0;
4791}
4792EXPORT_SYMBOL_GPL(devlink_health_report);
4793
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004794static struct devlink_health_reporter *
Aya Levine44ef4e2019-05-16 09:49:20 +03004795devlink_health_reporter_get_from_attrs(struct devlink *devlink,
4796 struct nlattr **attrs)
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004797{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004798 struct devlink_health_reporter *reporter;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004799 char *reporter_name;
4800
Aya Levine44ef4e2019-05-16 09:49:20 +03004801 if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004802 return NULL;
4803
Aya Levine44ef4e2019-05-16 09:49:20 +03004804 reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004805 mutex_lock(&devlink->reporters_lock);
4806 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
4807 if (reporter)
4808 refcount_inc(&reporter->refcount);
4809 mutex_unlock(&devlink->reporters_lock);
4810 return reporter;
4811}
4812
Aya Levine44ef4e2019-05-16 09:49:20 +03004813static struct devlink_health_reporter *
4814devlink_health_reporter_get_from_info(struct devlink *devlink,
4815 struct genl_info *info)
4816{
4817 return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
4818}
4819
4820static struct devlink_health_reporter *
4821devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
4822{
4823 struct devlink_health_reporter *reporter;
4824 struct devlink *devlink;
4825 struct nlattr **attrs;
4826 int err;
4827
4828 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
4829 if (!attrs)
4830 return NULL;
4831
4832 err = nlmsg_parse_deprecated(cb->nlh,
4833 GENL_HDRLEN + devlink_nl_family.hdrsize,
4834 attrs, DEVLINK_ATTR_MAX,
4835 devlink_nl_family.policy, cb->extack);
4836 if (err)
4837 goto free;
4838
4839 mutex_lock(&devlink_mutex);
4840 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
4841 if (IS_ERR(devlink))
4842 goto unlock;
4843
4844 reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
4845 mutex_unlock(&devlink_mutex);
4846 kfree(attrs);
4847 return reporter;
4848unlock:
4849 mutex_unlock(&devlink_mutex);
4850free:
4851 kfree(attrs);
4852 return NULL;
4853}
4854
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004855static void
4856devlink_health_reporter_put(struct devlink_health_reporter *reporter)
4857{
4858 refcount_dec(&reporter->refcount);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004859}
4860
4861static int
4862devlink_nl_health_reporter_fill(struct sk_buff *msg,
4863 struct devlink *devlink,
4864 struct devlink_health_reporter *reporter,
4865 enum devlink_command cmd, u32 portid,
4866 u32 seq, int flags)
4867{
4868 struct nlattr *reporter_attr;
4869 void *hdr;
4870
4871 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4872 if (!hdr)
4873 return -EMSGSIZE;
4874
4875 if (devlink_nl_put_handle(msg, devlink))
4876 goto genlmsg_cancel;
4877
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004878 reporter_attr = nla_nest_start_noflag(msg,
4879 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004880 if (!reporter_attr)
4881 goto genlmsg_cancel;
4882 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4883 reporter->ops->name))
4884 goto reporter_nest_cancel;
4885 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4886 reporter->health_state))
4887 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02004888 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004889 reporter->error_count, DEVLINK_ATTR_PAD))
4890 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02004891 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004892 reporter->recovery_count, DEVLINK_ATTR_PAD))
4893 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02004894 if (reporter->ops->recover &&
4895 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004896 reporter->graceful_period,
4897 DEVLINK_ATTR_PAD))
4898 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02004899 if (reporter->ops->recover &&
4900 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004901 reporter->auto_recover))
4902 goto reporter_nest_cancel;
4903 if (reporter->dump_fmsg &&
4904 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4905 jiffies_to_msecs(reporter->dump_ts),
4906 DEVLINK_ATTR_PAD))
4907 goto reporter_nest_cancel;
4908
4909 nla_nest_end(msg, reporter_attr);
4910 genlmsg_end(msg, hdr);
4911 return 0;
4912
4913reporter_nest_cancel:
4914 nla_nest_end(msg, reporter_attr);
4915genlmsg_cancel:
4916 genlmsg_cancel(msg, hdr);
4917 return -EMSGSIZE;
4918}
4919
4920static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4921 struct genl_info *info)
4922{
4923 struct devlink *devlink = info->user_ptr[0];
4924 struct devlink_health_reporter *reporter;
4925 struct sk_buff *msg;
4926 int err;
4927
4928 reporter = devlink_health_reporter_get_from_info(devlink, info);
4929 if (!reporter)
4930 return -EINVAL;
4931
4932 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004933 if (!msg) {
4934 err = -ENOMEM;
4935 goto out;
4936 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004937
4938 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4939 DEVLINK_CMD_HEALTH_REPORTER_GET,
4940 info->snd_portid, info->snd_seq,
4941 0);
4942 if (err) {
4943 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004944 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004945 }
4946
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004947 err = genlmsg_reply(msg, info);
4948out:
4949 devlink_health_reporter_put(reporter);
4950 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004951}
4952
4953static int
4954devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4955 struct netlink_callback *cb)
4956{
4957 struct devlink_health_reporter *reporter;
4958 struct devlink *devlink;
4959 int start = cb->args[0];
4960 int idx = 0;
4961 int err;
4962
4963 mutex_lock(&devlink_mutex);
4964 list_for_each_entry(devlink, &devlink_list, list) {
4965 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4966 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004967 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004968 list_for_each_entry(reporter, &devlink->reporter_list,
4969 list) {
4970 if (idx < start) {
4971 idx++;
4972 continue;
4973 }
4974 err = devlink_nl_health_reporter_fill(msg, devlink,
4975 reporter,
4976 DEVLINK_CMD_HEALTH_REPORTER_GET,
4977 NETLINK_CB(cb->skb).portid,
4978 cb->nlh->nlmsg_seq,
4979 NLM_F_MULTI);
4980 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004981 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004982 goto out;
4983 }
4984 idx++;
4985 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004986 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004987 }
4988out:
4989 mutex_unlock(&devlink_mutex);
4990
4991 cb->args[0] = idx;
4992 return msg->len;
4993}
4994
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004995static int
4996devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
4997 struct genl_info *info)
4998{
4999 struct devlink *devlink = info->user_ptr[0];
5000 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005001 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005002
5003 reporter = devlink_health_reporter_get_from_info(devlink, info);
5004 if (!reporter)
5005 return -EINVAL;
5006
5007 if (!reporter->ops->recover &&
5008 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005009 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
5010 err = -EOPNOTSUPP;
5011 goto out;
5012 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005013
5014 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
5015 reporter->graceful_period =
5016 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
5017
5018 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
5019 reporter->auto_recover =
5020 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
5021
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005022 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005023 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005024out:
5025 devlink_health_reporter_put(reporter);
5026 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005027}
5028
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005029static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
5030 struct genl_info *info)
5031{
5032 struct devlink *devlink = info->user_ptr[0];
5033 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005034 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005035
5036 reporter = devlink_health_reporter_get_from_info(devlink, info);
5037 if (!reporter)
5038 return -EINVAL;
5039
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005040 err = devlink_health_reporter_recover(reporter, NULL);
5041
5042 devlink_health_reporter_put(reporter);
5043 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005044}
5045
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005046static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
5047 struct genl_info *info)
5048{
5049 struct devlink *devlink = info->user_ptr[0];
5050 struct devlink_health_reporter *reporter;
5051 struct devlink_fmsg *fmsg;
5052 int err;
5053
5054 reporter = devlink_health_reporter_get_from_info(devlink, info);
5055 if (!reporter)
5056 return -EINVAL;
5057
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005058 if (!reporter->ops->diagnose) {
5059 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005060 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005061 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005062
5063 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005064 if (!fmsg) {
5065 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005066 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005067 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005068
5069 err = devlink_fmsg_obj_nest_start(fmsg);
5070 if (err)
5071 goto out;
5072
5073 err = reporter->ops->diagnose(reporter, fmsg);
5074 if (err)
5075 goto out;
5076
5077 err = devlink_fmsg_obj_nest_end(fmsg);
5078 if (err)
5079 goto out;
5080
5081 err = devlink_fmsg_snd(fmsg, info,
5082 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
5083
5084out:
5085 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005086 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005087 return err;
5088}
5089
Aya Levine44ef4e2019-05-16 09:49:20 +03005090static int
5091devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
5092 struct netlink_callback *cb)
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005093{
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005094 struct devlink_health_reporter *reporter;
Aya Levine44ef4e2019-05-16 09:49:20 +03005095 u64 start = cb->args[0];
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005096 int err;
5097
Aya Levine44ef4e2019-05-16 09:49:20 +03005098 reporter = devlink_health_reporter_get_from_cb(cb);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005099 if (!reporter)
5100 return -EINVAL;
5101
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005102 if (!reporter->ops->dump) {
Aya Levine44ef4e2019-05-16 09:49:20 +03005103 err = -EOPNOTSUPP;
5104 goto out;
5105 }
5106 mutex_lock(&reporter->dump_lock);
5107 if (!start) {
5108 err = devlink_health_do_dump(reporter, NULL);
5109 if (err)
5110 goto unlock;
5111 cb->args[1] = reporter->dump_ts;
5112 }
5113 if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
5114 NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
5115 err = -EAGAIN;
5116 goto unlock;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005117 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005118
Aya Levine44ef4e2019-05-16 09:49:20 +03005119 err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
5120 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
5121unlock:
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005122 mutex_unlock(&reporter->dump_lock);
Aya Levine44ef4e2019-05-16 09:49:20 +03005123out:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005124 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005125 return err;
5126}
5127
5128static int
5129devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
5130 struct genl_info *info)
5131{
5132 struct devlink *devlink = info->user_ptr[0];
5133 struct devlink_health_reporter *reporter;
5134
5135 reporter = devlink_health_reporter_get_from_info(devlink, info);
5136 if (!reporter)
5137 return -EINVAL;
5138
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005139 if (!reporter->ops->dump) {
5140 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005141 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005142 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005143
5144 mutex_lock(&reporter->dump_lock);
5145 devlink_health_dump_clear(reporter);
5146 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005147 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005148 return 0;
5149}
5150
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005151static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
5152 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
5153 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
5154 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
5155 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
5156 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02005157 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
5158 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
5159 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
5160 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
5161 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
5162 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
5163 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03005164 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
Roi Dayan59bfde02016-11-22 23:09:57 +02005165 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03005166 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005167 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
5168 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005169 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
5170 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005171 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
5172 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
5173 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005174 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03005175 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005176 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005177 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
5178 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08005179 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
5180 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005181};
5182
5183static const struct genl_ops devlink_nl_ops[] = {
5184 {
5185 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005186 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005187 .doit = devlink_nl_cmd_get_doit,
5188 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirko1fc22572016-04-08 19:12:48 +02005189 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005190 /* can be retrieved by unprivileged users */
5191 },
5192 {
5193 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005194 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005195 .doit = devlink_nl_cmd_port_get_doit,
5196 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005197 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5198 /* can be retrieved by unprivileged users */
5199 },
5200 {
5201 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005202 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005203 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005204 .flags = GENL_ADMIN_PERM,
5205 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5206 },
5207 {
5208 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02005209 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005210 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005211 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005212 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5213 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005214 },
5215 {
5216 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02005217 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005218 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005219 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005220 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5221 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005222 },
Jiri Pirkobf797472016-04-14 18:19:13 +02005223 {
5224 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005225 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005226 .doit = devlink_nl_cmd_sb_get_doit,
5227 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005228 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5229 DEVLINK_NL_FLAG_NEED_SB,
5230 /* can be retrieved by unprivileged users */
5231 },
5232 {
5233 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005234 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005235 .doit = devlink_nl_cmd_sb_pool_get_doit,
5236 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005237 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5238 DEVLINK_NL_FLAG_NEED_SB,
5239 /* can be retrieved by unprivileged users */
5240 },
5241 {
5242 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005243 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005244 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005245 .flags = GENL_ADMIN_PERM,
5246 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5247 DEVLINK_NL_FLAG_NEED_SB,
5248 },
5249 {
5250 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005251 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005252 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
5253 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005254 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5255 DEVLINK_NL_FLAG_NEED_SB,
5256 /* can be retrieved by unprivileged users */
5257 },
5258 {
5259 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005260 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005261 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005262 .flags = GENL_ADMIN_PERM,
5263 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5264 DEVLINK_NL_FLAG_NEED_SB,
5265 },
5266 {
5267 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005268 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005269 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
5270 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005271 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5272 DEVLINK_NL_FLAG_NEED_SB,
5273 /* can be retrieved by unprivileged users */
5274 },
5275 {
5276 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005277 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005278 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005279 .flags = GENL_ADMIN_PERM,
5280 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5281 DEVLINK_NL_FLAG_NEED_SB,
5282 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005283 {
5284 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02005285 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005286 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005287 .flags = GENL_ADMIN_PERM,
5288 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005289 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005290 },
5291 {
5292 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02005293 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005294 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005295 .flags = GENL_ADMIN_PERM,
5296 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005297 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005298 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03005299 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005300 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005301 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005302 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005303 .flags = GENL_ADMIN_PERM,
5304 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5305 },
5306 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005307 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005308 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005309 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005310 .flags = GENL_ADMIN_PERM,
Jakub Kicinski7ac1cc92018-05-21 22:12:50 -07005311 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5312 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005313 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005314 {
5315 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005316 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005317 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005318 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005319 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005320 },
5321 {
5322 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005323 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005324 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005325 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005326 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005327 },
5328 {
5329 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005330 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005331 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005332 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005333 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005334 },
5335 {
5336 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005337 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005338 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005339 .flags = GENL_ADMIN_PERM,
5340 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5341 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005342 {
5343 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005344 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005345 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005346 .flags = GENL_ADMIN_PERM,
5347 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5348 },
5349 {
5350 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02005351 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005352 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005353 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005354 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005355 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005356 {
5357 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02005358 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005359 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005360 .flags = GENL_ADMIN_PERM,
5361 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5362 DEVLINK_NL_FLAG_NO_LOCK,
5363 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005364 {
5365 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005366 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005367 .doit = devlink_nl_cmd_param_get_doit,
5368 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005369 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5370 /* can be retrieved by unprivileged users */
5371 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005372 {
5373 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005374 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005375 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005376 .flags = GENL_ADMIN_PERM,
5377 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5378 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005379 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305380 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005381 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305382 .doit = devlink_nl_cmd_port_param_get_doit,
5383 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305384 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5385 /* can be retrieved by unprivileged users */
5386 },
5387 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05305388 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005389 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05305390 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05305391 .flags = GENL_ADMIN_PERM,
5392 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5393 },
5394 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005395 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005396 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005397 .doit = devlink_nl_cmd_region_get_doit,
5398 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005399 .flags = GENL_ADMIN_PERM,
5400 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5401 },
Alex Vesker866319b2018-07-12 15:13:13 +03005402 {
5403 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02005404 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03005405 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03005406 .flags = GENL_ADMIN_PERM,
5407 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5408 },
Alex Vesker4e547952018-07-12 15:13:14 +03005409 {
5410 .cmd = DEVLINK_CMD_REGION_READ,
Johannes Bergef6243a2019-04-26 14:07:31 +02005411 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker4e547952018-07-12 15:13:14 +03005412 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03005413 .flags = GENL_ADMIN_PERM,
5414 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5415 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005416 {
5417 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005418 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005419 .doit = devlink_nl_cmd_info_get_doit,
5420 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005421 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5422 /* can be retrieved by unprivileged users */
5423 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005424 {
5425 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005426 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005427 .doit = devlink_nl_cmd_health_reporter_get_doit,
5428 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005429 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5430 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005431 /* can be retrieved by unprivileged users */
5432 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005433 {
5434 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005435 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005436 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005437 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005438 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5439 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005440 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005441 {
5442 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02005443 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005444 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005445 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005446 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5447 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005448 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005449 {
5450 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02005451 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005452 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005453 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005454 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5455 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005456 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005457 {
5458 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005459 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Aya Levine44ef4e2019-05-16 09:49:20 +03005460 .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005461 .flags = GENL_ADMIN_PERM,
5462 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5463 DEVLINK_NL_FLAG_NO_LOCK,
5464 },
5465 {
5466 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02005467 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005468 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005469 .flags = GENL_ADMIN_PERM,
5470 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5471 DEVLINK_NL_FLAG_NO_LOCK,
5472 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08005473 {
5474 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02005475 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08005476 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08005477 .flags = GENL_ADMIN_PERM,
5478 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5479 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005480};
5481
Johannes Berg56989f62016-10-24 14:40:05 +02005482static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02005483 .name = DEVLINK_GENL_NAME,
5484 .version = DEVLINK_GENL_VERSION,
5485 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01005486 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02005487 .netnsok = true,
5488 .pre_doit = devlink_nl_pre_doit,
5489 .post_doit = devlink_nl_post_doit,
5490 .module = THIS_MODULE,
5491 .ops = devlink_nl_ops,
5492 .n_ops = ARRAY_SIZE(devlink_nl_ops),
5493 .mcgrps = devlink_nl_mcgrps,
5494 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
5495};
5496
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005497/**
5498 * devlink_alloc - Allocate new devlink instance resources
5499 *
5500 * @ops: ops
5501 * @priv_size: size of user private data
5502 *
5503 * Allocate new devlink instance resources, including devlink index
5504 * and name.
5505 */
5506struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
5507{
5508 struct devlink *devlink;
5509
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08005510 if (WARN_ON(!ops))
5511 return NULL;
5512
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005513 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
5514 if (!devlink)
5515 return NULL;
5516 devlink->ops = ops;
5517 devlink_net_set(devlink, &init_net);
5518 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02005519 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005520 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005521 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03005522 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03005523 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005524 INIT_LIST_HEAD(&devlink->reporter_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005525 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005526 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005527 return devlink;
5528}
5529EXPORT_SYMBOL_GPL(devlink_alloc);
5530
5531/**
5532 * devlink_register - Register devlink instance
5533 *
5534 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08005535 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005536 */
5537int devlink_register(struct devlink *devlink, struct device *dev)
5538{
5539 mutex_lock(&devlink_mutex);
5540 devlink->dev = dev;
5541 list_add_tail(&devlink->list, &devlink_list);
5542 devlink_notify(devlink, DEVLINK_CMD_NEW);
5543 mutex_unlock(&devlink_mutex);
5544 return 0;
5545}
5546EXPORT_SYMBOL_GPL(devlink_register);
5547
5548/**
5549 * devlink_unregister - Unregister devlink instance
5550 *
5551 * @devlink: devlink
5552 */
5553void devlink_unregister(struct devlink *devlink)
5554{
5555 mutex_lock(&devlink_mutex);
5556 devlink_notify(devlink, DEVLINK_CMD_DEL);
5557 list_del(&devlink->list);
5558 mutex_unlock(&devlink_mutex);
5559}
5560EXPORT_SYMBOL_GPL(devlink_unregister);
5561
5562/**
5563 * devlink_free - Free devlink instance resources
5564 *
5565 * @devlink: devlink
5566 */
5567void devlink_free(struct devlink *devlink)
5568{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005569 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01005570 mutex_destroy(&devlink->lock);
Parav Panditb904aad2019-02-08 15:15:00 -06005571 WARN_ON(!list_empty(&devlink->reporter_list));
5572 WARN_ON(!list_empty(&devlink->region_list));
5573 WARN_ON(!list_empty(&devlink->param_list));
5574 WARN_ON(!list_empty(&devlink->resource_list));
5575 WARN_ON(!list_empty(&devlink->dpipe_table_list));
5576 WARN_ON(!list_empty(&devlink->sb_list));
5577 WARN_ON(!list_empty(&devlink->port_list));
5578
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005579 kfree(devlink);
5580}
5581EXPORT_SYMBOL_GPL(devlink_free);
5582
Jiri Pirko136bf272019-05-23 10:43:35 +02005583static void devlink_port_type_warn(struct work_struct *work)
5584{
5585 WARN(true, "Type was not set for devlink port.");
5586}
5587
5588static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
5589{
5590 /* Ignore CPU and DSA flavours. */
5591 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
5592 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
5593}
5594
5595#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 30)
5596
5597static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
5598{
5599 if (!devlink_port_type_should_warn(devlink_port))
5600 return;
5601 /* Schedule a work to WARN in case driver does not set port
5602 * type within timeout.
5603 */
5604 schedule_delayed_work(&devlink_port->type_warn_dw,
5605 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
5606}
5607
5608static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
5609{
5610 if (!devlink_port_type_should_warn(devlink_port))
5611 return;
5612 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
5613}
5614
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005615/**
5616 * devlink_port_register - Register devlink port
5617 *
5618 * @devlink: devlink
5619 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08005620 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005621 *
5622 * Register devlink port with provided port index. User can use
5623 * any indexing, even hw-related one. devlink_port structure
5624 * is convenient to be embedded inside user driver private structure.
5625 * Note that the caller should take care of zeroing the devlink_port
5626 * structure.
5627 */
5628int devlink_port_register(struct devlink *devlink,
5629 struct devlink_port *devlink_port,
5630 unsigned int port_index)
5631{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005632 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005633 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005634 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005635 return -EEXIST;
5636 }
5637 devlink_port->devlink = devlink;
5638 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005639 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01005640 spin_lock_init(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005641 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305642 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005643 mutex_unlock(&devlink->lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02005644 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
5645 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005646 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5647 return 0;
5648}
5649EXPORT_SYMBOL_GPL(devlink_port_register);
5650
5651/**
5652 * devlink_port_unregister - Unregister devlink port
5653 *
5654 * @devlink_port: devlink port
5655 */
5656void devlink_port_unregister(struct devlink_port *devlink_port)
5657{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005658 struct devlink *devlink = devlink_port->devlink;
5659
Jiri Pirko136bf272019-05-23 10:43:35 +02005660 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005661 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005662 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005663 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005664 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005665}
5666EXPORT_SYMBOL_GPL(devlink_port_unregister);
5667
5668static void __devlink_port_type_set(struct devlink_port *devlink_port,
5669 enum devlink_port_type type,
5670 void *type_dev)
5671{
Jiri Pirko2b239e72019-03-24 11:14:36 +01005672 if (WARN_ON(!devlink_port->registered))
5673 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02005674 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkob8f97552019-03-24 11:14:37 +01005675 spin_lock(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005676 devlink_port->type = type;
5677 devlink_port->type_dev = type_dev;
Jiri Pirkob8f97552019-03-24 11:14:37 +01005678 spin_unlock(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005679 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5680}
5681
5682/**
5683 * devlink_port_type_eth_set - Set port type to Ethernet
5684 *
5685 * @devlink_port: devlink port
5686 * @netdev: related netdevice
5687 */
5688void devlink_port_type_eth_set(struct devlink_port *devlink_port,
5689 struct net_device *netdev)
5690{
Jiri Pirko119c0b52019-04-03 14:24:27 +02005691 const struct net_device_ops *ops = netdev->netdev_ops;
5692
Jiri Pirko746364f2019-03-28 13:56:46 +01005693 /* If driver registers devlink port, it should set devlink port
5694 * attributes accordingly so the compat functions are called
5695 * and the original ops are not used.
5696 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02005697 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01005698 /* Some drivers use the same set of ndos for netdevs
5699 * that have devlink_port registered and also for
5700 * those who don't. Make sure that ndo_get_phys_port_name
5701 * returns -EOPNOTSUPP here in case it is defined.
5702 * Warn if not.
5703 */
Jiri Pirko746364f2019-03-28 13:56:46 +01005704 char name[IFNAMSIZ];
5705 int err;
5706
5707 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
5708 WARN_ON(err != -EOPNOTSUPP);
5709 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02005710 if (ops->ndo_get_port_parent_id) {
5711 /* Some drivers use the same set of ndos for netdevs
5712 * that have devlink_port registered and also for
5713 * those who don't. Make sure that ndo_get_port_parent_id
5714 * returns -EOPNOTSUPP here in case it is defined.
5715 * Warn if not.
5716 */
5717 struct netdev_phys_item_id ppid;
5718 int err;
5719
5720 err = ops->ndo_get_port_parent_id(netdev, &ppid);
5721 WARN_ON(err != -EOPNOTSUPP);
5722 }
Jiri Pirko773b1f32019-03-24 11:14:30 +01005723 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005724}
5725EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
5726
5727/**
5728 * devlink_port_type_ib_set - Set port type to InfiniBand
5729 *
5730 * @devlink_port: devlink port
5731 * @ibdev: related IB device
5732 */
5733void devlink_port_type_ib_set(struct devlink_port *devlink_port,
5734 struct ib_device *ibdev)
5735{
Jiri Pirko773b1f32019-03-24 11:14:30 +01005736 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005737}
5738EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
5739
5740/**
5741 * devlink_port_type_clear - Clear port type
5742 *
5743 * @devlink_port: devlink port
5744 */
5745void devlink_port_type_clear(struct devlink_port *devlink_port)
5746{
Jiri Pirko773b1f32019-03-24 11:14:30 +01005747 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02005748 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005749}
5750EXPORT_SYMBOL_GPL(devlink_port_type_clear);
5751
Parav Pandit378ef012019-07-08 23:17:35 -05005752static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
5753 enum devlink_port_flavour flavour,
5754 const unsigned char *switch_id,
5755 unsigned char switch_id_len)
5756{
5757 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5758
5759 if (WARN_ON(devlink_port->registered))
5760 return -EEXIST;
5761 attrs->set = true;
5762 attrs->flavour = flavour;
5763 if (switch_id) {
5764 attrs->switch_port = true;
5765 if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
5766 switch_id_len = MAX_PHYS_ITEM_ID_LEN;
5767 memcpy(attrs->switch_id.id, switch_id, switch_id_len);
5768 attrs->switch_id.id_len = switch_id_len;
5769 } else {
5770 attrs->switch_port = false;
5771 }
5772 return 0;
5773}
5774
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005775/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005776 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005777 *
5778 * @devlink_port: devlink port
Jiri Pirko5ec13802018-05-18 09:29:01 +02005779 * @flavour: flavour of the port
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005780 * @port_number: number of the port that is facing user, for example
5781 * the front panel port number
5782 * @split: indicates if this is split port
5783 * @split_subport_number: if the port is split, this is the number
5784 * of subport.
Jiri Pirkobec52672019-04-03 14:24:16 +02005785 * @switch_id: if the port is part of switch, this is buffer with ID,
5786 * otwerwise this is NULL
5787 * @switch_id_len: length of the switch_id buffer
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005788 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005789void devlink_port_attrs_set(struct devlink_port *devlink_port,
Jiri Pirko5ec13802018-05-18 09:29:01 +02005790 enum devlink_port_flavour flavour,
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005791 u32 port_number, bool split,
Jiri Pirkobec52672019-04-03 14:24:16 +02005792 u32 split_subport_number,
5793 const unsigned char *switch_id,
5794 unsigned char switch_id_len)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005795{
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005796 struct devlink_port_attrs *attrs = &devlink_port->attrs;
Parav Pandit378ef012019-07-08 23:17:35 -05005797 int ret;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005798
Parav Pandit378ef012019-07-08 23:17:35 -05005799 ret = __devlink_port_attrs_set(devlink_port, flavour,
5800 switch_id, switch_id_len);
5801 if (ret)
Jiri Pirko45b86112019-03-24 11:14:33 +01005802 return;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005803 attrs->split = split;
Parav Pandit378ef012019-07-08 23:17:35 -05005804 attrs->phys.port_number = port_number;
5805 attrs->phys.split_subport_number = split_subport_number;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005806}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005807EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005808
Parav Pandit98fd2d62019-07-08 23:17:37 -05005809/**
5810 * devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
5811 *
5812 * @devlink_port: devlink port
5813 * @pf: associated PF for the devlink port instance
5814 * @switch_id: if the port is part of switch, this is buffer with ID,
5815 * otherwise this is NULL
5816 * @switch_id_len: length of the switch_id buffer
5817 */
5818void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port,
5819 const unsigned char *switch_id,
5820 unsigned char switch_id_len, u16 pf)
5821{
5822 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5823 int ret;
5824
5825 ret = __devlink_port_attrs_set(devlink_port,
5826 DEVLINK_PORT_FLAVOUR_PCI_PF,
5827 switch_id, switch_id_len);
5828 if (ret)
5829 return;
5830
5831 attrs->pci_pf.pf = pf;
5832}
5833EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
5834
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01005835static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
5836 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02005837{
5838 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5839 int n = 0;
5840
5841 if (!attrs->set)
5842 return -EOPNOTSUPP;
5843
5844 switch (attrs->flavour) {
5845 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
5846 if (!attrs->split)
Parav Pandit378ef012019-07-08 23:17:35 -05005847 n = snprintf(name, len, "p%u", attrs->phys.port_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02005848 else
Parav Pandit378ef012019-07-08 23:17:35 -05005849 n = snprintf(name, len, "p%us%u",
5850 attrs->phys.port_number,
5851 attrs->phys.split_subport_number);
Jiri Pirko08474c12018-05-18 09:29:02 +02005852 break;
5853 case DEVLINK_PORT_FLAVOUR_CPU:
5854 case DEVLINK_PORT_FLAVOUR_DSA:
5855 /* As CPU and DSA ports do not have a netdevice associated
5856 * case should not ever happen.
5857 */
5858 WARN_ON(1);
5859 return -EINVAL;
Parav Pandit98fd2d62019-07-08 23:17:37 -05005860 case DEVLINK_PORT_FLAVOUR_PCI_PF:
5861 n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
5862 break;
Jiri Pirko08474c12018-05-18 09:29:02 +02005863 }
5864
5865 if (n >= len)
5866 return -EINVAL;
5867
5868 return 0;
5869}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01005870
Jiri Pirkobf797472016-04-14 18:19:13 +02005871int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
5872 u32 size, u16 ingress_pools_count,
5873 u16 egress_pools_count, u16 ingress_tc_count,
5874 u16 egress_tc_count)
5875{
5876 struct devlink_sb *devlink_sb;
5877 int err = 0;
5878
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005879 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005880 if (devlink_sb_index_exists(devlink, sb_index)) {
5881 err = -EEXIST;
5882 goto unlock;
5883 }
5884
5885 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
5886 if (!devlink_sb) {
5887 err = -ENOMEM;
5888 goto unlock;
5889 }
5890 devlink_sb->index = sb_index;
5891 devlink_sb->size = size;
5892 devlink_sb->ingress_pools_count = ingress_pools_count;
5893 devlink_sb->egress_pools_count = egress_pools_count;
5894 devlink_sb->ingress_tc_count = ingress_tc_count;
5895 devlink_sb->egress_tc_count = egress_tc_count;
5896 list_add_tail(&devlink_sb->list, &devlink->sb_list);
5897unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005898 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005899 return err;
5900}
5901EXPORT_SYMBOL_GPL(devlink_sb_register);
5902
5903void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
5904{
5905 struct devlink_sb *devlink_sb;
5906
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005907 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005908 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
5909 WARN_ON(!devlink_sb);
5910 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005911 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005912 kfree(devlink_sb);
5913}
5914EXPORT_SYMBOL_GPL(devlink_sb_unregister);
5915
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005916/**
5917 * devlink_dpipe_headers_register - register dpipe headers
5918 *
5919 * @devlink: devlink
5920 * @dpipe_headers: dpipe header array
5921 *
5922 * Register the headers supported by hardware.
5923 */
5924int devlink_dpipe_headers_register(struct devlink *devlink,
5925 struct devlink_dpipe_headers *dpipe_headers)
5926{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005927 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005928 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005929 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005930 return 0;
5931}
5932EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
5933
5934/**
5935 * devlink_dpipe_headers_unregister - unregister dpipe headers
5936 *
5937 * @devlink: devlink
5938 *
5939 * Unregister the headers supported by hardware.
5940 */
5941void devlink_dpipe_headers_unregister(struct devlink *devlink)
5942{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005943 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005944 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005945 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005946}
5947EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
5948
5949/**
5950 * devlink_dpipe_table_counter_enabled - check if counter allocation
5951 * required
5952 * @devlink: devlink
5953 * @table_name: tables name
5954 *
5955 * Used by driver to check if counter allocation is required.
5956 * After counter allocation is turned on the table entries
5957 * are updated to include counter statistics.
5958 *
5959 * After that point on the driver must respect the counter
5960 * state so that each entry added to the table is added
5961 * with a counter.
5962 */
5963bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
5964 const char *table_name)
5965{
5966 struct devlink_dpipe_table *table;
5967 bool enabled;
5968
5969 rcu_read_lock();
5970 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5971 table_name);
5972 enabled = false;
5973 if (table)
5974 enabled = table->counters_enabled;
5975 rcu_read_unlock();
5976 return enabled;
5977}
5978EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
5979
5980/**
5981 * devlink_dpipe_table_register - register dpipe table
5982 *
5983 * @devlink: devlink
5984 * @table_name: table name
5985 * @table_ops: table ops
5986 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005987 * @counter_control_extern: external control for counters
5988 */
5989int devlink_dpipe_table_register(struct devlink *devlink,
5990 const char *table_name,
5991 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02005992 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005993{
5994 struct devlink_dpipe_table *table;
5995
5996 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
5997 return -EEXIST;
5998
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02005999 if (WARN_ON(!table_ops->size_get))
6000 return -EINVAL;
6001
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006002 table = kzalloc(sizeof(*table), GFP_KERNEL);
6003 if (!table)
6004 return -ENOMEM;
6005
6006 table->name = table_name;
6007 table->table_ops = table_ops;
6008 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006009 table->counter_control_extern = counter_control_extern;
6010
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006011 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006012 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006013 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006014 return 0;
6015}
6016EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
6017
6018/**
6019 * devlink_dpipe_table_unregister - unregister dpipe table
6020 *
6021 * @devlink: devlink
6022 * @table_name: table name
6023 */
6024void devlink_dpipe_table_unregister(struct devlink *devlink,
6025 const char *table_name)
6026{
6027 struct devlink_dpipe_table *table;
6028
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006029 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006030 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6031 table_name);
6032 if (!table)
6033 goto unlock;
6034 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006035 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006036 kfree_rcu(table, rcu);
6037 return;
6038unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01006039 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02006040}
6041EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
6042
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006043/**
6044 * devlink_resource_register - devlink resource register
6045 *
6046 * @devlink: devlink
6047 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006048 * @resource_size: resource's size
6049 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08006050 * @parent_resource_id: resource's parent id
6051 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006052 */
6053int devlink_resource_register(struct devlink *devlink,
6054 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006055 u64 resource_size,
6056 u64 resource_id,
6057 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02006058 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006059{
6060 struct devlink_resource *resource;
6061 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07006062 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006063 int err = 0;
6064
David Ahern14530742018-03-20 19:31:14 -07006065 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
6066
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006067 mutex_lock(&devlink->lock);
6068 resource = devlink_resource_find(devlink, NULL, resource_id);
6069 if (resource) {
6070 err = -EINVAL;
6071 goto out;
6072 }
6073
6074 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
6075 if (!resource) {
6076 err = -ENOMEM;
6077 goto out;
6078 }
6079
6080 if (top_hierarchy) {
6081 resource_list = &devlink->resource_list;
6082 } else {
6083 struct devlink_resource *parent_resource;
6084
6085 parent_resource = devlink_resource_find(devlink, NULL,
6086 parent_resource_id);
6087 if (parent_resource) {
6088 resource_list = &parent_resource->resource_list;
6089 resource->parent = parent_resource;
6090 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00006091 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006092 err = -EINVAL;
6093 goto out;
6094 }
6095 }
6096
6097 resource->name = resource_name;
6098 resource->size = resource_size;
6099 resource->size_new = resource_size;
6100 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006101 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01006102 memcpy(&resource->size_params, size_params,
6103 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01006104 INIT_LIST_HEAD(&resource->resource_list);
6105 list_add_tail(&resource->list, resource_list);
6106out:
6107 mutex_unlock(&devlink->lock);
6108 return err;
6109}
6110EXPORT_SYMBOL_GPL(devlink_resource_register);
6111
6112/**
6113 * devlink_resources_unregister - free all resources
6114 *
6115 * @devlink: devlink
6116 * @resource: resource
6117 */
6118void devlink_resources_unregister(struct devlink *devlink,
6119 struct devlink_resource *resource)
6120{
6121 struct devlink_resource *tmp, *child_resource;
6122 struct list_head *resource_list;
6123
6124 if (resource)
6125 resource_list = &resource->resource_list;
6126 else
6127 resource_list = &devlink->resource_list;
6128
6129 if (!resource)
6130 mutex_lock(&devlink->lock);
6131
6132 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
6133 devlink_resources_unregister(devlink, child_resource);
6134 list_del(&child_resource->list);
6135 kfree(child_resource);
6136 }
6137
6138 if (!resource)
6139 mutex_unlock(&devlink->lock);
6140}
6141EXPORT_SYMBOL_GPL(devlink_resources_unregister);
6142
6143/**
6144 * devlink_resource_size_get - get and update size
6145 *
6146 * @devlink: devlink
6147 * @resource_id: the requested resource id
6148 * @p_resource_size: ptr to update
6149 */
6150int devlink_resource_size_get(struct devlink *devlink,
6151 u64 resource_id,
6152 u64 *p_resource_size)
6153{
6154 struct devlink_resource *resource;
6155 int err = 0;
6156
6157 mutex_lock(&devlink->lock);
6158 resource = devlink_resource_find(devlink, NULL, resource_id);
6159 if (!resource) {
6160 err = -EINVAL;
6161 goto out;
6162 }
6163 *p_resource_size = resource->size_new;
6164 resource->size = resource->size_new;
6165out:
6166 mutex_unlock(&devlink->lock);
6167 return err;
6168}
6169EXPORT_SYMBOL_GPL(devlink_resource_size_get);
6170
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01006171/**
6172 * devlink_dpipe_table_resource_set - set the resource id
6173 *
6174 * @devlink: devlink
6175 * @table_name: table name
6176 * @resource_id: resource id
6177 * @resource_units: number of resource's units consumed per table's entry
6178 */
6179int devlink_dpipe_table_resource_set(struct devlink *devlink,
6180 const char *table_name, u64 resource_id,
6181 u64 resource_units)
6182{
6183 struct devlink_dpipe_table *table;
6184 int err = 0;
6185
6186 mutex_lock(&devlink->lock);
6187 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
6188 table_name);
6189 if (!table) {
6190 err = -EINVAL;
6191 goto out;
6192 }
6193 table->resource_id = resource_id;
6194 table->resource_units = resource_units;
6195 table->resource_valid = true;
6196out:
6197 mutex_unlock(&devlink->lock);
6198 return err;
6199}
6200EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
6201
Jiri Pirkofc56be42018-04-05 22:13:21 +02006202/**
6203 * devlink_resource_occ_get_register - register occupancy getter
6204 *
6205 * @devlink: devlink
6206 * @resource_id: resource id
6207 * @occ_get: occupancy getter callback
6208 * @occ_get_priv: occupancy getter callback priv
6209 */
6210void devlink_resource_occ_get_register(struct devlink *devlink,
6211 u64 resource_id,
6212 devlink_resource_occ_get_t *occ_get,
6213 void *occ_get_priv)
6214{
6215 struct devlink_resource *resource;
6216
6217 mutex_lock(&devlink->lock);
6218 resource = devlink_resource_find(devlink, NULL, resource_id);
6219 if (WARN_ON(!resource))
6220 goto out;
6221 WARN_ON(resource->occ_get);
6222
6223 resource->occ_get = occ_get;
6224 resource->occ_get_priv = occ_get_priv;
6225out:
6226 mutex_unlock(&devlink->lock);
6227}
6228EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
6229
6230/**
6231 * devlink_resource_occ_get_unregister - unregister occupancy getter
6232 *
6233 * @devlink: devlink
6234 * @resource_id: resource id
6235 */
6236void devlink_resource_occ_get_unregister(struct devlink *devlink,
6237 u64 resource_id)
6238{
6239 struct devlink_resource *resource;
6240
6241 mutex_lock(&devlink->lock);
6242 resource = devlink_resource_find(devlink, NULL, resource_id);
6243 if (WARN_ON(!resource))
6244 goto out;
6245 WARN_ON(!resource->occ_get);
6246
6247 resource->occ_get = NULL;
6248 resource->occ_get_priv = NULL;
6249out:
6250 mutex_unlock(&devlink->lock);
6251}
6252EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
6253
Vasundhara Volam39e61602019-01-28 18:00:20 +05306254static int devlink_param_verify(const struct devlink_param *param)
6255{
6256 if (!param || !param->name || !param->supported_cmodes)
6257 return -EINVAL;
6258 if (param->generic)
6259 return devlink_param_generic_verify(param);
6260 else
6261 return devlink_param_driver_verify(param);
6262}
6263
6264static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306265 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306266 struct list_head *param_list,
6267 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306268 size_t params_count,
6269 enum devlink_command reg_cmd,
6270 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05306271{
6272 const struct devlink_param *param = params;
6273 int i;
6274 int err;
6275
6276 mutex_lock(&devlink->lock);
6277 for (i = 0; i < params_count; i++, param++) {
6278 err = devlink_param_verify(param);
6279 if (err)
6280 goto rollback;
6281
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306282 err = devlink_param_register_one(devlink, port_index,
6283 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306284 if (err)
6285 goto rollback;
6286 }
6287
6288 mutex_unlock(&devlink->lock);
6289 return 0;
6290
6291rollback:
6292 if (!i)
6293 goto unlock;
6294 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306295 devlink_param_unregister_one(devlink, port_index, param_list,
6296 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306297unlock:
6298 mutex_unlock(&devlink->lock);
6299 return err;
6300}
6301
6302static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306303 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306304 struct list_head *param_list,
6305 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306306 size_t params_count,
6307 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05306308{
6309 const struct devlink_param *param = params;
6310 int i;
6311
6312 mutex_lock(&devlink->lock);
6313 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306314 devlink_param_unregister_one(devlink, 0, param_list, param,
6315 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306316 mutex_unlock(&devlink->lock);
6317}
6318
Moshe Shemesheabaef12018-07-04 14:30:28 +03006319/**
6320 * devlink_params_register - register configuration parameters
6321 *
6322 * @devlink: devlink
6323 * @params: configuration parameters array
6324 * @params_count: number of parameters provided
6325 *
6326 * Register the configuration parameters supported by the driver.
6327 */
6328int devlink_params_register(struct devlink *devlink,
6329 const struct devlink_param *params,
6330 size_t params_count)
6331{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306332 return __devlink_params_register(devlink, 0, &devlink->param_list,
6333 params, params_count,
6334 DEVLINK_CMD_PARAM_NEW,
6335 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03006336}
6337EXPORT_SYMBOL_GPL(devlink_params_register);
6338
6339/**
6340 * devlink_params_unregister - unregister configuration parameters
6341 * @devlink: devlink
6342 * @params: configuration parameters to unregister
6343 * @params_count: number of parameters provided
6344 */
6345void devlink_params_unregister(struct devlink *devlink,
6346 const struct devlink_param *params,
6347 size_t params_count)
6348{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306349 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
6350 params, params_count,
6351 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03006352}
6353EXPORT_SYMBOL_GPL(devlink_params_unregister);
6354
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006355/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00006356 * devlink_params_publish - publish configuration parameters
6357 *
6358 * @devlink: devlink
6359 *
6360 * Publish previously registered configuration parameters.
6361 */
6362void devlink_params_publish(struct devlink *devlink)
6363{
6364 struct devlink_param_item *param_item;
6365
6366 list_for_each_entry(param_item, &devlink->param_list, list) {
6367 if (param_item->published)
6368 continue;
6369 param_item->published = true;
6370 devlink_param_notify(devlink, 0, param_item,
6371 DEVLINK_CMD_PARAM_NEW);
6372 }
6373}
6374EXPORT_SYMBOL_GPL(devlink_params_publish);
6375
6376/**
6377 * devlink_params_unpublish - unpublish configuration parameters
6378 *
6379 * @devlink: devlink
6380 *
6381 * Unpublish previously registered configuration parameters.
6382 */
6383void devlink_params_unpublish(struct devlink *devlink)
6384{
6385 struct devlink_param_item *param_item;
6386
6387 list_for_each_entry(param_item, &devlink->param_list, list) {
6388 if (!param_item->published)
6389 continue;
6390 param_item->published = false;
6391 devlink_param_notify(devlink, 0, param_item,
6392 DEVLINK_CMD_PARAM_DEL);
6393 }
6394}
6395EXPORT_SYMBOL_GPL(devlink_params_unpublish);
6396
6397/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05306398 * devlink_port_params_register - register port configuration parameters
6399 *
6400 * @devlink_port: devlink port
6401 * @params: configuration parameters array
6402 * @params_count: number of parameters provided
6403 *
6404 * Register the configuration parameters supported by the port.
6405 */
6406int devlink_port_params_register(struct devlink_port *devlink_port,
6407 const struct devlink_param *params,
6408 size_t params_count)
6409{
6410 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306411 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306412 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306413 params_count,
6414 DEVLINK_CMD_PORT_PARAM_NEW,
6415 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306416}
6417EXPORT_SYMBOL_GPL(devlink_port_params_register);
6418
6419/**
6420 * devlink_port_params_unregister - unregister port configuration
6421 * parameters
6422 *
6423 * @devlink_port: devlink port
6424 * @params: configuration parameters array
6425 * @params_count: number of parameters provided
6426 */
6427void devlink_port_params_unregister(struct devlink_port *devlink_port,
6428 const struct devlink_param *params,
6429 size_t params_count)
6430{
6431 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306432 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306433 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306434 params, params_count,
6435 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306436}
6437EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
6438
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306439static int
6440__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
6441 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006442{
6443 struct devlink_param_item *param_item;
6444
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306445 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006446 if (!param_item)
6447 return -EINVAL;
6448
6449 if (!param_item->driverinit_value_valid ||
6450 !devlink_param_cmode_is_supported(param_item->param,
6451 DEVLINK_PARAM_CMODE_DRIVERINIT))
6452 return -EOPNOTSUPP;
6453
Moshe Shemesh12765342018-10-10 16:09:26 +03006454 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6455 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
6456 else
6457 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006458
6459 return 0;
6460}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306461
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306462static int
6463__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306464 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306465 struct list_head *param_list, u32 param_id,
6466 union devlink_param_value init_val,
6467 enum devlink_command cmd)
6468{
6469 struct devlink_param_item *param_item;
6470
6471 param_item = devlink_param_find_by_id(param_list, param_id);
6472 if (!param_item)
6473 return -EINVAL;
6474
6475 if (!devlink_param_cmode_is_supported(param_item->param,
6476 DEVLINK_PARAM_CMODE_DRIVERINIT))
6477 return -EOPNOTSUPP;
6478
6479 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6480 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
6481 else
6482 param_item->driverinit_value = init_val;
6483 param_item->driverinit_value_valid = true;
6484
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306485 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306486 return 0;
6487}
6488
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306489/**
6490 * devlink_param_driverinit_value_get - get configuration parameter
6491 * value for driver initializing
6492 *
6493 * @devlink: devlink
6494 * @param_id: parameter ID
6495 * @init_val: value of parameter in driverinit configuration mode
6496 *
6497 * This function should be used by the driver to get driverinit
6498 * configuration for initialization after reload command.
6499 */
6500int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
6501 union devlink_param_value *init_val)
6502{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08006503 if (!devlink->ops->reload)
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306504 return -EOPNOTSUPP;
6505
6506 return __devlink_param_driverinit_value_get(&devlink->param_list,
6507 param_id, init_val);
6508}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006509EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
6510
6511/**
6512 * devlink_param_driverinit_value_set - set value of configuration
6513 * parameter for driverinit
6514 * configuration mode
6515 *
6516 * @devlink: devlink
6517 * @param_id: parameter ID
6518 * @init_val: value of parameter to set for driverinit configuration mode
6519 *
6520 * This function should be used by the driver to set driverinit
6521 * configuration mode default value.
6522 */
6523int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
6524 union devlink_param_value init_val)
6525{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306526 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306527 &devlink->param_list,
6528 param_id, init_val,
6529 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006530}
6531EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
6532
Moshe Shemeshea601e12018-07-04 14:30:32 +03006533/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306534 * devlink_port_param_driverinit_value_get - get configuration parameter
6535 * value for driver initializing
6536 *
6537 * @devlink_port: devlink_port
6538 * @param_id: parameter ID
6539 * @init_val: value of parameter in driverinit configuration mode
6540 *
6541 * This function should be used by the driver to get driverinit
6542 * configuration for initialization after reload command.
6543 */
6544int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
6545 u32 param_id,
6546 union devlink_param_value *init_val)
6547{
6548 struct devlink *devlink = devlink_port->devlink;
6549
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08006550 if (!devlink->ops->reload)
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306551 return -EOPNOTSUPP;
6552
6553 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
6554 param_id, init_val);
6555}
6556EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
6557
6558/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306559 * devlink_port_param_driverinit_value_set - set value of configuration
6560 * parameter for driverinit
6561 * configuration mode
6562 *
6563 * @devlink_port: devlink_port
6564 * @param_id: parameter ID
6565 * @init_val: value of parameter to set for driverinit configuration mode
6566 *
6567 * This function should be used by the driver to set driverinit
6568 * configuration mode default value.
6569 */
6570int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
6571 u32 param_id,
6572 union devlink_param_value init_val)
6573{
6574 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306575 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306576 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306577 param_id, init_val,
6578 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306579}
6580EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
6581
6582/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03006583 * devlink_param_value_changed - notify devlink on a parameter's value
6584 * change. Should be called by the driver
6585 * right after the change.
6586 *
6587 * @devlink: devlink
6588 * @param_id: parameter ID
6589 *
6590 * This function should be used by the driver to notify devlink on value
6591 * change, excluding driverinit configuration mode.
6592 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03006593 */
6594void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
6595{
6596 struct devlink_param_item *param_item;
6597
6598 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
6599 WARN_ON(!param_item);
6600
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306601 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03006602}
6603EXPORT_SYMBOL_GPL(devlink_param_value_changed);
6604
Alex Veskerb16ebe92018-07-12 15:13:08 +03006605/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306606 * devlink_port_param_value_changed - notify devlink on a parameter's value
6607 * change. Should be called by the driver
6608 * right after the change.
6609 *
6610 * @devlink_port: devlink_port
6611 * @param_id: parameter ID
6612 *
6613 * This function should be used by the driver to notify devlink on value
6614 * change, excluding driverinit configuration mode.
6615 * For driverinit configuration mode driver should use the function
6616 * devlink_port_param_driverinit_value_set() instead.
6617 */
6618void devlink_port_param_value_changed(struct devlink_port *devlink_port,
6619 u32 param_id)
6620{
6621 struct devlink_param_item *param_item;
6622
6623 param_item = devlink_param_find_by_id(&devlink_port->param_list,
6624 param_id);
6625 WARN_ON(!param_item);
6626
6627 devlink_param_notify(devlink_port->devlink, devlink_port->index,
6628 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
6629}
6630EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
6631
6632/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03006633 * devlink_param_value_str_fill - Safely fill-up the string preventing
6634 * from overflow of the preallocated buffer
6635 *
6636 * @dst_val: destination devlink_param_value
6637 * @src: source buffer
6638 */
6639void devlink_param_value_str_fill(union devlink_param_value *dst_val,
6640 const char *src)
6641{
6642 size_t len;
6643
6644 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
6645 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
6646}
6647EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
6648
6649/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03006650 * devlink_region_create - create a new address region
6651 *
6652 * @devlink: devlink
6653 * @region_name: region name
6654 * @region_max_snapshots: Maximum supported number of snapshots for region
6655 * @region_size: size of region
6656 */
6657struct devlink_region *devlink_region_create(struct devlink *devlink,
6658 const char *region_name,
6659 u32 region_max_snapshots,
6660 u64 region_size)
6661{
6662 struct devlink_region *region;
6663 int err = 0;
6664
6665 mutex_lock(&devlink->lock);
6666
6667 if (devlink_region_get_by_name(devlink, region_name)) {
6668 err = -EEXIST;
6669 goto unlock;
6670 }
6671
6672 region = kzalloc(sizeof(*region), GFP_KERNEL);
6673 if (!region) {
6674 err = -ENOMEM;
6675 goto unlock;
6676 }
6677
6678 region->devlink = devlink;
6679 region->max_snapshots = region_max_snapshots;
6680 region->name = region_name;
6681 region->size = region_size;
6682 INIT_LIST_HEAD(&region->snapshot_list);
6683 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03006684 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03006685
6686 mutex_unlock(&devlink->lock);
6687 return region;
6688
6689unlock:
6690 mutex_unlock(&devlink->lock);
6691 return ERR_PTR(err);
6692}
6693EXPORT_SYMBOL_GPL(devlink_region_create);
6694
6695/**
6696 * devlink_region_destroy - destroy address region
6697 *
6698 * @region: devlink region to destroy
6699 */
6700void devlink_region_destroy(struct devlink_region *region)
6701{
6702 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03006703 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03006704
6705 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03006706
6707 /* Free all snapshots of region */
6708 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
6709 devlink_region_snapshot_del(snapshot);
6710
Alex Veskerb16ebe92018-07-12 15:13:08 +03006711 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03006712
6713 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03006714 mutex_unlock(&devlink->lock);
6715 kfree(region);
6716}
6717EXPORT_SYMBOL_GPL(devlink_region_destroy);
6718
Alex Veskerccadfa42018-07-12 15:13:09 +03006719/**
6720 * devlink_region_shapshot_id_get - get snapshot ID
6721 *
6722 * This callback should be called when adding a new snapshot,
6723 * Driver should use the same id for multiple snapshots taken
6724 * on multiple regions at the same time/by the same trigger.
6725 *
6726 * @devlink: devlink
6727 */
6728u32 devlink_region_shapshot_id_get(struct devlink *devlink)
6729{
6730 u32 id;
6731
6732 mutex_lock(&devlink->lock);
6733 id = ++devlink->snapshot_id;
6734 mutex_unlock(&devlink->lock);
6735
6736 return id;
6737}
6738EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
6739
Alex Veskerd7e52722018-07-12 15:13:10 +03006740/**
6741 * devlink_region_snapshot_create - create a new snapshot
6742 * This will add a new snapshot of a region. The snapshot
6743 * will be stored on the region struct and can be accessed
6744 * from devlink. This is useful for future analyses of snapshots.
6745 * Multiple snapshots can be created on a region.
6746 * The @snapshot_id should be obtained using the getter function.
6747 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08006748 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03006749 * @data_len: size of snapshot data
6750 * @data: snapshot data
6751 * @snapshot_id: snapshot id to be created
6752 * @data_destructor: pointer to destructor function to free data
6753 */
6754int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
6755 u8 *data, u32 snapshot_id,
6756 devlink_snapshot_data_dest_t *data_destructor)
6757{
6758 struct devlink *devlink = region->devlink;
6759 struct devlink_snapshot *snapshot;
6760 int err;
6761
6762 mutex_lock(&devlink->lock);
6763
6764 /* check if region can hold one more snapshot */
6765 if (region->cur_snapshots == region->max_snapshots) {
6766 err = -ENOMEM;
6767 goto unlock;
6768 }
6769
6770 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
6771 err = -EEXIST;
6772 goto unlock;
6773 }
6774
6775 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
6776 if (!snapshot) {
6777 err = -ENOMEM;
6778 goto unlock;
6779 }
6780
6781 snapshot->id = snapshot_id;
6782 snapshot->region = region;
6783 snapshot->data = data;
6784 snapshot->data_len = data_len;
6785 snapshot->data_destructor = data_destructor;
6786
6787 list_add_tail(&snapshot->list, &region->snapshot_list);
6788
6789 region->cur_snapshots++;
6790
Alex Vesker866319b2018-07-12 15:13:13 +03006791 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
Alex Veskerd7e52722018-07-12 15:13:10 +03006792 mutex_unlock(&devlink->lock);
6793 return 0;
6794
6795unlock:
6796 mutex_unlock(&devlink->lock);
6797 return err;
6798}
6799EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
6800
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006801static void __devlink_compat_running_version(struct devlink *devlink,
6802 char *buf, size_t len)
6803{
6804 const struct nlattr *nlattr;
6805 struct devlink_info_req req;
6806 struct sk_buff *msg;
6807 int rem, err;
6808
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006809 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6810 if (!msg)
6811 return;
6812
6813 req.msg = msg;
6814 err = devlink->ops->info_get(devlink, &req, NULL);
6815 if (err)
6816 goto free_msg;
6817
6818 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
6819 const struct nlattr *kv;
6820 int rem_kv;
6821
6822 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
6823 continue;
6824
6825 nla_for_each_nested(kv, nlattr, rem_kv) {
6826 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
6827 continue;
6828
6829 strlcat(buf, nla_data(kv), len);
6830 strlcat(buf, " ", len);
6831 }
6832 }
6833free_msg:
6834 nlmsg_free(msg);
6835}
6836
6837void devlink_compat_running_version(struct net_device *dev,
6838 char *buf, size_t len)
6839{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006840 struct devlink *devlink;
6841
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006842 dev_hold(dev);
6843 rtnl_unlock();
6844
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006845 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08006846 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006847 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006848
6849 mutex_lock(&devlink->lock);
6850 __devlink_compat_running_version(devlink, buf, len);
6851 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006852
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006853out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006854 rtnl_lock();
6855 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006856}
6857
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006858int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
6859{
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006860 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006861 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006862
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006863 dev_hold(dev);
6864 rtnl_unlock();
6865
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006866 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006867 if (!devlink || !devlink->ops->flash_update) {
6868 ret = -EOPNOTSUPP;
6869 goto out;
6870 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006871
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006872 mutex_lock(&devlink->lock);
6873 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
6874 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006875
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006876out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006877 rtnl_lock();
6878 dev_put(dev);
6879
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006880 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006881}
6882
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01006883int devlink_compat_phys_port_name_get(struct net_device *dev,
6884 char *name, size_t len)
6885{
6886 struct devlink_port *devlink_port;
6887
6888 /* RTNL mutex is held here which ensures that devlink_port
6889 * instance cannot disappear in the middle. No need to take
6890 * any devlink lock as only permanent values are accessed.
6891 */
6892 ASSERT_RTNL();
6893
6894 devlink_port = netdev_to_devlink_port(dev);
6895 if (!devlink_port)
6896 return -EOPNOTSUPP;
6897
6898 return __devlink_port_phys_port_name_get(devlink_port, name, len);
6899}
6900
Jiri Pirko7e1146e2019-04-03 14:24:17 +02006901int devlink_compat_switch_id_get(struct net_device *dev,
6902 struct netdev_phys_item_id *ppid)
6903{
6904 struct devlink_port *devlink_port;
6905
6906 /* RTNL mutex is held here which ensures that devlink_port
6907 * instance cannot disappear in the middle. No need to take
6908 * any devlink lock as only permanent values are accessed.
6909 */
6910 ASSERT_RTNL();
6911 devlink_port = netdev_to_devlink_port(dev);
6912 if (!devlink_port || !devlink_port->attrs.switch_port)
6913 return -EOPNOTSUPP;
6914
6915 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
6916
6917 return 0;
6918}
6919
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08006920static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006921{
Johannes Berg489111e2016-10-24 14:40:03 +02006922 return genl_register_family(&devlink_nl_family);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006923}
6924
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08006925subsys_initcall(devlink_init);