Merge branch 'devlink-use-spec-to-generate-split-ops'

Jiri Pirko says:

====================
devlink: use spec to generate split ops

This is an outcome of the discussion in the following thread:
https://lore.kernel.org/netdev/20230720121829.566974-1-jiri@resnulli.us/
It serves as a dependency on the linked selector patchset.

There is an existing spec for devlink used for userspace part
generation. There are two commands supported there.

This patchset extends the spec so kernel split ops code could
be generated from it.
====================

Link: https://lore.kernel.org/r/20230803111340.1074067-1-jiri@resnulli.us
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2023-08-04 14:03:03 -07:00
commit eef9630de0
14 changed files with 230 additions and 60 deletions

View File

@ -274,7 +274,7 @@ properties:
description: Kernel attribute validation flags.
type: array
items:
enum: [ strict, dump ]
enum: [ strict, dump, dump-strict ]
do: &subop-type
description: Main command handler.
type: object

View File

@ -321,7 +321,7 @@ properties:
description: Kernel attribute validation flags.
type: array
items:
enum: [ strict, dump ]
enum: [ strict, dump, dump-strict ]
# Start genetlink-legacy
fixed-header: *fixed-header
# End genetlink-legacy

View File

@ -243,7 +243,7 @@ properties:
description: Kernel attribute validation flags.
type: array
items:
enum: [ strict, dump ]
enum: [ strict, dump, dump-strict ]
do: &subop-type
description: Main command handler.
type: object

View File

@ -165,8 +165,13 @@ operations:
name: get
doc: Get devlink instances.
attribute-set: devlink
dont-validate:
- strict
- dump
do:
pre: devlink-nl-pre-doit
post: devlink-nl-post-doit
request:
value: 1
attributes: &dev-id-attrs
@ -189,12 +194,17 @@ operations:
name: info-get
doc: Get device information, like driver name, hardware and firmware versions etc.
attribute-set: devlink
dont-validate:
- strict
- dump
do:
pre: devlink-nl-pre-doit
post: devlink-nl-post-doit
request:
value: 51
attributes: *dev-id-attrs
reply:
reply: &info-get-reply
value: 51
attributes:
- bus-name
@ -204,3 +214,5 @@ operations:
- info-version-fixed
- info-version-running
- info-version-stored
dump:
reply: *info-get-reply

View File

@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-y := leftover.o core.o netlink.o dev.o health.o
obj-y := leftover.o core.o netlink.o netlink_gen.o dev.o health.o

View File

