blob: 9716a7f382cb56ab56aee17c5059b536e6458af1 [file] [log] [blame]
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01001/*
2 * net/core/devlink.c - Network physical/parent device Netlink interface
3 *
4 * Heavily inspired by net/wireless/
5 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
6 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/slab.h>
18#include <linux/gfp.h>
19#include <linux/device.h>
20#include <linux/list.h>
21#include <linux/netdevice.h>
Jiri Pirkob8f97552019-03-24 11:14:37 +010022#include <linux/spinlock.h>
Moshe Shemeshb587bda2019-04-29 12:41:45 +030023#include <linux/refcount.h>
Jiri Pirko136bf272019-05-23 10:43:35 +020024#include <linux/workqueue.h>
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010025#include <rdma/ib_verbs.h>
26#include <net/netlink.h>
27#include <net/genetlink.h>
28#include <net/rtnetlink.h>
29#include <net/net_namespace.h>
30#include <net/sock.h>
31#include <net/devlink.h>
Jiri Pirkoe5224f02016-07-12 18:05:03 +020032#define CREATE_TRACE_POINTS
33#include <trace/events/devlink.h>
34
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020035static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
36 {
David Ahern12bdc5e2017-08-30 17:07:30 -070037 .name = "destination mac",
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020038 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
39 .bitwidth = 48,
40 },
41};
42
43struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
44 .name = "ethernet",
45 .id = DEVLINK_DPIPE_HEADER_ETHERNET,
46 .fields = devlink_dpipe_fields_ethernet,
47 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
48 .global = true,
49};
50EXPORT_SYMBOL(devlink_dpipe_header_ethernet);
51
Arkadi Sharshevsky3fb886e2017-08-24 08:40:00 +020052static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
53 {
54 .name = "destination ip",
55 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
56 .bitwidth = 32,
57 },
58};
59
60struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
61 .name = "ipv4",
62 .id = DEVLINK_DPIPE_HEADER_IPV4,
63 .fields = devlink_dpipe_fields_ipv4,
64 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
65 .global = true,
66};
67EXPORT_SYMBOL(devlink_dpipe_header_ipv4);
68
Arkadi Sharshevsky1797f5b2017-08-31 17:59:12 +020069static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
70 {
71 .name = "destination ip",
72 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
73 .bitwidth = 128,
74 },
75};
76
77struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
78 .name = "ipv6",
79 .id = DEVLINK_DPIPE_HEADER_IPV6,
80 .fields = devlink_dpipe_fields_ipv6,
81 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
82 .global = true,
83};
84EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
85
Jiri Pirkoe5224f02016-07-12 18:05:03 +020086EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
Nir Dotan57186a52019-02-04 18:47:45 +000087EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010088
89static LIST_HEAD(devlink_list);
90
91/* devlink_mutex
92 *
93 * An overall lock guarding every operation coming from userspace.
94 * It also guards devlink devices list and it is taken when
95 * driver registers/unregisters it.
96 */
97static DEFINE_MUTEX(devlink_mutex);
98
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010099static struct net *devlink_net(const struct devlink *devlink)
100{
101 return read_pnet(&devlink->_net);
102}
103
104static void devlink_net_set(struct devlink *devlink, struct net *net)
105{
106 write_pnet(&devlink->_net, net);
107}
108
109static struct devlink *devlink_get_from_attrs(struct net *net,
110 struct nlattr **attrs)
111{
112 struct devlink *devlink;
113 char *busname;
114 char *devname;
115
116 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
117 return ERR_PTR(-EINVAL);
118
119 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
120 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
121
Parav Panditdac7c082019-02-12 14:24:08 -0600122 lockdep_assert_held(&devlink_mutex);
123
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100124 list_for_each_entry(devlink, &devlink_list, list) {
125 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
126 strcmp(dev_name(devlink->dev), devname) == 0 &&
127 net_eq(devlink_net(devlink), net))
128 return devlink;
129 }
130
131 return ERR_PTR(-ENODEV);
132}
133
134static struct devlink *devlink_get_from_info(struct genl_info *info)
135{
136 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
137}
138
139static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
140 int port_index)
141{
142 struct devlink_port *devlink_port;
143
144 list_for_each_entry(devlink_port, &devlink->port_list, list) {
145 if (devlink_port->index == port_index)
146 return devlink_port;
147 }
148 return NULL;
149}
150
151static bool devlink_port_index_exists(struct devlink *devlink, int port_index)
152{
153 return devlink_port_get_by_index(devlink, port_index);
154}
155
156static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
157 struct nlattr **attrs)
158{
159 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
160 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
161 struct devlink_port *devlink_port;
162
163 devlink_port = devlink_port_get_by_index(devlink, port_index);
164 if (!devlink_port)
165 return ERR_PTR(-ENODEV);
166 return devlink_port;
167 }
168 return ERR_PTR(-EINVAL);
169}
170
171static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
172 struct genl_info *info)
173{
174 return devlink_port_get_from_attrs(devlink, info->attrs);
175}
176
Jiri Pirkobf797472016-04-14 18:19:13 +0200177struct devlink_sb {
178 struct list_head list;
179 unsigned int index;
180 u32 size;
181 u16 ingress_pools_count;
182 u16 egress_pools_count;
183 u16 ingress_tc_count;
184 u16 egress_tc_count;
185};
186
187static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
188{
189 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
190}
191
192static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
193 unsigned int sb_index)
194{
195 struct devlink_sb *devlink_sb;
196
197 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
198 if (devlink_sb->index == sb_index)
199 return devlink_sb;
200 }
201 return NULL;
202}
203
204static bool devlink_sb_index_exists(struct devlink *devlink,
205 unsigned int sb_index)
206{
207 return devlink_sb_get_by_index(devlink, sb_index);
208}
209
210static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
211 struct nlattr **attrs)
212{
213 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
214 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
215 struct devlink_sb *devlink_sb;
216
217 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
218 if (!devlink_sb)
219 return ERR_PTR(-ENODEV);
220 return devlink_sb;
221 }
222 return ERR_PTR(-EINVAL);
223}
224
225static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
226 struct genl_info *info)
227{
228 return devlink_sb_get_from_attrs(devlink, info->attrs);
229}
230
231static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
232 struct nlattr **attrs,
233 u16 *p_pool_index)
234{
235 u16 val;
236
237 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
238 return -EINVAL;
239
240 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
241 if (val >= devlink_sb_pool_count(devlink_sb))
242 return -EINVAL;
243 *p_pool_index = val;
244 return 0;
245}
246
247static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
248 struct genl_info *info,
249 u16 *p_pool_index)
250{
251 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
252 p_pool_index);
253}
254
255static int
256devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
257 enum devlink_sb_pool_type *p_pool_type)
258{
259 u8 val;
260
261 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
262 return -EINVAL;
263
264 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
265 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
266 val != DEVLINK_SB_POOL_TYPE_EGRESS)
267 return -EINVAL;
268 *p_pool_type = val;
269 return 0;
270}
271
272static int
273devlink_sb_pool_type_get_from_info(struct genl_info *info,
274 enum devlink_sb_pool_type *p_pool_type)
275{
276 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
277}
278
279static int
280devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
281 enum devlink_sb_threshold_type *p_th_type)
282{
283 u8 val;
284
285 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
286 return -EINVAL;
287
288 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
289 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
290 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
291 return -EINVAL;
292 *p_th_type = val;
293 return 0;
294}
295
296static int
297devlink_sb_th_type_get_from_info(struct genl_info *info,
298 enum devlink_sb_threshold_type *p_th_type)
299{
300 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
301}
302
303static int
304devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
305 struct nlattr **attrs,
306 enum devlink_sb_pool_type pool_type,
307 u16 *p_tc_index)
308{
309 u16 val;
310
311 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
312 return -EINVAL;
313
314 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
315 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
316 val >= devlink_sb->ingress_tc_count)
317 return -EINVAL;
318 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
319 val >= devlink_sb->egress_tc_count)
320 return -EINVAL;
321 *p_tc_index = val;
322 return 0;
323}
324
325static int
326devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
327 struct genl_info *info,
328 enum devlink_sb_pool_type pool_type,
329 u16 *p_tc_index)
330{
331 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
332 pool_type, p_tc_index);
333}
334
Alex Veskerb16ebe92018-07-12 15:13:08 +0300335struct devlink_region {
336 struct devlink *devlink;
337 struct list_head list;
338 const char *name;
339 struct list_head snapshot_list;
340 u32 max_snapshots;
341 u32 cur_snapshots;
342 u64 size;
343};
344
Alex Veskerd7e52722018-07-12 15:13:10 +0300345struct devlink_snapshot {
346 struct list_head list;
347 struct devlink_region *region;
348 devlink_snapshot_data_dest_t *data_destructor;
349 u64 data_len;
350 u8 *data;
351 u32 id;
352};
353
Alex Veskerb16ebe92018-07-12 15:13:08 +0300354static struct devlink_region *
355devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
356{
357 struct devlink_region *region;
358
359 list_for_each_entry(region, &devlink->region_list, list)
360 if (!strcmp(region->name, region_name))
361 return region;
362
363 return NULL;
364}
365
Alex Veskerd7e52722018-07-12 15:13:10 +0300366static struct devlink_snapshot *
367devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
368{
369 struct devlink_snapshot *snapshot;
370
371 list_for_each_entry(snapshot, &region->snapshot_list, list)
372 if (snapshot->id == id)
373 return snapshot;
374
375 return NULL;
376}
377
378static void devlink_region_snapshot_del(struct devlink_snapshot *snapshot)
379{
380 snapshot->region->cur_snapshots--;
381 list_del(&snapshot->list);
382 (*snapshot->data_destructor)(snapshot->data);
383 kfree(snapshot);
384}
385
Jiri Pirko1fc2257e2016-04-08 19:12:48 +0200386#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
387#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
Jiri Pirkobf797472016-04-14 18:19:13 +0200388#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100389
390/* The per devlink instance lock is taken by default in the pre-doit
391 * operation, yet several commands do not require this. The global
392 * devlink lock is taken and protects from disruption by user-calls.
393 */
394#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100395
396static int devlink_nl_pre_doit(const struct genl_ops *ops,
397 struct sk_buff *skb, struct genl_info *info)
398{
399 struct devlink *devlink;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100400 int err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100401
402 mutex_lock(&devlink_mutex);
403 devlink = devlink_get_from_info(info);
404 if (IS_ERR(devlink)) {
405 mutex_unlock(&devlink_mutex);
406 return PTR_ERR(devlink);
407 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100408 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
409 mutex_lock(&devlink->lock);
Jiri Pirko1fc2257e2016-04-08 19:12:48 +0200410 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
411 info->user_ptr[0] = devlink;
412 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100413 struct devlink_port *devlink_port;
414
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100415 devlink_port = devlink_port_get_from_info(devlink, info);
416 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100417 err = PTR_ERR(devlink_port);
418 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100419 }
Jiri Pirko1fc2257e2016-04-08 19:12:48 +0200420 info->user_ptr[0] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100421 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200422 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
423 struct devlink_sb *devlink_sb;
424
425 devlink_sb = devlink_sb_get_from_info(devlink, info);
426 if (IS_ERR(devlink_sb)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100427 err = PTR_ERR(devlink_sb);
428 goto unlock;
Jiri Pirkobf797472016-04-14 18:19:13 +0200429 }
430 info->user_ptr[1] = devlink_sb;
431 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100432 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100433
434unlock:
435 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
436 mutex_unlock(&devlink->lock);
437 mutex_unlock(&devlink_mutex);
438 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100439}
440
441static void devlink_nl_post_doit(const struct genl_ops *ops,
442 struct sk_buff *skb, struct genl_info *info)
443{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100444 struct devlink *devlink;
445
446 devlink = devlink_get_from_info(info);
447 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
448 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100449 mutex_unlock(&devlink_mutex);
450}
451
Johannes Berg489111e2016-10-24 14:40:03 +0200452static struct genl_family devlink_nl_family;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100453
454enum devlink_multicast_groups {
455 DEVLINK_MCGRP_CONFIG,
456};
457
458static const struct genl_multicast_group devlink_nl_mcgrps[] = {
459 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
460};
461
462static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
463{
464 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
465 return -EMSGSIZE;
466 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
467 return -EMSGSIZE;
468 return 0;
469}
470
471static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
472 enum devlink_command cmd, u32 portid,
473 u32 seq, int flags)
474{
475 void *hdr;
476
477 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
478 if (!hdr)
479 return -EMSGSIZE;
480
481 if (devlink_nl_put_handle(msg, devlink))
482 goto nla_put_failure;
483
484 genlmsg_end(msg, hdr);
485 return 0;
486
487nla_put_failure:
488 genlmsg_cancel(msg, hdr);
489 return -EMSGSIZE;
490}
491
492static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
493{
494 struct sk_buff *msg;
495 int err;
496
497 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
498
499 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
500 if (!msg)
501 return;
502
503 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
504 if (err) {
505 nlmsg_free(msg);
506 return;
507 }
508
509 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
510 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
511}
512
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200513static int devlink_nl_port_attrs_put(struct sk_buff *msg,
514 struct devlink_port *devlink_port)
515{
516 struct devlink_port_attrs *attrs = &devlink_port->attrs;
517
518 if (!attrs->set)
519 return 0;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200520 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
521 return -EMSGSIZE;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200522 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER, attrs->port_number))
523 return -EMSGSIZE;
524 if (!attrs->split)
525 return 0;
526 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP, attrs->port_number))
527 return -EMSGSIZE;
528 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
529 attrs->split_subport_number))
530 return -EMSGSIZE;
531 return 0;
532}
533
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100534static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
535 struct devlink_port *devlink_port,
536 enum devlink_command cmd, u32 portid,
537 u32 seq, int flags)
538{
539 void *hdr;
540
541 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
542 if (!hdr)
543 return -EMSGSIZE;
544
545 if (devlink_nl_put_handle(msg, devlink))
546 goto nla_put_failure;
547 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
548 goto nla_put_failure;
Jiri Pirkob8f97552019-03-24 11:14:37 +0100549
550 spin_lock(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100551 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100552 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100553 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
554 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
555 devlink_port->desired_type))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100556 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100557 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
558 struct net_device *netdev = devlink_port->type_dev;
559
560 if (netdev &&
561 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
562 netdev->ifindex) ||
563 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
564 netdev->name)))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100565 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100566 }
567 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
568 struct ib_device *ibdev = devlink_port->type_dev;
569
570 if (ibdev &&
571 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
572 ibdev->name))
Jiri Pirkob8f97552019-03-24 11:14:37 +0100573 goto nla_put_failure_type_locked;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100574 }
Jiri Pirkob8f97552019-03-24 11:14:37 +0100575 spin_unlock(&devlink_port->type_lock);
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200576 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100577 goto nla_put_failure;
578
579 genlmsg_end(msg, hdr);
580 return 0;
581
Jiri Pirkob8f97552019-03-24 11:14:37 +0100582nla_put_failure_type_locked:
583 spin_unlock(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100584nla_put_failure:
585 genlmsg_cancel(msg, hdr);
586 return -EMSGSIZE;
587}
588
589static void devlink_port_notify(struct devlink_port *devlink_port,
590 enum devlink_command cmd)
591{
592 struct devlink *devlink = devlink_port->devlink;
593 struct sk_buff *msg;
594 int err;
595
596 if (!devlink_port->registered)
597 return;
598
599 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
600
601 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
602 if (!msg)
603 return;
604
605 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
606 if (err) {
607 nlmsg_free(msg);
608 return;
609 }
610
611 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
612 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
613}
614
615static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
616{
617 struct devlink *devlink = info->user_ptr[0];
618 struct sk_buff *msg;
619 int err;
620
621 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
622 if (!msg)
623 return -ENOMEM;
624
625 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
626 info->snd_portid, info->snd_seq, 0);
627 if (err) {
628 nlmsg_free(msg);
629 return err;
630 }
631
632 return genlmsg_reply(msg, info);
633}
634
635static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
636 struct netlink_callback *cb)
637{
638 struct devlink *devlink;
639 int start = cb->args[0];
640 int idx = 0;
641 int err;
642
643 mutex_lock(&devlink_mutex);
644 list_for_each_entry(devlink, &devlink_list, list) {
645 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
646 continue;
647 if (idx < start) {
648 idx++;
649 continue;
650 }
651 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
652 NETLINK_CB(cb->skb).portid,
653 cb->nlh->nlmsg_seq, NLM_F_MULTI);
654 if (err)
655 goto out;
656 idx++;
657 }
658out:
659 mutex_unlock(&devlink_mutex);
660
661 cb->args[0] = idx;
662 return msg->len;
663}
664
665static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
666 struct genl_info *info)
667{
Jiri Pirko1fc2257e2016-04-08 19:12:48 +0200668 struct devlink_port *devlink_port = info->user_ptr[0];
669 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100670 struct sk_buff *msg;
671 int err;
672
673 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
674 if (!msg)
675 return -ENOMEM;
676
677 err = devlink_nl_port_fill(msg, devlink, devlink_port,
678 DEVLINK_CMD_PORT_NEW,
679 info->snd_portid, info->snd_seq, 0);
680 if (err) {
681 nlmsg_free(msg);
682 return err;
683 }
684
685 return genlmsg_reply(msg, info);
686}
687
688static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
689 struct netlink_callback *cb)
690{
691 struct devlink *devlink;
692 struct devlink_port *devlink_port;
693 int start = cb->args[0];
694 int idx = 0;
695 int err;
696
697 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100698 list_for_each_entry(devlink, &devlink_list, list) {
699 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
700 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100701 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100702 list_for_each_entry(devlink_port, &devlink->port_list, list) {
703 if (idx < start) {
704 idx++;
705 continue;
706 }
707 err = devlink_nl_port_fill(msg, devlink, devlink_port,
708 DEVLINK_CMD_NEW,
709 NETLINK_CB(cb->skb).portid,
710 cb->nlh->nlmsg_seq,
711 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100712 if (err) {
713 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100714 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100715 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100716 idx++;
717 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100718 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100719 }
720out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100721 mutex_unlock(&devlink_mutex);
722
723 cb->args[0] = idx;
724 return msg->len;
725}
726
727static int devlink_port_type_set(struct devlink *devlink,
728 struct devlink_port *devlink_port,
729 enum devlink_port_type port_type)
730
731{
732 int err;
733
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800734 if (devlink->ops->port_type_set) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100735 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
736 return -EINVAL;
Elad Raz6edf1012016-10-23 17:43:05 +0200737 if (port_type == devlink_port->type)
738 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100739 err = devlink->ops->port_type_set(devlink_port, port_type);
740 if (err)
741 return err;
742 devlink_port->desired_type = port_type;
743 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
744 return 0;
745 }
746 return -EOPNOTSUPP;
747}
748
749static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
750 struct genl_info *info)
751{
Jiri Pirko1fc2257e2016-04-08 19:12:48 +0200752 struct devlink_port *devlink_port = info->user_ptr[0];
753 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100754 int err;
755
756 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
757 enum devlink_port_type port_type;
758
759 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
760 err = devlink_port_type_set(devlink, devlink_port, port_type);
761 if (err)
762 return err;
763 }
764 return 0;
765}
766
David Ahernac0fc8a2018-06-05 08:14:09 -0700767static int devlink_port_split(struct devlink *devlink, u32 port_index,
768 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100769
770{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800771 if (devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -0700772 return devlink->ops->port_split(devlink, port_index, count,
773 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100774 return -EOPNOTSUPP;
775}
776
777static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
778 struct genl_info *info)
779{
780 struct devlink *devlink = info->user_ptr[0];
781 u32 port_index;
782 u32 count;
783
784 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
785 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
786 return -EINVAL;
787
788 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
789 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700790 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100791}
792
David Ahernac0fc8a2018-06-05 08:14:09 -0700793static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
794 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100795
796{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800797 if (devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -0700798 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100799 return -EOPNOTSUPP;
800}
801
802static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
803 struct genl_info *info)
804{
805 struct devlink *devlink = info->user_ptr[0];
806 u32 port_index;
807
808 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
809 return -EINVAL;
810
811 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700812 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100813}
814
Jiri Pirkobf797472016-04-14 18:19:13 +0200815static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
816 struct devlink_sb *devlink_sb,
817 enum devlink_command cmd, u32 portid,
818 u32 seq, int flags)
819{
820 void *hdr;
821
822 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
823 if (!hdr)
824 return -EMSGSIZE;
825
826 if (devlink_nl_put_handle(msg, devlink))
827 goto nla_put_failure;
828 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
829 goto nla_put_failure;
830 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
831 goto nla_put_failure;
832 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
833 devlink_sb->ingress_pools_count))
834 goto nla_put_failure;
835 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
836 devlink_sb->egress_pools_count))
837 goto nla_put_failure;
838 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
839 devlink_sb->ingress_tc_count))
840 goto nla_put_failure;
841 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
842 devlink_sb->egress_tc_count))
843 goto nla_put_failure;
844
845 genlmsg_end(msg, hdr);
846 return 0;
847
848nla_put_failure:
849 genlmsg_cancel(msg, hdr);
850 return -EMSGSIZE;
851}
852
853static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
854 struct genl_info *info)
855{
856 struct devlink *devlink = info->user_ptr[0];
857 struct devlink_sb *devlink_sb = info->user_ptr[1];
858 struct sk_buff *msg;
859 int err;
860
861 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
862 if (!msg)
863 return -ENOMEM;
864
865 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
866 DEVLINK_CMD_SB_NEW,
867 info->snd_portid, info->snd_seq, 0);
868 if (err) {
869 nlmsg_free(msg);
870 return err;
871 }
872
873 return genlmsg_reply(msg, info);
874}
875
876static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
877 struct netlink_callback *cb)
878{
879 struct devlink *devlink;
880 struct devlink_sb *devlink_sb;
881 int start = cb->args[0];
882 int idx = 0;
883 int err;
884
885 mutex_lock(&devlink_mutex);
886 list_for_each_entry(devlink, &devlink_list, list) {
887 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
888 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100889 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200890 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
891 if (idx < start) {
892 idx++;
893 continue;
894 }
895 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
896 DEVLINK_CMD_SB_NEW,
897 NETLINK_CB(cb->skb).portid,
898 cb->nlh->nlmsg_seq,
899 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100900 if (err) {
901 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200902 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100903 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200904 idx++;
905 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100906 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200907 }
908out:
909 mutex_unlock(&devlink_mutex);
910
911 cb->args[0] = idx;
912 return msg->len;
913}
914
915static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
916 struct devlink_sb *devlink_sb,
917 u16 pool_index, enum devlink_command cmd,
918 u32 portid, u32 seq, int flags)
919{
920 struct devlink_sb_pool_info pool_info;
921 void *hdr;
922 int err;
923
924 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
925 pool_index, &pool_info);
926 if (err)
927 return err;
928
929 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
930 if (!hdr)
931 return -EMSGSIZE;
932
933 if (devlink_nl_put_handle(msg, devlink))
934 goto nla_put_failure;
935 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
936 goto nla_put_failure;
937 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
938 goto nla_put_failure;
939 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
940 goto nla_put_failure;
941 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
942 goto nla_put_failure;
943 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
944 pool_info.threshold_type))
945 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -0800946 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
947 pool_info.cell_size))
948 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +0200949
950 genlmsg_end(msg, hdr);
951 return 0;
952
953nla_put_failure:
954 genlmsg_cancel(msg, hdr);
955 return -EMSGSIZE;
956}
957
958static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
959 struct genl_info *info)
960{
961 struct devlink *devlink = info->user_ptr[0];
962 struct devlink_sb *devlink_sb = info->user_ptr[1];
963 struct sk_buff *msg;
964 u16 pool_index;
965 int err;
966
967 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
968 &pool_index);
969 if (err)
970 return err;
971
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -0800972 if (!devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +0200973 return -EOPNOTSUPP;
974
975 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
976 if (!msg)
977 return -ENOMEM;
978
979 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
980 DEVLINK_CMD_SB_POOL_NEW,
981 info->snd_portid, info->snd_seq, 0);
982 if (err) {
983 nlmsg_free(msg);
984 return err;
985 }
986
987 return genlmsg_reply(msg, info);
988}
989
990static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
991 struct devlink *devlink,
992 struct devlink_sb *devlink_sb,
993 u32 portid, u32 seq)
994{
995 u16 pool_count = devlink_sb_pool_count(devlink_sb);
996 u16 pool_index;
997 int err;
998
999 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1000 if (*p_idx < start) {
1001 (*p_idx)++;
1002 continue;
1003 }
1004 err = devlink_nl_sb_pool_fill(msg, devlink,
1005 devlink_sb,
1006 pool_index,
1007 DEVLINK_CMD_SB_POOL_NEW,
1008 portid, seq, NLM_F_MULTI);
1009 if (err)
1010 return err;
1011 (*p_idx)++;
1012 }
1013 return 0;
1014}
1015
1016static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1017 struct netlink_callback *cb)
1018{
1019 struct devlink *devlink;
1020 struct devlink_sb *devlink_sb;
1021 int start = cb->args[0];
1022 int idx = 0;
1023 int err;
1024
1025 mutex_lock(&devlink_mutex);
1026 list_for_each_entry(devlink, &devlink_list, list) {
1027 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001028 !devlink->ops->sb_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001029 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001030 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001031 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1032 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1033 devlink_sb,
1034 NETLINK_CB(cb->skb).portid,
1035 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001036 if (err && err != -EOPNOTSUPP) {
1037 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001038 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001039 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001040 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001041 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001042 }
1043out:
1044 mutex_unlock(&devlink_mutex);
1045
1046 cb->args[0] = idx;
1047 return msg->len;
1048}
1049
1050static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1051 u16 pool_index, u32 size,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001052 enum devlink_sb_threshold_type threshold_type,
1053 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001054
1055{
1056 const struct devlink_ops *ops = devlink->ops;
1057
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001058 if (ops->sb_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001059 return ops->sb_pool_set(devlink, sb_index, pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001060 size, threshold_type, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001061 return -EOPNOTSUPP;
1062}
1063
1064static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1065 struct genl_info *info)
1066{
1067 struct devlink *devlink = info->user_ptr[0];
1068 struct devlink_sb *devlink_sb = info->user_ptr[1];
1069 enum devlink_sb_threshold_type threshold_type;
1070 u16 pool_index;
1071 u32 size;
1072 int err;
1073
1074 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1075 &pool_index);
1076 if (err)
1077 return err;
1078
1079 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1080 if (err)
1081 return err;
1082
1083 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1084 return -EINVAL;
1085
1086 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1087 return devlink_sb_pool_set(devlink, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001088 pool_index, size, threshold_type,
1089 info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001090}
1091
1092static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1093 struct devlink *devlink,
1094 struct devlink_port *devlink_port,
1095 struct devlink_sb *devlink_sb,
1096 u16 pool_index,
1097 enum devlink_command cmd,
1098 u32 portid, u32 seq, int flags)
1099{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001100 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001101 u32 threshold;
1102 void *hdr;
1103 int err;
1104
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001105 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1106 pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001107 if (err)
1108 return err;
1109
1110 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1111 if (!hdr)
1112 return -EMSGSIZE;
1113
1114 if (devlink_nl_put_handle(msg, devlink))
1115 goto nla_put_failure;
1116 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1117 goto nla_put_failure;
1118 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1119 goto nla_put_failure;
1120 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1121 goto nla_put_failure;
1122 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1123 goto nla_put_failure;
1124
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001125 if (ops->sb_occ_port_pool_get) {
1126 u32 cur;
1127 u32 max;
1128
1129 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1130 pool_index, &cur, &max);
1131 if (err && err != -EOPNOTSUPP)
1132 return err;
1133 if (!err) {
1134 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1135 goto nla_put_failure;
1136 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1137 goto nla_put_failure;
1138 }
1139 }
1140
Jiri Pirkobf797472016-04-14 18:19:13 +02001141 genlmsg_end(msg, hdr);
1142 return 0;
1143
1144nla_put_failure:
1145 genlmsg_cancel(msg, hdr);
1146 return -EMSGSIZE;
1147}
1148
1149static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1150 struct genl_info *info)
1151{
1152 struct devlink_port *devlink_port = info->user_ptr[0];
1153 struct devlink *devlink = devlink_port->devlink;
1154 struct devlink_sb *devlink_sb = info->user_ptr[1];
1155 struct sk_buff *msg;
1156 u16 pool_index;
1157 int err;
1158
1159 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1160 &pool_index);
1161 if (err)
1162 return err;
1163
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001164 if (!devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001165 return -EOPNOTSUPP;
1166
1167 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1168 if (!msg)
1169 return -ENOMEM;
1170
1171 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1172 devlink_sb, pool_index,
1173 DEVLINK_CMD_SB_PORT_POOL_NEW,
1174 info->snd_portid, info->snd_seq, 0);
1175 if (err) {
1176 nlmsg_free(msg);
1177 return err;
1178 }
1179
1180 return genlmsg_reply(msg, info);
1181}
1182
1183static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1184 struct devlink *devlink,
1185 struct devlink_sb *devlink_sb,
1186 u32 portid, u32 seq)
1187{
1188 struct devlink_port *devlink_port;
1189 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1190 u16 pool_index;
1191 int err;
1192
1193 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1194 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1195 if (*p_idx < start) {
1196 (*p_idx)++;
1197 continue;
1198 }
1199 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1200 devlink_port,
1201 devlink_sb,
1202 pool_index,
1203 DEVLINK_CMD_SB_PORT_POOL_NEW,
1204 portid, seq,
1205 NLM_F_MULTI);
1206 if (err)
1207 return err;
1208 (*p_idx)++;
1209 }
1210 }
1211 return 0;
1212}
1213
1214static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1215 struct netlink_callback *cb)
1216{
1217 struct devlink *devlink;
1218 struct devlink_sb *devlink_sb;
1219 int start = cb->args[0];
1220 int idx = 0;
1221 int err;
1222
1223 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001224 list_for_each_entry(devlink, &devlink_list, list) {
1225 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001226 !devlink->ops->sb_port_pool_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001227 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001228 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001229 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1230 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1231 devlink, devlink_sb,
1232 NETLINK_CB(cb->skb).portid,
1233 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001234 if (err && err != -EOPNOTSUPP) {
1235 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001236 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001237 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001238 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001239 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001240 }
1241out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001242 mutex_unlock(&devlink_mutex);
1243
1244 cb->args[0] = idx;
1245 return msg->len;
1246}
1247
1248static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1249 unsigned int sb_index, u16 pool_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001250 u32 threshold,
1251 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001252
1253{
1254 const struct devlink_ops *ops = devlink_port->devlink->ops;
1255
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001256 if (ops->sb_port_pool_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001257 return ops->sb_port_pool_set(devlink_port, sb_index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001258 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001259 return -EOPNOTSUPP;
1260}
1261
1262static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1263 struct genl_info *info)
1264{
1265 struct devlink_port *devlink_port = info->user_ptr[0];
1266 struct devlink_sb *devlink_sb = info->user_ptr[1];
1267 u16 pool_index;
1268 u32 threshold;
1269 int err;
1270
1271 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1272 &pool_index);
1273 if (err)
1274 return err;
1275
1276 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1277 return -EINVAL;
1278
1279 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1280 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001281 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001282}
1283
1284static int
1285devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1286 struct devlink_port *devlink_port,
1287 struct devlink_sb *devlink_sb, u16 tc_index,
1288 enum devlink_sb_pool_type pool_type,
1289 enum devlink_command cmd,
1290 u32 portid, u32 seq, int flags)
1291{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001292 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001293 u16 pool_index;
1294 u32 threshold;
1295 void *hdr;
1296 int err;
1297
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001298 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1299 tc_index, pool_type,
1300 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001301 if (err)
1302 return err;
1303
1304 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1305 if (!hdr)
1306 return -EMSGSIZE;
1307
1308 if (devlink_nl_put_handle(msg, devlink))
1309 goto nla_put_failure;
1310 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1311 goto nla_put_failure;
1312 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1313 goto nla_put_failure;
1314 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1315 goto nla_put_failure;
1316 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1317 goto nla_put_failure;
1318 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1319 goto nla_put_failure;
1320 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1321 goto nla_put_failure;
1322
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001323 if (ops->sb_occ_tc_port_bind_get) {
1324 u32 cur;
1325 u32 max;
1326
1327 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1328 devlink_sb->index,
1329 tc_index, pool_type,
1330 &cur, &max);
1331 if (err && err != -EOPNOTSUPP)
1332 return err;
1333 if (!err) {
1334 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1335 goto nla_put_failure;
1336 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1337 goto nla_put_failure;
1338 }
1339 }
1340
Jiri Pirkobf797472016-04-14 18:19:13 +02001341 genlmsg_end(msg, hdr);
1342 return 0;
1343
1344nla_put_failure:
1345 genlmsg_cancel(msg, hdr);
1346 return -EMSGSIZE;
1347}
1348
1349static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1350 struct genl_info *info)
1351{
1352 struct devlink_port *devlink_port = info->user_ptr[0];
1353 struct devlink *devlink = devlink_port->devlink;
1354 struct devlink_sb *devlink_sb = info->user_ptr[1];
1355 struct sk_buff *msg;
1356 enum devlink_sb_pool_type pool_type;
1357 u16 tc_index;
1358 int err;
1359
1360 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1361 if (err)
1362 return err;
1363
1364 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1365 pool_type, &tc_index);
1366 if (err)
1367 return err;
1368
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001369 if (!devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001370 return -EOPNOTSUPP;
1371
1372 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1373 if (!msg)
1374 return -ENOMEM;
1375
1376 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1377 devlink_sb, tc_index, pool_type,
1378 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1379 info->snd_portid,
1380 info->snd_seq, 0);
1381 if (err) {
1382 nlmsg_free(msg);
1383 return err;
1384 }
1385
1386 return genlmsg_reply(msg, info);
1387}
1388
1389static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1390 int start, int *p_idx,
1391 struct devlink *devlink,
1392 struct devlink_sb *devlink_sb,
1393 u32 portid, u32 seq)
1394{
1395 struct devlink_port *devlink_port;
1396 u16 tc_index;
1397 int err;
1398
1399 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1400 for (tc_index = 0;
1401 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1402 if (*p_idx < start) {
1403 (*p_idx)++;
1404 continue;
1405 }
1406 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1407 devlink_port,
1408 devlink_sb,
1409 tc_index,
1410 DEVLINK_SB_POOL_TYPE_INGRESS,
1411 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1412 portid, seq,
1413 NLM_F_MULTI);
1414 if (err)
1415 return err;
1416 (*p_idx)++;
1417 }
1418 for (tc_index = 0;
1419 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1420 if (*p_idx < start) {
1421 (*p_idx)++;
1422 continue;
1423 }
1424 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1425 devlink_port,
1426 devlink_sb,
1427 tc_index,
1428 DEVLINK_SB_POOL_TYPE_EGRESS,
1429 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1430 portid, seq,
1431 NLM_F_MULTI);
1432 if (err)
1433 return err;
1434 (*p_idx)++;
1435 }
1436 }
1437 return 0;
1438}
1439
1440static int
1441devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1442 struct netlink_callback *cb)
1443{
1444 struct devlink *devlink;
1445 struct devlink_sb *devlink_sb;
1446 int start = cb->args[0];
1447 int idx = 0;
1448 int err;
1449
1450 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001451 list_for_each_entry(devlink, &devlink_list, list) {
1452 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001453 !devlink->ops->sb_tc_pool_bind_get)
Jiri Pirkobf797472016-04-14 18:19:13 +02001454 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001455
1456 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001457 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1458 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1459 devlink,
1460 devlink_sb,
1461 NETLINK_CB(cb->skb).portid,
1462 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001463 if (err && err != -EOPNOTSUPP) {
1464 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001465 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001466 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001467 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001468 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001469 }
1470out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001471 mutex_unlock(&devlink_mutex);
1472
1473 cb->args[0] = idx;
1474 return msg->len;
1475}
1476
1477static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1478 unsigned int sb_index, u16 tc_index,
1479 enum devlink_sb_pool_type pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001480 u16 pool_index, u32 threshold,
1481 struct netlink_ext_ack *extack)
Jiri Pirkobf797472016-04-14 18:19:13 +02001482
1483{
1484 const struct devlink_ops *ops = devlink_port->devlink->ops;
1485
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001486 if (ops->sb_tc_pool_bind_set)
Jiri Pirkobf797472016-04-14 18:19:13 +02001487 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1488 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001489 pool_index, threshold, extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001490 return -EOPNOTSUPP;
1491}
1492
1493static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1494 struct genl_info *info)
1495{
1496 struct devlink_port *devlink_port = info->user_ptr[0];
1497 struct devlink_sb *devlink_sb = info->user_ptr[1];
1498 enum devlink_sb_pool_type pool_type;
1499 u16 tc_index;
1500 u16 pool_index;
1501 u32 threshold;
1502 int err;
1503
1504 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1505 if (err)
1506 return err;
1507
1508 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1509 pool_type, &tc_index);
1510 if (err)
1511 return err;
1512
1513 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1514 &pool_index);
1515 if (err)
1516 return err;
1517
1518 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1519 return -EINVAL;
1520
1521 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1522 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1523 tc_index, pool_type,
Ido Schimmelf2ad1a52019-04-22 12:08:39 +00001524 pool_index, threshold, info->extack);
Jiri Pirkobf797472016-04-14 18:19:13 +02001525}
1526
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001527static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1528 struct genl_info *info)
1529{
1530 struct devlink *devlink = info->user_ptr[0];
1531 struct devlink_sb *devlink_sb = info->user_ptr[1];
1532 const struct devlink_ops *ops = devlink->ops;
1533
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001534 if (ops->sb_occ_snapshot)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001535 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1536 return -EOPNOTSUPP;
1537}
1538
1539static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1540 struct genl_info *info)
1541{
1542 struct devlink *devlink = info->user_ptr[0];
1543 struct devlink_sb *devlink_sb = info->user_ptr[1];
1544 const struct devlink_ops *ops = devlink->ops;
1545
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08001546 if (ops->sb_occ_max_clear)
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001547 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1548 return -EOPNOTSUPP;
1549}
1550
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001551static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1552 enum devlink_command cmd, u32 portid,
1553 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001554{
Roi Dayan59bfde02016-11-22 23:09:57 +02001555 const struct devlink_ops *ops = devlink->ops;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001556 u8 inline_mode, encap_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001557 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001558 int err = 0;
1559 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001560
1561 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1562 if (!hdr)
1563 return -EMSGSIZE;
1564
Roi Dayan59bfde02016-11-22 23:09:57 +02001565 err = devlink_nl_put_handle(msg, devlink);
1566 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001567 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001568
Jiri Pirko4456f612017-02-09 15:54:36 +01001569 if (ops->eswitch_mode_get) {
1570 err = ops->eswitch_mode_get(devlink, &mode);
1571 if (err)
1572 goto nla_put_failure;
1573 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1574 if (err)
1575 goto nla_put_failure;
1576 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001577
1578 if (ops->eswitch_inline_mode_get) {
1579 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1580 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001581 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001582 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1583 inline_mode);
1584 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001585 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001586 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001587
Roi Dayanf43e9b02016-09-25 13:52:44 +03001588 if (ops->eswitch_encap_mode_get) {
1589 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1590 if (err)
1591 goto nla_put_failure;
1592 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1593 if (err)
1594 goto nla_put_failure;
1595 }
1596
Or Gerlitz08f4b592016-07-01 14:51:01 +03001597 genlmsg_end(msg, hdr);
1598 return 0;
1599
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001600nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001601 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001602 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001603}
1604
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001605static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1606 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001607{
1608 struct devlink *devlink = info->user_ptr[0];
Or Gerlitz08f4b592016-07-01 14:51:01 +03001609 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001610 int err;
1611
Or Gerlitz08f4b592016-07-01 14:51:01 +03001612 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1613 if (!msg)
1614 return -ENOMEM;
1615
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001616 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1617 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001618
1619 if (err) {
1620 nlmsg_free(msg);
1621 return err;
1622 }
1623
1624 return genlmsg_reply(msg, info);
1625}
1626
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001627static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1628 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001629{
1630 struct devlink *devlink = info->user_ptr[0];
1631 const struct devlink_ops *ops = devlink->ops;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001632 u8 inline_mode, encap_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001633 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001634 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001635
Roi Dayan59bfde02016-11-22 23:09:57 +02001636 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1637 if (!ops->eswitch_mode_set)
1638 return -EOPNOTSUPP;
1639 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001640 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001641 if (err)
1642 return err;
1643 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001644
Roi Dayan59bfde02016-11-22 23:09:57 +02001645 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1646 if (!ops->eswitch_inline_mode_set)
1647 return -EOPNOTSUPP;
1648 inline_mode = nla_get_u8(
1649 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001650 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1651 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001652 if (err)
1653 return err;
1654 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03001655
1656 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1657 if (!ops->eswitch_encap_mode_set)
1658 return -EOPNOTSUPP;
1659 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001660 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1661 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03001662 if (err)
1663 return err;
1664 }
1665
Roi Dayan59bfde02016-11-22 23:09:57 +02001666 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001667}
1668
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001669int devlink_dpipe_match_put(struct sk_buff *skb,
1670 struct devlink_dpipe_match *match)
1671{
1672 struct devlink_dpipe_header *header = match->header;
1673 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1674 struct nlattr *match_attr;
1675
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001676 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001677 if (!match_attr)
1678 return -EMSGSIZE;
1679
1680 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1681 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1682 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1683 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1684 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1685 goto nla_put_failure;
1686
1687 nla_nest_end(skb, match_attr);
1688 return 0;
1689
1690nla_put_failure:
1691 nla_nest_cancel(skb, match_attr);
1692 return -EMSGSIZE;
1693}
1694EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1695
1696static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1697 struct sk_buff *skb)
1698{
1699 struct nlattr *matches_attr;
1700
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001701 matches_attr = nla_nest_start_noflag(skb,
1702 DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001703 if (!matches_attr)
1704 return -EMSGSIZE;
1705
1706 if (table->table_ops->matches_dump(table->priv, skb))
1707 goto nla_put_failure;
1708
1709 nla_nest_end(skb, matches_attr);
1710 return 0;
1711
1712nla_put_failure:
1713 nla_nest_cancel(skb, matches_attr);
1714 return -EMSGSIZE;
1715}
1716
1717int devlink_dpipe_action_put(struct sk_buff *skb,
1718 struct devlink_dpipe_action *action)
1719{
1720 struct devlink_dpipe_header *header = action->header;
1721 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1722 struct nlattr *action_attr;
1723
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001724 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001725 if (!action_attr)
1726 return -EMSGSIZE;
1727
1728 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1729 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1730 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1731 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1732 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1733 goto nla_put_failure;
1734
1735 nla_nest_end(skb, action_attr);
1736 return 0;
1737
1738nla_put_failure:
1739 nla_nest_cancel(skb, action_attr);
1740 return -EMSGSIZE;
1741}
1742EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1743
1744static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1745 struct sk_buff *skb)
1746{
1747 struct nlattr *actions_attr;
1748
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001749 actions_attr = nla_nest_start_noflag(skb,
1750 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001751 if (!actions_attr)
1752 return -EMSGSIZE;
1753
1754 if (table->table_ops->actions_dump(table->priv, skb))
1755 goto nla_put_failure;
1756
1757 nla_nest_end(skb, actions_attr);
1758 return 0;
1759
1760nla_put_failure:
1761 nla_nest_cancel(skb, actions_attr);
1762 return -EMSGSIZE;
1763}
1764
1765static int devlink_dpipe_table_put(struct sk_buff *skb,
1766 struct devlink_dpipe_table *table)
1767{
1768 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001769 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001770
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001771 table_size = table->table_ops->size_get(table->priv);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001772 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001773 if (!table_attr)
1774 return -EMSGSIZE;
1775
1776 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001777 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001778 DEVLINK_ATTR_PAD))
1779 goto nla_put_failure;
1780 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1781 table->counters_enabled))
1782 goto nla_put_failure;
1783
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001784 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02001785 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1786 table->resource_id, DEVLINK_ATTR_PAD) ||
1787 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1788 table->resource_units, DEVLINK_ATTR_PAD))
1789 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001790 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001791 if (devlink_dpipe_matches_put(table, skb))
1792 goto nla_put_failure;
1793
1794 if (devlink_dpipe_actions_put(table, skb))
1795 goto nla_put_failure;
1796
1797 nla_nest_end(skb, table_attr);
1798 return 0;
1799
1800nla_put_failure:
1801 nla_nest_cancel(skb, table_attr);
1802 return -EMSGSIZE;
1803}
1804
1805static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1806 struct genl_info *info)
1807{
1808 int err;
1809
1810 if (*pskb) {
1811 err = genlmsg_reply(*pskb, info);
1812 if (err)
1813 return err;
1814 }
1815 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1816 if (!*pskb)
1817 return -ENOMEM;
1818 return 0;
1819}
1820
1821static int devlink_dpipe_tables_fill(struct genl_info *info,
1822 enum devlink_command cmd, int flags,
1823 struct list_head *dpipe_tables,
1824 const char *table_name)
1825{
1826 struct devlink *devlink = info->user_ptr[0];
1827 struct devlink_dpipe_table *table;
1828 struct nlattr *tables_attr;
1829 struct sk_buff *skb = NULL;
1830 struct nlmsghdr *nlh;
1831 bool incomplete;
1832 void *hdr;
1833 int i;
1834 int err;
1835
1836 table = list_first_entry(dpipe_tables,
1837 struct devlink_dpipe_table, list);
1838start_again:
1839 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1840 if (err)
1841 return err;
1842
1843 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1844 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08001845 if (!hdr) {
1846 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001847 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08001848 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001849
1850 if (devlink_nl_put_handle(skb, devlink))
1851 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001852 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001853 if (!tables_attr)
1854 goto nla_put_failure;
1855
1856 i = 0;
1857 incomplete = false;
1858 list_for_each_entry_from(table, dpipe_tables, list) {
1859 if (!table_name) {
1860 err = devlink_dpipe_table_put(skb, table);
1861 if (err) {
1862 if (!i)
1863 goto err_table_put;
1864 incomplete = true;
1865 break;
1866 }
1867 } else {
1868 if (!strcmp(table->name, table_name)) {
1869 err = devlink_dpipe_table_put(skb, table);
1870 if (err)
1871 break;
1872 }
1873 }
1874 i++;
1875 }
1876
1877 nla_nest_end(skb, tables_attr);
1878 genlmsg_end(skb, hdr);
1879 if (incomplete)
1880 goto start_again;
1881
1882send_done:
1883 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1884 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1885 if (!nlh) {
1886 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1887 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02001888 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001889 goto send_done;
1890 }
1891
1892 return genlmsg_reply(skb, info);
1893
1894nla_put_failure:
1895 err = -EMSGSIZE;
1896err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001897 nlmsg_free(skb);
1898 return err;
1899}
1900
1901static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
1902 struct genl_info *info)
1903{
1904 struct devlink *devlink = info->user_ptr[0];
1905 const char *table_name = NULL;
1906
1907 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
1908 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
1909
1910 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
1911 &devlink->dpipe_table_list,
1912 table_name);
1913}
1914
1915static int devlink_dpipe_value_put(struct sk_buff *skb,
1916 struct devlink_dpipe_value *value)
1917{
1918 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
1919 value->value_size, value->value))
1920 return -EMSGSIZE;
1921 if (value->mask)
1922 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
1923 value->value_size, value->mask))
1924 return -EMSGSIZE;
1925 if (value->mapping_valid)
1926 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
1927 value->mapping_value))
1928 return -EMSGSIZE;
1929 return 0;
1930}
1931
1932static int devlink_dpipe_action_value_put(struct sk_buff *skb,
1933 struct devlink_dpipe_value *value)
1934{
1935 if (!value->action)
1936 return -EINVAL;
1937 if (devlink_dpipe_action_put(skb, value->action))
1938 return -EMSGSIZE;
1939 if (devlink_dpipe_value_put(skb, value))
1940 return -EMSGSIZE;
1941 return 0;
1942}
1943
1944static int devlink_dpipe_action_values_put(struct sk_buff *skb,
1945 struct devlink_dpipe_value *values,
1946 unsigned int values_count)
1947{
1948 struct nlattr *action_attr;
1949 int i;
1950 int err;
1951
1952 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001953 action_attr = nla_nest_start_noflag(skb,
1954 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001955 if (!action_attr)
1956 return -EMSGSIZE;
1957 err = devlink_dpipe_action_value_put(skb, &values[i]);
1958 if (err)
1959 goto err_action_value_put;
1960 nla_nest_end(skb, action_attr);
1961 }
1962 return 0;
1963
1964err_action_value_put:
1965 nla_nest_cancel(skb, action_attr);
1966 return err;
1967}
1968
1969static int devlink_dpipe_match_value_put(struct sk_buff *skb,
1970 struct devlink_dpipe_value *value)
1971{
1972 if (!value->match)
1973 return -EINVAL;
1974 if (devlink_dpipe_match_put(skb, value->match))
1975 return -EMSGSIZE;
1976 if (devlink_dpipe_value_put(skb, value))
1977 return -EMSGSIZE;
1978 return 0;
1979}
1980
1981static int devlink_dpipe_match_values_put(struct sk_buff *skb,
1982 struct devlink_dpipe_value *values,
1983 unsigned int values_count)
1984{
1985 struct nlattr *match_attr;
1986 int i;
1987 int err;
1988
1989 for (i = 0; i < values_count; i++) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001990 match_attr = nla_nest_start_noflag(skb,
1991 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001992 if (!match_attr)
1993 return -EMSGSIZE;
1994 err = devlink_dpipe_match_value_put(skb, &values[i]);
1995 if (err)
1996 goto err_match_value_put;
1997 nla_nest_end(skb, match_attr);
1998 }
1999 return 0;
2000
2001err_match_value_put:
2002 nla_nest_cancel(skb, match_attr);
2003 return err;
2004}
2005
2006static int devlink_dpipe_entry_put(struct sk_buff *skb,
2007 struct devlink_dpipe_entry *entry)
2008{
2009 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2010 int err;
2011
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002012 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002013 if (!entry_attr)
2014 return -EMSGSIZE;
2015
2016 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2017 DEVLINK_ATTR_PAD))
2018 goto nla_put_failure;
2019 if (entry->counter_valid)
2020 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2021 entry->counter, DEVLINK_ATTR_PAD))
2022 goto nla_put_failure;
2023
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002024 matches_attr = nla_nest_start_noflag(skb,
2025 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002026 if (!matches_attr)
2027 goto nla_put_failure;
2028
2029 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2030 entry->match_values_count);
2031 if (err) {
2032 nla_nest_cancel(skb, matches_attr);
2033 goto err_match_values_put;
2034 }
2035 nla_nest_end(skb, matches_attr);
2036
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002037 actions_attr = nla_nest_start_noflag(skb,
2038 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002039 if (!actions_attr)
2040 goto nla_put_failure;
2041
2042 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2043 entry->action_values_count);
2044 if (err) {
2045 nla_nest_cancel(skb, actions_attr);
2046 goto err_action_values_put;
2047 }
2048 nla_nest_end(skb, actions_attr);
2049
2050 nla_nest_end(skb, entry_attr);
2051 return 0;
2052
2053nla_put_failure:
2054 err = -EMSGSIZE;
2055err_match_values_put:
2056err_action_values_put:
2057 nla_nest_cancel(skb, entry_attr);
2058 return err;
2059}
2060
2061static struct devlink_dpipe_table *
2062devlink_dpipe_table_find(struct list_head *dpipe_tables,
2063 const char *table_name)
2064{
2065 struct devlink_dpipe_table *table;
2066
2067 list_for_each_entry_rcu(table, dpipe_tables, list) {
2068 if (!strcmp(table->name, table_name))
2069 return table;
2070 }
2071 return NULL;
2072}
2073
2074int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2075{
2076 struct devlink *devlink;
2077 int err;
2078
2079 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2080 dump_ctx->info);
2081 if (err)
2082 return err;
2083
2084 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2085 dump_ctx->info->snd_portid,
2086 dump_ctx->info->snd_seq,
2087 &devlink_nl_family, NLM_F_MULTI,
2088 dump_ctx->cmd);
2089 if (!dump_ctx->hdr)
2090 goto nla_put_failure;
2091
2092 devlink = dump_ctx->info->user_ptr[0];
2093 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2094 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002095 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
2096 DEVLINK_ATTR_DPIPE_ENTRIES);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002097 if (!dump_ctx->nest)
2098 goto nla_put_failure;
2099 return 0;
2100
2101nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002102 nlmsg_free(dump_ctx->skb);
2103 return -EMSGSIZE;
2104}
2105EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2106
2107int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2108 struct devlink_dpipe_entry *entry)
2109{
2110 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2111}
2112EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2113
2114int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2115{
2116 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2117 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2118 return 0;
2119}
2120EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2121
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002122void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2123
2124{
2125 unsigned int value_count, value_index;
2126 struct devlink_dpipe_value *value;
2127
2128 value = entry->action_values;
2129 value_count = entry->action_values_count;
2130 for (value_index = 0; value_index < value_count; value_index++) {
2131 kfree(value[value_index].value);
2132 kfree(value[value_index].mask);
2133 }
2134
2135 value = entry->match_values;
2136 value_count = entry->match_values_count;
2137 for (value_index = 0; value_index < value_count; value_index++) {
2138 kfree(value[value_index].value);
2139 kfree(value[value_index].mask);
2140 }
2141}
2142EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2143
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002144static int devlink_dpipe_entries_fill(struct genl_info *info,
2145 enum devlink_command cmd, int flags,
2146 struct devlink_dpipe_table *table)
2147{
2148 struct devlink_dpipe_dump_ctx dump_ctx;
2149 struct nlmsghdr *nlh;
2150 int err;
2151
2152 dump_ctx.skb = NULL;
2153 dump_ctx.cmd = cmd;
2154 dump_ctx.info = info;
2155
2156 err = table->table_ops->entries_dump(table->priv,
2157 table->counters_enabled,
2158 &dump_ctx);
2159 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002160 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002161
2162send_done:
2163 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2164 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2165 if (!nlh) {
2166 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2167 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002168 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002169 goto send_done;
2170 }
2171 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002172}
2173
2174static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2175 struct genl_info *info)
2176{
2177 struct devlink *devlink = info->user_ptr[0];
2178 struct devlink_dpipe_table *table;
2179 const char *table_name;
2180
2181 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2182 return -EINVAL;
2183
2184 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2185 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2186 table_name);
2187 if (!table)
2188 return -EINVAL;
2189
2190 if (!table->table_ops->entries_dump)
2191 return -EINVAL;
2192
2193 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2194 0, table);
2195}
2196
2197static int devlink_dpipe_fields_put(struct sk_buff *skb,
2198 const struct devlink_dpipe_header *header)
2199{
2200 struct devlink_dpipe_field *field;
2201 struct nlattr *field_attr;
2202 int i;
2203
2204 for (i = 0; i < header->fields_count; i++) {
2205 field = &header->fields[i];
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002206 field_attr = nla_nest_start_noflag(skb,
2207 DEVLINK_ATTR_DPIPE_FIELD);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002208 if (!field_attr)
2209 return -EMSGSIZE;
2210 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2211 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2212 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2213 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2214 goto nla_put_failure;
2215 nla_nest_end(skb, field_attr);
2216 }
2217 return 0;
2218
2219nla_put_failure:
2220 nla_nest_cancel(skb, field_attr);
2221 return -EMSGSIZE;
2222}
2223
2224static int devlink_dpipe_header_put(struct sk_buff *skb,
2225 struct devlink_dpipe_header *header)
2226{
2227 struct nlattr *fields_attr, *header_attr;
2228 int err;
2229
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002230 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002231 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002232 return -EMSGSIZE;
2233
2234 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2235 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2236 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2237 goto nla_put_failure;
2238
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002239 fields_attr = nla_nest_start_noflag(skb,
2240 DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002241 if (!fields_attr)
2242 goto nla_put_failure;
2243
2244 err = devlink_dpipe_fields_put(skb, header);
2245 if (err) {
2246 nla_nest_cancel(skb, fields_attr);
2247 goto nla_put_failure;
2248 }
2249 nla_nest_end(skb, fields_attr);
2250 nla_nest_end(skb, header_attr);
2251 return 0;
2252
2253nla_put_failure:
2254 err = -EMSGSIZE;
2255 nla_nest_cancel(skb, header_attr);
2256 return err;
2257}
2258
2259static int devlink_dpipe_headers_fill(struct genl_info *info,
2260 enum devlink_command cmd, int flags,
2261 struct devlink_dpipe_headers *
2262 dpipe_headers)
2263{
2264 struct devlink *devlink = info->user_ptr[0];
2265 struct nlattr *headers_attr;
2266 struct sk_buff *skb = NULL;
2267 struct nlmsghdr *nlh;
2268 void *hdr;
2269 int i, j;
2270 int err;
2271
2272 i = 0;
2273start_again:
2274 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2275 if (err)
2276 return err;
2277
2278 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2279 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002280 if (!hdr) {
2281 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002282 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002283 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002284
2285 if (devlink_nl_put_handle(skb, devlink))
2286 goto nla_put_failure;
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002287 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002288 if (!headers_attr)
2289 goto nla_put_failure;
2290
2291 j = 0;
2292 for (; i < dpipe_headers->headers_count; i++) {
2293 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2294 if (err) {
2295 if (!j)
2296 goto err_table_put;
2297 break;
2298 }
2299 j++;
2300 }
2301 nla_nest_end(skb, headers_attr);
2302 genlmsg_end(skb, hdr);
2303 if (i != dpipe_headers->headers_count)
2304 goto start_again;
2305
2306send_done:
2307 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2308 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2309 if (!nlh) {
2310 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2311 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002312 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002313 goto send_done;
2314 }
2315 return genlmsg_reply(skb, info);
2316
2317nla_put_failure:
2318 err = -EMSGSIZE;
2319err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002320 nlmsg_free(skb);
2321 return err;
2322}
2323
2324static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2325 struct genl_info *info)
2326{
2327 struct devlink *devlink = info->user_ptr[0];
2328
2329 if (!devlink->dpipe_headers)
2330 return -EOPNOTSUPP;
2331 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2332 0, devlink->dpipe_headers);
2333}
2334
2335static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2336 const char *table_name,
2337 bool enable)
2338{
2339 struct devlink_dpipe_table *table;
2340
2341 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2342 table_name);
2343 if (!table)
2344 return -EINVAL;
2345
2346 if (table->counter_control_extern)
2347 return -EOPNOTSUPP;
2348
2349 if (!(table->counters_enabled ^ enable))
2350 return 0;
2351
2352 table->counters_enabled = enable;
2353 if (table->table_ops->counters_set_update)
2354 table->table_ops->counters_set_update(table->priv, enable);
2355 return 0;
2356}
2357
2358static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2359 struct genl_info *info)
2360{
2361 struct devlink *devlink = info->user_ptr[0];
2362 const char *table_name;
2363 bool counters_enable;
2364
2365 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2366 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2367 return -EINVAL;
2368
2369 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2370 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2371
2372 return devlink_dpipe_table_counters_set(devlink, table_name,
2373 counters_enable);
2374}
2375
Wei Yongjun43dd7512018-01-17 03:27:42 +00002376static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002377devlink_resource_find(struct devlink *devlink,
2378 struct devlink_resource *resource, u64 resource_id)
2379{
2380 struct list_head *resource_list;
2381
2382 if (resource)
2383 resource_list = &resource->resource_list;
2384 else
2385 resource_list = &devlink->resource_list;
2386
2387 list_for_each_entry(resource, resource_list, list) {
2388 struct devlink_resource *child_resource;
2389
2390 if (resource->id == resource_id)
2391 return resource;
2392
2393 child_resource = devlink_resource_find(devlink, resource,
2394 resource_id);
2395 if (child_resource)
2396 return child_resource;
2397 }
2398 return NULL;
2399}
2400
Wei Yongjun43dd7512018-01-17 03:27:42 +00002401static void
2402devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002403{
2404 struct devlink_resource *child_resource;
2405 bool size_valid = true;
2406 u64 parts_size = 0;
2407
2408 if (list_empty(&resource->resource_list))
2409 goto out;
2410
2411 list_for_each_entry(child_resource, &resource->resource_list, list)
2412 parts_size += child_resource->size_new;
2413
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002414 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002415 size_valid = false;
2416out:
2417 resource->size_valid = size_valid;
2418}
2419
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002420static int
2421devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2422 struct netlink_ext_ack *extack)
2423{
2424 u64 reminder;
2425 int err = 0;
2426
David S. Miller0f3e9c92018-03-06 00:53:44 -05002427 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002428 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2429 err = -EINVAL;
2430 }
2431
David S. Miller0f3e9c92018-03-06 00:53:44 -05002432 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002433 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2434 err = -EINVAL;
2435 }
2436
David S. Miller0f3e9c92018-03-06 00:53:44 -05002437 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002438 if (reminder) {
2439 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2440 err = -EINVAL;
2441 }
2442
2443 return err;
2444}
2445
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002446static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2447 struct genl_info *info)
2448{
2449 struct devlink *devlink = info->user_ptr[0];
2450 struct devlink_resource *resource;
2451 u64 resource_id;
2452 u64 size;
2453 int err;
2454
2455 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2456 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2457 return -EINVAL;
2458 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2459
2460 resource = devlink_resource_find(devlink, NULL, resource_id);
2461 if (!resource)
2462 return -EINVAL;
2463
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002464 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002465 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002466 if (err)
2467 return err;
2468
2469 resource->size_new = size;
2470 devlink_resource_validate_children(resource);
2471 if (resource->parent)
2472 devlink_resource_validate_children(resource->parent);
2473 return 0;
2474}
2475
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002476static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002477devlink_resource_size_params_put(struct devlink_resource *resource,
2478 struct sk_buff *skb)
2479{
2480 struct devlink_resource_size_params *size_params;
2481
Jiri Pirko77d27092018-02-28 13:12:09 +01002482 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002483 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2484 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2485 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2486 size_params->size_max, DEVLINK_ATTR_PAD) ||
2487 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2488 size_params->size_min, DEVLINK_ATTR_PAD) ||
2489 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2490 return -EMSGSIZE;
2491 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002492}
2493
Jiri Pirkofc56be42018-04-05 22:13:21 +02002494static int devlink_resource_occ_put(struct devlink_resource *resource,
2495 struct sk_buff *skb)
2496{
2497 if (!resource->occ_get)
2498 return 0;
2499 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2500 resource->occ_get(resource->occ_get_priv),
2501 DEVLINK_ATTR_PAD);
2502}
2503
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002504static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2505 struct devlink_resource *resource)
2506{
2507 struct devlink_resource *child_resource;
2508 struct nlattr *child_resource_attr;
2509 struct nlattr *resource_attr;
2510
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002511 resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002512 if (!resource_attr)
2513 return -EMSGSIZE;
2514
2515 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2516 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2517 DEVLINK_ATTR_PAD) ||
2518 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2519 DEVLINK_ATTR_PAD))
2520 goto nla_put_failure;
2521 if (resource->size != resource->size_new)
2522 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2523 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002524 if (devlink_resource_occ_put(resource, skb))
2525 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002526 if (devlink_resource_size_params_put(resource, skb))
2527 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002528 if (list_empty(&resource->resource_list))
2529 goto out;
2530
2531 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2532 resource->size_valid))
2533 goto nla_put_failure;
2534
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002535 child_resource_attr = nla_nest_start_noflag(skb,
2536 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002537 if (!child_resource_attr)
2538 goto nla_put_failure;
2539
2540 list_for_each_entry(child_resource, &resource->resource_list, list) {
2541 if (devlink_resource_put(devlink, skb, child_resource))
2542 goto resource_put_failure;
2543 }
2544
2545 nla_nest_end(skb, child_resource_attr);
2546out:
2547 nla_nest_end(skb, resource_attr);
2548 return 0;
2549
2550resource_put_failure:
2551 nla_nest_cancel(skb, child_resource_attr);
2552nla_put_failure:
2553 nla_nest_cancel(skb, resource_attr);
2554 return -EMSGSIZE;
2555}
2556
2557static int devlink_resource_fill(struct genl_info *info,
2558 enum devlink_command cmd, int flags)
2559{
2560 struct devlink *devlink = info->user_ptr[0];
2561 struct devlink_resource *resource;
2562 struct nlattr *resources_attr;
2563 struct sk_buff *skb = NULL;
2564 struct nlmsghdr *nlh;
2565 bool incomplete;
2566 void *hdr;
2567 int i;
2568 int err;
2569
2570 resource = list_first_entry(&devlink->resource_list,
2571 struct devlink_resource, list);
2572start_again:
2573 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2574 if (err)
2575 return err;
2576
2577 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2578 &devlink_nl_family, NLM_F_MULTI, cmd);
2579 if (!hdr) {
2580 nlmsg_free(skb);
2581 return -EMSGSIZE;
2582 }
2583
2584 if (devlink_nl_put_handle(skb, devlink))
2585 goto nla_put_failure;
2586
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002587 resources_attr = nla_nest_start_noflag(skb,
2588 DEVLINK_ATTR_RESOURCE_LIST);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002589 if (!resources_attr)
2590 goto nla_put_failure;
2591
2592 incomplete = false;
2593 i = 0;
2594 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2595 err = devlink_resource_put(devlink, skb, resource);
2596 if (err) {
2597 if (!i)
2598 goto err_resource_put;
2599 incomplete = true;
2600 break;
2601 }
2602 i++;
2603 }
2604 nla_nest_end(skb, resources_attr);
2605 genlmsg_end(skb, hdr);
2606 if (incomplete)
2607 goto start_again;
2608send_done:
2609 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2610 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2611 if (!nlh) {
2612 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2613 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002614 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002615 goto send_done;
2616 }
2617 return genlmsg_reply(skb, info);
2618
2619nla_put_failure:
2620 err = -EMSGSIZE;
2621err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002622 nlmsg_free(skb);
2623 return err;
2624}
2625
2626static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2627 struct genl_info *info)
2628{
2629 struct devlink *devlink = info->user_ptr[0];
2630
2631 if (list_empty(&devlink->resource_list))
2632 return -EOPNOTSUPP;
2633
2634 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2635}
2636
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002637static int
2638devlink_resources_validate(struct devlink *devlink,
2639 struct devlink_resource *resource,
2640 struct genl_info *info)
2641{
2642 struct list_head *resource_list;
2643 int err = 0;
2644
2645 if (resource)
2646 resource_list = &resource->resource_list;
2647 else
2648 resource_list = &devlink->resource_list;
2649
2650 list_for_each_entry(resource, resource_list, list) {
2651 if (!resource->size_valid)
2652 return -EINVAL;
2653 err = devlink_resources_validate(devlink, resource, info);
2654 if (err)
2655 return err;
2656 }
2657 return err;
2658}
2659
2660static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2661{
2662 struct devlink *devlink = info->user_ptr[0];
2663 int err;
2664
2665 if (!devlink->ops->reload)
2666 return -EOPNOTSUPP;
2667
2668 err = devlink_resources_validate(devlink, NULL, info);
2669 if (err) {
2670 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2671 return err;
2672 }
David Ahernac0fc8a2018-06-05 08:14:09 -07002673 return devlink->ops->reload(devlink, info->extack);
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002674}
2675
Jakub Kicinski76726cc2019-02-14 13:40:44 -08002676static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
2677 struct genl_info *info)
2678{
2679 struct devlink *devlink = info->user_ptr[0];
2680 const char *file_name, *component;
2681 struct nlattr *nla_component;
2682
2683 if (!devlink->ops->flash_update)
2684 return -EOPNOTSUPP;
2685
2686 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
2687 return -EINVAL;
2688 file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
2689
2690 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
2691 component = nla_component ? nla_data(nla_component) : NULL;
2692
2693 return devlink->ops->flash_update(devlink, file_name, component,
2694 info->extack);
2695}
2696
Moshe Shemesh036467c2018-07-04 14:30:33 +03002697static const struct devlink_param devlink_param_generic[] = {
2698 {
2699 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
2700 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
2701 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
2702 },
2703 {
2704 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
2705 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
2706 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
2707 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03002708 {
2709 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
2710 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
2711 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
2712 },
Alex Veskerf6a698852018-07-12 15:13:17 +03002713 {
2714 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
2715 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
2716 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
2717 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05302718 {
2719 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
2720 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
2721 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
2722 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05302723 {
2724 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
2725 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
2726 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
2727 },
Vasundhara Volam16511782018-10-04 11:13:46 +05302728 {
2729 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
2730 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
2731 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
2732 },
Shalom Toledo846e9802018-12-03 07:58:59 +00002733 {
2734 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
2735 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
2736 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
2737 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03002738};
Moshe Shemesheabaef12018-07-04 14:30:28 +03002739
2740static int devlink_param_generic_verify(const struct devlink_param *param)
2741{
2742 /* verify it match generic parameter by id and name */
2743 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
2744 return -EINVAL;
2745 if (strcmp(param->name, devlink_param_generic[param->id].name))
2746 return -ENOENT;
2747
2748 WARN_ON(param->type != devlink_param_generic[param->id].type);
2749
2750 return 0;
2751}
2752
2753static int devlink_param_driver_verify(const struct devlink_param *param)
2754{
2755 int i;
2756
2757 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
2758 return -EINVAL;
2759 /* verify no such name in generic params */
2760 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
2761 if (!strcmp(param->name, devlink_param_generic[i].name))
2762 return -EEXIST;
2763
2764 return 0;
2765}
2766
2767static struct devlink_param_item *
2768devlink_param_find_by_name(struct list_head *param_list,
2769 const char *param_name)
2770{
2771 struct devlink_param_item *param_item;
2772
2773 list_for_each_entry(param_item, param_list, list)
2774 if (!strcmp(param_item->param->name, param_name))
2775 return param_item;
2776 return NULL;
2777}
2778
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03002779static struct devlink_param_item *
2780devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
2781{
2782 struct devlink_param_item *param_item;
2783
2784 list_for_each_entry(param_item, param_list, list)
2785 if (param_item->param->id == param_id)
2786 return param_item;
2787 return NULL;
2788}
2789
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002790static bool
2791devlink_param_cmode_is_supported(const struct devlink_param *param,
2792 enum devlink_param_cmode cmode)
2793{
2794 return test_bit(cmode, &param->supported_cmodes);
2795}
2796
2797static int devlink_param_get(struct devlink *devlink,
2798 const struct devlink_param *param,
2799 struct devlink_param_gset_ctx *ctx)
2800{
2801 if (!param->get)
2802 return -EOPNOTSUPP;
2803 return param->get(devlink, param->id, ctx);
2804}
2805
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03002806static int devlink_param_set(struct devlink *devlink,
2807 const struct devlink_param *param,
2808 struct devlink_param_gset_ctx *ctx)
2809{
2810 if (!param->set)
2811 return -EOPNOTSUPP;
2812 return param->set(devlink, param->id, ctx);
2813}
2814
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002815static int
2816devlink_param_type_to_nla_type(enum devlink_param_type param_type)
2817{
2818 switch (param_type) {
2819 case DEVLINK_PARAM_TYPE_U8:
2820 return NLA_U8;
2821 case DEVLINK_PARAM_TYPE_U16:
2822 return NLA_U16;
2823 case DEVLINK_PARAM_TYPE_U32:
2824 return NLA_U32;
2825 case DEVLINK_PARAM_TYPE_STRING:
2826 return NLA_STRING;
2827 case DEVLINK_PARAM_TYPE_BOOL:
2828 return NLA_FLAG;
2829 default:
2830 return -EINVAL;
2831 }
2832}
2833
2834static int
2835devlink_nl_param_value_fill_one(struct sk_buff *msg,
2836 enum devlink_param_type type,
2837 enum devlink_param_cmode cmode,
2838 union devlink_param_value val)
2839{
2840 struct nlattr *param_value_attr;
2841
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002842 param_value_attr = nla_nest_start_noflag(msg,
2843 DEVLINK_ATTR_PARAM_VALUE);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002844 if (!param_value_attr)
2845 goto nla_put_failure;
2846
2847 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
2848 goto value_nest_cancel;
2849
2850 switch (type) {
2851 case DEVLINK_PARAM_TYPE_U8:
2852 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
2853 goto value_nest_cancel;
2854 break;
2855 case DEVLINK_PARAM_TYPE_U16:
2856 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
2857 goto value_nest_cancel;
2858 break;
2859 case DEVLINK_PARAM_TYPE_U32:
2860 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
2861 goto value_nest_cancel;
2862 break;
2863 case DEVLINK_PARAM_TYPE_STRING:
2864 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
2865 val.vstr))
2866 goto value_nest_cancel;
2867 break;
2868 case DEVLINK_PARAM_TYPE_BOOL:
2869 if (val.vbool &&
2870 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
2871 goto value_nest_cancel;
2872 break;
2873 }
2874
2875 nla_nest_end(msg, param_value_attr);
2876 return 0;
2877
2878value_nest_cancel:
2879 nla_nest_cancel(msg, param_value_attr);
2880nla_put_failure:
2881 return -EMSGSIZE;
2882}
2883
2884static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302885 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002886 struct devlink_param_item *param_item,
2887 enum devlink_command cmd,
2888 u32 portid, u32 seq, int flags)
2889{
2890 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002891 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002892 const struct devlink_param *param = param_item->param;
2893 struct devlink_param_gset_ctx ctx;
2894 struct nlattr *param_values_list;
2895 struct nlattr *param_attr;
2896 int nla_type;
2897 void *hdr;
2898 int err;
2899 int i;
2900
2901 /* Get value from driver part to driverinit configuration mode */
2902 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
2903 if (!devlink_param_cmode_is_supported(param, i))
2904 continue;
2905 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
2906 if (!param_item->driverinit_value_valid)
2907 return -EOPNOTSUPP;
2908 param_value[i] = param_item->driverinit_value;
2909 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002910 if (!param_item->published)
2911 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002912 ctx.cmode = i;
2913 err = devlink_param_get(devlink, param, &ctx);
2914 if (err)
2915 return err;
2916 param_value[i] = ctx.val;
2917 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002918 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002919 }
2920
2921 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
2922 if (!hdr)
2923 return -EMSGSIZE;
2924
2925 if (devlink_nl_put_handle(msg, devlink))
2926 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302927
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302928 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
2929 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
2930 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302931 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
2932 goto genlmsg_cancel;
2933
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002934 param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002935 if (!param_attr)
2936 goto genlmsg_cancel;
2937 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
2938 goto param_nest_cancel;
2939 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
2940 goto param_nest_cancel;
2941
2942 nla_type = devlink_param_type_to_nla_type(param->type);
2943 if (nla_type < 0)
2944 goto param_nest_cancel;
2945 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
2946 goto param_nest_cancel;
2947
Michal Kubecekae0be8d2019-04-26 11:13:06 +02002948 param_values_list = nla_nest_start_noflag(msg,
2949 DEVLINK_ATTR_PARAM_VALUES_LIST);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002950 if (!param_values_list)
2951 goto param_nest_cancel;
2952
2953 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002954 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002955 continue;
2956 err = devlink_nl_param_value_fill_one(msg, param->type,
2957 i, param_value[i]);
2958 if (err)
2959 goto values_list_nest_cancel;
2960 }
2961
2962 nla_nest_end(msg, param_values_list);
2963 nla_nest_end(msg, param_attr);
2964 genlmsg_end(msg, hdr);
2965 return 0;
2966
2967values_list_nest_cancel:
2968 nla_nest_end(msg, param_values_list);
2969param_nest_cancel:
2970 nla_nest_cancel(msg, param_attr);
2971genlmsg_cancel:
2972 genlmsg_cancel(msg, hdr);
2973 return -EMSGSIZE;
2974}
2975
Moshe Shemeshea601e12018-07-04 14:30:32 +03002976static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302977 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03002978 struct devlink_param_item *param_item,
2979 enum devlink_command cmd)
2980{
2981 struct sk_buff *msg;
2982 int err;
2983
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302984 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
2985 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
2986 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03002987
2988 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2989 if (!msg)
2990 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302991 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
2992 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03002993 if (err) {
2994 nlmsg_free(msg);
2995 return;
2996 }
2997
2998 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
2999 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3000}
3001
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003002static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
3003 struct netlink_callback *cb)
3004{
3005 struct devlink_param_item *param_item;
3006 struct devlink *devlink;
3007 int start = cb->args[0];
3008 int idx = 0;
3009 int err;
3010
3011 mutex_lock(&devlink_mutex);
3012 list_for_each_entry(devlink, &devlink_list, list) {
3013 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3014 continue;
3015 mutex_lock(&devlink->lock);
3016 list_for_each_entry(param_item, &devlink->param_list, list) {
3017 if (idx < start) {
3018 idx++;
3019 continue;
3020 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303021 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003022 DEVLINK_CMD_PARAM_GET,
3023 NETLINK_CB(cb->skb).portid,
3024 cb->nlh->nlmsg_seq,
3025 NLM_F_MULTI);
3026 if (err) {
3027 mutex_unlock(&devlink->lock);
3028 goto out;
3029 }
3030 idx++;
3031 }
3032 mutex_unlock(&devlink->lock);
3033 }
3034out:
3035 mutex_unlock(&devlink_mutex);
3036
3037 cb->args[0] = idx;
3038 return msg->len;
3039}
3040
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003041static int
3042devlink_param_type_get_from_info(struct genl_info *info,
3043 enum devlink_param_type *param_type)
3044{
3045 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3046 return -EINVAL;
3047
3048 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3049 case NLA_U8:
3050 *param_type = DEVLINK_PARAM_TYPE_U8;
3051 break;
3052 case NLA_U16:
3053 *param_type = DEVLINK_PARAM_TYPE_U16;
3054 break;
3055 case NLA_U32:
3056 *param_type = DEVLINK_PARAM_TYPE_U32;
3057 break;
3058 case NLA_STRING:
3059 *param_type = DEVLINK_PARAM_TYPE_STRING;
3060 break;
3061 case NLA_FLAG:
3062 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3063 break;
3064 default:
3065 return -EINVAL;
3066 }
3067
3068 return 0;
3069}
3070
3071static int
3072devlink_param_value_get_from_info(const struct devlink_param *param,
3073 struct genl_info *info,
3074 union devlink_param_value *value)
3075{
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003076 int len;
3077
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003078 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3079 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3080 return -EINVAL;
3081
3082 switch (param->type) {
3083 case DEVLINK_PARAM_TYPE_U8:
3084 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3085 break;
3086 case DEVLINK_PARAM_TYPE_U16:
3087 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3088 break;
3089 case DEVLINK_PARAM_TYPE_U32:
3090 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3091 break;
3092 case DEVLINK_PARAM_TYPE_STRING:
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003093 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3094 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3095 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003096 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003097 return -EINVAL;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003098 strcpy(value->vstr,
3099 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003100 break;
3101 case DEVLINK_PARAM_TYPE_BOOL:
3102 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3103 true : false;
3104 break;
3105 }
3106 return 0;
3107}
3108
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003109static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303110devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003111 struct genl_info *info)
3112{
3113 char *param_name;
3114
3115 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3116 return NULL;
3117
3118 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303119 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003120}
3121
3122static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3123 struct genl_info *info)
3124{
3125 struct devlink *devlink = info->user_ptr[0];
3126 struct devlink_param_item *param_item;
3127 struct sk_buff *msg;
3128 int err;
3129
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303130 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003131 if (!param_item)
3132 return -EINVAL;
3133
3134 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3135 if (!msg)
3136 return -ENOMEM;
3137
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303138 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003139 DEVLINK_CMD_PARAM_GET,
3140 info->snd_portid, info->snd_seq, 0);
3141 if (err) {
3142 nlmsg_free(msg);
3143 return err;
3144 }
3145
3146 return genlmsg_reply(msg, info);
3147}
3148
Vasundhara Volam9c548732019-01-28 18:00:22 +05303149static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303150 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303151 struct list_head *param_list,
3152 struct genl_info *info,
3153 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003154{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003155 enum devlink_param_type param_type;
3156 struct devlink_param_gset_ctx ctx;
3157 enum devlink_param_cmode cmode;
3158 struct devlink_param_item *param_item;
3159 const struct devlink_param *param;
3160 union devlink_param_value value;
3161 int err = 0;
3162
Vasundhara Volam9c548732019-01-28 18:00:22 +05303163 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003164 if (!param_item)
3165 return -EINVAL;
3166 param = param_item->param;
3167 err = devlink_param_type_get_from_info(info, &param_type);
3168 if (err)
3169 return err;
3170 if (param_type != param->type)
3171 return -EINVAL;
3172 err = devlink_param_value_get_from_info(param, info, &value);
3173 if (err)
3174 return err;
3175 if (param->validate) {
3176 err = param->validate(devlink, param->id, value, info->extack);
3177 if (err)
3178 return err;
3179 }
3180
3181 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3182 return -EINVAL;
3183 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3184 if (!devlink_param_cmode_is_supported(param, cmode))
3185 return -EOPNOTSUPP;
3186
3187 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003188 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3189 strcpy(param_item->driverinit_value.vstr, value.vstr);
3190 else
3191 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003192 param_item->driverinit_value_valid = true;
3193 } else {
3194 if (!param->set)
3195 return -EOPNOTSUPP;
3196 ctx.val = value;
3197 ctx.cmode = cmode;
3198 err = devlink_param_set(devlink, param, &ctx);
3199 if (err)
3200 return err;
3201 }
3202
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303203 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003204 return 0;
3205}
3206
Vasundhara Volam9c548732019-01-28 18:00:22 +05303207static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3208 struct genl_info *info)
3209{
3210 struct devlink *devlink = info->user_ptr[0];
3211
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303212 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303213 info, DEVLINK_CMD_PARAM_NEW);
3214}
3215
Moshe Shemesheabaef12018-07-04 14:30:28 +03003216static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303217 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303218 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303219 const struct devlink_param *param,
3220 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003221{
3222 struct devlink_param_item *param_item;
3223
Vasundhara Volam39e61602019-01-28 18:00:20 +05303224 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03003225 return -EEXIST;
3226
3227 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3228 WARN_ON(param->get || param->set);
3229 else
3230 WARN_ON(!param->get || !param->set);
3231
3232 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3233 if (!param_item)
3234 return -ENOMEM;
3235 param_item->param = param;
3236
Vasundhara Volam39e61602019-01-28 18:00:20 +05303237 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303238 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003239 return 0;
3240}
3241
3242static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303243 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303244 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303245 const struct devlink_param *param,
3246 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003247{
3248 struct devlink_param_item *param_item;
3249
Vasundhara Volam39e61602019-01-28 18:00:20 +05303250 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003251 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303252 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003253 list_del(&param_item->list);
3254 kfree(param_item);
3255}
3256
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303257static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3258 struct netlink_callback *cb)
3259{
3260 struct devlink_param_item *param_item;
3261 struct devlink_port *devlink_port;
3262 struct devlink *devlink;
3263 int start = cb->args[0];
3264 int idx = 0;
3265 int err;
3266
3267 mutex_lock(&devlink_mutex);
3268 list_for_each_entry(devlink, &devlink_list, list) {
3269 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3270 continue;
3271 mutex_lock(&devlink->lock);
3272 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3273 list_for_each_entry(param_item,
3274 &devlink_port->param_list, list) {
3275 if (idx < start) {
3276 idx++;
3277 continue;
3278 }
3279 err = devlink_nl_param_fill(msg,
3280 devlink_port->devlink,
3281 devlink_port->index, param_item,
3282 DEVLINK_CMD_PORT_PARAM_GET,
3283 NETLINK_CB(cb->skb).portid,
3284 cb->nlh->nlmsg_seq,
3285 NLM_F_MULTI);
3286 if (err) {
3287 mutex_unlock(&devlink->lock);
3288 goto out;
3289 }
3290 idx++;
3291 }
3292 }
3293 mutex_unlock(&devlink->lock);
3294 }
3295out:
3296 mutex_unlock(&devlink_mutex);
3297
3298 cb->args[0] = idx;
3299 return msg->len;
3300}
3301
3302static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3303 struct genl_info *info)
3304{
3305 struct devlink_port *devlink_port = info->user_ptr[0];
3306 struct devlink_param_item *param_item;
3307 struct sk_buff *msg;
3308 int err;
3309
3310 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3311 info);
3312 if (!param_item)
3313 return -EINVAL;
3314
3315 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3316 if (!msg)
3317 return -ENOMEM;
3318
3319 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3320 devlink_port->index, param_item,
3321 DEVLINK_CMD_PORT_PARAM_GET,
3322 info->snd_portid, info->snd_seq, 0);
3323 if (err) {
3324 nlmsg_free(msg);
3325 return err;
3326 }
3327
3328 return genlmsg_reply(msg, info);
3329}
3330
Vasundhara Volam9c548732019-01-28 18:00:22 +05303331static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3332 struct genl_info *info)
3333{
3334 struct devlink_port *devlink_port = info->user_ptr[0];
3335
3336 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303337 devlink_port->index,
3338 &devlink_port->param_list, info,
3339 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05303340}
3341
Alex Veskera006d462018-07-12 15:13:12 +03003342static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3343 struct devlink *devlink,
3344 struct devlink_snapshot *snapshot)
3345{
3346 struct nlattr *snap_attr;
3347 int err;
3348
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003349 snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
Alex Veskera006d462018-07-12 15:13:12 +03003350 if (!snap_attr)
3351 return -EINVAL;
3352
3353 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3354 if (err)
3355 goto nla_put_failure;
3356
3357 nla_nest_end(msg, snap_attr);
3358 return 0;
3359
3360nla_put_failure:
3361 nla_nest_cancel(msg, snap_attr);
3362 return err;
3363}
3364
3365static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3366 struct devlink *devlink,
3367 struct devlink_region *region)
3368{
3369 struct devlink_snapshot *snapshot;
3370 struct nlattr *snapshots_attr;
3371 int err;
3372
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003373 snapshots_attr = nla_nest_start_noflag(msg,
3374 DEVLINK_ATTR_REGION_SNAPSHOTS);
Alex Veskera006d462018-07-12 15:13:12 +03003375 if (!snapshots_attr)
3376 return -EINVAL;
3377
3378 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3379 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3380 if (err)
3381 goto nla_put_failure;
3382 }
3383
3384 nla_nest_end(msg, snapshots_attr);
3385 return 0;
3386
3387nla_put_failure:
3388 nla_nest_cancel(msg, snapshots_attr);
3389 return err;
3390}
3391
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003392static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3393 enum devlink_command cmd, u32 portid,
3394 u32 seq, int flags,
3395 struct devlink_region *region)
3396{
3397 void *hdr;
3398 int err;
3399
3400 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3401 if (!hdr)
3402 return -EMSGSIZE;
3403
3404 err = devlink_nl_put_handle(msg, devlink);
3405 if (err)
3406 goto nla_put_failure;
3407
3408 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3409 if (err)
3410 goto nla_put_failure;
3411
3412 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3413 region->size,
3414 DEVLINK_ATTR_PAD);
3415 if (err)
3416 goto nla_put_failure;
3417
Alex Veskera006d462018-07-12 15:13:12 +03003418 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3419 if (err)
3420 goto nla_put_failure;
3421
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003422 genlmsg_end(msg, hdr);
3423 return 0;
3424
3425nla_put_failure:
3426 genlmsg_cancel(msg, hdr);
3427 return err;
3428}
3429
Alex Vesker866319b2018-07-12 15:13:13 +03003430static void devlink_nl_region_notify(struct devlink_region *region,
3431 struct devlink_snapshot *snapshot,
3432 enum devlink_command cmd)
3433{
3434 struct devlink *devlink = region->devlink;
3435 struct sk_buff *msg;
3436 void *hdr;
3437 int err;
3438
3439 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3440
3441 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3442 if (!msg)
3443 return;
3444
3445 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3446 if (!hdr)
3447 goto out_free_msg;
3448
3449 err = devlink_nl_put_handle(msg, devlink);
3450 if (err)
3451 goto out_cancel_msg;
3452
3453 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3454 region->name);
3455 if (err)
3456 goto out_cancel_msg;
3457
3458 if (snapshot) {
3459 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3460 snapshot->id);
3461 if (err)
3462 goto out_cancel_msg;
3463 } else {
3464 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3465 region->size, DEVLINK_ATTR_PAD);
3466 if (err)
3467 goto out_cancel_msg;
3468 }
3469 genlmsg_end(msg, hdr);
3470
3471 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3472 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3473
3474 return;
3475
3476out_cancel_msg:
3477 genlmsg_cancel(msg, hdr);
3478out_free_msg:
3479 nlmsg_free(msg);
3480}
3481
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003482static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3483 struct genl_info *info)
3484{
3485 struct devlink *devlink = info->user_ptr[0];
3486 struct devlink_region *region;
3487 const char *region_name;
3488 struct sk_buff *msg;
3489 int err;
3490
3491 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3492 return -EINVAL;
3493
3494 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3495 region = devlink_region_get_by_name(devlink, region_name);
3496 if (!region)
3497 return -EINVAL;
3498
3499 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3500 if (!msg)
3501 return -ENOMEM;
3502
3503 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3504 info->snd_portid, info->snd_seq, 0,
3505 region);
3506 if (err) {
3507 nlmsg_free(msg);
3508 return err;
3509 }
3510
3511 return genlmsg_reply(msg, info);
3512}
3513
3514static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3515 struct netlink_callback *cb)
3516{
3517 struct devlink_region *region;
3518 struct devlink *devlink;
3519 int start = cb->args[0];
3520 int idx = 0;
3521 int err;
3522
3523 mutex_lock(&devlink_mutex);
3524 list_for_each_entry(devlink, &devlink_list, list) {
3525 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3526 continue;
3527
3528 mutex_lock(&devlink->lock);
3529 list_for_each_entry(region, &devlink->region_list, list) {
3530 if (idx < start) {
3531 idx++;
3532 continue;
3533 }
3534 err = devlink_nl_region_fill(msg, devlink,
3535 DEVLINK_CMD_REGION_GET,
3536 NETLINK_CB(cb->skb).portid,
3537 cb->nlh->nlmsg_seq,
3538 NLM_F_MULTI, region);
3539 if (err) {
3540 mutex_unlock(&devlink->lock);
3541 goto out;
3542 }
3543 idx++;
3544 }
3545 mutex_unlock(&devlink->lock);
3546 }
3547out:
3548 mutex_unlock(&devlink_mutex);
3549 cb->args[0] = idx;
3550 return msg->len;
3551}
3552
Alex Vesker866319b2018-07-12 15:13:13 +03003553static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3554 struct genl_info *info)
3555{
3556 struct devlink *devlink = info->user_ptr[0];
3557 struct devlink_snapshot *snapshot;
3558 struct devlink_region *region;
3559 const char *region_name;
3560 u32 snapshot_id;
3561
3562 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3563 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3564 return -EINVAL;
3565
3566 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3567 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3568
3569 region = devlink_region_get_by_name(devlink, region_name);
3570 if (!region)
3571 return -EINVAL;
3572
3573 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3574 if (!snapshot)
3575 return -EINVAL;
3576
3577 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3578 devlink_region_snapshot_del(snapshot);
3579 return 0;
3580}
3581
Alex Vesker4e547952018-07-12 15:13:14 +03003582static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3583 struct devlink *devlink,
3584 u8 *chunk, u32 chunk_size,
3585 u64 addr)
3586{
3587 struct nlattr *chunk_attr;
3588 int err;
3589
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003590 chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
Alex Vesker4e547952018-07-12 15:13:14 +03003591 if (!chunk_attr)
3592 return -EINVAL;
3593
3594 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3595 if (err)
3596 goto nla_put_failure;
3597
3598 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3599 DEVLINK_ATTR_PAD);
3600 if (err)
3601 goto nla_put_failure;
3602
3603 nla_nest_end(msg, chunk_attr);
3604 return 0;
3605
3606nla_put_failure:
3607 nla_nest_cancel(msg, chunk_attr);
3608 return err;
3609}
3610
3611#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3612
3613static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3614 struct devlink *devlink,
3615 struct devlink_region *region,
3616 struct nlattr **attrs,
3617 u64 start_offset,
3618 u64 end_offset,
3619 bool dump,
3620 u64 *new_offset)
3621{
3622 struct devlink_snapshot *snapshot;
3623 u64 curr_offset = start_offset;
3624 u32 snapshot_id;
3625 int err = 0;
3626
3627 *new_offset = start_offset;
3628
3629 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3630 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3631 if (!snapshot)
3632 return -EINVAL;
3633
3634 if (end_offset > snapshot->data_len || dump)
3635 end_offset = snapshot->data_len;
3636
3637 while (curr_offset < end_offset) {
3638 u32 data_size;
3639 u8 *data;
3640
3641 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3642 data_size = end_offset - curr_offset;
3643 else
3644 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3645
3646 data = &snapshot->data[curr_offset];
3647 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3648 data, data_size,
3649 curr_offset);
3650 if (err)
3651 break;
3652
3653 curr_offset += data_size;
3654 }
3655 *new_offset = curr_offset;
3656
3657 return err;
3658}
3659
3660static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3661 struct netlink_callback *cb)
3662{
3663 u64 ret_offset, start_offset, end_offset = 0;
Alex Vesker4e547952018-07-12 15:13:14 +03003664 struct devlink_region *region;
3665 struct nlattr *chunks_attr;
3666 const char *region_name;
3667 struct devlink *devlink;
Jakub Kicinski68750562019-02-10 19:35:28 -08003668 struct nlattr **attrs;
Alex Vesker4e547952018-07-12 15:13:14 +03003669 bool dump = true;
3670 void *hdr;
3671 int err;
3672
3673 start_offset = *((u64 *)&cb->args[0]);
3674
Jakub Kicinski68750562019-02-10 19:35:28 -08003675 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
3676 if (!attrs)
3677 return -ENOMEM;
3678
Johannes Berg8cb08172019-04-26 14:07:28 +02003679 err = nlmsg_parse_deprecated(cb->nlh,
3680 GENL_HDRLEN + devlink_nl_family.hdrsize,
3681 attrs, DEVLINK_ATTR_MAX,
3682 devlink_nl_family.policy, cb->extack);
Alex Vesker4e547952018-07-12 15:13:14 +03003683 if (err)
Jakub Kicinski68750562019-02-10 19:35:28 -08003684 goto out_free;
Alex Vesker4e547952018-07-12 15:13:14 +03003685
Parav Panditdac7c082019-02-12 14:24:08 -06003686 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03003687 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003688 if (IS_ERR(devlink)) {
3689 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06003690 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003691 }
Alex Vesker4e547952018-07-12 15:13:14 +03003692
Alex Vesker4e547952018-07-12 15:13:14 +03003693 mutex_lock(&devlink->lock);
3694
3695 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06003696 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
3697 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003698 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003699 }
Alex Vesker4e547952018-07-12 15:13:14 +03003700
3701 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3702 region = devlink_region_get_by_name(devlink, region_name);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003703 if (!region) {
3704 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003705 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003706 }
Alex Vesker4e547952018-07-12 15:13:14 +03003707
3708 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3709 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3710 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003711 if (!hdr) {
3712 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03003713 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003714 }
Alex Vesker4e547952018-07-12 15:13:14 +03003715
3716 err = devlink_nl_put_handle(skb, devlink);
3717 if (err)
3718 goto nla_put_failure;
3719
3720 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3721 if (err)
3722 goto nla_put_failure;
3723
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003724 chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003725 if (!chunks_attr) {
3726 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03003727 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003728 }
Alex Vesker4e547952018-07-12 15:13:14 +03003729
3730 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3731 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3732 if (!start_offset)
3733 start_offset =
3734 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3735
3736 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3737 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3738 dump = false;
3739 }
3740
3741 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3742 region, attrs,
3743 start_offset,
3744 end_offset, dump,
3745 &ret_offset);
3746
3747 if (err && err != -EMSGSIZE)
3748 goto nla_put_failure;
3749
3750 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06003751 if (ret_offset == start_offset) {
3752 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003753 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003754 }
Alex Vesker4e547952018-07-12 15:13:14 +03003755
3756 *((u64 *)&cb->args[0]) = ret_offset;
3757
3758 nla_nest_end(skb, chunks_attr);
3759 genlmsg_end(skb, hdr);
3760 mutex_unlock(&devlink->lock);
3761 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003762 kfree(attrs);
Alex Vesker4e547952018-07-12 15:13:14 +03003763
3764 return skb->len;
3765
3766nla_put_failure:
3767 genlmsg_cancel(skb, hdr);
3768out_unlock:
3769 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06003770out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03003771 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003772out_free:
3773 kfree(attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003774 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03003775}
3776
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003777struct devlink_info_req {
3778 struct sk_buff *msg;
3779};
3780
3781int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3782{
3783 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3784}
3785EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3786
3787int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3788{
3789 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3790}
3791EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3792
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08003793static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3794 const char *version_name,
3795 const char *version_value)
3796{
3797 struct nlattr *nest;
3798 int err;
3799
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003800 nest = nla_nest_start_noflag(req->msg, attr);
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08003801 if (!nest)
3802 return -EMSGSIZE;
3803
3804 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3805 version_name);
3806 if (err)
3807 goto nla_put_failure;
3808
3809 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3810 version_value);
3811 if (err)
3812 goto nla_put_failure;
3813
3814 nla_nest_end(req->msg, nest);
3815
3816 return 0;
3817
3818nla_put_failure:
3819 nla_nest_cancel(req->msg, nest);
3820 return err;
3821}
3822
3823int devlink_info_version_fixed_put(struct devlink_info_req *req,
3824 const char *version_name,
3825 const char *version_value)
3826{
3827 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3828 version_name, version_value);
3829}
3830EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3831
3832int devlink_info_version_stored_put(struct devlink_info_req *req,
3833 const char *version_name,
3834 const char *version_value)
3835{
3836 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3837 version_name, version_value);
3838}
3839EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3840
3841int devlink_info_version_running_put(struct devlink_info_req *req,
3842 const char *version_name,
3843 const char *version_value)
3844{
3845 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3846 version_name, version_value);
3847}
3848EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3849
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003850static int
3851devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3852 enum devlink_command cmd, u32 portid,
3853 u32 seq, int flags, struct netlink_ext_ack *extack)
3854{
3855 struct devlink_info_req req;
3856 void *hdr;
3857 int err;
3858
3859 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3860 if (!hdr)
3861 return -EMSGSIZE;
3862
3863 err = -EMSGSIZE;
3864 if (devlink_nl_put_handle(msg, devlink))
3865 goto err_cancel_msg;
3866
3867 req.msg = msg;
3868 err = devlink->ops->info_get(devlink, &req, extack);
3869 if (err)
3870 goto err_cancel_msg;
3871
3872 genlmsg_end(msg, hdr);
3873 return 0;
3874
3875err_cancel_msg:
3876 genlmsg_cancel(msg, hdr);
3877 return err;
3878}
3879
3880static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
3881 struct genl_info *info)
3882{
3883 struct devlink *devlink = info->user_ptr[0];
3884 struct sk_buff *msg;
3885 int err;
3886
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08003887 if (!devlink->ops->info_get)
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003888 return -EOPNOTSUPP;
3889
3890 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3891 if (!msg)
3892 return -ENOMEM;
3893
3894 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3895 info->snd_portid, info->snd_seq, 0,
3896 info->extack);
3897 if (err) {
3898 nlmsg_free(msg);
3899 return err;
3900 }
3901
3902 return genlmsg_reply(msg, info);
3903}
3904
3905static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
3906 struct netlink_callback *cb)
3907{
3908 struct devlink *devlink;
3909 int start = cb->args[0];
3910 int idx = 0;
3911 int err;
3912
3913 mutex_lock(&devlink_mutex);
3914 list_for_each_entry(devlink, &devlink_list, list) {
3915 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3916 continue;
3917 if (idx < start) {
3918 idx++;
3919 continue;
3920 }
3921
Jiri Pirkoc493b09b2019-03-24 00:21:03 +01003922 if (!devlink->ops->info_get) {
3923 idx++;
3924 continue;
3925 }
3926
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003927 mutex_lock(&devlink->lock);
3928 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3929 NETLINK_CB(cb->skb).portid,
3930 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3931 cb->extack);
3932 mutex_unlock(&devlink->lock);
3933 if (err)
3934 break;
3935 idx++;
3936 }
3937 mutex_unlock(&devlink_mutex);
3938
3939 cb->args[0] = idx;
3940 return msg->len;
3941}
3942
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02003943struct devlink_fmsg_item {
3944 struct list_head list;
3945 int attrtype;
3946 u8 nla_type;
3947 u16 len;
3948 int value[0];
3949};
3950
3951struct devlink_fmsg {
3952 struct list_head item_list;
3953};
3954
3955static struct devlink_fmsg *devlink_fmsg_alloc(void)
3956{
3957 struct devlink_fmsg *fmsg;
3958
3959 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
3960 if (!fmsg)
3961 return NULL;
3962
3963 INIT_LIST_HEAD(&fmsg->item_list);
3964
3965 return fmsg;
3966}
3967
3968static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
3969{
3970 struct devlink_fmsg_item *item, *tmp;
3971
3972 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
3973 list_del(&item->list);
3974 kfree(item);
3975 }
3976 kfree(fmsg);
3977}
3978
3979static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
3980 int attrtype)
3981{
3982 struct devlink_fmsg_item *item;
3983
3984 item = kzalloc(sizeof(*item), GFP_KERNEL);
3985 if (!item)
3986 return -ENOMEM;
3987
3988 item->attrtype = attrtype;
3989 list_add_tail(&item->list, &fmsg->item_list);
3990
3991 return 0;
3992}
3993
3994int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
3995{
3996 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
3997}
3998EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
3999
4000static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
4001{
4002 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
4003}
4004
4005int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
4006{
4007 return devlink_fmsg_nest_end(fmsg);
4008}
4009EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
4010
4011#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
4012
4013static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
4014{
4015 struct devlink_fmsg_item *item;
4016
4017 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4018 return -EMSGSIZE;
4019
4020 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4021 if (!item)
4022 return -ENOMEM;
4023
4024 item->nla_type = NLA_NUL_STRING;
4025 item->len = strlen(name) + 1;
4026 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4027 memcpy(&item->value, name, item->len);
4028 list_add_tail(&item->list, &fmsg->item_list);
4029
4030 return 0;
4031}
4032
4033int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4034{
4035 int err;
4036
4037 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4038 if (err)
4039 return err;
4040
4041 err = devlink_fmsg_put_name(fmsg, name);
4042 if (err)
4043 return err;
4044
4045 return 0;
4046}
4047EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4048
4049int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4050{
4051 return devlink_fmsg_nest_end(fmsg);
4052}
4053EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4054
4055int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4056 const char *name)
4057{
4058 int err;
4059
4060 err = devlink_fmsg_pair_nest_start(fmsg, name);
4061 if (err)
4062 return err;
4063
4064 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4065 if (err)
4066 return err;
4067
4068 return 0;
4069}
4070EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4071
4072int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4073{
4074 int err;
4075
4076 err = devlink_fmsg_nest_end(fmsg);
4077 if (err)
4078 return err;
4079
4080 err = devlink_fmsg_nest_end(fmsg);
4081 if (err)
4082 return err;
4083
4084 return 0;
4085}
4086EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4087
4088static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4089 const void *value, u16 value_len,
4090 u8 value_nla_type)
4091{
4092 struct devlink_fmsg_item *item;
4093
4094 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4095 return -EMSGSIZE;
4096
4097 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4098 if (!item)
4099 return -ENOMEM;
4100
4101 item->nla_type = value_nla_type;
4102 item->len = value_len;
4103 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4104 memcpy(&item->value, value, item->len);
4105 list_add_tail(&item->list, &fmsg->item_list);
4106
4107 return 0;
4108}
4109
4110int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4111{
4112 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4113}
4114EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4115
4116int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4117{
4118 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4119}
4120EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4121
4122int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4123{
4124 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4125}
4126EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4127
4128int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4129{
4130 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4131}
4132EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4133
4134int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4135{
4136 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4137 NLA_NUL_STRING);
4138}
4139EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4140
4141int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4142 u16 value_len)
4143{
4144 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4145}
4146EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4147
4148int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4149 bool value)
4150{
4151 int err;
4152
4153 err = devlink_fmsg_pair_nest_start(fmsg, name);
4154 if (err)
4155 return err;
4156
4157 err = devlink_fmsg_bool_put(fmsg, value);
4158 if (err)
4159 return err;
4160
4161 err = devlink_fmsg_pair_nest_end(fmsg);
4162 if (err)
4163 return err;
4164
4165 return 0;
4166}
4167EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4168
4169int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4170 u8 value)
4171{
4172 int err;
4173
4174 err = devlink_fmsg_pair_nest_start(fmsg, name);
4175 if (err)
4176 return err;
4177
4178 err = devlink_fmsg_u8_put(fmsg, value);
4179 if (err)
4180 return err;
4181
4182 err = devlink_fmsg_pair_nest_end(fmsg);
4183 if (err)
4184 return err;
4185
4186 return 0;
4187}
4188EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4189
4190int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4191 u32 value)
4192{
4193 int err;
4194
4195 err = devlink_fmsg_pair_nest_start(fmsg, name);
4196 if (err)
4197 return err;
4198
4199 err = devlink_fmsg_u32_put(fmsg, value);
4200 if (err)
4201 return err;
4202
4203 err = devlink_fmsg_pair_nest_end(fmsg);
4204 if (err)
4205 return err;
4206
4207 return 0;
4208}
4209EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4210
4211int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4212 u64 value)
4213{
4214 int err;
4215
4216 err = devlink_fmsg_pair_nest_start(fmsg, name);
4217 if (err)
4218 return err;
4219
4220 err = devlink_fmsg_u64_put(fmsg, value);
4221 if (err)
4222 return err;
4223
4224 err = devlink_fmsg_pair_nest_end(fmsg);
4225 if (err)
4226 return err;
4227
4228 return 0;
4229}
4230EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4231
4232int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4233 const char *value)
4234{
4235 int err;
4236
4237 err = devlink_fmsg_pair_nest_start(fmsg, name);
4238 if (err)
4239 return err;
4240
4241 err = devlink_fmsg_string_put(fmsg, value);
4242 if (err)
4243 return err;
4244
4245 err = devlink_fmsg_pair_nest_end(fmsg);
4246 if (err)
4247 return err;
4248
4249 return 0;
4250}
4251EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4252
4253int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4254 const void *value, u16 value_len)
4255{
4256 int err;
4257
4258 err = devlink_fmsg_pair_nest_start(fmsg, name);
4259 if (err)
4260 return err;
4261
4262 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4263 if (err)
4264 return err;
4265
4266 err = devlink_fmsg_pair_nest_end(fmsg);
4267 if (err)
4268 return err;
4269
4270 return 0;
4271}
4272EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4273
4274static int
4275devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4276{
4277 switch (msg->nla_type) {
4278 case NLA_FLAG:
4279 case NLA_U8:
4280 case NLA_U32:
4281 case NLA_U64:
4282 case NLA_NUL_STRING:
4283 case NLA_BINARY:
4284 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4285 msg->nla_type);
4286 default:
4287 return -EINVAL;
4288 }
4289}
4290
4291static int
4292devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4293{
4294 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4295 u8 tmp;
4296
4297 switch (msg->nla_type) {
4298 case NLA_FLAG:
4299 /* Always provide flag data, regardless of its value */
4300 tmp = *(bool *) msg->value;
4301
4302 return nla_put_u8(skb, attrtype, tmp);
4303 case NLA_U8:
4304 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4305 case NLA_U32:
4306 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4307 case NLA_U64:
4308 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4309 DEVLINK_ATTR_PAD);
4310 case NLA_NUL_STRING:
4311 return nla_put_string(skb, attrtype, (char *) &msg->value);
4312 case NLA_BINARY:
4313 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4314 default:
4315 return -EINVAL;
4316 }
4317}
4318
4319static int
4320devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4321 int *start)
4322{
4323 struct devlink_fmsg_item *item;
4324 struct nlattr *fmsg_nlattr;
4325 int i = 0;
4326 int err;
4327
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004328 fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004329 if (!fmsg_nlattr)
4330 return -EMSGSIZE;
4331
4332 list_for_each_entry(item, &fmsg->item_list, list) {
4333 if (i < *start) {
4334 i++;
4335 continue;
4336 }
4337
4338 switch (item->attrtype) {
4339 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4340 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4341 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4342 case DEVLINK_ATTR_FMSG_NEST_END:
4343 err = nla_put_flag(skb, item->attrtype);
4344 break;
4345 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4346 err = devlink_fmsg_item_fill_type(item, skb);
4347 if (err)
4348 break;
4349 err = devlink_fmsg_item_fill_data(item, skb);
4350 break;
4351 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4352 err = nla_put_string(skb, item->attrtype,
4353 (char *) &item->value);
4354 break;
4355 default:
4356 err = -EINVAL;
4357 break;
4358 }
4359 if (!err)
4360 *start = ++i;
4361 else
4362 break;
4363 }
4364
4365 nla_nest_end(skb, fmsg_nlattr);
4366 return err;
4367}
4368
4369static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4370 struct genl_info *info,
4371 enum devlink_command cmd, int flags)
4372{
4373 struct nlmsghdr *nlh;
4374 struct sk_buff *skb;
4375 bool last = false;
4376 int index = 0;
4377 void *hdr;
4378 int err;
4379
4380 while (!last) {
4381 int tmp_index = index;
4382
4383 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4384 if (!skb)
4385 return -ENOMEM;
4386
4387 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4388 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4389 if (!hdr) {
4390 err = -EMSGSIZE;
4391 goto nla_put_failure;
4392 }
4393
4394 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4395 if (!err)
4396 last = true;
4397 else if (err != -EMSGSIZE || tmp_index == index)
4398 goto nla_put_failure;
4399
4400 genlmsg_end(skb, hdr);
4401 err = genlmsg_reply(skb, info);
4402 if (err)
4403 return err;
4404 }
4405
4406 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4407 if (!skb)
4408 return -ENOMEM;
4409 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4410 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4411 if (!nlh) {
4412 err = -EMSGSIZE;
4413 goto nla_put_failure;
4414 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004415
Li RongQingfde55ea2019-02-11 19:09:07 +08004416 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004417
4418nla_put_failure:
4419 nlmsg_free(skb);
4420 return err;
4421}
4422
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004423struct devlink_health_reporter {
4424 struct list_head list;
4425 void *priv;
4426 const struct devlink_health_reporter_ops *ops;
4427 struct devlink *devlink;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004428 struct devlink_fmsg *dump_fmsg;
4429 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004430 u64 graceful_period;
4431 bool auto_recover;
4432 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004433 u64 dump_ts;
4434 u64 error_count;
4435 u64 recovery_count;
4436 u64 last_recovery_ts;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004437 refcount_t refcount;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004438};
4439
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004440void *
4441devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4442{
4443 return reporter->priv;
4444}
4445EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4446
4447static struct devlink_health_reporter *
4448devlink_health_reporter_find_by_name(struct devlink *devlink,
4449 const char *reporter_name)
4450{
4451 struct devlink_health_reporter *reporter;
4452
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004453 lockdep_assert_held(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004454 list_for_each_entry(reporter, &devlink->reporter_list, list)
4455 if (!strcmp(reporter->ops->name, reporter_name))
4456 return reporter;
4457 return NULL;
4458}
4459
4460/**
4461 * devlink_health_reporter_create - create devlink health reporter
4462 *
4463 * @devlink: devlink
4464 * @ops: ops
4465 * @graceful_period: to avoid recovery loops, in msecs
4466 * @auto_recover: auto recover when error occurs
4467 * @priv: priv
4468 */
4469struct devlink_health_reporter *
4470devlink_health_reporter_create(struct devlink *devlink,
4471 const struct devlink_health_reporter_ops *ops,
4472 u64 graceful_period, bool auto_recover,
4473 void *priv)
4474{
4475 struct devlink_health_reporter *reporter;
4476
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004477 mutex_lock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004478 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4479 reporter = ERR_PTR(-EEXIST);
4480 goto unlock;
4481 }
4482
4483 if (WARN_ON(auto_recover && !ops->recover) ||
4484 WARN_ON(graceful_period && !ops->recover)) {
4485 reporter = ERR_PTR(-EINVAL);
4486 goto unlock;
4487 }
4488
4489 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4490 if (!reporter) {
4491 reporter = ERR_PTR(-ENOMEM);
4492 goto unlock;
4493 }
4494
4495 reporter->priv = priv;
4496 reporter->ops = ops;
4497 reporter->devlink = devlink;
4498 reporter->graceful_period = graceful_period;
4499 reporter->auto_recover = auto_recover;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004500 mutex_init(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004501 refcount_set(&reporter->refcount, 1);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004502 list_add_tail(&reporter->list, &devlink->reporter_list);
4503unlock:
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004504 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004505 return reporter;
4506}
4507EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4508
4509/**
4510 * devlink_health_reporter_destroy - destroy devlink health reporter
4511 *
4512 * @reporter: devlink health reporter to destroy
4513 */
4514void
4515devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4516{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004517 mutex_lock(&reporter->devlink->reporters_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004518 list_del(&reporter->list);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004519 mutex_unlock(&reporter->devlink->reporters_lock);
4520 while (refcount_read(&reporter->refcount) > 1)
4521 msleep(100);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01004522 mutex_destroy(&reporter->dump_lock);
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004523 if (reporter->dump_fmsg)
4524 devlink_fmsg_free(reporter->dump_fmsg);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004525 kfree(reporter);
4526}
4527EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4528
Eran Ben Elisha3167b272019-03-03 10:57:30 +02004529void
4530devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
4531 enum devlink_health_reporter_state state)
4532{
4533 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
4534 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
4535 return;
4536
4537 if (reporter->health_state == state)
4538 return;
4539
4540 reporter->health_state = state;
4541 trace_devlink_health_reporter_state_update(reporter->devlink,
4542 reporter->ops->name, state);
4543}
4544EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
4545
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004546static int
4547devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4548 void *priv_ctx)
4549{
4550 int err;
4551
4552 if (!reporter->ops->recover)
4553 return -EOPNOTSUPP;
4554
4555 err = reporter->ops->recover(reporter, priv_ctx);
4556 if (err)
4557 return err;
4558
4559 reporter->recovery_count++;
4560 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4561 reporter->last_recovery_ts = jiffies;
4562
4563 return 0;
4564}
4565
4566static void
4567devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4568{
4569 if (!reporter->dump_fmsg)
4570 return;
4571 devlink_fmsg_free(reporter->dump_fmsg);
4572 reporter->dump_fmsg = NULL;
4573}
4574
4575static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4576 void *priv_ctx)
4577{
4578 int err;
4579
4580 if (!reporter->ops->dump)
4581 return 0;
4582
4583 if (reporter->dump_fmsg)
4584 return 0;
4585
4586 reporter->dump_fmsg = devlink_fmsg_alloc();
4587 if (!reporter->dump_fmsg) {
4588 err = -ENOMEM;
4589 return err;
4590 }
4591
4592 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4593 if (err)
4594 goto dump_err;
4595
4596 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4597 priv_ctx);
4598 if (err)
4599 goto dump_err;
4600
4601 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4602 if (err)
4603 goto dump_err;
4604
4605 reporter->dump_ts = jiffies;
4606
4607 return 0;
4608
4609dump_err:
4610 devlink_health_dump_clear(reporter);
4611 return err;
4612}
4613
4614int devlink_health_report(struct devlink_health_reporter *reporter,
4615 const char *msg, void *priv_ctx)
4616{
Eran Ben Elishaa0a21ad2019-03-03 10:57:29 +02004617 enum devlink_health_reporter_state prev_health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004618 struct devlink *devlink = reporter->devlink;
4619
4620 /* write a log message of the current error */
4621 WARN_ON(!msg);
4622 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4623 reporter->error_count++;
Eran Ben Elishaa0a21ad2019-03-03 10:57:29 +02004624 prev_health_state = reporter->health_state;
4625 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004626
4627 /* abort if the previous error wasn't recovered */
4628 if (reporter->auto_recover &&
Eran Ben Elishaa0a21ad2019-03-03 10:57:29 +02004629 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004630 jiffies - reporter->last_recovery_ts <
4631 msecs_to_jiffies(reporter->graceful_period))) {
4632 trace_devlink_health_recover_aborted(devlink,
4633 reporter->ops->name,
4634 reporter->health_state,
4635 jiffies -
4636 reporter->last_recovery_ts);
4637 return -ECANCELED;
4638 }
4639
4640 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4641
4642 mutex_lock(&reporter->dump_lock);
4643 /* store current dump of current error, for later analysis */
4644 devlink_health_do_dump(reporter, priv_ctx);
4645 mutex_unlock(&reporter->dump_lock);
4646
4647 if (reporter->auto_recover)
4648 return devlink_health_reporter_recover(reporter, priv_ctx);
4649
4650 return 0;
4651}
4652EXPORT_SYMBOL_GPL(devlink_health_report);
4653
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004654static struct devlink_health_reporter *
4655devlink_health_reporter_get_from_info(struct devlink *devlink,
4656 struct genl_info *info)
4657{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004658 struct devlink_health_reporter *reporter;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004659 char *reporter_name;
4660
4661 if (!info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
4662 return NULL;
4663
4664 reporter_name =
4665 nla_data(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004666 mutex_lock(&devlink->reporters_lock);
4667 reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
4668 if (reporter)
4669 refcount_inc(&reporter->refcount);
4670 mutex_unlock(&devlink->reporters_lock);
4671 return reporter;
4672}
4673
4674static void
4675devlink_health_reporter_put(struct devlink_health_reporter *reporter)
4676{
4677 refcount_dec(&reporter->refcount);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004678}
4679
4680static int
4681devlink_nl_health_reporter_fill(struct sk_buff *msg,
4682 struct devlink *devlink,
4683 struct devlink_health_reporter *reporter,
4684 enum devlink_command cmd, u32 portid,
4685 u32 seq, int flags)
4686{
4687 struct nlattr *reporter_attr;
4688 void *hdr;
4689
4690 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4691 if (!hdr)
4692 return -EMSGSIZE;
4693
4694 if (devlink_nl_put_handle(msg, devlink))
4695 goto genlmsg_cancel;
4696
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004697 reporter_attr = nla_nest_start_noflag(msg,
4698 DEVLINK_ATTR_HEALTH_REPORTER);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004699 if (!reporter_attr)
4700 goto genlmsg_cancel;
4701 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4702 reporter->ops->name))
4703 goto reporter_nest_cancel;
4704 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4705 reporter->health_state))
4706 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02004707 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004708 reporter->error_count, DEVLINK_ATTR_PAD))
4709 goto reporter_nest_cancel;
Aya Levin54719522019-02-21 14:12:01 +02004710 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004711 reporter->recovery_count, DEVLINK_ATTR_PAD))
4712 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02004713 if (reporter->ops->recover &&
4714 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004715 reporter->graceful_period,
4716 DEVLINK_ATTR_PAD))
4717 goto reporter_nest_cancel;
Aya Levin574b1e12019-02-21 14:12:02 +02004718 if (reporter->ops->recover &&
4719 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004720 reporter->auto_recover))
4721 goto reporter_nest_cancel;
4722 if (reporter->dump_fmsg &&
4723 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4724 jiffies_to_msecs(reporter->dump_ts),
4725 DEVLINK_ATTR_PAD))
4726 goto reporter_nest_cancel;
4727
4728 nla_nest_end(msg, reporter_attr);
4729 genlmsg_end(msg, hdr);
4730 return 0;
4731
4732reporter_nest_cancel:
4733 nla_nest_end(msg, reporter_attr);
4734genlmsg_cancel:
4735 genlmsg_cancel(msg, hdr);
4736 return -EMSGSIZE;
4737}
4738
4739static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4740 struct genl_info *info)
4741{
4742 struct devlink *devlink = info->user_ptr[0];
4743 struct devlink_health_reporter *reporter;
4744 struct sk_buff *msg;
4745 int err;
4746
4747 reporter = devlink_health_reporter_get_from_info(devlink, info);
4748 if (!reporter)
4749 return -EINVAL;
4750
4751 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004752 if (!msg) {
4753 err = -ENOMEM;
4754 goto out;
4755 }
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004756
4757 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4758 DEVLINK_CMD_HEALTH_REPORTER_GET,
4759 info->snd_portid, info->snd_seq,
4760 0);
4761 if (err) {
4762 nlmsg_free(msg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004763 goto out;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004764 }
4765
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004766 err = genlmsg_reply(msg, info);
4767out:
4768 devlink_health_reporter_put(reporter);
4769 return err;
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004770}
4771
4772static int
4773devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4774 struct netlink_callback *cb)
4775{
4776 struct devlink_health_reporter *reporter;
4777 struct devlink *devlink;
4778 int start = cb->args[0];
4779 int idx = 0;
4780 int err;
4781
4782 mutex_lock(&devlink_mutex);
4783 list_for_each_entry(devlink, &devlink_list, list) {
4784 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4785 continue;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004786 mutex_lock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004787 list_for_each_entry(reporter, &devlink->reporter_list,
4788 list) {
4789 if (idx < start) {
4790 idx++;
4791 continue;
4792 }
4793 err = devlink_nl_health_reporter_fill(msg, devlink,
4794 reporter,
4795 DEVLINK_CMD_HEALTH_REPORTER_GET,
4796 NETLINK_CB(cb->skb).portid,
4797 cb->nlh->nlmsg_seq,
4798 NLM_F_MULTI);
4799 if (err) {
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004800 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004801 goto out;
4802 }
4803 idx++;
4804 }
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004805 mutex_unlock(&devlink->reporters_lock);
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004806 }
4807out:
4808 mutex_unlock(&devlink_mutex);
4809
4810 cb->args[0] = idx;
4811 return msg->len;
4812}
4813
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004814static int
4815devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
4816 struct genl_info *info)
4817{
4818 struct devlink *devlink = info->user_ptr[0];
4819 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004820 int err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004821
4822 reporter = devlink_health_reporter_get_from_info(devlink, info);
4823 if (!reporter)
4824 return -EINVAL;
4825
4826 if (!reporter->ops->recover &&
4827 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004828 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
4829 err = -EOPNOTSUPP;
4830 goto out;
4831 }
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004832
4833 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
4834 reporter->graceful_period =
4835 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
4836
4837 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
4838 reporter->auto_recover =
4839 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
4840
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004841 devlink_health_reporter_put(reporter);
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004842 return 0;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004843out:
4844 devlink_health_reporter_put(reporter);
4845 return err;
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004846}
4847
Eran Ben Elisha20a09432019-02-07 11:36:37 +02004848static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
4849 struct genl_info *info)
4850{
4851 struct devlink *devlink = info->user_ptr[0];
4852 struct devlink_health_reporter *reporter;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004853 int err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02004854
4855 reporter = devlink_health_reporter_get_from_info(devlink, info);
4856 if (!reporter)
4857 return -EINVAL;
4858
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004859 err = devlink_health_reporter_recover(reporter, NULL);
4860
4861 devlink_health_reporter_put(reporter);
4862 return err;
Eran Ben Elisha20a09432019-02-07 11:36:37 +02004863}
4864
Eran Ben Elishafca42a22019-02-07 11:36:38 +02004865static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
4866 struct genl_info *info)
4867{
4868 struct devlink *devlink = info->user_ptr[0];
4869 struct devlink_health_reporter *reporter;
4870 struct devlink_fmsg *fmsg;
4871 int err;
4872
4873 reporter = devlink_health_reporter_get_from_info(devlink, info);
4874 if (!reporter)
4875 return -EINVAL;
4876
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004877 if (!reporter->ops->diagnose) {
4878 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02004879 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004880 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02004881
4882 fmsg = devlink_fmsg_alloc();
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004883 if (!fmsg) {
4884 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02004885 return -ENOMEM;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004886 }
Eran Ben Elishafca42a22019-02-07 11:36:38 +02004887
4888 err = devlink_fmsg_obj_nest_start(fmsg);
4889 if (err)
4890 goto out;
4891
4892 err = reporter->ops->diagnose(reporter, fmsg);
4893 if (err)
4894 goto out;
4895
4896 err = devlink_fmsg_obj_nest_end(fmsg);
4897 if (err)
4898 goto out;
4899
4900 err = devlink_fmsg_snd(fmsg, info,
4901 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
4902
4903out:
4904 devlink_fmsg_free(fmsg);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004905 devlink_health_reporter_put(reporter);
Eran Ben Elishafca42a22019-02-07 11:36:38 +02004906 return err;
4907}
4908
Eran Ben Elisha35455e22019-02-07 11:36:39 +02004909static int devlink_nl_cmd_health_reporter_dump_get_doit(struct sk_buff *skb,
4910 struct genl_info *info)
4911{
4912 struct devlink *devlink = info->user_ptr[0];
4913 struct devlink_health_reporter *reporter;
4914 int err;
4915
4916 reporter = devlink_health_reporter_get_from_info(devlink, info);
4917 if (!reporter)
4918 return -EINVAL;
4919
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004920 if (!reporter->ops->dump) {
4921 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02004922 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004923 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02004924
4925 mutex_lock(&reporter->dump_lock);
4926 err = devlink_health_do_dump(reporter, NULL);
4927 if (err)
4928 goto out;
4929
4930 err = devlink_fmsg_snd(reporter->dump_fmsg, info,
4931 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 0);
4932
4933out:
4934 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004935 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02004936 return err;
4937}
4938
4939static int
4940devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
4941 struct genl_info *info)
4942{
4943 struct devlink *devlink = info->user_ptr[0];
4944 struct devlink_health_reporter *reporter;
4945
4946 reporter = devlink_health_reporter_get_from_info(devlink, info);
4947 if (!reporter)
4948 return -EINVAL;
4949
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004950 if (!reporter->ops->dump) {
4951 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02004952 return -EOPNOTSUPP;
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004953 }
Eran Ben Elisha35455e22019-02-07 11:36:39 +02004954
4955 mutex_lock(&reporter->dump_lock);
4956 devlink_health_dump_clear(reporter);
4957 mutex_unlock(&reporter->dump_lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03004958 devlink_health_reporter_put(reporter);
Eran Ben Elisha35455e22019-02-07 11:36:39 +02004959 return 0;
4960}
4961
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004962static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
4963 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
4964 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
4965 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
4966 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
4967 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02004968 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
4969 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
4970 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
4971 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
4972 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
4973 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
4974 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03004975 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
Roi Dayan59bfde02016-11-22 23:09:57 +02004976 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03004977 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02004978 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
4979 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01004980 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
4981 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03004982 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
4983 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
4984 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004985 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03004986 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004987 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004988 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
4989 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08004990 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
4991 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004992};
4993
4994static const struct genl_ops devlink_nl_ops[] = {
4995 {
4996 .cmd = DEVLINK_CMD_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02004997 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004998 .doit = devlink_nl_cmd_get_doit,
4999 .dumpit = devlink_nl_cmd_get_dumpit,
Jiri Pirko1fc2257e2016-04-08 19:12:48 +02005000 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005001 /* can be retrieved by unprivileged users */
5002 },
5003 {
5004 .cmd = DEVLINK_CMD_PORT_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005005 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005006 .doit = devlink_nl_cmd_port_get_doit,
5007 .dumpit = devlink_nl_cmd_port_get_dumpit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005008 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5009 /* can be retrieved by unprivileged users */
5010 },
5011 {
5012 .cmd = DEVLINK_CMD_PORT_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005013 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005014 .doit = devlink_nl_cmd_port_set_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005015 .flags = GENL_ADMIN_PERM,
5016 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5017 },
5018 {
5019 .cmd = DEVLINK_CMD_PORT_SPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02005020 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005021 .doit = devlink_nl_cmd_port_split_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005022 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005023 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5024 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005025 },
5026 {
5027 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
Johannes Bergef6243a2019-04-26 14:07:31 +02005028 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005029 .doit = devlink_nl_cmd_port_unsplit_doit,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005030 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005031 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5032 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005033 },
Jiri Pirkobf797472016-04-14 18:19:13 +02005034 {
5035 .cmd = DEVLINK_CMD_SB_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005036 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005037 .doit = devlink_nl_cmd_sb_get_doit,
5038 .dumpit = devlink_nl_cmd_sb_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005039 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5040 DEVLINK_NL_FLAG_NEED_SB,
5041 /* can be retrieved by unprivileged users */
5042 },
5043 {
5044 .cmd = DEVLINK_CMD_SB_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005045 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005046 .doit = devlink_nl_cmd_sb_pool_get_doit,
5047 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005048 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5049 DEVLINK_NL_FLAG_NEED_SB,
5050 /* can be retrieved by unprivileged users */
5051 },
5052 {
5053 .cmd = DEVLINK_CMD_SB_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005054 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005055 .doit = devlink_nl_cmd_sb_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005056 .flags = GENL_ADMIN_PERM,
5057 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5058 DEVLINK_NL_FLAG_NEED_SB,
5059 },
5060 {
5061 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005062 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005063 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
5064 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005065 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5066 DEVLINK_NL_FLAG_NEED_SB,
5067 /* can be retrieved by unprivileged users */
5068 },
5069 {
5070 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005071 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005072 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005073 .flags = GENL_ADMIN_PERM,
5074 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5075 DEVLINK_NL_FLAG_NEED_SB,
5076 },
5077 {
5078 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005079 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005080 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
5081 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005082 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5083 DEVLINK_NL_FLAG_NEED_SB,
5084 /* can be retrieved by unprivileged users */
5085 },
5086 {
5087 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005088 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkobf797472016-04-14 18:19:13 +02005089 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
Jiri Pirkobf797472016-04-14 18:19:13 +02005090 .flags = GENL_ADMIN_PERM,
5091 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5092 DEVLINK_NL_FLAG_NEED_SB,
5093 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005094 {
5095 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
Johannes Bergef6243a2019-04-26 14:07:31 +02005096 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005097 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005098 .flags = GENL_ADMIN_PERM,
5099 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005100 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005101 },
5102 {
5103 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02005104 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005105 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005106 .flags = GENL_ADMIN_PERM,
5107 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005108 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005109 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03005110 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005111 .cmd = DEVLINK_CMD_ESWITCH_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005112 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005113 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005114 .flags = GENL_ADMIN_PERM,
5115 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5116 },
5117 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005118 .cmd = DEVLINK_CMD_ESWITCH_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005119 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005120 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005121 .flags = GENL_ADMIN_PERM,
Jakub Kicinski7ac1cc92018-05-21 22:12:50 -07005122 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5123 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005124 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005125 {
5126 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005127 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005128 .doit = devlink_nl_cmd_dpipe_table_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005129 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005130 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005131 },
5132 {
5133 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005134 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005135 .doit = devlink_nl_cmd_dpipe_entries_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005136 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005137 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005138 },
5139 {
5140 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005141 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005142 .doit = devlink_nl_cmd_dpipe_headers_get,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005143 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005144 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005145 },
5146 {
5147 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005148 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005149 .doit = devlink_nl_cmd_dpipe_table_counters_set,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005150 .flags = GENL_ADMIN_PERM,
5151 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5152 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005153 {
5154 .cmd = DEVLINK_CMD_RESOURCE_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005155 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005156 .doit = devlink_nl_cmd_resource_set,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005157 .flags = GENL_ADMIN_PERM,
5158 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5159 },
5160 {
5161 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
Johannes Bergef6243a2019-04-26 14:07:31 +02005162 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005163 .doit = devlink_nl_cmd_resource_dump,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005164 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005165 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005166 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005167 {
5168 .cmd = DEVLINK_CMD_RELOAD,
Johannes Bergef6243a2019-04-26 14:07:31 +02005169 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005170 .doit = devlink_nl_cmd_reload,
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005171 .flags = GENL_ADMIN_PERM,
5172 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5173 DEVLINK_NL_FLAG_NO_LOCK,
5174 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005175 {
5176 .cmd = DEVLINK_CMD_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005177 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005178 .doit = devlink_nl_cmd_param_get_doit,
5179 .dumpit = devlink_nl_cmd_param_get_dumpit,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005180 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5181 /* can be retrieved by unprivileged users */
5182 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005183 {
5184 .cmd = DEVLINK_CMD_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005185 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005186 .doit = devlink_nl_cmd_param_set_doit,
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005187 .flags = GENL_ADMIN_PERM,
5188 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5189 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005190 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305191 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005192 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305193 .doit = devlink_nl_cmd_port_param_get_doit,
5194 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305195 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5196 /* can be retrieved by unprivileged users */
5197 },
5198 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05305199 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005200 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Vasundhara Volam9c548732019-01-28 18:00:22 +05305201 .doit = devlink_nl_cmd_port_param_set_doit,
Vasundhara Volam9c548732019-01-28 18:00:22 +05305202 .flags = GENL_ADMIN_PERM,
5203 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5204 },
5205 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005206 .cmd = DEVLINK_CMD_REGION_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005207 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005208 .doit = devlink_nl_cmd_region_get_doit,
5209 .dumpit = devlink_nl_cmd_region_get_dumpit,
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005210 .flags = GENL_ADMIN_PERM,
5211 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5212 },
Alex Vesker866319b2018-07-12 15:13:13 +03005213 {
5214 .cmd = DEVLINK_CMD_REGION_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +02005215 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker866319b2018-07-12 15:13:13 +03005216 .doit = devlink_nl_cmd_region_del,
Alex Vesker866319b2018-07-12 15:13:13 +03005217 .flags = GENL_ADMIN_PERM,
5218 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5219 },
Alex Vesker4e547952018-07-12 15:13:14 +03005220 {
5221 .cmd = DEVLINK_CMD_REGION_READ,
Johannes Bergef6243a2019-04-26 14:07:31 +02005222 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Alex Vesker4e547952018-07-12 15:13:14 +03005223 .dumpit = devlink_nl_cmd_region_read_dumpit,
Alex Vesker4e547952018-07-12 15:13:14 +03005224 .flags = GENL_ADMIN_PERM,
5225 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5226 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005227 {
5228 .cmd = DEVLINK_CMD_INFO_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005229 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005230 .doit = devlink_nl_cmd_info_get_doit,
5231 .dumpit = devlink_nl_cmd_info_get_dumpit,
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005232 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5233 /* can be retrieved by unprivileged users */
5234 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005235 {
5236 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005237 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005238 .doit = devlink_nl_cmd_health_reporter_get_doit,
5239 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005240 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5241 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005242 /* can be retrieved by unprivileged users */
5243 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005244 {
5245 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005246 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005247 .doit = devlink_nl_cmd_health_reporter_set_doit,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005248 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005249 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5250 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005251 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005252 {
5253 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
Johannes Bergef6243a2019-04-26 14:07:31 +02005254 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005255 .doit = devlink_nl_cmd_health_reporter_recover_doit,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005256 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005257 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5258 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005259 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005260 {
5261 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
Johannes Bergef6243a2019-04-26 14:07:31 +02005262 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005263 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005264 .flags = GENL_ADMIN_PERM,
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005265 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5266 DEVLINK_NL_FLAG_NO_LOCK,
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005267 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005268 {
5269 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +02005270 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005271 .doit = devlink_nl_cmd_health_reporter_dump_get_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005272 .flags = GENL_ADMIN_PERM,
5273 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5274 DEVLINK_NL_FLAG_NO_LOCK,
5275 },
5276 {
5277 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
Johannes Bergef6243a2019-04-26 14:07:31 +02005278 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005279 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005280 .flags = GENL_ADMIN_PERM,
5281 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5282 DEVLINK_NL_FLAG_NO_LOCK,
5283 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08005284 {
5285 .cmd = DEVLINK_CMD_FLASH_UPDATE,
Johannes Bergef6243a2019-04-26 14:07:31 +02005286 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08005287 .doit = devlink_nl_cmd_flash_update,
Jakub Kicinski76726cc2019-02-14 13:40:44 -08005288 .flags = GENL_ADMIN_PERM,
5289 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5290 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005291};
5292
Johannes Berg56989f62016-10-24 14:40:05 +02005293static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02005294 .name = DEVLINK_GENL_NAME,
5295 .version = DEVLINK_GENL_VERSION,
5296 .maxattr = DEVLINK_ATTR_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +01005297 .policy = devlink_nl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +02005298 .netnsok = true,
5299 .pre_doit = devlink_nl_pre_doit,
5300 .post_doit = devlink_nl_post_doit,
5301 .module = THIS_MODULE,
5302 .ops = devlink_nl_ops,
5303 .n_ops = ARRAY_SIZE(devlink_nl_ops),
5304 .mcgrps = devlink_nl_mcgrps,
5305 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
5306};
5307
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005308/**
5309 * devlink_alloc - Allocate new devlink instance resources
5310 *
5311 * @ops: ops
5312 * @priv_size: size of user private data
5313 *
5314 * Allocate new devlink instance resources, including devlink index
5315 * and name.
5316 */
5317struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
5318{
5319 struct devlink *devlink;
5320
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08005321 if (WARN_ON(!ops))
5322 return NULL;
5323
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005324 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
5325 if (!devlink)
5326 return NULL;
5327 devlink->ops = ops;
5328 devlink_net_set(devlink, &init_net);
5329 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02005330 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005331 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005332 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03005333 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03005334 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005335 INIT_LIST_HEAD(&devlink->reporter_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005336 mutex_init(&devlink->lock);
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005337 mutex_init(&devlink->reporters_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005338 return devlink;
5339}
5340EXPORT_SYMBOL_GPL(devlink_alloc);
5341
5342/**
5343 * devlink_register - Register devlink instance
5344 *
5345 * @devlink: devlink
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08005346 * @dev: parent device
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005347 */
5348int devlink_register(struct devlink *devlink, struct device *dev)
5349{
5350 mutex_lock(&devlink_mutex);
5351 devlink->dev = dev;
5352 list_add_tail(&devlink->list, &devlink_list);
5353 devlink_notify(devlink, DEVLINK_CMD_NEW);
5354 mutex_unlock(&devlink_mutex);
5355 return 0;
5356}
5357EXPORT_SYMBOL_GPL(devlink_register);
5358
5359/**
5360 * devlink_unregister - Unregister devlink instance
5361 *
5362 * @devlink: devlink
5363 */
5364void devlink_unregister(struct devlink *devlink)
5365{
5366 mutex_lock(&devlink_mutex);
5367 devlink_notify(devlink, DEVLINK_CMD_DEL);
5368 list_del(&devlink->list);
5369 mutex_unlock(&devlink_mutex);
5370}
5371EXPORT_SYMBOL_GPL(devlink_unregister);
5372
5373/**
5374 * devlink_free - Free devlink instance resources
5375 *
5376 * @devlink: devlink
5377 */
5378void devlink_free(struct devlink *devlink)
5379{
Moshe Shemeshb587bda2019-04-29 12:41:45 +03005380 mutex_destroy(&devlink->reporters_lock);
Jiri Pirko375cf8c2019-03-24 11:14:24 +01005381 mutex_destroy(&devlink->lock);
Parav Panditb904aad2019-02-08 15:15:00 -06005382 WARN_ON(!list_empty(&devlink->reporter_list));
5383 WARN_ON(!list_empty(&devlink->region_list));
5384 WARN_ON(!list_empty(&devlink->param_list));
5385 WARN_ON(!list_empty(&devlink->resource_list));
5386 WARN_ON(!list_empty(&devlink->dpipe_table_list));
5387 WARN_ON(!list_empty(&devlink->sb_list));
5388 WARN_ON(!list_empty(&devlink->port_list));
5389
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005390 kfree(devlink);
5391}
5392EXPORT_SYMBOL_GPL(devlink_free);
5393
Jiri Pirko136bf272019-05-23 10:43:35 +02005394static void devlink_port_type_warn(struct work_struct *work)
5395{
5396 WARN(true, "Type was not set for devlink port.");
5397}
5398
5399static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
5400{
5401 /* Ignore CPU and DSA flavours. */
5402 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
5403 devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA;
5404}
5405
5406#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 30)
5407
5408static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
5409{
5410 if (!devlink_port_type_should_warn(devlink_port))
5411 return;
5412 /* Schedule a work to WARN in case driver does not set port
5413 * type within timeout.
5414 */
5415 schedule_delayed_work(&devlink_port->type_warn_dw,
5416 DEVLINK_PORT_TYPE_WARN_TIMEOUT);
5417}
5418
5419static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
5420{
5421 if (!devlink_port_type_should_warn(devlink_port))
5422 return;
5423 cancel_delayed_work_sync(&devlink_port->type_warn_dw);
5424}
5425
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005426/**
5427 * devlink_port_register - Register devlink port
5428 *
5429 * @devlink: devlink
5430 * @devlink_port: devlink port
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08005431 * @port_index: driver-specific numerical identifier of the port
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005432 *
5433 * Register devlink port with provided port index. User can use
5434 * any indexing, even hw-related one. devlink_port structure
5435 * is convenient to be embedded inside user driver private structure.
5436 * Note that the caller should take care of zeroing the devlink_port
5437 * structure.
5438 */
5439int devlink_port_register(struct devlink *devlink,
5440 struct devlink_port *devlink_port,
5441 unsigned int port_index)
5442{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005443 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005444 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005445 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005446 return -EEXIST;
5447 }
5448 devlink_port->devlink = devlink;
5449 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005450 devlink_port->registered = true;
Jiri Pirkob8f97552019-03-24 11:14:37 +01005451 spin_lock_init(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005452 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305453 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005454 mutex_unlock(&devlink->lock);
Jiri Pirko136bf272019-05-23 10:43:35 +02005455 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
5456 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005457 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5458 return 0;
5459}
5460EXPORT_SYMBOL_GPL(devlink_port_register);
5461
5462/**
5463 * devlink_port_unregister - Unregister devlink port
5464 *
5465 * @devlink_port: devlink port
5466 */
5467void devlink_port_unregister(struct devlink_port *devlink_port)
5468{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005469 struct devlink *devlink = devlink_port->devlink;
5470
Jiri Pirko136bf272019-05-23 10:43:35 +02005471 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005472 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005473 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005474 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005475 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005476}
5477EXPORT_SYMBOL_GPL(devlink_port_unregister);
5478
5479static void __devlink_port_type_set(struct devlink_port *devlink_port,
5480 enum devlink_port_type type,
5481 void *type_dev)
5482{
Jiri Pirko2b239e72019-03-24 11:14:36 +01005483 if (WARN_ON(!devlink_port->registered))
5484 return;
Jiri Pirko136bf272019-05-23 10:43:35 +02005485 devlink_port_type_warn_cancel(devlink_port);
Jiri Pirkob8f97552019-03-24 11:14:37 +01005486 spin_lock(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005487 devlink_port->type = type;
5488 devlink_port->type_dev = type_dev;
Jiri Pirkob8f97552019-03-24 11:14:37 +01005489 spin_unlock(&devlink_port->type_lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005490 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5491}
5492
5493/**
5494 * devlink_port_type_eth_set - Set port type to Ethernet
5495 *
5496 * @devlink_port: devlink port
5497 * @netdev: related netdevice
5498 */
5499void devlink_port_type_eth_set(struct devlink_port *devlink_port,
5500 struct net_device *netdev)
5501{
Jiri Pirko119c0b52019-04-03 14:24:27 +02005502 const struct net_device_ops *ops = netdev->netdev_ops;
5503
Jiri Pirko746364f2019-03-28 13:56:46 +01005504 /* If driver registers devlink port, it should set devlink port
5505 * attributes accordingly so the compat functions are called
5506 * and the original ops are not used.
5507 */
Jiri Pirko119c0b52019-04-03 14:24:27 +02005508 if (ops->ndo_get_phys_port_name) {
Jiri Pirko746364f2019-03-28 13:56:46 +01005509 /* Some drivers use the same set of ndos for netdevs
5510 * that have devlink_port registered and also for
5511 * those who don't. Make sure that ndo_get_phys_port_name
5512 * returns -EOPNOTSUPP here in case it is defined.
5513 * Warn if not.
5514 */
Jiri Pirko746364f2019-03-28 13:56:46 +01005515 char name[IFNAMSIZ];
5516 int err;
5517
5518 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
5519 WARN_ON(err != -EOPNOTSUPP);
5520 }
Jiri Pirko119c0b52019-04-03 14:24:27 +02005521 if (ops->ndo_get_port_parent_id) {
5522 /* Some drivers use the same set of ndos for netdevs
5523 * that have devlink_port registered and also for
5524 * those who don't. Make sure that ndo_get_port_parent_id
5525 * returns -EOPNOTSUPP here in case it is defined.
5526 * Warn if not.
5527 */
5528 struct netdev_phys_item_id ppid;
5529 int err;
5530
5531 err = ops->ndo_get_port_parent_id(netdev, &ppid);
5532 WARN_ON(err != -EOPNOTSUPP);
5533 }
Jiri Pirko773b1f32019-03-24 11:14:30 +01005534 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005535}
5536EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
5537
5538/**
5539 * devlink_port_type_ib_set - Set port type to InfiniBand
5540 *
5541 * @devlink_port: devlink port
5542 * @ibdev: related IB device
5543 */
5544void devlink_port_type_ib_set(struct devlink_port *devlink_port,
5545 struct ib_device *ibdev)
5546{
Jiri Pirko773b1f32019-03-24 11:14:30 +01005547 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005548}
5549EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
5550
5551/**
5552 * devlink_port_type_clear - Clear port type
5553 *
5554 * @devlink_port: devlink port
5555 */
5556void devlink_port_type_clear(struct devlink_port *devlink_port)
5557{
Jiri Pirko773b1f32019-03-24 11:14:30 +01005558 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
Jiri Pirko136bf272019-05-23 10:43:35 +02005559 devlink_port_type_warn_schedule(devlink_port);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005560}
5561EXPORT_SYMBOL_GPL(devlink_port_type_clear);
5562
5563/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005564 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005565 *
5566 * @devlink_port: devlink port
Jiri Pirko5ec13802018-05-18 09:29:01 +02005567 * @flavour: flavour of the port
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005568 * @port_number: number of the port that is facing user, for example
5569 * the front panel port number
5570 * @split: indicates if this is split port
5571 * @split_subport_number: if the port is split, this is the number
5572 * of subport.
Jiri Pirkobec52672019-04-03 14:24:16 +02005573 * @switch_id: if the port is part of switch, this is buffer with ID,
5574 * otwerwise this is NULL
5575 * @switch_id_len: length of the switch_id buffer
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005576 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005577void devlink_port_attrs_set(struct devlink_port *devlink_port,
Jiri Pirko5ec13802018-05-18 09:29:01 +02005578 enum devlink_port_flavour flavour,
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005579 u32 port_number, bool split,
Jiri Pirkobec52672019-04-03 14:24:16 +02005580 u32 split_subport_number,
5581 const unsigned char *switch_id,
5582 unsigned char switch_id_len)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005583{
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005584 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5585
Jiri Pirko45b86112019-03-24 11:14:33 +01005586 if (WARN_ON(devlink_port->registered))
5587 return;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005588 attrs->set = true;
Jiri Pirko5ec13802018-05-18 09:29:01 +02005589 attrs->flavour = flavour;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005590 attrs->port_number = port_number;
5591 attrs->split = split;
5592 attrs->split_subport_number = split_subport_number;
Jiri Pirkobec52672019-04-03 14:24:16 +02005593 if (switch_id) {
5594 attrs->switch_port = true;
5595 if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
5596 switch_id_len = MAX_PHYS_ITEM_ID_LEN;
5597 memcpy(attrs->switch_id.id, switch_id, switch_id_len);
5598 attrs->switch_id.id_len = switch_id_len;
5599 } else {
5600 attrs->switch_port = false;
5601 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005602}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005603EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005604
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01005605static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
5606 char *name, size_t len)
Jiri Pirko08474c12018-05-18 09:29:02 +02005607{
5608 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5609 int n = 0;
5610
5611 if (!attrs->set)
5612 return -EOPNOTSUPP;
5613
5614 switch (attrs->flavour) {
5615 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
5616 if (!attrs->split)
5617 n = snprintf(name, len, "p%u", attrs->port_number);
5618 else
5619 n = snprintf(name, len, "p%us%u", attrs->port_number,
5620 attrs->split_subport_number);
5621 break;
5622 case DEVLINK_PORT_FLAVOUR_CPU:
5623 case DEVLINK_PORT_FLAVOUR_DSA:
5624 /* As CPU and DSA ports do not have a netdevice associated
5625 * case should not ever happen.
5626 */
5627 WARN_ON(1);
5628 return -EINVAL;
5629 }
5630
5631 if (n >= len)
5632 return -EINVAL;
5633
5634 return 0;
5635}
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01005636
Jiri Pirkobf797472016-04-14 18:19:13 +02005637int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
5638 u32 size, u16 ingress_pools_count,
5639 u16 egress_pools_count, u16 ingress_tc_count,
5640 u16 egress_tc_count)
5641{
5642 struct devlink_sb *devlink_sb;
5643 int err = 0;
5644
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005645 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005646 if (devlink_sb_index_exists(devlink, sb_index)) {
5647 err = -EEXIST;
5648 goto unlock;
5649 }
5650
5651 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
5652 if (!devlink_sb) {
5653 err = -ENOMEM;
5654 goto unlock;
5655 }
5656 devlink_sb->index = sb_index;
5657 devlink_sb->size = size;
5658 devlink_sb->ingress_pools_count = ingress_pools_count;
5659 devlink_sb->egress_pools_count = egress_pools_count;
5660 devlink_sb->ingress_tc_count = ingress_tc_count;
5661 devlink_sb->egress_tc_count = egress_tc_count;
5662 list_add_tail(&devlink_sb->list, &devlink->sb_list);
5663unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005664 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005665 return err;
5666}
5667EXPORT_SYMBOL_GPL(devlink_sb_register);
5668
5669void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
5670{
5671 struct devlink_sb *devlink_sb;
5672
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005673 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005674 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
5675 WARN_ON(!devlink_sb);
5676 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005677 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005678 kfree(devlink_sb);
5679}
5680EXPORT_SYMBOL_GPL(devlink_sb_unregister);
5681
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005682/**
5683 * devlink_dpipe_headers_register - register dpipe headers
5684 *
5685 * @devlink: devlink
5686 * @dpipe_headers: dpipe header array
5687 *
5688 * Register the headers supported by hardware.
5689 */
5690int devlink_dpipe_headers_register(struct devlink *devlink,
5691 struct devlink_dpipe_headers *dpipe_headers)
5692{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005693 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005694 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005695 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005696 return 0;
5697}
5698EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
5699
5700/**
5701 * devlink_dpipe_headers_unregister - unregister dpipe headers
5702 *
5703 * @devlink: devlink
5704 *
5705 * Unregister the headers supported by hardware.
5706 */
5707void devlink_dpipe_headers_unregister(struct devlink *devlink)
5708{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005709 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005710 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005711 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005712}
5713EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
5714
5715/**
5716 * devlink_dpipe_table_counter_enabled - check if counter allocation
5717 * required
5718 * @devlink: devlink
5719 * @table_name: tables name
5720 *
5721 * Used by driver to check if counter allocation is required.
5722 * After counter allocation is turned on the table entries
5723 * are updated to include counter statistics.
5724 *
5725 * After that point on the driver must respect the counter
5726 * state so that each entry added to the table is added
5727 * with a counter.
5728 */
5729bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
5730 const char *table_name)
5731{
5732 struct devlink_dpipe_table *table;
5733 bool enabled;
5734
5735 rcu_read_lock();
5736 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5737 table_name);
5738 enabled = false;
5739 if (table)
5740 enabled = table->counters_enabled;
5741 rcu_read_unlock();
5742 return enabled;
5743}
5744EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
5745
5746/**
5747 * devlink_dpipe_table_register - register dpipe table
5748 *
5749 * @devlink: devlink
5750 * @table_name: table name
5751 * @table_ops: table ops
5752 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005753 * @counter_control_extern: external control for counters
5754 */
5755int devlink_dpipe_table_register(struct devlink *devlink,
5756 const char *table_name,
5757 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02005758 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005759{
5760 struct devlink_dpipe_table *table;
5761
5762 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
5763 return -EEXIST;
5764
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02005765 if (WARN_ON(!table_ops->size_get))
5766 return -EINVAL;
5767
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005768 table = kzalloc(sizeof(*table), GFP_KERNEL);
5769 if (!table)
5770 return -ENOMEM;
5771
5772 table->name = table_name;
5773 table->table_ops = table_ops;
5774 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005775 table->counter_control_extern = counter_control_extern;
5776
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005777 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005778 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005779 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005780 return 0;
5781}
5782EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
5783
5784/**
5785 * devlink_dpipe_table_unregister - unregister dpipe table
5786 *
5787 * @devlink: devlink
5788 * @table_name: table name
5789 */
5790void devlink_dpipe_table_unregister(struct devlink *devlink,
5791 const char *table_name)
5792{
5793 struct devlink_dpipe_table *table;
5794
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005795 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005796 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5797 table_name);
5798 if (!table)
5799 goto unlock;
5800 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005801 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005802 kfree_rcu(table, rcu);
5803 return;
5804unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005805 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005806}
5807EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
5808
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005809/**
5810 * devlink_resource_register - devlink resource register
5811 *
5812 * @devlink: devlink
5813 * @resource_name: resource's name
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005814 * @resource_size: resource's size
5815 * @resource_id: resource's id
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08005816 * @parent_resource_id: resource's parent id
5817 * @size_params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005818 */
5819int devlink_resource_register(struct devlink *devlink,
5820 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005821 u64 resource_size,
5822 u64 resource_id,
5823 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02005824 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005825{
5826 struct devlink_resource *resource;
5827 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07005828 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005829 int err = 0;
5830
David Ahern14530742018-03-20 19:31:14 -07005831 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
5832
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005833 mutex_lock(&devlink->lock);
5834 resource = devlink_resource_find(devlink, NULL, resource_id);
5835 if (resource) {
5836 err = -EINVAL;
5837 goto out;
5838 }
5839
5840 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
5841 if (!resource) {
5842 err = -ENOMEM;
5843 goto out;
5844 }
5845
5846 if (top_hierarchy) {
5847 resource_list = &devlink->resource_list;
5848 } else {
5849 struct devlink_resource *parent_resource;
5850
5851 parent_resource = devlink_resource_find(devlink, NULL,
5852 parent_resource_id);
5853 if (parent_resource) {
5854 resource_list = &parent_resource->resource_list;
5855 resource->parent = parent_resource;
5856 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00005857 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005858 err = -EINVAL;
5859 goto out;
5860 }
5861 }
5862
5863 resource->name = resource_name;
5864 resource->size = resource_size;
5865 resource->size_new = resource_size;
5866 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005867 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01005868 memcpy(&resource->size_params, size_params,
5869 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005870 INIT_LIST_HEAD(&resource->resource_list);
5871 list_add_tail(&resource->list, resource_list);
5872out:
5873 mutex_unlock(&devlink->lock);
5874 return err;
5875}
5876EXPORT_SYMBOL_GPL(devlink_resource_register);
5877
5878/**
5879 * devlink_resources_unregister - free all resources
5880 *
5881 * @devlink: devlink
5882 * @resource: resource
5883 */
5884void devlink_resources_unregister(struct devlink *devlink,
5885 struct devlink_resource *resource)
5886{
5887 struct devlink_resource *tmp, *child_resource;
5888 struct list_head *resource_list;
5889
5890 if (resource)
5891 resource_list = &resource->resource_list;
5892 else
5893 resource_list = &devlink->resource_list;
5894
5895 if (!resource)
5896 mutex_lock(&devlink->lock);
5897
5898 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
5899 devlink_resources_unregister(devlink, child_resource);
5900 list_del(&child_resource->list);
5901 kfree(child_resource);
5902 }
5903
5904 if (!resource)
5905 mutex_unlock(&devlink->lock);
5906}
5907EXPORT_SYMBOL_GPL(devlink_resources_unregister);
5908
5909/**
5910 * devlink_resource_size_get - get and update size
5911 *
5912 * @devlink: devlink
5913 * @resource_id: the requested resource id
5914 * @p_resource_size: ptr to update
5915 */
5916int devlink_resource_size_get(struct devlink *devlink,
5917 u64 resource_id,
5918 u64 *p_resource_size)
5919{
5920 struct devlink_resource *resource;
5921 int err = 0;
5922
5923 mutex_lock(&devlink->lock);
5924 resource = devlink_resource_find(devlink, NULL, resource_id);
5925 if (!resource) {
5926 err = -EINVAL;
5927 goto out;
5928 }
5929 *p_resource_size = resource->size_new;
5930 resource->size = resource->size_new;
5931out:
5932 mutex_unlock(&devlink->lock);
5933 return err;
5934}
5935EXPORT_SYMBOL_GPL(devlink_resource_size_get);
5936
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01005937/**
5938 * devlink_dpipe_table_resource_set - set the resource id
5939 *
5940 * @devlink: devlink
5941 * @table_name: table name
5942 * @resource_id: resource id
5943 * @resource_units: number of resource's units consumed per table's entry
5944 */
5945int devlink_dpipe_table_resource_set(struct devlink *devlink,
5946 const char *table_name, u64 resource_id,
5947 u64 resource_units)
5948{
5949 struct devlink_dpipe_table *table;
5950 int err = 0;
5951
5952 mutex_lock(&devlink->lock);
5953 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5954 table_name);
5955 if (!table) {
5956 err = -EINVAL;
5957 goto out;
5958 }
5959 table->resource_id = resource_id;
5960 table->resource_units = resource_units;
5961 table->resource_valid = true;
5962out:
5963 mutex_unlock(&devlink->lock);
5964 return err;
5965}
5966EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
5967
Jiri Pirkofc56be42018-04-05 22:13:21 +02005968/**
5969 * devlink_resource_occ_get_register - register occupancy getter
5970 *
5971 * @devlink: devlink
5972 * @resource_id: resource id
5973 * @occ_get: occupancy getter callback
5974 * @occ_get_priv: occupancy getter callback priv
5975 */
5976void devlink_resource_occ_get_register(struct devlink *devlink,
5977 u64 resource_id,
5978 devlink_resource_occ_get_t *occ_get,
5979 void *occ_get_priv)
5980{
5981 struct devlink_resource *resource;
5982
5983 mutex_lock(&devlink->lock);
5984 resource = devlink_resource_find(devlink, NULL, resource_id);
5985 if (WARN_ON(!resource))
5986 goto out;
5987 WARN_ON(resource->occ_get);
5988
5989 resource->occ_get = occ_get;
5990 resource->occ_get_priv = occ_get_priv;
5991out:
5992 mutex_unlock(&devlink->lock);
5993}
5994EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
5995
5996/**
5997 * devlink_resource_occ_get_unregister - unregister occupancy getter
5998 *
5999 * @devlink: devlink
6000 * @resource_id: resource id
6001 */
6002void devlink_resource_occ_get_unregister(struct devlink *devlink,
6003 u64 resource_id)
6004{
6005 struct devlink_resource *resource;
6006
6007 mutex_lock(&devlink->lock);
6008 resource = devlink_resource_find(devlink, NULL, resource_id);
6009 if (WARN_ON(!resource))
6010 goto out;
6011 WARN_ON(!resource->occ_get);
6012
6013 resource->occ_get = NULL;
6014 resource->occ_get_priv = NULL;
6015out:
6016 mutex_unlock(&devlink->lock);
6017}
6018EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
6019
Vasundhara Volam39e61602019-01-28 18:00:20 +05306020static int devlink_param_verify(const struct devlink_param *param)
6021{
6022 if (!param || !param->name || !param->supported_cmodes)
6023 return -EINVAL;
6024 if (param->generic)
6025 return devlink_param_generic_verify(param);
6026 else
6027 return devlink_param_driver_verify(param);
6028}
6029
6030static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306031 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306032 struct list_head *param_list,
6033 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306034 size_t params_count,
6035 enum devlink_command reg_cmd,
6036 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05306037{
6038 const struct devlink_param *param = params;
6039 int i;
6040 int err;
6041
6042 mutex_lock(&devlink->lock);
6043 for (i = 0; i < params_count; i++, param++) {
6044 err = devlink_param_verify(param);
6045 if (err)
6046 goto rollback;
6047
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306048 err = devlink_param_register_one(devlink, port_index,
6049 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306050 if (err)
6051 goto rollback;
6052 }
6053
6054 mutex_unlock(&devlink->lock);
6055 return 0;
6056
6057rollback:
6058 if (!i)
6059 goto unlock;
6060 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306061 devlink_param_unregister_one(devlink, port_index, param_list,
6062 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306063unlock:
6064 mutex_unlock(&devlink->lock);
6065 return err;
6066}
6067
6068static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306069 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306070 struct list_head *param_list,
6071 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306072 size_t params_count,
6073 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05306074{
6075 const struct devlink_param *param = params;
6076 int i;
6077
6078 mutex_lock(&devlink->lock);
6079 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306080 devlink_param_unregister_one(devlink, 0, param_list, param,
6081 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306082 mutex_unlock(&devlink->lock);
6083}
6084
Moshe Shemesheabaef12018-07-04 14:30:28 +03006085/**
6086 * devlink_params_register - register configuration parameters
6087 *
6088 * @devlink: devlink
6089 * @params: configuration parameters array
6090 * @params_count: number of parameters provided
6091 *
6092 * Register the configuration parameters supported by the driver.
6093 */
6094int devlink_params_register(struct devlink *devlink,
6095 const struct devlink_param *params,
6096 size_t params_count)
6097{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306098 return __devlink_params_register(devlink, 0, &devlink->param_list,
6099 params, params_count,
6100 DEVLINK_CMD_PARAM_NEW,
6101 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03006102}
6103EXPORT_SYMBOL_GPL(devlink_params_register);
6104
6105/**
6106 * devlink_params_unregister - unregister configuration parameters
6107 * @devlink: devlink
6108 * @params: configuration parameters to unregister
6109 * @params_count: number of parameters provided
6110 */
6111void devlink_params_unregister(struct devlink *devlink,
6112 const struct devlink_param *params,
6113 size_t params_count)
6114{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306115 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
6116 params, params_count,
6117 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03006118}
6119EXPORT_SYMBOL_GPL(devlink_params_unregister);
6120
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006121/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00006122 * devlink_params_publish - publish configuration parameters
6123 *
6124 * @devlink: devlink
6125 *
6126 * Publish previously registered configuration parameters.
6127 */
6128void devlink_params_publish(struct devlink *devlink)
6129{
6130 struct devlink_param_item *param_item;
6131
6132 list_for_each_entry(param_item, &devlink->param_list, list) {
6133 if (param_item->published)
6134 continue;
6135 param_item->published = true;
6136 devlink_param_notify(devlink, 0, param_item,
6137 DEVLINK_CMD_PARAM_NEW);
6138 }
6139}
6140EXPORT_SYMBOL_GPL(devlink_params_publish);
6141
6142/**
6143 * devlink_params_unpublish - unpublish configuration parameters
6144 *
6145 * @devlink: devlink
6146 *
6147 * Unpublish previously registered configuration parameters.
6148 */
6149void devlink_params_unpublish(struct devlink *devlink)
6150{
6151 struct devlink_param_item *param_item;
6152
6153 list_for_each_entry(param_item, &devlink->param_list, list) {
6154 if (!param_item->published)
6155 continue;
6156 param_item->published = false;
6157 devlink_param_notify(devlink, 0, param_item,
6158 DEVLINK_CMD_PARAM_DEL);
6159 }
6160}
6161EXPORT_SYMBOL_GPL(devlink_params_unpublish);
6162
6163/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05306164 * devlink_port_params_register - register port configuration parameters
6165 *
6166 * @devlink_port: devlink port
6167 * @params: configuration parameters array
6168 * @params_count: number of parameters provided
6169 *
6170 * Register the configuration parameters supported by the port.
6171 */
6172int devlink_port_params_register(struct devlink_port *devlink_port,
6173 const struct devlink_param *params,
6174 size_t params_count)
6175{
6176 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306177 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306178 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306179 params_count,
6180 DEVLINK_CMD_PORT_PARAM_NEW,
6181 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306182}
6183EXPORT_SYMBOL_GPL(devlink_port_params_register);
6184
6185/**
6186 * devlink_port_params_unregister - unregister port configuration
6187 * parameters
6188 *
6189 * @devlink_port: devlink port
6190 * @params: configuration parameters array
6191 * @params_count: number of parameters provided
6192 */
6193void devlink_port_params_unregister(struct devlink_port *devlink_port,
6194 const struct devlink_param *params,
6195 size_t params_count)
6196{
6197 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306198 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306199 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306200 params, params_count,
6201 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306202}
6203EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
6204
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306205static int
6206__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
6207 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006208{
6209 struct devlink_param_item *param_item;
6210
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306211 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006212 if (!param_item)
6213 return -EINVAL;
6214
6215 if (!param_item->driverinit_value_valid ||
6216 !devlink_param_cmode_is_supported(param_item->param,
6217 DEVLINK_PARAM_CMODE_DRIVERINIT))
6218 return -EOPNOTSUPP;
6219
Moshe Shemesh12765342018-10-10 16:09:26 +03006220 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6221 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
6222 else
6223 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006224
6225 return 0;
6226}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306227
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306228static int
6229__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306230 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306231 struct list_head *param_list, u32 param_id,
6232 union devlink_param_value init_val,
6233 enum devlink_command cmd)
6234{
6235 struct devlink_param_item *param_item;
6236
6237 param_item = devlink_param_find_by_id(param_list, param_id);
6238 if (!param_item)
6239 return -EINVAL;
6240
6241 if (!devlink_param_cmode_is_supported(param_item->param,
6242 DEVLINK_PARAM_CMODE_DRIVERINIT))
6243 return -EOPNOTSUPP;
6244
6245 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6246 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
6247 else
6248 param_item->driverinit_value = init_val;
6249 param_item->driverinit_value_valid = true;
6250
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306251 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306252 return 0;
6253}
6254
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306255/**
6256 * devlink_param_driverinit_value_get - get configuration parameter
6257 * value for driver initializing
6258 *
6259 * @devlink: devlink
6260 * @param_id: parameter ID
6261 * @init_val: value of parameter in driverinit configuration mode
6262 *
6263 * This function should be used by the driver to get driverinit
6264 * configuration for initialization after reload command.
6265 */
6266int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
6267 union devlink_param_value *init_val)
6268{
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08006269 if (!devlink->ops->reload)
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306270 return -EOPNOTSUPP;
6271
6272 return __devlink_param_driverinit_value_get(&devlink->param_list,
6273 param_id, init_val);
6274}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006275EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
6276
6277/**
6278 * devlink_param_driverinit_value_set - set value of configuration
6279 * parameter for driverinit
6280 * configuration mode
6281 *
6282 * @devlink: devlink
6283 * @param_id: parameter ID
6284 * @init_val: value of parameter to set for driverinit configuration mode
6285 *
6286 * This function should be used by the driver to set driverinit
6287 * configuration mode default value.
6288 */
6289int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
6290 union devlink_param_value init_val)
6291{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306292 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306293 &devlink->param_list,
6294 param_id, init_val,
6295 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006296}
6297EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
6298
Moshe Shemeshea601e12018-07-04 14:30:32 +03006299/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306300 * devlink_port_param_driverinit_value_get - get configuration parameter
6301 * value for driver initializing
6302 *
6303 * @devlink_port: devlink_port
6304 * @param_id: parameter ID
6305 * @init_val: value of parameter in driverinit configuration mode
6306 *
6307 * This function should be used by the driver to get driverinit
6308 * configuration for initialization after reload command.
6309 */
6310int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
6311 u32 param_id,
6312 union devlink_param_value *init_val)
6313{
6314 struct devlink *devlink = devlink_port->devlink;
6315
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08006316 if (!devlink->ops->reload)
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306317 return -EOPNOTSUPP;
6318
6319 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
6320 param_id, init_val);
6321}
6322EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
6323
6324/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306325 * devlink_port_param_driverinit_value_set - set value of configuration
6326 * parameter for driverinit
6327 * configuration mode
6328 *
6329 * @devlink_port: devlink_port
6330 * @param_id: parameter ID
6331 * @init_val: value of parameter to set for driverinit configuration mode
6332 *
6333 * This function should be used by the driver to set driverinit
6334 * configuration mode default value.
6335 */
6336int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
6337 u32 param_id,
6338 union devlink_param_value init_val)
6339{
6340 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306341 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306342 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306343 param_id, init_val,
6344 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306345}
6346EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
6347
6348/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03006349 * devlink_param_value_changed - notify devlink on a parameter's value
6350 * change. Should be called by the driver
6351 * right after the change.
6352 *
6353 * @devlink: devlink
6354 * @param_id: parameter ID
6355 *
6356 * This function should be used by the driver to notify devlink on value
6357 * change, excluding driverinit configuration mode.
6358 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03006359 */
6360void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
6361{
6362 struct devlink_param_item *param_item;
6363
6364 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
6365 WARN_ON(!param_item);
6366
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306367 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03006368}
6369EXPORT_SYMBOL_GPL(devlink_param_value_changed);
6370
Alex Veskerb16ebe92018-07-12 15:13:08 +03006371/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306372 * devlink_port_param_value_changed - notify devlink on a parameter's value
6373 * change. Should be called by the driver
6374 * right after the change.
6375 *
6376 * @devlink_port: devlink_port
6377 * @param_id: parameter ID
6378 *
6379 * This function should be used by the driver to notify devlink on value
6380 * change, excluding driverinit configuration mode.
6381 * For driverinit configuration mode driver should use the function
6382 * devlink_port_param_driverinit_value_set() instead.
6383 */
6384void devlink_port_param_value_changed(struct devlink_port *devlink_port,
6385 u32 param_id)
6386{
6387 struct devlink_param_item *param_item;
6388
6389 param_item = devlink_param_find_by_id(&devlink_port->param_list,
6390 param_id);
6391 WARN_ON(!param_item);
6392
6393 devlink_param_notify(devlink_port->devlink, devlink_port->index,
6394 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
6395}
6396EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
6397
6398/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03006399 * devlink_param_value_str_fill - Safely fill-up the string preventing
6400 * from overflow of the preallocated buffer
6401 *
6402 * @dst_val: destination devlink_param_value
6403 * @src: source buffer
6404 */
6405void devlink_param_value_str_fill(union devlink_param_value *dst_val,
6406 const char *src)
6407{
6408 size_t len;
6409
6410 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
6411 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
6412}
6413EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
6414
6415/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03006416 * devlink_region_create - create a new address region
6417 *
6418 * @devlink: devlink
6419 * @region_name: region name
6420 * @region_max_snapshots: Maximum supported number of snapshots for region
6421 * @region_size: size of region
6422 */
6423struct devlink_region *devlink_region_create(struct devlink *devlink,
6424 const char *region_name,
6425 u32 region_max_snapshots,
6426 u64 region_size)
6427{
6428 struct devlink_region *region;
6429 int err = 0;
6430
6431 mutex_lock(&devlink->lock);
6432
6433 if (devlink_region_get_by_name(devlink, region_name)) {
6434 err = -EEXIST;
6435 goto unlock;
6436 }
6437
6438 region = kzalloc(sizeof(*region), GFP_KERNEL);
6439 if (!region) {
6440 err = -ENOMEM;
6441 goto unlock;
6442 }
6443
6444 region->devlink = devlink;
6445 region->max_snapshots = region_max_snapshots;
6446 region->name = region_name;
6447 region->size = region_size;
6448 INIT_LIST_HEAD(&region->snapshot_list);
6449 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03006450 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03006451
6452 mutex_unlock(&devlink->lock);
6453 return region;
6454
6455unlock:
6456 mutex_unlock(&devlink->lock);
6457 return ERR_PTR(err);
6458}
6459EXPORT_SYMBOL_GPL(devlink_region_create);
6460
6461/**
6462 * devlink_region_destroy - destroy address region
6463 *
6464 * @region: devlink region to destroy
6465 */
6466void devlink_region_destroy(struct devlink_region *region)
6467{
6468 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03006469 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03006470
6471 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03006472
6473 /* Free all snapshots of region */
6474 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
6475 devlink_region_snapshot_del(snapshot);
6476
Alex Veskerb16ebe92018-07-12 15:13:08 +03006477 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03006478
6479 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03006480 mutex_unlock(&devlink->lock);
6481 kfree(region);
6482}
6483EXPORT_SYMBOL_GPL(devlink_region_destroy);
6484
Alex Veskerccadfa42018-07-12 15:13:09 +03006485/**
6486 * devlink_region_shapshot_id_get - get snapshot ID
6487 *
6488 * This callback should be called when adding a new snapshot,
6489 * Driver should use the same id for multiple snapshots taken
6490 * on multiple regions at the same time/by the same trigger.
6491 *
6492 * @devlink: devlink
6493 */
6494u32 devlink_region_shapshot_id_get(struct devlink *devlink)
6495{
6496 u32 id;
6497
6498 mutex_lock(&devlink->lock);
6499 id = ++devlink->snapshot_id;
6500 mutex_unlock(&devlink->lock);
6501
6502 return id;
6503}
6504EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
6505
Alex Veskerd7e52722018-07-12 15:13:10 +03006506/**
6507 * devlink_region_snapshot_create - create a new snapshot
6508 * This will add a new snapshot of a region. The snapshot
6509 * will be stored on the region struct and can be accessed
6510 * from devlink. This is useful for future analyses of snapshots.
6511 * Multiple snapshots can be created on a region.
6512 * The @snapshot_id should be obtained using the getter function.
6513 *
Jakub Kicinskieeaadd82019-02-27 11:36:36 -08006514 * @region: devlink region of the snapshot
Alex Veskerd7e52722018-07-12 15:13:10 +03006515 * @data_len: size of snapshot data
6516 * @data: snapshot data
6517 * @snapshot_id: snapshot id to be created
6518 * @data_destructor: pointer to destructor function to free data
6519 */
6520int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
6521 u8 *data, u32 snapshot_id,
6522 devlink_snapshot_data_dest_t *data_destructor)
6523{
6524 struct devlink *devlink = region->devlink;
6525 struct devlink_snapshot *snapshot;
6526 int err;
6527
6528 mutex_lock(&devlink->lock);
6529
6530 /* check if region can hold one more snapshot */
6531 if (region->cur_snapshots == region->max_snapshots) {
6532 err = -ENOMEM;
6533 goto unlock;
6534 }
6535
6536 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
6537 err = -EEXIST;
6538 goto unlock;
6539 }
6540
6541 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
6542 if (!snapshot) {
6543 err = -ENOMEM;
6544 goto unlock;
6545 }
6546
6547 snapshot->id = snapshot_id;
6548 snapshot->region = region;
6549 snapshot->data = data;
6550 snapshot->data_len = data_len;
6551 snapshot->data_destructor = data_destructor;
6552
6553 list_add_tail(&snapshot->list, &region->snapshot_list);
6554
6555 region->cur_snapshots++;
6556
Alex Vesker866319b2018-07-12 15:13:13 +03006557 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
Alex Veskerd7e52722018-07-12 15:13:10 +03006558 mutex_unlock(&devlink->lock);
6559 return 0;
6560
6561unlock:
6562 mutex_unlock(&devlink->lock);
6563 return err;
6564}
6565EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
6566
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006567static void __devlink_compat_running_version(struct devlink *devlink,
6568 char *buf, size_t len)
6569{
6570 const struct nlattr *nlattr;
6571 struct devlink_info_req req;
6572 struct sk_buff *msg;
6573 int rem, err;
6574
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006575 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6576 if (!msg)
6577 return;
6578
6579 req.msg = msg;
6580 err = devlink->ops->info_get(devlink, &req, NULL);
6581 if (err)
6582 goto free_msg;
6583
6584 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
6585 const struct nlattr *kv;
6586 int rem_kv;
6587
6588 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
6589 continue;
6590
6591 nla_for_each_nested(kv, nlattr, rem_kv) {
6592 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
6593 continue;
6594
6595 strlcat(buf, nla_data(kv), len);
6596 strlcat(buf, " ", len);
6597 }
6598 }
6599free_msg:
6600 nlmsg_free(msg);
6601}
6602
6603void devlink_compat_running_version(struct net_device *dev,
6604 char *buf, size_t len)
6605{
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006606 struct devlink *devlink;
6607
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006608 dev_hold(dev);
6609 rtnl_unlock();
6610
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006611 devlink = netdev_to_devlink(dev);
Jakub Kicinskibe6fe1d2019-02-25 19:34:07 -08006612 if (!devlink || !devlink->ops->info_get)
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006613 goto out;
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006614
6615 mutex_lock(&devlink->lock);
6616 __devlink_compat_running_version(devlink, buf, len);
6617 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006618
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006619out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006620 rtnl_lock();
6621 dev_put(dev);
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006622}
6623
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006624int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
6625{
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006626 struct devlink *devlink;
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006627 int ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006628
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006629 dev_hold(dev);
6630 rtnl_unlock();
6631
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006632 devlink = netdev_to_devlink(dev);
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006633 if (!devlink || !devlink->ops->flash_update) {
6634 ret = -EOPNOTSUPP;
6635 goto out;
6636 }
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006637
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006638 mutex_lock(&devlink->lock);
6639 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
6640 mutex_unlock(&devlink->lock);
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006641
Jiri Pirkoe0dcd382019-03-24 11:14:29 +01006642out:
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08006643 rtnl_lock();
6644 dev_put(dev);
6645
Jakub Kicinskib473b0d2019-02-25 19:34:03 -08006646 return ret;
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006647}
6648
Jiri Pirkoaf3836d2019-03-28 13:56:37 +01006649int devlink_compat_phys_port_name_get(struct net_device *dev,
6650 char *name, size_t len)
6651{
6652 struct devlink_port *devlink_port;
6653
6654 /* RTNL mutex is held here which ensures that devlink_port
6655 * instance cannot disappear in the middle. No need to take
6656 * any devlink lock as only permanent values are accessed.
6657 */
6658 ASSERT_RTNL();
6659
6660 devlink_port = netdev_to_devlink_port(dev);
6661 if (!devlink_port)
6662 return -EOPNOTSUPP;
6663
6664 return __devlink_port_phys_port_name_get(devlink_port, name, len);
6665}
6666
Jiri Pirko7e1146e2019-04-03 14:24:17 +02006667int devlink_compat_switch_id_get(struct net_device *dev,
6668 struct netdev_phys_item_id *ppid)
6669{
6670 struct devlink_port *devlink_port;
6671
6672 /* RTNL mutex is held here which ensures that devlink_port
6673 * instance cannot disappear in the middle. No need to take
6674 * any devlink lock as only permanent values are accessed.
6675 */
6676 ASSERT_RTNL();
6677 devlink_port = netdev_to_devlink_port(dev);
6678 if (!devlink_port || !devlink_port->attrs.switch_port)
6679 return -EOPNOTSUPP;
6680
6681 memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
6682
6683 return 0;
6684}
6685
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08006686static int __init devlink_init(void)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006687{
Johannes Berg489111e2016-10-24 14:40:03 +02006688 return genl_register_family(&devlink_nl_family);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006689}
6690
Jakub Kicinskif4b6bcc2019-02-25 19:34:02 -08006691subsys_initcall(devlink_init);