blob: 04d98550c78ce062937feda53adabdc9c38b3d39 [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>
22#include <rdma/ib_verbs.h>
23#include <net/netlink.h>
24#include <net/genetlink.h>
25#include <net/rtnetlink.h>
26#include <net/net_namespace.h>
27#include <net/sock.h>
28#include <net/devlink.h>
Jiri Pirkoe5224f02016-07-12 18:05:03 +020029#define CREATE_TRACE_POINTS
30#include <trace/events/devlink.h>
31
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020032static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
33 {
David Ahern12bdc5e2017-08-30 17:07:30 -070034 .name = "destination mac",
Arkadi Sharshevsky11770092017-08-24 08:39:59 +020035 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
36 .bitwidth = 48,
37 },
38};
39
40struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
41 .name = "ethernet",
42 .id = DEVLINK_DPIPE_HEADER_ETHERNET,
43 .fields = devlink_dpipe_fields_ethernet,
44 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
45 .global = true,
46};
47EXPORT_SYMBOL(devlink_dpipe_header_ethernet);
48
Arkadi Sharshevsky3fb886e2017-08-24 08:40:00 +020049static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
50 {
51 .name = "destination ip",
52 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
53 .bitwidth = 32,
54 },
55};
56
57struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
58 .name = "ipv4",
59 .id = DEVLINK_DPIPE_HEADER_IPV4,
60 .fields = devlink_dpipe_fields_ipv4,
61 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
62 .global = true,
63};
64EXPORT_SYMBOL(devlink_dpipe_header_ipv4);
65
Arkadi Sharshevsky1797f5b2017-08-31 17:59:12 +020066static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
67 {
68 .name = "destination ip",
69 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
70 .bitwidth = 128,
71 },
72};
73
74struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
75 .name = "ipv6",
76 .id = DEVLINK_DPIPE_HEADER_IPV6,
77 .fields = devlink_dpipe_fields_ipv6,
78 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
79 .global = true,
80};
81EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
82
Jiri Pirkoe5224f02016-07-12 18:05:03 +020083EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
Nir Dotan57186a52019-02-04 18:47:45 +000084EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010085
86static LIST_HEAD(devlink_list);
87
88/* devlink_mutex
89 *
90 * An overall lock guarding every operation coming from userspace.
91 * It also guards devlink devices list and it is taken when
92 * driver registers/unregisters it.
93 */
94static DEFINE_MUTEX(devlink_mutex);
95
Jiri Pirkobfcd3a42016-02-26 17:32:23 +010096static struct net *devlink_net(const struct devlink *devlink)
97{
98 return read_pnet(&devlink->_net);
99}
100
101static void devlink_net_set(struct devlink *devlink, struct net *net)
102{
103 write_pnet(&devlink->_net, net);
104}
105
106static struct devlink *devlink_get_from_attrs(struct net *net,
107 struct nlattr **attrs)
108{
109 struct devlink *devlink;
110 char *busname;
111 char *devname;
112
113 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
114 return ERR_PTR(-EINVAL);
115
116 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
117 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
118
Parav Panditdac7c082019-02-12 14:24:08 -0600119 lockdep_assert_held(&devlink_mutex);
120
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100121 list_for_each_entry(devlink, &devlink_list, list) {
122 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
123 strcmp(dev_name(devlink->dev), devname) == 0 &&
124 net_eq(devlink_net(devlink), net))
125 return devlink;
126 }
127
128 return ERR_PTR(-ENODEV);
129}
130
131static struct devlink *devlink_get_from_info(struct genl_info *info)
132{
133 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
134}
135
136static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
137 int port_index)
138{
139 struct devlink_port *devlink_port;
140
141 list_for_each_entry(devlink_port, &devlink->port_list, list) {
142 if (devlink_port->index == port_index)
143 return devlink_port;
144 }
145 return NULL;
146}
147
148static bool devlink_port_index_exists(struct devlink *devlink, int port_index)
149{
150 return devlink_port_get_by_index(devlink, port_index);
151}
152
153static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
154 struct nlattr **attrs)
155{
156 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
157 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
158 struct devlink_port *devlink_port;
159
160 devlink_port = devlink_port_get_by_index(devlink, port_index);
161 if (!devlink_port)
162 return ERR_PTR(-ENODEV);
163 return devlink_port;
164 }
165 return ERR_PTR(-EINVAL);
166}
167
168static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
169 struct genl_info *info)
170{
171 return devlink_port_get_from_attrs(devlink, info->attrs);
172}
173
Jiri Pirkobf797472016-04-14 18:19:13 +0200174struct devlink_sb {
175 struct list_head list;
176 unsigned int index;
177 u32 size;
178 u16 ingress_pools_count;
179 u16 egress_pools_count;
180 u16 ingress_tc_count;
181 u16 egress_tc_count;
182};
183
184static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
185{
186 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
187}
188
189static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
190 unsigned int sb_index)
191{
192 struct devlink_sb *devlink_sb;
193
194 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
195 if (devlink_sb->index == sb_index)
196 return devlink_sb;
197 }
198 return NULL;
199}
200
201static bool devlink_sb_index_exists(struct devlink *devlink,
202 unsigned int sb_index)
203{
204 return devlink_sb_get_by_index(devlink, sb_index);
205}
206
207static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
208 struct nlattr **attrs)
209{
210 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
211 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
212 struct devlink_sb *devlink_sb;
213
214 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
215 if (!devlink_sb)
216 return ERR_PTR(-ENODEV);
217 return devlink_sb;
218 }
219 return ERR_PTR(-EINVAL);
220}
221
222static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
223 struct genl_info *info)
224{
225 return devlink_sb_get_from_attrs(devlink, info->attrs);
226}
227
228static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
229 struct nlattr **attrs,
230 u16 *p_pool_index)
231{
232 u16 val;
233
234 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
235 return -EINVAL;
236
237 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
238 if (val >= devlink_sb_pool_count(devlink_sb))
239 return -EINVAL;
240 *p_pool_index = val;
241 return 0;
242}
243
244static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
245 struct genl_info *info,
246 u16 *p_pool_index)
247{
248 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
249 p_pool_index);
250}
251
252static int
253devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
254 enum devlink_sb_pool_type *p_pool_type)
255{
256 u8 val;
257
258 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
259 return -EINVAL;
260
261 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
262 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
263 val != DEVLINK_SB_POOL_TYPE_EGRESS)
264 return -EINVAL;
265 *p_pool_type = val;
266 return 0;
267}
268
269static int
270devlink_sb_pool_type_get_from_info(struct genl_info *info,
271 enum devlink_sb_pool_type *p_pool_type)
272{
273 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
274}
275
276static int
277devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
278 enum devlink_sb_threshold_type *p_th_type)
279{
280 u8 val;
281
282 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
283 return -EINVAL;
284
285 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
286 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
287 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
288 return -EINVAL;
289 *p_th_type = val;
290 return 0;
291}
292
293static int
294devlink_sb_th_type_get_from_info(struct genl_info *info,
295 enum devlink_sb_threshold_type *p_th_type)
296{
297 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
298}
299
300static int
301devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
302 struct nlattr **attrs,
303 enum devlink_sb_pool_type pool_type,
304 u16 *p_tc_index)
305{
306 u16 val;
307
308 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
309 return -EINVAL;
310
311 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
312 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
313 val >= devlink_sb->ingress_tc_count)
314 return -EINVAL;
315 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
316 val >= devlink_sb->egress_tc_count)
317 return -EINVAL;
318 *p_tc_index = val;
319 return 0;
320}
321
322static int
323devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
324 struct genl_info *info,
325 enum devlink_sb_pool_type pool_type,
326 u16 *p_tc_index)
327{
328 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
329 pool_type, p_tc_index);
330}
331
Alex Veskerb16ebe92018-07-12 15:13:08 +0300332struct devlink_region {
333 struct devlink *devlink;
334 struct list_head list;
335 const char *name;
336 struct list_head snapshot_list;
337 u32 max_snapshots;
338 u32 cur_snapshots;
339 u64 size;
340};
341
Alex Veskerd7e52722018-07-12 15:13:10 +0300342struct devlink_snapshot {
343 struct list_head list;
344 struct devlink_region *region;
345 devlink_snapshot_data_dest_t *data_destructor;
346 u64 data_len;
347 u8 *data;
348 u32 id;
349};
350
Alex Veskerb16ebe92018-07-12 15:13:08 +0300351static struct devlink_region *
352devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
353{
354 struct devlink_region *region;
355
356 list_for_each_entry(region, &devlink->region_list, list)
357 if (!strcmp(region->name, region_name))
358 return region;
359
360 return NULL;
361}
362
Alex Veskerd7e52722018-07-12 15:13:10 +0300363static struct devlink_snapshot *
364devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
365{
366 struct devlink_snapshot *snapshot;
367
368 list_for_each_entry(snapshot, &region->snapshot_list, list)
369 if (snapshot->id == id)
370 return snapshot;
371
372 return NULL;
373}
374
375static void devlink_region_snapshot_del(struct devlink_snapshot *snapshot)
376{
377 snapshot->region->cur_snapshots--;
378 list_del(&snapshot->list);
379 (*snapshot->data_destructor)(snapshot->data);
380 kfree(snapshot);
381}
382
Jiri Pirko1fc22572016-04-08 19:12:48 +0200383#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
384#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
Jiri Pirkobf797472016-04-14 18:19:13 +0200385#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100386
387/* The per devlink instance lock is taken by default in the pre-doit
388 * operation, yet several commands do not require this. The global
389 * devlink lock is taken and protects from disruption by user-calls.
390 */
391#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100392
393static int devlink_nl_pre_doit(const struct genl_ops *ops,
394 struct sk_buff *skb, struct genl_info *info)
395{
396 struct devlink *devlink;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100397 int err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100398
399 mutex_lock(&devlink_mutex);
400 devlink = devlink_get_from_info(info);
401 if (IS_ERR(devlink)) {
402 mutex_unlock(&devlink_mutex);
403 return PTR_ERR(devlink);
404 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100405 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
406 mutex_lock(&devlink->lock);
Jiri Pirko1fc22572016-04-08 19:12:48 +0200407 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
408 info->user_ptr[0] = devlink;
409 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100410 struct devlink_port *devlink_port;
411
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100412 devlink_port = devlink_port_get_from_info(devlink, info);
413 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100414 err = PTR_ERR(devlink_port);
415 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100416 }
Jiri Pirko1fc22572016-04-08 19:12:48 +0200417 info->user_ptr[0] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100418 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200419 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
420 struct devlink_sb *devlink_sb;
421
422 devlink_sb = devlink_sb_get_from_info(devlink, info);
423 if (IS_ERR(devlink_sb)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100424 err = PTR_ERR(devlink_sb);
425 goto unlock;
Jiri Pirkobf797472016-04-14 18:19:13 +0200426 }
427 info->user_ptr[1] = devlink_sb;
428 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100429 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100430
431unlock:
432 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
433 mutex_unlock(&devlink->lock);
434 mutex_unlock(&devlink_mutex);
435 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100436}
437
438static void devlink_nl_post_doit(const struct genl_ops *ops,
439 struct sk_buff *skb, struct genl_info *info)
440{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100441 struct devlink *devlink;
442
443 devlink = devlink_get_from_info(info);
444 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
445 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100446 mutex_unlock(&devlink_mutex);
447}
448
Johannes Berg489111e2016-10-24 14:40:03 +0200449static struct genl_family devlink_nl_family;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100450
451enum devlink_multicast_groups {
452 DEVLINK_MCGRP_CONFIG,
453};
454
455static const struct genl_multicast_group devlink_nl_mcgrps[] = {
456 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
457};
458
459static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
460{
461 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
462 return -EMSGSIZE;
463 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
464 return -EMSGSIZE;
465 return 0;
466}
467
468static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
469 enum devlink_command cmd, u32 portid,
470 u32 seq, int flags)
471{
472 void *hdr;
473
474 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
475 if (!hdr)
476 return -EMSGSIZE;
477
478 if (devlink_nl_put_handle(msg, devlink))
479 goto nla_put_failure;
480
481 genlmsg_end(msg, hdr);
482 return 0;
483
484nla_put_failure:
485 genlmsg_cancel(msg, hdr);
486 return -EMSGSIZE;
487}
488
489static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
490{
491 struct sk_buff *msg;
492 int err;
493
494 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
495
496 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
497 if (!msg)
498 return;
499
500 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
501 if (err) {
502 nlmsg_free(msg);
503 return;
504 }
505
506 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
507 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
508}
509
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200510static int devlink_nl_port_attrs_put(struct sk_buff *msg,
511 struct devlink_port *devlink_port)
512{
513 struct devlink_port_attrs *attrs = &devlink_port->attrs;
514
515 if (!attrs->set)
516 return 0;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200517 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
518 return -EMSGSIZE;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200519 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER, attrs->port_number))
520 return -EMSGSIZE;
521 if (!attrs->split)
522 return 0;
523 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP, attrs->port_number))
524 return -EMSGSIZE;
525 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
526 attrs->split_subport_number))
527 return -EMSGSIZE;
528 return 0;
529}
530
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100531static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
532 struct devlink_port *devlink_port,
533 enum devlink_command cmd, u32 portid,
534 u32 seq, int flags)
535{
536 void *hdr;
537
538 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
539 if (!hdr)
540 return -EMSGSIZE;
541
542 if (devlink_nl_put_handle(msg, devlink))
543 goto nla_put_failure;
544 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
545 goto nla_put_failure;
546 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
547 goto nla_put_failure;
548 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
549 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
550 devlink_port->desired_type))
551 goto nla_put_failure;
552 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
553 struct net_device *netdev = devlink_port->type_dev;
554
555 if (netdev &&
556 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
557 netdev->ifindex) ||
558 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
559 netdev->name)))
560 goto nla_put_failure;
561 }
562 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
563 struct ib_device *ibdev = devlink_port->type_dev;
564
565 if (ibdev &&
566 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
567 ibdev->name))
568 goto nla_put_failure;
569 }
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200570 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100571 goto nla_put_failure;
572
573 genlmsg_end(msg, hdr);
574 return 0;
575
576nla_put_failure:
577 genlmsg_cancel(msg, hdr);
578 return -EMSGSIZE;
579}
580
581static void devlink_port_notify(struct devlink_port *devlink_port,
582 enum devlink_command cmd)
583{
584 struct devlink *devlink = devlink_port->devlink;
585 struct sk_buff *msg;
586 int err;
587
588 if (!devlink_port->registered)
589 return;
590
591 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
592
593 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
594 if (!msg)
595 return;
596
597 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
598 if (err) {
599 nlmsg_free(msg);
600 return;
601 }
602
603 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
604 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
605}
606
607static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
608{
609 struct devlink *devlink = info->user_ptr[0];
610 struct sk_buff *msg;
611 int err;
612
613 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
614 if (!msg)
615 return -ENOMEM;
616
617 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
618 info->snd_portid, info->snd_seq, 0);
619 if (err) {
620 nlmsg_free(msg);
621 return err;
622 }
623
624 return genlmsg_reply(msg, info);
625}
626
627static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
628 struct netlink_callback *cb)
629{
630 struct devlink *devlink;
631 int start = cb->args[0];
632 int idx = 0;
633 int err;
634
635 mutex_lock(&devlink_mutex);
636 list_for_each_entry(devlink, &devlink_list, list) {
637 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
638 continue;
639 if (idx < start) {
640 idx++;
641 continue;
642 }
643 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
644 NETLINK_CB(cb->skb).portid,
645 cb->nlh->nlmsg_seq, NLM_F_MULTI);
646 if (err)
647 goto out;
648 idx++;
649 }
650out:
651 mutex_unlock(&devlink_mutex);
652
653 cb->args[0] = idx;
654 return msg->len;
655}
656
657static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
658 struct genl_info *info)
659{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200660 struct devlink_port *devlink_port = info->user_ptr[0];
661 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100662 struct sk_buff *msg;
663 int err;
664
665 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
666 if (!msg)
667 return -ENOMEM;
668
669 err = devlink_nl_port_fill(msg, devlink, devlink_port,
670 DEVLINK_CMD_PORT_NEW,
671 info->snd_portid, info->snd_seq, 0);
672 if (err) {
673 nlmsg_free(msg);
674 return err;
675 }
676
677 return genlmsg_reply(msg, info);
678}
679
680static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
681 struct netlink_callback *cb)
682{
683 struct devlink *devlink;
684 struct devlink_port *devlink_port;
685 int start = cb->args[0];
686 int idx = 0;
687 int err;
688
689 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100690 list_for_each_entry(devlink, &devlink_list, list) {
691 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
692 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100693 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100694 list_for_each_entry(devlink_port, &devlink->port_list, list) {
695 if (idx < start) {
696 idx++;
697 continue;
698 }
699 err = devlink_nl_port_fill(msg, devlink, devlink_port,
700 DEVLINK_CMD_NEW,
701 NETLINK_CB(cb->skb).portid,
702 cb->nlh->nlmsg_seq,
703 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100704 if (err) {
705 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100706 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100707 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100708 idx++;
709 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100710 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100711 }
712out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100713 mutex_unlock(&devlink_mutex);
714
715 cb->args[0] = idx;
716 return msg->len;
717}
718
719static int devlink_port_type_set(struct devlink *devlink,
720 struct devlink_port *devlink_port,
721 enum devlink_port_type port_type)
722
723{
724 int err;
725
726 if (devlink->ops && devlink->ops->port_type_set) {
727 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
728 return -EINVAL;
Elad Raz6edf1012016-10-23 17:43:05 +0200729 if (port_type == devlink_port->type)
730 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100731 err = devlink->ops->port_type_set(devlink_port, port_type);
732 if (err)
733 return err;
734 devlink_port->desired_type = port_type;
735 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
736 return 0;
737 }
738 return -EOPNOTSUPP;
739}
740
741static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
742 struct genl_info *info)
743{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200744 struct devlink_port *devlink_port = info->user_ptr[0];
745 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100746 int err;
747
748 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
749 enum devlink_port_type port_type;
750
751 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
752 err = devlink_port_type_set(devlink, devlink_port, port_type);
753 if (err)
754 return err;
755 }
756 return 0;
757}
758
David Ahernac0fc8a2018-06-05 08:14:09 -0700759static int devlink_port_split(struct devlink *devlink, u32 port_index,
760 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100761
762{
763 if (devlink->ops && devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -0700764 return devlink->ops->port_split(devlink, port_index, count,
765 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100766 return -EOPNOTSUPP;
767}
768
769static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
770 struct genl_info *info)
771{
772 struct devlink *devlink = info->user_ptr[0];
773 u32 port_index;
774 u32 count;
775
776 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
777 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
778 return -EINVAL;
779
780 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
781 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700782 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100783}
784
David Ahernac0fc8a2018-06-05 08:14:09 -0700785static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
786 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100787
788{
789 if (devlink->ops && devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -0700790 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100791 return -EOPNOTSUPP;
792}
793
794static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
795 struct genl_info *info)
796{
797 struct devlink *devlink = info->user_ptr[0];
798 u32 port_index;
799
800 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
801 return -EINVAL;
802
803 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700804 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100805}
806
Jiri Pirkobf797472016-04-14 18:19:13 +0200807static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
808 struct devlink_sb *devlink_sb,
809 enum devlink_command cmd, u32 portid,
810 u32 seq, int flags)
811{
812 void *hdr;
813
814 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
815 if (!hdr)
816 return -EMSGSIZE;
817
818 if (devlink_nl_put_handle(msg, devlink))
819 goto nla_put_failure;
820 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
821 goto nla_put_failure;
822 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
823 goto nla_put_failure;
824 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
825 devlink_sb->ingress_pools_count))
826 goto nla_put_failure;
827 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
828 devlink_sb->egress_pools_count))
829 goto nla_put_failure;
830 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
831 devlink_sb->ingress_tc_count))
832 goto nla_put_failure;
833 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
834 devlink_sb->egress_tc_count))
835 goto nla_put_failure;
836
837 genlmsg_end(msg, hdr);
838 return 0;
839
840nla_put_failure:
841 genlmsg_cancel(msg, hdr);
842 return -EMSGSIZE;
843}
844
845static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
846 struct genl_info *info)
847{
848 struct devlink *devlink = info->user_ptr[0];
849 struct devlink_sb *devlink_sb = info->user_ptr[1];
850 struct sk_buff *msg;
851 int err;
852
853 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
854 if (!msg)
855 return -ENOMEM;
856
857 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
858 DEVLINK_CMD_SB_NEW,
859 info->snd_portid, info->snd_seq, 0);
860 if (err) {
861 nlmsg_free(msg);
862 return err;
863 }
864
865 return genlmsg_reply(msg, info);
866}
867
868static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
869 struct netlink_callback *cb)
870{
871 struct devlink *devlink;
872 struct devlink_sb *devlink_sb;
873 int start = cb->args[0];
874 int idx = 0;
875 int err;
876
877 mutex_lock(&devlink_mutex);
878 list_for_each_entry(devlink, &devlink_list, list) {
879 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
880 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100881 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200882 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
883 if (idx < start) {
884 idx++;
885 continue;
886 }
887 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
888 DEVLINK_CMD_SB_NEW,
889 NETLINK_CB(cb->skb).portid,
890 cb->nlh->nlmsg_seq,
891 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100892 if (err) {
893 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200894 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100895 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200896 idx++;
897 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100898 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200899 }
900out:
901 mutex_unlock(&devlink_mutex);
902
903 cb->args[0] = idx;
904 return msg->len;
905}
906
907static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
908 struct devlink_sb *devlink_sb,
909 u16 pool_index, enum devlink_command cmd,
910 u32 portid, u32 seq, int flags)
911{
912 struct devlink_sb_pool_info pool_info;
913 void *hdr;
914 int err;
915
916 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
917 pool_index, &pool_info);
918 if (err)
919 return err;
920
921 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
922 if (!hdr)
923 return -EMSGSIZE;
924
925 if (devlink_nl_put_handle(msg, devlink))
926 goto nla_put_failure;
927 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
928 goto nla_put_failure;
929 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
930 goto nla_put_failure;
931 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
932 goto nla_put_failure;
933 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
934 goto nla_put_failure;
935 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
936 pool_info.threshold_type))
937 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -0800938 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
939 pool_info.cell_size))
940 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +0200941
942 genlmsg_end(msg, hdr);
943 return 0;
944
945nla_put_failure:
946 genlmsg_cancel(msg, hdr);
947 return -EMSGSIZE;
948}
949
950static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
951 struct genl_info *info)
952{
953 struct devlink *devlink = info->user_ptr[0];
954 struct devlink_sb *devlink_sb = info->user_ptr[1];
955 struct sk_buff *msg;
956 u16 pool_index;
957 int err;
958
959 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
960 &pool_index);
961 if (err)
962 return err;
963
964 if (!devlink->ops || !devlink->ops->sb_pool_get)
965 return -EOPNOTSUPP;
966
967 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
968 if (!msg)
969 return -ENOMEM;
970
971 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
972 DEVLINK_CMD_SB_POOL_NEW,
973 info->snd_portid, info->snd_seq, 0);
974 if (err) {
975 nlmsg_free(msg);
976 return err;
977 }
978
979 return genlmsg_reply(msg, info);
980}
981
982static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
983 struct devlink *devlink,
984 struct devlink_sb *devlink_sb,
985 u32 portid, u32 seq)
986{
987 u16 pool_count = devlink_sb_pool_count(devlink_sb);
988 u16 pool_index;
989 int err;
990
991 for (pool_index = 0; pool_index < pool_count; pool_index++) {
992 if (*p_idx < start) {
993 (*p_idx)++;
994 continue;
995 }
996 err = devlink_nl_sb_pool_fill(msg, devlink,
997 devlink_sb,
998 pool_index,
999 DEVLINK_CMD_SB_POOL_NEW,
1000 portid, seq, NLM_F_MULTI);
1001 if (err)
1002 return err;
1003 (*p_idx)++;
1004 }
1005 return 0;
1006}
1007
1008static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1009 struct netlink_callback *cb)
1010{
1011 struct devlink *devlink;
1012 struct devlink_sb *devlink_sb;
1013 int start = cb->args[0];
1014 int idx = 0;
1015 int err;
1016
1017 mutex_lock(&devlink_mutex);
1018 list_for_each_entry(devlink, &devlink_list, list) {
1019 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1020 !devlink->ops || !devlink->ops->sb_pool_get)
1021 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001022 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001023 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1024 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1025 devlink_sb,
1026 NETLINK_CB(cb->skb).portid,
1027 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001028 if (err && err != -EOPNOTSUPP) {
1029 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001030 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001031 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001032 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001033 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001034 }
1035out:
1036 mutex_unlock(&devlink_mutex);
1037
1038 cb->args[0] = idx;
1039 return msg->len;
1040}
1041
1042static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1043 u16 pool_index, u32 size,
1044 enum devlink_sb_threshold_type threshold_type)
1045
1046{
1047 const struct devlink_ops *ops = devlink->ops;
1048
1049 if (ops && ops->sb_pool_set)
1050 return ops->sb_pool_set(devlink, sb_index, pool_index,
1051 size, threshold_type);
1052 return -EOPNOTSUPP;
1053}
1054
1055static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1056 struct genl_info *info)
1057{
1058 struct devlink *devlink = info->user_ptr[0];
1059 struct devlink_sb *devlink_sb = info->user_ptr[1];
1060 enum devlink_sb_threshold_type threshold_type;
1061 u16 pool_index;
1062 u32 size;
1063 int err;
1064
1065 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1066 &pool_index);
1067 if (err)
1068 return err;
1069
1070 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1071 if (err)
1072 return err;
1073
1074 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1075 return -EINVAL;
1076
1077 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1078 return devlink_sb_pool_set(devlink, devlink_sb->index,
1079 pool_index, size, threshold_type);
1080}
1081
1082static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1083 struct devlink *devlink,
1084 struct devlink_port *devlink_port,
1085 struct devlink_sb *devlink_sb,
1086 u16 pool_index,
1087 enum devlink_command cmd,
1088 u32 portid, u32 seq, int flags)
1089{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001090 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001091 u32 threshold;
1092 void *hdr;
1093 int err;
1094
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001095 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1096 pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001097 if (err)
1098 return err;
1099
1100 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1101 if (!hdr)
1102 return -EMSGSIZE;
1103
1104 if (devlink_nl_put_handle(msg, devlink))
1105 goto nla_put_failure;
1106 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1107 goto nla_put_failure;
1108 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1109 goto nla_put_failure;
1110 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1111 goto nla_put_failure;
1112 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1113 goto nla_put_failure;
1114
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001115 if (ops->sb_occ_port_pool_get) {
1116 u32 cur;
1117 u32 max;
1118
1119 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1120 pool_index, &cur, &max);
1121 if (err && err != -EOPNOTSUPP)
1122 return err;
1123 if (!err) {
1124 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1125 goto nla_put_failure;
1126 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1127 goto nla_put_failure;
1128 }
1129 }
1130
Jiri Pirkobf797472016-04-14 18:19:13 +02001131 genlmsg_end(msg, hdr);
1132 return 0;
1133
1134nla_put_failure:
1135 genlmsg_cancel(msg, hdr);
1136 return -EMSGSIZE;
1137}
1138
1139static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1140 struct genl_info *info)
1141{
1142 struct devlink_port *devlink_port = info->user_ptr[0];
1143 struct devlink *devlink = devlink_port->devlink;
1144 struct devlink_sb *devlink_sb = info->user_ptr[1];
1145 struct sk_buff *msg;
1146 u16 pool_index;
1147 int err;
1148
1149 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1150 &pool_index);
1151 if (err)
1152 return err;
1153
1154 if (!devlink->ops || !devlink->ops->sb_port_pool_get)
1155 return -EOPNOTSUPP;
1156
1157 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1158 if (!msg)
1159 return -ENOMEM;
1160
1161 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1162 devlink_sb, pool_index,
1163 DEVLINK_CMD_SB_PORT_POOL_NEW,
1164 info->snd_portid, info->snd_seq, 0);
1165 if (err) {
1166 nlmsg_free(msg);
1167 return err;
1168 }
1169
1170 return genlmsg_reply(msg, info);
1171}
1172
1173static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1174 struct devlink *devlink,
1175 struct devlink_sb *devlink_sb,
1176 u32 portid, u32 seq)
1177{
1178 struct devlink_port *devlink_port;
1179 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1180 u16 pool_index;
1181 int err;
1182
1183 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1184 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1185 if (*p_idx < start) {
1186 (*p_idx)++;
1187 continue;
1188 }
1189 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1190 devlink_port,
1191 devlink_sb,
1192 pool_index,
1193 DEVLINK_CMD_SB_PORT_POOL_NEW,
1194 portid, seq,
1195 NLM_F_MULTI);
1196 if (err)
1197 return err;
1198 (*p_idx)++;
1199 }
1200 }
1201 return 0;
1202}
1203
1204static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1205 struct netlink_callback *cb)
1206{
1207 struct devlink *devlink;
1208 struct devlink_sb *devlink_sb;
1209 int start = cb->args[0];
1210 int idx = 0;
1211 int err;
1212
1213 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001214 list_for_each_entry(devlink, &devlink_list, list) {
1215 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1216 !devlink->ops || !devlink->ops->sb_port_pool_get)
1217 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001218 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001219 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1220 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1221 devlink, devlink_sb,
1222 NETLINK_CB(cb->skb).portid,
1223 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001224 if (err && err != -EOPNOTSUPP) {
1225 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001226 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001227 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001228 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001229 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001230 }
1231out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001232 mutex_unlock(&devlink_mutex);
1233
1234 cb->args[0] = idx;
1235 return msg->len;
1236}
1237
1238static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1239 unsigned int sb_index, u16 pool_index,
1240 u32 threshold)
1241
1242{
1243 const struct devlink_ops *ops = devlink_port->devlink->ops;
1244
1245 if (ops && ops->sb_port_pool_set)
1246 return ops->sb_port_pool_set(devlink_port, sb_index,
1247 pool_index, threshold);
1248 return -EOPNOTSUPP;
1249}
1250
1251static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1252 struct genl_info *info)
1253{
1254 struct devlink_port *devlink_port = info->user_ptr[0];
1255 struct devlink_sb *devlink_sb = info->user_ptr[1];
1256 u16 pool_index;
1257 u32 threshold;
1258 int err;
1259
1260 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1261 &pool_index);
1262 if (err)
1263 return err;
1264
1265 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1266 return -EINVAL;
1267
1268 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1269 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
1270 pool_index, threshold);
1271}
1272
1273static int
1274devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1275 struct devlink_port *devlink_port,
1276 struct devlink_sb *devlink_sb, u16 tc_index,
1277 enum devlink_sb_pool_type pool_type,
1278 enum devlink_command cmd,
1279 u32 portid, u32 seq, int flags)
1280{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001281 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001282 u16 pool_index;
1283 u32 threshold;
1284 void *hdr;
1285 int err;
1286
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001287 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1288 tc_index, pool_type,
1289 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001290 if (err)
1291 return err;
1292
1293 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1294 if (!hdr)
1295 return -EMSGSIZE;
1296
1297 if (devlink_nl_put_handle(msg, devlink))
1298 goto nla_put_failure;
1299 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1300 goto nla_put_failure;
1301 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1302 goto nla_put_failure;
1303 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1304 goto nla_put_failure;
1305 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1306 goto nla_put_failure;
1307 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1308 goto nla_put_failure;
1309 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1310 goto nla_put_failure;
1311
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001312 if (ops->sb_occ_tc_port_bind_get) {
1313 u32 cur;
1314 u32 max;
1315
1316 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1317 devlink_sb->index,
1318 tc_index, pool_type,
1319 &cur, &max);
1320 if (err && err != -EOPNOTSUPP)
1321 return err;
1322 if (!err) {
1323 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1324 goto nla_put_failure;
1325 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1326 goto nla_put_failure;
1327 }
1328 }
1329
Jiri Pirkobf797472016-04-14 18:19:13 +02001330 genlmsg_end(msg, hdr);
1331 return 0;
1332
1333nla_put_failure:
1334 genlmsg_cancel(msg, hdr);
1335 return -EMSGSIZE;
1336}
1337
1338static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1339 struct genl_info *info)
1340{
1341 struct devlink_port *devlink_port = info->user_ptr[0];
1342 struct devlink *devlink = devlink_port->devlink;
1343 struct devlink_sb *devlink_sb = info->user_ptr[1];
1344 struct sk_buff *msg;
1345 enum devlink_sb_pool_type pool_type;
1346 u16 tc_index;
1347 int err;
1348
1349 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1350 if (err)
1351 return err;
1352
1353 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1354 pool_type, &tc_index);
1355 if (err)
1356 return err;
1357
1358 if (!devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
1359 return -EOPNOTSUPP;
1360
1361 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1362 if (!msg)
1363 return -ENOMEM;
1364
1365 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1366 devlink_sb, tc_index, pool_type,
1367 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1368 info->snd_portid,
1369 info->snd_seq, 0);
1370 if (err) {
1371 nlmsg_free(msg);
1372 return err;
1373 }
1374
1375 return genlmsg_reply(msg, info);
1376}
1377
1378static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1379 int start, int *p_idx,
1380 struct devlink *devlink,
1381 struct devlink_sb *devlink_sb,
1382 u32 portid, u32 seq)
1383{
1384 struct devlink_port *devlink_port;
1385 u16 tc_index;
1386 int err;
1387
1388 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1389 for (tc_index = 0;
1390 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1391 if (*p_idx < start) {
1392 (*p_idx)++;
1393 continue;
1394 }
1395 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1396 devlink_port,
1397 devlink_sb,
1398 tc_index,
1399 DEVLINK_SB_POOL_TYPE_INGRESS,
1400 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1401 portid, seq,
1402 NLM_F_MULTI);
1403 if (err)
1404 return err;
1405 (*p_idx)++;
1406 }
1407 for (tc_index = 0;
1408 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1409 if (*p_idx < start) {
1410 (*p_idx)++;
1411 continue;
1412 }
1413 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1414 devlink_port,
1415 devlink_sb,
1416 tc_index,
1417 DEVLINK_SB_POOL_TYPE_EGRESS,
1418 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1419 portid, seq,
1420 NLM_F_MULTI);
1421 if (err)
1422 return err;
1423 (*p_idx)++;
1424 }
1425 }
1426 return 0;
1427}
1428
1429static int
1430devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1431 struct netlink_callback *cb)
1432{
1433 struct devlink *devlink;
1434 struct devlink_sb *devlink_sb;
1435 int start = cb->args[0];
1436 int idx = 0;
1437 int err;
1438
1439 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001440 list_for_each_entry(devlink, &devlink_list, list) {
1441 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1442 !devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
1443 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001444
1445 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001446 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1447 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1448 devlink,
1449 devlink_sb,
1450 NETLINK_CB(cb->skb).portid,
1451 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001452 if (err && err != -EOPNOTSUPP) {
1453 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001454 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001455 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001456 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001457 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001458 }
1459out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001460 mutex_unlock(&devlink_mutex);
1461
1462 cb->args[0] = idx;
1463 return msg->len;
1464}
1465
1466static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1467 unsigned int sb_index, u16 tc_index,
1468 enum devlink_sb_pool_type pool_type,
1469 u16 pool_index, u32 threshold)
1470
1471{
1472 const struct devlink_ops *ops = devlink_port->devlink->ops;
1473
1474 if (ops && ops->sb_tc_pool_bind_set)
1475 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1476 tc_index, pool_type,
1477 pool_index, threshold);
1478 return -EOPNOTSUPP;
1479}
1480
1481static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1482 struct genl_info *info)
1483{
1484 struct devlink_port *devlink_port = info->user_ptr[0];
1485 struct devlink_sb *devlink_sb = info->user_ptr[1];
1486 enum devlink_sb_pool_type pool_type;
1487 u16 tc_index;
1488 u16 pool_index;
1489 u32 threshold;
1490 int err;
1491
1492 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1493 if (err)
1494 return err;
1495
1496 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1497 pool_type, &tc_index);
1498 if (err)
1499 return err;
1500
1501 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1502 &pool_index);
1503 if (err)
1504 return err;
1505
1506 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1507 return -EINVAL;
1508
1509 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1510 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1511 tc_index, pool_type,
1512 pool_index, threshold);
1513}
1514
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001515static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1516 struct genl_info *info)
1517{
1518 struct devlink *devlink = info->user_ptr[0];
1519 struct devlink_sb *devlink_sb = info->user_ptr[1];
1520 const struct devlink_ops *ops = devlink->ops;
1521
1522 if (ops && ops->sb_occ_snapshot)
1523 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1524 return -EOPNOTSUPP;
1525}
1526
1527static int devlink_nl_cmd_sb_occ_max_clear_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
1534 if (ops && ops->sb_occ_max_clear)
1535 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1536 return -EOPNOTSUPP;
1537}
1538
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001539static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1540 enum devlink_command cmd, u32 portid,
1541 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001542{
Roi Dayan59bfde02016-11-22 23:09:57 +02001543 const struct devlink_ops *ops = devlink->ops;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001544 u8 inline_mode, encap_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001545 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001546 int err = 0;
1547 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001548
1549 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1550 if (!hdr)
1551 return -EMSGSIZE;
1552
Roi Dayan59bfde02016-11-22 23:09:57 +02001553 err = devlink_nl_put_handle(msg, devlink);
1554 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001555 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001556
Jiri Pirko4456f612017-02-09 15:54:36 +01001557 if (ops->eswitch_mode_get) {
1558 err = ops->eswitch_mode_get(devlink, &mode);
1559 if (err)
1560 goto nla_put_failure;
1561 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1562 if (err)
1563 goto nla_put_failure;
1564 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001565
1566 if (ops->eswitch_inline_mode_get) {
1567 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1568 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001569 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001570 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1571 inline_mode);
1572 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001573 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001574 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001575
Roi Dayanf43e9b02016-09-25 13:52:44 +03001576 if (ops->eswitch_encap_mode_get) {
1577 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1578 if (err)
1579 goto nla_put_failure;
1580 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1581 if (err)
1582 goto nla_put_failure;
1583 }
1584
Or Gerlitz08f4b592016-07-01 14:51:01 +03001585 genlmsg_end(msg, hdr);
1586 return 0;
1587
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001588nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001589 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001590 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001591}
1592
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001593static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1594 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001595{
1596 struct devlink *devlink = info->user_ptr[0];
1597 const struct devlink_ops *ops = devlink->ops;
1598 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001599 int err;
1600
Jiri Pirko4456f612017-02-09 15:54:36 +01001601 if (!ops)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001602 return -EOPNOTSUPP;
1603
Or Gerlitz08f4b592016-07-01 14:51:01 +03001604 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1605 if (!msg)
1606 return -ENOMEM;
1607
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001608 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1609 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001610
1611 if (err) {
1612 nlmsg_free(msg);
1613 return err;
1614 }
1615
1616 return genlmsg_reply(msg, info);
1617}
1618
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001619static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1620 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001621{
1622 struct devlink *devlink = info->user_ptr[0];
1623 const struct devlink_ops *ops = devlink->ops;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001624 u8 inline_mode, encap_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001625 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001626 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001627
Roi Dayan59bfde02016-11-22 23:09:57 +02001628 if (!ops)
1629 return -EOPNOTSUPP;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001630
Roi Dayan59bfde02016-11-22 23:09:57 +02001631 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1632 if (!ops->eswitch_mode_set)
1633 return -EOPNOTSUPP;
1634 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001635 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001636 if (err)
1637 return err;
1638 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001639
Roi Dayan59bfde02016-11-22 23:09:57 +02001640 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1641 if (!ops->eswitch_inline_mode_set)
1642 return -EOPNOTSUPP;
1643 inline_mode = nla_get_u8(
1644 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001645 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1646 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001647 if (err)
1648 return err;
1649 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03001650
1651 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1652 if (!ops->eswitch_encap_mode_set)
1653 return -EOPNOTSUPP;
1654 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001655 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1656 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03001657 if (err)
1658 return err;
1659 }
1660
Roi Dayan59bfde02016-11-22 23:09:57 +02001661 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001662}
1663
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001664int devlink_dpipe_match_put(struct sk_buff *skb,
1665 struct devlink_dpipe_match *match)
1666{
1667 struct devlink_dpipe_header *header = match->header;
1668 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1669 struct nlattr *match_attr;
1670
1671 match_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_MATCH);
1672 if (!match_attr)
1673 return -EMSGSIZE;
1674
1675 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1676 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1677 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1678 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1679 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1680 goto nla_put_failure;
1681
1682 nla_nest_end(skb, match_attr);
1683 return 0;
1684
1685nla_put_failure:
1686 nla_nest_cancel(skb, match_attr);
1687 return -EMSGSIZE;
1688}
1689EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1690
1691static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1692 struct sk_buff *skb)
1693{
1694 struct nlattr *matches_attr;
1695
1696 matches_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
1697 if (!matches_attr)
1698 return -EMSGSIZE;
1699
1700 if (table->table_ops->matches_dump(table->priv, skb))
1701 goto nla_put_failure;
1702
1703 nla_nest_end(skb, matches_attr);
1704 return 0;
1705
1706nla_put_failure:
1707 nla_nest_cancel(skb, matches_attr);
1708 return -EMSGSIZE;
1709}
1710
1711int devlink_dpipe_action_put(struct sk_buff *skb,
1712 struct devlink_dpipe_action *action)
1713{
1714 struct devlink_dpipe_header *header = action->header;
1715 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1716 struct nlattr *action_attr;
1717
1718 action_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ACTION);
1719 if (!action_attr)
1720 return -EMSGSIZE;
1721
1722 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1723 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1724 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1725 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1726 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1727 goto nla_put_failure;
1728
1729 nla_nest_end(skb, action_attr);
1730 return 0;
1731
1732nla_put_failure:
1733 nla_nest_cancel(skb, action_attr);
1734 return -EMSGSIZE;
1735}
1736EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1737
1738static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1739 struct sk_buff *skb)
1740{
1741 struct nlattr *actions_attr;
1742
1743 actions_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
1744 if (!actions_attr)
1745 return -EMSGSIZE;
1746
1747 if (table->table_ops->actions_dump(table->priv, skb))
1748 goto nla_put_failure;
1749
1750 nla_nest_end(skb, actions_attr);
1751 return 0;
1752
1753nla_put_failure:
1754 nla_nest_cancel(skb, actions_attr);
1755 return -EMSGSIZE;
1756}
1757
1758static int devlink_dpipe_table_put(struct sk_buff *skb,
1759 struct devlink_dpipe_table *table)
1760{
1761 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001762 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001763
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001764 table_size = table->table_ops->size_get(table->priv);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001765 table_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE);
1766 if (!table_attr)
1767 return -EMSGSIZE;
1768
1769 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001770 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001771 DEVLINK_ATTR_PAD))
1772 goto nla_put_failure;
1773 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1774 table->counters_enabled))
1775 goto nla_put_failure;
1776
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001777 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02001778 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1779 table->resource_id, DEVLINK_ATTR_PAD) ||
1780 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1781 table->resource_units, DEVLINK_ATTR_PAD))
1782 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001783 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001784 if (devlink_dpipe_matches_put(table, skb))
1785 goto nla_put_failure;
1786
1787 if (devlink_dpipe_actions_put(table, skb))
1788 goto nla_put_failure;
1789
1790 nla_nest_end(skb, table_attr);
1791 return 0;
1792
1793nla_put_failure:
1794 nla_nest_cancel(skb, table_attr);
1795 return -EMSGSIZE;
1796}
1797
1798static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1799 struct genl_info *info)
1800{
1801 int err;
1802
1803 if (*pskb) {
1804 err = genlmsg_reply(*pskb, info);
1805 if (err)
1806 return err;
1807 }
1808 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1809 if (!*pskb)
1810 return -ENOMEM;
1811 return 0;
1812}
1813
1814static int devlink_dpipe_tables_fill(struct genl_info *info,
1815 enum devlink_command cmd, int flags,
1816 struct list_head *dpipe_tables,
1817 const char *table_name)
1818{
1819 struct devlink *devlink = info->user_ptr[0];
1820 struct devlink_dpipe_table *table;
1821 struct nlattr *tables_attr;
1822 struct sk_buff *skb = NULL;
1823 struct nlmsghdr *nlh;
1824 bool incomplete;
1825 void *hdr;
1826 int i;
1827 int err;
1828
1829 table = list_first_entry(dpipe_tables,
1830 struct devlink_dpipe_table, list);
1831start_again:
1832 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1833 if (err)
1834 return err;
1835
1836 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1837 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08001838 if (!hdr) {
1839 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001840 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08001841 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001842
1843 if (devlink_nl_put_handle(skb, devlink))
1844 goto nla_put_failure;
1845 tables_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLES);
1846 if (!tables_attr)
1847 goto nla_put_failure;
1848
1849 i = 0;
1850 incomplete = false;
1851 list_for_each_entry_from(table, dpipe_tables, list) {
1852 if (!table_name) {
1853 err = devlink_dpipe_table_put(skb, table);
1854 if (err) {
1855 if (!i)
1856 goto err_table_put;
1857 incomplete = true;
1858 break;
1859 }
1860 } else {
1861 if (!strcmp(table->name, table_name)) {
1862 err = devlink_dpipe_table_put(skb, table);
1863 if (err)
1864 break;
1865 }
1866 }
1867 i++;
1868 }
1869
1870 nla_nest_end(skb, tables_attr);
1871 genlmsg_end(skb, hdr);
1872 if (incomplete)
1873 goto start_again;
1874
1875send_done:
1876 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1877 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1878 if (!nlh) {
1879 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1880 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02001881 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001882 goto send_done;
1883 }
1884
1885 return genlmsg_reply(skb, info);
1886
1887nla_put_failure:
1888 err = -EMSGSIZE;
1889err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001890 nlmsg_free(skb);
1891 return err;
1892}
1893
1894static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
1895 struct genl_info *info)
1896{
1897 struct devlink *devlink = info->user_ptr[0];
1898 const char *table_name = NULL;
1899
1900 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
1901 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
1902
1903 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
1904 &devlink->dpipe_table_list,
1905 table_name);
1906}
1907
1908static int devlink_dpipe_value_put(struct sk_buff *skb,
1909 struct devlink_dpipe_value *value)
1910{
1911 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
1912 value->value_size, value->value))
1913 return -EMSGSIZE;
1914 if (value->mask)
1915 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
1916 value->value_size, value->mask))
1917 return -EMSGSIZE;
1918 if (value->mapping_valid)
1919 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
1920 value->mapping_value))
1921 return -EMSGSIZE;
1922 return 0;
1923}
1924
1925static int devlink_dpipe_action_value_put(struct sk_buff *skb,
1926 struct devlink_dpipe_value *value)
1927{
1928 if (!value->action)
1929 return -EINVAL;
1930 if (devlink_dpipe_action_put(skb, value->action))
1931 return -EMSGSIZE;
1932 if (devlink_dpipe_value_put(skb, value))
1933 return -EMSGSIZE;
1934 return 0;
1935}
1936
1937static int devlink_dpipe_action_values_put(struct sk_buff *skb,
1938 struct devlink_dpipe_value *values,
1939 unsigned int values_count)
1940{
1941 struct nlattr *action_attr;
1942 int i;
1943 int err;
1944
1945 for (i = 0; i < values_count; i++) {
1946 action_attr = nla_nest_start(skb,
1947 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
1948 if (!action_attr)
1949 return -EMSGSIZE;
1950 err = devlink_dpipe_action_value_put(skb, &values[i]);
1951 if (err)
1952 goto err_action_value_put;
1953 nla_nest_end(skb, action_attr);
1954 }
1955 return 0;
1956
1957err_action_value_put:
1958 nla_nest_cancel(skb, action_attr);
1959 return err;
1960}
1961
1962static int devlink_dpipe_match_value_put(struct sk_buff *skb,
1963 struct devlink_dpipe_value *value)
1964{
1965 if (!value->match)
1966 return -EINVAL;
1967 if (devlink_dpipe_match_put(skb, value->match))
1968 return -EMSGSIZE;
1969 if (devlink_dpipe_value_put(skb, value))
1970 return -EMSGSIZE;
1971 return 0;
1972}
1973
1974static int devlink_dpipe_match_values_put(struct sk_buff *skb,
1975 struct devlink_dpipe_value *values,
1976 unsigned int values_count)
1977{
1978 struct nlattr *match_attr;
1979 int i;
1980 int err;
1981
1982 for (i = 0; i < values_count; i++) {
1983 match_attr = nla_nest_start(skb,
1984 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
1985 if (!match_attr)
1986 return -EMSGSIZE;
1987 err = devlink_dpipe_match_value_put(skb, &values[i]);
1988 if (err)
1989 goto err_match_value_put;
1990 nla_nest_end(skb, match_attr);
1991 }
1992 return 0;
1993
1994err_match_value_put:
1995 nla_nest_cancel(skb, match_attr);
1996 return err;
1997}
1998
1999static int devlink_dpipe_entry_put(struct sk_buff *skb,
2000 struct devlink_dpipe_entry *entry)
2001{
2002 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2003 int err;
2004
2005 entry_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ENTRY);
2006 if (!entry_attr)
2007 return -EMSGSIZE;
2008
2009 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2010 DEVLINK_ATTR_PAD))
2011 goto nla_put_failure;
2012 if (entry->counter_valid)
2013 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2014 entry->counter, DEVLINK_ATTR_PAD))
2015 goto nla_put_failure;
2016
2017 matches_attr = nla_nest_start(skb,
2018 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
2019 if (!matches_attr)
2020 goto nla_put_failure;
2021
2022 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2023 entry->match_values_count);
2024 if (err) {
2025 nla_nest_cancel(skb, matches_attr);
2026 goto err_match_values_put;
2027 }
2028 nla_nest_end(skb, matches_attr);
2029
2030 actions_attr = nla_nest_start(skb,
2031 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
2032 if (!actions_attr)
2033 goto nla_put_failure;
2034
2035 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2036 entry->action_values_count);
2037 if (err) {
2038 nla_nest_cancel(skb, actions_attr);
2039 goto err_action_values_put;
2040 }
2041 nla_nest_end(skb, actions_attr);
2042
2043 nla_nest_end(skb, entry_attr);
2044 return 0;
2045
2046nla_put_failure:
2047 err = -EMSGSIZE;
2048err_match_values_put:
2049err_action_values_put:
2050 nla_nest_cancel(skb, entry_attr);
2051 return err;
2052}
2053
2054static struct devlink_dpipe_table *
2055devlink_dpipe_table_find(struct list_head *dpipe_tables,
2056 const char *table_name)
2057{
2058 struct devlink_dpipe_table *table;
2059
2060 list_for_each_entry_rcu(table, dpipe_tables, list) {
2061 if (!strcmp(table->name, table_name))
2062 return table;
2063 }
2064 return NULL;
2065}
2066
2067int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2068{
2069 struct devlink *devlink;
2070 int err;
2071
2072 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2073 dump_ctx->info);
2074 if (err)
2075 return err;
2076
2077 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2078 dump_ctx->info->snd_portid,
2079 dump_ctx->info->snd_seq,
2080 &devlink_nl_family, NLM_F_MULTI,
2081 dump_ctx->cmd);
2082 if (!dump_ctx->hdr)
2083 goto nla_put_failure;
2084
2085 devlink = dump_ctx->info->user_ptr[0];
2086 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2087 goto nla_put_failure;
2088 dump_ctx->nest = nla_nest_start(dump_ctx->skb,
2089 DEVLINK_ATTR_DPIPE_ENTRIES);
2090 if (!dump_ctx->nest)
2091 goto nla_put_failure;
2092 return 0;
2093
2094nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002095 nlmsg_free(dump_ctx->skb);
2096 return -EMSGSIZE;
2097}
2098EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2099
2100int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2101 struct devlink_dpipe_entry *entry)
2102{
2103 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2104}
2105EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2106
2107int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2108{
2109 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2110 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2111 return 0;
2112}
2113EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2114
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002115void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2116
2117{
2118 unsigned int value_count, value_index;
2119 struct devlink_dpipe_value *value;
2120
2121 value = entry->action_values;
2122 value_count = entry->action_values_count;
2123 for (value_index = 0; value_index < value_count; value_index++) {
2124 kfree(value[value_index].value);
2125 kfree(value[value_index].mask);
2126 }
2127
2128 value = entry->match_values;
2129 value_count = entry->match_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}
2135EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2136
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002137static int devlink_dpipe_entries_fill(struct genl_info *info,
2138 enum devlink_command cmd, int flags,
2139 struct devlink_dpipe_table *table)
2140{
2141 struct devlink_dpipe_dump_ctx dump_ctx;
2142 struct nlmsghdr *nlh;
2143 int err;
2144
2145 dump_ctx.skb = NULL;
2146 dump_ctx.cmd = cmd;
2147 dump_ctx.info = info;
2148
2149 err = table->table_ops->entries_dump(table->priv,
2150 table->counters_enabled,
2151 &dump_ctx);
2152 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002153 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002154
2155send_done:
2156 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2157 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2158 if (!nlh) {
2159 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2160 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002161 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002162 goto send_done;
2163 }
2164 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002165}
2166
2167static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2168 struct genl_info *info)
2169{
2170 struct devlink *devlink = info->user_ptr[0];
2171 struct devlink_dpipe_table *table;
2172 const char *table_name;
2173
2174 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2175 return -EINVAL;
2176
2177 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2178 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2179 table_name);
2180 if (!table)
2181 return -EINVAL;
2182
2183 if (!table->table_ops->entries_dump)
2184 return -EINVAL;
2185
2186 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2187 0, table);
2188}
2189
2190static int devlink_dpipe_fields_put(struct sk_buff *skb,
2191 const struct devlink_dpipe_header *header)
2192{
2193 struct devlink_dpipe_field *field;
2194 struct nlattr *field_attr;
2195 int i;
2196
2197 for (i = 0; i < header->fields_count; i++) {
2198 field = &header->fields[i];
2199 field_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_FIELD);
2200 if (!field_attr)
2201 return -EMSGSIZE;
2202 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2203 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2204 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2205 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2206 goto nla_put_failure;
2207 nla_nest_end(skb, field_attr);
2208 }
2209 return 0;
2210
2211nla_put_failure:
2212 nla_nest_cancel(skb, field_attr);
2213 return -EMSGSIZE;
2214}
2215
2216static int devlink_dpipe_header_put(struct sk_buff *skb,
2217 struct devlink_dpipe_header *header)
2218{
2219 struct nlattr *fields_attr, *header_attr;
2220 int err;
2221
2222 header_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002223 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002224 return -EMSGSIZE;
2225
2226 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2227 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2228 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2229 goto nla_put_failure;
2230
2231 fields_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
2232 if (!fields_attr)
2233 goto nla_put_failure;
2234
2235 err = devlink_dpipe_fields_put(skb, header);
2236 if (err) {
2237 nla_nest_cancel(skb, fields_attr);
2238 goto nla_put_failure;
2239 }
2240 nla_nest_end(skb, fields_attr);
2241 nla_nest_end(skb, header_attr);
2242 return 0;
2243
2244nla_put_failure:
2245 err = -EMSGSIZE;
2246 nla_nest_cancel(skb, header_attr);
2247 return err;
2248}
2249
2250static int devlink_dpipe_headers_fill(struct genl_info *info,
2251 enum devlink_command cmd, int flags,
2252 struct devlink_dpipe_headers *
2253 dpipe_headers)
2254{
2255 struct devlink *devlink = info->user_ptr[0];
2256 struct nlattr *headers_attr;
2257 struct sk_buff *skb = NULL;
2258 struct nlmsghdr *nlh;
2259 void *hdr;
2260 int i, j;
2261 int err;
2262
2263 i = 0;
2264start_again:
2265 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2266 if (err)
2267 return err;
2268
2269 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2270 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002271 if (!hdr) {
2272 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002273 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002274 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002275
2276 if (devlink_nl_put_handle(skb, devlink))
2277 goto nla_put_failure;
2278 headers_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADERS);
2279 if (!headers_attr)
2280 goto nla_put_failure;
2281
2282 j = 0;
2283 for (; i < dpipe_headers->headers_count; i++) {
2284 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2285 if (err) {
2286 if (!j)
2287 goto err_table_put;
2288 break;
2289 }
2290 j++;
2291 }
2292 nla_nest_end(skb, headers_attr);
2293 genlmsg_end(skb, hdr);
2294 if (i != dpipe_headers->headers_count)
2295 goto start_again;
2296
2297send_done:
2298 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2299 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2300 if (!nlh) {
2301 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2302 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002303 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002304 goto send_done;
2305 }
2306 return genlmsg_reply(skb, info);
2307
2308nla_put_failure:
2309 err = -EMSGSIZE;
2310err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002311 nlmsg_free(skb);
2312 return err;
2313}
2314
2315static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2316 struct genl_info *info)
2317{
2318 struct devlink *devlink = info->user_ptr[0];
2319
2320 if (!devlink->dpipe_headers)
2321 return -EOPNOTSUPP;
2322 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2323 0, devlink->dpipe_headers);
2324}
2325
2326static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2327 const char *table_name,
2328 bool enable)
2329{
2330 struct devlink_dpipe_table *table;
2331
2332 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2333 table_name);
2334 if (!table)
2335 return -EINVAL;
2336
2337 if (table->counter_control_extern)
2338 return -EOPNOTSUPP;
2339
2340 if (!(table->counters_enabled ^ enable))
2341 return 0;
2342
2343 table->counters_enabled = enable;
2344 if (table->table_ops->counters_set_update)
2345 table->table_ops->counters_set_update(table->priv, enable);
2346 return 0;
2347}
2348
2349static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2350 struct genl_info *info)
2351{
2352 struct devlink *devlink = info->user_ptr[0];
2353 const char *table_name;
2354 bool counters_enable;
2355
2356 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2357 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2358 return -EINVAL;
2359
2360 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2361 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2362
2363 return devlink_dpipe_table_counters_set(devlink, table_name,
2364 counters_enable);
2365}
2366
Wei Yongjun43dd7512018-01-17 03:27:42 +00002367static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002368devlink_resource_find(struct devlink *devlink,
2369 struct devlink_resource *resource, u64 resource_id)
2370{
2371 struct list_head *resource_list;
2372
2373 if (resource)
2374 resource_list = &resource->resource_list;
2375 else
2376 resource_list = &devlink->resource_list;
2377
2378 list_for_each_entry(resource, resource_list, list) {
2379 struct devlink_resource *child_resource;
2380
2381 if (resource->id == resource_id)
2382 return resource;
2383
2384 child_resource = devlink_resource_find(devlink, resource,
2385 resource_id);
2386 if (child_resource)
2387 return child_resource;
2388 }
2389 return NULL;
2390}
2391
Wei Yongjun43dd7512018-01-17 03:27:42 +00002392static void
2393devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002394{
2395 struct devlink_resource *child_resource;
2396 bool size_valid = true;
2397 u64 parts_size = 0;
2398
2399 if (list_empty(&resource->resource_list))
2400 goto out;
2401
2402 list_for_each_entry(child_resource, &resource->resource_list, list)
2403 parts_size += child_resource->size_new;
2404
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002405 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002406 size_valid = false;
2407out:
2408 resource->size_valid = size_valid;
2409}
2410
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002411static int
2412devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2413 struct netlink_ext_ack *extack)
2414{
2415 u64 reminder;
2416 int err = 0;
2417
David S. Miller0f3e9c92018-03-06 00:53:44 -05002418 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002419 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2420 err = -EINVAL;
2421 }
2422
David S. Miller0f3e9c92018-03-06 00:53:44 -05002423 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002424 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2425 err = -EINVAL;
2426 }
2427
David S. Miller0f3e9c92018-03-06 00:53:44 -05002428 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002429 if (reminder) {
2430 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2431 err = -EINVAL;
2432 }
2433
2434 return err;
2435}
2436
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002437static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2438 struct genl_info *info)
2439{
2440 struct devlink *devlink = info->user_ptr[0];
2441 struct devlink_resource *resource;
2442 u64 resource_id;
2443 u64 size;
2444 int err;
2445
2446 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2447 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2448 return -EINVAL;
2449 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2450
2451 resource = devlink_resource_find(devlink, NULL, resource_id);
2452 if (!resource)
2453 return -EINVAL;
2454
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002455 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002456 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002457 if (err)
2458 return err;
2459
2460 resource->size_new = size;
2461 devlink_resource_validate_children(resource);
2462 if (resource->parent)
2463 devlink_resource_validate_children(resource->parent);
2464 return 0;
2465}
2466
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002467static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002468devlink_resource_size_params_put(struct devlink_resource *resource,
2469 struct sk_buff *skb)
2470{
2471 struct devlink_resource_size_params *size_params;
2472
Jiri Pirko77d27092018-02-28 13:12:09 +01002473 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002474 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2475 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2476 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2477 size_params->size_max, DEVLINK_ATTR_PAD) ||
2478 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2479 size_params->size_min, DEVLINK_ATTR_PAD) ||
2480 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2481 return -EMSGSIZE;
2482 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002483}
2484
Jiri Pirkofc56be42018-04-05 22:13:21 +02002485static int devlink_resource_occ_put(struct devlink_resource *resource,
2486 struct sk_buff *skb)
2487{
2488 if (!resource->occ_get)
2489 return 0;
2490 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2491 resource->occ_get(resource->occ_get_priv),
2492 DEVLINK_ATTR_PAD);
2493}
2494
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002495static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2496 struct devlink_resource *resource)
2497{
2498 struct devlink_resource *child_resource;
2499 struct nlattr *child_resource_attr;
2500 struct nlattr *resource_attr;
2501
2502 resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE);
2503 if (!resource_attr)
2504 return -EMSGSIZE;
2505
2506 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2507 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2508 DEVLINK_ATTR_PAD) ||
2509 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2510 DEVLINK_ATTR_PAD))
2511 goto nla_put_failure;
2512 if (resource->size != resource->size_new)
2513 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2514 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002515 if (devlink_resource_occ_put(resource, skb))
2516 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002517 if (devlink_resource_size_params_put(resource, skb))
2518 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002519 if (list_empty(&resource->resource_list))
2520 goto out;
2521
2522 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2523 resource->size_valid))
2524 goto nla_put_failure;
2525
2526 child_resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2527 if (!child_resource_attr)
2528 goto nla_put_failure;
2529
2530 list_for_each_entry(child_resource, &resource->resource_list, list) {
2531 if (devlink_resource_put(devlink, skb, child_resource))
2532 goto resource_put_failure;
2533 }
2534
2535 nla_nest_end(skb, child_resource_attr);
2536out:
2537 nla_nest_end(skb, resource_attr);
2538 return 0;
2539
2540resource_put_failure:
2541 nla_nest_cancel(skb, child_resource_attr);
2542nla_put_failure:
2543 nla_nest_cancel(skb, resource_attr);
2544 return -EMSGSIZE;
2545}
2546
2547static int devlink_resource_fill(struct genl_info *info,
2548 enum devlink_command cmd, int flags)
2549{
2550 struct devlink *devlink = info->user_ptr[0];
2551 struct devlink_resource *resource;
2552 struct nlattr *resources_attr;
2553 struct sk_buff *skb = NULL;
2554 struct nlmsghdr *nlh;
2555 bool incomplete;
2556 void *hdr;
2557 int i;
2558 int err;
2559
2560 resource = list_first_entry(&devlink->resource_list,
2561 struct devlink_resource, list);
2562start_again:
2563 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2564 if (err)
2565 return err;
2566
2567 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2568 &devlink_nl_family, NLM_F_MULTI, cmd);
2569 if (!hdr) {
2570 nlmsg_free(skb);
2571 return -EMSGSIZE;
2572 }
2573
2574 if (devlink_nl_put_handle(skb, devlink))
2575 goto nla_put_failure;
2576
2577 resources_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2578 if (!resources_attr)
2579 goto nla_put_failure;
2580
2581 incomplete = false;
2582 i = 0;
2583 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2584 err = devlink_resource_put(devlink, skb, resource);
2585 if (err) {
2586 if (!i)
2587 goto err_resource_put;
2588 incomplete = true;
2589 break;
2590 }
2591 i++;
2592 }
2593 nla_nest_end(skb, resources_attr);
2594 genlmsg_end(skb, hdr);
2595 if (incomplete)
2596 goto start_again;
2597send_done:
2598 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2599 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2600 if (!nlh) {
2601 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2602 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002603 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002604 goto send_done;
2605 }
2606 return genlmsg_reply(skb, info);
2607
2608nla_put_failure:
2609 err = -EMSGSIZE;
2610err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002611 nlmsg_free(skb);
2612 return err;
2613}
2614
2615static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2616 struct genl_info *info)
2617{
2618 struct devlink *devlink = info->user_ptr[0];
2619
2620 if (list_empty(&devlink->resource_list))
2621 return -EOPNOTSUPP;
2622
2623 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2624}
2625
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002626static int
2627devlink_resources_validate(struct devlink *devlink,
2628 struct devlink_resource *resource,
2629 struct genl_info *info)
2630{
2631 struct list_head *resource_list;
2632 int err = 0;
2633
2634 if (resource)
2635 resource_list = &resource->resource_list;
2636 else
2637 resource_list = &devlink->resource_list;
2638
2639 list_for_each_entry(resource, resource_list, list) {
2640 if (!resource->size_valid)
2641 return -EINVAL;
2642 err = devlink_resources_validate(devlink, resource, info);
2643 if (err)
2644 return err;
2645 }
2646 return err;
2647}
2648
2649static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2650{
2651 struct devlink *devlink = info->user_ptr[0];
2652 int err;
2653
2654 if (!devlink->ops->reload)
2655 return -EOPNOTSUPP;
2656
2657 err = devlink_resources_validate(devlink, NULL, info);
2658 if (err) {
2659 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2660 return err;
2661 }
David Ahernac0fc8a2018-06-05 08:14:09 -07002662 return devlink->ops->reload(devlink, info->extack);
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002663}
2664
Jakub Kicinski76726cc2019-02-14 13:40:44 -08002665static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
2666 struct genl_info *info)
2667{
2668 struct devlink *devlink = info->user_ptr[0];
2669 const char *file_name, *component;
2670 struct nlattr *nla_component;
2671
2672 if (!devlink->ops->flash_update)
2673 return -EOPNOTSUPP;
2674
2675 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
2676 return -EINVAL;
2677 file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
2678
2679 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
2680 component = nla_component ? nla_data(nla_component) : NULL;
2681
2682 return devlink->ops->flash_update(devlink, file_name, component,
2683 info->extack);
2684}
2685
Moshe Shemesh036467c2018-07-04 14:30:33 +03002686static const struct devlink_param devlink_param_generic[] = {
2687 {
2688 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
2689 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
2690 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
2691 },
2692 {
2693 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
2694 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
2695 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
2696 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03002697 {
2698 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
2699 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
2700 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
2701 },
Alex Veskerf6a698852018-07-12 15:13:17 +03002702 {
2703 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
2704 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
2705 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
2706 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05302707 {
2708 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
2709 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
2710 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
2711 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05302712 {
2713 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
2714 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
2715 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
2716 },
Vasundhara Volam16511782018-10-04 11:13:46 +05302717 {
2718 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
2719 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
2720 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
2721 },
Shalom Toledo846e9802018-12-03 07:58:59 +00002722 {
2723 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
2724 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
2725 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
2726 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03002727};
Moshe Shemesheabaef12018-07-04 14:30:28 +03002728
2729static int devlink_param_generic_verify(const struct devlink_param *param)
2730{
2731 /* verify it match generic parameter by id and name */
2732 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
2733 return -EINVAL;
2734 if (strcmp(param->name, devlink_param_generic[param->id].name))
2735 return -ENOENT;
2736
2737 WARN_ON(param->type != devlink_param_generic[param->id].type);
2738
2739 return 0;
2740}
2741
2742static int devlink_param_driver_verify(const struct devlink_param *param)
2743{
2744 int i;
2745
2746 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
2747 return -EINVAL;
2748 /* verify no such name in generic params */
2749 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
2750 if (!strcmp(param->name, devlink_param_generic[i].name))
2751 return -EEXIST;
2752
2753 return 0;
2754}
2755
2756static struct devlink_param_item *
2757devlink_param_find_by_name(struct list_head *param_list,
2758 const char *param_name)
2759{
2760 struct devlink_param_item *param_item;
2761
2762 list_for_each_entry(param_item, param_list, list)
2763 if (!strcmp(param_item->param->name, param_name))
2764 return param_item;
2765 return NULL;
2766}
2767
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03002768static struct devlink_param_item *
2769devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
2770{
2771 struct devlink_param_item *param_item;
2772
2773 list_for_each_entry(param_item, param_list, list)
2774 if (param_item->param->id == param_id)
2775 return param_item;
2776 return NULL;
2777}
2778
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002779static bool
2780devlink_param_cmode_is_supported(const struct devlink_param *param,
2781 enum devlink_param_cmode cmode)
2782{
2783 return test_bit(cmode, &param->supported_cmodes);
2784}
2785
2786static int devlink_param_get(struct devlink *devlink,
2787 const struct devlink_param *param,
2788 struct devlink_param_gset_ctx *ctx)
2789{
2790 if (!param->get)
2791 return -EOPNOTSUPP;
2792 return param->get(devlink, param->id, ctx);
2793}
2794
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03002795static int devlink_param_set(struct devlink *devlink,
2796 const struct devlink_param *param,
2797 struct devlink_param_gset_ctx *ctx)
2798{
2799 if (!param->set)
2800 return -EOPNOTSUPP;
2801 return param->set(devlink, param->id, ctx);
2802}
2803
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002804static int
2805devlink_param_type_to_nla_type(enum devlink_param_type param_type)
2806{
2807 switch (param_type) {
2808 case DEVLINK_PARAM_TYPE_U8:
2809 return NLA_U8;
2810 case DEVLINK_PARAM_TYPE_U16:
2811 return NLA_U16;
2812 case DEVLINK_PARAM_TYPE_U32:
2813 return NLA_U32;
2814 case DEVLINK_PARAM_TYPE_STRING:
2815 return NLA_STRING;
2816 case DEVLINK_PARAM_TYPE_BOOL:
2817 return NLA_FLAG;
2818 default:
2819 return -EINVAL;
2820 }
2821}
2822
2823static int
2824devlink_nl_param_value_fill_one(struct sk_buff *msg,
2825 enum devlink_param_type type,
2826 enum devlink_param_cmode cmode,
2827 union devlink_param_value val)
2828{
2829 struct nlattr *param_value_attr;
2830
2831 param_value_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUE);
2832 if (!param_value_attr)
2833 goto nla_put_failure;
2834
2835 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
2836 goto value_nest_cancel;
2837
2838 switch (type) {
2839 case DEVLINK_PARAM_TYPE_U8:
2840 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
2841 goto value_nest_cancel;
2842 break;
2843 case DEVLINK_PARAM_TYPE_U16:
2844 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
2845 goto value_nest_cancel;
2846 break;
2847 case DEVLINK_PARAM_TYPE_U32:
2848 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
2849 goto value_nest_cancel;
2850 break;
2851 case DEVLINK_PARAM_TYPE_STRING:
2852 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
2853 val.vstr))
2854 goto value_nest_cancel;
2855 break;
2856 case DEVLINK_PARAM_TYPE_BOOL:
2857 if (val.vbool &&
2858 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
2859 goto value_nest_cancel;
2860 break;
2861 }
2862
2863 nla_nest_end(msg, param_value_attr);
2864 return 0;
2865
2866value_nest_cancel:
2867 nla_nest_cancel(msg, param_value_attr);
2868nla_put_failure:
2869 return -EMSGSIZE;
2870}
2871
2872static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302873 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002874 struct devlink_param_item *param_item,
2875 enum devlink_command cmd,
2876 u32 portid, u32 seq, int flags)
2877{
2878 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002879 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002880 const struct devlink_param *param = param_item->param;
2881 struct devlink_param_gset_ctx ctx;
2882 struct nlattr *param_values_list;
2883 struct nlattr *param_attr;
2884 int nla_type;
2885 void *hdr;
2886 int err;
2887 int i;
2888
2889 /* Get value from driver part to driverinit configuration mode */
2890 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
2891 if (!devlink_param_cmode_is_supported(param, i))
2892 continue;
2893 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
2894 if (!param_item->driverinit_value_valid)
2895 return -EOPNOTSUPP;
2896 param_value[i] = param_item->driverinit_value;
2897 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002898 if (!param_item->published)
2899 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002900 ctx.cmode = i;
2901 err = devlink_param_get(devlink, param, &ctx);
2902 if (err)
2903 return err;
2904 param_value[i] = ctx.val;
2905 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002906 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002907 }
2908
2909 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
2910 if (!hdr)
2911 return -EMSGSIZE;
2912
2913 if (devlink_nl_put_handle(msg, devlink))
2914 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302915
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302916 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
2917 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
2918 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302919 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
2920 goto genlmsg_cancel;
2921
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002922 param_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM);
2923 if (!param_attr)
2924 goto genlmsg_cancel;
2925 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
2926 goto param_nest_cancel;
2927 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
2928 goto param_nest_cancel;
2929
2930 nla_type = devlink_param_type_to_nla_type(param->type);
2931 if (nla_type < 0)
2932 goto param_nest_cancel;
2933 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
2934 goto param_nest_cancel;
2935
2936 param_values_list = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUES_LIST);
2937 if (!param_values_list)
2938 goto param_nest_cancel;
2939
2940 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002941 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002942 continue;
2943 err = devlink_nl_param_value_fill_one(msg, param->type,
2944 i, param_value[i]);
2945 if (err)
2946 goto values_list_nest_cancel;
2947 }
2948
2949 nla_nest_end(msg, param_values_list);
2950 nla_nest_end(msg, param_attr);
2951 genlmsg_end(msg, hdr);
2952 return 0;
2953
2954values_list_nest_cancel:
2955 nla_nest_end(msg, param_values_list);
2956param_nest_cancel:
2957 nla_nest_cancel(msg, param_attr);
2958genlmsg_cancel:
2959 genlmsg_cancel(msg, hdr);
2960 return -EMSGSIZE;
2961}
2962
Moshe Shemeshea601e12018-07-04 14:30:32 +03002963static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302964 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03002965 struct devlink_param_item *param_item,
2966 enum devlink_command cmd)
2967{
2968 struct sk_buff *msg;
2969 int err;
2970
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302971 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
2972 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
2973 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03002974
2975 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2976 if (!msg)
2977 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302978 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
2979 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03002980 if (err) {
2981 nlmsg_free(msg);
2982 return;
2983 }
2984
2985 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
2986 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
2987}
2988
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002989static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
2990 struct netlink_callback *cb)
2991{
2992 struct devlink_param_item *param_item;
2993 struct devlink *devlink;
2994 int start = cb->args[0];
2995 int idx = 0;
2996 int err;
2997
2998 mutex_lock(&devlink_mutex);
2999 list_for_each_entry(devlink, &devlink_list, list) {
3000 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3001 continue;
3002 mutex_lock(&devlink->lock);
3003 list_for_each_entry(param_item, &devlink->param_list, list) {
3004 if (idx < start) {
3005 idx++;
3006 continue;
3007 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303008 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003009 DEVLINK_CMD_PARAM_GET,
3010 NETLINK_CB(cb->skb).portid,
3011 cb->nlh->nlmsg_seq,
3012 NLM_F_MULTI);
3013 if (err) {
3014 mutex_unlock(&devlink->lock);
3015 goto out;
3016 }
3017 idx++;
3018 }
3019 mutex_unlock(&devlink->lock);
3020 }
3021out:
3022 mutex_unlock(&devlink_mutex);
3023
3024 cb->args[0] = idx;
3025 return msg->len;
3026}
3027
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003028static int
3029devlink_param_type_get_from_info(struct genl_info *info,
3030 enum devlink_param_type *param_type)
3031{
3032 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3033 return -EINVAL;
3034
3035 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3036 case NLA_U8:
3037 *param_type = DEVLINK_PARAM_TYPE_U8;
3038 break;
3039 case NLA_U16:
3040 *param_type = DEVLINK_PARAM_TYPE_U16;
3041 break;
3042 case NLA_U32:
3043 *param_type = DEVLINK_PARAM_TYPE_U32;
3044 break;
3045 case NLA_STRING:
3046 *param_type = DEVLINK_PARAM_TYPE_STRING;
3047 break;
3048 case NLA_FLAG:
3049 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3050 break;
3051 default:
3052 return -EINVAL;
3053 }
3054
3055 return 0;
3056}
3057
3058static int
3059devlink_param_value_get_from_info(const struct devlink_param *param,
3060 struct genl_info *info,
3061 union devlink_param_value *value)
3062{
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003063 int len;
3064
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003065 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3066 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3067 return -EINVAL;
3068
3069 switch (param->type) {
3070 case DEVLINK_PARAM_TYPE_U8:
3071 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3072 break;
3073 case DEVLINK_PARAM_TYPE_U16:
3074 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3075 break;
3076 case DEVLINK_PARAM_TYPE_U32:
3077 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3078 break;
3079 case DEVLINK_PARAM_TYPE_STRING:
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003080 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3081 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3082 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003083 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003084 return -EINVAL;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003085 strcpy(value->vstr,
3086 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003087 break;
3088 case DEVLINK_PARAM_TYPE_BOOL:
3089 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3090 true : false;
3091 break;
3092 }
3093 return 0;
3094}
3095
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003096static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303097devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003098 struct genl_info *info)
3099{
3100 char *param_name;
3101
3102 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3103 return NULL;
3104
3105 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303106 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003107}
3108
3109static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3110 struct genl_info *info)
3111{
3112 struct devlink *devlink = info->user_ptr[0];
3113 struct devlink_param_item *param_item;
3114 struct sk_buff *msg;
3115 int err;
3116
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303117 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003118 if (!param_item)
3119 return -EINVAL;
3120
3121 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3122 if (!msg)
3123 return -ENOMEM;
3124
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303125 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003126 DEVLINK_CMD_PARAM_GET,
3127 info->snd_portid, info->snd_seq, 0);
3128 if (err) {
3129 nlmsg_free(msg);
3130 return err;
3131 }
3132
3133 return genlmsg_reply(msg, info);
3134}
3135
Vasundhara Volam9c548732019-01-28 18:00:22 +05303136static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303137 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303138 struct list_head *param_list,
3139 struct genl_info *info,
3140 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003141{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003142 enum devlink_param_type param_type;
3143 struct devlink_param_gset_ctx ctx;
3144 enum devlink_param_cmode cmode;
3145 struct devlink_param_item *param_item;
3146 const struct devlink_param *param;
3147 union devlink_param_value value;
3148 int err = 0;
3149
Vasundhara Volam9c548732019-01-28 18:00:22 +05303150 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003151 if (!param_item)
3152 return -EINVAL;
3153 param = param_item->param;
3154 err = devlink_param_type_get_from_info(info, &param_type);
3155 if (err)
3156 return err;
3157 if (param_type != param->type)
3158 return -EINVAL;
3159 err = devlink_param_value_get_from_info(param, info, &value);
3160 if (err)
3161 return err;
3162 if (param->validate) {
3163 err = param->validate(devlink, param->id, value, info->extack);
3164 if (err)
3165 return err;
3166 }
3167
3168 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3169 return -EINVAL;
3170 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3171 if (!devlink_param_cmode_is_supported(param, cmode))
3172 return -EOPNOTSUPP;
3173
3174 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003175 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3176 strcpy(param_item->driverinit_value.vstr, value.vstr);
3177 else
3178 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003179 param_item->driverinit_value_valid = true;
3180 } else {
3181 if (!param->set)
3182 return -EOPNOTSUPP;
3183 ctx.val = value;
3184 ctx.cmode = cmode;
3185 err = devlink_param_set(devlink, param, &ctx);
3186 if (err)
3187 return err;
3188 }
3189
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303190 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003191 return 0;
3192}
3193
Vasundhara Volam9c548732019-01-28 18:00:22 +05303194static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3195 struct genl_info *info)
3196{
3197 struct devlink *devlink = info->user_ptr[0];
3198
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303199 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303200 info, DEVLINK_CMD_PARAM_NEW);
3201}
3202
Moshe Shemesheabaef12018-07-04 14:30:28 +03003203static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303204 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303205 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303206 const struct devlink_param *param,
3207 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003208{
3209 struct devlink_param_item *param_item;
3210
Vasundhara Volam39e61602019-01-28 18:00:20 +05303211 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03003212 return -EEXIST;
3213
3214 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3215 WARN_ON(param->get || param->set);
3216 else
3217 WARN_ON(!param->get || !param->set);
3218
3219 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3220 if (!param_item)
3221 return -ENOMEM;
3222 param_item->param = param;
3223
Vasundhara Volam39e61602019-01-28 18:00:20 +05303224 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303225 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003226 return 0;
3227}
3228
3229static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303230 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303231 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303232 const struct devlink_param *param,
3233 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003234{
3235 struct devlink_param_item *param_item;
3236
Vasundhara Volam39e61602019-01-28 18:00:20 +05303237 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003238 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303239 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003240 list_del(&param_item->list);
3241 kfree(param_item);
3242}
3243
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303244static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3245 struct netlink_callback *cb)
3246{
3247 struct devlink_param_item *param_item;
3248 struct devlink_port *devlink_port;
3249 struct devlink *devlink;
3250 int start = cb->args[0];
3251 int idx = 0;
3252 int err;
3253
3254 mutex_lock(&devlink_mutex);
3255 list_for_each_entry(devlink, &devlink_list, list) {
3256 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3257 continue;
3258 mutex_lock(&devlink->lock);
3259 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3260 list_for_each_entry(param_item,
3261 &devlink_port->param_list, list) {
3262 if (idx < start) {
3263 idx++;
3264 continue;
3265 }
3266 err = devlink_nl_param_fill(msg,
3267 devlink_port->devlink,
3268 devlink_port->index, param_item,
3269 DEVLINK_CMD_PORT_PARAM_GET,
3270 NETLINK_CB(cb->skb).portid,
3271 cb->nlh->nlmsg_seq,
3272 NLM_F_MULTI);
3273 if (err) {
3274 mutex_unlock(&devlink->lock);
3275 goto out;
3276 }
3277 idx++;
3278 }
3279 }
3280 mutex_unlock(&devlink->lock);
3281 }
3282out:
3283 mutex_unlock(&devlink_mutex);
3284
3285 cb->args[0] = idx;
3286 return msg->len;
3287}
3288
3289static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3290 struct genl_info *info)
3291{
3292 struct devlink_port *devlink_port = info->user_ptr[0];
3293 struct devlink_param_item *param_item;
3294 struct sk_buff *msg;
3295 int err;
3296
3297 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3298 info);
3299 if (!param_item)
3300 return -EINVAL;
3301
3302 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3303 if (!msg)
3304 return -ENOMEM;
3305
3306 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3307 devlink_port->index, param_item,
3308 DEVLINK_CMD_PORT_PARAM_GET,
3309 info->snd_portid, info->snd_seq, 0);
3310 if (err) {
3311 nlmsg_free(msg);
3312 return err;
3313 }
3314
3315 return genlmsg_reply(msg, info);
3316}
3317
Vasundhara Volam9c548732019-01-28 18:00:22 +05303318static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3319 struct genl_info *info)
3320{
3321 struct devlink_port *devlink_port = info->user_ptr[0];
3322
3323 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303324 devlink_port->index,
3325 &devlink_port->param_list, info,
3326 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05303327}
3328
Alex Veskera006d462018-07-12 15:13:12 +03003329static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3330 struct devlink *devlink,
3331 struct devlink_snapshot *snapshot)
3332{
3333 struct nlattr *snap_attr;
3334 int err;
3335
3336 snap_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
3337 if (!snap_attr)
3338 return -EINVAL;
3339
3340 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3341 if (err)
3342 goto nla_put_failure;
3343
3344 nla_nest_end(msg, snap_attr);
3345 return 0;
3346
3347nla_put_failure:
3348 nla_nest_cancel(msg, snap_attr);
3349 return err;
3350}
3351
3352static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3353 struct devlink *devlink,
3354 struct devlink_region *region)
3355{
3356 struct devlink_snapshot *snapshot;
3357 struct nlattr *snapshots_attr;
3358 int err;
3359
3360 snapshots_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOTS);
3361 if (!snapshots_attr)
3362 return -EINVAL;
3363
3364 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3365 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3366 if (err)
3367 goto nla_put_failure;
3368 }
3369
3370 nla_nest_end(msg, snapshots_attr);
3371 return 0;
3372
3373nla_put_failure:
3374 nla_nest_cancel(msg, snapshots_attr);
3375 return err;
3376}
3377
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003378static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3379 enum devlink_command cmd, u32 portid,
3380 u32 seq, int flags,
3381 struct devlink_region *region)
3382{
3383 void *hdr;
3384 int err;
3385
3386 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3387 if (!hdr)
3388 return -EMSGSIZE;
3389
3390 err = devlink_nl_put_handle(msg, devlink);
3391 if (err)
3392 goto nla_put_failure;
3393
3394 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3395 if (err)
3396 goto nla_put_failure;
3397
3398 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3399 region->size,
3400 DEVLINK_ATTR_PAD);
3401 if (err)
3402 goto nla_put_failure;
3403
Alex Veskera006d462018-07-12 15:13:12 +03003404 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3405 if (err)
3406 goto nla_put_failure;
3407
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003408 genlmsg_end(msg, hdr);
3409 return 0;
3410
3411nla_put_failure:
3412 genlmsg_cancel(msg, hdr);
3413 return err;
3414}
3415
Alex Vesker866319b2018-07-12 15:13:13 +03003416static void devlink_nl_region_notify(struct devlink_region *region,
3417 struct devlink_snapshot *snapshot,
3418 enum devlink_command cmd)
3419{
3420 struct devlink *devlink = region->devlink;
3421 struct sk_buff *msg;
3422 void *hdr;
3423 int err;
3424
3425 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3426
3427 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3428 if (!msg)
3429 return;
3430
3431 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3432 if (!hdr)
3433 goto out_free_msg;
3434
3435 err = devlink_nl_put_handle(msg, devlink);
3436 if (err)
3437 goto out_cancel_msg;
3438
3439 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3440 region->name);
3441 if (err)
3442 goto out_cancel_msg;
3443
3444 if (snapshot) {
3445 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3446 snapshot->id);
3447 if (err)
3448 goto out_cancel_msg;
3449 } else {
3450 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3451 region->size, DEVLINK_ATTR_PAD);
3452 if (err)
3453 goto out_cancel_msg;
3454 }
3455 genlmsg_end(msg, hdr);
3456
3457 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3458 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3459
3460 return;
3461
3462out_cancel_msg:
3463 genlmsg_cancel(msg, hdr);
3464out_free_msg:
3465 nlmsg_free(msg);
3466}
3467
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003468static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3469 struct genl_info *info)
3470{
3471 struct devlink *devlink = info->user_ptr[0];
3472 struct devlink_region *region;
3473 const char *region_name;
3474 struct sk_buff *msg;
3475 int err;
3476
3477 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3478 return -EINVAL;
3479
3480 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3481 region = devlink_region_get_by_name(devlink, region_name);
3482 if (!region)
3483 return -EINVAL;
3484
3485 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3486 if (!msg)
3487 return -ENOMEM;
3488
3489 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3490 info->snd_portid, info->snd_seq, 0,
3491 region);
3492 if (err) {
3493 nlmsg_free(msg);
3494 return err;
3495 }
3496
3497 return genlmsg_reply(msg, info);
3498}
3499
3500static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3501 struct netlink_callback *cb)
3502{
3503 struct devlink_region *region;
3504 struct devlink *devlink;
3505 int start = cb->args[0];
3506 int idx = 0;
3507 int err;
3508
3509 mutex_lock(&devlink_mutex);
3510 list_for_each_entry(devlink, &devlink_list, list) {
3511 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3512 continue;
3513
3514 mutex_lock(&devlink->lock);
3515 list_for_each_entry(region, &devlink->region_list, list) {
3516 if (idx < start) {
3517 idx++;
3518 continue;
3519 }
3520 err = devlink_nl_region_fill(msg, devlink,
3521 DEVLINK_CMD_REGION_GET,
3522 NETLINK_CB(cb->skb).portid,
3523 cb->nlh->nlmsg_seq,
3524 NLM_F_MULTI, region);
3525 if (err) {
3526 mutex_unlock(&devlink->lock);
3527 goto out;
3528 }
3529 idx++;
3530 }
3531 mutex_unlock(&devlink->lock);
3532 }
3533out:
3534 mutex_unlock(&devlink_mutex);
3535 cb->args[0] = idx;
3536 return msg->len;
3537}
3538
Alex Vesker866319b2018-07-12 15:13:13 +03003539static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3540 struct genl_info *info)
3541{
3542 struct devlink *devlink = info->user_ptr[0];
3543 struct devlink_snapshot *snapshot;
3544 struct devlink_region *region;
3545 const char *region_name;
3546 u32 snapshot_id;
3547
3548 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3549 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3550 return -EINVAL;
3551
3552 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3553 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3554
3555 region = devlink_region_get_by_name(devlink, region_name);
3556 if (!region)
3557 return -EINVAL;
3558
3559 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3560 if (!snapshot)
3561 return -EINVAL;
3562
3563 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3564 devlink_region_snapshot_del(snapshot);
3565 return 0;
3566}
3567
Alex Vesker4e547952018-07-12 15:13:14 +03003568static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3569 struct devlink *devlink,
3570 u8 *chunk, u32 chunk_size,
3571 u64 addr)
3572{
3573 struct nlattr *chunk_attr;
3574 int err;
3575
3576 chunk_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_CHUNK);
3577 if (!chunk_attr)
3578 return -EINVAL;
3579
3580 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3581 if (err)
3582 goto nla_put_failure;
3583
3584 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3585 DEVLINK_ATTR_PAD);
3586 if (err)
3587 goto nla_put_failure;
3588
3589 nla_nest_end(msg, chunk_attr);
3590 return 0;
3591
3592nla_put_failure:
3593 nla_nest_cancel(msg, chunk_attr);
3594 return err;
3595}
3596
3597#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3598
3599static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3600 struct devlink *devlink,
3601 struct devlink_region *region,
3602 struct nlattr **attrs,
3603 u64 start_offset,
3604 u64 end_offset,
3605 bool dump,
3606 u64 *new_offset)
3607{
3608 struct devlink_snapshot *snapshot;
3609 u64 curr_offset = start_offset;
3610 u32 snapshot_id;
3611 int err = 0;
3612
3613 *new_offset = start_offset;
3614
3615 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3616 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3617 if (!snapshot)
3618 return -EINVAL;
3619
3620 if (end_offset > snapshot->data_len || dump)
3621 end_offset = snapshot->data_len;
3622
3623 while (curr_offset < end_offset) {
3624 u32 data_size;
3625 u8 *data;
3626
3627 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3628 data_size = end_offset - curr_offset;
3629 else
3630 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3631
3632 data = &snapshot->data[curr_offset];
3633 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3634 data, data_size,
3635 curr_offset);
3636 if (err)
3637 break;
3638
3639 curr_offset += data_size;
3640 }
3641 *new_offset = curr_offset;
3642
3643 return err;
3644}
3645
3646static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3647 struct netlink_callback *cb)
3648{
3649 u64 ret_offset, start_offset, end_offset = 0;
Alex Vesker4e547952018-07-12 15:13:14 +03003650 const struct genl_ops *ops = cb->data;
3651 struct devlink_region *region;
3652 struct nlattr *chunks_attr;
3653 const char *region_name;
3654 struct devlink *devlink;
Jakub Kicinski68750562019-02-10 19:35:28 -08003655 struct nlattr **attrs;
Alex Vesker4e547952018-07-12 15:13:14 +03003656 bool dump = true;
3657 void *hdr;
3658 int err;
3659
3660 start_offset = *((u64 *)&cb->args[0]);
3661
Jakub Kicinski68750562019-02-10 19:35:28 -08003662 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
3663 if (!attrs)
3664 return -ENOMEM;
3665
Alex Vesker4e547952018-07-12 15:13:14 +03003666 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + devlink_nl_family.hdrsize,
David Aherndac9c972018-10-07 20:16:24 -07003667 attrs, DEVLINK_ATTR_MAX, ops->policy, cb->extack);
Alex Vesker4e547952018-07-12 15:13:14 +03003668 if (err)
Jakub Kicinski68750562019-02-10 19:35:28 -08003669 goto out_free;
Alex Vesker4e547952018-07-12 15:13:14 +03003670
Parav Panditdac7c082019-02-12 14:24:08 -06003671 mutex_lock(&devlink_mutex);
Alex Vesker4e547952018-07-12 15:13:14 +03003672 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003673 if (IS_ERR(devlink)) {
3674 err = PTR_ERR(devlink);
Parav Panditdac7c082019-02-12 14:24:08 -06003675 goto out_dev;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003676 }
Alex Vesker4e547952018-07-12 15:13:14 +03003677
Alex Vesker4e547952018-07-12 15:13:14 +03003678 mutex_lock(&devlink->lock);
3679
3680 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
Parav Panditfdd41ec2019-02-12 14:23:58 -06003681 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
3682 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003683 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003684 }
Alex Vesker4e547952018-07-12 15:13:14 +03003685
3686 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3687 region = devlink_region_get_by_name(devlink, region_name);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003688 if (!region) {
3689 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003690 goto out_unlock;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003691 }
Alex Vesker4e547952018-07-12 15:13:14 +03003692
3693 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3694 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3695 DEVLINK_CMD_REGION_READ);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003696 if (!hdr) {
3697 err = -EMSGSIZE;
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 err = devlink_nl_put_handle(skb, devlink);
3702 if (err)
3703 goto nla_put_failure;
3704
3705 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3706 if (err)
3707 goto nla_put_failure;
3708
3709 chunks_attr = nla_nest_start(skb, DEVLINK_ATTR_REGION_CHUNKS);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003710 if (!chunks_attr) {
3711 err = -EMSGSIZE;
Alex Vesker4e547952018-07-12 15:13:14 +03003712 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003713 }
Alex Vesker4e547952018-07-12 15:13:14 +03003714
3715 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3716 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3717 if (!start_offset)
3718 start_offset =
3719 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3720
3721 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3722 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3723 dump = false;
3724 }
3725
3726 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3727 region, attrs,
3728 start_offset,
3729 end_offset, dump,
3730 &ret_offset);
3731
3732 if (err && err != -EMSGSIZE)
3733 goto nla_put_failure;
3734
3735 /* Check if there was any progress done to prevent infinite loop */
Parav Panditfdd41ec2019-02-12 14:23:58 -06003736 if (ret_offset == start_offset) {
3737 err = -EINVAL;
Alex Vesker4e547952018-07-12 15:13:14 +03003738 goto nla_put_failure;
Parav Panditfdd41ec2019-02-12 14:23:58 -06003739 }
Alex Vesker4e547952018-07-12 15:13:14 +03003740
3741 *((u64 *)&cb->args[0]) = ret_offset;
3742
3743 nla_nest_end(skb, chunks_attr);
3744 genlmsg_end(skb, hdr);
3745 mutex_unlock(&devlink->lock);
3746 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003747 kfree(attrs);
Alex Vesker4e547952018-07-12 15:13:14 +03003748
3749 return skb->len;
3750
3751nla_put_failure:
3752 genlmsg_cancel(skb, hdr);
3753out_unlock:
3754 mutex_unlock(&devlink->lock);
Parav Panditdac7c082019-02-12 14:24:08 -06003755out_dev:
Alex Vesker4e547952018-07-12 15:13:14 +03003756 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003757out_free:
3758 kfree(attrs);
Parav Panditfdd41ec2019-02-12 14:23:58 -06003759 return err;
Alex Vesker4e547952018-07-12 15:13:14 +03003760}
3761
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003762struct devlink_info_req {
3763 struct sk_buff *msg;
3764};
3765
3766int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3767{
3768 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3769}
3770EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3771
3772int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3773{
3774 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3775}
3776EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3777
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08003778static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3779 const char *version_name,
3780 const char *version_value)
3781{
3782 struct nlattr *nest;
3783 int err;
3784
3785 nest = nla_nest_start(req->msg, attr);
3786 if (!nest)
3787 return -EMSGSIZE;
3788
3789 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3790 version_name);
3791 if (err)
3792 goto nla_put_failure;
3793
3794 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3795 version_value);
3796 if (err)
3797 goto nla_put_failure;
3798
3799 nla_nest_end(req->msg, nest);
3800
3801 return 0;
3802
3803nla_put_failure:
3804 nla_nest_cancel(req->msg, nest);
3805 return err;
3806}
3807
3808int devlink_info_version_fixed_put(struct devlink_info_req *req,
3809 const char *version_name,
3810 const char *version_value)
3811{
3812 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3813 version_name, version_value);
3814}
3815EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3816
3817int devlink_info_version_stored_put(struct devlink_info_req *req,
3818 const char *version_name,
3819 const char *version_value)
3820{
3821 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3822 version_name, version_value);
3823}
3824EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3825
3826int devlink_info_version_running_put(struct devlink_info_req *req,
3827 const char *version_name,
3828 const char *version_value)
3829{
3830 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3831 version_name, version_value);
3832}
3833EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3834
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003835static int
3836devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3837 enum devlink_command cmd, u32 portid,
3838 u32 seq, int flags, struct netlink_ext_ack *extack)
3839{
3840 struct devlink_info_req req;
3841 void *hdr;
3842 int err;
3843
3844 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3845 if (!hdr)
3846 return -EMSGSIZE;
3847
3848 err = -EMSGSIZE;
3849 if (devlink_nl_put_handle(msg, devlink))
3850 goto err_cancel_msg;
3851
3852 req.msg = msg;
3853 err = devlink->ops->info_get(devlink, &req, extack);
3854 if (err)
3855 goto err_cancel_msg;
3856
3857 genlmsg_end(msg, hdr);
3858 return 0;
3859
3860err_cancel_msg:
3861 genlmsg_cancel(msg, hdr);
3862 return err;
3863}
3864
3865static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
3866 struct genl_info *info)
3867{
3868 struct devlink *devlink = info->user_ptr[0];
3869 struct sk_buff *msg;
3870 int err;
3871
3872 if (!devlink->ops || !devlink->ops->info_get)
3873 return -EOPNOTSUPP;
3874
3875 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3876 if (!msg)
3877 return -ENOMEM;
3878
3879 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3880 info->snd_portid, info->snd_seq, 0,
3881 info->extack);
3882 if (err) {
3883 nlmsg_free(msg);
3884 return err;
3885 }
3886
3887 return genlmsg_reply(msg, info);
3888}
3889
3890static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
3891 struct netlink_callback *cb)
3892{
3893 struct devlink *devlink;
3894 int start = cb->args[0];
3895 int idx = 0;
3896 int err;
3897
3898 mutex_lock(&devlink_mutex);
3899 list_for_each_entry(devlink, &devlink_list, list) {
3900 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3901 continue;
3902 if (idx < start) {
3903 idx++;
3904 continue;
3905 }
3906
3907 mutex_lock(&devlink->lock);
3908 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3909 NETLINK_CB(cb->skb).portid,
3910 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3911 cb->extack);
3912 mutex_unlock(&devlink->lock);
3913 if (err)
3914 break;
3915 idx++;
3916 }
3917 mutex_unlock(&devlink_mutex);
3918
3919 cb->args[0] = idx;
3920 return msg->len;
3921}
3922
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02003923struct devlink_fmsg_item {
3924 struct list_head list;
3925 int attrtype;
3926 u8 nla_type;
3927 u16 len;
3928 int value[0];
3929};
3930
3931struct devlink_fmsg {
3932 struct list_head item_list;
3933};
3934
3935static struct devlink_fmsg *devlink_fmsg_alloc(void)
3936{
3937 struct devlink_fmsg *fmsg;
3938
3939 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
3940 if (!fmsg)
3941 return NULL;
3942
3943 INIT_LIST_HEAD(&fmsg->item_list);
3944
3945 return fmsg;
3946}
3947
3948static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
3949{
3950 struct devlink_fmsg_item *item, *tmp;
3951
3952 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
3953 list_del(&item->list);
3954 kfree(item);
3955 }
3956 kfree(fmsg);
3957}
3958
3959static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
3960 int attrtype)
3961{
3962 struct devlink_fmsg_item *item;
3963
3964 item = kzalloc(sizeof(*item), GFP_KERNEL);
3965 if (!item)
3966 return -ENOMEM;
3967
3968 item->attrtype = attrtype;
3969 list_add_tail(&item->list, &fmsg->item_list);
3970
3971 return 0;
3972}
3973
3974int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
3975{
3976 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
3977}
3978EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
3979
3980static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
3981{
3982 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
3983}
3984
3985int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
3986{
3987 return devlink_fmsg_nest_end(fmsg);
3988}
3989EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
3990
3991#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
3992
3993static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
3994{
3995 struct devlink_fmsg_item *item;
3996
3997 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
3998 return -EMSGSIZE;
3999
4000 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4001 if (!item)
4002 return -ENOMEM;
4003
4004 item->nla_type = NLA_NUL_STRING;
4005 item->len = strlen(name) + 1;
4006 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4007 memcpy(&item->value, name, item->len);
4008 list_add_tail(&item->list, &fmsg->item_list);
4009
4010 return 0;
4011}
4012
4013int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4014{
4015 int err;
4016
4017 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4018 if (err)
4019 return err;
4020
4021 err = devlink_fmsg_put_name(fmsg, name);
4022 if (err)
4023 return err;
4024
4025 return 0;
4026}
4027EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4028
4029int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4030{
4031 return devlink_fmsg_nest_end(fmsg);
4032}
4033EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4034
4035int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4036 const char *name)
4037{
4038 int err;
4039
4040 err = devlink_fmsg_pair_nest_start(fmsg, name);
4041 if (err)
4042 return err;
4043
4044 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4045 if (err)
4046 return err;
4047
4048 return 0;
4049}
4050EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4051
4052int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4053{
4054 int err;
4055
4056 err = devlink_fmsg_nest_end(fmsg);
4057 if (err)
4058 return err;
4059
4060 err = devlink_fmsg_nest_end(fmsg);
4061 if (err)
4062 return err;
4063
4064 return 0;
4065}
4066EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4067
4068static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4069 const void *value, u16 value_len,
4070 u8 value_nla_type)
4071{
4072 struct devlink_fmsg_item *item;
4073
4074 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4075 return -EMSGSIZE;
4076
4077 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4078 if (!item)
4079 return -ENOMEM;
4080
4081 item->nla_type = value_nla_type;
4082 item->len = value_len;
4083 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4084 memcpy(&item->value, value, item->len);
4085 list_add_tail(&item->list, &fmsg->item_list);
4086
4087 return 0;
4088}
4089
4090int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4091{
4092 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4093}
4094EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4095
4096int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4097{
4098 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4099}
4100EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4101
4102int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4103{
4104 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4105}
4106EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4107
4108int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4109{
4110 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4111}
4112EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4113
4114int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4115{
4116 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4117 NLA_NUL_STRING);
4118}
4119EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4120
4121int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4122 u16 value_len)
4123{
4124 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4125}
4126EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4127
4128int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4129 bool value)
4130{
4131 int err;
4132
4133 err = devlink_fmsg_pair_nest_start(fmsg, name);
4134 if (err)
4135 return err;
4136
4137 err = devlink_fmsg_bool_put(fmsg, value);
4138 if (err)
4139 return err;
4140
4141 err = devlink_fmsg_pair_nest_end(fmsg);
4142 if (err)
4143 return err;
4144
4145 return 0;
4146}
4147EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4148
4149int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4150 u8 value)
4151{
4152 int err;
4153
4154 err = devlink_fmsg_pair_nest_start(fmsg, name);
4155 if (err)
4156 return err;
4157
4158 err = devlink_fmsg_u8_put(fmsg, value);
4159 if (err)
4160 return err;
4161
4162 err = devlink_fmsg_pair_nest_end(fmsg);
4163 if (err)
4164 return err;
4165
4166 return 0;
4167}
4168EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4169
4170int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4171 u32 value)
4172{
4173 int err;
4174
4175 err = devlink_fmsg_pair_nest_start(fmsg, name);
4176 if (err)
4177 return err;
4178
4179 err = devlink_fmsg_u32_put(fmsg, value);
4180 if (err)
4181 return err;
4182
4183 err = devlink_fmsg_pair_nest_end(fmsg);
4184 if (err)
4185 return err;
4186
4187 return 0;
4188}
4189EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4190
4191int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4192 u64 value)
4193{
4194 int err;
4195
4196 err = devlink_fmsg_pair_nest_start(fmsg, name);
4197 if (err)
4198 return err;
4199
4200 err = devlink_fmsg_u64_put(fmsg, value);
4201 if (err)
4202 return err;
4203
4204 err = devlink_fmsg_pair_nest_end(fmsg);
4205 if (err)
4206 return err;
4207
4208 return 0;
4209}
4210EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4211
4212int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4213 const char *value)
4214{
4215 int err;
4216
4217 err = devlink_fmsg_pair_nest_start(fmsg, name);
4218 if (err)
4219 return err;
4220
4221 err = devlink_fmsg_string_put(fmsg, value);
4222 if (err)
4223 return err;
4224
4225 err = devlink_fmsg_pair_nest_end(fmsg);
4226 if (err)
4227 return err;
4228
4229 return 0;
4230}
4231EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4232
4233int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4234 const void *value, u16 value_len)
4235{
4236 int err;
4237
4238 err = devlink_fmsg_pair_nest_start(fmsg, name);
4239 if (err)
4240 return err;
4241
4242 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4243 if (err)
4244 return err;
4245
4246 err = devlink_fmsg_pair_nest_end(fmsg);
4247 if (err)
4248 return err;
4249
4250 return 0;
4251}
4252EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4253
4254static int
4255devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4256{
4257 switch (msg->nla_type) {
4258 case NLA_FLAG:
4259 case NLA_U8:
4260 case NLA_U32:
4261 case NLA_U64:
4262 case NLA_NUL_STRING:
4263 case NLA_BINARY:
4264 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4265 msg->nla_type);
4266 default:
4267 return -EINVAL;
4268 }
4269}
4270
4271static int
4272devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4273{
4274 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4275 u8 tmp;
4276
4277 switch (msg->nla_type) {
4278 case NLA_FLAG:
4279 /* Always provide flag data, regardless of its value */
4280 tmp = *(bool *) msg->value;
4281
4282 return nla_put_u8(skb, attrtype, tmp);
4283 case NLA_U8:
4284 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4285 case NLA_U32:
4286 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4287 case NLA_U64:
4288 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4289 DEVLINK_ATTR_PAD);
4290 case NLA_NUL_STRING:
4291 return nla_put_string(skb, attrtype, (char *) &msg->value);
4292 case NLA_BINARY:
4293 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4294 default:
4295 return -EINVAL;
4296 }
4297}
4298
4299static int
4300devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4301 int *start)
4302{
4303 struct devlink_fmsg_item *item;
4304 struct nlattr *fmsg_nlattr;
4305 int i = 0;
4306 int err;
4307
4308 fmsg_nlattr = nla_nest_start(skb, DEVLINK_ATTR_FMSG);
4309 if (!fmsg_nlattr)
4310 return -EMSGSIZE;
4311
4312 list_for_each_entry(item, &fmsg->item_list, list) {
4313 if (i < *start) {
4314 i++;
4315 continue;
4316 }
4317
4318 switch (item->attrtype) {
4319 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4320 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4321 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4322 case DEVLINK_ATTR_FMSG_NEST_END:
4323 err = nla_put_flag(skb, item->attrtype);
4324 break;
4325 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4326 err = devlink_fmsg_item_fill_type(item, skb);
4327 if (err)
4328 break;
4329 err = devlink_fmsg_item_fill_data(item, skb);
4330 break;
4331 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4332 err = nla_put_string(skb, item->attrtype,
4333 (char *) &item->value);
4334 break;
4335 default:
4336 err = -EINVAL;
4337 break;
4338 }
4339 if (!err)
4340 *start = ++i;
4341 else
4342 break;
4343 }
4344
4345 nla_nest_end(skb, fmsg_nlattr);
4346 return err;
4347}
4348
4349static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4350 struct genl_info *info,
4351 enum devlink_command cmd, int flags)
4352{
4353 struct nlmsghdr *nlh;
4354 struct sk_buff *skb;
4355 bool last = false;
4356 int index = 0;
4357 void *hdr;
4358 int err;
4359
4360 while (!last) {
4361 int tmp_index = index;
4362
4363 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4364 if (!skb)
4365 return -ENOMEM;
4366
4367 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4368 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4369 if (!hdr) {
4370 err = -EMSGSIZE;
4371 goto nla_put_failure;
4372 }
4373
4374 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4375 if (!err)
4376 last = true;
4377 else if (err != -EMSGSIZE || tmp_index == index)
4378 goto nla_put_failure;
4379
4380 genlmsg_end(skb, hdr);
4381 err = genlmsg_reply(skb, info);
4382 if (err)
4383 return err;
4384 }
4385
4386 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4387 if (!skb)
4388 return -ENOMEM;
4389 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4390 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4391 if (!nlh) {
4392 err = -EMSGSIZE;
4393 goto nla_put_failure;
4394 }
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004395
Li RongQingfde55ea2019-02-11 19:09:07 +08004396 return genlmsg_reply(skb, info);
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02004397
4398nla_put_failure:
4399 nlmsg_free(skb);
4400 return err;
4401}
4402
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004403struct devlink_health_reporter {
4404 struct list_head list;
4405 void *priv;
4406 const struct devlink_health_reporter_ops *ops;
4407 struct devlink *devlink;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004408 struct devlink_fmsg *dump_fmsg;
4409 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004410 u64 graceful_period;
4411 bool auto_recover;
4412 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004413 u64 dump_ts;
4414 u64 error_count;
4415 u64 recovery_count;
4416 u64 last_recovery_ts;
4417};
4418
4419enum devlink_health_reporter_state {
4420 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
4421 DEVLINK_HEALTH_REPORTER_STATE_ERROR,
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004422};
4423
4424void *
4425devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4426{
4427 return reporter->priv;
4428}
4429EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4430
4431static struct devlink_health_reporter *
4432devlink_health_reporter_find_by_name(struct devlink *devlink,
4433 const char *reporter_name)
4434{
4435 struct devlink_health_reporter *reporter;
4436
4437 list_for_each_entry(reporter, &devlink->reporter_list, list)
4438 if (!strcmp(reporter->ops->name, reporter_name))
4439 return reporter;
4440 return NULL;
4441}
4442
4443/**
4444 * devlink_health_reporter_create - create devlink health reporter
4445 *
4446 * @devlink: devlink
4447 * @ops: ops
4448 * @graceful_period: to avoid recovery loops, in msecs
4449 * @auto_recover: auto recover when error occurs
4450 * @priv: priv
4451 */
4452struct devlink_health_reporter *
4453devlink_health_reporter_create(struct devlink *devlink,
4454 const struct devlink_health_reporter_ops *ops,
4455 u64 graceful_period, bool auto_recover,
4456 void *priv)
4457{
4458 struct devlink_health_reporter *reporter;
4459
4460 mutex_lock(&devlink->lock);
4461 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4462 reporter = ERR_PTR(-EEXIST);
4463 goto unlock;
4464 }
4465
4466 if (WARN_ON(auto_recover && !ops->recover) ||
4467 WARN_ON(graceful_period && !ops->recover)) {
4468 reporter = ERR_PTR(-EINVAL);
4469 goto unlock;
4470 }
4471
4472 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4473 if (!reporter) {
4474 reporter = ERR_PTR(-ENOMEM);
4475 goto unlock;
4476 }
4477
4478 reporter->priv = priv;
4479 reporter->ops = ops;
4480 reporter->devlink = devlink;
4481 reporter->graceful_period = graceful_period;
4482 reporter->auto_recover = auto_recover;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004483 mutex_init(&reporter->dump_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004484 list_add_tail(&reporter->list, &devlink->reporter_list);
4485unlock:
4486 mutex_unlock(&devlink->lock);
4487 return reporter;
4488}
4489EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4490
4491/**
4492 * devlink_health_reporter_destroy - destroy devlink health reporter
4493 *
4494 * @reporter: devlink health reporter to destroy
4495 */
4496void
4497devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4498{
4499 mutex_lock(&reporter->devlink->lock);
4500 list_del(&reporter->list);
4501 mutex_unlock(&reporter->devlink->lock);
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004502 if (reporter->dump_fmsg)
4503 devlink_fmsg_free(reporter->dump_fmsg);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004504 kfree(reporter);
4505}
4506EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4507
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004508static int
4509devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4510 void *priv_ctx)
4511{
4512 int err;
4513
4514 if (!reporter->ops->recover)
4515 return -EOPNOTSUPP;
4516
4517 err = reporter->ops->recover(reporter, priv_ctx);
4518 if (err)
4519 return err;
4520
4521 reporter->recovery_count++;
4522 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4523 reporter->last_recovery_ts = jiffies;
4524
4525 return 0;
4526}
4527
4528static void
4529devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4530{
4531 if (!reporter->dump_fmsg)
4532 return;
4533 devlink_fmsg_free(reporter->dump_fmsg);
4534 reporter->dump_fmsg = NULL;
4535}
4536
4537static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4538 void *priv_ctx)
4539{
4540 int err;
4541
4542 if (!reporter->ops->dump)
4543 return 0;
4544
4545 if (reporter->dump_fmsg)
4546 return 0;
4547
4548 reporter->dump_fmsg = devlink_fmsg_alloc();
4549 if (!reporter->dump_fmsg) {
4550 err = -ENOMEM;
4551 return err;
4552 }
4553
4554 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4555 if (err)
4556 goto dump_err;
4557
4558 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4559 priv_ctx);
4560 if (err)
4561 goto dump_err;
4562
4563 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4564 if (err)
4565 goto dump_err;
4566
4567 reporter->dump_ts = jiffies;
4568
4569 return 0;
4570
4571dump_err:
4572 devlink_health_dump_clear(reporter);
4573 return err;
4574}
4575
4576int devlink_health_report(struct devlink_health_reporter *reporter,
4577 const char *msg, void *priv_ctx)
4578{
4579 struct devlink *devlink = reporter->devlink;
4580
4581 /* write a log message of the current error */
4582 WARN_ON(!msg);
4583 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4584 reporter->error_count++;
4585
4586 /* abort if the previous error wasn't recovered */
4587 if (reporter->auto_recover &&
4588 (reporter->health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
4589 jiffies - reporter->last_recovery_ts <
4590 msecs_to_jiffies(reporter->graceful_period))) {
4591 trace_devlink_health_recover_aborted(devlink,
4592 reporter->ops->name,
4593 reporter->health_state,
4594 jiffies -
4595 reporter->last_recovery_ts);
4596 return -ECANCELED;
4597 }
4598
4599 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4600
4601 mutex_lock(&reporter->dump_lock);
4602 /* store current dump of current error, for later analysis */
4603 devlink_health_do_dump(reporter, priv_ctx);
4604 mutex_unlock(&reporter->dump_lock);
4605
4606 if (reporter->auto_recover)
4607 return devlink_health_reporter_recover(reporter, priv_ctx);
4608
4609 return 0;
4610}
4611EXPORT_SYMBOL_GPL(devlink_health_report);
4612
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004613static struct devlink_health_reporter *
4614devlink_health_reporter_get_from_info(struct devlink *devlink,
4615 struct genl_info *info)
4616{
4617 char *reporter_name;
4618
4619 if (!info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
4620 return NULL;
4621
4622 reporter_name =
4623 nla_data(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
4624 return devlink_health_reporter_find_by_name(devlink, reporter_name);
4625}
4626
4627static int
4628devlink_nl_health_reporter_fill(struct sk_buff *msg,
4629 struct devlink *devlink,
4630 struct devlink_health_reporter *reporter,
4631 enum devlink_command cmd, u32 portid,
4632 u32 seq, int flags)
4633{
4634 struct nlattr *reporter_attr;
4635 void *hdr;
4636
4637 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4638 if (!hdr)
4639 return -EMSGSIZE;
4640
4641 if (devlink_nl_put_handle(msg, devlink))
4642 goto genlmsg_cancel;
4643
4644 reporter_attr = nla_nest_start(msg, DEVLINK_ATTR_HEALTH_REPORTER);
4645 if (!reporter_attr)
4646 goto genlmsg_cancel;
4647 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4648 reporter->ops->name))
4649 goto reporter_nest_cancel;
4650 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4651 reporter->health_state))
4652 goto reporter_nest_cancel;
4653 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR,
4654 reporter->error_count, DEVLINK_ATTR_PAD))
4655 goto reporter_nest_cancel;
4656 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER,
4657 reporter->recovery_count, DEVLINK_ATTR_PAD))
4658 goto reporter_nest_cancel;
4659 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
4660 reporter->graceful_period,
4661 DEVLINK_ATTR_PAD))
4662 goto reporter_nest_cancel;
4663 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
4664 reporter->auto_recover))
4665 goto reporter_nest_cancel;
4666 if (reporter->dump_fmsg &&
4667 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4668 jiffies_to_msecs(reporter->dump_ts),
4669 DEVLINK_ATTR_PAD))
4670 goto reporter_nest_cancel;
4671
4672 nla_nest_end(msg, reporter_attr);
4673 genlmsg_end(msg, hdr);
4674 return 0;
4675
4676reporter_nest_cancel:
4677 nla_nest_end(msg, reporter_attr);
4678genlmsg_cancel:
4679 genlmsg_cancel(msg, hdr);
4680 return -EMSGSIZE;
4681}
4682
4683static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4684 struct genl_info *info)
4685{
4686 struct devlink *devlink = info->user_ptr[0];
4687 struct devlink_health_reporter *reporter;
4688 struct sk_buff *msg;
4689 int err;
4690
4691 reporter = devlink_health_reporter_get_from_info(devlink, info);
4692 if (!reporter)
4693 return -EINVAL;
4694
4695 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4696 if (!msg)
4697 return -ENOMEM;
4698
4699 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4700 DEVLINK_CMD_HEALTH_REPORTER_GET,
4701 info->snd_portid, info->snd_seq,
4702 0);
4703 if (err) {
4704 nlmsg_free(msg);
4705 return err;
4706 }
4707
4708 return genlmsg_reply(msg, info);
4709}
4710
4711static int
4712devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4713 struct netlink_callback *cb)
4714{
4715 struct devlink_health_reporter *reporter;
4716 struct devlink *devlink;
4717 int start = cb->args[0];
4718 int idx = 0;
4719 int err;
4720
4721 mutex_lock(&devlink_mutex);
4722 list_for_each_entry(devlink, &devlink_list, list) {
4723 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4724 continue;
4725 mutex_lock(&devlink->lock);
4726 list_for_each_entry(reporter, &devlink->reporter_list,
4727 list) {
4728 if (idx < start) {
4729 idx++;
4730 continue;
4731 }
4732 err = devlink_nl_health_reporter_fill(msg, devlink,
4733 reporter,
4734 DEVLINK_CMD_HEALTH_REPORTER_GET,
4735 NETLINK_CB(cb->skb).portid,
4736 cb->nlh->nlmsg_seq,
4737 NLM_F_MULTI);
4738 if (err) {
4739 mutex_unlock(&devlink->lock);
4740 goto out;
4741 }
4742 idx++;
4743 }
4744 mutex_unlock(&devlink->lock);
4745 }
4746out:
4747 mutex_unlock(&devlink_mutex);
4748
4749 cb->args[0] = idx;
4750 return msg->len;
4751}
4752
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004753static int
4754devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
4755 struct genl_info *info)
4756{
4757 struct devlink *devlink = info->user_ptr[0];
4758 struct devlink_health_reporter *reporter;
4759
4760 reporter = devlink_health_reporter_get_from_info(devlink, info);
4761 if (!reporter)
4762 return -EINVAL;
4763
4764 if (!reporter->ops->recover &&
4765 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
4766 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]))
4767 return -EOPNOTSUPP;
4768
4769 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
4770 reporter->graceful_period =
4771 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
4772
4773 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
4774 reporter->auto_recover =
4775 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
4776
4777 return 0;
4778}
4779
Eran Ben Elisha20a09432019-02-07 11:36:37 +02004780static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
4781 struct genl_info *info)
4782{
4783 struct devlink *devlink = info->user_ptr[0];
4784 struct devlink_health_reporter *reporter;
4785
4786 reporter = devlink_health_reporter_get_from_info(devlink, info);
4787 if (!reporter)
4788 return -EINVAL;
4789
4790 return devlink_health_reporter_recover(reporter, NULL);
4791}
4792
Eran Ben Elishafca42a22019-02-07 11:36:38 +02004793static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
4794 struct genl_info *info)
4795{
4796 struct devlink *devlink = info->user_ptr[0];
4797 struct devlink_health_reporter *reporter;
4798 struct devlink_fmsg *fmsg;
4799 int err;
4800
4801 reporter = devlink_health_reporter_get_from_info(devlink, info);
4802 if (!reporter)
4803 return -EINVAL;
4804
4805 if (!reporter->ops->diagnose)
4806 return -EOPNOTSUPP;
4807
4808 fmsg = devlink_fmsg_alloc();
4809 if (!fmsg)
4810 return -ENOMEM;
4811
4812 err = devlink_fmsg_obj_nest_start(fmsg);
4813 if (err)
4814 goto out;
4815
4816 err = reporter->ops->diagnose(reporter, fmsg);
4817 if (err)
4818 goto out;
4819
4820 err = devlink_fmsg_obj_nest_end(fmsg);
4821 if (err)
4822 goto out;
4823
4824 err = devlink_fmsg_snd(fmsg, info,
4825 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
4826
4827out:
4828 devlink_fmsg_free(fmsg);
4829 return err;
4830}
4831
Eran Ben Elisha35455e22019-02-07 11:36:39 +02004832static int devlink_nl_cmd_health_reporter_dump_get_doit(struct sk_buff *skb,
4833 struct genl_info *info)
4834{
4835 struct devlink *devlink = info->user_ptr[0];
4836 struct devlink_health_reporter *reporter;
4837 int err;
4838
4839 reporter = devlink_health_reporter_get_from_info(devlink, info);
4840 if (!reporter)
4841 return -EINVAL;
4842
4843 if (!reporter->ops->dump)
4844 return -EOPNOTSUPP;
4845
4846 mutex_lock(&reporter->dump_lock);
4847 err = devlink_health_do_dump(reporter, NULL);
4848 if (err)
4849 goto out;
4850
4851 err = devlink_fmsg_snd(reporter->dump_fmsg, info,
4852 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 0);
4853
4854out:
4855 mutex_unlock(&reporter->dump_lock);
4856 return err;
4857}
4858
4859static int
4860devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
4861 struct genl_info *info)
4862{
4863 struct devlink *devlink = info->user_ptr[0];
4864 struct devlink_health_reporter *reporter;
4865
4866 reporter = devlink_health_reporter_get_from_info(devlink, info);
4867 if (!reporter)
4868 return -EINVAL;
4869
4870 if (!reporter->ops->dump)
4871 return -EOPNOTSUPP;
4872
4873 mutex_lock(&reporter->dump_lock);
4874 devlink_health_dump_clear(reporter);
4875 mutex_unlock(&reporter->dump_lock);
4876 return 0;
4877}
4878
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004879static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
4880 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
4881 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
4882 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
4883 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
4884 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02004885 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
4886 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
4887 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
4888 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
4889 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
4890 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
4891 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03004892 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
Roi Dayan59bfde02016-11-22 23:09:57 +02004893 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03004894 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02004895 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
4896 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01004897 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
4898 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03004899 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
4900 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
4901 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004902 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03004903 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004904 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004905 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
4906 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08004907 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
4908 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004909};
4910
4911static const struct genl_ops devlink_nl_ops[] = {
4912 {
4913 .cmd = DEVLINK_CMD_GET,
4914 .doit = devlink_nl_cmd_get_doit,
4915 .dumpit = devlink_nl_cmd_get_dumpit,
4916 .policy = devlink_nl_policy,
Jiri Pirko1fc22572016-04-08 19:12:48 +02004917 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004918 /* can be retrieved by unprivileged users */
4919 },
4920 {
4921 .cmd = DEVLINK_CMD_PORT_GET,
4922 .doit = devlink_nl_cmd_port_get_doit,
4923 .dumpit = devlink_nl_cmd_port_get_dumpit,
4924 .policy = devlink_nl_policy,
4925 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4926 /* can be retrieved by unprivileged users */
4927 },
4928 {
4929 .cmd = DEVLINK_CMD_PORT_SET,
4930 .doit = devlink_nl_cmd_port_set_doit,
4931 .policy = devlink_nl_policy,
4932 .flags = GENL_ADMIN_PERM,
4933 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4934 },
4935 {
4936 .cmd = DEVLINK_CMD_PORT_SPLIT,
4937 .doit = devlink_nl_cmd_port_split_doit,
4938 .policy = devlink_nl_policy,
4939 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01004940 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4941 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004942 },
4943 {
4944 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
4945 .doit = devlink_nl_cmd_port_unsplit_doit,
4946 .policy = devlink_nl_policy,
4947 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01004948 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4949 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004950 },
Jiri Pirkobf797472016-04-14 18:19:13 +02004951 {
4952 .cmd = DEVLINK_CMD_SB_GET,
4953 .doit = devlink_nl_cmd_sb_get_doit,
4954 .dumpit = devlink_nl_cmd_sb_get_dumpit,
4955 .policy = devlink_nl_policy,
4956 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4957 DEVLINK_NL_FLAG_NEED_SB,
4958 /* can be retrieved by unprivileged users */
4959 },
4960 {
4961 .cmd = DEVLINK_CMD_SB_POOL_GET,
4962 .doit = devlink_nl_cmd_sb_pool_get_doit,
4963 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
4964 .policy = devlink_nl_policy,
4965 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4966 DEVLINK_NL_FLAG_NEED_SB,
4967 /* can be retrieved by unprivileged users */
4968 },
4969 {
4970 .cmd = DEVLINK_CMD_SB_POOL_SET,
4971 .doit = devlink_nl_cmd_sb_pool_set_doit,
4972 .policy = devlink_nl_policy,
4973 .flags = GENL_ADMIN_PERM,
4974 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4975 DEVLINK_NL_FLAG_NEED_SB,
4976 },
4977 {
4978 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
4979 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
4980 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
4981 .policy = devlink_nl_policy,
4982 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4983 DEVLINK_NL_FLAG_NEED_SB,
4984 /* can be retrieved by unprivileged users */
4985 },
4986 {
4987 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
4988 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
4989 .policy = devlink_nl_policy,
4990 .flags = GENL_ADMIN_PERM,
4991 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4992 DEVLINK_NL_FLAG_NEED_SB,
4993 },
4994 {
4995 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
4996 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
4997 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
4998 .policy = devlink_nl_policy,
4999 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5000 DEVLINK_NL_FLAG_NEED_SB,
5001 /* can be retrieved by unprivileged users */
5002 },
5003 {
5004 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
5005 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
5006 .policy = devlink_nl_policy,
5007 .flags = GENL_ADMIN_PERM,
5008 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5009 DEVLINK_NL_FLAG_NEED_SB,
5010 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005011 {
5012 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
5013 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
5014 .policy = devlink_nl_policy,
5015 .flags = GENL_ADMIN_PERM,
5016 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005017 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005018 },
5019 {
5020 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
5021 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
5022 .policy = devlink_nl_policy,
5023 .flags = GENL_ADMIN_PERM,
5024 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005025 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02005026 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03005027 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005028 .cmd = DEVLINK_CMD_ESWITCH_GET,
5029 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005030 .policy = devlink_nl_policy,
5031 .flags = GENL_ADMIN_PERM,
5032 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5033 },
5034 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005035 .cmd = DEVLINK_CMD_ESWITCH_SET,
5036 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005037 .policy = devlink_nl_policy,
5038 .flags = GENL_ADMIN_PERM,
Jakub Kicinski7ac1cc92018-05-21 22:12:50 -07005039 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5040 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005041 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005042 {
5043 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
5044 .doit = devlink_nl_cmd_dpipe_table_get,
5045 .policy = devlink_nl_policy,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005046 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005047 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005048 },
5049 {
5050 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
5051 .doit = devlink_nl_cmd_dpipe_entries_get,
5052 .policy = devlink_nl_policy,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005053 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005054 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005055 },
5056 {
5057 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
5058 .doit = devlink_nl_cmd_dpipe_headers_get,
5059 .policy = devlink_nl_policy,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005060 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005061 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005062 },
5063 {
5064 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
5065 .doit = devlink_nl_cmd_dpipe_table_counters_set,
5066 .policy = devlink_nl_policy,
5067 .flags = GENL_ADMIN_PERM,
5068 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5069 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005070 {
5071 .cmd = DEVLINK_CMD_RESOURCE_SET,
5072 .doit = devlink_nl_cmd_resource_set,
5073 .policy = devlink_nl_policy,
5074 .flags = GENL_ADMIN_PERM,
5075 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5076 },
5077 {
5078 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
5079 .doit = devlink_nl_cmd_resource_dump,
5080 .policy = devlink_nl_policy,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005081 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005082 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005083 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005084 {
5085 .cmd = DEVLINK_CMD_RELOAD,
5086 .doit = devlink_nl_cmd_reload,
5087 .policy = devlink_nl_policy,
5088 .flags = GENL_ADMIN_PERM,
5089 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5090 DEVLINK_NL_FLAG_NO_LOCK,
5091 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005092 {
5093 .cmd = DEVLINK_CMD_PARAM_GET,
5094 .doit = devlink_nl_cmd_param_get_doit,
5095 .dumpit = devlink_nl_cmd_param_get_dumpit,
5096 .policy = devlink_nl_policy,
5097 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5098 /* can be retrieved by unprivileged users */
5099 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005100 {
5101 .cmd = DEVLINK_CMD_PARAM_SET,
5102 .doit = devlink_nl_cmd_param_set_doit,
5103 .policy = devlink_nl_policy,
5104 .flags = GENL_ADMIN_PERM,
5105 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5106 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005107 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305108 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
5109 .doit = devlink_nl_cmd_port_param_get_doit,
5110 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
5111 .policy = devlink_nl_policy,
5112 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5113 /* can be retrieved by unprivileged users */
5114 },
5115 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05305116 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
5117 .doit = devlink_nl_cmd_port_param_set_doit,
5118 .policy = devlink_nl_policy,
5119 .flags = GENL_ADMIN_PERM,
5120 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5121 },
5122 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005123 .cmd = DEVLINK_CMD_REGION_GET,
5124 .doit = devlink_nl_cmd_region_get_doit,
5125 .dumpit = devlink_nl_cmd_region_get_dumpit,
5126 .policy = devlink_nl_policy,
5127 .flags = GENL_ADMIN_PERM,
5128 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5129 },
Alex Vesker866319b2018-07-12 15:13:13 +03005130 {
5131 .cmd = DEVLINK_CMD_REGION_DEL,
5132 .doit = devlink_nl_cmd_region_del,
5133 .policy = devlink_nl_policy,
5134 .flags = GENL_ADMIN_PERM,
5135 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5136 },
Alex Vesker4e547952018-07-12 15:13:14 +03005137 {
5138 .cmd = DEVLINK_CMD_REGION_READ,
5139 .dumpit = devlink_nl_cmd_region_read_dumpit,
5140 .policy = devlink_nl_policy,
5141 .flags = GENL_ADMIN_PERM,
5142 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5143 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005144 {
5145 .cmd = DEVLINK_CMD_INFO_GET,
5146 .doit = devlink_nl_cmd_info_get_doit,
5147 .dumpit = devlink_nl_cmd_info_get_dumpit,
5148 .policy = devlink_nl_policy,
5149 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5150 /* can be retrieved by unprivileged users */
5151 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005152 {
5153 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
5154 .doit = devlink_nl_cmd_health_reporter_get_doit,
5155 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
5156 .policy = devlink_nl_policy,
5157 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5158 /* can be retrieved by unprivileged users */
5159 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005160 {
5161 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
5162 .doit = devlink_nl_cmd_health_reporter_set_doit,
5163 .policy = devlink_nl_policy,
5164 .flags = GENL_ADMIN_PERM,
5165 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5166 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005167 {
5168 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
5169 .doit = devlink_nl_cmd_health_reporter_recover_doit,
5170 .policy = devlink_nl_policy,
5171 .flags = GENL_ADMIN_PERM,
5172 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5173 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005174 {
5175 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
5176 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
5177 .policy = devlink_nl_policy,
5178 .flags = GENL_ADMIN_PERM,
5179 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5180 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005181 {
5182 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
5183 .doit = devlink_nl_cmd_health_reporter_dump_get_doit,
5184 .policy = devlink_nl_policy,
5185 .flags = GENL_ADMIN_PERM,
5186 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5187 DEVLINK_NL_FLAG_NO_LOCK,
5188 },
5189 {
5190 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
5191 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
5192 .policy = devlink_nl_policy,
5193 .flags = GENL_ADMIN_PERM,
5194 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5195 DEVLINK_NL_FLAG_NO_LOCK,
5196 },
Jakub Kicinski76726cc2019-02-14 13:40:44 -08005197 {
5198 .cmd = DEVLINK_CMD_FLASH_UPDATE,
5199 .doit = devlink_nl_cmd_flash_update,
5200 .policy = devlink_nl_policy,
5201 .flags = GENL_ADMIN_PERM,
5202 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5203 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005204};
5205
Johannes Berg56989f62016-10-24 14:40:05 +02005206static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02005207 .name = DEVLINK_GENL_NAME,
5208 .version = DEVLINK_GENL_VERSION,
5209 .maxattr = DEVLINK_ATTR_MAX,
5210 .netnsok = true,
5211 .pre_doit = devlink_nl_pre_doit,
5212 .post_doit = devlink_nl_post_doit,
5213 .module = THIS_MODULE,
5214 .ops = devlink_nl_ops,
5215 .n_ops = ARRAY_SIZE(devlink_nl_ops),
5216 .mcgrps = devlink_nl_mcgrps,
5217 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
5218};
5219
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005220/**
5221 * devlink_alloc - Allocate new devlink instance resources
5222 *
5223 * @ops: ops
5224 * @priv_size: size of user private data
5225 *
5226 * Allocate new devlink instance resources, including devlink index
5227 * and name.
5228 */
5229struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
5230{
5231 struct devlink *devlink;
5232
5233 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
5234 if (!devlink)
5235 return NULL;
5236 devlink->ops = ops;
5237 devlink_net_set(devlink, &init_net);
5238 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02005239 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005240 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005241 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03005242 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03005243 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005244 INIT_LIST_HEAD(&devlink->reporter_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005245 mutex_init(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005246 return devlink;
5247}
5248EXPORT_SYMBOL_GPL(devlink_alloc);
5249
5250/**
5251 * devlink_register - Register devlink instance
5252 *
5253 * @devlink: devlink
5254 */
5255int devlink_register(struct devlink *devlink, struct device *dev)
5256{
5257 mutex_lock(&devlink_mutex);
5258 devlink->dev = dev;
5259 list_add_tail(&devlink->list, &devlink_list);
5260 devlink_notify(devlink, DEVLINK_CMD_NEW);
5261 mutex_unlock(&devlink_mutex);
5262 return 0;
5263}
5264EXPORT_SYMBOL_GPL(devlink_register);
5265
5266/**
5267 * devlink_unregister - Unregister devlink instance
5268 *
5269 * @devlink: devlink
5270 */
5271void devlink_unregister(struct devlink *devlink)
5272{
5273 mutex_lock(&devlink_mutex);
5274 devlink_notify(devlink, DEVLINK_CMD_DEL);
5275 list_del(&devlink->list);
5276 mutex_unlock(&devlink_mutex);
5277}
5278EXPORT_SYMBOL_GPL(devlink_unregister);
5279
5280/**
5281 * devlink_free - Free devlink instance resources
5282 *
5283 * @devlink: devlink
5284 */
5285void devlink_free(struct devlink *devlink)
5286{
Parav Panditb904aad2019-02-08 15:15:00 -06005287 WARN_ON(!list_empty(&devlink->reporter_list));
5288 WARN_ON(!list_empty(&devlink->region_list));
5289 WARN_ON(!list_empty(&devlink->param_list));
5290 WARN_ON(!list_empty(&devlink->resource_list));
5291 WARN_ON(!list_empty(&devlink->dpipe_table_list));
5292 WARN_ON(!list_empty(&devlink->sb_list));
5293 WARN_ON(!list_empty(&devlink->port_list));
5294
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005295 kfree(devlink);
5296}
5297EXPORT_SYMBOL_GPL(devlink_free);
5298
5299/**
5300 * devlink_port_register - Register devlink port
5301 *
5302 * @devlink: devlink
5303 * @devlink_port: devlink port
5304 * @port_index
5305 *
5306 * Register devlink port with provided port index. User can use
5307 * any indexing, even hw-related one. devlink_port structure
5308 * is convenient to be embedded inside user driver private structure.
5309 * Note that the caller should take care of zeroing the devlink_port
5310 * structure.
5311 */
5312int devlink_port_register(struct devlink *devlink,
5313 struct devlink_port *devlink_port,
5314 unsigned int port_index)
5315{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005316 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005317 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005318 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005319 return -EEXIST;
5320 }
5321 devlink_port->devlink = devlink;
5322 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005323 devlink_port->registered = true;
5324 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305325 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005326 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005327 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5328 return 0;
5329}
5330EXPORT_SYMBOL_GPL(devlink_port_register);
5331
5332/**
5333 * devlink_port_unregister - Unregister devlink port
5334 *
5335 * @devlink_port: devlink port
5336 */
5337void devlink_port_unregister(struct devlink_port *devlink_port)
5338{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005339 struct devlink *devlink = devlink_port->devlink;
5340
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005341 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005342 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005343 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005344 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005345}
5346EXPORT_SYMBOL_GPL(devlink_port_unregister);
5347
5348static void __devlink_port_type_set(struct devlink_port *devlink_port,
5349 enum devlink_port_type type,
5350 void *type_dev)
5351{
5352 devlink_port->type = type;
5353 devlink_port->type_dev = type_dev;
5354 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5355}
5356
5357/**
5358 * devlink_port_type_eth_set - Set port type to Ethernet
5359 *
5360 * @devlink_port: devlink port
5361 * @netdev: related netdevice
5362 */
5363void devlink_port_type_eth_set(struct devlink_port *devlink_port,
5364 struct net_device *netdev)
5365{
5366 return __devlink_port_type_set(devlink_port,
5367 DEVLINK_PORT_TYPE_ETH, netdev);
5368}
5369EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
5370
5371/**
5372 * devlink_port_type_ib_set - Set port type to InfiniBand
5373 *
5374 * @devlink_port: devlink port
5375 * @ibdev: related IB device
5376 */
5377void devlink_port_type_ib_set(struct devlink_port *devlink_port,
5378 struct ib_device *ibdev)
5379{
5380 return __devlink_port_type_set(devlink_port,
5381 DEVLINK_PORT_TYPE_IB, ibdev);
5382}
5383EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
5384
5385/**
5386 * devlink_port_type_clear - Clear port type
5387 *
5388 * @devlink_port: devlink port
5389 */
5390void devlink_port_type_clear(struct devlink_port *devlink_port)
5391{
5392 return __devlink_port_type_set(devlink_port,
5393 DEVLINK_PORT_TYPE_NOTSET, NULL);
5394}
5395EXPORT_SYMBOL_GPL(devlink_port_type_clear);
5396
5397/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005398 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005399 *
5400 * @devlink_port: devlink port
Jiri Pirko5ec13802018-05-18 09:29:01 +02005401 * @flavour: flavour of the port
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005402 * @port_number: number of the port that is facing user, for example
5403 * the front panel port number
5404 * @split: indicates if this is split port
5405 * @split_subport_number: if the port is split, this is the number
5406 * of subport.
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005407 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005408void devlink_port_attrs_set(struct devlink_port *devlink_port,
Jiri Pirko5ec13802018-05-18 09:29:01 +02005409 enum devlink_port_flavour flavour,
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005410 u32 port_number, bool split,
5411 u32 split_subport_number)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005412{
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005413 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5414
5415 attrs->set = true;
Jiri Pirko5ec13802018-05-18 09:29:01 +02005416 attrs->flavour = flavour;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005417 attrs->port_number = port_number;
5418 attrs->split = split;
5419 attrs->split_subport_number = split_subport_number;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005420 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5421}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005422EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005423
Jiri Pirko08474c12018-05-18 09:29:02 +02005424int devlink_port_get_phys_port_name(struct devlink_port *devlink_port,
5425 char *name, size_t len)
5426{
5427 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5428 int n = 0;
5429
5430 if (!attrs->set)
5431 return -EOPNOTSUPP;
5432
5433 switch (attrs->flavour) {
5434 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
5435 if (!attrs->split)
5436 n = snprintf(name, len, "p%u", attrs->port_number);
5437 else
5438 n = snprintf(name, len, "p%us%u", attrs->port_number,
5439 attrs->split_subport_number);
5440 break;
5441 case DEVLINK_PORT_FLAVOUR_CPU:
5442 case DEVLINK_PORT_FLAVOUR_DSA:
5443 /* As CPU and DSA ports do not have a netdevice associated
5444 * case should not ever happen.
5445 */
5446 WARN_ON(1);
5447 return -EINVAL;
5448 }
5449
5450 if (n >= len)
5451 return -EINVAL;
5452
5453 return 0;
5454}
5455EXPORT_SYMBOL_GPL(devlink_port_get_phys_port_name);
5456
Jiri Pirkobf797472016-04-14 18:19:13 +02005457int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
5458 u32 size, u16 ingress_pools_count,
5459 u16 egress_pools_count, u16 ingress_tc_count,
5460 u16 egress_tc_count)
5461{
5462 struct devlink_sb *devlink_sb;
5463 int err = 0;
5464
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005465 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005466 if (devlink_sb_index_exists(devlink, sb_index)) {
5467 err = -EEXIST;
5468 goto unlock;
5469 }
5470
5471 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
5472 if (!devlink_sb) {
5473 err = -ENOMEM;
5474 goto unlock;
5475 }
5476 devlink_sb->index = sb_index;
5477 devlink_sb->size = size;
5478 devlink_sb->ingress_pools_count = ingress_pools_count;
5479 devlink_sb->egress_pools_count = egress_pools_count;
5480 devlink_sb->ingress_tc_count = ingress_tc_count;
5481 devlink_sb->egress_tc_count = egress_tc_count;
5482 list_add_tail(&devlink_sb->list, &devlink->sb_list);
5483unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005484 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005485 return err;
5486}
5487EXPORT_SYMBOL_GPL(devlink_sb_register);
5488
5489void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
5490{
5491 struct devlink_sb *devlink_sb;
5492
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005493 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005494 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
5495 WARN_ON(!devlink_sb);
5496 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005497 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005498 kfree(devlink_sb);
5499}
5500EXPORT_SYMBOL_GPL(devlink_sb_unregister);
5501
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005502/**
5503 * devlink_dpipe_headers_register - register dpipe headers
5504 *
5505 * @devlink: devlink
5506 * @dpipe_headers: dpipe header array
5507 *
5508 * Register the headers supported by hardware.
5509 */
5510int devlink_dpipe_headers_register(struct devlink *devlink,
5511 struct devlink_dpipe_headers *dpipe_headers)
5512{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005513 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005514 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005515 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005516 return 0;
5517}
5518EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
5519
5520/**
5521 * devlink_dpipe_headers_unregister - unregister dpipe headers
5522 *
5523 * @devlink: devlink
5524 *
5525 * Unregister the headers supported by hardware.
5526 */
5527void devlink_dpipe_headers_unregister(struct devlink *devlink)
5528{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005529 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005530 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005531 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005532}
5533EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
5534
5535/**
5536 * devlink_dpipe_table_counter_enabled - check if counter allocation
5537 * required
5538 * @devlink: devlink
5539 * @table_name: tables name
5540 *
5541 * Used by driver to check if counter allocation is required.
5542 * After counter allocation is turned on the table entries
5543 * are updated to include counter statistics.
5544 *
5545 * After that point on the driver must respect the counter
5546 * state so that each entry added to the table is added
5547 * with a counter.
5548 */
5549bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
5550 const char *table_name)
5551{
5552 struct devlink_dpipe_table *table;
5553 bool enabled;
5554
5555 rcu_read_lock();
5556 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5557 table_name);
5558 enabled = false;
5559 if (table)
5560 enabled = table->counters_enabled;
5561 rcu_read_unlock();
5562 return enabled;
5563}
5564EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
5565
5566/**
5567 * devlink_dpipe_table_register - register dpipe table
5568 *
5569 * @devlink: devlink
5570 * @table_name: table name
5571 * @table_ops: table ops
5572 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005573 * @counter_control_extern: external control for counters
5574 */
5575int devlink_dpipe_table_register(struct devlink *devlink,
5576 const char *table_name,
5577 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02005578 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005579{
5580 struct devlink_dpipe_table *table;
5581
5582 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
5583 return -EEXIST;
5584
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02005585 if (WARN_ON(!table_ops->size_get))
5586 return -EINVAL;
5587
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005588 table = kzalloc(sizeof(*table), GFP_KERNEL);
5589 if (!table)
5590 return -ENOMEM;
5591
5592 table->name = table_name;
5593 table->table_ops = table_ops;
5594 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005595 table->counter_control_extern = counter_control_extern;
5596
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005597 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005598 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005599 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005600 return 0;
5601}
5602EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
5603
5604/**
5605 * devlink_dpipe_table_unregister - unregister dpipe table
5606 *
5607 * @devlink: devlink
5608 * @table_name: table name
5609 */
5610void devlink_dpipe_table_unregister(struct devlink *devlink,
5611 const char *table_name)
5612{
5613 struct devlink_dpipe_table *table;
5614
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005615 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005616 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5617 table_name);
5618 if (!table)
5619 goto unlock;
5620 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005621 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005622 kfree_rcu(table, rcu);
5623 return;
5624unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005625 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005626}
5627EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
5628
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005629/**
5630 * devlink_resource_register - devlink resource register
5631 *
5632 * @devlink: devlink
5633 * @resource_name: resource's name
5634 * @top_hierarchy: top hierarchy
5635 * @reload_required: reload is required for new configuration to
5636 * apply
5637 * @resource_size: resource's size
5638 * @resource_id: resource's id
5639 * @parent_reosurce_id: resource's parent id
5640 * @size params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005641 */
5642int devlink_resource_register(struct devlink *devlink,
5643 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005644 u64 resource_size,
5645 u64 resource_id,
5646 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02005647 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005648{
5649 struct devlink_resource *resource;
5650 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07005651 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005652 int err = 0;
5653
David Ahern14530742018-03-20 19:31:14 -07005654 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
5655
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005656 mutex_lock(&devlink->lock);
5657 resource = devlink_resource_find(devlink, NULL, resource_id);
5658 if (resource) {
5659 err = -EINVAL;
5660 goto out;
5661 }
5662
5663 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
5664 if (!resource) {
5665 err = -ENOMEM;
5666 goto out;
5667 }
5668
5669 if (top_hierarchy) {
5670 resource_list = &devlink->resource_list;
5671 } else {
5672 struct devlink_resource *parent_resource;
5673
5674 parent_resource = devlink_resource_find(devlink, NULL,
5675 parent_resource_id);
5676 if (parent_resource) {
5677 resource_list = &parent_resource->resource_list;
5678 resource->parent = parent_resource;
5679 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00005680 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005681 err = -EINVAL;
5682 goto out;
5683 }
5684 }
5685
5686 resource->name = resource_name;
5687 resource->size = resource_size;
5688 resource->size_new = resource_size;
5689 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005690 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01005691 memcpy(&resource->size_params, size_params,
5692 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005693 INIT_LIST_HEAD(&resource->resource_list);
5694 list_add_tail(&resource->list, resource_list);
5695out:
5696 mutex_unlock(&devlink->lock);
5697 return err;
5698}
5699EXPORT_SYMBOL_GPL(devlink_resource_register);
5700
5701/**
5702 * devlink_resources_unregister - free all resources
5703 *
5704 * @devlink: devlink
5705 * @resource: resource
5706 */
5707void devlink_resources_unregister(struct devlink *devlink,
5708 struct devlink_resource *resource)
5709{
5710 struct devlink_resource *tmp, *child_resource;
5711 struct list_head *resource_list;
5712
5713 if (resource)
5714 resource_list = &resource->resource_list;
5715 else
5716 resource_list = &devlink->resource_list;
5717
5718 if (!resource)
5719 mutex_lock(&devlink->lock);
5720
5721 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
5722 devlink_resources_unregister(devlink, child_resource);
5723 list_del(&child_resource->list);
5724 kfree(child_resource);
5725 }
5726
5727 if (!resource)
5728 mutex_unlock(&devlink->lock);
5729}
5730EXPORT_SYMBOL_GPL(devlink_resources_unregister);
5731
5732/**
5733 * devlink_resource_size_get - get and update size
5734 *
5735 * @devlink: devlink
5736 * @resource_id: the requested resource id
5737 * @p_resource_size: ptr to update
5738 */
5739int devlink_resource_size_get(struct devlink *devlink,
5740 u64 resource_id,
5741 u64 *p_resource_size)
5742{
5743 struct devlink_resource *resource;
5744 int err = 0;
5745
5746 mutex_lock(&devlink->lock);
5747 resource = devlink_resource_find(devlink, NULL, resource_id);
5748 if (!resource) {
5749 err = -EINVAL;
5750 goto out;
5751 }
5752 *p_resource_size = resource->size_new;
5753 resource->size = resource->size_new;
5754out:
5755 mutex_unlock(&devlink->lock);
5756 return err;
5757}
5758EXPORT_SYMBOL_GPL(devlink_resource_size_get);
5759
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01005760/**
5761 * devlink_dpipe_table_resource_set - set the resource id
5762 *
5763 * @devlink: devlink
5764 * @table_name: table name
5765 * @resource_id: resource id
5766 * @resource_units: number of resource's units consumed per table's entry
5767 */
5768int devlink_dpipe_table_resource_set(struct devlink *devlink,
5769 const char *table_name, u64 resource_id,
5770 u64 resource_units)
5771{
5772 struct devlink_dpipe_table *table;
5773 int err = 0;
5774
5775 mutex_lock(&devlink->lock);
5776 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5777 table_name);
5778 if (!table) {
5779 err = -EINVAL;
5780 goto out;
5781 }
5782 table->resource_id = resource_id;
5783 table->resource_units = resource_units;
5784 table->resource_valid = true;
5785out:
5786 mutex_unlock(&devlink->lock);
5787 return err;
5788}
5789EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
5790
Jiri Pirkofc56be42018-04-05 22:13:21 +02005791/**
5792 * devlink_resource_occ_get_register - register occupancy getter
5793 *
5794 * @devlink: devlink
5795 * @resource_id: resource id
5796 * @occ_get: occupancy getter callback
5797 * @occ_get_priv: occupancy getter callback priv
5798 */
5799void devlink_resource_occ_get_register(struct devlink *devlink,
5800 u64 resource_id,
5801 devlink_resource_occ_get_t *occ_get,
5802 void *occ_get_priv)
5803{
5804 struct devlink_resource *resource;
5805
5806 mutex_lock(&devlink->lock);
5807 resource = devlink_resource_find(devlink, NULL, resource_id);
5808 if (WARN_ON(!resource))
5809 goto out;
5810 WARN_ON(resource->occ_get);
5811
5812 resource->occ_get = occ_get;
5813 resource->occ_get_priv = occ_get_priv;
5814out:
5815 mutex_unlock(&devlink->lock);
5816}
5817EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
5818
5819/**
5820 * devlink_resource_occ_get_unregister - unregister occupancy getter
5821 *
5822 * @devlink: devlink
5823 * @resource_id: resource id
5824 */
5825void devlink_resource_occ_get_unregister(struct devlink *devlink,
5826 u64 resource_id)
5827{
5828 struct devlink_resource *resource;
5829
5830 mutex_lock(&devlink->lock);
5831 resource = devlink_resource_find(devlink, NULL, resource_id);
5832 if (WARN_ON(!resource))
5833 goto out;
5834 WARN_ON(!resource->occ_get);
5835
5836 resource->occ_get = NULL;
5837 resource->occ_get_priv = NULL;
5838out:
5839 mutex_unlock(&devlink->lock);
5840}
5841EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
5842
Vasundhara Volam39e61602019-01-28 18:00:20 +05305843static int devlink_param_verify(const struct devlink_param *param)
5844{
5845 if (!param || !param->name || !param->supported_cmodes)
5846 return -EINVAL;
5847 if (param->generic)
5848 return devlink_param_generic_verify(param);
5849 else
5850 return devlink_param_driver_verify(param);
5851}
5852
5853static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305854 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05305855 struct list_head *param_list,
5856 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305857 size_t params_count,
5858 enum devlink_command reg_cmd,
5859 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05305860{
5861 const struct devlink_param *param = params;
5862 int i;
5863 int err;
5864
5865 mutex_lock(&devlink->lock);
5866 for (i = 0; i < params_count; i++, param++) {
5867 err = devlink_param_verify(param);
5868 if (err)
5869 goto rollback;
5870
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305871 err = devlink_param_register_one(devlink, port_index,
5872 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305873 if (err)
5874 goto rollback;
5875 }
5876
5877 mutex_unlock(&devlink->lock);
5878 return 0;
5879
5880rollback:
5881 if (!i)
5882 goto unlock;
5883 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305884 devlink_param_unregister_one(devlink, port_index, param_list,
5885 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305886unlock:
5887 mutex_unlock(&devlink->lock);
5888 return err;
5889}
5890
5891static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305892 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05305893 struct list_head *param_list,
5894 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305895 size_t params_count,
5896 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05305897{
5898 const struct devlink_param *param = params;
5899 int i;
5900
5901 mutex_lock(&devlink->lock);
5902 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305903 devlink_param_unregister_one(devlink, 0, param_list, param,
5904 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305905 mutex_unlock(&devlink->lock);
5906}
5907
Moshe Shemesheabaef12018-07-04 14:30:28 +03005908/**
5909 * devlink_params_register - register configuration parameters
5910 *
5911 * @devlink: devlink
5912 * @params: configuration parameters array
5913 * @params_count: number of parameters provided
5914 *
5915 * Register the configuration parameters supported by the driver.
5916 */
5917int devlink_params_register(struct devlink *devlink,
5918 const struct devlink_param *params,
5919 size_t params_count)
5920{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305921 return __devlink_params_register(devlink, 0, &devlink->param_list,
5922 params, params_count,
5923 DEVLINK_CMD_PARAM_NEW,
5924 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03005925}
5926EXPORT_SYMBOL_GPL(devlink_params_register);
5927
5928/**
5929 * devlink_params_unregister - unregister configuration parameters
5930 * @devlink: devlink
5931 * @params: configuration parameters to unregister
5932 * @params_count: number of parameters provided
5933 */
5934void devlink_params_unregister(struct devlink *devlink,
5935 const struct devlink_param *params,
5936 size_t params_count)
5937{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305938 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
5939 params, params_count,
5940 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03005941}
5942EXPORT_SYMBOL_GPL(devlink_params_unregister);
5943
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03005944/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00005945 * devlink_params_publish - publish configuration parameters
5946 *
5947 * @devlink: devlink
5948 *
5949 * Publish previously registered configuration parameters.
5950 */
5951void devlink_params_publish(struct devlink *devlink)
5952{
5953 struct devlink_param_item *param_item;
5954
5955 list_for_each_entry(param_item, &devlink->param_list, list) {
5956 if (param_item->published)
5957 continue;
5958 param_item->published = true;
5959 devlink_param_notify(devlink, 0, param_item,
5960 DEVLINK_CMD_PARAM_NEW);
5961 }
5962}
5963EXPORT_SYMBOL_GPL(devlink_params_publish);
5964
5965/**
5966 * devlink_params_unpublish - unpublish configuration parameters
5967 *
5968 * @devlink: devlink
5969 *
5970 * Unpublish previously registered configuration parameters.
5971 */
5972void devlink_params_unpublish(struct devlink *devlink)
5973{
5974 struct devlink_param_item *param_item;
5975
5976 list_for_each_entry(param_item, &devlink->param_list, list) {
5977 if (!param_item->published)
5978 continue;
5979 param_item->published = false;
5980 devlink_param_notify(devlink, 0, param_item,
5981 DEVLINK_CMD_PARAM_DEL);
5982 }
5983}
5984EXPORT_SYMBOL_GPL(devlink_params_unpublish);
5985
5986/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05305987 * devlink_port_params_register - register port configuration parameters
5988 *
5989 * @devlink_port: devlink port
5990 * @params: configuration parameters array
5991 * @params_count: number of parameters provided
5992 *
5993 * Register the configuration parameters supported by the port.
5994 */
5995int devlink_port_params_register(struct devlink_port *devlink_port,
5996 const struct devlink_param *params,
5997 size_t params_count)
5998{
5999 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306000 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306001 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306002 params_count,
6003 DEVLINK_CMD_PORT_PARAM_NEW,
6004 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306005}
6006EXPORT_SYMBOL_GPL(devlink_port_params_register);
6007
6008/**
6009 * devlink_port_params_unregister - unregister port configuration
6010 * parameters
6011 *
6012 * @devlink_port: devlink port
6013 * @params: configuration parameters array
6014 * @params_count: number of parameters provided
6015 */
6016void devlink_port_params_unregister(struct devlink_port *devlink_port,
6017 const struct devlink_param *params,
6018 size_t params_count)
6019{
6020 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306021 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05306022 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306023 params, params_count,
6024 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05306025}
6026EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
6027
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306028static int
6029__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
6030 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006031{
6032 struct devlink_param_item *param_item;
6033
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306034 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006035 if (!param_item)
6036 return -EINVAL;
6037
6038 if (!param_item->driverinit_value_valid ||
6039 !devlink_param_cmode_is_supported(param_item->param,
6040 DEVLINK_PARAM_CMODE_DRIVERINIT))
6041 return -EOPNOTSUPP;
6042
Moshe Shemesh12765342018-10-10 16:09:26 +03006043 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6044 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
6045 else
6046 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006047
6048 return 0;
6049}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306050
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306051static int
6052__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306053 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306054 struct list_head *param_list, u32 param_id,
6055 union devlink_param_value init_val,
6056 enum devlink_command cmd)
6057{
6058 struct devlink_param_item *param_item;
6059
6060 param_item = devlink_param_find_by_id(param_list, param_id);
6061 if (!param_item)
6062 return -EINVAL;
6063
6064 if (!devlink_param_cmode_is_supported(param_item->param,
6065 DEVLINK_PARAM_CMODE_DRIVERINIT))
6066 return -EOPNOTSUPP;
6067
6068 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6069 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
6070 else
6071 param_item->driverinit_value = init_val;
6072 param_item->driverinit_value_valid = true;
6073
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306074 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306075 return 0;
6076}
6077
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306078/**
6079 * devlink_param_driverinit_value_get - get configuration parameter
6080 * value for driver initializing
6081 *
6082 * @devlink: devlink
6083 * @param_id: parameter ID
6084 * @init_val: value of parameter in driverinit configuration mode
6085 *
6086 * This function should be used by the driver to get driverinit
6087 * configuration for initialization after reload command.
6088 */
6089int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
6090 union devlink_param_value *init_val)
6091{
6092 if (!devlink->ops || !devlink->ops->reload)
6093 return -EOPNOTSUPP;
6094
6095 return __devlink_param_driverinit_value_get(&devlink->param_list,
6096 param_id, init_val);
6097}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006098EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
6099
6100/**
6101 * devlink_param_driverinit_value_set - set value of configuration
6102 * parameter for driverinit
6103 * configuration mode
6104 *
6105 * @devlink: devlink
6106 * @param_id: parameter ID
6107 * @init_val: value of parameter to set for driverinit configuration mode
6108 *
6109 * This function should be used by the driver to set driverinit
6110 * configuration mode default value.
6111 */
6112int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
6113 union devlink_param_value init_val)
6114{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306115 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306116 &devlink->param_list,
6117 param_id, init_val,
6118 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006119}
6120EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
6121
Moshe Shemeshea601e12018-07-04 14:30:32 +03006122/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306123 * devlink_port_param_driverinit_value_get - get configuration parameter
6124 * value for driver initializing
6125 *
6126 * @devlink_port: devlink_port
6127 * @param_id: parameter ID
6128 * @init_val: value of parameter in driverinit configuration mode
6129 *
6130 * This function should be used by the driver to get driverinit
6131 * configuration for initialization after reload command.
6132 */
6133int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
6134 u32 param_id,
6135 union devlink_param_value *init_val)
6136{
6137 struct devlink *devlink = devlink_port->devlink;
6138
6139 if (!devlink->ops || !devlink->ops->reload)
6140 return -EOPNOTSUPP;
6141
6142 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
6143 param_id, init_val);
6144}
6145EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
6146
6147/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306148 * devlink_port_param_driverinit_value_set - set value of configuration
6149 * parameter for driverinit
6150 * configuration mode
6151 *
6152 * @devlink_port: devlink_port
6153 * @param_id: parameter ID
6154 * @init_val: value of parameter to set for driverinit configuration mode
6155 *
6156 * This function should be used by the driver to set driverinit
6157 * configuration mode default value.
6158 */
6159int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
6160 u32 param_id,
6161 union devlink_param_value init_val)
6162{
6163 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306164 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306165 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306166 param_id, init_val,
6167 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306168}
6169EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
6170
6171/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03006172 * devlink_param_value_changed - notify devlink on a parameter's value
6173 * change. Should be called by the driver
6174 * right after the change.
6175 *
6176 * @devlink: devlink
6177 * @param_id: parameter ID
6178 *
6179 * This function should be used by the driver to notify devlink on value
6180 * change, excluding driverinit configuration mode.
6181 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03006182 */
6183void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
6184{
6185 struct devlink_param_item *param_item;
6186
6187 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
6188 WARN_ON(!param_item);
6189
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306190 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03006191}
6192EXPORT_SYMBOL_GPL(devlink_param_value_changed);
6193
Alex Veskerb16ebe92018-07-12 15:13:08 +03006194/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306195 * devlink_port_param_value_changed - notify devlink on a parameter's value
6196 * change. Should be called by the driver
6197 * right after the change.
6198 *
6199 * @devlink_port: devlink_port
6200 * @param_id: parameter ID
6201 *
6202 * This function should be used by the driver to notify devlink on value
6203 * change, excluding driverinit configuration mode.
6204 * For driverinit configuration mode driver should use the function
6205 * devlink_port_param_driverinit_value_set() instead.
6206 */
6207void devlink_port_param_value_changed(struct devlink_port *devlink_port,
6208 u32 param_id)
6209{
6210 struct devlink_param_item *param_item;
6211
6212 param_item = devlink_param_find_by_id(&devlink_port->param_list,
6213 param_id);
6214 WARN_ON(!param_item);
6215
6216 devlink_param_notify(devlink_port->devlink, devlink_port->index,
6217 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
6218}
6219EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
6220
6221/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03006222 * devlink_param_value_str_fill - Safely fill-up the string preventing
6223 * from overflow of the preallocated buffer
6224 *
6225 * @dst_val: destination devlink_param_value
6226 * @src: source buffer
6227 */
6228void devlink_param_value_str_fill(union devlink_param_value *dst_val,
6229 const char *src)
6230{
6231 size_t len;
6232
6233 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
6234 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
6235}
6236EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
6237
6238/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03006239 * devlink_region_create - create a new address region
6240 *
6241 * @devlink: devlink
6242 * @region_name: region name
6243 * @region_max_snapshots: Maximum supported number of snapshots for region
6244 * @region_size: size of region
6245 */
6246struct devlink_region *devlink_region_create(struct devlink *devlink,
6247 const char *region_name,
6248 u32 region_max_snapshots,
6249 u64 region_size)
6250{
6251 struct devlink_region *region;
6252 int err = 0;
6253
6254 mutex_lock(&devlink->lock);
6255
6256 if (devlink_region_get_by_name(devlink, region_name)) {
6257 err = -EEXIST;
6258 goto unlock;
6259 }
6260
6261 region = kzalloc(sizeof(*region), GFP_KERNEL);
6262 if (!region) {
6263 err = -ENOMEM;
6264 goto unlock;
6265 }
6266
6267 region->devlink = devlink;
6268 region->max_snapshots = region_max_snapshots;
6269 region->name = region_name;
6270 region->size = region_size;
6271 INIT_LIST_HEAD(&region->snapshot_list);
6272 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03006273 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03006274
6275 mutex_unlock(&devlink->lock);
6276 return region;
6277
6278unlock:
6279 mutex_unlock(&devlink->lock);
6280 return ERR_PTR(err);
6281}
6282EXPORT_SYMBOL_GPL(devlink_region_create);
6283
6284/**
6285 * devlink_region_destroy - destroy address region
6286 *
6287 * @region: devlink region to destroy
6288 */
6289void devlink_region_destroy(struct devlink_region *region)
6290{
6291 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03006292 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03006293
6294 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03006295
6296 /* Free all snapshots of region */
6297 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
6298 devlink_region_snapshot_del(snapshot);
6299
Alex Veskerb16ebe92018-07-12 15:13:08 +03006300 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03006301
6302 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03006303 mutex_unlock(&devlink->lock);
6304 kfree(region);
6305}
6306EXPORT_SYMBOL_GPL(devlink_region_destroy);
6307
Alex Veskerccadfa42018-07-12 15:13:09 +03006308/**
6309 * devlink_region_shapshot_id_get - get snapshot ID
6310 *
6311 * This callback should be called when adding a new snapshot,
6312 * Driver should use the same id for multiple snapshots taken
6313 * on multiple regions at the same time/by the same trigger.
6314 *
6315 * @devlink: devlink
6316 */
6317u32 devlink_region_shapshot_id_get(struct devlink *devlink)
6318{
6319 u32 id;
6320
6321 mutex_lock(&devlink->lock);
6322 id = ++devlink->snapshot_id;
6323 mutex_unlock(&devlink->lock);
6324
6325 return id;
6326}
6327EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
6328
Alex Veskerd7e52722018-07-12 15:13:10 +03006329/**
6330 * devlink_region_snapshot_create - create a new snapshot
6331 * This will add a new snapshot of a region. The snapshot
6332 * will be stored on the region struct and can be accessed
6333 * from devlink. This is useful for future analyses of snapshots.
6334 * Multiple snapshots can be created on a region.
6335 * The @snapshot_id should be obtained using the getter function.
6336 *
6337 * @devlink_region: devlink region of the snapshot
6338 * @data_len: size of snapshot data
6339 * @data: snapshot data
6340 * @snapshot_id: snapshot id to be created
6341 * @data_destructor: pointer to destructor function to free data
6342 */
6343int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
6344 u8 *data, u32 snapshot_id,
6345 devlink_snapshot_data_dest_t *data_destructor)
6346{
6347 struct devlink *devlink = region->devlink;
6348 struct devlink_snapshot *snapshot;
6349 int err;
6350
6351 mutex_lock(&devlink->lock);
6352
6353 /* check if region can hold one more snapshot */
6354 if (region->cur_snapshots == region->max_snapshots) {
6355 err = -ENOMEM;
6356 goto unlock;
6357 }
6358
6359 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
6360 err = -EEXIST;
6361 goto unlock;
6362 }
6363
6364 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
6365 if (!snapshot) {
6366 err = -ENOMEM;
6367 goto unlock;
6368 }
6369
6370 snapshot->id = snapshot_id;
6371 snapshot->region = region;
6372 snapshot->data = data;
6373 snapshot->data_len = data_len;
6374 snapshot->data_destructor = data_destructor;
6375
6376 list_add_tail(&snapshot->list, &region->snapshot_list);
6377
6378 region->cur_snapshots++;
6379
Alex Vesker866319b2018-07-12 15:13:13 +03006380 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
Alex Veskerd7e52722018-07-12 15:13:10 +03006381 mutex_unlock(&devlink->lock);
6382 return 0;
6383
6384unlock:
6385 mutex_unlock(&devlink->lock);
6386 return err;
6387}
6388EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
6389
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006390static void __devlink_compat_running_version(struct devlink *devlink,
6391 char *buf, size_t len)
6392{
6393 const struct nlattr *nlattr;
6394 struct devlink_info_req req;
6395 struct sk_buff *msg;
6396 int rem, err;
6397
6398 if (!devlink->ops->info_get)
6399 return;
6400
6401 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6402 if (!msg)
6403 return;
6404
6405 req.msg = msg;
6406 err = devlink->ops->info_get(devlink, &req, NULL);
6407 if (err)
6408 goto free_msg;
6409
6410 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
6411 const struct nlattr *kv;
6412 int rem_kv;
6413
6414 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
6415 continue;
6416
6417 nla_for_each_nested(kv, nlattr, rem_kv) {
6418 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
6419 continue;
6420
6421 strlcat(buf, nla_data(kv), len);
6422 strlcat(buf, " ", len);
6423 }
6424 }
6425free_msg:
6426 nlmsg_free(msg);
6427}
6428
6429void devlink_compat_running_version(struct net_device *dev,
6430 char *buf, size_t len)
6431{
6432 struct devlink_port *devlink_port;
6433 struct devlink *devlink;
6434
6435 mutex_lock(&devlink_mutex);
6436 list_for_each_entry(devlink, &devlink_list, list) {
6437 mutex_lock(&devlink->lock);
6438 list_for_each_entry(devlink_port, &devlink->port_list, list) {
Jakub Kicinski3ceb7452019-02-10 19:35:27 -08006439 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH &&
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006440 devlink_port->type_dev == dev) {
6441 __devlink_compat_running_version(devlink,
6442 buf, len);
6443 mutex_unlock(&devlink->lock);
6444 goto out;
6445 }
6446 }
6447 mutex_unlock(&devlink->lock);
6448 }
6449out:
6450 mutex_unlock(&devlink_mutex);
6451}
6452
Jakub Kicinski4eceba12019-02-14 13:40:45 -08006453int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
6454{
6455 struct devlink_port *devlink_port;
6456 struct devlink *devlink;
6457
6458 mutex_lock(&devlink_mutex);
6459 list_for_each_entry(devlink, &devlink_list, list) {
6460 mutex_lock(&devlink->lock);
6461 list_for_each_entry(devlink_port, &devlink->port_list, list) {
6462 int ret = -EOPNOTSUPP;
6463
6464 if (devlink_port->type != DEVLINK_PORT_TYPE_ETH ||
6465 devlink_port->type_dev != dev)
6466 continue;
6467
6468 mutex_unlock(&devlink_mutex);
6469 if (devlink->ops->flash_update)
6470 ret = devlink->ops->flash_update(devlink,
6471 file_name,
6472 NULL, NULL);
6473 mutex_unlock(&devlink->lock);
6474 return ret;
6475 }
6476 mutex_unlock(&devlink->lock);
6477 }
6478 mutex_unlock(&devlink_mutex);
6479
6480 return -EOPNOTSUPP;
6481}
6482
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006483static int __init devlink_module_init(void)
6484{
Johannes Berg489111e2016-10-24 14:40:03 +02006485 return genl_register_family(&devlink_nl_family);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006486}
6487
6488static void __exit devlink_module_exit(void)
6489{
6490 genl_unregister_family(&devlink_nl_family);
6491}
6492
6493module_init(devlink_module_init);
6494module_exit(devlink_module_exit);
6495
6496MODULE_LICENSE("GPL v2");
6497MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
6498MODULE_DESCRIPTION("Network physical device Netlink interface");
6499MODULE_ALIAS_GENL_FAMILY(DEVLINK_GENL_NAME);