Allow privileged user to get the HW address of a vdev.

Example:

$ devlink vdev show pci/0000:03:00.0/1
pci/0000:03:00.0/1: flavour pcivf pf 0 vf 0 port_index 1 hw_addr 
00:23:35:af:35:34

$ devlink vdev show pci/0000:03:00.0/1 -pj
{
    "vdev": {
        "pci/0000:03:00.0/1": {
            "flavour": "pcivf",
            "pf": 0,
            "vf": 0,
            "port_index": 1,
            "hw_addr": "00:23:35:af:35:34"
        }
    }
}

Signed-off-by: Yuval Avnery <yuva...@mellanox.com>
Acked-by: Jiri Pirko <j...@mellanox.com>
---
 include/net/devlink.h        |  3 +++
 include/uapi/linux/devlink.h |  1 +
 net/core/devlink.c           | 33 +++++++++++++++++++++++++++------
 3 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/include/net/devlink.h b/include/net/devlink.h
index 138d33275963..12550cc92e9d 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -765,6 +765,9 @@ struct devlink_ops {
 };
 
 struct devlink_vdev_ops {
+       int (*hw_addr_get)(struct devlink_vdev *vdev,
+                          u8 *hw_addr, struct netlink_ext_ack *extack);
+       unsigned int hw_addr_len;
 };
 
 static inline void *devlink_priv(struct devlink *devlink)
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 161bad54d528..2f2c2d60796f 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -439,6 +439,7 @@ enum devlink_attr {
        DEVLINK_ATTR_VDEV_FLAVOUR,              /* u16 */
        DEVLINK_ATTR_VDEV_PF_INDEX,             /* u32 */
        DEVLINK_ATTR_VDEV_VF_INDEX,             /* u32 */
+       DEVLINK_ATTR_VDEV_HW_ADDR,              /* binary */
 
        /* add new attributes above here, update the policy in devlink.c */
 
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 2fffbd37e710..94599409f12c 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -711,10 +711,13 @@ static void devlink_port_notify(struct devlink_port 
*devlink_port,
 static int devlink_nl_vdev_fill(struct sk_buff *msg, struct devlink *devlink,
                                struct devlink_vdev *devlink_vdev,
                                enum devlink_command cmd, u32 vdevid,
-                               u32 seq, int flags)
+                               u32 seq, int flags,
+                               struct netlink_ext_ack *extack)
 {
        struct devlink_vdev_attrs *attrs = &devlink_vdev->attrs;
+       const struct devlink_vdev_ops *ops = devlink_vdev->ops;
        void *hdr;
+       int err;
 
        hdr = genlmsg_put(msg, vdevid, seq, &devlink_nl_family, flags, cmd);
        if (!hdr)
@@ -748,6 +751,19 @@ static int devlink_nl_vdev_fill(struct sk_buff *msg, 
struct devlink *devlink,
                                devlink_vdev->devlink_port->index))
                        goto nla_put_failure;
 
+       if (ops && ops->hw_addr_get) {
+               u8 hw_addr[MAX_ADDR_LEN];
+
+               err = ops->hw_addr_get(devlink_vdev, hw_addr, extack);
+               if (err) {
+                       genlmsg_cancel(msg, hdr);
+                       return err;
+               }
+               if (nla_put(msg, DEVLINK_ATTR_VDEV_HW_ADDR,
+                           ops->hw_addr_len, hw_addr))
+                       goto nla_put_failure;
+       }
+
        genlmsg_end(msg, hdr);
        return 0;
 
@@ -769,7 +785,8 @@ static void devlink_vdev_notify(struct devlink_vdev 
*devlink_vdev,
        if (!msg)
                return;
 
-       err = devlink_nl_vdev_fill(msg, devlink, devlink_vdev, cmd, 0, 0, 0);
+       err = devlink_nl_vdev_fill(msg, devlink, devlink_vdev, cmd,
+                                  0, 0, 0, NULL);
        if (err) {
                nlmsg_free(msg);
                return;
@@ -992,8 +1009,8 @@ static int devlink_nl_cmd_vdev_get_doit(struct sk_buff 
*skb,
                return -ENOMEM;
 
        err = devlink_nl_vdev_fill(msg, devlink, devlink_vdev,
-                                  DEVLINK_CMD_VDEV_NEW,
-                                  info->snd_portid, info->snd_seq, 0);
+                                  DEVLINK_CMD_VDEV_NEW, info->snd_portid,
+                                  info->snd_seq, 0, info->extack);
        if (err) {
                nlmsg_free(msg);
                return err;
@@ -1009,7 +1026,7 @@ static int devlink_nl_cmd_vdev_get_dumpit(struct sk_buff 
*msg,
        struct devlink *devlink;
        int start = cb->args[0];
        int idx = 0;
-       int err;
+       int err = 0;
 
        mutex_lock(&devlink_mutex);
        list_for_each_entry(devlink, &devlink_list, list) {
@@ -1025,7 +1042,7 @@ static int devlink_nl_cmd_vdev_get_dumpit(struct sk_buff 
*msg,
                                                   DEVLINK_CMD_NEW,
                                                   NETLINK_CB(cb->skb).portid,
                                                   cb->nlh->nlmsg_seq,
-                                                  NLM_F_MULTI);
+                                                  NLM_F_MULTI, NULL);
                        if (err) {
                                mutex_unlock(&devlink->lock);
                                goto out;
@@ -1036,6 +1053,8 @@ static int devlink_nl_cmd_vdev_get_dumpit(struct sk_buff 
*msg,
        }
 out:
        mutex_unlock(&devlink_mutex);
+       if (err != -EMSGSIZE)
+               return err;
 
        cb->args[0] = idx;
        return msg->len;
@@ -6109,6 +6128,8 @@ static const struct nla_policy 
devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
        [DEVLINK_ATTR_VDEV_FLAVOUR] = { .type = NLA_U16 },
        [DEVLINK_ATTR_VDEV_PF_INDEX] = { .type = NLA_U32 },
        [DEVLINK_ATTR_VDEV_VF_INDEX] = { .type = NLA_U32 },
+       [DEVLINK_ATTR_VDEV_HW_ADDR] = { .type = NLA_BINARY,
+                                       .len = MAX_ADDR_LEN },
 };
 
 static const struct genl_ops devlink_nl_ops[] = {
-- 
2.17.1

Reply via email to