1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 5 */ 6 7 #include <net/genetlink.h> 8 #include <net/sock.h> 9 10 #include "devl_internal.h" 11 12 #define DEVLINK_NL_FLAG_NEED_PORT BIT(0) 13 #define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) 14 #define DEVLINK_NL_FLAG_NEED_DEV_LOCK BIT(2) 15 16 static const struct genl_multicast_group devlink_nl_mcgrps[] = { 17 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME }, 18 }; 19 20 int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net, 21 struct devlink *devlink, int attrtype) 22 { 23 struct nlattr *nested_attr; 24 struct net *devl_net; 25 26 nested_attr = nla_nest_start(msg, attrtype); 27 if (!nested_attr) 28 return -EMSGSIZE; 29 if (devlink_nl_put_handle(msg, devlink)) 30 goto nla_put_failure; 31 32 rcu_read_lock(); 33 devl_net = read_pnet_rcu(&devlink->_net); 34 if (!net_eq(net, devl_net)) { 35 int id = peernet2id_alloc(net, devl_net, GFP_ATOMIC); 36 37 rcu_read_unlock(); 38 if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id)) 39 return -EMSGSIZE; 40 } else { 41 rcu_read_unlock(); 42 } 43 44 nla_nest_end(msg, nested_attr); 45 return 0; 46 47 nla_put_failure: 48 nla_nest_cancel(msg, nested_attr); 49 return -EMSGSIZE; 50 } 51 52 int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info) 53 { 54 int err; 55 56 if (*msg) { 57 err = genlmsg_reply(*msg, info); 58 if (err) 59 return err; 60 } 61 *msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 62 if (!*msg) 63 return -ENOMEM; 64 return 0; 65 } 66 67 struct devlink * 68 devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs, 69 bool dev_lock) 70 { 71 struct devlink *devlink; 72 unsigned long index; 73 char *busname; 74 char *devname; 75 76 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME]) 77 return ERR_PTR(-EINVAL); 78 79 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]); 80 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]); 81 82 devlinks_xa_for_each_registered_get(net, index, devlink) { 83 devl_dev_lock(devlink, dev_lock); 84 if (devl_is_registered(devlink) && 85 strcmp(devlink->dev->bus->name, busname) == 0 && 86 strcmp(dev_name(devlink->dev), devname) == 0) 87 return devlink; 88 devl_dev_unlock(devlink, dev_lock); 89 devlink_put(devlink); 90 } 91 92 return ERR_PTR(-ENODEV); 93 } 94 95 static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info, 96 u8 flags) 97 { 98 bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK; 99 struct devlink_port *devlink_port; 100 struct devlink *devlink; 101 int err; 102 103 devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs, 104 dev_lock); 105 if (IS_ERR(devlink)) 106 return PTR_ERR(devlink); 107 108 info->user_ptr[0] = devlink; 109 if (flags & DEVLINK_NL_FLAG_NEED_PORT) { 110 devlink_port = devlink_port_get_from_info(devlink, info); 111 if (IS_ERR(devlink_port)) { 112 err = PTR_ERR(devlink_port); 113 goto unlock; 114 } 115 info->user_ptr[1] = devlink_port; 116 } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) { 117 devlink_port = devlink_port_get_from_info(devlink, info); 118 if (!IS_ERR(devlink_port)) 119 info->user_ptr[1] = devlink_port; 120 } 121 return 0; 122 123 unlock: 124 devl_dev_unlock(devlink, dev_lock); 125 devlink_put(devlink); 126 return err; 127 } 128 129 int devlink_nl_pre_doit(const struct genl_split_ops *ops, 130 struct sk_buff *skb, struct genl_info *info) 131 { 132 return __devlink_nl_pre_doit(skb, info, 0); 133 } 134 135 int devlink_nl_pre_doit_port(const struct genl_split_ops *ops, 136 struct sk_buff *skb, struct genl_info *info) 137 { 138 return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_PORT); 139 } 140 141 int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops, 142 struct sk_buff *skb, struct genl_info *info) 143 { 144 return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEV_LOCK); 145 } 146 147 int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops, 148 struct sk_buff *skb, 149 struct genl_info *info) 150 { 151 return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT); 152 } 153 154 static void __devlink_nl_post_doit(struct sk_buff *skb, struct genl_info *info, 155 u8 flags) 156 { 157 bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK; 158 struct devlink *devlink; 159 160 devlink = info->user_ptr[0]; 161 devl_dev_unlock(devlink, dev_lock); 162 devlink_put(devlink); 163 } 164 165 void devlink_nl_post_doit(const struct genl_split_ops *ops, 166 struct sk_buff *skb, struct genl_info *info) 167 { 168 __devlink_nl_post_doit(skb, info, 0); 169 } 170 171 void 172 devlink_nl_post_doit_dev_lock(const struct genl_split_ops *ops, 173 struct sk_buff *skb, struct genl_info *info) 174 { 175 __devlink_nl_post_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEV_LOCK); 176 } 177 178 static int devlink_nl_inst_single_dumpit(struct sk_buff *msg, 179 struct netlink_callback *cb, int flags, 180 devlink_nl_dump_one_func_t *dump_one, 181 struct nlattr **attrs) 182 { 183 struct devlink *devlink; 184 int err; 185 186 devlink = devlink_get_from_attrs_lock(sock_net(msg->sk), attrs, false); 187 if (IS_ERR(devlink)) 188 return PTR_ERR(devlink); 189 err = dump_one(msg, devlink, cb, flags | NLM_F_DUMP_FILTERED); 190 191 devl_unlock(devlink); 192 devlink_put(devlink); 193 194 if (err != -EMSGSIZE) 195 return err; 196 return msg->len; 197 } 198 199 static int devlink_nl_inst_iter_dumpit(struct sk_buff *msg, 200 struct netlink_callback *cb, int flags, 201 devlink_nl_dump_one_func_t *dump_one) 202 { 203 struct devlink_nl_dump_state *state = devlink_dump_state(cb); 204 struct devlink *devlink; 205 int err = 0; 206 207 while ((devlink = devlinks_xa_find_get(sock_net(msg->sk), 208 &state->instance))) { 209 devl_lock(devlink); 210 211 if (devl_is_registered(devlink)) 212 err = dump_one(msg, devlink, cb, flags); 213 else 214 err = 0; 215 216 devl_unlock(devlink); 217 devlink_put(devlink); 218 219 if (err) 220 break; 221 222 state->instance++; 223 224 /* restart sub-object walk for the next instance */ 225 state->idx = 0; 226 } 227 228 if (err != -EMSGSIZE) 229 return err; 230 return msg->len; 231 } 232 233 int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb, 234 devlink_nl_dump_one_func_t *dump_one) 235 { 236 const struct genl_info *info = genl_info_dump(cb); 237 struct nlattr **attrs = info->attrs; 238 int flags = NLM_F_MULTI; 239 240 if (attrs && 241 (attrs[DEVLINK_ATTR_BUS_NAME] || attrs[DEVLINK_ATTR_DEV_NAME])) 242 return devlink_nl_inst_single_dumpit(msg, cb, flags, dump_one, 243 attrs); 244 else 245 return devlink_nl_inst_iter_dumpit(msg, cb, flags, dump_one); 246 } 247 248 struct genl_family devlink_nl_family __ro_after_init = { 249 .name = DEVLINK_GENL_NAME, 250 .version = DEVLINK_GENL_VERSION, 251 .netnsok = true, 252 .parallel_ops = true, 253 .module = THIS_MODULE, 254 .split_ops = devlink_nl_ops, 255 .n_split_ops = ARRAY_SIZE(devlink_nl_ops), 256 .resv_start_op = DEVLINK_CMD_SELFTESTS_RUN + 1, 257 .mcgrps = devlink_nl_mcgrps, 258 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps), 259 }; 260