Skip to content

Commit

Permalink
Merge branch 'devlink-kernel-region-snapshot-id-allocation'
Browse files Browse the repository at this point in the history
Jakub Kicinski says:

====================
devlink: kernel region snapshot id allocation

currently users have to find a free snapshot id to pass
to the kernel when they are requesting a snapshot to be
taken.

This set extends the kernel so it can allocate the id
on its own and send it back to user space in a response.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 4, 2020
2 parents 39d0105 + aebbd7d commit 1248dc0
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 26 deletions.
11 changes: 9 additions & 2 deletions Documentation/networking/devlink/devlink-region.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Region snapshots are collected by the driver, and can be accessed via read
or dump commands. This allows future analysis on the created snapshots.
Regions may optionally support triggering snapshots on demand.

Snapshot identifiers are scoped to the devlink instance, not a region.
All snapshots with the same snapshot id within a devlink instance
correspond to the same event.

The major benefit to creating a region is to provide access to internal
address regions that are otherwise inaccessible to the user.

Expand All @@ -23,7 +27,9 @@ states, but see also :doc:`devlink-health`
Regions may optionally support capturing a snapshot on demand via the
``DEVLINK_CMD_REGION_NEW`` netlink message. A driver wishing to allow
requested snapshots must implement the ``.snapshot`` callback for the region
in its ``devlink_region_ops`` structure.
in its ``devlink_region_ops`` structure. If snapshot id is not set in
the ``DEVLINK_CMD_REGION_NEW`` request kernel will allocate one and send
the snapshot information to user space.

example usage
-------------
Expand All @@ -45,7 +51,8 @@ example usage
$ devlink region del pci/0000:00:05.0/cr-space snapshot 1
# Request an immediate snapshot, if supported by the region
$ devlink region new pci/0000:00:05.0/cr-space snapshot 5
$ devlink region new pci/0000:00:05.0/cr-space
pci/0000:00:05.0/cr-space: snapshot 5
# Dump a snapshot:
$ devlink region dump pci/0000:00:05.0/fw-health snapshot 1
Expand Down
96 changes: 72 additions & 24 deletions net/core/devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -3716,24 +3716,26 @@ static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
return err;
}

static void devlink_nl_region_notify(struct devlink_region *region,
struct devlink_snapshot *snapshot,
enum devlink_command cmd)
static struct sk_buff *
devlink_nl_region_notify_build(struct devlink_region *region,
struct devlink_snapshot *snapshot,
enum devlink_command cmd, u32 portid, u32 seq)
{
struct devlink *devlink = region->devlink;
struct sk_buff *msg;
void *hdr;
int err;

WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);

msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return;
return ERR_PTR(-ENOMEM);

hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
if (!hdr)
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
if (!hdr) {
err = -EMSGSIZE;
goto out_free_msg;
}

err = devlink_nl_put_handle(msg, devlink);
if (err)
Expand All @@ -3757,15 +3759,30 @@ static void devlink_nl_region_notify(struct devlink_region *region,
}
genlmsg_end(msg, hdr);

genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);

return;
return msg;

out_cancel_msg:
genlmsg_cancel(msg, hdr);
out_free_msg:
nlmsg_free(msg);
return ERR_PTR(err);
}

static void devlink_nl_region_notify(struct devlink_region *region,
struct devlink_snapshot *snapshot,
enum devlink_command cmd)
{
struct devlink *devlink = region->devlink;
struct sk_buff *msg;

WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);

msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
if (IS_ERR(msg))
return;

genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
}

/**
Expand Down Expand Up @@ -4069,6 +4086,8 @@ static int
devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
{
struct devlink *devlink = info->user_ptr[0];
struct devlink_snapshot *snapshot;
struct nlattr *snapshot_id_attr;
struct devlink_region *region;
const char *region_name;
u32 snapshot_id;
Expand All @@ -4080,11 +4099,6 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}

if (!info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
NL_SET_ERR_MSG_MOD(info->extack, "No snapshot id provided");
return -EINVAL;
}

region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
region = devlink_region_get_by_name(devlink, region_name);
if (!region) {
Expand All @@ -4102,16 +4116,25 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
return -ENOSPC;
}

snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
if (snapshot_id_attr) {
snapshot_id = nla_get_u32(snapshot_id_attr);

if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
return -EEXIST;
}
if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
return -EEXIST;
}

err = __devlink_snapshot_id_insert(devlink, snapshot_id);
if (err)
return err;
err = __devlink_snapshot_id_insert(devlink, snapshot_id);
if (err)
return err;
} else {
err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
if (err) {
NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
return err;
}
}

err = region->ops->snapshot(devlink, info->extack, &data);
if (err)
Expand All @@ -4121,13 +4144,38 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
if (err)
goto err_snapshot_create;

if (!snapshot_id_attr) {
struct sk_buff *msg;

snapshot = devlink_region_snapshot_get_by_id(region,
snapshot_id);
if (WARN_ON(!snapshot))
return -EINVAL;

msg = devlink_nl_region_notify_build(region, snapshot,
DEVLINK_CMD_REGION_NEW,
info->snd_portid,
info->snd_seq);
err = PTR_ERR_OR_ZERO(msg);
if (err)
goto err_notify;

err = genlmsg_reply(msg, info);
if (err)
goto err_notify;
}

return 0;

err_snapshot_create:
region->ops->destructor(data);
err_snapshot_capture:
__devlink_snapshot_id_decrement(devlink, snapshot_id);
return err;

err_notify:
devlink_region_snapshot_del(region, snapshot);
return err;
}

static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
Expand Down
13 changes: 13 additions & 0 deletions tools/testing/selftests/drivers/net/netdevsim/devlink.sh
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,19 @@ regions_test()

check_region_snapshot_count dummy post-second-delete 2

sid=$(devlink -j region new $DL_HANDLE/dummy | jq '.[][][][]')
check_err $? "Failed to create a new snapshot with id allocated by the kernel"

check_region_snapshot_count dummy post-first-request 3

devlink region dump $DL_HANDLE/dummy snapshot $sid >> /dev/null
check_err $? "Failed to dump a snapshot with id allocated by the kernel"

devlink region del $DL_HANDLE/dummy snapshot $sid
check_err $? "Failed to delete snapshot with id allocated by the kernel"

check_region_snapshot_count dummy post-first-request 2

log_test "regions test"
}

Expand Down

0 comments on commit 1248dc0

Please sign in to comment.