@ -196,7 +196,7 @@ void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
}
int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
int devlink_nl_get_doit(struct sk_buff *skb, struct genl_info *info)
{
struct devlink *devlink = info->user_ptr[0];
struct sk_buff *msg;
@ -217,17 +217,18 @@ int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
}
static int
devlink_nl_cmd_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
struct netlink_callback *cb)
devlink_nl_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
struct netlink_callback *cb)
{
return devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI);
}
const struct devlink_cmd devl_cmd_get = {
.dump_one = devlink_nl_cmd_get_dump_one,
};
int devlink_nl_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb)
{
return devlink_nl_dumpit(msg, cb, devlink_nl_get_dump_one);
}
static void devlink_reload_failed_set(struct devlink *devlink,
bool reload_failed)
@ -804,7 +805,7 @@ err_cancel_msg:
return err;
}
int devlink_nl_cmd_info_get_doit(struct sk_buff *skb, struct genl_info *info)
int devlink_nl_info_get_doit(struct sk_buff *skb, struct genl_info *info)
{
struct devlink *devlink = info->user_ptr[0];
struct sk_buff *msg;
@ -826,8 +827,8 @@ int devlink_nl_cmd_info_get_doit(struct sk_buff *skb, struct genl_info *info)
}
static int
devlink_nl_cmd_info_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
struct netlink_callback *cb)
devlink_nl_info_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
struct netlink_callback *cb)
{
int err;
@ -840,9 +841,10 @@ devlink_nl_cmd_info_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
return err;
}
const struct devlink_cmd devl_cmd_info_get = {
.dump_one = devlink_nl_cmd_info_get_dump_one,
};
int devlink_nl_info_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb)
{
return devlink_nl_dumpit(msg, cb, devlink_nl_info_get_dump_one);
}
static int devlink_nl_flash_update_fill(struct sk_buff *msg,
struct devlink *devlink,

View File

@ -12,6 +12,8 @@
#include <net/devlink.h>
#include <net/net_namespace.h>
#include "netlink_gen.h"
#define DEVLINK_REGISTERED XA_MARK_1
#define DEVLINK_RELOAD_STATS_ARRAY_SIZE \
@ -114,12 +116,15 @@ struct devlink_nl_dump_state {
};
};
typedef int devlink_nl_dump_one_func_t(struct sk_buff *msg,
struct devlink *devlink,
struct netlink_callback *cb);
struct devlink_cmd {
int (*dump_one)(struct sk_buff *msg, struct devlink *devlink,
struct netlink_callback *cb);
devlink_nl_dump_one_func_t *dump_one;
};
extern const struct genl_small_ops devlink_nl_ops[56];
extern const struct genl_small_ops devlink_nl_small_ops[54];
struct devlink *
devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs);
@ -127,8 +132,9 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs);
void devlink_notify_unregister(struct devlink *devlink);
void devlink_notify_register(struct devlink *devlink);
int devlink_nl_instance_iter_dumpit(struct sk_buff *msg,
struct netlink_callback *cb);
int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
devlink_nl_dump_one_func_t *dump_one);
int devlink_nl_instance_iter_dumpit(struct sk_buff *msg, struct netlink_callback *cb);
static inline struct devlink_nl_dump_state *
devlink_dump_state(struct netlink_callback *cb)
@ -149,7 +155,6 @@ devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
}
/* Commands */
extern const struct devlink_cmd devl_cmd_get;
extern const struct devlink_cmd devl_cmd_port_get;
extern const struct devlink_cmd devl_cmd_sb_get;
extern const struct devlink_cmd devl_cmd_sb_pool_get;
@ -157,7 +162,6 @@ extern const struct devlink_cmd devl_cmd_sb_port_pool_get;
extern const struct devlink_cmd devl_cmd_sb_tc_pool_bind_get;
extern const struct devlink_cmd devl_cmd_param_get;
extern const struct devlink_cmd devl_cmd_region_get;
extern const struct devlink_cmd devl_cmd_info_get;
extern const struct devlink_cmd devl_cmd_health_reporter_get;
extern const struct devlink_cmd devl_cmd_trap_get;
extern const struct devlink_cmd devl_cmd_trap_group_get;
@ -214,11 +218,9 @@ struct devlink_rate *
devlink_rate_node_get_from_info(struct devlink *devlink,
struct genl_info *info);
/* Devlink nl cmds */
int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_info_get_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_flash_update(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_selftests_get_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_selftests_run(struct sk_buff *skb, struct genl_info *info);

View File

@ -6278,14 +6278,7 @@ static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
return devlink_trap_policer_set(devlink, policer_item, info);
}
const struct genl_small_ops devlink_nl_ops[56] = {
{
.cmd = DEVLINK_CMD_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_get_doit,
.dumpit = devlink_nl_instance_iter_dumpit,
/* can be retrieved by unprivileged users */
},
const struct genl_small_ops devlink_nl_small_ops[54] = {
{
.cmd = DEVLINK_CMD_PORT_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@ -6533,13 +6526,6 @@ const struct genl_small_ops devlink_nl_ops[56] = {
.dumpit = devlink_nl_cmd_region_read_dumpit,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = DEVLINK_CMD_INFO_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_info_get_doit,
.dumpit = devlink_nl_instance_iter_dumpit,
/* can be retrieved by unprivileged users */
},
{
.cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,

View File

@ -109,8 +109,8 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs)
return ERR_PTR(-ENODEV);
}
static int devlink_nl_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
int devlink_nl_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
struct devlink_linecard *linecard;
struct devlink_port *devlink_port;
@ -167,8 +167,8 @@ unlock:
return err;
}
static void devlink_nl_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
void devlink_nl_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
struct devlink *devlink;
@ -178,7 +178,6 @@ static void devlink_nl_post_doit(const struct genl_split_ops *ops,
}
static const struct devlink_cmd *devl_cmds[] = {
[DEVLINK_CMD_GET] = &devl_cmd_get,
[DEVLINK_CMD_PORT_GET] = &devl_cmd_port_get,
[DEVLINK_CMD_SB_GET] = &devl_cmd_sb_get,
[DEVLINK_CMD_SB_POOL_GET] = &devl_cmd_sb_pool_get,
@ -186,7 +185,6 @@ static const struct devlink_cmd *devl_cmds[] = {
[DEVLINK_CMD_SB_TC_POOL_BIND_GET] = &devl_cmd_sb_tc_pool_bind_get,
[DEVLINK_CMD_PARAM_GET] = &devl_cmd_param_get,
[DEVLINK_CMD_REGION_GET] = &devl_cmd_region_get,
[DEVLINK_CMD_INFO_GET] = &devl_cmd_info_get,
[DEVLINK_CMD_HEALTH_REPORTER_GET] = &devl_cmd_health_reporter_get,
[DEVLINK_CMD_TRAP_GET] = &devl_cmd_trap_get,
[DEVLINK_CMD_TRAP_GROUP_GET] = &devl_cmd_trap_group_get,
@ -196,23 +194,19 @@ static const struct devlink_cmd *devl_cmds[] = {
[DEVLINK_CMD_SELFTESTS_GET] = &devl_cmd_selftests_get,
};
int devlink_nl_instance_iter_dumpit(struct sk_buff *msg,
struct netlink_callback *cb)
int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
devlink_nl_dump_one_func_t *dump_one)
{
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
const struct devlink_cmd *cmd;
struct devlink *devlink;
int err = 0;
cmd = devl_cmds[info->op.cmd];
while ((devlink = devlinks_xa_find_get(sock_net(msg->sk),
&state->instance))) {
devl_lock(devlink);
if (devl_is_registered(devlink))
err = cmd->dump_one(msg, devlink, cb);
err = dump_one(msg, devlink, cb);
else
err = 0;
@ -233,6 +227,15 @@ int devlink_nl_instance_iter_dumpit(struct sk_buff *msg,
return msg->len;
}
int devlink_nl_instance_iter_dumpit(struct sk_buff *msg,
struct netlink_callback *cb)
{
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
const struct devlink_cmd *cmd = devl_cmds[info->op.cmd];
return devlink_nl_dumpit(msg, cb, cmd->dump_one);
}
struct genl_family devlink_nl_family __ro_after_init = {
.name = DEVLINK_GENL_NAME,
.version = DEVLINK_GENL_VERSION,
@ -243,8 +246,10 @@ struct genl_family devlink_nl_family __ro_after_init = {
.pre_doit = devlink_nl_pre_doit,
.post_doit = devlink_nl_post_doit,
.module = THIS_MODULE,
.small_ops = devlink_nl_ops,
.n_small_ops = ARRAY_SIZE(devlink_nl_ops),
.small_ops = devlink_nl_small_ops,
.n_small_ops = ARRAY_SIZE(devlink_nl_small_ops),
.split_ops = devlink_nl_ops,
.n_split_ops = ARRAY_SIZE(devlink_nl_ops),
.resv_start_op = DEVLINK_CMD_SELFTESTS_RUN + 1,
.mcgrps = devlink_nl_mcgrps,
.n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),

59
net/devlink/netlink_gen.c Normal file
View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
/* Do not edit directly, auto-generated from: */
/* Documentation/netlink/specs/devlink.yaml */
/* YNL-GEN kernel source */
#include <net/netlink.h>
#include <net/genetlink.h>
#include "netlink_gen.h"
#include <uapi/linux/devlink.h>
/* DEVLINK_CMD_GET - do */
static const struct nla_policy devlink_get_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = {
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
};
/* DEVLINK_CMD_INFO_GET - do */
static const struct nla_policy devlink_info_get_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = {
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
};
/* Ops table for devlink */
const struct genl_split_ops devlink_nl_ops[4] = {
{
.cmd = DEVLINK_CMD_GET,
.validate = GENL_DONT_VALIDATE_STRICT,
.pre_doit = devlink_nl_pre_doit,
.doit = devlink_nl_get_doit,
.post_doit = devlink_nl_post_doit,
.policy = devlink_get_nl_policy,
.maxattr = DEVLINK_ATTR_DEV_NAME,
.flags = GENL_CMD_CAP_DO,
},
{
.cmd = DEVLINK_CMD_GET,
.validate = GENL_DONT_VALIDATE_DUMP,
.dumpit = devlink_nl_get_dumpit,
.flags = GENL_CMD_CAP_DUMP,
},
{
.cmd = DEVLINK_CMD_INFO_GET,
.validate = GENL_DONT_VALIDATE_STRICT,
.pre_doit = devlink_nl_pre_doit,
.doit = devlink_nl_info_get_doit,
.post_doit = devlink_nl_post_doit,
.policy = devlink_info_get_nl_policy,
.maxattr = DEVLINK_ATTR_DEV_NAME,
.flags = GENL_CMD_CAP_DO,
},
{
.cmd = DEVLINK_CMD_INFO_GET,
.validate = GENL_DONT_VALIDATE_DUMP,
.dumpit = devlink_nl_info_get_dumpit,
.flags = GENL_CMD_CAP_DUMP,
},
};

29
net/devlink/netlink_gen.h Normal file
View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* Do not edit directly, auto-generated from: */
/* Documentation/netlink/specs/devlink.yaml */
/* YNL-GEN kernel header */
#ifndef _LINUX_DEVLINK_GEN_H
#define _LINUX_DEVLINK_GEN_H
#include <net/netlink.h>
#include <net/genetlink.h>
#include <uapi/linux/devlink.h>
/* Ops table for devlink */
extern const struct genl_split_ops devlink_nl_ops[4];
int devlink_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info);
void
devlink_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info);
int devlink_nl_get_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
int devlink_nl_info_get_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_info_get_dumpit(struct sk_buff *skb,
struct netlink_callback *cb);
#endif /* _LINUX_DEVLINK_GEN_H */

View File

@ -716,6 +716,59 @@ err_free:
return NULL;
}
/* DEVLINK_CMD_INFO_GET - dump */
void devlink_info_get_list_free(struct devlink_info_get_list *rsp)
{
struct devlink_info_get_list *next = rsp;
while ((void *)next != YNL_LIST_END) {
unsigned int i;
rsp = next;
next = rsp->next;
free(rsp->obj.bus_name);
free(rsp->obj.dev_name);
free(rsp->obj.info_driver_name);
free(rsp->obj.info_serial_number);
for (i = 0; i < rsp->obj.n_info_version_fixed; i++)
devlink_dl_info_version_free(&rsp->obj.info_version_fixed[i]);
free(rsp->obj.info_version_fixed);
for (i = 0; i < rsp->obj.n_info_version_running; i++)
devlink_dl_info_version_free(&rsp->obj.info_version_running[i]);
free(rsp->obj.info_version_running);
for (i = 0; i < rsp->obj.n_info_version_stored; i++)
devlink_dl_info_version_free(&rsp->obj.info_version_stored[i]);
free(rsp->obj.info_version_stored);
free(rsp);
}
}
struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys)
{
struct ynl_dump_state yds = {};
struct nlmsghdr *nlh;
int err;
yds.ys = ys;
yds.alloc_sz = sizeof(struct devlink_info_get_list);
yds.cb = devlink_info_get_rsp_parse;
yds.rsp_cmd = DEVLINK_CMD_INFO_GET;
yds.rsp_policy = &devlink_nest;
nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_INFO_GET, 1);
err = ynl_exec_dump(ys, nlh, &yds);
if (err < 0)
goto free_list;
return yds.first;
free_list:
devlink_info_get_list_free(yds.first);
return NULL;
}
const struct ynl_family ynl_devlink_family = {
.name = "devlink",
};

