summaryrefslogtreecommitdiff
path: root/net/devlink
diff options
context:
space:
mode:
Diffstat (limited to 'net/devlink')
-rw-r--r--net/devlink/core.c22
-rw-r--r--net/devlink/dev.c17
-rw-r--r--net/devlink/devl_internal.h20
-rw-r--r--net/devlink/dpipe.c14
-rw-r--r--net/devlink/health.c12
-rw-r--r--net/devlink/linecard.c4
-rw-r--r--net/devlink/netlink.c82
-rw-r--r--net/devlink/netlink_gen.c26
-rw-r--r--net/devlink/netlink_gen.h8
-rw-r--r--net/devlink/param.c136
-rw-r--r--net/devlink/port.c26
-rw-r--r--net/devlink/rate.c352
-rw-r--r--net/devlink/region.c6
-rw-r--r--net/devlink/resource.c16
-rw-r--r--net/devlink/sb.c22
-rw-r--r--net/devlink/trap.c12
16 files changed, 576 insertions, 199 deletions
diff --git a/net/devlink/core.c b/net/devlink/core.c
index eeb6a71f5f56..c53a42e17a58 100644
--- a/net/devlink/core.c
+++ b/net/devlink/core.c
@@ -67,6 +67,22 @@ static void __devlink_rel_put(struct devlink_rel *rel)
devlink_rel_free(rel);
}
+struct devlink *__must_check devlink_nested_in_get_lock(struct devlink *devlink)
+{
+ devl_assert_locked(devlink);
+ if (!devlink->rel)
+ return NULL;
+ devlink = devlinks_xa_get(devlink->rel->nested_in.devlink_index);
+ if (!devlink)
+ return NULL;
+ devl_lock(devlink);
+ if (devl_is_registered(devlink))
+ return devlink;
+ devl_unlock(devlink);
+ devlink_put(devlink);
+ return NULL;
+}
+
static void devlink_rel_nested_in_notify_work(struct work_struct *work)
{
struct devlink_rel *rel = container_of(work, struct devlink_rel,
@@ -518,6 +534,11 @@ void devlink_free(struct devlink *devlink)
{
ASSERT_DEVLINK_NOT_REGISTERED(devlink);
+ devl_lock(devlink);
+ WARN_ON(devlink_rates_check(devlink, NULL, NULL));
+ devl_unlock(devlink);
+ devlink_rel_put(devlink);
+
WARN_ON(!list_empty(&devlink->trap_policer_list));
WARN_ON(!list_empty(&devlink->trap_group_list));
WARN_ON(!list_empty(&devlink->trap_list));
@@ -526,7 +547,6 @@ void devlink_free(struct devlink *devlink)
WARN_ON(!list_empty(&devlink->resource_list));
WARN_ON(!list_empty(&devlink->dpipe_table_list));
WARN_ON(!list_empty(&devlink->sb_list));
- WARN_ON(devlink_rates_check(devlink, NULL, NULL));
WARN_ON(!list_empty(&devlink->linecard_list));
WARN_ON(!xa_empty(&devlink->ports));
diff --git a/net/devlink/dev.c b/net/devlink/dev.c
index 57b2b8f03543..55959b0ff5ab 100644
--- a/net/devlink/dev.c
+++ b/net/devlink/dev.c
@@ -222,7 +222,7 @@ static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
int devlink_nl_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct sk_buff *msg;
int err;
@@ -519,7 +519,7 @@ free_msg:
int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
enum devlink_reload_action action;
enum devlink_reload_limit limit;
struct net *dest_net = NULL;
@@ -578,6 +578,7 @@ int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info)
action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) {
NL_SET_ERR_MSG_MOD(info->extack,
"Changing namespace is only supported for reinit action");
+ put_net(dest_net);
return -EOPNOTSUPP;
}
}
@@ -683,7 +684,7 @@ nla_put_failure:
int devlink_nl_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct sk_buff *msg;
int err;
@@ -704,7 +705,7 @@ int devlink_nl_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info)
int devlink_nl_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
const struct devlink_ops *ops = devlink->ops;
enum devlink_eswitch_encap_mode encap_mode;
u8 inline_mode;
@@ -906,7 +907,7 @@ err_cancel_msg:
int devlink_nl_info_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct sk_buff *msg;
int err;
@@ -1134,7 +1135,7 @@ int devlink_nl_flash_update_doit(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *nla_overwrite_mask, *nla_file_name;
struct devlink_flash_update_params params = {};
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
const char *file_name;
u32 supported_params;
int ret;
@@ -1302,7 +1303,7 @@ err_cancel_msg:
int devlink_nl_selftests_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct sk_buff *msg;
int err;
@@ -1372,7 +1373,7 @@ static const struct nla_policy devlink_selftest_nl_policy[DEVLINK_ATTR_SELFTEST_
int devlink_nl_selftests_run_doit(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *tb[DEVLINK_ATTR_SELFTEST_ID_MAX + 1];
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct nlattr *attrs, *selftests;
struct sk_buff *msg;
void *hdr;
diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h
index e4e48ee2da5a..cdf894ba5a9d 100644
--- a/net/devlink/devl_internal.h
+++ b/net/devlink/devl_internal.h
@@ -136,6 +136,10 @@ typedef void devlink_rel_notify_cb_t(struct devlink *devlink, u32 obj_index);
typedef void devlink_rel_cleanup_cb_t(struct devlink *devlink, u32 obj_index,
u32 rel_index);
+/* Returns the locked+referenced nested-in instance or NULL. */
+struct devlink *__must_check
+devlink_nested_in_get_lock(struct devlink *devlink);
+
void devlink_rel_nested_in_clear(u32 rel_index);
int devlink_rel_nested_in_add(u32 *rel_index, u32 devlink_index,
u32 obj_index, devlink_rel_notify_cb_t *notify_cb,
@@ -147,6 +151,20 @@ int devlink_rel_devlink_handle_put(struct sk_buff *msg, struct devlink *devlink,
bool *msg_updated);
/* Netlink */
+struct devlink_nl_ctx {
+ struct devlink *devlink;
+ struct devlink_port *devlink_port;
+ struct devlink *parent_devlink;
+};
+
+static inline struct devlink_nl_ctx *
+devlink_nl_ctx(struct genl_info *info)
+{
+ BUILD_BUG_ON(sizeof(struct devlink_nl_ctx) >
+ sizeof_field(struct genl_info, ctx));
+ return (struct devlink_nl_ctx *)info->ctx;
+}
+
enum devlink_multicast_groups {
DEVLINK_MCGRP_CONFIG,
};
@@ -180,6 +198,8 @@ typedef int devlink_nl_dump_one_func_t(struct sk_buff *msg,
struct devlink *
devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs,
bool dev_lock);
+struct devlink *
+devlink_get_parent_from_attrs_lock(struct net *net, struct nlattr **attrs);
int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
devlink_nl_dump_one_func_t *dump_one);
diff --git a/net/devlink/dpipe.c b/net/devlink/dpipe.c
index c8d4a4374ae1..08c7b66fc3e8 100644
--- a/net/devlink/dpipe.c
+++ b/net/devlink/dpipe.c
@@ -213,7 +213,7 @@ static int devlink_dpipe_tables_fill(struct genl_info *info,
struct list_head *dpipe_tables,
const char *table_name)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_dpipe_table *table;
struct nlattr *tables_attr;
struct sk_buff *skb = NULL;
@@ -290,7 +290,7 @@ err_table_put:
int devlink_nl_dpipe_table_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
const char *table_name = NULL;
if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
@@ -478,7 +478,7 @@ int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
if (!dump_ctx->hdr)
goto nla_put_failure;
- devlink = dump_ctx->info->user_ptr[0];
+ devlink = devlink_nl_ctx(dump_ctx->info)->devlink;
if (devlink_nl_put_handle(dump_ctx->skb, devlink))
goto nla_put_failure;
dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
@@ -563,7 +563,7 @@ send_done:
int devlink_nl_dpipe_entries_get_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_dpipe_table *table;
const char *table_name;
@@ -650,7 +650,7 @@ static int devlink_dpipe_headers_fill(struct genl_info *info,
struct devlink_dpipe_headers *
dpipe_headers)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct nlattr *headers_attr;
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
@@ -713,7 +713,7 @@ err_table_put:
int devlink_nl_dpipe_headers_get_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
if (!devlink->dpipe_headers)
return -EOPNOTSUPP;
@@ -747,7 +747,7 @@ static int devlink_dpipe_table_counters_set(struct devlink *devlink,
int devlink_nl_dpipe_table_counters_set_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
const char *table_name;
bool counters_enable;
diff --git a/net/devlink/health.c b/net/devlink/health.c
index ea7a334e939b..8ce6cd399cb7 100644
--- a/net/devlink/health.c
+++ b/net/devlink/health.c
@@ -358,7 +358,7 @@ devlink_health_reporter_get_from_info(struct devlink *devlink,
int devlink_nl_health_reporter_get_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_health_reporter *reporter;
struct sk_buff *msg;
int err;
@@ -456,7 +456,7 @@ int devlink_nl_health_reporter_get_dumpit(struct sk_buff *skb,
int devlink_nl_health_reporter_set_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_health_reporter *reporter;
reporter = devlink_health_reporter_get_from_info(devlink, info);
@@ -715,7 +715,7 @@ EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
int devlink_nl_health_reporter_recover_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_health_reporter *reporter;
reporter = devlink_health_reporter_get_from_info(devlink, info);
@@ -1157,7 +1157,7 @@ nla_put_failure:
int devlink_nl_health_reporter_diagnose_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_health_reporter *reporter;
struct devlink_fmsg *fmsg;
int err;
@@ -1252,7 +1252,7 @@ unlock:
int devlink_nl_health_reporter_dump_clear_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_health_reporter *reporter;
reporter = devlink_health_reporter_get_from_info(devlink, info);
@@ -1269,7 +1269,7 @@ int devlink_nl_health_reporter_dump_clear_doit(struct sk_buff *skb,
int devlink_nl_health_reporter_test_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_health_reporter *reporter;
reporter = devlink_health_reporter_get_from_info(devlink, info);
diff --git a/net/devlink/linecard.c b/net/devlink/linecard.c
index 8315d35cb91d..fd18f2759770 100644
--- a/net/devlink/linecard.c
+++ b/net/devlink/linecard.c
@@ -171,7 +171,7 @@ void devlink_linecards_notify_unregister(struct devlink *devlink)
int devlink_nl_linecard_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_linecard *linecard;
struct sk_buff *msg;
int err;
@@ -371,7 +371,7 @@ out:
int devlink_nl_linecard_set_doit(struct sk_buff *skb, struct genl_info *info)
{
struct netlink_ext_ack *extack = info->extack;
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_linecard *linecard;
int err;
diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c
index ae4afc739678..300580c1a217 100644
--- a/net/devlink/netlink.c
+++ b/net/devlink/netlink.c
@@ -12,6 +12,7 @@
#define DEVLINK_NL_FLAG_NEED_PORT BIT(0)
#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1)
#define DEVLINK_NL_FLAG_NEED_DEV_LOCK BIT(2)
+#define DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV BIT(3)
static const struct genl_multicast_group devlink_nl_mcgrps[] = {
[DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
@@ -239,37 +240,82 @@ found:
return ERR_PTR(-ENODEV);
}
+struct devlink *
+devlink_get_parent_from_attrs_lock(struct net *net, struct nlattr **attrs)
+{
+ unsigned int maxtype = ARRAY_SIZE(devlink_dl_parent_dev_nl_policy) - 1;
+ struct devlink *devlink;
+ struct nlattr **tb;
+ int err;
+
+ if (!attrs[DEVLINK_ATTR_PARENT_DEV])
+ return ERR_PTR(-EINVAL);
+
+ tb = kcalloc(maxtype + 1, sizeof(*tb), GFP_KERNEL);
+ if (!tb)
+ return ERR_PTR(-ENOMEM);
+
+ err = nla_parse_nested(tb, maxtype, attrs[DEVLINK_ATTR_PARENT_DEV],
+ devlink_dl_parent_dev_nl_policy, NULL);
+ if (err)
+ goto out;
+
+ devlink = devlink_get_from_attrs_lock(net, tb, false);
+ kfree(tb);
+ return devlink;
+out:
+ kfree(tb);
+ return ERR_PTR(err);
+}
+
static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
u8 flags)
{
+ bool parent_dev = flags & DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV;
bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK;
+ struct devlink *devlink, *parent_devlink = NULL;
+ struct net *net = genl_info_net(info);
+ struct nlattr **attrs = info->attrs;
struct devlink_port *devlink_port;
- struct devlink *devlink;
int err;
- devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs,
- dev_lock);
- if (IS_ERR(devlink))
- return PTR_ERR(devlink);
+ if (parent_dev && attrs[DEVLINK_ATTR_PARENT_DEV]) {
+ parent_devlink = devlink_get_parent_from_attrs_lock(net, attrs);
+ if (IS_ERR(parent_devlink))
+ return PTR_ERR(parent_devlink);
+ devlink_nl_ctx(info)->parent_devlink = parent_devlink;
+ /* Drop the parent devlink lock but don't release the reference.
+ * This will keep it alive until the end of the request.
+ */
+ devl_unlock(parent_devlink);
+ }
- info->user_ptr[0] = devlink;
+ devlink = devlink_get_from_attrs_lock(net, attrs, dev_lock);
+ if (IS_ERR(devlink)) {
+ err = PTR_ERR(devlink);
+ goto parent_put;
+ }
+ devlink_nl_ctx(info)->devlink = devlink;
if (flags & DEVLINK_NL_FLAG_NEED_PORT) {
devlink_port = devlink_port_get_from_info(devlink, info);
if (IS_ERR(devlink_port)) {
err = PTR_ERR(devlink_port);
goto unlock;
}
- info->user_ptr[1] = devlink_port;
+ devlink_nl_ctx(info)->devlink_port = devlink_port;
} else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
devlink_port = devlink_port_get_from_info(devlink, info);
if (!IS_ERR(devlink_port))
- info->user_ptr[1] = devlink_port;
+ devlink_nl_ctx(info)->devlink_port = devlink_port;
}
return 0;
unlock:
devl_dev_unlock(devlink, dev_lock);
devlink_put(devlink);
+parent_put:
+ if (parent_dev && parent_devlink)
+ devlink_put(parent_devlink);
return err;
}
@@ -298,15 +344,25 @@ int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT);
}
+int devlink_nl_pre_doit_parent_dev_optional(const struct genl_split_ops *ops,
+ struct sk_buff *skb,
+ struct genl_info *info)
+{
+ return __devlink_nl_pre_doit(skb, info,
+ DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV);
+}
+
static void __devlink_nl_post_doit(struct sk_buff *skb, struct genl_info *info,
u8 flags)
{
bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK;
struct devlink *devlink;
- devlink = info->user_ptr[0];
+ devlink = devlink_nl_ctx(info)->devlink;
devl_dev_unlock(devlink, dev_lock);
devlink_put(devlink);
+ if (devlink_nl_ctx(info)->parent_devlink)
+ devlink_put(devlink_nl_ctx(info)->parent_devlink);
}
void devlink_nl_post_doit(const struct genl_split_ops *ops,
@@ -322,6 +378,14 @@ devlink_nl_post_doit_dev_lock(const struct genl_split_ops *ops,
__devlink_nl_post_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEV_LOCK);
}
+void
+devlink_nl_post_doit_parent_dev_optional(const struct genl_split_ops *ops,
+ struct sk_buff *skb,
+ struct genl_info *info)
+{
+ __devlink_nl_post_doit(skb, info, DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV);
+}
+
static int devlink_nl_inst_single_dumpit(struct sk_buff *msg,
struct netlink_callback *cb, int flags,
devlink_nl_dump_one_func_t *dump_one,
diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c
index 81899786fd98..dec00133178d 100644
--- a/net/devlink/netlink_gen.c
+++ b/net/devlink/netlink_gen.c
@@ -37,6 +37,8 @@ devlink_attr_param_type_validate(const struct nlattr *attr,
case DEVLINK_VAR_ATTR_TYPE_NUL_STRING:
fallthrough;
case DEVLINK_VAR_ATTR_TYPE_BINARY:
+ fallthrough;
+ case DEVLINK_VAR_ATTR_TYPE_U64_ARRAY:
return 0;
}
NL_SET_ERR_MSG_ATTR(extack, attr, "invalid enum value");
@@ -44,6 +46,12 @@ devlink_attr_param_type_validate(const struct nlattr *attr,
}
/* Common nested types */
+const struct nla_policy devlink_dl_parent_dev_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
+ [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
+ [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
+ [DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range),
+};
+
const struct nla_policy devlink_dl_port_function_nl_policy[DEVLINK_PORT_FN_ATTR_CAPS + 1] = {
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY, },
[DEVLINK_PORT_FN_ATTR_STATE] = NLA_POLICY_MAX(NLA_U8, 1),
@@ -606,7 +614,7 @@ static const struct nla_policy devlink_rate_get_dump_nl_policy[DEVLINK_ATTR_INDE
};
/* DEVLINK_CMD_RATE_SET - do */
-static const struct nla_policy devlink_rate_set_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
+static const struct nla_policy devlink_rate_set_nl_policy[DEVLINK_ATTR_PARENT_DEV + 1] = {
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range),
@@ -617,10 +625,11 @@ static const struct nla_policy devlink_rate_set_nl_policy[DEVLINK_ATTR_INDEX + 1
[DEVLINK_ATTR_RATE_TX_WEIGHT] = { .type = NLA_U32, },
[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_RATE_TC_BWS] = NLA_POLICY_NESTED(devlink_dl_rate_tc_bws_nl_policy),
+ [DEVLINK_ATTR_PARENT_DEV] = NLA_POLICY_NESTED(devlink_dl_parent_dev_nl_policy),
};
/* DEVLINK_CMD_RATE_NEW - do */
-static const struct nla_policy devlink_rate_new_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
+static const struct nla_policy devlink_rate_new_nl_policy[DEVLINK_ATTR_PARENT_DEV + 1] = {
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range),
@@ -631,6 +640,7 @@ static const struct nla_policy devlink_rate_new_nl_policy[DEVLINK_ATTR_INDEX + 1
[DEVLINK_ATTR_RATE_TX_WEIGHT] = { .type = NLA_U32, },
[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_RATE_TC_BWS] = NLA_POLICY_NESTED(devlink_dl_rate_tc_bws_nl_policy),
+ [DEVLINK_ATTR_PARENT_DEV] = NLA_POLICY_NESTED(devlink_dl_parent_dev_nl_policy),
};
/* DEVLINK_CMD_RATE_DEL - do */
@@ -1288,21 +1298,21 @@ const struct genl_split_ops devlink_nl_ops[75] = {
{
.cmd = DEVLINK_CMD_RATE_SET,
.validate = GENL_DONT_VALIDATE_STRICT,
- .pre_doit = devlink_nl_pre_doit,
+ .pre_doit = devlink_nl_pre_doit_parent_dev_optional,
.doit = devlink_nl_rate_set_doit,
- .post_doit = devlink_nl_post_doit,
+ .post_doit = devlink_nl_post_doit_parent_dev_optional,
.policy = devlink_rate_set_nl_policy,
- .maxattr = DEVLINK_ATTR_INDEX,
+ .maxattr = DEVLINK_ATTR_PARENT_DEV,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
.cmd = DEVLINK_CMD_RATE_NEW,
.validate = GENL_DONT_VALIDATE_STRICT,
- .pre_doit = devlink_nl_pre_doit,
+ .pre_doit = devlink_nl_pre_doit_parent_dev_optional,
.doit = devlink_nl_rate_new_doit,
- .post_doit = devlink_nl_post_doit,
+ .post_doit = devlink_nl_post_doit_parent_dev_optional,
.policy = devlink_rate_new_nl_policy,
- .maxattr = DEVLINK_ATTR_INDEX,
+ .maxattr = DEVLINK_ATTR_PARENT_DEV,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
diff --git a/net/devlink/netlink_gen.h b/net/devlink/netlink_gen.h
index 20034b0929a8..a70e0e4769aa 100644
--- a/net/devlink/netlink_gen.h
+++ b/net/devlink/netlink_gen.h
@@ -13,6 +13,7 @@
#include <uapi/linux/devlink.h>
/* Common nested types */
+extern const struct nla_policy devlink_dl_parent_dev_nl_policy[DEVLINK_ATTR_INDEX + 1];
extern const struct nla_policy devlink_dl_port_function_nl_policy[DEVLINK_PORT_FN_ATTR_CAPS + 1];
extern const struct nla_policy devlink_dl_rate_tc_bws_nl_policy[DEVLINK_RATE_TC_ATTR_BW + 1];
extern const struct nla_policy devlink_dl_selftest_id_nl_policy[DEVLINK_ATTR_SELFTEST_ID_FLASH + 1];
@@ -29,12 +30,19 @@ int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
struct genl_info *info);
int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
+int devlink_nl_pre_doit_parent_dev_optional(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);
void
devlink_nl_post_doit_dev_lock(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
+void
+devlink_nl_post_doit_parent_dev_optional(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);
diff --git a/net/devlink/param.c b/net/devlink/param.c
index cf95268da5b0..8ca0f3ed646c 100644
--- a/net/devlink/param.c
+++ b/net/devlink/param.c
@@ -117,6 +117,11 @@ static const struct devlink_param devlink_param_generic[] = {
.name = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_NAME,
.type = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_TYPE,
},
+ {
+ .id = DEVLINK_PARAM_GENERIC_ID_MAX_SFS,
+ .name = DEVLINK_PARAM_GENERIC_MAX_SFS_NAME,
+ .type = DEVLINK_PARAM_GENERIC_MAX_SFS_TYPE,
+ },
};
static int devlink_param_generic_verify(const struct devlink_param *param)
@@ -216,28 +221,28 @@ static int devlink_param_reset_default(struct devlink *devlink,
static int
devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,
- int nla_type, union devlink_param_value val,
+ int nla_type, union devlink_param_value *val,
bool flag_as_u8)
{
switch (type) {
case DEVLINK_PARAM_TYPE_U8:
- if (nla_put_u8(msg, nla_type, val.vu8))
+ if (nla_put_u8(msg, nla_type, val->vu8))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_U16:
- if (nla_put_u16(msg, nla_type, val.vu16))
+ if (nla_put_u16(msg, nla_type, val->vu16))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_U32:
- if (nla_put_u32(msg, nla_type, val.vu32))
+ if (nla_put_u32(msg, nla_type, val->vu32))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_U64:
- if (devlink_nl_put_u64(msg, nla_type, val.vu64))
+ if (devlink_nl_put_u64(msg, nla_type, val->vu64))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_STRING:
- if (nla_put_string(msg, nla_type, val.vstr))
+ if (nla_put_string(msg, nla_type, val->vstr))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_BOOL:
@@ -245,10 +250,19 @@ devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,
* false can be distinguished from not present
*/
if (flag_as_u8) {
- if (nla_put_u8(msg, nla_type, val.vbool))
+ if (nla_put_u8(msg, nla_type, val->vbool))
return -EMSGSIZE;
} else {
- if (val.vbool && nla_put_flag(msg, nla_type))
+ if (val->vbool && nla_put_flag(msg, nla_type))
+ return -EMSGSIZE;
+ }
+ break;
+ case DEVLINK_PARAM_TYPE_U64_ARRAY:
+ if (val->u64arr.size > __DEVLINK_PARAM_MAX_ARRAY_SIZE)
+ return -EMSGSIZE;
+
+ for (int i = 0; i < val->u64arr.size; i++) {
+ if (nla_put_uint(msg, nla_type, val->u64arr.val[i]))
return -EMSGSIZE;
}
break;
@@ -260,8 +274,8 @@ static int
devlink_nl_param_value_fill_one(struct sk_buff *msg,
enum devlink_param_type type,
enum devlink_param_cmode cmode,
- union devlink_param_value val,
- union devlink_param_value default_val,
+ union devlink_param_value *val,
+ union devlink_param_value *default_val,
bool has_default)
{
struct nlattr *param_value_attr;
@@ -304,56 +318,79 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
u32 portid, u32 seq, int flags,
struct netlink_ext_ack *extack)
{
- union devlink_param_value default_value[DEVLINK_PARAM_CMODE_MAX + 1];
- union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
const struct devlink_param *param = param_item->param;
- struct devlink_param_gset_ctx ctx;
+ union devlink_param_value *default_value;
+ union devlink_param_value *param_value;
+ struct devlink_param_gset_ctx *ctx;
struct nlattr *param_values_list;
struct nlattr *param_attr;
void *hdr;
int err;
int i;
+ default_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+ sizeof(*default_value), GFP_KERNEL);
+ if (!default_value)
+ return -ENOMEM;
+
+ param_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+ sizeof(*param_value), GFP_KERNEL);
+ if (!param_value) {
+ kfree(default_value);
+ return -ENOMEM;
+ }
+
+ ctx = kzalloc_obj(*ctx);
+ if (!ctx) {
+ kfree(param_value);
+ kfree(default_value);
+ return -ENOMEM;
+ }
+
/* Get value from driver part to driverinit configuration mode */
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
if (!devlink_param_cmode_is_supported(param, i))
continue;
if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
- if (param_item->driverinit_value_new_valid)
+ if (param_item->driverinit_value_new_valid) {
param_value[i] = param_item->driverinit_value_new;
- else if (param_item->driverinit_value_valid)
+ } else if (param_item->driverinit_value_valid) {
param_value[i] = param_item->driverinit_value;
- else
- return -EOPNOTSUPP;
+ } else {
+ err = -EOPNOTSUPP;
+ goto get_put_fail;
+ }
if (param_item->driverinit_value_valid) {
default_value[i] = param_item->driverinit_default;
default_value_set[i] = true;
}
} else {
- ctx.cmode = i;
- err = devlink_param_get(devlink, param, &ctx, extack);
+ ctx->cmode = i;
+ err = devlink_param_get(devlink, param, ctx, extack);
if (err)
- return err;
- param_value[i] = ctx.val;
+ goto get_put_fail;
+
+ param_value[i] = ctx->val;
- err = devlink_param_get_default(devlink, param, &ctx,
+ err = devlink_param_get_default(devlink, param, ctx,
extack);
if (!err) {
- default_value[i] = ctx.val;
+ default_value[i] = ctx->val;
default_value_set[i] = true;
} else if (err != -EOPNOTSUPP) {
- return err;
+ goto get_put_fail;
}
}
param_value_set[i] = true;
}
+ err = -EMSGSIZE;
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
if (!hdr)
- return -EMSGSIZE;
+ goto get_put_fail;
if (devlink_nl_put_handle(msg, devlink))
goto genlmsg_cancel;
@@ -383,8 +420,8 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
if (!param_value_set[i])
continue;
err = devlink_nl_param_value_fill_one(msg, param->type,
- i, param_value[i],
- default_value[i],
+ i, &param_value[i],
+ &default_value[i],
default_value_set[i]);
if (err)
goto values_list_nest_cancel;
@@ -393,6 +430,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
nla_nest_end(msg, param_values_list);
nla_nest_end(msg, param_attr);
genlmsg_end(msg, hdr);
+ kfree(default_value);
+ kfree(param_value);
+ kfree(ctx);
return 0;
values_list_nest_cancel:
@@ -401,7 +441,11 @@ param_nest_cancel:
nla_nest_cancel(msg, param_attr);
genlmsg_cancel:
genlmsg_cancel(msg, hdr);
- return -EMSGSIZE;
+get_put_fail:
+ kfree(default_value);
+ kfree(param_value);
+ kfree(ctx);
+ return err;
}
static void devlink_param_notify(struct devlink *devlink,
@@ -507,7 +551,7 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
union devlink_param_value *value)
{
struct nlattr *param_data;
- int len;
+ int len, cnt, rem;
param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
@@ -547,6 +591,28 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
return -EINVAL;
value->vbool = nla_get_flag(param_data);
break;
+
+ case DEVLINK_PARAM_TYPE_U64_ARRAY:
+ cnt = 0;
+ nla_for_each_attr_type(param_data,
+ DEVLINK_ATTR_PARAM_VALUE_DATA,
+ genlmsg_data(info->genlhdr),
+ genlmsg_len(info->genlhdr), rem) {
+ if (cnt >= __DEVLINK_PARAM_MAX_ARRAY_SIZE)
+ return -EMSGSIZE;
+
+ if ((nla_len(param_data) != sizeof(u64)) &&
+ (nla_len(param_data) != sizeof(u32))) {
+ NL_SET_BAD_ATTR(info->extack, param_data);
+ return -EINVAL;
+ }
+
+ value->u64arr.val[cnt] = nla_get_uint(param_data);
+ cnt++;
+ }
+
+ value->u64arr.size = cnt;
+ break;
}
return 0;
}
@@ -566,7 +632,7 @@ devlink_param_get_from_info(struct xarray *params, struct genl_info *info)
int devlink_nl_param_get_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_param_item *param_item;
struct sk_buff *msg;
int err;
@@ -621,7 +687,7 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
if (err)
return err;
if (param->validate) {
- err = param->validate(devlink, param->id, value,
+ err = param->validate(devlink, param->id, &value,
info->extack);
if (err)
return err;
@@ -667,7 +733,7 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
int devlink_nl_param_set_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->params,
info, DEVLINK_CMD_PARAM_NEW);
@@ -888,7 +954,7 @@ EXPORT_SYMBOL_GPL(devl_param_driverinit_value_get);
* configuration mode default value.
*/
void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
- union devlink_param_value init_val)
+ union devlink_param_value *init_val)
{
struct devlink_param_item *param_item;
@@ -902,9 +968,9 @@ void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
DEVLINK_PARAM_CMODE_DRIVERINIT)))
return;
- param_item->driverinit_value = init_val;
+ param_item->driverinit_value = *init_val;
param_item->driverinit_value_valid = true;
- param_item->driverinit_default = init_val;
+ param_item->driverinit_default = *init_val;
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
}
diff --git a/net/devlink/port.c b/net/devlink/port.c
index 485029d43428..1528f2d148df 100644
--- a/net/devlink/port.c
+++ b/net/devlink/port.c
@@ -267,6 +267,8 @@ static int devlink_nl_port_attrs_put(struct sk_buff *msg,
nla_put_u32(msg, DEVLINK_ATTR_PORT_PCI_SF_NUMBER,
attrs->pci_sf.sf))
return -EMSGSIZE;
+ if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_sf.external))
+ return -EMSGSIZE;
break;
case DEVLINK_PORT_FLAVOUR_PHYSICAL:
case DEVLINK_PORT_FLAVOUR_CPU:
@@ -594,7 +596,7 @@ void devlink_ports_notify_unregister(struct devlink *devlink)
int devlink_nl_port_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
+ struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port;
struct sk_buff *msg;
int err;
@@ -830,7 +832,7 @@ static int devlink_port_function_set(struct devlink_port *port,
int devlink_nl_port_set_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
+ struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port;
int err;
if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
@@ -856,8 +858,8 @@ int devlink_nl_port_set_doit(struct sk_buff *skb, struct genl_info *info)
int devlink_nl_port_split_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port;
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
u32 count;
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PORT_SPLIT_COUNT))
@@ -887,8 +889,8 @@ int devlink_nl_port_split_doit(struct sk_buff *skb, struct genl_info *info)
int devlink_nl_port_unsplit_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port;
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
if (!devlink_port->ops->port_unsplit)
return -EOPNOTSUPP;
@@ -899,7 +901,7 @@ int devlink_nl_port_new_doit(struct sk_buff *skb, struct genl_info *info)
{
struct netlink_ext_ack *extack = info->extack;
struct devlink_port_new_attrs new_attrs = {};
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_port *devlink_port;
struct sk_buff *msg;
int err;
@@ -961,9 +963,9 @@ err_out_port_del:
int devlink_nl_port_del_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
+ struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port;
struct netlink_ext_ack *extack = info->extack;
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
if (!devlink_port->ops->port_del)
return -EOPNOTSUPP;
@@ -1529,7 +1531,7 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
WARN_ON(1);
return -EINVAL;
case DEVLINK_PORT_FLAVOUR_PCI_PF:
- if (attrs->pci_pf.external) {
+ if (attrs->pci_pf.external || attrs->pci_pf.controller) {
n = snprintf(name, len, "c%u", attrs->pci_pf.controller);
if (n >= len)
return -EINVAL;
@@ -1539,7 +1541,7 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
break;
case DEVLINK_PORT_FLAVOUR_PCI_VF:
- if (attrs->pci_vf.external) {
+ if (attrs->pci_vf.external || attrs->pci_vf.controller) {
n = snprintf(name, len, "c%u", attrs->pci_vf.controller);
if (n >= len)
return -EINVAL;
@@ -1550,7 +1552,7 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
attrs->pci_vf.pf, attrs->pci_vf.vf);
break;
case DEVLINK_PORT_FLAVOUR_PCI_SF:
- if (attrs->pci_sf.external) {
+ if (attrs->pci_sf.external || attrs->pci_sf.controller) {
n = snprintf(name, len, "c%u", attrs->pci_sf.controller);
if (n >= len)
return -EINVAL;
diff --git a/net/devlink/rate.c b/net/devlink/rate.c
index 41be2d6c2954..e727c8b8b33e 100644
--- a/net/devlink/rate.c
+++ b/net/devlink/rate.c
@@ -30,13 +30,53 @@ devlink_rate_leaf_get_from_info(struct devlink *devlink, struct genl_info *info)
return devlink_rate ?: ERR_PTR(-ENODEV);
}
+/* Repeatedly walks the nested devlink chain while cross device rate nodes are
+ * supported and finds the topmost instance where rates should be stored.
+ * That instance is locked, referenced and returned.
+ * When cross device rate nodes aren't supported the original devlink instance
+ * is returned.
+ */
+static struct devlink *devl_rate_lock(struct devlink *devlink)
+{
+ struct devlink *rate_devlink = devlink, *parent;
+
+ devl_assert_locked(devlink);
+
+ while (rate_devlink->ops &&
+ rate_devlink->ops->supported_cross_device_rate_nodes) {
+ parent = devlink_nested_in_get_lock(rate_devlink);
+ if (!parent)
+ break;
+ if (rate_devlink != devlink) {
+ /* Unlock intermediate instances. */
+ devl_unlock(rate_devlink);
+ devlink_put(rate_devlink);
+ }
+ rate_devlink = parent;
+ }
+ return rate_devlink;
+}
+
+/* Unlocks and puts 'rate devlink' if different than 'devlink'. */
+static void devl_rate_unlock(struct devlink *devlink,
+ struct devlink *rate_devlink)
+{
+ if (devlink == rate_devlink)
+ return;
+
+ devl_unlock(rate_devlink);
+ devlink_put(rate_devlink);
+}
+
static struct devlink_rate *
-devlink_rate_node_get_by_name(struct devlink *devlink, const char *node_name)
+devlink_rate_node_get_by_name(struct devlink *rate_devlink,
+ struct devlink *devlink, const char *node_name)
{
struct devlink_rate *devlink_rate;
- list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
- if (devlink_rate_is_node(devlink_rate) &&
+ list_for_each_entry(devlink_rate, &rate_devlink->rate_list, list) {
+ if (devlink_rate->devlink == devlink &&
+ devlink_rate_is_node(devlink_rate) &&
!strcmp(node_name, devlink_rate->name))
return devlink_rate;
}
@@ -44,7 +84,8 @@ devlink_rate_node_get_by_name(struct devlink *devlink, const char *node_name)
}
static struct devlink_rate *
-devlink_rate_node_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
+devlink_rate_node_get_from_attrs(struct devlink *rate_devlink,
+ struct devlink *devlink, struct nlattr **attrs)
{
const char *rate_node_name;
size_t len;
@@ -57,24 +98,30 @@ devlink_rate_node_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
if (!len || strspn(rate_node_name, "0123456789") == len)
return ERR_PTR(-EINVAL);
- return devlink_rate_node_get_by_name(devlink, rate_node_name);
+ return devlink_rate_node_get_by_name(rate_devlink, devlink,
+ rate_node_name);
}
static struct devlink_rate *
-devlink_rate_node_get_from_info(struct devlink *devlink, struct genl_info *info)
+devlink_rate_node_get_from_info(struct devlink *rate_devlink,
+ struct devlink *devlink,
+ struct genl_info *info)
{
- return devlink_rate_node_get_from_attrs(devlink, info->attrs);
+ return devlink_rate_node_get_from_attrs(rate_devlink, devlink,
+ info->attrs);
}
static struct devlink_rate *
-devlink_rate_get_from_info(struct devlink *devlink, struct genl_info *info)
+devlink_rate_get_from_info(struct devlink *rate_devlink,
+ struct devlink *devlink, struct genl_info *info)
{
struct nlattr **attrs = info->attrs;
if (attrs[DEVLINK_ATTR_PORT_INDEX])
return devlink_rate_leaf_get_from_info(devlink, info);
else if (attrs[DEVLINK_ATTR_RATE_NODE_NAME])
- return devlink_rate_node_get_from_info(devlink, info);
+ return devlink_rate_node_get_from_info(rate_devlink, devlink,
+ info);
else
return ERR_PTR(-EINVAL);
}
@@ -102,6 +149,25 @@ nla_put_failure:
return -EMSGSIZE;
}
+static int devlink_nl_rate_parent_fill(struct sk_buff *msg,
+ struct devlink_rate *devlink_rate)
+{
+ struct devlink_rate *parent = devlink_rate->parent;
+ struct devlink *devlink = parent->devlink;
+
+ if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME,
+ parent->name))
+ return -EMSGSIZE;
+
+ if (devlink != devlink_rate->devlink &&
+ devlink_nl_put_nested_handle(msg,
+ devlink_net(devlink_rate->devlink),
+ devlink, DEVLINK_ATTR_PARENT_DEV))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
static int devlink_nl_rate_fill(struct sk_buff *msg,
struct devlink_rate *devlink_rate,
enum devlink_command cmd, u32 portid, u32 seq,
@@ -146,10 +212,9 @@ static int devlink_nl_rate_fill(struct sk_buff *msg,
devlink_rate->tx_weight))
goto nla_put_failure;
- if (devlink_rate->parent)
- if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME,
- devlink_rate->parent->name))
- goto nla_put_failure;
+ if (devlink_rate->parent &&
+ devlink_nl_rate_parent_fill(msg, devlink_rate))
+ goto nla_put_failure;
if (devlink_rate_put_tc_bws(msg, devlink_rate->tc_bw))
goto nla_put_failure;
@@ -190,17 +255,25 @@ static void devlink_rate_notify(struct devlink_rate *devlink_rate,
void devlink_rates_notify_register(struct devlink *devlink)
{
struct devlink_rate *rate_node;
+ struct devlink *rate_devlink;
- list_for_each_entry(rate_node, &devlink->rate_list, list)
- devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
+ rate_devlink = devl_rate_lock(devlink);
+ list_for_each_entry(rate_node, &rate_devlink->rate_list, list)
+ if (rate_node->devlink == devlink)
+ devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
+ devl_rate_unlock(devlink, rate_devlink);
}
void devlink_rates_notify_unregister(struct devlink *devlink)
{
struct devlink_rate *rate_node;
+ struct devlink *rate_devlink;
- list_for_each_entry_reverse(rate_node, &devlink->rate_list, list)
- devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
+ rate_devlink = devl_rate_lock(devlink);
+ list_for_each_entry_reverse(rate_node, &rate_devlink->rate_list, list)
+ if (rate_node->devlink == devlink)
+ devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
+ devl_rate_unlock(devlink, rate_devlink);
}
static int
@@ -209,17 +282,20 @@ devlink_nl_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
{
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
struct devlink_rate *devlink_rate;
+ struct devlink *rate_devlink;
int idx = 0;
int err = 0;
- list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
+ rate_devlink = devl_rate_lock(devlink);
+ list_for_each_entry(devlink_rate, &rate_devlink->rate_list, list) {
enum devlink_command cmd = DEVLINK_CMD_RATE_NEW;
u32 id = NETLINK_CB(cb->skb).portid;
- if (idx < state->idx) {
+ if (idx < state->idx || devlink_rate->devlink != devlink) {
idx++;
continue;
}
+
err = devlink_nl_rate_fill(msg, devlink_rate, cmd, id,
cb->nlh->nlmsg_seq, flags, NULL);
if (err) {
@@ -228,6 +304,7 @@ devlink_nl_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
}
idx++;
}
+ devl_rate_unlock(devlink, rate_devlink);
return err;
}
@@ -239,28 +316,38 @@ int devlink_nl_rate_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
int devlink_nl_rate_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *rate_devlink, *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_rate *devlink_rate;
struct sk_buff *msg;
int err;
- devlink_rate = devlink_rate_get_from_info(devlink, info);
- if (IS_ERR(devlink_rate))
- return PTR_ERR(devlink_rate);
+ rate_devlink = devl_rate_lock(devlink);
+ devlink_rate = devlink_rate_get_from_info(rate_devlink, devlink, info);
+ if (IS_ERR(devlink_rate)) {
+ err = PTR_ERR(devlink_rate);
+ goto unlock;
+ }
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
+ if (!msg) {
+ err = -ENOMEM;
+ goto unlock;
+ }
err = devlink_nl_rate_fill(msg, devlink_rate, DEVLINK_CMD_RATE_NEW,
info->snd_portid, info->snd_seq, 0,
info->extack);
- if (err) {
- nlmsg_free(msg);
- return err;
- }
+ if (err)
+ goto err_fill;
+ devl_rate_unlock(devlink, rate_devlink);
return genlmsg_reply(msg, info);
+
+err_fill:
+ nlmsg_free(msg);
+unlock:
+ devl_rate_unlock(devlink, rate_devlink);
+ return err;
}
static bool
@@ -277,16 +364,18 @@ devlink_rate_is_parent_node(struct devlink_rate *devlink_rate,
static int
devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
+ struct devlink *rate_devlink,
struct genl_info *info,
struct nlattr *nla_parent)
{
- struct devlink *devlink = devlink_rate->devlink;
+ struct devlink *devlink = devlink_rate->devlink, *parent_devlink;
const char *parent_name = nla_data(nla_parent);
const struct devlink_ops *ops = devlink->ops;
size_t len = strlen(parent_name);
struct devlink_rate *parent;
int err = -EOPNOTSUPP;
+ parent_devlink = devlink_nl_ctx(info)->parent_devlink ? : devlink;
parent = devlink_rate->parent;
if (parent && !len) {
@@ -304,7 +393,14 @@ devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
refcount_dec(&parent->refcnt);
devlink_rate->parent = NULL;
} else if (len) {
- parent = devlink_rate_node_get_by_name(devlink, parent_name);
+ /* parent_devlink (when different than devlink) isn't locked,
+ * but the rate node devlink instance is, so nobody from the
+ * same group of devices sharing rates could change the used
+ * fields or unregister the parent.
+ */
+ parent = devlink_rate_node_get_by_name(rate_devlink,
+ parent_devlink,
+ parent_name);
if (IS_ERR(parent))
return -ENODEV;
@@ -423,6 +519,7 @@ static int devlink_nl_rate_tc_bw_set(struct devlink_rate *devlink_rate,
}
static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
+ struct devlink *rate_devlink,
const struct devlink_ops *ops,
struct genl_info *info)
{
@@ -486,16 +583,20 @@ static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
devlink_rate->tx_weight = weight;
}
- nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
- if (nla_parent) {
- err = devlink_nl_rate_parent_node_set(devlink_rate, info,
- nla_parent);
+ if (attrs[DEVLINK_ATTR_RATE_TC_BWS]) {
+ err = devlink_nl_rate_tc_bw_set(devlink_rate, info);
if (err)
return err;
}
- if (attrs[DEVLINK_ATTR_RATE_TC_BWS]) {
- err = devlink_nl_rate_tc_bw_set(devlink_rate, info);
+ /* Keep parent setting last because it takes a reference. This function
+ * has no rollback, so failing after taking the ref would leak it.
+ */
+ nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
+ if (nla_parent) {
+ err = devlink_nl_rate_parent_node_set(devlink_rate,
+ rate_devlink, info,
+ nla_parent);
if (err)
return err;
}
@@ -585,31 +686,51 @@ static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops,
int devlink_nl_rate_set_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink_nl_ctx *ctx = devlink_nl_ctx(info);
+ struct devlink *devlink = ctx->devlink;
struct devlink_rate *devlink_rate;
const struct devlink_ops *ops;
+ struct devlink *rate_devlink;
int err;
- devlink_rate = devlink_rate_get_from_info(devlink, info);
- if (IS_ERR(devlink_rate))
- return PTR_ERR(devlink_rate);
+ rate_devlink = devl_rate_lock(devlink);
+ devlink_rate = devlink_rate_get_from_info(rate_devlink, devlink, info);
+ if (IS_ERR(devlink_rate)) {
+ err = PTR_ERR(devlink_rate);
+ goto unlock;
+ }
ops = devlink->ops;
- if (!ops || !devlink_rate_set_ops_supported(ops, info, devlink_rate->type))
- return -EOPNOTSUPP;
+ if (!ops ||
+ !devlink_rate_set_ops_supported(ops, info, devlink_rate->type)) {
+ err = -EOPNOTSUPP;
+ goto unlock;
+ }
- err = devlink_nl_rate_set(devlink_rate, ops, info);
+ if (ctx->parent_devlink && ctx->parent_devlink != devlink &&
+ !ops->supported_cross_device_rate_nodes) {
+ NL_SET_ERR_MSG(info->extack,
+ "Cross-device rate parents aren't supported");
+ err = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+ err = devlink_nl_rate_set(devlink_rate, rate_devlink, ops, info);
if (!err)
devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
+unlock:
+ devl_rate_unlock(devlink, rate_devlink);
return err;
}
int devlink_nl_rate_new_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink_nl_ctx *ctx = devlink_nl_ctx(info);
+ struct devlink *devlink = ctx->devlink;
struct devlink_rate *rate_node;
const struct devlink_ops *ops;
+ struct devlink *rate_devlink;
int err;
ops = devlink->ops;
@@ -621,15 +742,29 @@ int devlink_nl_rate_new_doit(struct sk_buff *skb, struct genl_info *info)
if (!devlink_rate_set_ops_supported(ops, info, DEVLINK_RATE_TYPE_NODE))
return -EOPNOTSUPP;
- rate_node = devlink_rate_node_get_from_attrs(devlink, info->attrs);
- if (!IS_ERR(rate_node))
- return -EEXIST;
- else if (rate_node == ERR_PTR(-EINVAL))
- return -EINVAL;
+ if (ctx->parent_devlink && ctx->parent_devlink != devlink &&
+ !ops->supported_cross_device_rate_nodes) {
+ NL_SET_ERR_MSG(info->extack,
+ "Cross-device rate parents aren't supported");
+ return -EOPNOTSUPP;
+ }
+
+ rate_devlink = devl_rate_lock(devlink);
+ rate_node = devlink_rate_node_get_from_attrs(rate_devlink, devlink,
+ info->attrs);
+ if (!IS_ERR(rate_node)) {
+ err = -EEXIST;
+ goto unlock;
+ } else if (rate_node == ERR_PTR(-EINVAL)) {
+ err = -EINVAL;
+ goto unlock;
+ }
rate_node = kzalloc_obj(*rate_node);
- if (!rate_node)
- return -ENOMEM;
+ if (!rate_node) {
+ err = -ENOMEM;
+ goto unlock;
+ }
rate_node->devlink = devlink;
rate_node->type = DEVLINK_RATE_TYPE_NODE;
@@ -643,13 +778,14 @@ int devlink_nl_rate_new_doit(struct sk_buff *skb, struct genl_info *info)
if (err)
goto err_node_new;
- err = devlink_nl_rate_set(rate_node, ops, info);
+ err = devlink_nl_rate_set(rate_node, rate_devlink, ops, info);
if (err)
goto err_rate_set;
refcount_set(&rate_node->refcnt, 1);
- list_add(&rate_node->list, &devlink->rate_list);
+ list_add(&rate_node->list, &rate_devlink->rate_list);
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
+ devl_rate_unlock(devlink, rate_devlink);
return 0;
err_rate_set:
@@ -658,22 +794,29 @@ err_node_new:
kfree(rate_node->name);
err_strdup:
kfree(rate_node);
+unlock:
+ devl_rate_unlock(devlink, rate_devlink);
return err;
}
int devlink_nl_rate_del_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *rate_devlink, *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_rate *rate_node;
int err;
- rate_node = devlink_rate_node_get_from_info(devlink, info);
- if (IS_ERR(rate_node))
- return PTR_ERR(rate_node);
+ rate_devlink = devl_rate_lock(devlink);
+ rate_node = devlink_rate_node_get_from_info(rate_devlink, devlink,
+ info);
+ if (IS_ERR(rate_node)) {
+ err = PTR_ERR(rate_node);
+ goto unlock;
+ }
if (refcount_read(&rate_node->refcnt) > 1) {
NL_SET_ERR_MSG(info->extack, "Node has children. Cannot delete node.");
- return -EBUSY;
+ err = -EBUSY;
+ goto unlock;
}
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
@@ -684,6 +827,8 @@ int devlink_nl_rate_del_doit(struct sk_buff *skb, struct genl_info *info)
list_del(&rate_node->list);
kfree(rate_node->name);
kfree(rate_node);
+unlock:
+ devl_rate_unlock(devlink, rate_devlink);
return err;
}
@@ -692,14 +837,20 @@ int devlink_rates_check(struct devlink *devlink,
struct netlink_ext_ack *extack)
{
struct devlink_rate *devlink_rate;
+ struct devlink *rate_devlink;
+ int err = 0;
- list_for_each_entry(devlink_rate, &devlink->rate_list, list)
- if (!rate_filter || rate_filter(devlink_rate)) {
+ rate_devlink = devl_rate_lock(devlink);
+ list_for_each_entry(devlink_rate, &rate_devlink->rate_list, list)
+ if (devlink_rate->devlink == devlink &&
+ (!rate_filter || rate_filter(devlink_rate))) {
if (extack)
NL_SET_ERR_MSG(extack, "Rate node(s) exists.");
- return -EBUSY;
+ err = -EBUSY;
+ break;
}
- return 0;
+ devl_rate_unlock(devlink, rate_devlink);
+ return err;
}
/**
@@ -716,18 +867,20 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,
struct devlink_rate *parent)
{
struct devlink_rate *rate_node;
-
- rate_node = devlink_rate_node_get_by_name(devlink, node_name);
- if (!IS_ERR(rate_node))
- return ERR_PTR(-EEXIST);
+ struct devlink *rate_devlink;
+
+ rate_devlink = devl_rate_lock(devlink);
+ rate_node = devlink_rate_node_get_by_name(rate_devlink, devlink,
+ node_name);
+ if (!IS_ERR(rate_node)) {
+ rate_node = ERR_PTR(-EEXIST);
+ goto unlock;
+ }
rate_node = kzalloc_obj(*rate_node);
- if (!rate_node)
- return ERR_PTR(-ENOMEM);
-
- if (parent) {
- rate_node->parent = parent;
- refcount_inc(&rate_node->parent->refcnt);
+ if (!rate_node) {
+ rate_node = ERR_PTR(-ENOMEM);
+ goto unlock;
}
rate_node->type = DEVLINK_RATE_TYPE_NODE;
@@ -737,12 +890,20 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,
rate_node->name = kstrdup(node_name, GFP_KERNEL);
if (!rate_node->name) {
kfree(rate_node);
- return ERR_PTR(-ENOMEM);
+ rate_node = ERR_PTR(-ENOMEM);
+ goto unlock;
+ }
+
+ if (parent) {
+ rate_node->parent = parent;
+ refcount_inc(&rate_node->parent->refcnt);
}
refcount_set(&rate_node->refcnt, 1);
- list_add(&rate_node->list, &devlink->rate_list);
+ list_add(&rate_node->list, &rate_devlink->rate_list);
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
+unlock:
+ devl_rate_unlock(devlink, rate_devlink);
return rate_node;
}
EXPORT_SYMBOL_GPL(devl_rate_node_create);
@@ -758,10 +919,10 @@ EXPORT_SYMBOL_GPL(devl_rate_node_create);
int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv,
struct devlink_rate *parent)
{
- struct devlink *devlink = devlink_port->devlink;
+ struct devlink *rate_devlink, *devlink = devlink_port->devlink;
struct devlink_rate *devlink_rate;
- devl_assert_locked(devlink_port->devlink);
+ devl_assert_locked(devlink);
if (WARN_ON(devlink_port->devlink_rate))
return -EBUSY;
@@ -770,6 +931,7 @@ int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv,
if (!devlink_rate)
return -ENOMEM;
+ rate_devlink = devl_rate_lock(devlink);
if (parent) {
devlink_rate->parent = parent;
refcount_inc(&devlink_rate->parent->refcnt);
@@ -779,9 +941,10 @@ int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv,
devlink_rate->devlink = devlink;
devlink_rate->devlink_port = devlink_port;
devlink_rate->priv = priv;
- list_add_tail(&devlink_rate->list, &devlink->rate_list);
+ list_add_tail(&devlink_rate->list, &rate_devlink->rate_list);
devlink_port->devlink_rate = devlink_rate;
devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
+ devl_rate_unlock(devlink, rate_devlink);
return 0;
}
@@ -797,16 +960,19 @@ EXPORT_SYMBOL_GPL(devl_rate_leaf_create);
void devl_rate_leaf_destroy(struct devlink_port *devlink_port)
{
struct devlink_rate *devlink_rate = devlink_port->devlink_rate;
+ struct devlink *rate_devlink, *devlink = devlink_port->devlink;
- devl_assert_locked(devlink_port->devlink);
+ devl_assert_locked(devlink);
if (!devlink_rate)
return;
+ rate_devlink = devl_rate_lock(devlink);
devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_DEL);
if (devlink_rate->parent)
refcount_dec(&devlink_rate->parent->refcnt);
list_del(&devlink_rate->list);
devlink_port->devlink_rate = NULL;
+ devl_rate_unlock(devlink, rate_devlink);
kfree(devlink_rate);
}
EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy);
@@ -815,20 +981,30 @@ EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy);
* devl_rate_nodes_destroy - destroy all devlink rate nodes on device
* @devlink: devlink instance
*
- * Unset parent for all rate objects and destroy all rate nodes
- * on specified device.
+ * Unset parent for all rate objects involving this device and destroy all rate
+ * nodes on it.
*/
void devl_rate_nodes_destroy(struct devlink *devlink)
{
- const struct devlink_ops *ops = devlink->ops;
struct devlink_rate *devlink_rate, *tmp;
+ const struct devlink_ops *ops;
+ struct devlink *rate_devlink;
devl_assert_locked(devlink);
+ rate_devlink = devl_rate_lock(devlink);
- list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
- if (!devlink_rate->parent)
+ list_for_each_entry(devlink_rate, &rate_devlink->rate_list, list) {
+ if (!devlink_rate->parent ||
+ (devlink_rate->devlink != devlink &&
+ devlink_rate->parent->devlink != devlink))
continue;
+ /* This could destroy rate objects on other devlinks in the
+ * same hierarchy under 'rate_devlink'. This is safe because
+ * the shared common ancestor is locked so there can be no
+ * other concurrent rate operations on devlink_rate->devlink.
+ */
+ ops = devlink_rate->devlink->ops;
if (devlink_rate_is_leaf(devlink_rate))
ops->rate_leaf_parent_set(devlink_rate, NULL, devlink_rate->priv,
NULL, NULL);
@@ -839,13 +1015,17 @@ void devl_rate_nodes_destroy(struct devlink *devlink)
refcount_dec(&devlink_rate->parent->refcnt);
devlink_rate->parent = NULL;
}
- list_for_each_entry_safe(devlink_rate, tmp, &devlink->rate_list, list) {
- if (devlink_rate_is_node(devlink_rate)) {
+ ops = devlink->ops;
+ list_for_each_entry_safe(devlink_rate, tmp, &rate_devlink->rate_list,
+ list) {
+ if (devlink_rate->devlink == devlink &&
+ devlink_rate_is_node(devlink_rate)) {
ops->rate_node_del(devlink_rate, devlink_rate->priv, NULL);
list_del(&devlink_rate->list);
kfree(devlink_rate->name);
kfree(devlink_rate);
}
}
+ devl_rate_unlock(devlink, rate_devlink);
}
EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy);
diff --git a/net/devlink/region.c b/net/devlink/region.c
index 5588e3d560b9..537779bbff07 100644
--- a/net/devlink/region.c
+++ b/net/devlink/region.c
@@ -469,7 +469,7 @@ static void devlink_region_snapshot_del(struct devlink_region *region,
int devlink_nl_region_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_port *port = NULL;
struct devlink_region *region;
const char *region_name;
@@ -588,7 +588,7 @@ int devlink_nl_region_get_dumpit(struct sk_buff *skb,
int devlink_nl_region_del_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_snapshot *snapshot;
struct devlink_port *port = NULL;
struct devlink_region *region;
@@ -633,7 +633,7 @@ int devlink_nl_region_del_doit(struct sk_buff *skb, struct genl_info *info)
int devlink_nl_region_new_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_snapshot *snapshot;
struct devlink_port *port = NULL;
struct nlattr *snapshot_id_attr;
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index 3d2f42bc2fb5..c3cfda7ea070 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -117,7 +117,7 @@ devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
int devlink_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_resource *resource;
u64 resource_id;
u64 size;
@@ -251,8 +251,9 @@ static int devlink_resource_list_fill(struct sk_buff *skb,
static int devlink_resource_fill(struct genl_info *info,
enum devlink_command cmd, int flags)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink_nl_ctx *ctx = devlink_nl_ctx(info);
+ struct devlink *devlink = ctx->devlink;
+ struct devlink_port *devlink_port;
struct devlink_resource *resource;
struct list_head *resource_list;
struct nlattr *resources_attr;
@@ -263,6 +264,7 @@ static int devlink_resource_fill(struct genl_info *info,
int i;
int err;
+ devlink_port = ctx->devlink_port;
resource_list = devlink_port ?
&devlink_port->resource_list : &devlink->resource_list;
resource = list_first_entry(resource_list,
@@ -326,10 +328,12 @@ err_resource_put:
int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink_nl_ctx *ctx = devlink_nl_ctx(info);
+ struct devlink *devlink = ctx->devlink;
+ struct devlink_port *devlink_port;
struct list_head *resource_list;
+ devlink_port = ctx->devlink_port;
if (info->attrs[DEVLINK_ATTR_PORT_INDEX] && !devlink_port)
return -ENODEV;
@@ -486,6 +490,8 @@ __devl_resource_register(struct devlink *devlink,
struct list_head *resource_list;
bool top_hierarchy;
+ WARN_ON(resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP);
+
lockdep_assert_held(&devlink->lock);
top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
diff --git a/net/devlink/sb.c b/net/devlink/sb.c
index 49fcbfe08f15..129bd016e302 100644
--- a/net/devlink/sb.c
+++ b/net/devlink/sb.c
@@ -204,7 +204,7 @@ nla_put_failure:
int devlink_nl_sb_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_sb *devlink_sb;
struct sk_buff *msg;
int err;
@@ -306,7 +306,7 @@ nla_put_failure:
int devlink_nl_sb_pool_get_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_sb *devlink_sb;
struct sk_buff *msg;
u16 pool_index;
@@ -415,7 +415,7 @@ static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
int devlink_nl_sb_pool_set_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
enum devlink_sb_threshold_type threshold_type;
struct devlink_sb *devlink_sb;
u16 pool_index;
@@ -506,7 +506,7 @@ sb_occ_get_failure:
int devlink_nl_sb_port_pool_get_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
+ struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port;
struct devlink *devlink = devlink_port->devlink;
struct devlink_sb *devlink_sb;
struct sk_buff *msg;
@@ -624,8 +624,8 @@ static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
int devlink_nl_sb_port_pool_set_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port;
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_sb *devlink_sb;
u16 pool_index;
u32 threshold;
@@ -716,7 +716,7 @@ nla_put_failure:
int devlink_nl_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
+ struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port;
struct devlink *devlink = devlink_port->devlink;
struct devlink_sb *devlink_sb;
struct sk_buff *msg;
@@ -864,8 +864,8 @@ static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
int devlink_nl_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink_port *devlink_port = devlink_nl_ctx(info)->devlink_port;
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
enum devlink_sb_pool_type pool_type;
struct devlink_sb *devlink_sb;
u16 tc_index;
@@ -902,7 +902,7 @@ int devlink_nl_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
int devlink_nl_sb_occ_snapshot_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
const struct devlink_ops *ops = devlink->ops;
struct devlink_sb *devlink_sb;
@@ -918,7 +918,7 @@ int devlink_nl_sb_occ_snapshot_doit(struct sk_buff *skb, struct genl_info *info)
int devlink_nl_sb_occ_max_clear_doit(struct sk_buff *skb,
struct genl_info *info)
{
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
const struct devlink_ops *ops = devlink->ops;
struct devlink_sb *devlink_sb;
diff --git a/net/devlink/trap.c b/net/devlink/trap.c
index 8edb31654a68..793ffc66dc11 100644
--- a/net/devlink/trap.c
+++ b/net/devlink/trap.c
@@ -302,7 +302,7 @@ nla_put_failure:
int devlink_nl_trap_get_doit(struct sk_buff *skb, struct genl_info *info)
{
struct netlink_ext_ack *extack = info->extack;
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_trap_item *trap_item;
struct sk_buff *msg;
int err;
@@ -412,7 +412,7 @@ static int devlink_trap_action_set(struct devlink *devlink,
int devlink_nl_trap_set_doit(struct sk_buff *skb, struct genl_info *info)
{
struct netlink_ext_ack *extack = info->extack;
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_trap_item *trap_item;
if (list_empty(&devlink->trap_list))
@@ -511,7 +511,7 @@ nla_put_failure:
int devlink_nl_trap_group_get_doit(struct sk_buff *skb, struct genl_info *info)
{
struct netlink_ext_ack *extack = info->extack;
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_trap_group_item *group_item;
struct sk_buff *msg;
int err;
@@ -682,7 +682,7 @@ static int devlink_trap_group_set(struct devlink *devlink,
int devlink_nl_trap_group_set_doit(struct sk_buff *skb, struct genl_info *info)
{
struct netlink_ext_ack *extack = info->extack;
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct devlink_trap_group_item *group_item;
bool modified = false;
int err;
@@ -804,7 +804,7 @@ int devlink_nl_trap_policer_get_doit(struct sk_buff *skb,
{
struct devlink_trap_policer_item *policer_item;
struct netlink_ext_ack *extack = info->extack;
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
struct sk_buff *msg;
int err;
@@ -924,7 +924,7 @@ int devlink_nl_trap_policer_set_doit(struct sk_buff *skb,
{
struct devlink_trap_policer_item *policer_item;
struct netlink_ext_ack *extack = info->extack;
- struct devlink *devlink = info->user_ptr[0];
+ struct devlink *devlink = devlink_nl_ctx(info)->devlink;
if (list_empty(&devlink->trap_policer_list))
return -EOPNOTSUPP;