blob: d3dfdcacf7eb25200d0e2b919cc2c7228b1eaa63 [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
119 list_for_each_entry(devlink, &devlink_list, list) {
120 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
121 strcmp(dev_name(devlink->dev), devname) == 0 &&
122 net_eq(devlink_net(devlink), net))
123 return devlink;
124 }
125
126 return ERR_PTR(-ENODEV);
127}
128
129static struct devlink *devlink_get_from_info(struct genl_info *info)
130{
131 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
132}
133
134static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
135 int port_index)
136{
137 struct devlink_port *devlink_port;
138
139 list_for_each_entry(devlink_port, &devlink->port_list, list) {
140 if (devlink_port->index == port_index)
141 return devlink_port;
142 }
143 return NULL;
144}
145
146static bool devlink_port_index_exists(struct devlink *devlink, int port_index)
147{
148 return devlink_port_get_by_index(devlink, port_index);
149}
150
151static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
152 struct nlattr **attrs)
153{
154 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
155 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
156 struct devlink_port *devlink_port;
157
158 devlink_port = devlink_port_get_by_index(devlink, port_index);
159 if (!devlink_port)
160 return ERR_PTR(-ENODEV);
161 return devlink_port;
162 }
163 return ERR_PTR(-EINVAL);
164}
165
166static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
167 struct genl_info *info)
168{
169 return devlink_port_get_from_attrs(devlink, info->attrs);
170}
171
Jiri Pirkobf797472016-04-14 18:19:13 +0200172struct devlink_sb {
173 struct list_head list;
174 unsigned int index;
175 u32 size;
176 u16 ingress_pools_count;
177 u16 egress_pools_count;
178 u16 ingress_tc_count;
179 u16 egress_tc_count;
180};
181
182static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
183{
184 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
185}
186
187static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
188 unsigned int sb_index)
189{
190 struct devlink_sb *devlink_sb;
191
192 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
193 if (devlink_sb->index == sb_index)
194 return devlink_sb;
195 }
196 return NULL;
197}
198
199static bool devlink_sb_index_exists(struct devlink *devlink,
200 unsigned int sb_index)
201{
202 return devlink_sb_get_by_index(devlink, sb_index);
203}
204
205static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
206 struct nlattr **attrs)
207{
208 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
209 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
210 struct devlink_sb *devlink_sb;
211
212 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
213 if (!devlink_sb)
214 return ERR_PTR(-ENODEV);
215 return devlink_sb;
216 }
217 return ERR_PTR(-EINVAL);
218}
219
220static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
221 struct genl_info *info)
222{
223 return devlink_sb_get_from_attrs(devlink, info->attrs);
224}
225
226static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
227 struct nlattr **attrs,
228 u16 *p_pool_index)
229{
230 u16 val;
231
232 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
233 return -EINVAL;
234
235 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
236 if (val >= devlink_sb_pool_count(devlink_sb))
237 return -EINVAL;
238 *p_pool_index = val;
239 return 0;
240}
241
242static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
243 struct genl_info *info,
244 u16 *p_pool_index)
245{
246 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
247 p_pool_index);
248}
249
250static int
251devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
252 enum devlink_sb_pool_type *p_pool_type)
253{
254 u8 val;
255
256 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
257 return -EINVAL;
258
259 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
260 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
261 val != DEVLINK_SB_POOL_TYPE_EGRESS)
262 return -EINVAL;
263 *p_pool_type = val;
264 return 0;
265}
266
267static int
268devlink_sb_pool_type_get_from_info(struct genl_info *info,
269 enum devlink_sb_pool_type *p_pool_type)
270{
271 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
272}
273
274static int
275devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
276 enum devlink_sb_threshold_type *p_th_type)
277{
278 u8 val;
279
280 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
281 return -EINVAL;
282
283 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
284 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
285 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
286 return -EINVAL;
287 *p_th_type = val;
288 return 0;
289}
290
291static int
292devlink_sb_th_type_get_from_info(struct genl_info *info,
293 enum devlink_sb_threshold_type *p_th_type)
294{
295 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
296}
297
298static int
299devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
300 struct nlattr **attrs,
301 enum devlink_sb_pool_type pool_type,
302 u16 *p_tc_index)
303{
304 u16 val;
305
306 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
307 return -EINVAL;
308
309 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
310 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
311 val >= devlink_sb->ingress_tc_count)
312 return -EINVAL;
313 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
314 val >= devlink_sb->egress_tc_count)
315 return -EINVAL;
316 *p_tc_index = val;
317 return 0;
318}
319
320static int
321devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
322 struct genl_info *info,
323 enum devlink_sb_pool_type pool_type,
324 u16 *p_tc_index)
325{
326 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
327 pool_type, p_tc_index);
328}
329
Alex Veskerb16ebe92018-07-12 15:13:08 +0300330struct devlink_region {
331 struct devlink *devlink;
332 struct list_head list;
333 const char *name;
334 struct list_head snapshot_list;
335 u32 max_snapshots;
336 u32 cur_snapshots;
337 u64 size;
338};
339
Alex Veskerd7e52722018-07-12 15:13:10 +0300340struct devlink_snapshot {
341 struct list_head list;
342 struct devlink_region *region;
343 devlink_snapshot_data_dest_t *data_destructor;
344 u64 data_len;
345 u8 *data;
346 u32 id;
347};
348
Alex Veskerb16ebe92018-07-12 15:13:08 +0300349static struct devlink_region *
350devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
351{
352 struct devlink_region *region;
353
354 list_for_each_entry(region, &devlink->region_list, list)
355 if (!strcmp(region->name, region_name))
356 return region;
357
358 return NULL;
359}
360
Alex Veskerd7e52722018-07-12 15:13:10 +0300361static struct devlink_snapshot *
362devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
363{
364 struct devlink_snapshot *snapshot;
365
366 list_for_each_entry(snapshot, &region->snapshot_list, list)
367 if (snapshot->id == id)
368 return snapshot;
369
370 return NULL;
371}
372
373static void devlink_region_snapshot_del(struct devlink_snapshot *snapshot)
374{
375 snapshot->region->cur_snapshots--;
376 list_del(&snapshot->list);
377 (*snapshot->data_destructor)(snapshot->data);
378 kfree(snapshot);
379}
380
Jiri Pirko1fc22572016-04-08 19:12:48 +0200381#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
382#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
Jiri Pirkobf797472016-04-14 18:19:13 +0200383#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100384
385/* The per devlink instance lock is taken by default in the pre-doit
386 * operation, yet several commands do not require this. The global
387 * devlink lock is taken and protects from disruption by user-calls.
388 */
389#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100390
391static int devlink_nl_pre_doit(const struct genl_ops *ops,
392 struct sk_buff *skb, struct genl_info *info)
393{
394 struct devlink *devlink;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100395 int err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100396
397 mutex_lock(&devlink_mutex);
398 devlink = devlink_get_from_info(info);
399 if (IS_ERR(devlink)) {
400 mutex_unlock(&devlink_mutex);
401 return PTR_ERR(devlink);
402 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100403 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
404 mutex_lock(&devlink->lock);
Jiri Pirko1fc22572016-04-08 19:12:48 +0200405 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
406 info->user_ptr[0] = devlink;
407 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100408 struct devlink_port *devlink_port;
409
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100410 devlink_port = devlink_port_get_from_info(devlink, info);
411 if (IS_ERR(devlink_port)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100412 err = PTR_ERR(devlink_port);
413 goto unlock;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100414 }
Jiri Pirko1fc22572016-04-08 19:12:48 +0200415 info->user_ptr[0] = devlink_port;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100416 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200417 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
418 struct devlink_sb *devlink_sb;
419
420 devlink_sb = devlink_sb_get_from_info(devlink, info);
421 if (IS_ERR(devlink_sb)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100422 err = PTR_ERR(devlink_sb);
423 goto unlock;
Jiri Pirkobf797472016-04-14 18:19:13 +0200424 }
425 info->user_ptr[1] = devlink_sb;
426 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100427 return 0;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100428
429unlock:
430 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
431 mutex_unlock(&devlink->lock);
432 mutex_unlock(&devlink_mutex);
433 return err;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100434}
435
436static void devlink_nl_post_doit(const struct genl_ops *ops,
437 struct sk_buff *skb, struct genl_info *info)
438{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100439 struct devlink *devlink;
440
441 devlink = devlink_get_from_info(info);
442 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
443 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100444 mutex_unlock(&devlink_mutex);
445}
446
Johannes Berg489111e2016-10-24 14:40:03 +0200447static struct genl_family devlink_nl_family;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100448
449enum devlink_multicast_groups {
450 DEVLINK_MCGRP_CONFIG,
451};
452
453static const struct genl_multicast_group devlink_nl_mcgrps[] = {
454 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
455};
456
457static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
458{
459 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
460 return -EMSGSIZE;
461 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
462 return -EMSGSIZE;
463 return 0;
464}
465
466static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
467 enum devlink_command cmd, u32 portid,
468 u32 seq, int flags)
469{
470 void *hdr;
471
472 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
473 if (!hdr)
474 return -EMSGSIZE;
475
476 if (devlink_nl_put_handle(msg, devlink))
477 goto nla_put_failure;
478
479 genlmsg_end(msg, hdr);
480 return 0;
481
482nla_put_failure:
483 genlmsg_cancel(msg, hdr);
484 return -EMSGSIZE;
485}
486
487static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
488{
489 struct sk_buff *msg;
490 int err;
491
492 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
493
494 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
495 if (!msg)
496 return;
497
498 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
499 if (err) {
500 nlmsg_free(msg);
501 return;
502 }
503
504 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
505 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
506}
507
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200508static int devlink_nl_port_attrs_put(struct sk_buff *msg,
509 struct devlink_port *devlink_port)
510{
511 struct devlink_port_attrs *attrs = &devlink_port->attrs;
512
513 if (!attrs->set)
514 return 0;
Jiri Pirko5ec13802018-05-18 09:29:01 +0200515 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
516 return -EMSGSIZE;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200517 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER, attrs->port_number))
518 return -EMSGSIZE;
519 if (!attrs->split)
520 return 0;
521 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP, attrs->port_number))
522 return -EMSGSIZE;
523 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
524 attrs->split_subport_number))
525 return -EMSGSIZE;
526 return 0;
527}
528
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100529static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
530 struct devlink_port *devlink_port,
531 enum devlink_command cmd, u32 portid,
532 u32 seq, int flags)
533{
534 void *hdr;
535
536 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
537 if (!hdr)
538 return -EMSGSIZE;
539
540 if (devlink_nl_put_handle(msg, devlink))
541 goto nla_put_failure;
542 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
543 goto nla_put_failure;
544 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
545 goto nla_put_failure;
546 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
547 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
548 devlink_port->desired_type))
549 goto nla_put_failure;
550 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
551 struct net_device *netdev = devlink_port->type_dev;
552
553 if (netdev &&
554 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
555 netdev->ifindex) ||
556 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
557 netdev->name)))
558 goto nla_put_failure;
559 }
560 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
561 struct ib_device *ibdev = devlink_port->type_dev;
562
563 if (ibdev &&
564 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
565 ibdev->name))
566 goto nla_put_failure;
567 }
Jiri Pirkob9ffcba2018-05-18 09:29:00 +0200568 if (devlink_nl_port_attrs_put(msg, devlink_port))
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100569 goto nla_put_failure;
570
571 genlmsg_end(msg, hdr);
572 return 0;
573
574nla_put_failure:
575 genlmsg_cancel(msg, hdr);
576 return -EMSGSIZE;
577}
578
579static void devlink_port_notify(struct devlink_port *devlink_port,
580 enum devlink_command cmd)
581{
582 struct devlink *devlink = devlink_port->devlink;
583 struct sk_buff *msg;
584 int err;
585
586 if (!devlink_port->registered)
587 return;
588
589 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
590
591 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
592 if (!msg)
593 return;
594
595 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
596 if (err) {
597 nlmsg_free(msg);
598 return;
599 }
600
601 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
602 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
603}
604
605static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
606{
607 struct devlink *devlink = info->user_ptr[0];
608 struct sk_buff *msg;
609 int err;
610
611 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
612 if (!msg)
613 return -ENOMEM;
614
615 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
616 info->snd_portid, info->snd_seq, 0);
617 if (err) {
618 nlmsg_free(msg);
619 return err;
620 }
621
622 return genlmsg_reply(msg, info);
623}
624
625static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
626 struct netlink_callback *cb)
627{
628 struct devlink *devlink;
629 int start = cb->args[0];
630 int idx = 0;
631 int err;
632
633 mutex_lock(&devlink_mutex);
634 list_for_each_entry(devlink, &devlink_list, list) {
635 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
636 continue;
637 if (idx < start) {
638 idx++;
639 continue;
640 }
641 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
642 NETLINK_CB(cb->skb).portid,
643 cb->nlh->nlmsg_seq, NLM_F_MULTI);
644 if (err)
645 goto out;
646 idx++;
647 }
648out:
649 mutex_unlock(&devlink_mutex);
650
651 cb->args[0] = idx;
652 return msg->len;
653}
654
655static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
656 struct genl_info *info)
657{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200658 struct devlink_port *devlink_port = info->user_ptr[0];
659 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100660 struct sk_buff *msg;
661 int err;
662
663 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
664 if (!msg)
665 return -ENOMEM;
666
667 err = devlink_nl_port_fill(msg, devlink, devlink_port,
668 DEVLINK_CMD_PORT_NEW,
669 info->snd_portid, info->snd_seq, 0);
670 if (err) {
671 nlmsg_free(msg);
672 return err;
673 }
674
675 return genlmsg_reply(msg, info);
676}
677
678static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
679 struct netlink_callback *cb)
680{
681 struct devlink *devlink;
682 struct devlink_port *devlink_port;
683 int start = cb->args[0];
684 int idx = 0;
685 int err;
686
687 mutex_lock(&devlink_mutex);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100688 list_for_each_entry(devlink, &devlink_list, list) {
689 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
690 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100691 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100692 list_for_each_entry(devlink_port, &devlink->port_list, list) {
693 if (idx < start) {
694 idx++;
695 continue;
696 }
697 err = devlink_nl_port_fill(msg, devlink, devlink_port,
698 DEVLINK_CMD_NEW,
699 NETLINK_CB(cb->skb).portid,
700 cb->nlh->nlmsg_seq,
701 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100702 if (err) {
703 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100704 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100705 }
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100706 idx++;
707 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100708 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100709 }
710out:
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100711 mutex_unlock(&devlink_mutex);
712
713 cb->args[0] = idx;
714 return msg->len;
715}
716
717static int devlink_port_type_set(struct devlink *devlink,
718 struct devlink_port *devlink_port,
719 enum devlink_port_type port_type)
720
721{
722 int err;
723
724 if (devlink->ops && devlink->ops->port_type_set) {
725 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
726 return -EINVAL;
Elad Raz6edf1012016-10-23 17:43:05 +0200727 if (port_type == devlink_port->type)
728 return 0;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100729 err = devlink->ops->port_type_set(devlink_port, port_type);
730 if (err)
731 return err;
732 devlink_port->desired_type = port_type;
733 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
734 return 0;
735 }
736 return -EOPNOTSUPP;
737}
738
739static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
740 struct genl_info *info)
741{
Jiri Pirko1fc22572016-04-08 19:12:48 +0200742 struct devlink_port *devlink_port = info->user_ptr[0];
743 struct devlink *devlink = devlink_port->devlink;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100744 int err;
745
746 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
747 enum devlink_port_type port_type;
748
749 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
750 err = devlink_port_type_set(devlink, devlink_port, port_type);
751 if (err)
752 return err;
753 }
754 return 0;
755}
756
David Ahernac0fc8a2018-06-05 08:14:09 -0700757static int devlink_port_split(struct devlink *devlink, u32 port_index,
758 u32 count, struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100759
760{
761 if (devlink->ops && devlink->ops->port_split)
David Ahernac0fc8a2018-06-05 08:14:09 -0700762 return devlink->ops->port_split(devlink, port_index, count,
763 extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100764 return -EOPNOTSUPP;
765}
766
767static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
768 struct genl_info *info)
769{
770 struct devlink *devlink = info->user_ptr[0];
771 u32 port_index;
772 u32 count;
773
774 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
775 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
776 return -EINVAL;
777
778 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
779 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700780 return devlink_port_split(devlink, port_index, count, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100781}
782
David Ahernac0fc8a2018-06-05 08:14:09 -0700783static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
784 struct netlink_ext_ack *extack)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100785
786{
787 if (devlink->ops && devlink->ops->port_unsplit)
David Ahernac0fc8a2018-06-05 08:14:09 -0700788 return devlink->ops->port_unsplit(devlink, port_index, extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100789 return -EOPNOTSUPP;
790}
791
792static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
793 struct genl_info *info)
794{
795 struct devlink *devlink = info->user_ptr[0];
796 u32 port_index;
797
798 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
799 return -EINVAL;
800
801 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
David Ahernac0fc8a2018-06-05 08:14:09 -0700802 return devlink_port_unsplit(devlink, port_index, info->extack);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +0100803}
804
Jiri Pirkobf797472016-04-14 18:19:13 +0200805static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
806 struct devlink_sb *devlink_sb,
807 enum devlink_command cmd, u32 portid,
808 u32 seq, int flags)
809{
810 void *hdr;
811
812 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
813 if (!hdr)
814 return -EMSGSIZE;
815
816 if (devlink_nl_put_handle(msg, devlink))
817 goto nla_put_failure;
818 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
819 goto nla_put_failure;
820 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
821 goto nla_put_failure;
822 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
823 devlink_sb->ingress_pools_count))
824 goto nla_put_failure;
825 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
826 devlink_sb->egress_pools_count))
827 goto nla_put_failure;
828 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
829 devlink_sb->ingress_tc_count))
830 goto nla_put_failure;
831 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
832 devlink_sb->egress_tc_count))
833 goto nla_put_failure;
834
835 genlmsg_end(msg, hdr);
836 return 0;
837
838nla_put_failure:
839 genlmsg_cancel(msg, hdr);
840 return -EMSGSIZE;
841}
842
843static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
844 struct genl_info *info)
845{
846 struct devlink *devlink = info->user_ptr[0];
847 struct devlink_sb *devlink_sb = info->user_ptr[1];
848 struct sk_buff *msg;
849 int err;
850
851 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
852 if (!msg)
853 return -ENOMEM;
854
855 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
856 DEVLINK_CMD_SB_NEW,
857 info->snd_portid, info->snd_seq, 0);
858 if (err) {
859 nlmsg_free(msg);
860 return err;
861 }
862
863 return genlmsg_reply(msg, info);
864}
865
866static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
867 struct netlink_callback *cb)
868{
869 struct devlink *devlink;
870 struct devlink_sb *devlink_sb;
871 int start = cb->args[0];
872 int idx = 0;
873 int err;
874
875 mutex_lock(&devlink_mutex);
876 list_for_each_entry(devlink, &devlink_list, list) {
877 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
878 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100879 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200880 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
881 if (idx < start) {
882 idx++;
883 continue;
884 }
885 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
886 DEVLINK_CMD_SB_NEW,
887 NETLINK_CB(cb->skb).portid,
888 cb->nlh->nlmsg_seq,
889 NLM_F_MULTI);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100890 if (err) {
891 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200892 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100893 }
Jiri Pirkobf797472016-04-14 18:19:13 +0200894 idx++;
895 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +0100896 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +0200897 }
898out:
899 mutex_unlock(&devlink_mutex);
900
901 cb->args[0] = idx;
902 return msg->len;
903}
904
905static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
906 struct devlink_sb *devlink_sb,
907 u16 pool_index, enum devlink_command cmd,
908 u32 portid, u32 seq, int flags)
909{
910 struct devlink_sb_pool_info pool_info;
911 void *hdr;
912 int err;
913
914 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
915 pool_index, &pool_info);
916 if (err)
917 return err;
918
919 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
920 if (!hdr)
921 return -EMSGSIZE;
922
923 if (devlink_nl_put_handle(msg, devlink))
924 goto nla_put_failure;
925 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
926 goto nla_put_failure;
927 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
928 goto nla_put_failure;
929 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
930 goto nla_put_failure;
931 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
932 goto nla_put_failure;
933 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
934 pool_info.threshold_type))
935 goto nla_put_failure;
Jakub Kicinskibff57312019-02-01 17:56:28 -0800936 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
937 pool_info.cell_size))
938 goto nla_put_failure;
Jiri Pirkobf797472016-04-14 18:19:13 +0200939
940 genlmsg_end(msg, hdr);
941 return 0;
942
943nla_put_failure:
944 genlmsg_cancel(msg, hdr);
945 return -EMSGSIZE;
946}
947
948static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
949 struct genl_info *info)
950{
951 struct devlink *devlink = info->user_ptr[0];
952 struct devlink_sb *devlink_sb = info->user_ptr[1];
953 struct sk_buff *msg;
954 u16 pool_index;
955 int err;
956
957 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
958 &pool_index);
959 if (err)
960 return err;
961
962 if (!devlink->ops || !devlink->ops->sb_pool_get)
963 return -EOPNOTSUPP;
964
965 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
966 if (!msg)
967 return -ENOMEM;
968
969 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
970 DEVLINK_CMD_SB_POOL_NEW,
971 info->snd_portid, info->snd_seq, 0);
972 if (err) {
973 nlmsg_free(msg);
974 return err;
975 }
976
977 return genlmsg_reply(msg, info);
978}
979
980static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
981 struct devlink *devlink,
982 struct devlink_sb *devlink_sb,
983 u32 portid, u32 seq)
984{
985 u16 pool_count = devlink_sb_pool_count(devlink_sb);
986 u16 pool_index;
987 int err;
988
989 for (pool_index = 0; pool_index < pool_count; pool_index++) {
990 if (*p_idx < start) {
991 (*p_idx)++;
992 continue;
993 }
994 err = devlink_nl_sb_pool_fill(msg, devlink,
995 devlink_sb,
996 pool_index,
997 DEVLINK_CMD_SB_POOL_NEW,
998 portid, seq, NLM_F_MULTI);
999 if (err)
1000 return err;
1001 (*p_idx)++;
1002 }
1003 return 0;
1004}
1005
1006static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1007 struct netlink_callback *cb)
1008{
1009 struct devlink *devlink;
1010 struct devlink_sb *devlink_sb;
1011 int start = cb->args[0];
1012 int idx = 0;
1013 int err;
1014
1015 mutex_lock(&devlink_mutex);
1016 list_for_each_entry(devlink, &devlink_list, list) {
1017 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1018 !devlink->ops || !devlink->ops->sb_pool_get)
1019 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001020 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001021 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1022 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1023 devlink_sb,
1024 NETLINK_CB(cb->skb).portid,
1025 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001026 if (err && err != -EOPNOTSUPP) {
1027 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001028 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001029 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001030 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001031 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001032 }
1033out:
1034 mutex_unlock(&devlink_mutex);
1035
1036 cb->args[0] = idx;
1037 return msg->len;
1038}
1039
1040static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1041 u16 pool_index, u32 size,
1042 enum devlink_sb_threshold_type threshold_type)
1043
1044{
1045 const struct devlink_ops *ops = devlink->ops;
1046
1047 if (ops && ops->sb_pool_set)
1048 return ops->sb_pool_set(devlink, sb_index, pool_index,
1049 size, threshold_type);
1050 return -EOPNOTSUPP;
1051}
1052
1053static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1054 struct genl_info *info)
1055{
1056 struct devlink *devlink = info->user_ptr[0];
1057 struct devlink_sb *devlink_sb = info->user_ptr[1];
1058 enum devlink_sb_threshold_type threshold_type;
1059 u16 pool_index;
1060 u32 size;
1061 int err;
1062
1063 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1064 &pool_index);
1065 if (err)
1066 return err;
1067
1068 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1069 if (err)
1070 return err;
1071
1072 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1073 return -EINVAL;
1074
1075 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1076 return devlink_sb_pool_set(devlink, devlink_sb->index,
1077 pool_index, size, threshold_type);
1078}
1079
1080static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1081 struct devlink *devlink,
1082 struct devlink_port *devlink_port,
1083 struct devlink_sb *devlink_sb,
1084 u16 pool_index,
1085 enum devlink_command cmd,
1086 u32 portid, u32 seq, int flags)
1087{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001088 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001089 u32 threshold;
1090 void *hdr;
1091 int err;
1092
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001093 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1094 pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001095 if (err)
1096 return err;
1097
1098 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1099 if (!hdr)
1100 return -EMSGSIZE;
1101
1102 if (devlink_nl_put_handle(msg, devlink))
1103 goto nla_put_failure;
1104 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1105 goto nla_put_failure;
1106 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1107 goto nla_put_failure;
1108 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1109 goto nla_put_failure;
1110 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1111 goto nla_put_failure;
1112
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001113 if (ops->sb_occ_port_pool_get) {
1114 u32 cur;
1115 u32 max;
1116
1117 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1118 pool_index, &cur, &max);
1119 if (err && err != -EOPNOTSUPP)
1120 return err;
1121 if (!err) {
1122 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1123 goto nla_put_failure;
1124 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1125 goto nla_put_failure;
1126 }
1127 }
1128
Jiri Pirkobf797472016-04-14 18:19:13 +02001129 genlmsg_end(msg, hdr);
1130 return 0;
1131
1132nla_put_failure:
1133 genlmsg_cancel(msg, hdr);
1134 return -EMSGSIZE;
1135}
1136
1137static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1138 struct genl_info *info)
1139{
1140 struct devlink_port *devlink_port = info->user_ptr[0];
1141 struct devlink *devlink = devlink_port->devlink;
1142 struct devlink_sb *devlink_sb = info->user_ptr[1];
1143 struct sk_buff *msg;
1144 u16 pool_index;
1145 int err;
1146
1147 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1148 &pool_index);
1149 if (err)
1150 return err;
1151
1152 if (!devlink->ops || !devlink->ops->sb_port_pool_get)
1153 return -EOPNOTSUPP;
1154
1155 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1156 if (!msg)
1157 return -ENOMEM;
1158
1159 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1160 devlink_sb, pool_index,
1161 DEVLINK_CMD_SB_PORT_POOL_NEW,
1162 info->snd_portid, info->snd_seq, 0);
1163 if (err) {
1164 nlmsg_free(msg);
1165 return err;
1166 }
1167
1168 return genlmsg_reply(msg, info);
1169}
1170
1171static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1172 struct devlink *devlink,
1173 struct devlink_sb *devlink_sb,
1174 u32 portid, u32 seq)
1175{
1176 struct devlink_port *devlink_port;
1177 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1178 u16 pool_index;
1179 int err;
1180
1181 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1182 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1183 if (*p_idx < start) {
1184 (*p_idx)++;
1185 continue;
1186 }
1187 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1188 devlink_port,
1189 devlink_sb,
1190 pool_index,
1191 DEVLINK_CMD_SB_PORT_POOL_NEW,
1192 portid, seq,
1193 NLM_F_MULTI);
1194 if (err)
1195 return err;
1196 (*p_idx)++;
1197 }
1198 }
1199 return 0;
1200}
1201
1202static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1203 struct netlink_callback *cb)
1204{
1205 struct devlink *devlink;
1206 struct devlink_sb *devlink_sb;
1207 int start = cb->args[0];
1208 int idx = 0;
1209 int err;
1210
1211 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001212 list_for_each_entry(devlink, &devlink_list, list) {
1213 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1214 !devlink->ops || !devlink->ops->sb_port_pool_get)
1215 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001216 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001217 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1218 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1219 devlink, devlink_sb,
1220 NETLINK_CB(cb->skb).portid,
1221 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001222 if (err && err != -EOPNOTSUPP) {
1223 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001224 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001225 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001226 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001227 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001228 }
1229out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001230 mutex_unlock(&devlink_mutex);
1231
1232 cb->args[0] = idx;
1233 return msg->len;
1234}
1235
1236static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1237 unsigned int sb_index, u16 pool_index,
1238 u32 threshold)
1239
1240{
1241 const struct devlink_ops *ops = devlink_port->devlink->ops;
1242
1243 if (ops && ops->sb_port_pool_set)
1244 return ops->sb_port_pool_set(devlink_port, sb_index,
1245 pool_index, threshold);
1246 return -EOPNOTSUPP;
1247}
1248
1249static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1250 struct genl_info *info)
1251{
1252 struct devlink_port *devlink_port = info->user_ptr[0];
1253 struct devlink_sb *devlink_sb = info->user_ptr[1];
1254 u16 pool_index;
1255 u32 threshold;
1256 int err;
1257
1258 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1259 &pool_index);
1260 if (err)
1261 return err;
1262
1263 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1264 return -EINVAL;
1265
1266 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1267 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
1268 pool_index, threshold);
1269}
1270
1271static int
1272devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1273 struct devlink_port *devlink_port,
1274 struct devlink_sb *devlink_sb, u16 tc_index,
1275 enum devlink_sb_pool_type pool_type,
1276 enum devlink_command cmd,
1277 u32 portid, u32 seq, int flags)
1278{
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001279 const struct devlink_ops *ops = devlink->ops;
Jiri Pirkobf797472016-04-14 18:19:13 +02001280 u16 pool_index;
1281 u32 threshold;
1282 void *hdr;
1283 int err;
1284
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001285 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1286 tc_index, pool_type,
1287 &pool_index, &threshold);
Jiri Pirkobf797472016-04-14 18:19:13 +02001288 if (err)
1289 return err;
1290
1291 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1292 if (!hdr)
1293 return -EMSGSIZE;
1294
1295 if (devlink_nl_put_handle(msg, devlink))
1296 goto nla_put_failure;
1297 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1298 goto nla_put_failure;
1299 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1300 goto nla_put_failure;
1301 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1302 goto nla_put_failure;
1303 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1304 goto nla_put_failure;
1305 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1306 goto nla_put_failure;
1307 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1308 goto nla_put_failure;
1309
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001310 if (ops->sb_occ_tc_port_bind_get) {
1311 u32 cur;
1312 u32 max;
1313
1314 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1315 devlink_sb->index,
1316 tc_index, pool_type,
1317 &cur, &max);
1318 if (err && err != -EOPNOTSUPP)
1319 return err;
1320 if (!err) {
1321 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1322 goto nla_put_failure;
1323 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1324 goto nla_put_failure;
1325 }
1326 }
1327
Jiri Pirkobf797472016-04-14 18:19:13 +02001328 genlmsg_end(msg, hdr);
1329 return 0;
1330
1331nla_put_failure:
1332 genlmsg_cancel(msg, hdr);
1333 return -EMSGSIZE;
1334}
1335
1336static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1337 struct genl_info *info)
1338{
1339 struct devlink_port *devlink_port = info->user_ptr[0];
1340 struct devlink *devlink = devlink_port->devlink;
1341 struct devlink_sb *devlink_sb = info->user_ptr[1];
1342 struct sk_buff *msg;
1343 enum devlink_sb_pool_type pool_type;
1344 u16 tc_index;
1345 int err;
1346
1347 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1348 if (err)
1349 return err;
1350
1351 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1352 pool_type, &tc_index);
1353 if (err)
1354 return err;
1355
1356 if (!devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
1357 return -EOPNOTSUPP;
1358
1359 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1360 if (!msg)
1361 return -ENOMEM;
1362
1363 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1364 devlink_sb, tc_index, pool_type,
1365 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1366 info->snd_portid,
1367 info->snd_seq, 0);
1368 if (err) {
1369 nlmsg_free(msg);
1370 return err;
1371 }
1372
1373 return genlmsg_reply(msg, info);
1374}
1375
1376static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1377 int start, int *p_idx,
1378 struct devlink *devlink,
1379 struct devlink_sb *devlink_sb,
1380 u32 portid, u32 seq)
1381{
1382 struct devlink_port *devlink_port;
1383 u16 tc_index;
1384 int err;
1385
1386 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1387 for (tc_index = 0;
1388 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1389 if (*p_idx < start) {
1390 (*p_idx)++;
1391 continue;
1392 }
1393 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1394 devlink_port,
1395 devlink_sb,
1396 tc_index,
1397 DEVLINK_SB_POOL_TYPE_INGRESS,
1398 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1399 portid, seq,
1400 NLM_F_MULTI);
1401 if (err)
1402 return err;
1403 (*p_idx)++;
1404 }
1405 for (tc_index = 0;
1406 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1407 if (*p_idx < start) {
1408 (*p_idx)++;
1409 continue;
1410 }
1411 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1412 devlink_port,
1413 devlink_sb,
1414 tc_index,
1415 DEVLINK_SB_POOL_TYPE_EGRESS,
1416 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1417 portid, seq,
1418 NLM_F_MULTI);
1419 if (err)
1420 return err;
1421 (*p_idx)++;
1422 }
1423 }
1424 return 0;
1425}
1426
1427static int
1428devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1429 struct netlink_callback *cb)
1430{
1431 struct devlink *devlink;
1432 struct devlink_sb *devlink_sb;
1433 int start = cb->args[0];
1434 int idx = 0;
1435 int err;
1436
1437 mutex_lock(&devlink_mutex);
Jiri Pirkobf797472016-04-14 18:19:13 +02001438 list_for_each_entry(devlink, &devlink_list, list) {
1439 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1440 !devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
1441 continue;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001442
1443 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001444 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1445 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1446 devlink,
1447 devlink_sb,
1448 NETLINK_CB(cb->skb).portid,
1449 cb->nlh->nlmsg_seq);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001450 if (err && err != -EOPNOTSUPP) {
1451 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001452 goto out;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001453 }
Jiri Pirkobf797472016-04-14 18:19:13 +02001454 }
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01001455 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02001456 }
1457out:
Jiri Pirkobf797472016-04-14 18:19:13 +02001458 mutex_unlock(&devlink_mutex);
1459
1460 cb->args[0] = idx;
1461 return msg->len;
1462}
1463
1464static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1465 unsigned int sb_index, u16 tc_index,
1466 enum devlink_sb_pool_type pool_type,
1467 u16 pool_index, u32 threshold)
1468
1469{
1470 const struct devlink_ops *ops = devlink_port->devlink->ops;
1471
1472 if (ops && ops->sb_tc_pool_bind_set)
1473 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1474 tc_index, pool_type,
1475 pool_index, threshold);
1476 return -EOPNOTSUPP;
1477}
1478
1479static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1480 struct genl_info *info)
1481{
1482 struct devlink_port *devlink_port = info->user_ptr[0];
1483 struct devlink_sb *devlink_sb = info->user_ptr[1];
1484 enum devlink_sb_pool_type pool_type;
1485 u16 tc_index;
1486 u16 pool_index;
1487 u32 threshold;
1488 int err;
1489
1490 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1491 if (err)
1492 return err;
1493
1494 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1495 pool_type, &tc_index);
1496 if (err)
1497 return err;
1498
1499 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1500 &pool_index);
1501 if (err)
1502 return err;
1503
1504 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1505 return -EINVAL;
1506
1507 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1508 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1509 tc_index, pool_type,
1510 pool_index, threshold);
1511}
1512
Jiri Pirkodf38daf2016-04-14 18:19:14 +02001513static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1514 struct genl_info *info)
1515{
1516 struct devlink *devlink = info->user_ptr[0];
1517 struct devlink_sb *devlink_sb = info->user_ptr[1];
1518 const struct devlink_ops *ops = devlink->ops;
1519
1520 if (ops && ops->sb_occ_snapshot)
1521 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1522 return -EOPNOTSUPP;
1523}
1524
1525static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1526 struct genl_info *info)
1527{
1528 struct devlink *devlink = info->user_ptr[0];
1529 struct devlink_sb *devlink_sb = info->user_ptr[1];
1530 const struct devlink_ops *ops = devlink->ops;
1531
1532 if (ops && ops->sb_occ_max_clear)
1533 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1534 return -EOPNOTSUPP;
1535}
1536
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001537static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1538 enum devlink_command cmd, u32 portid,
1539 u32 seq, int flags)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001540{
Roi Dayan59bfde02016-11-22 23:09:57 +02001541 const struct devlink_ops *ops = devlink->ops;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001542 u8 inline_mode, encap_mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001543 void *hdr;
Roi Dayan59bfde02016-11-22 23:09:57 +02001544 int err = 0;
1545 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001546
1547 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1548 if (!hdr)
1549 return -EMSGSIZE;
1550
Roi Dayan59bfde02016-11-22 23:09:57 +02001551 err = devlink_nl_put_handle(msg, devlink);
1552 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001553 goto nla_put_failure;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001554
Jiri Pirko4456f612017-02-09 15:54:36 +01001555 if (ops->eswitch_mode_get) {
1556 err = ops->eswitch_mode_get(devlink, &mode);
1557 if (err)
1558 goto nla_put_failure;
1559 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1560 if (err)
1561 goto nla_put_failure;
1562 }
Roi Dayan59bfde02016-11-22 23:09:57 +02001563
1564 if (ops->eswitch_inline_mode_get) {
1565 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1566 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001567 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001568 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1569 inline_mode);
1570 if (err)
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001571 goto nla_put_failure;
Roi Dayan59bfde02016-11-22 23:09:57 +02001572 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001573
Roi Dayanf43e9b02016-09-25 13:52:44 +03001574 if (ops->eswitch_encap_mode_get) {
1575 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1576 if (err)
1577 goto nla_put_failure;
1578 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1579 if (err)
1580 goto nla_put_failure;
1581 }
1582
Or Gerlitz08f4b592016-07-01 14:51:01 +03001583 genlmsg_end(msg, hdr);
1584 return 0;
1585
Jiri Pirko1a6aa362017-02-09 15:54:35 +01001586nla_put_failure:
Or Gerlitz08f4b592016-07-01 14:51:01 +03001587 genlmsg_cancel(msg, hdr);
Roi Dayan59bfde02016-11-22 23:09:57 +02001588 return err;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001589}
1590
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001591static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1592 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001593{
1594 struct devlink *devlink = info->user_ptr[0];
1595 const struct devlink_ops *ops = devlink->ops;
1596 struct sk_buff *msg;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001597 int err;
1598
Jiri Pirko4456f612017-02-09 15:54:36 +01001599 if (!ops)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001600 return -EOPNOTSUPP;
1601
Or Gerlitz08f4b592016-07-01 14:51:01 +03001602 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1603 if (!msg)
1604 return -ENOMEM;
1605
Jiri Pirko21e3d2d2017-02-09 15:54:34 +01001606 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1607 info->snd_portid, info->snd_seq, 0);
Or Gerlitz08f4b592016-07-01 14:51:01 +03001608
1609 if (err) {
1610 nlmsg_free(msg);
1611 return err;
1612 }
1613
1614 return genlmsg_reply(msg, info);
1615}
1616
Jiri Pirkoadf200f2017-02-09 15:54:33 +01001617static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1618 struct genl_info *info)
Or Gerlitz08f4b592016-07-01 14:51:01 +03001619{
1620 struct devlink *devlink = info->user_ptr[0];
1621 const struct devlink_ops *ops = devlink->ops;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001622 u8 inline_mode, encap_mode;
Roi Dayan59bfde02016-11-22 23:09:57 +02001623 int err = 0;
Roi Dayanf43e9b02016-09-25 13:52:44 +03001624 u16 mode;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001625
Roi Dayan59bfde02016-11-22 23:09:57 +02001626 if (!ops)
1627 return -EOPNOTSUPP;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001628
Roi Dayan59bfde02016-11-22 23:09:57 +02001629 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1630 if (!ops->eswitch_mode_set)
1631 return -EOPNOTSUPP;
1632 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001633 err = ops->eswitch_mode_set(devlink, mode, info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001634 if (err)
1635 return err;
1636 }
Or Gerlitz08f4b592016-07-01 14:51:01 +03001637
Roi Dayan59bfde02016-11-22 23:09:57 +02001638 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1639 if (!ops->eswitch_inline_mode_set)
1640 return -EOPNOTSUPP;
1641 inline_mode = nla_get_u8(
1642 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001643 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1644 info->extack);
Roi Dayan59bfde02016-11-22 23:09:57 +02001645 if (err)
1646 return err;
1647 }
Roi Dayanf43e9b02016-09-25 13:52:44 +03001648
1649 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1650 if (!ops->eswitch_encap_mode_set)
1651 return -EOPNOTSUPP;
1652 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
Eli Britsteindb7ff192018-08-15 16:02:18 +03001653 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1654 info->extack);
Roi Dayanf43e9b02016-09-25 13:52:44 +03001655 if (err)
1656 return err;
1657 }
1658
Roi Dayan59bfde02016-11-22 23:09:57 +02001659 return 0;
Or Gerlitz08f4b592016-07-01 14:51:01 +03001660}
1661
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001662int devlink_dpipe_match_put(struct sk_buff *skb,
1663 struct devlink_dpipe_match *match)
1664{
1665 struct devlink_dpipe_header *header = match->header;
1666 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1667 struct nlattr *match_attr;
1668
1669 match_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_MATCH);
1670 if (!match_attr)
1671 return -EMSGSIZE;
1672
1673 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1674 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1675 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1676 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1677 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1678 goto nla_put_failure;
1679
1680 nla_nest_end(skb, match_attr);
1681 return 0;
1682
1683nla_put_failure:
1684 nla_nest_cancel(skb, match_attr);
1685 return -EMSGSIZE;
1686}
1687EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1688
1689static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1690 struct sk_buff *skb)
1691{
1692 struct nlattr *matches_attr;
1693
1694 matches_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
1695 if (!matches_attr)
1696 return -EMSGSIZE;
1697
1698 if (table->table_ops->matches_dump(table->priv, skb))
1699 goto nla_put_failure;
1700
1701 nla_nest_end(skb, matches_attr);
1702 return 0;
1703
1704nla_put_failure:
1705 nla_nest_cancel(skb, matches_attr);
1706 return -EMSGSIZE;
1707}
1708
1709int devlink_dpipe_action_put(struct sk_buff *skb,
1710 struct devlink_dpipe_action *action)
1711{
1712 struct devlink_dpipe_header *header = action->header;
1713 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1714 struct nlattr *action_attr;
1715
1716 action_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ACTION);
1717 if (!action_attr)
1718 return -EMSGSIZE;
1719
1720 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1721 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1722 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1723 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1724 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1725 goto nla_put_failure;
1726
1727 nla_nest_end(skb, action_attr);
1728 return 0;
1729
1730nla_put_failure:
1731 nla_nest_cancel(skb, action_attr);
1732 return -EMSGSIZE;
1733}
1734EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1735
1736static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1737 struct sk_buff *skb)
1738{
1739 struct nlattr *actions_attr;
1740
1741 actions_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
1742 if (!actions_attr)
1743 return -EMSGSIZE;
1744
1745 if (table->table_ops->actions_dump(table->priv, skb))
1746 goto nla_put_failure;
1747
1748 nla_nest_end(skb, actions_attr);
1749 return 0;
1750
1751nla_put_failure:
1752 nla_nest_cancel(skb, actions_attr);
1753 return -EMSGSIZE;
1754}
1755
1756static int devlink_dpipe_table_put(struct sk_buff *skb,
1757 struct devlink_dpipe_table *table)
1758{
1759 struct nlattr *table_attr;
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001760 u64 table_size;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001761
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001762 table_size = table->table_ops->size_get(table->priv);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001763 table_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE);
1764 if (!table_attr)
1765 return -EMSGSIZE;
1766
1767 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02001768 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001769 DEVLINK_ATTR_PAD))
1770 goto nla_put_failure;
1771 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1772 table->counters_enabled))
1773 goto nla_put_failure;
1774
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001775 if (table->resource_valid) {
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02001776 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1777 table->resource_id, DEVLINK_ATTR_PAD) ||
1778 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1779 table->resource_units, DEVLINK_ATTR_PAD))
1780 goto nla_put_failure;
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01001781 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001782 if (devlink_dpipe_matches_put(table, skb))
1783 goto nla_put_failure;
1784
1785 if (devlink_dpipe_actions_put(table, skb))
1786 goto nla_put_failure;
1787
1788 nla_nest_end(skb, table_attr);
1789 return 0;
1790
1791nla_put_failure:
1792 nla_nest_cancel(skb, table_attr);
1793 return -EMSGSIZE;
1794}
1795
1796static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1797 struct genl_info *info)
1798{
1799 int err;
1800
1801 if (*pskb) {
1802 err = genlmsg_reply(*pskb, info);
1803 if (err)
1804 return err;
1805 }
1806 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1807 if (!*pskb)
1808 return -ENOMEM;
1809 return 0;
1810}
1811
1812static int devlink_dpipe_tables_fill(struct genl_info *info,
1813 enum devlink_command cmd, int flags,
1814 struct list_head *dpipe_tables,
1815 const char *table_name)
1816{
1817 struct devlink *devlink = info->user_ptr[0];
1818 struct devlink_dpipe_table *table;
1819 struct nlattr *tables_attr;
1820 struct sk_buff *skb = NULL;
1821 struct nlmsghdr *nlh;
1822 bool incomplete;
1823 void *hdr;
1824 int i;
1825 int err;
1826
1827 table = list_first_entry(dpipe_tables,
1828 struct devlink_dpipe_table, list);
1829start_again:
1830 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1831 if (err)
1832 return err;
1833
1834 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1835 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08001836 if (!hdr) {
1837 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001838 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08001839 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001840
1841 if (devlink_nl_put_handle(skb, devlink))
1842 goto nla_put_failure;
1843 tables_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLES);
1844 if (!tables_attr)
1845 goto nla_put_failure;
1846
1847 i = 0;
1848 incomplete = false;
1849 list_for_each_entry_from(table, dpipe_tables, list) {
1850 if (!table_name) {
1851 err = devlink_dpipe_table_put(skb, table);
1852 if (err) {
1853 if (!i)
1854 goto err_table_put;
1855 incomplete = true;
1856 break;
1857 }
1858 } else {
1859 if (!strcmp(table->name, table_name)) {
1860 err = devlink_dpipe_table_put(skb, table);
1861 if (err)
1862 break;
1863 }
1864 }
1865 i++;
1866 }
1867
1868 nla_nest_end(skb, tables_attr);
1869 genlmsg_end(skb, hdr);
1870 if (incomplete)
1871 goto start_again;
1872
1873send_done:
1874 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1875 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1876 if (!nlh) {
1877 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1878 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02001879 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001880 goto send_done;
1881 }
1882
1883 return genlmsg_reply(skb, info);
1884
1885nla_put_failure:
1886 err = -EMSGSIZE;
1887err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02001888 nlmsg_free(skb);
1889 return err;
1890}
1891
1892static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
1893 struct genl_info *info)
1894{
1895 struct devlink *devlink = info->user_ptr[0];
1896 const char *table_name = NULL;
1897
1898 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
1899 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
1900
1901 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
1902 &devlink->dpipe_table_list,
1903 table_name);
1904}
1905
1906static int devlink_dpipe_value_put(struct sk_buff *skb,
1907 struct devlink_dpipe_value *value)
1908{
1909 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
1910 value->value_size, value->value))
1911 return -EMSGSIZE;
1912 if (value->mask)
1913 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
1914 value->value_size, value->mask))
1915 return -EMSGSIZE;
1916 if (value->mapping_valid)
1917 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
1918 value->mapping_value))
1919 return -EMSGSIZE;
1920 return 0;
1921}
1922
1923static int devlink_dpipe_action_value_put(struct sk_buff *skb,
1924 struct devlink_dpipe_value *value)
1925{
1926 if (!value->action)
1927 return -EINVAL;
1928 if (devlink_dpipe_action_put(skb, value->action))
1929 return -EMSGSIZE;
1930 if (devlink_dpipe_value_put(skb, value))
1931 return -EMSGSIZE;
1932 return 0;
1933}
1934
1935static int devlink_dpipe_action_values_put(struct sk_buff *skb,
1936 struct devlink_dpipe_value *values,
1937 unsigned int values_count)
1938{
1939 struct nlattr *action_attr;
1940 int i;
1941 int err;
1942
1943 for (i = 0; i < values_count; i++) {
1944 action_attr = nla_nest_start(skb,
1945 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
1946 if (!action_attr)
1947 return -EMSGSIZE;
1948 err = devlink_dpipe_action_value_put(skb, &values[i]);
1949 if (err)
1950 goto err_action_value_put;
1951 nla_nest_end(skb, action_attr);
1952 }
1953 return 0;
1954
1955err_action_value_put:
1956 nla_nest_cancel(skb, action_attr);
1957 return err;
1958}
1959
1960static int devlink_dpipe_match_value_put(struct sk_buff *skb,
1961 struct devlink_dpipe_value *value)
1962{
1963 if (!value->match)
1964 return -EINVAL;
1965 if (devlink_dpipe_match_put(skb, value->match))
1966 return -EMSGSIZE;
1967 if (devlink_dpipe_value_put(skb, value))
1968 return -EMSGSIZE;
1969 return 0;
1970}
1971
1972static int devlink_dpipe_match_values_put(struct sk_buff *skb,
1973 struct devlink_dpipe_value *values,
1974 unsigned int values_count)
1975{
1976 struct nlattr *match_attr;
1977 int i;
1978 int err;
1979
1980 for (i = 0; i < values_count; i++) {
1981 match_attr = nla_nest_start(skb,
1982 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
1983 if (!match_attr)
1984 return -EMSGSIZE;
1985 err = devlink_dpipe_match_value_put(skb, &values[i]);
1986 if (err)
1987 goto err_match_value_put;
1988 nla_nest_end(skb, match_attr);
1989 }
1990 return 0;
1991
1992err_match_value_put:
1993 nla_nest_cancel(skb, match_attr);
1994 return err;
1995}
1996
1997static int devlink_dpipe_entry_put(struct sk_buff *skb,
1998 struct devlink_dpipe_entry *entry)
1999{
2000 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2001 int err;
2002
2003 entry_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ENTRY);
2004 if (!entry_attr)
2005 return -EMSGSIZE;
2006
2007 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2008 DEVLINK_ATTR_PAD))
2009 goto nla_put_failure;
2010 if (entry->counter_valid)
2011 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2012 entry->counter, DEVLINK_ATTR_PAD))
2013 goto nla_put_failure;
2014
2015 matches_attr = nla_nest_start(skb,
2016 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
2017 if (!matches_attr)
2018 goto nla_put_failure;
2019
2020 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2021 entry->match_values_count);
2022 if (err) {
2023 nla_nest_cancel(skb, matches_attr);
2024 goto err_match_values_put;
2025 }
2026 nla_nest_end(skb, matches_attr);
2027
2028 actions_attr = nla_nest_start(skb,
2029 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
2030 if (!actions_attr)
2031 goto nla_put_failure;
2032
2033 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2034 entry->action_values_count);
2035 if (err) {
2036 nla_nest_cancel(skb, actions_attr);
2037 goto err_action_values_put;
2038 }
2039 nla_nest_end(skb, actions_attr);
2040
2041 nla_nest_end(skb, entry_attr);
2042 return 0;
2043
2044nla_put_failure:
2045 err = -EMSGSIZE;
2046err_match_values_put:
2047err_action_values_put:
2048 nla_nest_cancel(skb, entry_attr);
2049 return err;
2050}
2051
2052static struct devlink_dpipe_table *
2053devlink_dpipe_table_find(struct list_head *dpipe_tables,
2054 const char *table_name)
2055{
2056 struct devlink_dpipe_table *table;
2057
2058 list_for_each_entry_rcu(table, dpipe_tables, list) {
2059 if (!strcmp(table->name, table_name))
2060 return table;
2061 }
2062 return NULL;
2063}
2064
2065int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2066{
2067 struct devlink *devlink;
2068 int err;
2069
2070 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2071 dump_ctx->info);
2072 if (err)
2073 return err;
2074
2075 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2076 dump_ctx->info->snd_portid,
2077 dump_ctx->info->snd_seq,
2078 &devlink_nl_family, NLM_F_MULTI,
2079 dump_ctx->cmd);
2080 if (!dump_ctx->hdr)
2081 goto nla_put_failure;
2082
2083 devlink = dump_ctx->info->user_ptr[0];
2084 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2085 goto nla_put_failure;
2086 dump_ctx->nest = nla_nest_start(dump_ctx->skb,
2087 DEVLINK_ATTR_DPIPE_ENTRIES);
2088 if (!dump_ctx->nest)
2089 goto nla_put_failure;
2090 return 0;
2091
2092nla_put_failure:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002093 nlmsg_free(dump_ctx->skb);
2094 return -EMSGSIZE;
2095}
2096EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2097
2098int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2099 struct devlink_dpipe_entry *entry)
2100{
2101 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2102}
2103EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2104
2105int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2106{
2107 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2108 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2109 return 0;
2110}
2111EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2112
Arkadi Sharshevsky35807322017-08-24 08:40:03 +02002113void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2114
2115{
2116 unsigned int value_count, value_index;
2117 struct devlink_dpipe_value *value;
2118
2119 value = entry->action_values;
2120 value_count = entry->action_values_count;
2121 for (value_index = 0; value_index < value_count; value_index++) {
2122 kfree(value[value_index].value);
2123 kfree(value[value_index].mask);
2124 }
2125
2126 value = entry->match_values;
2127 value_count = entry->match_values_count;
2128 for (value_index = 0; value_index < value_count; value_index++) {
2129 kfree(value[value_index].value);
2130 kfree(value[value_index].mask);
2131 }
2132}
2133EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2134
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002135static int devlink_dpipe_entries_fill(struct genl_info *info,
2136 enum devlink_command cmd, int flags,
2137 struct devlink_dpipe_table *table)
2138{
2139 struct devlink_dpipe_dump_ctx dump_ctx;
2140 struct nlmsghdr *nlh;
2141 int err;
2142
2143 dump_ctx.skb = NULL;
2144 dump_ctx.cmd = cmd;
2145 dump_ctx.info = info;
2146
2147 err = table->table_ops->entries_dump(table->priv,
2148 table->counters_enabled,
2149 &dump_ctx);
2150 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002151 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002152
2153send_done:
2154 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2155 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2156 if (!nlh) {
2157 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2158 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002159 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002160 goto send_done;
2161 }
2162 return genlmsg_reply(dump_ctx.skb, info);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002163}
2164
2165static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2166 struct genl_info *info)
2167{
2168 struct devlink *devlink = info->user_ptr[0];
2169 struct devlink_dpipe_table *table;
2170 const char *table_name;
2171
2172 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2173 return -EINVAL;
2174
2175 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2176 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2177 table_name);
2178 if (!table)
2179 return -EINVAL;
2180
2181 if (!table->table_ops->entries_dump)
2182 return -EINVAL;
2183
2184 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2185 0, table);
2186}
2187
2188static int devlink_dpipe_fields_put(struct sk_buff *skb,
2189 const struct devlink_dpipe_header *header)
2190{
2191 struct devlink_dpipe_field *field;
2192 struct nlattr *field_attr;
2193 int i;
2194
2195 for (i = 0; i < header->fields_count; i++) {
2196 field = &header->fields[i];
2197 field_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_FIELD);
2198 if (!field_attr)
2199 return -EMSGSIZE;
2200 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2201 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2202 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2203 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2204 goto nla_put_failure;
2205 nla_nest_end(skb, field_attr);
2206 }
2207 return 0;
2208
2209nla_put_failure:
2210 nla_nest_cancel(skb, field_attr);
2211 return -EMSGSIZE;
2212}
2213
2214static int devlink_dpipe_header_put(struct sk_buff *skb,
2215 struct devlink_dpipe_header *header)
2216{
2217 struct nlattr *fields_attr, *header_attr;
2218 int err;
2219
2220 header_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER);
Wei Yongjuncb6bf9c2017-04-11 16:02:02 +00002221 if (!header_attr)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002222 return -EMSGSIZE;
2223
2224 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2225 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2226 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2227 goto nla_put_failure;
2228
2229 fields_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
2230 if (!fields_attr)
2231 goto nla_put_failure;
2232
2233 err = devlink_dpipe_fields_put(skb, header);
2234 if (err) {
2235 nla_nest_cancel(skb, fields_attr);
2236 goto nla_put_failure;
2237 }
2238 nla_nest_end(skb, fields_attr);
2239 nla_nest_end(skb, header_attr);
2240 return 0;
2241
2242nla_put_failure:
2243 err = -EMSGSIZE;
2244 nla_nest_cancel(skb, header_attr);
2245 return err;
2246}
2247
2248static int devlink_dpipe_headers_fill(struct genl_info *info,
2249 enum devlink_command cmd, int flags,
2250 struct devlink_dpipe_headers *
2251 dpipe_headers)
2252{
2253 struct devlink *devlink = info->user_ptr[0];
2254 struct nlattr *headers_attr;
2255 struct sk_buff *skb = NULL;
2256 struct nlmsghdr *nlh;
2257 void *hdr;
2258 int i, j;
2259 int err;
2260
2261 i = 0;
2262start_again:
2263 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2264 if (err)
2265 return err;
2266
2267 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2268 &devlink_nl_family, NLM_F_MULTI, cmd);
Haishuang Yan6044bd42017-06-05 08:57:21 +08002269 if (!hdr) {
2270 nlmsg_free(skb);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002271 return -EMSGSIZE;
Haishuang Yan6044bd42017-06-05 08:57:21 +08002272 }
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002273
2274 if (devlink_nl_put_handle(skb, devlink))
2275 goto nla_put_failure;
2276 headers_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADERS);
2277 if (!headers_attr)
2278 goto nla_put_failure;
2279
2280 j = 0;
2281 for (; i < dpipe_headers->headers_count; i++) {
2282 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2283 if (err) {
2284 if (!j)
2285 goto err_table_put;
2286 break;
2287 }
2288 j++;
2289 }
2290 nla_nest_end(skb, headers_attr);
2291 genlmsg_end(skb, hdr);
2292 if (i != dpipe_headers->headers_count)
2293 goto start_again;
2294
2295send_done:
2296 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2297 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2298 if (!nlh) {
2299 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2300 if (err)
Arkadi Sharshevsky7fe4d6d2018-03-18 17:37:22 +02002301 return err;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002302 goto send_done;
2303 }
2304 return genlmsg_reply(skb, info);
2305
2306nla_put_failure:
2307 err = -EMSGSIZE;
2308err_table_put:
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02002309 nlmsg_free(skb);
2310 return err;
2311}
2312
2313static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2314 struct genl_info *info)
2315{
2316 struct devlink *devlink = info->user_ptr[0];
2317
2318 if (!devlink->dpipe_headers)
2319 return -EOPNOTSUPP;
2320 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2321 0, devlink->dpipe_headers);
2322}
2323
2324static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2325 const char *table_name,
2326 bool enable)
2327{
2328 struct devlink_dpipe_table *table;
2329
2330 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2331 table_name);
2332 if (!table)
2333 return -EINVAL;
2334
2335 if (table->counter_control_extern)
2336 return -EOPNOTSUPP;
2337
2338 if (!(table->counters_enabled ^ enable))
2339 return 0;
2340
2341 table->counters_enabled = enable;
2342 if (table->table_ops->counters_set_update)
2343 table->table_ops->counters_set_update(table->priv, enable);
2344 return 0;
2345}
2346
2347static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2348 struct genl_info *info)
2349{
2350 struct devlink *devlink = info->user_ptr[0];
2351 const char *table_name;
2352 bool counters_enable;
2353
2354 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2355 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2356 return -EINVAL;
2357
2358 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2359 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2360
2361 return devlink_dpipe_table_counters_set(devlink, table_name,
2362 counters_enable);
2363}
2364
Wei Yongjun43dd7512018-01-17 03:27:42 +00002365static struct devlink_resource *
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002366devlink_resource_find(struct devlink *devlink,
2367 struct devlink_resource *resource, u64 resource_id)
2368{
2369 struct list_head *resource_list;
2370
2371 if (resource)
2372 resource_list = &resource->resource_list;
2373 else
2374 resource_list = &devlink->resource_list;
2375
2376 list_for_each_entry(resource, resource_list, list) {
2377 struct devlink_resource *child_resource;
2378
2379 if (resource->id == resource_id)
2380 return resource;
2381
2382 child_resource = devlink_resource_find(devlink, resource,
2383 resource_id);
2384 if (child_resource)
2385 return child_resource;
2386 }
2387 return NULL;
2388}
2389
Wei Yongjun43dd7512018-01-17 03:27:42 +00002390static void
2391devlink_resource_validate_children(struct devlink_resource *resource)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002392{
2393 struct devlink_resource *child_resource;
2394 bool size_valid = true;
2395 u64 parts_size = 0;
2396
2397 if (list_empty(&resource->resource_list))
2398 goto out;
2399
2400 list_for_each_entry(child_resource, &resource->resource_list, list)
2401 parts_size += child_resource->size_new;
2402
Arkadi Sharshevskyb9d17172018-02-26 10:59:53 +01002403 if (parts_size > resource->size_new)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002404 size_valid = false;
2405out:
2406 resource->size_valid = size_valid;
2407}
2408
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002409static int
2410devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2411 struct netlink_ext_ack *extack)
2412{
2413 u64 reminder;
2414 int err = 0;
2415
David S. Miller0f3e9c92018-03-06 00:53:44 -05002416 if (size > resource->size_params.size_max) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002417 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2418 err = -EINVAL;
2419 }
2420
David S. Miller0f3e9c92018-03-06 00:53:44 -05002421 if (size < resource->size_params.size_min) {
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002422 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2423 err = -EINVAL;
2424 }
2425
David S. Miller0f3e9c92018-03-06 00:53:44 -05002426 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002427 if (reminder) {
2428 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2429 err = -EINVAL;
2430 }
2431
2432 return err;
2433}
2434
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002435static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2436 struct genl_info *info)
2437{
2438 struct devlink *devlink = info->user_ptr[0];
2439 struct devlink_resource *resource;
2440 u64 resource_id;
2441 u64 size;
2442 int err;
2443
2444 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2445 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2446 return -EINVAL;
2447 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2448
2449 resource = devlink_resource_find(devlink, NULL, resource_id);
2450 if (!resource)
2451 return -EINVAL;
2452
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002453 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
Arkadi Sharshevskycc944ea2018-02-20 08:44:20 +01002454 err = devlink_resource_validate_size(resource, size, info->extack);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002455 if (err)
2456 return err;
2457
2458 resource->size_new = size;
2459 devlink_resource_validate_children(resource);
2460 if (resource->parent)
2461 devlink_resource_validate_children(resource->parent);
2462 return 0;
2463}
2464
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002465static int
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002466devlink_resource_size_params_put(struct devlink_resource *resource,
2467 struct sk_buff *skb)
2468{
2469 struct devlink_resource_size_params *size_params;
2470
Jiri Pirko77d27092018-02-28 13:12:09 +01002471 size_params = &resource->size_params;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002472 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2473 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2474 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2475 size_params->size_max, DEVLINK_ATTR_PAD) ||
2476 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2477 size_params->size_min, DEVLINK_ATTR_PAD) ||
2478 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2479 return -EMSGSIZE;
2480 return 0;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002481}
2482
Jiri Pirkofc56be42018-04-05 22:13:21 +02002483static int devlink_resource_occ_put(struct devlink_resource *resource,
2484 struct sk_buff *skb)
2485{
2486 if (!resource->occ_get)
2487 return 0;
2488 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2489 resource->occ_get(resource->occ_get_priv),
2490 DEVLINK_ATTR_PAD);
2491}
2492
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002493static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2494 struct devlink_resource *resource)
2495{
2496 struct devlink_resource *child_resource;
2497 struct nlattr *child_resource_attr;
2498 struct nlattr *resource_attr;
2499
2500 resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE);
2501 if (!resource_attr)
2502 return -EMSGSIZE;
2503
2504 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2505 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2506 DEVLINK_ATTR_PAD) ||
2507 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2508 DEVLINK_ATTR_PAD))
2509 goto nla_put_failure;
2510 if (resource->size != resource->size_new)
2511 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2512 resource->size_new, DEVLINK_ATTR_PAD);
Jiri Pirkofc56be42018-04-05 22:13:21 +02002513 if (devlink_resource_occ_put(resource, skb))
2514 goto nla_put_failure;
Arkadi Sharshevsky3d18e4f2018-02-26 18:25:42 +02002515 if (devlink_resource_size_params_put(resource, skb))
2516 goto nla_put_failure;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002517 if (list_empty(&resource->resource_list))
2518 goto out;
2519
2520 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2521 resource->size_valid))
2522 goto nla_put_failure;
2523
2524 child_resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2525 if (!child_resource_attr)
2526 goto nla_put_failure;
2527
2528 list_for_each_entry(child_resource, &resource->resource_list, list) {
2529 if (devlink_resource_put(devlink, skb, child_resource))
2530 goto resource_put_failure;
2531 }
2532
2533 nla_nest_end(skb, child_resource_attr);
2534out:
2535 nla_nest_end(skb, resource_attr);
2536 return 0;
2537
2538resource_put_failure:
2539 nla_nest_cancel(skb, child_resource_attr);
2540nla_put_failure:
2541 nla_nest_cancel(skb, resource_attr);
2542 return -EMSGSIZE;
2543}
2544
2545static int devlink_resource_fill(struct genl_info *info,
2546 enum devlink_command cmd, int flags)
2547{
2548 struct devlink *devlink = info->user_ptr[0];
2549 struct devlink_resource *resource;
2550 struct nlattr *resources_attr;
2551 struct sk_buff *skb = NULL;
2552 struct nlmsghdr *nlh;
2553 bool incomplete;
2554 void *hdr;
2555 int i;
2556 int err;
2557
2558 resource = list_first_entry(&devlink->resource_list,
2559 struct devlink_resource, list);
2560start_again:
2561 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2562 if (err)
2563 return err;
2564
2565 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2566 &devlink_nl_family, NLM_F_MULTI, cmd);
2567 if (!hdr) {
2568 nlmsg_free(skb);
2569 return -EMSGSIZE;
2570 }
2571
2572 if (devlink_nl_put_handle(skb, devlink))
2573 goto nla_put_failure;
2574
2575 resources_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2576 if (!resources_attr)
2577 goto nla_put_failure;
2578
2579 incomplete = false;
2580 i = 0;
2581 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2582 err = devlink_resource_put(devlink, skb, resource);
2583 if (err) {
2584 if (!i)
2585 goto err_resource_put;
2586 incomplete = true;
2587 break;
2588 }
2589 i++;
2590 }
2591 nla_nest_end(skb, resources_attr);
2592 genlmsg_end(skb, hdr);
2593 if (incomplete)
2594 goto start_again;
2595send_done:
2596 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2597 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2598 if (!nlh) {
2599 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2600 if (err)
Dan Carpenter83fe9a92018-09-21 11:07:55 +03002601 return err;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002602 goto send_done;
2603 }
2604 return genlmsg_reply(skb, info);
2605
2606nla_put_failure:
2607 err = -EMSGSIZE;
2608err_resource_put:
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01002609 nlmsg_free(skb);
2610 return err;
2611}
2612
2613static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2614 struct genl_info *info)
2615{
2616 struct devlink *devlink = info->user_ptr[0];
2617
2618 if (list_empty(&devlink->resource_list))
2619 return -EOPNOTSUPP;
2620
2621 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2622}
2623
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002624static int
2625devlink_resources_validate(struct devlink *devlink,
2626 struct devlink_resource *resource,
2627 struct genl_info *info)
2628{
2629 struct list_head *resource_list;
2630 int err = 0;
2631
2632 if (resource)
2633 resource_list = &resource->resource_list;
2634 else
2635 resource_list = &devlink->resource_list;
2636
2637 list_for_each_entry(resource, resource_list, list) {
2638 if (!resource->size_valid)
2639 return -EINVAL;
2640 err = devlink_resources_validate(devlink, resource, info);
2641 if (err)
2642 return err;
2643 }
2644 return err;
2645}
2646
2647static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2648{
2649 struct devlink *devlink = info->user_ptr[0];
2650 int err;
2651
2652 if (!devlink->ops->reload)
2653 return -EOPNOTSUPP;
2654
2655 err = devlink_resources_validate(devlink, NULL, info);
2656 if (err) {
2657 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2658 return err;
2659 }
David Ahernac0fc8a2018-06-05 08:14:09 -07002660 return devlink->ops->reload(devlink, info->extack);
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01002661}
2662
Moshe Shemesh036467c2018-07-04 14:30:33 +03002663static const struct devlink_param devlink_param_generic[] = {
2664 {
2665 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
2666 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
2667 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
2668 },
2669 {
2670 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
2671 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
2672 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
2673 },
Vasundhara Volamf567bcd2018-07-04 14:30:36 +03002674 {
2675 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
2676 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
2677 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
2678 },
Alex Veskerf6a698852018-07-12 15:13:17 +03002679 {
2680 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
2681 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
2682 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
2683 },
Vasundhara Volame3b51062018-10-04 11:13:44 +05302684 {
2685 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
2686 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
2687 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
2688 },
Vasundhara Volamf61cba42018-10-04 11:13:45 +05302689 {
2690 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
2691 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
2692 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
2693 },
Vasundhara Volam16511782018-10-04 11:13:46 +05302694 {
2695 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
2696 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
2697 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
2698 },
Shalom Toledo846e9802018-12-03 07:58:59 +00002699 {
2700 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
2701 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
2702 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
2703 },
Moshe Shemesh036467c2018-07-04 14:30:33 +03002704};
Moshe Shemesheabaef12018-07-04 14:30:28 +03002705
2706static int devlink_param_generic_verify(const struct devlink_param *param)
2707{
2708 /* verify it match generic parameter by id and name */
2709 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
2710 return -EINVAL;
2711 if (strcmp(param->name, devlink_param_generic[param->id].name))
2712 return -ENOENT;
2713
2714 WARN_ON(param->type != devlink_param_generic[param->id].type);
2715
2716 return 0;
2717}
2718
2719static int devlink_param_driver_verify(const struct devlink_param *param)
2720{
2721 int i;
2722
2723 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
2724 return -EINVAL;
2725 /* verify no such name in generic params */
2726 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
2727 if (!strcmp(param->name, devlink_param_generic[i].name))
2728 return -EEXIST;
2729
2730 return 0;
2731}
2732
2733static struct devlink_param_item *
2734devlink_param_find_by_name(struct list_head *param_list,
2735 const char *param_name)
2736{
2737 struct devlink_param_item *param_item;
2738
2739 list_for_each_entry(param_item, param_list, list)
2740 if (!strcmp(param_item->param->name, param_name))
2741 return param_item;
2742 return NULL;
2743}
2744
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03002745static struct devlink_param_item *
2746devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
2747{
2748 struct devlink_param_item *param_item;
2749
2750 list_for_each_entry(param_item, param_list, list)
2751 if (param_item->param->id == param_id)
2752 return param_item;
2753 return NULL;
2754}
2755
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002756static bool
2757devlink_param_cmode_is_supported(const struct devlink_param *param,
2758 enum devlink_param_cmode cmode)
2759{
2760 return test_bit(cmode, &param->supported_cmodes);
2761}
2762
2763static int devlink_param_get(struct devlink *devlink,
2764 const struct devlink_param *param,
2765 struct devlink_param_gset_ctx *ctx)
2766{
2767 if (!param->get)
2768 return -EOPNOTSUPP;
2769 return param->get(devlink, param->id, ctx);
2770}
2771
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03002772static int devlink_param_set(struct devlink *devlink,
2773 const struct devlink_param *param,
2774 struct devlink_param_gset_ctx *ctx)
2775{
2776 if (!param->set)
2777 return -EOPNOTSUPP;
2778 return param->set(devlink, param->id, ctx);
2779}
2780
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002781static int
2782devlink_param_type_to_nla_type(enum devlink_param_type param_type)
2783{
2784 switch (param_type) {
2785 case DEVLINK_PARAM_TYPE_U8:
2786 return NLA_U8;
2787 case DEVLINK_PARAM_TYPE_U16:
2788 return NLA_U16;
2789 case DEVLINK_PARAM_TYPE_U32:
2790 return NLA_U32;
2791 case DEVLINK_PARAM_TYPE_STRING:
2792 return NLA_STRING;
2793 case DEVLINK_PARAM_TYPE_BOOL:
2794 return NLA_FLAG;
2795 default:
2796 return -EINVAL;
2797 }
2798}
2799
2800static int
2801devlink_nl_param_value_fill_one(struct sk_buff *msg,
2802 enum devlink_param_type type,
2803 enum devlink_param_cmode cmode,
2804 union devlink_param_value val)
2805{
2806 struct nlattr *param_value_attr;
2807
2808 param_value_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUE);
2809 if (!param_value_attr)
2810 goto nla_put_failure;
2811
2812 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
2813 goto value_nest_cancel;
2814
2815 switch (type) {
2816 case DEVLINK_PARAM_TYPE_U8:
2817 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
2818 goto value_nest_cancel;
2819 break;
2820 case DEVLINK_PARAM_TYPE_U16:
2821 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
2822 goto value_nest_cancel;
2823 break;
2824 case DEVLINK_PARAM_TYPE_U32:
2825 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
2826 goto value_nest_cancel;
2827 break;
2828 case DEVLINK_PARAM_TYPE_STRING:
2829 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
2830 val.vstr))
2831 goto value_nest_cancel;
2832 break;
2833 case DEVLINK_PARAM_TYPE_BOOL:
2834 if (val.vbool &&
2835 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
2836 goto value_nest_cancel;
2837 break;
2838 }
2839
2840 nla_nest_end(msg, param_value_attr);
2841 return 0;
2842
2843value_nest_cancel:
2844 nla_nest_cancel(msg, param_value_attr);
2845nla_put_failure:
2846 return -EMSGSIZE;
2847}
2848
2849static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302850 unsigned int port_index,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002851 struct devlink_param_item *param_item,
2852 enum devlink_command cmd,
2853 u32 portid, u32 seq, int flags)
2854{
2855 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002856 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002857 const struct devlink_param *param = param_item->param;
2858 struct devlink_param_gset_ctx ctx;
2859 struct nlattr *param_values_list;
2860 struct nlattr *param_attr;
2861 int nla_type;
2862 void *hdr;
2863 int err;
2864 int i;
2865
2866 /* Get value from driver part to driverinit configuration mode */
2867 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
2868 if (!devlink_param_cmode_is_supported(param, i))
2869 continue;
2870 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
2871 if (!param_item->driverinit_value_valid)
2872 return -EOPNOTSUPP;
2873 param_value[i] = param_item->driverinit_value;
2874 } else {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002875 if (!param_item->published)
2876 continue;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002877 ctx.cmode = i;
2878 err = devlink_param_get(devlink, param, &ctx);
2879 if (err)
2880 return err;
2881 param_value[i] = ctx.val;
2882 }
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002883 param_value_set[i] = true;
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002884 }
2885
2886 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
2887 if (!hdr)
2888 return -EMSGSIZE;
2889
2890 if (devlink_nl_put_handle(msg, devlink))
2891 goto genlmsg_cancel;
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302892
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302893 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
2894 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
2895 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302896 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
2897 goto genlmsg_cancel;
2898
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002899 param_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM);
2900 if (!param_attr)
2901 goto genlmsg_cancel;
2902 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
2903 goto param_nest_cancel;
2904 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
2905 goto param_nest_cancel;
2906
2907 nla_type = devlink_param_type_to_nla_type(param->type);
2908 if (nla_type < 0)
2909 goto param_nest_cancel;
2910 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
2911 goto param_nest_cancel;
2912
2913 param_values_list = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUES_LIST);
2914 if (!param_values_list)
2915 goto param_nest_cancel;
2916
2917 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00002918 if (!param_value_set[i])
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002919 continue;
2920 err = devlink_nl_param_value_fill_one(msg, param->type,
2921 i, param_value[i]);
2922 if (err)
2923 goto values_list_nest_cancel;
2924 }
2925
2926 nla_nest_end(msg, param_values_list);
2927 nla_nest_end(msg, param_attr);
2928 genlmsg_end(msg, hdr);
2929 return 0;
2930
2931values_list_nest_cancel:
2932 nla_nest_end(msg, param_values_list);
2933param_nest_cancel:
2934 nla_nest_cancel(msg, param_attr);
2935genlmsg_cancel:
2936 genlmsg_cancel(msg, hdr);
2937 return -EMSGSIZE;
2938}
2939
Moshe Shemeshea601e12018-07-04 14:30:32 +03002940static void devlink_param_notify(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302941 unsigned int port_index,
Moshe Shemeshea601e12018-07-04 14:30:32 +03002942 struct devlink_param_item *param_item,
2943 enum devlink_command cmd)
2944{
2945 struct sk_buff *msg;
2946 int err;
2947
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302948 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
2949 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
2950 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
Moshe Shemeshea601e12018-07-04 14:30:32 +03002951
2952 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2953 if (!msg)
2954 return;
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05302955 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
2956 0, 0, 0);
Moshe Shemeshea601e12018-07-04 14:30:32 +03002957 if (err) {
2958 nlmsg_free(msg);
2959 return;
2960 }
2961
2962 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
2963 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
2964}
2965
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002966static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
2967 struct netlink_callback *cb)
2968{
2969 struct devlink_param_item *param_item;
2970 struct devlink *devlink;
2971 int start = cb->args[0];
2972 int idx = 0;
2973 int err;
2974
2975 mutex_lock(&devlink_mutex);
2976 list_for_each_entry(devlink, &devlink_list, list) {
2977 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
2978 continue;
2979 mutex_lock(&devlink->lock);
2980 list_for_each_entry(param_item, &devlink->param_list, list) {
2981 if (idx < start) {
2982 idx++;
2983 continue;
2984 }
Vasundhara Volamf4601de2019-01-28 18:00:21 +05302985 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03002986 DEVLINK_CMD_PARAM_GET,
2987 NETLINK_CB(cb->skb).portid,
2988 cb->nlh->nlmsg_seq,
2989 NLM_F_MULTI);
2990 if (err) {
2991 mutex_unlock(&devlink->lock);
2992 goto out;
2993 }
2994 idx++;
2995 }
2996 mutex_unlock(&devlink->lock);
2997 }
2998out:
2999 mutex_unlock(&devlink_mutex);
3000
3001 cb->args[0] = idx;
3002 return msg->len;
3003}
3004
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003005static int
3006devlink_param_type_get_from_info(struct genl_info *info,
3007 enum devlink_param_type *param_type)
3008{
3009 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3010 return -EINVAL;
3011
3012 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3013 case NLA_U8:
3014 *param_type = DEVLINK_PARAM_TYPE_U8;
3015 break;
3016 case NLA_U16:
3017 *param_type = DEVLINK_PARAM_TYPE_U16;
3018 break;
3019 case NLA_U32:
3020 *param_type = DEVLINK_PARAM_TYPE_U32;
3021 break;
3022 case NLA_STRING:
3023 *param_type = DEVLINK_PARAM_TYPE_STRING;
3024 break;
3025 case NLA_FLAG:
3026 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3027 break;
3028 default:
3029 return -EINVAL;
3030 }
3031
3032 return 0;
3033}
3034
3035static int
3036devlink_param_value_get_from_info(const struct devlink_param *param,
3037 struct genl_info *info,
3038 union devlink_param_value *value)
3039{
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003040 int len;
3041
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003042 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3043 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3044 return -EINVAL;
3045
3046 switch (param->type) {
3047 case DEVLINK_PARAM_TYPE_U8:
3048 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3049 break;
3050 case DEVLINK_PARAM_TYPE_U16:
3051 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3052 break;
3053 case DEVLINK_PARAM_TYPE_U32:
3054 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3055 break;
3056 case DEVLINK_PARAM_TYPE_STRING:
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003057 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3058 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3059 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03003060 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003061 return -EINVAL;
Moshe Shemeshf355cfc2018-10-10 16:09:25 +03003062 strcpy(value->vstr,
3063 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003064 break;
3065 case DEVLINK_PARAM_TYPE_BOOL:
3066 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3067 true : false;
3068 break;
3069 }
3070 return 0;
3071}
3072
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003073static struct devlink_param_item *
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303074devlink_param_get_from_info(struct list_head *param_list,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003075 struct genl_info *info)
3076{
3077 char *param_name;
3078
3079 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3080 return NULL;
3081
3082 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303083 return devlink_param_find_by_name(param_list, param_name);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003084}
3085
3086static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3087 struct genl_info *info)
3088{
3089 struct devlink *devlink = info->user_ptr[0];
3090 struct devlink_param_item *param_item;
3091 struct sk_buff *msg;
3092 int err;
3093
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303094 param_item = devlink_param_get_from_info(&devlink->param_list, info);
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003095 if (!param_item)
3096 return -EINVAL;
3097
3098 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3099 if (!msg)
3100 return -ENOMEM;
3101
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303102 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
Moshe Shemesh45f05de2018-07-04 14:30:29 +03003103 DEVLINK_CMD_PARAM_GET,
3104 info->snd_portid, info->snd_seq, 0);
3105 if (err) {
3106 nlmsg_free(msg);
3107 return err;
3108 }
3109
3110 return genlmsg_reply(msg, info);
3111}
3112
Vasundhara Volam9c548732019-01-28 18:00:22 +05303113static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303114 unsigned int port_index,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303115 struct list_head *param_list,
3116 struct genl_info *info,
3117 enum devlink_command cmd)
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003118{
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003119 enum devlink_param_type param_type;
3120 struct devlink_param_gset_ctx ctx;
3121 enum devlink_param_cmode cmode;
3122 struct devlink_param_item *param_item;
3123 const struct devlink_param *param;
3124 union devlink_param_value value;
3125 int err = 0;
3126
Vasundhara Volam9c548732019-01-28 18:00:22 +05303127 param_item = devlink_param_get_from_info(param_list, info);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003128 if (!param_item)
3129 return -EINVAL;
3130 param = param_item->param;
3131 err = devlink_param_type_get_from_info(info, &param_type);
3132 if (err)
3133 return err;
3134 if (param_type != param->type)
3135 return -EINVAL;
3136 err = devlink_param_value_get_from_info(param, info, &value);
3137 if (err)
3138 return err;
3139 if (param->validate) {
3140 err = param->validate(devlink, param->id, value, info->extack);
3141 if (err)
3142 return err;
3143 }
3144
3145 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3146 return -EINVAL;
3147 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3148 if (!devlink_param_cmode_is_supported(param, cmode))
3149 return -EOPNOTSUPP;
3150
3151 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
Moshe Shemesh12765342018-10-10 16:09:26 +03003152 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3153 strcpy(param_item->driverinit_value.vstr, value.vstr);
3154 else
3155 param_item->driverinit_value = value;
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003156 param_item->driverinit_value_valid = true;
3157 } else {
3158 if (!param->set)
3159 return -EOPNOTSUPP;
3160 ctx.val = value;
3161 ctx.cmode = cmode;
3162 err = devlink_param_set(devlink, param, &ctx);
3163 if (err)
3164 return err;
3165 }
3166
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303167 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03003168 return 0;
3169}
3170
Vasundhara Volam9c548732019-01-28 18:00:22 +05303171static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3172 struct genl_info *info)
3173{
3174 struct devlink *devlink = info->user_ptr[0];
3175
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303176 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
Vasundhara Volam9c548732019-01-28 18:00:22 +05303177 info, DEVLINK_CMD_PARAM_NEW);
3178}
3179
Moshe Shemesheabaef12018-07-04 14:30:28 +03003180static int devlink_param_register_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303181 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303182 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303183 const struct devlink_param *param,
3184 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003185{
3186 struct devlink_param_item *param_item;
3187
Vasundhara Volam39e61602019-01-28 18:00:20 +05303188 if (devlink_param_find_by_name(param_list, param->name))
Moshe Shemesheabaef12018-07-04 14:30:28 +03003189 return -EEXIST;
3190
3191 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3192 WARN_ON(param->get || param->set);
3193 else
3194 WARN_ON(!param->get || !param->set);
3195
3196 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3197 if (!param_item)
3198 return -ENOMEM;
3199 param_item->param = param;
3200
Vasundhara Volam39e61602019-01-28 18:00:20 +05303201 list_add_tail(&param_item->list, param_list);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303202 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003203 return 0;
3204}
3205
3206static void devlink_param_unregister_one(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303207 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05303208 struct list_head *param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303209 const struct devlink_param *param,
3210 enum devlink_command cmd)
Moshe Shemesheabaef12018-07-04 14:30:28 +03003211{
3212 struct devlink_param_item *param_item;
3213
Vasundhara Volam39e61602019-01-28 18:00:20 +05303214 param_item = devlink_param_find_by_name(param_list, param->name);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003215 WARN_ON(!param_item);
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303216 devlink_param_notify(devlink, port_index, param_item, cmd);
Moshe Shemesheabaef12018-07-04 14:30:28 +03003217 list_del(&param_item->list);
3218 kfree(param_item);
3219}
3220
Vasundhara Volamf4601de2019-01-28 18:00:21 +05303221static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3222 struct netlink_callback *cb)
3223{
3224 struct devlink_param_item *param_item;
3225 struct devlink_port *devlink_port;
3226 struct devlink *devlink;
3227 int start = cb->args[0];
3228 int idx = 0;
3229 int err;
3230
3231 mutex_lock(&devlink_mutex);
3232 list_for_each_entry(devlink, &devlink_list, list) {
3233 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3234 continue;
3235 mutex_lock(&devlink->lock);
3236 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3237 list_for_each_entry(param_item,
3238 &devlink_port->param_list, list) {
3239 if (idx < start) {
3240 idx++;
3241 continue;
3242 }
3243 err = devlink_nl_param_fill(msg,
3244 devlink_port->devlink,
3245 devlink_port->index, param_item,
3246 DEVLINK_CMD_PORT_PARAM_GET,
3247 NETLINK_CB(cb->skb).portid,
3248 cb->nlh->nlmsg_seq,
3249 NLM_F_MULTI);
3250 if (err) {
3251 mutex_unlock(&devlink->lock);
3252 goto out;
3253 }
3254 idx++;
3255 }
3256 }
3257 mutex_unlock(&devlink->lock);
3258 }
3259out:
3260 mutex_unlock(&devlink_mutex);
3261
3262 cb->args[0] = idx;
3263 return msg->len;
3264}
3265
3266static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3267 struct genl_info *info)
3268{
3269 struct devlink_port *devlink_port = info->user_ptr[0];
3270 struct devlink_param_item *param_item;
3271 struct sk_buff *msg;
3272 int err;
3273
3274 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3275 info);
3276 if (!param_item)
3277 return -EINVAL;
3278
3279 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3280 if (!msg)
3281 return -ENOMEM;
3282
3283 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3284 devlink_port->index, param_item,
3285 DEVLINK_CMD_PORT_PARAM_GET,
3286 info->snd_portid, info->snd_seq, 0);
3287 if (err) {
3288 nlmsg_free(msg);
3289 return err;
3290 }
3291
3292 return genlmsg_reply(msg, info);
3293}
3294
Vasundhara Volam9c548732019-01-28 18:00:22 +05303295static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3296 struct genl_info *info)
3297{
3298 struct devlink_port *devlink_port = info->user_ptr[0];
3299
3300 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05303301 devlink_port->index,
3302 &devlink_port->param_list, info,
3303 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam9c548732019-01-28 18:00:22 +05303304}
3305
Alex Veskera006d462018-07-12 15:13:12 +03003306static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3307 struct devlink *devlink,
3308 struct devlink_snapshot *snapshot)
3309{
3310 struct nlattr *snap_attr;
3311 int err;
3312
3313 snap_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
3314 if (!snap_attr)
3315 return -EINVAL;
3316
3317 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3318 if (err)
3319 goto nla_put_failure;
3320
3321 nla_nest_end(msg, snap_attr);
3322 return 0;
3323
3324nla_put_failure:
3325 nla_nest_cancel(msg, snap_attr);
3326 return err;
3327}
3328
3329static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3330 struct devlink *devlink,
3331 struct devlink_region *region)
3332{
3333 struct devlink_snapshot *snapshot;
3334 struct nlattr *snapshots_attr;
3335 int err;
3336
3337 snapshots_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOTS);
3338 if (!snapshots_attr)
3339 return -EINVAL;
3340
3341 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3342 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3343 if (err)
3344 goto nla_put_failure;
3345 }
3346
3347 nla_nest_end(msg, snapshots_attr);
3348 return 0;
3349
3350nla_put_failure:
3351 nla_nest_cancel(msg, snapshots_attr);
3352 return err;
3353}
3354
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003355static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3356 enum devlink_command cmd, u32 portid,
3357 u32 seq, int flags,
3358 struct devlink_region *region)
3359{
3360 void *hdr;
3361 int err;
3362
3363 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3364 if (!hdr)
3365 return -EMSGSIZE;
3366
3367 err = devlink_nl_put_handle(msg, devlink);
3368 if (err)
3369 goto nla_put_failure;
3370
3371 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3372 if (err)
3373 goto nla_put_failure;
3374
3375 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3376 region->size,
3377 DEVLINK_ATTR_PAD);
3378 if (err)
3379 goto nla_put_failure;
3380
Alex Veskera006d462018-07-12 15:13:12 +03003381 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3382 if (err)
3383 goto nla_put_failure;
3384
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003385 genlmsg_end(msg, hdr);
3386 return 0;
3387
3388nla_put_failure:
3389 genlmsg_cancel(msg, hdr);
3390 return err;
3391}
3392
Alex Vesker866319b2018-07-12 15:13:13 +03003393static void devlink_nl_region_notify(struct devlink_region *region,
3394 struct devlink_snapshot *snapshot,
3395 enum devlink_command cmd)
3396{
3397 struct devlink *devlink = region->devlink;
3398 struct sk_buff *msg;
3399 void *hdr;
3400 int err;
3401
3402 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3403
3404 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3405 if (!msg)
3406 return;
3407
3408 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3409 if (!hdr)
3410 goto out_free_msg;
3411
3412 err = devlink_nl_put_handle(msg, devlink);
3413 if (err)
3414 goto out_cancel_msg;
3415
3416 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3417 region->name);
3418 if (err)
3419 goto out_cancel_msg;
3420
3421 if (snapshot) {
3422 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3423 snapshot->id);
3424 if (err)
3425 goto out_cancel_msg;
3426 } else {
3427 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3428 region->size, DEVLINK_ATTR_PAD);
3429 if (err)
3430 goto out_cancel_msg;
3431 }
3432 genlmsg_end(msg, hdr);
3433
3434 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3435 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3436
3437 return;
3438
3439out_cancel_msg:
3440 genlmsg_cancel(msg, hdr);
3441out_free_msg:
3442 nlmsg_free(msg);
3443}
3444
Alex Veskerd8db7ea52018-07-12 15:13:11 +03003445static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3446 struct genl_info *info)
3447{
3448 struct devlink *devlink = info->user_ptr[0];
3449 struct devlink_region *region;
3450 const char *region_name;
3451 struct sk_buff *msg;
3452 int err;
3453
3454 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3455 return -EINVAL;
3456
3457 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3458 region = devlink_region_get_by_name(devlink, region_name);
3459 if (!region)
3460 return -EINVAL;
3461
3462 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3463 if (!msg)
3464 return -ENOMEM;
3465
3466 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3467 info->snd_portid, info->snd_seq, 0,
3468 region);
3469 if (err) {
3470 nlmsg_free(msg);
3471 return err;
3472 }
3473
3474 return genlmsg_reply(msg, info);
3475}
3476
3477static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3478 struct netlink_callback *cb)
3479{
3480 struct devlink_region *region;
3481 struct devlink *devlink;
3482 int start = cb->args[0];
3483 int idx = 0;
3484 int err;
3485
3486 mutex_lock(&devlink_mutex);
3487 list_for_each_entry(devlink, &devlink_list, list) {
3488 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3489 continue;
3490
3491 mutex_lock(&devlink->lock);
3492 list_for_each_entry(region, &devlink->region_list, list) {
3493 if (idx < start) {
3494 idx++;
3495 continue;
3496 }
3497 err = devlink_nl_region_fill(msg, devlink,
3498 DEVLINK_CMD_REGION_GET,
3499 NETLINK_CB(cb->skb).portid,
3500 cb->nlh->nlmsg_seq,
3501 NLM_F_MULTI, region);
3502 if (err) {
3503 mutex_unlock(&devlink->lock);
3504 goto out;
3505 }
3506 idx++;
3507 }
3508 mutex_unlock(&devlink->lock);
3509 }
3510out:
3511 mutex_unlock(&devlink_mutex);
3512 cb->args[0] = idx;
3513 return msg->len;
3514}
3515
Alex Vesker866319b2018-07-12 15:13:13 +03003516static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3517 struct genl_info *info)
3518{
3519 struct devlink *devlink = info->user_ptr[0];
3520 struct devlink_snapshot *snapshot;
3521 struct devlink_region *region;
3522 const char *region_name;
3523 u32 snapshot_id;
3524
3525 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3526 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3527 return -EINVAL;
3528
3529 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3530 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3531
3532 region = devlink_region_get_by_name(devlink, region_name);
3533 if (!region)
3534 return -EINVAL;
3535
3536 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3537 if (!snapshot)
3538 return -EINVAL;
3539
3540 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3541 devlink_region_snapshot_del(snapshot);
3542 return 0;
3543}
3544
Alex Vesker4e547952018-07-12 15:13:14 +03003545static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3546 struct devlink *devlink,
3547 u8 *chunk, u32 chunk_size,
3548 u64 addr)
3549{
3550 struct nlattr *chunk_attr;
3551 int err;
3552
3553 chunk_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_CHUNK);
3554 if (!chunk_attr)
3555 return -EINVAL;
3556
3557 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3558 if (err)
3559 goto nla_put_failure;
3560
3561 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3562 DEVLINK_ATTR_PAD);
3563 if (err)
3564 goto nla_put_failure;
3565
3566 nla_nest_end(msg, chunk_attr);
3567 return 0;
3568
3569nla_put_failure:
3570 nla_nest_cancel(msg, chunk_attr);
3571 return err;
3572}
3573
3574#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3575
3576static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3577 struct devlink *devlink,
3578 struct devlink_region *region,
3579 struct nlattr **attrs,
3580 u64 start_offset,
3581 u64 end_offset,
3582 bool dump,
3583 u64 *new_offset)
3584{
3585 struct devlink_snapshot *snapshot;
3586 u64 curr_offset = start_offset;
3587 u32 snapshot_id;
3588 int err = 0;
3589
3590 *new_offset = start_offset;
3591
3592 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3593 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3594 if (!snapshot)
3595 return -EINVAL;
3596
3597 if (end_offset > snapshot->data_len || dump)
3598 end_offset = snapshot->data_len;
3599
3600 while (curr_offset < end_offset) {
3601 u32 data_size;
3602 u8 *data;
3603
3604 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3605 data_size = end_offset - curr_offset;
3606 else
3607 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3608
3609 data = &snapshot->data[curr_offset];
3610 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3611 data, data_size,
3612 curr_offset);
3613 if (err)
3614 break;
3615
3616 curr_offset += data_size;
3617 }
3618 *new_offset = curr_offset;
3619
3620 return err;
3621}
3622
3623static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3624 struct netlink_callback *cb)
3625{
3626 u64 ret_offset, start_offset, end_offset = 0;
Alex Vesker4e547952018-07-12 15:13:14 +03003627 const struct genl_ops *ops = cb->data;
3628 struct devlink_region *region;
3629 struct nlattr *chunks_attr;
3630 const char *region_name;
3631 struct devlink *devlink;
Jakub Kicinski68750562019-02-10 19:35:28 -08003632 struct nlattr **attrs;
Alex Vesker4e547952018-07-12 15:13:14 +03003633 bool dump = true;
3634 void *hdr;
3635 int err;
3636
3637 start_offset = *((u64 *)&cb->args[0]);
3638
Jakub Kicinski68750562019-02-10 19:35:28 -08003639 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
3640 if (!attrs)
3641 return -ENOMEM;
3642
Alex Vesker4e547952018-07-12 15:13:14 +03003643 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + devlink_nl_family.hdrsize,
David Aherndac9c972018-10-07 20:16:24 -07003644 attrs, DEVLINK_ATTR_MAX, ops->policy, cb->extack);
Alex Vesker4e547952018-07-12 15:13:14 +03003645 if (err)
Jakub Kicinski68750562019-02-10 19:35:28 -08003646 goto out_free;
Alex Vesker4e547952018-07-12 15:13:14 +03003647
3648 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
3649 if (IS_ERR(devlink))
Jakub Kicinski68750562019-02-10 19:35:28 -08003650 goto out_free;
Alex Vesker4e547952018-07-12 15:13:14 +03003651
3652 mutex_lock(&devlink_mutex);
3653 mutex_lock(&devlink->lock);
3654
3655 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
3656 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3657 goto out_unlock;
3658
3659 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3660 region = devlink_region_get_by_name(devlink, region_name);
3661 if (!region)
3662 goto out_unlock;
3663
3664 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3665 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3666 DEVLINK_CMD_REGION_READ);
3667 if (!hdr)
3668 goto out_unlock;
3669
3670 err = devlink_nl_put_handle(skb, devlink);
3671 if (err)
3672 goto nla_put_failure;
3673
3674 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3675 if (err)
3676 goto nla_put_failure;
3677
3678 chunks_attr = nla_nest_start(skb, DEVLINK_ATTR_REGION_CHUNKS);
3679 if (!chunks_attr)
3680 goto nla_put_failure;
3681
3682 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3683 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3684 if (!start_offset)
3685 start_offset =
3686 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3687
3688 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3689 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3690 dump = false;
3691 }
3692
3693 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3694 region, attrs,
3695 start_offset,
3696 end_offset, dump,
3697 &ret_offset);
3698
3699 if (err && err != -EMSGSIZE)
3700 goto nla_put_failure;
3701
3702 /* Check if there was any progress done to prevent infinite loop */
3703 if (ret_offset == start_offset)
3704 goto nla_put_failure;
3705
3706 *((u64 *)&cb->args[0]) = ret_offset;
3707
3708 nla_nest_end(skb, chunks_attr);
3709 genlmsg_end(skb, hdr);
3710 mutex_unlock(&devlink->lock);
3711 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003712 kfree(attrs);
Alex Vesker4e547952018-07-12 15:13:14 +03003713
3714 return skb->len;
3715
3716nla_put_failure:
3717 genlmsg_cancel(skb, hdr);
3718out_unlock:
3719 mutex_unlock(&devlink->lock);
3720 mutex_unlock(&devlink_mutex);
Jakub Kicinski68750562019-02-10 19:35:28 -08003721out_free:
3722 kfree(attrs);
Alex Vesker4e547952018-07-12 15:13:14 +03003723 return 0;
3724}
3725
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003726struct devlink_info_req {
3727 struct sk_buff *msg;
3728};
3729
3730int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3731{
3732 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3733}
3734EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3735
3736int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3737{
3738 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3739}
3740EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3741
Jakub Kicinskifc6fae72019-01-31 10:50:41 -08003742static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3743 const char *version_name,
3744 const char *version_value)
3745{
3746 struct nlattr *nest;
3747 int err;
3748
3749 nest = nla_nest_start(req->msg, attr);
3750 if (!nest)
3751 return -EMSGSIZE;
3752
3753 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3754 version_name);
3755 if (err)
3756 goto nla_put_failure;
3757
3758 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3759 version_value);
3760 if (err)
3761 goto nla_put_failure;
3762
3763 nla_nest_end(req->msg, nest);
3764
3765 return 0;
3766
3767nla_put_failure:
3768 nla_nest_cancel(req->msg, nest);
3769 return err;
3770}
3771
3772int devlink_info_version_fixed_put(struct devlink_info_req *req,
3773 const char *version_name,
3774 const char *version_value)
3775{
3776 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3777 version_name, version_value);
3778}
3779EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3780
3781int devlink_info_version_stored_put(struct devlink_info_req *req,
3782 const char *version_name,
3783 const char *version_value)
3784{
3785 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3786 version_name, version_value);
3787}
3788EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3789
3790int devlink_info_version_running_put(struct devlink_info_req *req,
3791 const char *version_name,
3792 const char *version_value)
3793{
3794 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3795 version_name, version_value);
3796}
3797EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3798
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08003799static int
3800devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3801 enum devlink_command cmd, u32 portid,
3802 u32 seq, int flags, struct netlink_ext_ack *extack)
3803{
3804 struct devlink_info_req req;
3805 void *hdr;
3806 int err;
3807
3808 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3809 if (!hdr)
3810 return -EMSGSIZE;
3811
3812 err = -EMSGSIZE;
3813 if (devlink_nl_put_handle(msg, devlink))
3814 goto err_cancel_msg;
3815
3816 req.msg = msg;
3817 err = devlink->ops->info_get(devlink, &req, extack);
3818 if (err)
3819 goto err_cancel_msg;
3820
3821 genlmsg_end(msg, hdr);
3822 return 0;
3823
3824err_cancel_msg:
3825 genlmsg_cancel(msg, hdr);
3826 return err;
3827}
3828
3829static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
3830 struct genl_info *info)
3831{
3832 struct devlink *devlink = info->user_ptr[0];
3833 struct sk_buff *msg;
3834 int err;
3835
3836 if (!devlink->ops || !devlink->ops->info_get)
3837 return -EOPNOTSUPP;
3838
3839 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3840 if (!msg)
3841 return -ENOMEM;
3842
3843 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3844 info->snd_portid, info->snd_seq, 0,
3845 info->extack);
3846 if (err) {
3847 nlmsg_free(msg);
3848 return err;
3849 }
3850
3851 return genlmsg_reply(msg, info);
3852}
3853
3854static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
3855 struct netlink_callback *cb)
3856{
3857 struct devlink *devlink;
3858 int start = cb->args[0];
3859 int idx = 0;
3860 int err;
3861
3862 mutex_lock(&devlink_mutex);
3863 list_for_each_entry(devlink, &devlink_list, list) {
3864 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3865 continue;
3866 if (idx < start) {
3867 idx++;
3868 continue;
3869 }
3870
3871 mutex_lock(&devlink->lock);
3872 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3873 NETLINK_CB(cb->skb).portid,
3874 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3875 cb->extack);
3876 mutex_unlock(&devlink->lock);
3877 if (err)
3878 break;
3879 idx++;
3880 }
3881 mutex_unlock(&devlink_mutex);
3882
3883 cb->args[0] = idx;
3884 return msg->len;
3885}
3886
Eran Ben Elisha1db64e82019-02-07 11:36:32 +02003887struct devlink_fmsg_item {
3888 struct list_head list;
3889 int attrtype;
3890 u8 nla_type;
3891 u16 len;
3892 int value[0];
3893};
3894
3895struct devlink_fmsg {
3896 struct list_head item_list;
3897};
3898
3899static struct devlink_fmsg *devlink_fmsg_alloc(void)
3900{
3901 struct devlink_fmsg *fmsg;
3902
3903 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
3904 if (!fmsg)
3905 return NULL;
3906
3907 INIT_LIST_HEAD(&fmsg->item_list);
3908
3909 return fmsg;
3910}
3911
3912static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
3913{
3914 struct devlink_fmsg_item *item, *tmp;
3915
3916 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
3917 list_del(&item->list);
3918 kfree(item);
3919 }
3920 kfree(fmsg);
3921}
3922
3923static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
3924 int attrtype)
3925{
3926 struct devlink_fmsg_item *item;
3927
3928 item = kzalloc(sizeof(*item), GFP_KERNEL);
3929 if (!item)
3930 return -ENOMEM;
3931
3932 item->attrtype = attrtype;
3933 list_add_tail(&item->list, &fmsg->item_list);
3934
3935 return 0;
3936}
3937
3938int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
3939{
3940 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
3941}
3942EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
3943
3944static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
3945{
3946 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
3947}
3948
3949int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
3950{
3951 return devlink_fmsg_nest_end(fmsg);
3952}
3953EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
3954
3955#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
3956
3957static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
3958{
3959 struct devlink_fmsg_item *item;
3960
3961 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
3962 return -EMSGSIZE;
3963
3964 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
3965 if (!item)
3966 return -ENOMEM;
3967
3968 item->nla_type = NLA_NUL_STRING;
3969 item->len = strlen(name) + 1;
3970 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
3971 memcpy(&item->value, name, item->len);
3972 list_add_tail(&item->list, &fmsg->item_list);
3973
3974 return 0;
3975}
3976
3977int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
3978{
3979 int err;
3980
3981 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
3982 if (err)
3983 return err;
3984
3985 err = devlink_fmsg_put_name(fmsg, name);
3986 if (err)
3987 return err;
3988
3989 return 0;
3990}
3991EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
3992
3993int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
3994{
3995 return devlink_fmsg_nest_end(fmsg);
3996}
3997EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
3998
3999int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4000 const char *name)
4001{
4002 int err;
4003
4004 err = devlink_fmsg_pair_nest_start(fmsg, name);
4005 if (err)
4006 return err;
4007
4008 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4009 if (err)
4010 return err;
4011
4012 return 0;
4013}
4014EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4015
4016int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4017{
4018 int err;
4019
4020 err = devlink_fmsg_nest_end(fmsg);
4021 if (err)
4022 return err;
4023
4024 err = devlink_fmsg_nest_end(fmsg);
4025 if (err)
4026 return err;
4027
4028 return 0;
4029}
4030EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4031
4032static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4033 const void *value, u16 value_len,
4034 u8 value_nla_type)
4035{
4036 struct devlink_fmsg_item *item;
4037
4038 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4039 return -EMSGSIZE;
4040
4041 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4042 if (!item)
4043 return -ENOMEM;
4044
4045 item->nla_type = value_nla_type;
4046 item->len = value_len;
4047 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4048 memcpy(&item->value, value, item->len);
4049 list_add_tail(&item->list, &fmsg->item_list);
4050
4051 return 0;
4052}
4053
4054int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4055{
4056 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4057}
4058EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4059
4060int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4061{
4062 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4063}
4064EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4065
4066int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4067{
4068 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4069}
4070EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4071
4072int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4073{
4074 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4075}
4076EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4077
4078int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4079{
4080 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4081 NLA_NUL_STRING);
4082}
4083EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4084
4085int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4086 u16 value_len)
4087{
4088 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4089}
4090EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4091
4092int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4093 bool value)
4094{
4095 int err;
4096
4097 err = devlink_fmsg_pair_nest_start(fmsg, name);
4098 if (err)
4099 return err;
4100
4101 err = devlink_fmsg_bool_put(fmsg, value);
4102 if (err)
4103 return err;
4104
4105 err = devlink_fmsg_pair_nest_end(fmsg);
4106 if (err)
4107 return err;
4108
4109 return 0;
4110}
4111EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4112
4113int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4114 u8 value)
4115{
4116 int err;
4117
4118 err = devlink_fmsg_pair_nest_start(fmsg, name);
4119 if (err)
4120 return err;
4121
4122 err = devlink_fmsg_u8_put(fmsg, value);
4123 if (err)
4124 return err;
4125
4126 err = devlink_fmsg_pair_nest_end(fmsg);
4127 if (err)
4128 return err;
4129
4130 return 0;
4131}
4132EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4133
4134int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4135 u32 value)
4136{
4137 int err;
4138
4139 err = devlink_fmsg_pair_nest_start(fmsg, name);
4140 if (err)
4141 return err;
4142
4143 err = devlink_fmsg_u32_put(fmsg, value);
4144 if (err)
4145 return err;
4146
4147 err = devlink_fmsg_pair_nest_end(fmsg);
4148 if (err)
4149 return err;
4150
4151 return 0;
4152}
4153EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4154
4155int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4156 u64 value)
4157{
4158 int err;
4159
4160 err = devlink_fmsg_pair_nest_start(fmsg, name);
4161 if (err)
4162 return err;
4163
4164 err = devlink_fmsg_u64_put(fmsg, value);
4165 if (err)
4166 return err;
4167
4168 err = devlink_fmsg_pair_nest_end(fmsg);
4169 if (err)
4170 return err;
4171
4172 return 0;
4173}
4174EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4175
4176int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4177 const char *value)
4178{
4179 int err;
4180
4181 err = devlink_fmsg_pair_nest_start(fmsg, name);
4182 if (err)
4183 return err;
4184
4185 err = devlink_fmsg_string_put(fmsg, value);
4186 if (err)
4187 return err;
4188
4189 err = devlink_fmsg_pair_nest_end(fmsg);
4190 if (err)
4191 return err;
4192
4193 return 0;
4194}
4195EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4196
4197int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4198 const void *value, u16 value_len)
4199{
4200 int err;
4201
4202 err = devlink_fmsg_pair_nest_start(fmsg, name);
4203 if (err)
4204 return err;
4205
4206 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4207 if (err)
4208 return err;
4209
4210 err = devlink_fmsg_pair_nest_end(fmsg);
4211 if (err)
4212 return err;
4213
4214 return 0;
4215}
4216EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4217
4218static int
4219devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4220{
4221 switch (msg->nla_type) {
4222 case NLA_FLAG:
4223 case NLA_U8:
4224 case NLA_U32:
4225 case NLA_U64:
4226 case NLA_NUL_STRING:
4227 case NLA_BINARY:
4228 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4229 msg->nla_type);
4230 default:
4231 return -EINVAL;
4232 }
4233}
4234
4235static int
4236devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4237{
4238 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4239 u8 tmp;
4240
4241 switch (msg->nla_type) {
4242 case NLA_FLAG:
4243 /* Always provide flag data, regardless of its value */
4244 tmp = *(bool *) msg->value;
4245
4246 return nla_put_u8(skb, attrtype, tmp);
4247 case NLA_U8:
4248 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4249 case NLA_U32:
4250 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4251 case NLA_U64:
4252 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4253 DEVLINK_ATTR_PAD);
4254 case NLA_NUL_STRING:
4255 return nla_put_string(skb, attrtype, (char *) &msg->value);
4256 case NLA_BINARY:
4257 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4258 default:
4259 return -EINVAL;
4260 }
4261}
4262
4263static int
4264devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4265 int *start)
4266{
4267 struct devlink_fmsg_item *item;
4268 struct nlattr *fmsg_nlattr;
4269 int i = 0;
4270 int err;
4271
4272 fmsg_nlattr = nla_nest_start(skb, DEVLINK_ATTR_FMSG);
4273 if (!fmsg_nlattr)
4274 return -EMSGSIZE;
4275
4276 list_for_each_entry(item, &fmsg->item_list, list) {
4277 if (i < *start) {
4278 i++;
4279 continue;
4280 }
4281
4282 switch (item->attrtype) {
4283 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4284 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4285 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4286 case DEVLINK_ATTR_FMSG_NEST_END:
4287 err = nla_put_flag(skb, item->attrtype);
4288 break;
4289 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4290 err = devlink_fmsg_item_fill_type(item, skb);
4291 if (err)
4292 break;
4293 err = devlink_fmsg_item_fill_data(item, skb);
4294 break;
4295 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4296 err = nla_put_string(skb, item->attrtype,
4297 (char *) &item->value);
4298 break;
4299 default:
4300 err = -EINVAL;
4301 break;
4302 }
4303 if (!err)
4304 *start = ++i;
4305 else
4306 break;
4307 }
4308
4309 nla_nest_end(skb, fmsg_nlattr);
4310 return err;
4311}
4312
4313static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4314 struct genl_info *info,
4315 enum devlink_command cmd, int flags)
4316{
4317 struct nlmsghdr *nlh;
4318 struct sk_buff *skb;
4319 bool last = false;
4320 int index = 0;
4321 void *hdr;
4322 int err;
4323
4324 while (!last) {
4325 int tmp_index = index;
4326
4327 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4328 if (!skb)
4329 return -ENOMEM;
4330
4331 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4332 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4333 if (!hdr) {
4334 err = -EMSGSIZE;
4335 goto nla_put_failure;
4336 }
4337
4338 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4339 if (!err)
4340 last = true;
4341 else if (err != -EMSGSIZE || tmp_index == index)
4342 goto nla_put_failure;
4343
4344 genlmsg_end(skb, hdr);
4345 err = genlmsg_reply(skb, info);
4346 if (err)
4347 return err;
4348 }
4349
4350 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4351 if (!skb)
4352 return -ENOMEM;
4353 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4354 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4355 if (!nlh) {
4356 err = -EMSGSIZE;
4357 goto nla_put_failure;
4358 }
4359 err = genlmsg_reply(skb, info);
4360 if (err)
4361 return err;
4362
4363 return 0;
4364
4365nla_put_failure:
4366 nlmsg_free(skb);
4367 return err;
4368}
4369
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004370struct devlink_health_reporter {
4371 struct list_head list;
4372 void *priv;
4373 const struct devlink_health_reporter_ops *ops;
4374 struct devlink *devlink;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004375 struct devlink_fmsg *dump_fmsg;
4376 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004377 u64 graceful_period;
4378 bool auto_recover;
4379 u8 health_state;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004380 u64 dump_ts;
4381 u64 error_count;
4382 u64 recovery_count;
4383 u64 last_recovery_ts;
4384};
4385
4386enum devlink_health_reporter_state {
4387 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
4388 DEVLINK_HEALTH_REPORTER_STATE_ERROR,
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004389};
4390
4391void *
4392devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4393{
4394 return reporter->priv;
4395}
4396EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4397
4398static struct devlink_health_reporter *
4399devlink_health_reporter_find_by_name(struct devlink *devlink,
4400 const char *reporter_name)
4401{
4402 struct devlink_health_reporter *reporter;
4403
4404 list_for_each_entry(reporter, &devlink->reporter_list, list)
4405 if (!strcmp(reporter->ops->name, reporter_name))
4406 return reporter;
4407 return NULL;
4408}
4409
4410/**
4411 * devlink_health_reporter_create - create devlink health reporter
4412 *
4413 * @devlink: devlink
4414 * @ops: ops
4415 * @graceful_period: to avoid recovery loops, in msecs
4416 * @auto_recover: auto recover when error occurs
4417 * @priv: priv
4418 */
4419struct devlink_health_reporter *
4420devlink_health_reporter_create(struct devlink *devlink,
4421 const struct devlink_health_reporter_ops *ops,
4422 u64 graceful_period, bool auto_recover,
4423 void *priv)
4424{
4425 struct devlink_health_reporter *reporter;
4426
4427 mutex_lock(&devlink->lock);
4428 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4429 reporter = ERR_PTR(-EEXIST);
4430 goto unlock;
4431 }
4432
4433 if (WARN_ON(auto_recover && !ops->recover) ||
4434 WARN_ON(graceful_period && !ops->recover)) {
4435 reporter = ERR_PTR(-EINVAL);
4436 goto unlock;
4437 }
4438
4439 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4440 if (!reporter) {
4441 reporter = ERR_PTR(-ENOMEM);
4442 goto unlock;
4443 }
4444
4445 reporter->priv = priv;
4446 reporter->ops = ops;
4447 reporter->devlink = devlink;
4448 reporter->graceful_period = graceful_period;
4449 reporter->auto_recover = auto_recover;
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004450 mutex_init(&reporter->dump_lock);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004451 list_add_tail(&reporter->list, &devlink->reporter_list);
4452unlock:
4453 mutex_unlock(&devlink->lock);
4454 return reporter;
4455}
4456EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4457
4458/**
4459 * devlink_health_reporter_destroy - destroy devlink health reporter
4460 *
4461 * @reporter: devlink health reporter to destroy
4462 */
4463void
4464devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4465{
4466 mutex_lock(&reporter->devlink->lock);
4467 list_del(&reporter->list);
4468 mutex_unlock(&reporter->devlink->lock);
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004469 if (reporter->dump_fmsg)
4470 devlink_fmsg_free(reporter->dump_fmsg);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02004471 kfree(reporter);
4472}
4473EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4474
Eran Ben Elishac8e1da02019-02-07 11:36:34 +02004475static int
4476devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4477 void *priv_ctx)
4478{
4479 int err;
4480
4481 if (!reporter->ops->recover)
4482 return -EOPNOTSUPP;
4483
4484 err = reporter->ops->recover(reporter, priv_ctx);
4485 if (err)
4486 return err;
4487
4488 reporter->recovery_count++;
4489 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4490 reporter->last_recovery_ts = jiffies;
4491
4492 return 0;
4493}
4494
4495static void
4496devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4497{
4498 if (!reporter->dump_fmsg)
4499 return;
4500 devlink_fmsg_free(reporter->dump_fmsg);
4501 reporter->dump_fmsg = NULL;
4502}
4503
4504static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4505 void *priv_ctx)
4506{
4507 int err;
4508
4509 if (!reporter->ops->dump)
4510 return 0;
4511
4512 if (reporter->dump_fmsg)
4513 return 0;
4514
4515 reporter->dump_fmsg = devlink_fmsg_alloc();
4516 if (!reporter->dump_fmsg) {
4517 err = -ENOMEM;
4518 return err;
4519 }
4520
4521 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4522 if (err)
4523 goto dump_err;
4524
4525 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4526 priv_ctx);
4527 if (err)
4528 goto dump_err;
4529
4530 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4531 if (err)
4532 goto dump_err;
4533
4534 reporter->dump_ts = jiffies;
4535
4536 return 0;
4537
4538dump_err:
4539 devlink_health_dump_clear(reporter);
4540 return err;
4541}
4542
4543int devlink_health_report(struct devlink_health_reporter *reporter,
4544 const char *msg, void *priv_ctx)
4545{
4546 struct devlink *devlink = reporter->devlink;
4547
4548 /* write a log message of the current error */
4549 WARN_ON(!msg);
4550 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4551 reporter->error_count++;
4552
4553 /* abort if the previous error wasn't recovered */
4554 if (reporter->auto_recover &&
4555 (reporter->health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
4556 jiffies - reporter->last_recovery_ts <
4557 msecs_to_jiffies(reporter->graceful_period))) {
4558 trace_devlink_health_recover_aborted(devlink,
4559 reporter->ops->name,
4560 reporter->health_state,
4561 jiffies -
4562 reporter->last_recovery_ts);
4563 return -ECANCELED;
4564 }
4565
4566 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4567
4568 mutex_lock(&reporter->dump_lock);
4569 /* store current dump of current error, for later analysis */
4570 devlink_health_do_dump(reporter, priv_ctx);
4571 mutex_unlock(&reporter->dump_lock);
4572
4573 if (reporter->auto_recover)
4574 return devlink_health_reporter_recover(reporter, priv_ctx);
4575
4576 return 0;
4577}
4578EXPORT_SYMBOL_GPL(devlink_health_report);
4579
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004580static struct devlink_health_reporter *
4581devlink_health_reporter_get_from_info(struct devlink *devlink,
4582 struct genl_info *info)
4583{
4584 char *reporter_name;
4585
4586 if (!info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
4587 return NULL;
4588
4589 reporter_name =
4590 nla_data(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
4591 return devlink_health_reporter_find_by_name(devlink, reporter_name);
4592}
4593
4594static int
4595devlink_nl_health_reporter_fill(struct sk_buff *msg,
4596 struct devlink *devlink,
4597 struct devlink_health_reporter *reporter,
4598 enum devlink_command cmd, u32 portid,
4599 u32 seq, int flags)
4600{
4601 struct nlattr *reporter_attr;
4602 void *hdr;
4603
4604 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4605 if (!hdr)
4606 return -EMSGSIZE;
4607
4608 if (devlink_nl_put_handle(msg, devlink))
4609 goto genlmsg_cancel;
4610
4611 reporter_attr = nla_nest_start(msg, DEVLINK_ATTR_HEALTH_REPORTER);
4612 if (!reporter_attr)
4613 goto genlmsg_cancel;
4614 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4615 reporter->ops->name))
4616 goto reporter_nest_cancel;
4617 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4618 reporter->health_state))
4619 goto reporter_nest_cancel;
4620 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR,
4621 reporter->error_count, DEVLINK_ATTR_PAD))
4622 goto reporter_nest_cancel;
4623 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER,
4624 reporter->recovery_count, DEVLINK_ATTR_PAD))
4625 goto reporter_nest_cancel;
4626 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
4627 reporter->graceful_period,
4628 DEVLINK_ATTR_PAD))
4629 goto reporter_nest_cancel;
4630 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
4631 reporter->auto_recover))
4632 goto reporter_nest_cancel;
4633 if (reporter->dump_fmsg &&
4634 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4635 jiffies_to_msecs(reporter->dump_ts),
4636 DEVLINK_ATTR_PAD))
4637 goto reporter_nest_cancel;
4638
4639 nla_nest_end(msg, reporter_attr);
4640 genlmsg_end(msg, hdr);
4641 return 0;
4642
4643reporter_nest_cancel:
4644 nla_nest_end(msg, reporter_attr);
4645genlmsg_cancel:
4646 genlmsg_cancel(msg, hdr);
4647 return -EMSGSIZE;
4648}
4649
4650static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4651 struct genl_info *info)
4652{
4653 struct devlink *devlink = info->user_ptr[0];
4654 struct devlink_health_reporter *reporter;
4655 struct sk_buff *msg;
4656 int err;
4657
4658 reporter = devlink_health_reporter_get_from_info(devlink, info);
4659 if (!reporter)
4660 return -EINVAL;
4661
4662 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4663 if (!msg)
4664 return -ENOMEM;
4665
4666 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4667 DEVLINK_CMD_HEALTH_REPORTER_GET,
4668 info->snd_portid, info->snd_seq,
4669 0);
4670 if (err) {
4671 nlmsg_free(msg);
4672 return err;
4673 }
4674
4675 return genlmsg_reply(msg, info);
4676}
4677
4678static int
4679devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4680 struct netlink_callback *cb)
4681{
4682 struct devlink_health_reporter *reporter;
4683 struct devlink *devlink;
4684 int start = cb->args[0];
4685 int idx = 0;
4686 int err;
4687
4688 mutex_lock(&devlink_mutex);
4689 list_for_each_entry(devlink, &devlink_list, list) {
4690 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4691 continue;
4692 mutex_lock(&devlink->lock);
4693 list_for_each_entry(reporter, &devlink->reporter_list,
4694 list) {
4695 if (idx < start) {
4696 idx++;
4697 continue;
4698 }
4699 err = devlink_nl_health_reporter_fill(msg, devlink,
4700 reporter,
4701 DEVLINK_CMD_HEALTH_REPORTER_GET,
4702 NETLINK_CB(cb->skb).portid,
4703 cb->nlh->nlmsg_seq,
4704 NLM_F_MULTI);
4705 if (err) {
4706 mutex_unlock(&devlink->lock);
4707 goto out;
4708 }
4709 idx++;
4710 }
4711 mutex_unlock(&devlink->lock);
4712 }
4713out:
4714 mutex_unlock(&devlink_mutex);
4715
4716 cb->args[0] = idx;
4717 return msg->len;
4718}
4719
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004720static int
4721devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
4722 struct genl_info *info)
4723{
4724 struct devlink *devlink = info->user_ptr[0];
4725 struct devlink_health_reporter *reporter;
4726
4727 reporter = devlink_health_reporter_get_from_info(devlink, info);
4728 if (!reporter)
4729 return -EINVAL;
4730
4731 if (!reporter->ops->recover &&
4732 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
4733 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]))
4734 return -EOPNOTSUPP;
4735
4736 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
4737 reporter->graceful_period =
4738 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
4739
4740 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
4741 reporter->auto_recover =
4742 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
4743
4744 return 0;
4745}
4746
Eran Ben Elisha20a09432019-02-07 11:36:37 +02004747static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
4748 struct genl_info *info)
4749{
4750 struct devlink *devlink = info->user_ptr[0];
4751 struct devlink_health_reporter *reporter;
4752
4753 reporter = devlink_health_reporter_get_from_info(devlink, info);
4754 if (!reporter)
4755 return -EINVAL;
4756
4757 return devlink_health_reporter_recover(reporter, NULL);
4758}
4759
Eran Ben Elishafca42a22019-02-07 11:36:38 +02004760static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
4761 struct genl_info *info)
4762{
4763 struct devlink *devlink = info->user_ptr[0];
4764 struct devlink_health_reporter *reporter;
4765 struct devlink_fmsg *fmsg;
4766 int err;
4767
4768 reporter = devlink_health_reporter_get_from_info(devlink, info);
4769 if (!reporter)
4770 return -EINVAL;
4771
4772 if (!reporter->ops->diagnose)
4773 return -EOPNOTSUPP;
4774
4775 fmsg = devlink_fmsg_alloc();
4776 if (!fmsg)
4777 return -ENOMEM;
4778
4779 err = devlink_fmsg_obj_nest_start(fmsg);
4780 if (err)
4781 goto out;
4782
4783 err = reporter->ops->diagnose(reporter, fmsg);
4784 if (err)
4785 goto out;
4786
4787 err = devlink_fmsg_obj_nest_end(fmsg);
4788 if (err)
4789 goto out;
4790
4791 err = devlink_fmsg_snd(fmsg, info,
4792 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
4793
4794out:
4795 devlink_fmsg_free(fmsg);
4796 return err;
4797}
4798
Eran Ben Elisha35455e22019-02-07 11:36:39 +02004799static int devlink_nl_cmd_health_reporter_dump_get_doit(struct sk_buff *skb,
4800 struct genl_info *info)
4801{
4802 struct devlink *devlink = info->user_ptr[0];
4803 struct devlink_health_reporter *reporter;
4804 int err;
4805
4806 reporter = devlink_health_reporter_get_from_info(devlink, info);
4807 if (!reporter)
4808 return -EINVAL;
4809
4810 if (!reporter->ops->dump)
4811 return -EOPNOTSUPP;
4812
4813 mutex_lock(&reporter->dump_lock);
4814 err = devlink_health_do_dump(reporter, NULL);
4815 if (err)
4816 goto out;
4817
4818 err = devlink_fmsg_snd(reporter->dump_fmsg, info,
4819 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 0);
4820
4821out:
4822 mutex_unlock(&reporter->dump_lock);
4823 return err;
4824}
4825
4826static int
4827devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
4828 struct genl_info *info)
4829{
4830 struct devlink *devlink = info->user_ptr[0];
4831 struct devlink_health_reporter *reporter;
4832
4833 reporter = devlink_health_reporter_get_from_info(devlink, info);
4834 if (!reporter)
4835 return -EINVAL;
4836
4837 if (!reporter->ops->dump)
4838 return -EOPNOTSUPP;
4839
4840 mutex_lock(&reporter->dump_lock);
4841 devlink_health_dump_clear(reporter);
4842 mutex_unlock(&reporter->dump_lock);
4843 return 0;
4844}
4845
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004846static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
4847 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
4848 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
4849 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
4850 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
4851 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
Jiri Pirkobf797472016-04-14 18:19:13 +02004852 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
4853 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
4854 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
4855 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
4856 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
4857 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
4858 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03004859 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
Roi Dayan59bfde02016-11-22 23:09:57 +02004860 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
Roi Dayanf43e9b02016-09-25 13:52:44 +03004861 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02004862 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
4863 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01004864 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
4865 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03004866 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
4867 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
4868 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03004869 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
Alex Vesker866319b2018-07-12 15:13:13 +03004870 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02004871 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02004872 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
4873 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004874};
4875
4876static const struct genl_ops devlink_nl_ops[] = {
4877 {
4878 .cmd = DEVLINK_CMD_GET,
4879 .doit = devlink_nl_cmd_get_doit,
4880 .dumpit = devlink_nl_cmd_get_dumpit,
4881 .policy = devlink_nl_policy,
Jiri Pirko1fc22572016-04-08 19:12:48 +02004882 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004883 /* can be retrieved by unprivileged users */
4884 },
4885 {
4886 .cmd = DEVLINK_CMD_PORT_GET,
4887 .doit = devlink_nl_cmd_port_get_doit,
4888 .dumpit = devlink_nl_cmd_port_get_dumpit,
4889 .policy = devlink_nl_policy,
4890 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4891 /* can be retrieved by unprivileged users */
4892 },
4893 {
4894 .cmd = DEVLINK_CMD_PORT_SET,
4895 .doit = devlink_nl_cmd_port_set_doit,
4896 .policy = devlink_nl_policy,
4897 .flags = GENL_ADMIN_PERM,
4898 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4899 },
4900 {
4901 .cmd = DEVLINK_CMD_PORT_SPLIT,
4902 .doit = devlink_nl_cmd_port_split_doit,
4903 .policy = devlink_nl_policy,
4904 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01004905 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4906 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004907 },
4908 {
4909 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
4910 .doit = devlink_nl_cmd_port_unsplit_doit,
4911 .policy = devlink_nl_policy,
4912 .flags = GENL_ADMIN_PERM,
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01004913 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4914 DEVLINK_NL_FLAG_NO_LOCK,
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01004915 },
Jiri Pirkobf797472016-04-14 18:19:13 +02004916 {
4917 .cmd = DEVLINK_CMD_SB_GET,
4918 .doit = devlink_nl_cmd_sb_get_doit,
4919 .dumpit = devlink_nl_cmd_sb_get_dumpit,
4920 .policy = devlink_nl_policy,
4921 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4922 DEVLINK_NL_FLAG_NEED_SB,
4923 /* can be retrieved by unprivileged users */
4924 },
4925 {
4926 .cmd = DEVLINK_CMD_SB_POOL_GET,
4927 .doit = devlink_nl_cmd_sb_pool_get_doit,
4928 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
4929 .policy = devlink_nl_policy,
4930 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4931 DEVLINK_NL_FLAG_NEED_SB,
4932 /* can be retrieved by unprivileged users */
4933 },
4934 {
4935 .cmd = DEVLINK_CMD_SB_POOL_SET,
4936 .doit = devlink_nl_cmd_sb_pool_set_doit,
4937 .policy = devlink_nl_policy,
4938 .flags = GENL_ADMIN_PERM,
4939 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4940 DEVLINK_NL_FLAG_NEED_SB,
4941 },
4942 {
4943 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
4944 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
4945 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
4946 .policy = devlink_nl_policy,
4947 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4948 DEVLINK_NL_FLAG_NEED_SB,
4949 /* can be retrieved by unprivileged users */
4950 },
4951 {
4952 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
4953 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
4954 .policy = devlink_nl_policy,
4955 .flags = GENL_ADMIN_PERM,
4956 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4957 DEVLINK_NL_FLAG_NEED_SB,
4958 },
4959 {
4960 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
4961 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
4962 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
4963 .policy = devlink_nl_policy,
4964 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4965 DEVLINK_NL_FLAG_NEED_SB,
4966 /* can be retrieved by unprivileged users */
4967 },
4968 {
4969 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
4970 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
4971 .policy = devlink_nl_policy,
4972 .flags = GENL_ADMIN_PERM,
4973 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4974 DEVLINK_NL_FLAG_NEED_SB,
4975 },
Jiri Pirkodf38daf2016-04-14 18:19:14 +02004976 {
4977 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
4978 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
4979 .policy = devlink_nl_policy,
4980 .flags = GENL_ADMIN_PERM,
4981 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01004982 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02004983 },
4984 {
4985 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
4986 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
4987 .policy = devlink_nl_policy,
4988 .flags = GENL_ADMIN_PERM,
4989 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01004990 DEVLINK_NL_FLAG_NEED_SB,
Jiri Pirkodf38daf2016-04-14 18:19:14 +02004991 },
Or Gerlitz08f4b592016-07-01 14:51:01 +03004992 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01004993 .cmd = DEVLINK_CMD_ESWITCH_GET,
4994 .doit = devlink_nl_cmd_eswitch_get_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03004995 .policy = devlink_nl_policy,
4996 .flags = GENL_ADMIN_PERM,
4997 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
4998 },
4999 {
Jiri Pirkoadf200f2017-02-09 15:54:33 +01005000 .cmd = DEVLINK_CMD_ESWITCH_SET,
5001 .doit = devlink_nl_cmd_eswitch_set_doit,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005002 .policy = devlink_nl_policy,
5003 .flags = GENL_ADMIN_PERM,
Jakub Kicinski7ac1cc92018-05-21 22:12:50 -07005004 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5005 DEVLINK_NL_FLAG_NO_LOCK,
Or Gerlitz08f4b592016-07-01 14:51:01 +03005006 },
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005007 {
5008 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
5009 .doit = devlink_nl_cmd_dpipe_table_get,
5010 .policy = devlink_nl_policy,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005011 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005012 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005013 },
5014 {
5015 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
5016 .doit = devlink_nl_cmd_dpipe_entries_get,
5017 .policy = devlink_nl_policy,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005018 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005019 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005020 },
5021 {
5022 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
5023 .doit = devlink_nl_cmd_dpipe_headers_get,
5024 .policy = devlink_nl_policy,
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005025 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005026 /* can be retrieved by unprivileged users */
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005027 },
5028 {
5029 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
5030 .doit = devlink_nl_cmd_dpipe_table_counters_set,
5031 .policy = devlink_nl_policy,
5032 .flags = GENL_ADMIN_PERM,
5033 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5034 },
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005035 {
5036 .cmd = DEVLINK_CMD_RESOURCE_SET,
5037 .doit = devlink_nl_cmd_resource_set,
5038 .policy = devlink_nl_policy,
5039 .flags = GENL_ADMIN_PERM,
5040 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5041 },
5042 {
5043 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
5044 .doit = devlink_nl_cmd_resource_dump,
5045 .policy = devlink_nl_policy,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005046 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
Arkadi Sharshevsky67ae6862018-03-08 12:52:25 +02005047 /* can be retrieved by unprivileged users */
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005048 },
Arkadi Sharshevsky2d8dc5b2018-01-15 08:59:04 +01005049 {
5050 .cmd = DEVLINK_CMD_RELOAD,
5051 .doit = devlink_nl_cmd_reload,
5052 .policy = devlink_nl_policy,
5053 .flags = GENL_ADMIN_PERM,
5054 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5055 DEVLINK_NL_FLAG_NO_LOCK,
5056 },
Moshe Shemesh45f05de2018-07-04 14:30:29 +03005057 {
5058 .cmd = DEVLINK_CMD_PARAM_GET,
5059 .doit = devlink_nl_cmd_param_get_doit,
5060 .dumpit = devlink_nl_cmd_param_get_dumpit,
5061 .policy = devlink_nl_policy,
5062 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5063 /* can be retrieved by unprivileged users */
5064 },
Moshe Shemeshe3b7ca12018-07-04 14:30:30 +03005065 {
5066 .cmd = DEVLINK_CMD_PARAM_SET,
5067 .doit = devlink_nl_cmd_param_set_doit,
5068 .policy = devlink_nl_policy,
5069 .flags = GENL_ADMIN_PERM,
5070 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5071 },
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005072 {
Vasundhara Volamf4601de2019-01-28 18:00:21 +05305073 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
5074 .doit = devlink_nl_cmd_port_param_get_doit,
5075 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
5076 .policy = devlink_nl_policy,
5077 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5078 /* can be retrieved by unprivileged users */
5079 },
5080 {
Vasundhara Volam9c548732019-01-28 18:00:22 +05305081 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
5082 .doit = devlink_nl_cmd_port_param_set_doit,
5083 .policy = devlink_nl_policy,
5084 .flags = GENL_ADMIN_PERM,
5085 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5086 },
5087 {
Alex Veskerd8db7ea52018-07-12 15:13:11 +03005088 .cmd = DEVLINK_CMD_REGION_GET,
5089 .doit = devlink_nl_cmd_region_get_doit,
5090 .dumpit = devlink_nl_cmd_region_get_dumpit,
5091 .policy = devlink_nl_policy,
5092 .flags = GENL_ADMIN_PERM,
5093 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5094 },
Alex Vesker866319b2018-07-12 15:13:13 +03005095 {
5096 .cmd = DEVLINK_CMD_REGION_DEL,
5097 .doit = devlink_nl_cmd_region_del,
5098 .policy = devlink_nl_policy,
5099 .flags = GENL_ADMIN_PERM,
5100 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5101 },
Alex Vesker4e547952018-07-12 15:13:14 +03005102 {
5103 .cmd = DEVLINK_CMD_REGION_READ,
5104 .dumpit = devlink_nl_cmd_region_read_dumpit,
5105 .policy = devlink_nl_policy,
5106 .flags = GENL_ADMIN_PERM,
5107 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5108 },
Jakub Kicinskif9cf2282019-01-31 10:50:40 -08005109 {
5110 .cmd = DEVLINK_CMD_INFO_GET,
5111 .doit = devlink_nl_cmd_info_get_doit,
5112 .dumpit = devlink_nl_cmd_info_get_dumpit,
5113 .policy = devlink_nl_policy,
5114 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5115 /* can be retrieved by unprivileged users */
5116 },
Eran Ben Elisha7afe335a2019-02-07 11:36:35 +02005117 {
5118 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
5119 .doit = devlink_nl_cmd_health_reporter_get_doit,
5120 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
5121 .policy = devlink_nl_policy,
5122 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5123 /* can be retrieved by unprivileged users */
5124 },
Eran Ben Elishaa1e55ec2019-02-07 11:36:36 +02005125 {
5126 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
5127 .doit = devlink_nl_cmd_health_reporter_set_doit,
5128 .policy = devlink_nl_policy,
5129 .flags = GENL_ADMIN_PERM,
5130 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5131 },
Eran Ben Elisha20a09432019-02-07 11:36:37 +02005132 {
5133 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
5134 .doit = devlink_nl_cmd_health_reporter_recover_doit,
5135 .policy = devlink_nl_policy,
5136 .flags = GENL_ADMIN_PERM,
5137 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5138 },
Eran Ben Elishafca42a22019-02-07 11:36:38 +02005139 {
5140 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
5141 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
5142 .policy = devlink_nl_policy,
5143 .flags = GENL_ADMIN_PERM,
5144 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5145 },
Eran Ben Elisha35455e22019-02-07 11:36:39 +02005146 {
5147 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
5148 .doit = devlink_nl_cmd_health_reporter_dump_get_doit,
5149 .policy = devlink_nl_policy,
5150 .flags = GENL_ADMIN_PERM,
5151 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5152 DEVLINK_NL_FLAG_NO_LOCK,
5153 },
5154 {
5155 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
5156 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
5157 .policy = devlink_nl_policy,
5158 .flags = GENL_ADMIN_PERM,
5159 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5160 DEVLINK_NL_FLAG_NO_LOCK,
5161 },
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005162};
5163
Johannes Berg56989f62016-10-24 14:40:05 +02005164static struct genl_family devlink_nl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02005165 .name = DEVLINK_GENL_NAME,
5166 .version = DEVLINK_GENL_VERSION,
5167 .maxattr = DEVLINK_ATTR_MAX,
5168 .netnsok = true,
5169 .pre_doit = devlink_nl_pre_doit,
5170 .post_doit = devlink_nl_post_doit,
5171 .module = THIS_MODULE,
5172 .ops = devlink_nl_ops,
5173 .n_ops = ARRAY_SIZE(devlink_nl_ops),
5174 .mcgrps = devlink_nl_mcgrps,
5175 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
5176};
5177
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005178/**
5179 * devlink_alloc - Allocate new devlink instance resources
5180 *
5181 * @ops: ops
5182 * @priv_size: size of user private data
5183 *
5184 * Allocate new devlink instance resources, including devlink index
5185 * and name.
5186 */
5187struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
5188{
5189 struct devlink *devlink;
5190
5191 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
5192 if (!devlink)
5193 return NULL;
5194 devlink->ops = ops;
5195 devlink_net_set(devlink, &init_net);
5196 INIT_LIST_HEAD(&devlink->port_list);
Jiri Pirkobf797472016-04-14 18:19:13 +02005197 INIT_LIST_HEAD(&devlink->sb_list);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005198 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005199 INIT_LIST_HEAD(&devlink->resource_list);
Moshe Shemesheabaef12018-07-04 14:30:28 +03005200 INIT_LIST_HEAD(&devlink->param_list);
Alex Veskerb16ebe92018-07-12 15:13:08 +03005201 INIT_LIST_HEAD(&devlink->region_list);
Eran Ben Elishaa0bdcc52019-02-07 11:36:33 +02005202 INIT_LIST_HEAD(&devlink->reporter_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005203 mutex_init(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005204 return devlink;
5205}
5206EXPORT_SYMBOL_GPL(devlink_alloc);
5207
5208/**
5209 * devlink_register - Register devlink instance
5210 *
5211 * @devlink: devlink
5212 */
5213int devlink_register(struct devlink *devlink, struct device *dev)
5214{
5215 mutex_lock(&devlink_mutex);
5216 devlink->dev = dev;
5217 list_add_tail(&devlink->list, &devlink_list);
5218 devlink_notify(devlink, DEVLINK_CMD_NEW);
5219 mutex_unlock(&devlink_mutex);
5220 return 0;
5221}
5222EXPORT_SYMBOL_GPL(devlink_register);
5223
5224/**
5225 * devlink_unregister - Unregister devlink instance
5226 *
5227 * @devlink: devlink
5228 */
5229void devlink_unregister(struct devlink *devlink)
5230{
5231 mutex_lock(&devlink_mutex);
5232 devlink_notify(devlink, DEVLINK_CMD_DEL);
5233 list_del(&devlink->list);
5234 mutex_unlock(&devlink_mutex);
5235}
5236EXPORT_SYMBOL_GPL(devlink_unregister);
5237
5238/**
5239 * devlink_free - Free devlink instance resources
5240 *
5241 * @devlink: devlink
5242 */
5243void devlink_free(struct devlink *devlink)
5244{
Parav Panditb904aad2019-02-08 15:15:00 -06005245 WARN_ON(!list_empty(&devlink->reporter_list));
5246 WARN_ON(!list_empty(&devlink->region_list));
5247 WARN_ON(!list_empty(&devlink->param_list));
5248 WARN_ON(!list_empty(&devlink->resource_list));
5249 WARN_ON(!list_empty(&devlink->dpipe_table_list));
5250 WARN_ON(!list_empty(&devlink->sb_list));
5251 WARN_ON(!list_empty(&devlink->port_list));
5252
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005253 kfree(devlink);
5254}
5255EXPORT_SYMBOL_GPL(devlink_free);
5256
5257/**
5258 * devlink_port_register - Register devlink port
5259 *
5260 * @devlink: devlink
5261 * @devlink_port: devlink port
5262 * @port_index
5263 *
5264 * Register devlink port with provided port index. User can use
5265 * any indexing, even hw-related one. devlink_port structure
5266 * is convenient to be embedded inside user driver private structure.
5267 * Note that the caller should take care of zeroing the devlink_port
5268 * structure.
5269 */
5270int devlink_port_register(struct devlink *devlink,
5271 struct devlink_port *devlink_port,
5272 unsigned int port_index)
5273{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005274 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005275 if (devlink_port_index_exists(devlink, port_index)) {
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005276 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005277 return -EEXIST;
5278 }
5279 devlink_port->devlink = devlink;
5280 devlink_port->index = port_index;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005281 devlink_port->registered = true;
5282 list_add_tail(&devlink_port->list, &devlink->port_list);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305283 INIT_LIST_HEAD(&devlink_port->param_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005284 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005285 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5286 return 0;
5287}
5288EXPORT_SYMBOL_GPL(devlink_port_register);
5289
5290/**
5291 * devlink_port_unregister - Unregister devlink port
5292 *
5293 * @devlink_port: devlink port
5294 */
5295void devlink_port_unregister(struct devlink_port *devlink_port)
5296{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005297 struct devlink *devlink = devlink_port->devlink;
5298
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005299 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005300 mutex_lock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005301 list_del(&devlink_port->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005302 mutex_unlock(&devlink->lock);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005303}
5304EXPORT_SYMBOL_GPL(devlink_port_unregister);
5305
5306static void __devlink_port_type_set(struct devlink_port *devlink_port,
5307 enum devlink_port_type type,
5308 void *type_dev)
5309{
5310 devlink_port->type = type;
5311 devlink_port->type_dev = type_dev;
5312 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5313}
5314
5315/**
5316 * devlink_port_type_eth_set - Set port type to Ethernet
5317 *
5318 * @devlink_port: devlink port
5319 * @netdev: related netdevice
5320 */
5321void devlink_port_type_eth_set(struct devlink_port *devlink_port,
5322 struct net_device *netdev)
5323{
5324 return __devlink_port_type_set(devlink_port,
5325 DEVLINK_PORT_TYPE_ETH, netdev);
5326}
5327EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
5328
5329/**
5330 * devlink_port_type_ib_set - Set port type to InfiniBand
5331 *
5332 * @devlink_port: devlink port
5333 * @ibdev: related IB device
5334 */
5335void devlink_port_type_ib_set(struct devlink_port *devlink_port,
5336 struct ib_device *ibdev)
5337{
5338 return __devlink_port_type_set(devlink_port,
5339 DEVLINK_PORT_TYPE_IB, ibdev);
5340}
5341EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
5342
5343/**
5344 * devlink_port_type_clear - Clear port type
5345 *
5346 * @devlink_port: devlink port
5347 */
5348void devlink_port_type_clear(struct devlink_port *devlink_port)
5349{
5350 return __devlink_port_type_set(devlink_port,
5351 DEVLINK_PORT_TYPE_NOTSET, NULL);
5352}
5353EXPORT_SYMBOL_GPL(devlink_port_type_clear);
5354
5355/**
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005356 * devlink_port_attrs_set - Set port attributes
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005357 *
5358 * @devlink_port: devlink port
Jiri Pirko5ec13802018-05-18 09:29:01 +02005359 * @flavour: flavour of the port
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005360 * @port_number: number of the port that is facing user, for example
5361 * the front panel port number
5362 * @split: indicates if this is split port
5363 * @split_subport_number: if the port is split, this is the number
5364 * of subport.
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005365 */
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005366void devlink_port_attrs_set(struct devlink_port *devlink_port,
Jiri Pirko5ec13802018-05-18 09:29:01 +02005367 enum devlink_port_flavour flavour,
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005368 u32 port_number, bool split,
5369 u32 split_subport_number)
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005370{
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005371 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5372
5373 attrs->set = true;
Jiri Pirko5ec13802018-05-18 09:29:01 +02005374 attrs->flavour = flavour;
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005375 attrs->port_number = port_number;
5376 attrs->split = split;
5377 attrs->split_subport_number = split_subport_number;
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005378 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5379}
Jiri Pirkob9ffcba2018-05-18 09:29:00 +02005380EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01005381
Jiri Pirko08474c12018-05-18 09:29:02 +02005382int devlink_port_get_phys_port_name(struct devlink_port *devlink_port,
5383 char *name, size_t len)
5384{
5385 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5386 int n = 0;
5387
5388 if (!attrs->set)
5389 return -EOPNOTSUPP;
5390
5391 switch (attrs->flavour) {
5392 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
5393 if (!attrs->split)
5394 n = snprintf(name, len, "p%u", attrs->port_number);
5395 else
5396 n = snprintf(name, len, "p%us%u", attrs->port_number,
5397 attrs->split_subport_number);
5398 break;
5399 case DEVLINK_PORT_FLAVOUR_CPU:
5400 case DEVLINK_PORT_FLAVOUR_DSA:
5401 /* As CPU and DSA ports do not have a netdevice associated
5402 * case should not ever happen.
5403 */
5404 WARN_ON(1);
5405 return -EINVAL;
5406 }
5407
5408 if (n >= len)
5409 return -EINVAL;
5410
5411 return 0;
5412}
5413EXPORT_SYMBOL_GPL(devlink_port_get_phys_port_name);
5414
Jiri Pirkobf797472016-04-14 18:19:13 +02005415int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
5416 u32 size, u16 ingress_pools_count,
5417 u16 egress_pools_count, u16 ingress_tc_count,
5418 u16 egress_tc_count)
5419{
5420 struct devlink_sb *devlink_sb;
5421 int err = 0;
5422
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005423 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005424 if (devlink_sb_index_exists(devlink, sb_index)) {
5425 err = -EEXIST;
5426 goto unlock;
5427 }
5428
5429 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
5430 if (!devlink_sb) {
5431 err = -ENOMEM;
5432 goto unlock;
5433 }
5434 devlink_sb->index = sb_index;
5435 devlink_sb->size = size;
5436 devlink_sb->ingress_pools_count = ingress_pools_count;
5437 devlink_sb->egress_pools_count = egress_pools_count;
5438 devlink_sb->ingress_tc_count = ingress_tc_count;
5439 devlink_sb->egress_tc_count = egress_tc_count;
5440 list_add_tail(&devlink_sb->list, &devlink->sb_list);
5441unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005442 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005443 return err;
5444}
5445EXPORT_SYMBOL_GPL(devlink_sb_register);
5446
5447void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
5448{
5449 struct devlink_sb *devlink_sb;
5450
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005451 mutex_lock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005452 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
5453 WARN_ON(!devlink_sb);
5454 list_del(&devlink_sb->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005455 mutex_unlock(&devlink->lock);
Jiri Pirkobf797472016-04-14 18:19:13 +02005456 kfree(devlink_sb);
5457}
5458EXPORT_SYMBOL_GPL(devlink_sb_unregister);
5459
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005460/**
5461 * devlink_dpipe_headers_register - register dpipe headers
5462 *
5463 * @devlink: devlink
5464 * @dpipe_headers: dpipe header array
5465 *
5466 * Register the headers supported by hardware.
5467 */
5468int devlink_dpipe_headers_register(struct devlink *devlink,
5469 struct devlink_dpipe_headers *dpipe_headers)
5470{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005471 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005472 devlink->dpipe_headers = dpipe_headers;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005473 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005474 return 0;
5475}
5476EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
5477
5478/**
5479 * devlink_dpipe_headers_unregister - unregister dpipe headers
5480 *
5481 * @devlink: devlink
5482 *
5483 * Unregister the headers supported by hardware.
5484 */
5485void devlink_dpipe_headers_unregister(struct devlink *devlink)
5486{
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005487 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005488 devlink->dpipe_headers = NULL;
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005489 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005490}
5491EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
5492
5493/**
5494 * devlink_dpipe_table_counter_enabled - check if counter allocation
5495 * required
5496 * @devlink: devlink
5497 * @table_name: tables name
5498 *
5499 * Used by driver to check if counter allocation is required.
5500 * After counter allocation is turned on the table entries
5501 * are updated to include counter statistics.
5502 *
5503 * After that point on the driver must respect the counter
5504 * state so that each entry added to the table is added
5505 * with a counter.
5506 */
5507bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
5508 const char *table_name)
5509{
5510 struct devlink_dpipe_table *table;
5511 bool enabled;
5512
5513 rcu_read_lock();
5514 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5515 table_name);
5516 enabled = false;
5517 if (table)
5518 enabled = table->counters_enabled;
5519 rcu_read_unlock();
5520 return enabled;
5521}
5522EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
5523
5524/**
5525 * devlink_dpipe_table_register - register dpipe table
5526 *
5527 * @devlink: devlink
5528 * @table_name: table name
5529 * @table_ops: table ops
5530 * @priv: priv
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005531 * @counter_control_extern: external control for counters
5532 */
5533int devlink_dpipe_table_register(struct devlink *devlink,
5534 const char *table_name,
5535 struct devlink_dpipe_table_ops *table_ops,
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02005536 void *priv, bool counter_control_extern)
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005537{
5538 struct devlink_dpipe_table *table;
5539
5540 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
5541 return -EEXIST;
5542
Arkadi Sharshevskyffd3cdc2017-08-24 08:40:02 +02005543 if (WARN_ON(!table_ops->size_get))
5544 return -EINVAL;
5545
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005546 table = kzalloc(sizeof(*table), GFP_KERNEL);
5547 if (!table)
5548 return -ENOMEM;
5549
5550 table->name = table_name;
5551 table->table_ops = table_ops;
5552 table->priv = priv;
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005553 table->counter_control_extern = counter_control_extern;
5554
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005555 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005556 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005557 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005558 return 0;
5559}
5560EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
5561
5562/**
5563 * devlink_dpipe_table_unregister - unregister dpipe table
5564 *
5565 * @devlink: devlink
5566 * @table_name: table name
5567 */
5568void devlink_dpipe_table_unregister(struct devlink *devlink,
5569 const char *table_name)
5570{
5571 struct devlink_dpipe_table *table;
5572
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005573 mutex_lock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005574 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5575 table_name);
5576 if (!table)
5577 goto unlock;
5578 list_del_rcu(&table->list);
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005579 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005580 kfree_rcu(table, rcu);
5581 return;
5582unlock:
Arkadi Sharshevsky2406e7e2018-01-15 08:59:02 +01005583 mutex_unlock(&devlink->lock);
Arkadi Sharshevsky1555d202017-03-28 17:24:10 +02005584}
5585EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
5586
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005587/**
5588 * devlink_resource_register - devlink resource register
5589 *
5590 * @devlink: devlink
5591 * @resource_name: resource's name
5592 * @top_hierarchy: top hierarchy
5593 * @reload_required: reload is required for new configuration to
5594 * apply
5595 * @resource_size: resource's size
5596 * @resource_id: resource's id
5597 * @parent_reosurce_id: resource's parent id
5598 * @size params: size parameters
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005599 */
5600int devlink_resource_register(struct devlink *devlink,
5601 const char *resource_name,
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005602 u64 resource_size,
5603 u64 resource_id,
5604 u64 parent_resource_id,
Jiri Pirkofc56be42018-04-05 22:13:21 +02005605 const struct devlink_resource_size_params *size_params)
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005606{
5607 struct devlink_resource *resource;
5608 struct list_head *resource_list;
David Ahern14530742018-03-20 19:31:14 -07005609 bool top_hierarchy;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005610 int err = 0;
5611
David Ahern14530742018-03-20 19:31:14 -07005612 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
5613
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005614 mutex_lock(&devlink->lock);
5615 resource = devlink_resource_find(devlink, NULL, resource_id);
5616 if (resource) {
5617 err = -EINVAL;
5618 goto out;
5619 }
5620
5621 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
5622 if (!resource) {
5623 err = -ENOMEM;
5624 goto out;
5625 }
5626
5627 if (top_hierarchy) {
5628 resource_list = &devlink->resource_list;
5629 } else {
5630 struct devlink_resource *parent_resource;
5631
5632 parent_resource = devlink_resource_find(devlink, NULL,
5633 parent_resource_id);
5634 if (parent_resource) {
5635 resource_list = &parent_resource->resource_list;
5636 resource->parent = parent_resource;
5637 } else {
Colin Ian Kingb75703d2018-01-22 10:31:19 +00005638 kfree(resource);
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005639 err = -EINVAL;
5640 goto out;
5641 }
5642 }
5643
5644 resource->name = resource_name;
5645 resource->size = resource_size;
5646 resource->size_new = resource_size;
5647 resource->id = resource_id;
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005648 resource->size_valid = true;
Jiri Pirko77d27092018-02-28 13:12:09 +01005649 memcpy(&resource->size_params, size_params,
5650 sizeof(resource->size_params));
Arkadi Sharshevskyd9f9b9a2018-01-15 08:59:03 +01005651 INIT_LIST_HEAD(&resource->resource_list);
5652 list_add_tail(&resource->list, resource_list);
5653out:
5654 mutex_unlock(&devlink->lock);
5655 return err;
5656}
5657EXPORT_SYMBOL_GPL(devlink_resource_register);
5658
5659/**
5660 * devlink_resources_unregister - free all resources
5661 *
5662 * @devlink: devlink
5663 * @resource: resource
5664 */
5665void devlink_resources_unregister(struct devlink *devlink,
5666 struct devlink_resource *resource)
5667{
5668 struct devlink_resource *tmp, *child_resource;
5669 struct list_head *resource_list;
5670
5671 if (resource)
5672 resource_list = &resource->resource_list;
5673 else
5674 resource_list = &devlink->resource_list;
5675
5676 if (!resource)
5677 mutex_lock(&devlink->lock);
5678
5679 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
5680 devlink_resources_unregister(devlink, child_resource);
5681 list_del(&child_resource->list);
5682 kfree(child_resource);
5683 }
5684
5685 if (!resource)
5686 mutex_unlock(&devlink->lock);
5687}
5688EXPORT_SYMBOL_GPL(devlink_resources_unregister);
5689
5690/**
5691 * devlink_resource_size_get - get and update size
5692 *
5693 * @devlink: devlink
5694 * @resource_id: the requested resource id
5695 * @p_resource_size: ptr to update
5696 */
5697int devlink_resource_size_get(struct devlink *devlink,
5698 u64 resource_id,
5699 u64 *p_resource_size)
5700{
5701 struct devlink_resource *resource;
5702 int err = 0;
5703
5704 mutex_lock(&devlink->lock);
5705 resource = devlink_resource_find(devlink, NULL, resource_id);
5706 if (!resource) {
5707 err = -EINVAL;
5708 goto out;
5709 }
5710 *p_resource_size = resource->size_new;
5711 resource->size = resource->size_new;
5712out:
5713 mutex_unlock(&devlink->lock);
5714 return err;
5715}
5716EXPORT_SYMBOL_GPL(devlink_resource_size_get);
5717
Arkadi Sharshevsky56dc7cd2018-01-15 08:59:05 +01005718/**
5719 * devlink_dpipe_table_resource_set - set the resource id
5720 *
5721 * @devlink: devlink
5722 * @table_name: table name
5723 * @resource_id: resource id
5724 * @resource_units: number of resource's units consumed per table's entry
5725 */
5726int devlink_dpipe_table_resource_set(struct devlink *devlink,
5727 const char *table_name, u64 resource_id,
5728 u64 resource_units)
5729{
5730 struct devlink_dpipe_table *table;
5731 int err = 0;
5732
5733 mutex_lock(&devlink->lock);
5734 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5735 table_name);
5736 if (!table) {
5737 err = -EINVAL;
5738 goto out;
5739 }
5740 table->resource_id = resource_id;
5741 table->resource_units = resource_units;
5742 table->resource_valid = true;
5743out:
5744 mutex_unlock(&devlink->lock);
5745 return err;
5746}
5747EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
5748
Jiri Pirkofc56be42018-04-05 22:13:21 +02005749/**
5750 * devlink_resource_occ_get_register - register occupancy getter
5751 *
5752 * @devlink: devlink
5753 * @resource_id: resource id
5754 * @occ_get: occupancy getter callback
5755 * @occ_get_priv: occupancy getter callback priv
5756 */
5757void devlink_resource_occ_get_register(struct devlink *devlink,
5758 u64 resource_id,
5759 devlink_resource_occ_get_t *occ_get,
5760 void *occ_get_priv)
5761{
5762 struct devlink_resource *resource;
5763
5764 mutex_lock(&devlink->lock);
5765 resource = devlink_resource_find(devlink, NULL, resource_id);
5766 if (WARN_ON(!resource))
5767 goto out;
5768 WARN_ON(resource->occ_get);
5769
5770 resource->occ_get = occ_get;
5771 resource->occ_get_priv = occ_get_priv;
5772out:
5773 mutex_unlock(&devlink->lock);
5774}
5775EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
5776
5777/**
5778 * devlink_resource_occ_get_unregister - unregister occupancy getter
5779 *
5780 * @devlink: devlink
5781 * @resource_id: resource id
5782 */
5783void devlink_resource_occ_get_unregister(struct devlink *devlink,
5784 u64 resource_id)
5785{
5786 struct devlink_resource *resource;
5787
5788 mutex_lock(&devlink->lock);
5789 resource = devlink_resource_find(devlink, NULL, resource_id);
5790 if (WARN_ON(!resource))
5791 goto out;
5792 WARN_ON(!resource->occ_get);
5793
5794 resource->occ_get = NULL;
5795 resource->occ_get_priv = NULL;
5796out:
5797 mutex_unlock(&devlink->lock);
5798}
5799EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
5800
Vasundhara Volam39e61602019-01-28 18:00:20 +05305801static int devlink_param_verify(const struct devlink_param *param)
5802{
5803 if (!param || !param->name || !param->supported_cmodes)
5804 return -EINVAL;
5805 if (param->generic)
5806 return devlink_param_generic_verify(param);
5807 else
5808 return devlink_param_driver_verify(param);
5809}
5810
5811static int __devlink_params_register(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305812 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05305813 struct list_head *param_list,
5814 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305815 size_t params_count,
5816 enum devlink_command reg_cmd,
5817 enum devlink_command unreg_cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05305818{
5819 const struct devlink_param *param = params;
5820 int i;
5821 int err;
5822
5823 mutex_lock(&devlink->lock);
5824 for (i = 0; i < params_count; i++, param++) {
5825 err = devlink_param_verify(param);
5826 if (err)
5827 goto rollback;
5828
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305829 err = devlink_param_register_one(devlink, port_index,
5830 param_list, param, reg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305831 if (err)
5832 goto rollback;
5833 }
5834
5835 mutex_unlock(&devlink->lock);
5836 return 0;
5837
5838rollback:
5839 if (!i)
5840 goto unlock;
5841 for (param--; i > 0; i--, param--)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305842 devlink_param_unregister_one(devlink, port_index, param_list,
5843 param, unreg_cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305844unlock:
5845 mutex_unlock(&devlink->lock);
5846 return err;
5847}
5848
5849static void __devlink_params_unregister(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305850 unsigned int port_index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05305851 struct list_head *param_list,
5852 const struct devlink_param *params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305853 size_t params_count,
5854 enum devlink_command cmd)
Vasundhara Volam39e61602019-01-28 18:00:20 +05305855{
5856 const struct devlink_param *param = params;
5857 int i;
5858
5859 mutex_lock(&devlink->lock);
5860 for (i = 0; i < params_count; i++, param++)
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305861 devlink_param_unregister_one(devlink, 0, param_list, param,
5862 cmd);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305863 mutex_unlock(&devlink->lock);
5864}
5865
Moshe Shemesheabaef12018-07-04 14:30:28 +03005866/**
5867 * devlink_params_register - register configuration parameters
5868 *
5869 * @devlink: devlink
5870 * @params: configuration parameters array
5871 * @params_count: number of parameters provided
5872 *
5873 * Register the configuration parameters supported by the driver.
5874 */
5875int devlink_params_register(struct devlink *devlink,
5876 const struct devlink_param *params,
5877 size_t params_count)
5878{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305879 return __devlink_params_register(devlink, 0, &devlink->param_list,
5880 params, params_count,
5881 DEVLINK_CMD_PARAM_NEW,
5882 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03005883}
5884EXPORT_SYMBOL_GPL(devlink_params_register);
5885
5886/**
5887 * devlink_params_unregister - unregister configuration parameters
5888 * @devlink: devlink
5889 * @params: configuration parameters to unregister
5890 * @params_count: number of parameters provided
5891 */
5892void devlink_params_unregister(struct devlink *devlink,
5893 const struct devlink_param *params,
5894 size_t params_count)
5895{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305896 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
5897 params, params_count,
5898 DEVLINK_CMD_PARAM_DEL);
Moshe Shemesheabaef12018-07-04 14:30:28 +03005899}
5900EXPORT_SYMBOL_GPL(devlink_params_unregister);
5901
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03005902/**
Jiri Pirko7c62cfb2019-02-07 11:22:45 +00005903 * devlink_params_publish - publish configuration parameters
5904 *
5905 * @devlink: devlink
5906 *
5907 * Publish previously registered configuration parameters.
5908 */
5909void devlink_params_publish(struct devlink *devlink)
5910{
5911 struct devlink_param_item *param_item;
5912
5913 list_for_each_entry(param_item, &devlink->param_list, list) {
5914 if (param_item->published)
5915 continue;
5916 param_item->published = true;
5917 devlink_param_notify(devlink, 0, param_item,
5918 DEVLINK_CMD_PARAM_NEW);
5919 }
5920}
5921EXPORT_SYMBOL_GPL(devlink_params_publish);
5922
5923/**
5924 * devlink_params_unpublish - unpublish configuration parameters
5925 *
5926 * @devlink: devlink
5927 *
5928 * Unpublish previously registered configuration parameters.
5929 */
5930void devlink_params_unpublish(struct devlink *devlink)
5931{
5932 struct devlink_param_item *param_item;
5933
5934 list_for_each_entry(param_item, &devlink->param_list, list) {
5935 if (!param_item->published)
5936 continue;
5937 param_item->published = false;
5938 devlink_param_notify(devlink, 0, param_item,
5939 DEVLINK_CMD_PARAM_DEL);
5940 }
5941}
5942EXPORT_SYMBOL_GPL(devlink_params_unpublish);
5943
5944/**
Vasundhara Volam39e61602019-01-28 18:00:20 +05305945 * devlink_port_params_register - register port configuration parameters
5946 *
5947 * @devlink_port: devlink port
5948 * @params: configuration parameters array
5949 * @params_count: number of parameters provided
5950 *
5951 * Register the configuration parameters supported by the port.
5952 */
5953int devlink_port_params_register(struct devlink_port *devlink_port,
5954 const struct devlink_param *params,
5955 size_t params_count)
5956{
5957 return __devlink_params_register(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305958 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05305959 &devlink_port->param_list, params,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305960 params_count,
5961 DEVLINK_CMD_PORT_PARAM_NEW,
5962 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305963}
5964EXPORT_SYMBOL_GPL(devlink_port_params_register);
5965
5966/**
5967 * devlink_port_params_unregister - unregister port configuration
5968 * parameters
5969 *
5970 * @devlink_port: devlink port
5971 * @params: configuration parameters array
5972 * @params_count: number of parameters provided
5973 */
5974void devlink_port_params_unregister(struct devlink_port *devlink_port,
5975 const struct devlink_param *params,
5976 size_t params_count)
5977{
5978 return __devlink_params_unregister(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305979 devlink_port->index,
Vasundhara Volam39e61602019-01-28 18:00:20 +05305980 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05305981 params, params_count,
5982 DEVLINK_CMD_PORT_PARAM_DEL);
Vasundhara Volam39e61602019-01-28 18:00:20 +05305983}
5984EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
5985
Vasundhara Volamffd19b92019-01-28 18:00:23 +05305986static int
5987__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
5988 union devlink_param_value *init_val)
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03005989{
5990 struct devlink_param_item *param_item;
5991
Vasundhara Volamffd19b92019-01-28 18:00:23 +05305992 param_item = devlink_param_find_by_id(param_list, param_id);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03005993 if (!param_item)
5994 return -EINVAL;
5995
5996 if (!param_item->driverinit_value_valid ||
5997 !devlink_param_cmode_is_supported(param_item->param,
5998 DEVLINK_PARAM_CMODE_DRIVERINIT))
5999 return -EOPNOTSUPP;
6000
Moshe Shemesh12765342018-10-10 16:09:26 +03006001 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6002 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
6003 else
6004 *init_val = param_item->driverinit_value;
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006005
6006 return 0;
6007}
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306008
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306009static int
6010__devlink_param_driverinit_value_set(struct devlink *devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306011 unsigned int port_index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306012 struct list_head *param_list, u32 param_id,
6013 union devlink_param_value init_val,
6014 enum devlink_command cmd)
6015{
6016 struct devlink_param_item *param_item;
6017
6018 param_item = devlink_param_find_by_id(param_list, param_id);
6019 if (!param_item)
6020 return -EINVAL;
6021
6022 if (!devlink_param_cmode_is_supported(param_item->param,
6023 DEVLINK_PARAM_CMODE_DRIVERINIT))
6024 return -EOPNOTSUPP;
6025
6026 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6027 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
6028 else
6029 param_item->driverinit_value = init_val;
6030 param_item->driverinit_value_valid = true;
6031
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306032 devlink_param_notify(devlink, port_index, param_item, cmd);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306033 return 0;
6034}
6035
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306036/**
6037 * devlink_param_driverinit_value_get - get configuration parameter
6038 * value for driver initializing
6039 *
6040 * @devlink: devlink
6041 * @param_id: parameter ID
6042 * @init_val: value of parameter in driverinit configuration mode
6043 *
6044 * This function should be used by the driver to get driverinit
6045 * configuration for initialization after reload command.
6046 */
6047int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
6048 union devlink_param_value *init_val)
6049{
6050 if (!devlink->ops || !devlink->ops->reload)
6051 return -EOPNOTSUPP;
6052
6053 return __devlink_param_driverinit_value_get(&devlink->param_list,
6054 param_id, init_val);
6055}
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006056EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
6057
6058/**
6059 * devlink_param_driverinit_value_set - set value of configuration
6060 * parameter for driverinit
6061 * configuration mode
6062 *
6063 * @devlink: devlink
6064 * @param_id: parameter ID
6065 * @init_val: value of parameter to set for driverinit configuration mode
6066 *
6067 * This function should be used by the driver to set driverinit
6068 * configuration mode default value.
6069 */
6070int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
6071 union devlink_param_value init_val)
6072{
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306073 return __devlink_param_driverinit_value_set(devlink, 0,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306074 &devlink->param_list,
6075 param_id, init_val,
6076 DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshec01aeb2018-07-04 14:30:31 +03006077}
6078EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
6079
Moshe Shemeshea601e12018-07-04 14:30:32 +03006080/**
Vasundhara Volamffd19b92019-01-28 18:00:23 +05306081 * devlink_port_param_driverinit_value_get - get configuration parameter
6082 * value for driver initializing
6083 *
6084 * @devlink_port: devlink_port
6085 * @param_id: parameter ID
6086 * @init_val: value of parameter in driverinit configuration mode
6087 *
6088 * This function should be used by the driver to get driverinit
6089 * configuration for initialization after reload command.
6090 */
6091int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
6092 u32 param_id,
6093 union devlink_param_value *init_val)
6094{
6095 struct devlink *devlink = devlink_port->devlink;
6096
6097 if (!devlink->ops || !devlink->ops->reload)
6098 return -EOPNOTSUPP;
6099
6100 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
6101 param_id, init_val);
6102}
6103EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
6104
6105/**
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306106 * devlink_port_param_driverinit_value_set - set value of configuration
6107 * parameter for driverinit
6108 * configuration mode
6109 *
6110 * @devlink_port: devlink_port
6111 * @param_id: parameter ID
6112 * @init_val: value of parameter to set for driverinit configuration mode
6113 *
6114 * This function should be used by the driver to set driverinit
6115 * configuration mode default value.
6116 */
6117int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
6118 u32 param_id,
6119 union devlink_param_value init_val)
6120{
6121 return __devlink_param_driverinit_value_set(devlink_port->devlink,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306122 devlink_port->index,
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306123 &devlink_port->param_list,
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306124 param_id, init_val,
6125 DEVLINK_CMD_PORT_PARAM_NEW);
Vasundhara Volam5473a7b2019-01-28 18:00:24 +05306126}
6127EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
6128
6129/**
Moshe Shemeshea601e12018-07-04 14:30:32 +03006130 * devlink_param_value_changed - notify devlink on a parameter's value
6131 * change. Should be called by the driver
6132 * right after the change.
6133 *
6134 * @devlink: devlink
6135 * @param_id: parameter ID
6136 *
6137 * This function should be used by the driver to notify devlink on value
6138 * change, excluding driverinit configuration mode.
6139 * For driverinit configuration mode driver should use the function
Moshe Shemeshea601e12018-07-04 14:30:32 +03006140 */
6141void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
6142{
6143 struct devlink_param_item *param_item;
6144
6145 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
6146 WARN_ON(!param_item);
6147
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306148 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
Moshe Shemeshea601e12018-07-04 14:30:32 +03006149}
6150EXPORT_SYMBOL_GPL(devlink_param_value_changed);
6151
Alex Veskerb16ebe92018-07-12 15:13:08 +03006152/**
Vasundhara Volamc1e5786d2019-01-28 18:00:25 +05306153 * devlink_port_param_value_changed - notify devlink on a parameter's value
6154 * change. Should be called by the driver
6155 * right after the change.
6156 *
6157 * @devlink_port: devlink_port
6158 * @param_id: parameter ID
6159 *
6160 * This function should be used by the driver to notify devlink on value
6161 * change, excluding driverinit configuration mode.
6162 * For driverinit configuration mode driver should use the function
6163 * devlink_port_param_driverinit_value_set() instead.
6164 */
6165void devlink_port_param_value_changed(struct devlink_port *devlink_port,
6166 u32 param_id)
6167{
6168 struct devlink_param_item *param_item;
6169
6170 param_item = devlink_param_find_by_id(&devlink_port->param_list,
6171 param_id);
6172 WARN_ON(!param_item);
6173
6174 devlink_param_notify(devlink_port->devlink, devlink_port->index,
6175 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
6176}
6177EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
6178
6179/**
Moshe Shemeshbde74ad12018-10-10 16:09:27 +03006180 * devlink_param_value_str_fill - Safely fill-up the string preventing
6181 * from overflow of the preallocated buffer
6182 *
6183 * @dst_val: destination devlink_param_value
6184 * @src: source buffer
6185 */
6186void devlink_param_value_str_fill(union devlink_param_value *dst_val,
6187 const char *src)
6188{
6189 size_t len;
6190
6191 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
6192 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
6193}
6194EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
6195
6196/**
Alex Veskerb16ebe92018-07-12 15:13:08 +03006197 * devlink_region_create - create a new address region
6198 *
6199 * @devlink: devlink
6200 * @region_name: region name
6201 * @region_max_snapshots: Maximum supported number of snapshots for region
6202 * @region_size: size of region
6203 */
6204struct devlink_region *devlink_region_create(struct devlink *devlink,
6205 const char *region_name,
6206 u32 region_max_snapshots,
6207 u64 region_size)
6208{
6209 struct devlink_region *region;
6210 int err = 0;
6211
6212 mutex_lock(&devlink->lock);
6213
6214 if (devlink_region_get_by_name(devlink, region_name)) {
6215 err = -EEXIST;
6216 goto unlock;
6217 }
6218
6219 region = kzalloc(sizeof(*region), GFP_KERNEL);
6220 if (!region) {
6221 err = -ENOMEM;
6222 goto unlock;
6223 }
6224
6225 region->devlink = devlink;
6226 region->max_snapshots = region_max_snapshots;
6227 region->name = region_name;
6228 region->size = region_size;
6229 INIT_LIST_HEAD(&region->snapshot_list);
6230 list_add_tail(&region->list, &devlink->region_list);
Alex Vesker866319b2018-07-12 15:13:13 +03006231 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
Alex Veskerb16ebe92018-07-12 15:13:08 +03006232
6233 mutex_unlock(&devlink->lock);
6234 return region;
6235
6236unlock:
6237 mutex_unlock(&devlink->lock);
6238 return ERR_PTR(err);
6239}
6240EXPORT_SYMBOL_GPL(devlink_region_create);
6241
6242/**
6243 * devlink_region_destroy - destroy address region
6244 *
6245 * @region: devlink region to destroy
6246 */
6247void devlink_region_destroy(struct devlink_region *region)
6248{
6249 struct devlink *devlink = region->devlink;
Alex Veskerd7e52722018-07-12 15:13:10 +03006250 struct devlink_snapshot *snapshot, *ts;
Alex Veskerb16ebe92018-07-12 15:13:08 +03006251
6252 mutex_lock(&devlink->lock);
Alex Veskerd7e52722018-07-12 15:13:10 +03006253
6254 /* Free all snapshots of region */
6255 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
6256 devlink_region_snapshot_del(snapshot);
6257
Alex Veskerb16ebe92018-07-12 15:13:08 +03006258 list_del(&region->list);
Alex Vesker866319b2018-07-12 15:13:13 +03006259
6260 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
Alex Veskerb16ebe92018-07-12 15:13:08 +03006261 mutex_unlock(&devlink->lock);
6262 kfree(region);
6263}
6264EXPORT_SYMBOL_GPL(devlink_region_destroy);
6265
Alex Veskerccadfa42018-07-12 15:13:09 +03006266/**
6267 * devlink_region_shapshot_id_get - get snapshot ID
6268 *
6269 * This callback should be called when adding a new snapshot,
6270 * Driver should use the same id for multiple snapshots taken
6271 * on multiple regions at the same time/by the same trigger.
6272 *
6273 * @devlink: devlink
6274 */
6275u32 devlink_region_shapshot_id_get(struct devlink *devlink)
6276{
6277 u32 id;
6278
6279 mutex_lock(&devlink->lock);
6280 id = ++devlink->snapshot_id;
6281 mutex_unlock(&devlink->lock);
6282
6283 return id;
6284}
6285EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
6286
Alex Veskerd7e52722018-07-12 15:13:10 +03006287/**
6288 * devlink_region_snapshot_create - create a new snapshot
6289 * This will add a new snapshot of a region. The snapshot
6290 * will be stored on the region struct and can be accessed
6291 * from devlink. This is useful for future analyses of snapshots.
6292 * Multiple snapshots can be created on a region.
6293 * The @snapshot_id should be obtained using the getter function.
6294 *
6295 * @devlink_region: devlink region of the snapshot
6296 * @data_len: size of snapshot data
6297 * @data: snapshot data
6298 * @snapshot_id: snapshot id to be created
6299 * @data_destructor: pointer to destructor function to free data
6300 */
6301int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
6302 u8 *data, u32 snapshot_id,
6303 devlink_snapshot_data_dest_t *data_destructor)
6304{
6305 struct devlink *devlink = region->devlink;
6306 struct devlink_snapshot *snapshot;
6307 int err;
6308
6309 mutex_lock(&devlink->lock);
6310
6311 /* check if region can hold one more snapshot */
6312 if (region->cur_snapshots == region->max_snapshots) {
6313 err = -ENOMEM;
6314 goto unlock;
6315 }
6316
6317 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
6318 err = -EEXIST;
6319 goto unlock;
6320 }
6321
6322 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
6323 if (!snapshot) {
6324 err = -ENOMEM;
6325 goto unlock;
6326 }
6327
6328 snapshot->id = snapshot_id;
6329 snapshot->region = region;
6330 snapshot->data = data;
6331 snapshot->data_len = data_len;
6332 snapshot->data_destructor = data_destructor;
6333
6334 list_add_tail(&snapshot->list, &region->snapshot_list);
6335
6336 region->cur_snapshots++;
6337
Alex Vesker866319b2018-07-12 15:13:13 +03006338 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
Alex Veskerd7e52722018-07-12 15:13:10 +03006339 mutex_unlock(&devlink->lock);
6340 return 0;
6341
6342unlock:
6343 mutex_unlock(&devlink->lock);
6344 return err;
6345}
6346EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
6347
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006348static void __devlink_compat_running_version(struct devlink *devlink,
6349 char *buf, size_t len)
6350{
6351 const struct nlattr *nlattr;
6352 struct devlink_info_req req;
6353 struct sk_buff *msg;
6354 int rem, err;
6355
6356 if (!devlink->ops->info_get)
6357 return;
6358
6359 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6360 if (!msg)
6361 return;
6362
6363 req.msg = msg;
6364 err = devlink->ops->info_get(devlink, &req, NULL);
6365 if (err)
6366 goto free_msg;
6367
6368 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
6369 const struct nlattr *kv;
6370 int rem_kv;
6371
6372 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
6373 continue;
6374
6375 nla_for_each_nested(kv, nlattr, rem_kv) {
6376 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
6377 continue;
6378
6379 strlcat(buf, nla_data(kv), len);
6380 strlcat(buf, " ", len);
6381 }
6382 }
6383free_msg:
6384 nlmsg_free(msg);
6385}
6386
6387void devlink_compat_running_version(struct net_device *dev,
6388 char *buf, size_t len)
6389{
6390 struct devlink_port *devlink_port;
6391 struct devlink *devlink;
6392
6393 mutex_lock(&devlink_mutex);
6394 list_for_each_entry(devlink, &devlink_list, list) {
6395 mutex_lock(&devlink->lock);
6396 list_for_each_entry(devlink_port, &devlink->port_list, list) {
Jakub Kicinski3ceb7452019-02-10 19:35:27 -08006397 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH &&
Jakub Kicinskiddb6e992019-01-31 10:50:47 -08006398 devlink_port->type_dev == dev) {
6399 __devlink_compat_running_version(devlink,
6400 buf, len);
6401 mutex_unlock(&devlink->lock);
6402 goto out;
6403 }
6404 }
6405 mutex_unlock(&devlink->lock);
6406 }
6407out:
6408 mutex_unlock(&devlink_mutex);
6409}
6410
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006411static int __init devlink_module_init(void)
6412{
Johannes Berg489111e2016-10-24 14:40:03 +02006413 return genl_register_family(&devlink_nl_family);
Jiri Pirkobfcd3a42016-02-26 17:32:23 +01006414}
6415
6416static void __exit devlink_module_exit(void)
6417{
6418 genl_unregister_family(&devlink_nl_family);
6419}
6420
6421module_init(devlink_module_init);
6422module_exit(devlink_module_exit);
6423
6424MODULE_LICENSE("GPL v2");
6425MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
6426MODULE_DESCRIPTION("Network physical device Netlink interface");
6427MODULE_ALIAS_GENL_FAMILY(DEVLINK_GENL_NAME);