Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+230 -60
+1 -1
Documentation/netlink/genetlink.yaml
··· 243 243 description: Kernel attribute validation flags. 244 244 type: array 245 245 items: 246 - enum: [ strict, dump ] 246 + enum: [ strict, dump, dump-strict ] 247 247 do: &subop-type 248 248 description: Main command handler. 249 249 type: object
+13 -1
Documentation/netlink/specs/devlink.yaml
··· 165 165 name: get 166 166 doc: Get devlink instances. 167 167 attribute-set: devlink 168 + dont-validate: 169 + - strict 170 + - dump 168 171 169 172 do: 173 + pre: devlink-nl-pre-doit 174 + post: devlink-nl-post-doit 170 175 request: 171 176 value: 1 172 177 attributes: &dev-id-attrs ··· 194 189 name: info-get 195 190 doc: Get device information, like driver name, hardware and firmware versions etc. 196 191 attribute-set: devlink 192 + dont-validate: 193 + - strict 194 + - dump 197 195 198 196 do: 197 + pre: devlink-nl-pre-doit 198 + post: devlink-nl-post-doit 199 199 request: 200 200 value: 51 201 201 attributes: *dev-id-attrs 202 - reply: 202 + reply: &info-get-reply 203 203 value: 51 204 204 attributes: 205 205 - bus-name ··· 214 204 - info-version-fixed 215 205 - info-version-running 216 206 - info-version-stored 207 + dump: 208 + reply: *info-get-reply
+1 -1
net/devlink/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 - obj-y := leftover.o core.o netlink.o dev.o health.o 3 + obj-y := leftover.o core.o netlink.o netlink_gen.o dev.o health.o
+14 -12
net/devlink/dev.c
··· 196 196 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 197 197 } 198 198 199 - int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info) 199 + int devlink_nl_get_doit(struct sk_buff *skb, struct genl_info *info) 200 200 { 201 201 struct devlink *devlink = info->user_ptr[0]; 202 202 struct sk_buff *msg; ··· 217 217 } 218 218 219 219 static int 220 - devlink_nl_cmd_get_dump_one(struct sk_buff *msg, struct devlink *devlink, 221 - struct netlink_callback *cb) 220 + devlink_nl_get_dump_one(struct sk_buff *msg, struct devlink *devlink, 221 + struct netlink_callback *cb) 222 222 { 223 223 return devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW, 224 224 NETLINK_CB(cb->skb).portid, 225 225 cb->nlh->nlmsg_seq, NLM_F_MULTI); 226 226 } 227 227 228 - const struct devlink_cmd devl_cmd_get = { 229 - .dump_one = devlink_nl_cmd_get_dump_one, 230 - }; 228 + int devlink_nl_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb) 229 + { 230 + return devlink_nl_dumpit(msg, cb, devlink_nl_get_dump_one); 231 + } 231 232 232 233 static void devlink_reload_failed_set(struct devlink *devlink, 233 234 bool reload_failed) ··· 805 804 return err; 806 805 } 807 806 808 - int devlink_nl_cmd_info_get_doit(struct sk_buff *skb, struct genl_info *info) 807 + int devlink_nl_info_get_doit(struct sk_buff *skb, struct genl_info *info) 809 808 { 810 809 struct devlink *devlink = info->user_ptr[0]; 811 810 struct sk_buff *msg; ··· 827 826 } 828 827 829 828 static int 830 - devlink_nl_cmd_info_get_dump_one(struct sk_buff *msg, struct devlink *devlink, 831 - struct netlink_callback *cb) 829 + devlink_nl_info_get_dump_one(struct sk_buff *msg, struct devlink *devlink, 830 + struct netlink_callback *cb) 832 831 { 833 832 int err; 834 833 ··· 841 840 return err; 842 841 } 843 842 844 - const struct devlink_cmd devl_cmd_info_get = { 845 - .dump_one = devlink_nl_cmd_info_get_dump_one, 846 - }; 843 + int devlink_nl_info_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb) 844 + { 845 + return devlink_nl_dumpit(msg, cb, devlink_nl_info_get_dump_one); 846 + } 847 847 848 848 static int devlink_nl_flash_update_fill(struct sk_buff *msg, 849 849 struct devlink *devlink,
+11 -9
net/devlink/devl_internal.h
··· 12 12 #include <net/devlink.h> 13 13 #include <net/net_namespace.h> 14 14 15 + #include "netlink_gen.h" 16 + 15 17 #define DEVLINK_REGISTERED XA_MARK_1 16 18 17 19 #define DEVLINK_RELOAD_STATS_ARRAY_SIZE \ ··· 116 114 }; 117 115 }; 118 116 117 + typedef int devlink_nl_dump_one_func_t(struct sk_buff *msg, 118 + struct devlink *devlink, 119 + struct netlink_callback *cb); 120 + 119 121 struct devlink_cmd { 120 - int (*dump_one)(struct sk_buff *msg, struct devlink *devlink, 121 - struct netlink_callback *cb); 122 + devlink_nl_dump_one_func_t *dump_one; 122 123 }; 123 124 124 - extern const struct genl_small_ops devlink_nl_ops[56]; 125 + extern const struct genl_small_ops devlink_nl_small_ops[54]; 125 126 126 127 struct devlink * 127 128 devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs); ··· 132 127 void devlink_notify_unregister(struct devlink *devlink); 133 128 void devlink_notify_register(struct devlink *devlink); 134 129 135 - int devlink_nl_instance_iter_dumpit(struct sk_buff *msg, 136 - struct netlink_callback *cb); 130 + int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb, 131 + devlink_nl_dump_one_func_t *dump_one); 132 + int devlink_nl_instance_iter_dumpit(struct sk_buff *msg, struct netlink_callback *cb); 137 133 138 134 static inline struct devlink_nl_dump_state * 139 135 devlink_dump_state(struct netlink_callback *cb) ··· 155 149 } 156 150 157 151 /* Commands */ 158 - extern const struct devlink_cmd devl_cmd_get; 159 152 extern const struct devlink_cmd devl_cmd_port_get; 160 153 extern const struct devlink_cmd devl_cmd_sb_get; 161 154 extern const struct devlink_cmd devl_cmd_sb_pool_get; ··· 162 157 extern const struct devlink_cmd devl_cmd_sb_tc_pool_bind_get; 163 158 extern const struct devlink_cmd devl_cmd_param_get; 164 159 extern const struct devlink_cmd devl_cmd_region_get; 165 - extern const struct devlink_cmd devl_cmd_info_get; 166 160 extern const struct devlink_cmd devl_cmd_health_reporter_get; 167 161 extern const struct devlink_cmd devl_cmd_trap_get; 168 162 extern const struct devlink_cmd devl_cmd_trap_group_get; ··· 218 214 devlink_rate_node_get_from_info(struct devlink *devlink, 219 215 struct genl_info *info); 220 216 /* Devlink nl cmds */ 221 - int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info); 222 217 int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info); 223 218 int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info); 224 219 int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info); 225 - int devlink_nl_cmd_info_get_doit(struct sk_buff *skb, struct genl_info *info); 226 220 int devlink_nl_cmd_flash_update(struct sk_buff *skb, struct genl_info *info); 227 221 int devlink_nl_cmd_selftests_get_doit(struct sk_buff *skb, struct genl_info *info); 228 222 int devlink_nl_cmd_selftests_run(struct sk_buff *skb, struct genl_info *info);
+1 -15
net/devlink/leftover.c
··· 6278 6278 return devlink_trap_policer_set(devlink, policer_item, info); 6279 6279 } 6280 6280 6281 - const struct genl_small_ops devlink_nl_ops[56] = { 6282 - { 6283 - .cmd = DEVLINK_CMD_GET, 6284 - .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6285 - .doit = devlink_nl_cmd_get_doit, 6286 - .dumpit = devlink_nl_instance_iter_dumpit, 6287 - /* can be retrieved by unprivileged users */ 6288 - }, 6281 + const struct genl_small_ops devlink_nl_small_ops[54] = { 6289 6282 { 6290 6283 .cmd = DEVLINK_CMD_PORT_GET, 6291 6284 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ··· 6525 6532 GENL_DONT_VALIDATE_DUMP_STRICT, 6526 6533 .dumpit = devlink_nl_cmd_region_read_dumpit, 6527 6534 .flags = GENL_ADMIN_PERM, 6528 - }, 6529 - { 6530 - .cmd = DEVLINK_CMD_INFO_GET, 6531 - .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6532 - .doit = devlink_nl_cmd_info_get_doit, 6533 - .dumpit = devlink_nl_instance_iter_dumpit, 6534 - /* can be retrieved by unprivileged users */ 6535 6535 }, 6536 6536 { 6537 6537 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
+20 -15
net/devlink/netlink.c
··· 109 109 return ERR_PTR(-ENODEV); 110 110 } 111 111 112 - static int devlink_nl_pre_doit(const struct genl_split_ops *ops, 113 - struct sk_buff *skb, struct genl_info *info) 112 + int devlink_nl_pre_doit(const struct genl_split_ops *ops, 113 + struct sk_buff *skb, struct genl_info *info) 114 114 { 115 115 struct devlink_linecard *linecard; 116 116 struct devlink_port *devlink_port; ··· 167 167 return err; 168 168 } 169 169 170 - static void devlink_nl_post_doit(const struct genl_split_ops *ops, 171 - struct sk_buff *skb, struct genl_info *info) 170 + void devlink_nl_post_doit(const struct genl_split_ops *ops, 171 + struct sk_buff *skb, struct genl_info *info) 172 172 { 173 173 struct devlink *devlink; 174 174 ··· 178 178 } 179 179 180 180 static const struct devlink_cmd *devl_cmds[] = { 181 - [DEVLINK_CMD_GET] = &devl_cmd_get, 182 181 [DEVLINK_CMD_PORT_GET] = &devl_cmd_port_get, 183 182 [DEVLINK_CMD_SB_GET] = &devl_cmd_sb_get, 184 183 [DEVLINK_CMD_SB_POOL_GET] = &devl_cmd_sb_pool_get, ··· 185 186 [DEVLINK_CMD_SB_TC_POOL_BIND_GET] = &devl_cmd_sb_tc_pool_bind_get, 186 187 [DEVLINK_CMD_PARAM_GET] = &devl_cmd_param_get, 187 188 [DEVLINK_CMD_REGION_GET] = &devl_cmd_region_get, 188 - [DEVLINK_CMD_INFO_GET] = &devl_cmd_info_get, 189 189 [DEVLINK_CMD_HEALTH_REPORTER_GET] = &devl_cmd_health_reporter_get, 190 190 [DEVLINK_CMD_TRAP_GET] = &devl_cmd_trap_get, 191 191 [DEVLINK_CMD_TRAP_GROUP_GET] = &devl_cmd_trap_group_get, ··· 194 196 [DEVLINK_CMD_SELFTESTS_GET] = &devl_cmd_selftests_get, 195 197 }; 196 198 197 - int devlink_nl_instance_iter_dumpit(struct sk_buff *msg, 198 - struct netlink_callback *cb) 199 + int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb, 200 + devlink_nl_dump_one_func_t *dump_one) 199 201 { 200 - const struct genl_dumpit_info *info = genl_dumpit_info(cb); 201 202 struct devlink_nl_dump_state *state = devlink_dump_state(cb); 202 - const struct devlink_cmd *cmd; 203 203 struct devlink *devlink; 204 204 int err = 0; 205 - 206 - cmd = devl_cmds[info->op.cmd]; 207 205 208 206 while ((devlink = devlinks_xa_find_get(sock_net(msg->sk), 209 207 &state->instance))) { 210 208 devl_lock(devlink); 211 209 212 210 if (devl_is_registered(devlink)) 213 - err = cmd->dump_one(msg, devlink, cb); 211 + err = dump_one(msg, devlink, cb); 214 212 else 215 213 err = 0; 216 214 ··· 227 233 return msg->len; 228 234 } 229 235 236 + int devlink_nl_instance_iter_dumpit(struct sk_buff *msg, 237 + struct netlink_callback *cb) 238 + { 239 + const struct genl_dumpit_info *info = genl_dumpit_info(cb); 240 + const struct devlink_cmd *cmd = devl_cmds[info->op.cmd]; 241 + 242 + return devlink_nl_dumpit(msg, cb, cmd->dump_one); 243 + } 244 + 230 245 struct genl_family devlink_nl_family __ro_after_init = { 231 246 .name = DEVLINK_GENL_NAME, 232 247 .version = DEVLINK_GENL_VERSION, ··· 246 243 .pre_doit = devlink_nl_pre_doit, 247 244 .post_doit = devlink_nl_post_doit, 248 245 .module = THIS_MODULE, 249 - .small_ops = devlink_nl_ops, 250 - .n_small_ops = ARRAY_SIZE(devlink_nl_ops), 246 + .small_ops = devlink_nl_small_ops, 247 + .n_small_ops = ARRAY_SIZE(devlink_nl_small_ops), 248 + .split_ops = devlink_nl_ops, 249 + .n_split_ops = ARRAY_SIZE(devlink_nl_ops), 251 250 .resv_start_op = DEVLINK_CMD_SELFTESTS_RUN + 1, 252 251 .mcgrps = devlink_nl_mcgrps, 253 252 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
+16 -4
tools/net/ynl/ynl-gen-c.py
··· 1843 1843 1844 1844 1845 1845 def print_req_policy_fwd(cw, struct, ri=None, terminate=True): 1846 - if terminate and ri and kernel_can_gen_family_struct(struct.family): 1846 + if terminate and ri and policy_should_be_static(struct.family): 1847 1847 return 1848 1848 1849 1849 if terminate: 1850 1850 prefix = 'extern ' 1851 1851 else: 1852 - if kernel_can_gen_family_struct(struct.family) and ri: 1852 + if ri and policy_should_be_static(struct.family): 1853 1853 prefix = 'static ' 1854 1854 else: 1855 1855 prefix = '' ··· 1875 1875 1876 1876 def kernel_can_gen_family_struct(family): 1877 1877 return family.proto == 'genetlink' 1878 + 1879 + 1880 + def policy_should_be_static(family): 1881 + return family.kernel_policy == 'split' or kernel_can_gen_family_struct(family) 1878 1882 1879 1883 1880 1884 def print_kernel_op_table_fwd(family, cw, terminate): ··· 1992 1988 cw.block_start() 1993 1989 members = [('cmd', op.enum_name)] 1994 1990 if 'dont-validate' in op: 1991 + dont_validate = [] 1992 + for x in op['dont-validate']: 1993 + if op_mode == 'do' and x in ['dump', 'dump-strict']: 1994 + continue 1995 + if op_mode == "dump" and x == 'strict': 1996 + continue 1997 + dont_validate.append(x) 1998 + 1995 1999 members.append(('validate', 1996 2000 ' | '.join([c_upper('genl-dont-validate-' + x) 1997 - for x in op['dont-validate']])), ) 2001 + for x in dont_validate])), ) 1998 2002 name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it") 1999 2003 if 'pre' in op[op_mode]: 2000 2004 members.append((cb_names[op_mode]['pre'], c_lower(op[op_mode]['pre']))) ··· 2321 2309 return 2322 2310 2323 2311 supported_models = ['unified'] 2324 - if args.mode == 'user': 2312 + if args.mode in ['user', 'kernel']: 2325 2313 supported_models += ['directional'] 2326 2314 if parsed.msg_id_model not in supported_models: 2327 2315 print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation')