1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
7 #include <net/genetlink.h>
10 #include "devl_internal.h"
12 static const struct genl_multicast_group devlink_nl_mcgrps[] = {
13 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
16 int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
17 struct devlink *devlink, int attrtype)
19 struct nlattr *nested_attr;
22 nested_attr = nla_nest_start(msg, attrtype);
25 if (devlink_nl_put_handle(msg, devlink))
29 devl_net = read_pnet_rcu(&devlink->_net);
30 if (!net_eq(net, devl_net)) {
31 int id = peernet2id_alloc(net, devl_net, GFP_ATOMIC);
34 if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id))
40 nla_nest_end(msg, nested_attr);
44 nla_nest_cancel(msg, nested_attr);
48 int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info)
53 err = genlmsg_reply(*msg, info);
57 *msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
64 devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs)
66 struct devlink *devlink;
71 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
72 return ERR_PTR(-EINVAL);
74 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
75 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
77 devlinks_xa_for_each_registered_get(net, index, devlink) {
79 if (devl_is_registered(devlink) &&
80 strcmp(devlink->dev->bus->name, busname) == 0 &&
81 strcmp(dev_name(devlink->dev), devname) == 0)
87 return ERR_PTR(-ENODEV);
90 static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
93 struct devlink_port *devlink_port;
94 struct devlink *devlink;
97 devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs);
99 return PTR_ERR(devlink);
101 info->user_ptr[0] = devlink;
102 if (flags & DEVLINK_NL_FLAG_NEED_PORT) {
103 devlink_port = devlink_port_get_from_info(devlink, info);
104 if (IS_ERR(devlink_port)) {
105 err = PTR_ERR(devlink_port);
108 info->user_ptr[1] = devlink_port;
109 } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
110 devlink_port = devlink_port_get_from_info(devlink, info);
111 if (!IS_ERR(devlink_port))
112 info->user_ptr[1] = devlink_port;
117 devl_unlock(devlink);
118 devlink_put(devlink);
122 int devlink_nl_pre_doit(const struct genl_split_ops *ops,
123 struct sk_buff *skb, struct genl_info *info)
125 return __devlink_nl_pre_doit(skb, info, 0);
128 int devlink_nl_pre_doit_port(const struct genl_split_ops *ops,
129 struct sk_buff *skb, struct genl_info *info)
131 return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_PORT);
134 int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
136 struct genl_info *info)
138 return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT);
141 void devlink_nl_post_doit(const struct genl_split_ops *ops,
142 struct sk_buff *skb, struct genl_info *info)
144 struct devlink *devlink;
146 devlink = info->user_ptr[0];
147 devl_unlock(devlink);
148 devlink_put(devlink);
151 static int devlink_nl_inst_single_dumpit(struct sk_buff *msg,
152 struct netlink_callback *cb, int flags,
153 devlink_nl_dump_one_func_t *dump_one,
154 struct nlattr **attrs)
156 struct devlink *devlink;
159 devlink = devlink_get_from_attrs_lock(sock_net(msg->sk), attrs);
161 return PTR_ERR(devlink);
162 err = dump_one(msg, devlink, cb, flags | NLM_F_DUMP_FILTERED);
164 devl_unlock(devlink);
165 devlink_put(devlink);
167 if (err != -EMSGSIZE)
172 static int devlink_nl_inst_iter_dumpit(struct sk_buff *msg,
173 struct netlink_callback *cb, int flags,
174 devlink_nl_dump_one_func_t *dump_one)
176 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
177 struct devlink *devlink;
180 while ((devlink = devlinks_xa_find_get(sock_net(msg->sk),
181 &state->instance))) {
184 if (devl_is_registered(devlink))
185 err = dump_one(msg, devlink, cb, flags);
189 devl_unlock(devlink);
190 devlink_put(devlink);
197 /* restart sub-object walk for the next instance */
201 if (err != -EMSGSIZE)
206 int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
207 devlink_nl_dump_one_func_t *dump_one)
209 const struct genl_info *info = genl_info_dump(cb);
210 struct nlattr **attrs = info->attrs;
211 int flags = NLM_F_MULTI;
214 (attrs[DEVLINK_ATTR_BUS_NAME] || attrs[DEVLINK_ATTR_DEV_NAME]))
215 return devlink_nl_inst_single_dumpit(msg, cb, flags, dump_one,
218 return devlink_nl_inst_iter_dumpit(msg, cb, flags, dump_one);
221 struct genl_family devlink_nl_family __ro_after_init = {
222 .name = DEVLINK_GENL_NAME,
223 .version = DEVLINK_GENL_VERSION,
225 .parallel_ops = true,
226 .module = THIS_MODULE,
227 .split_ops = devlink_nl_ops,
228 .n_split_ops = ARRAY_SIZE(devlink_nl_ops),
229 .resv_start_op = DEVLINK_CMD_SELFTESTS_RUN + 1,
230 .mcgrps = devlink_nl_mcgrps,
231 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),