View File

@ -207,4 +207,14 @@ void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp);
struct devlink_info_get_rsp *
devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req);
/* DEVLINK_CMD_INFO_GET - dump */
struct devlink_info_get_list {
struct devlink_info_get_list *next;
struct devlink_info_get_rsp obj __attribute__ ((aligned (8)));
};
void devlink_info_get_list_free(struct devlink_info_get_list *rsp);
struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys);
#endif /* _LINUX_DEVLINK_GEN_H */

View File

@ -1843,13 +1843,13 @@ def print_ntf_type_free(ri):
def print_req_policy_fwd(cw, struct, ri=None, terminate=True):
if terminate and ri and kernel_can_gen_family_struct(struct.family):
if terminate and ri and policy_should_be_static(struct.family):
return
if terminate:
prefix = 'extern '
else:
if kernel_can_gen_family_struct(struct.family) and ri:
if ri and policy_should_be_static(struct.family):
prefix = 'static '
else:
prefix = ''
@ -1877,6 +1877,10 @@ def kernel_can_gen_family_struct(family):
return family.proto == 'genetlink'
def policy_should_be_static(family):
return family.kernel_policy == 'split' or kernel_can_gen_family_struct(family)
def print_kernel_op_table_fwd(family, cw, terminate):
exported = not kernel_can_gen_family_struct(family)
@ -1988,9 +1992,17 @@ def print_kernel_op_table(family, cw):
cw.block_start()
members = [('cmd', op.enum_name)]
if 'dont-validate' in op:
dont_validate = []
for x in op['dont-validate']:
if op_mode == 'do' and x in ['dump', 'dump-strict']:
continue
if op_mode == "dump" and x == 'strict':
continue
dont_validate.append(x)
members.append(('validate',
' | '.join([c_upper('genl-dont-validate-' + x)
for x in op['dont-validate']])), )
for x in dont_validate])), )
name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it")
if 'pre' in op[op_mode]:
members.append((cb_names[op_mode]['pre'], c_lower(op[op_mode]['pre'])))
@ -2309,7 +2321,7 @@ def main():
return
supported_models = ['unified']
if args.mode == 'user':
if args.mode in ['user', 'kernel']:
supported_models += ['directional']
if parsed.msg_id_model not in supported_models:
print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation')