devlink: introduce line card info get message
authorJiri Pirko <jiri@nvidia.com>
Mon, 25 Apr 2022 03:44:22 +0000 (06:44 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 25 Apr 2022 09:42:28 +0000 (10:42 +0100)
Allow the driver to provide per line card info get op to fill-up info,
similar to the "devlink dev info".

Example:

$ devlink lc info pci/0000:01:00.0 lc 8
pci/0000:01:00.0:
  lc 8
    versions:
        fixed:
          hw.revision 0
        running:
          ini.version 4

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/networking/devlink/devlink-linecard.rst
include/net/devlink.h
include/uapi/linux/devlink.h
net/core/devlink.c

index 6c0b8928bc130cbe32094566cf9707d2fd71eae5..5a8d5989702af375f84d0aa0865a82d3d290f491 100644 (file)
@@ -14,6 +14,7 @@ system. Following operations are provided:
   * Get a list of supported line card types.
   * Provision of a slot with specific line card type.
   * Get and monitor of line card state and its change.
+  * Get information about line card versions.
 
 Line card according to the type may contain one or more gearboxes
 to mux the lanes with certain speed to multiple ports with lanes
@@ -120,3 +121,6 @@ Example usage
 
     # Set slot 8 to be unprovisioned:
     $ devlink lc set pci/0000:01:00.0 lc 8 notype
+
+    # Set info for slot 8:
+    $ devlink lc info pci/0000:01:00.0 lc 8
index c84b52fb9ff0be63d35c964e15effa114ccef853..f96dcb37663081ea05c561fcabbe232c6a8b4d1a 100644 (file)
@@ -150,6 +150,8 @@ struct devlink_port_new_attrs {
           sfnum_valid:1;
 };
 
+struct devlink_info_req;
+
 /**
  * struct devlink_linecard_ops - Linecard operations
  * @provision: callback to provision the linecard slot with certain
@@ -168,6 +170,7 @@ struct devlink_port_new_attrs {
  *                  provisioned.
  * @types_count: callback to get number of supported types
  * @types_get: callback to get next type in list
+ * @info_get: callback to get linecard info
  */
 struct devlink_linecard_ops {
        int (*provision)(struct devlink_linecard *linecard, void *priv,
@@ -182,6 +185,9 @@ struct devlink_linecard_ops {
        void (*types_get)(struct devlink_linecard *linecard,
                          void *priv, unsigned int index, const char **type,
                          const void **type_priv);
+       int (*info_get)(struct devlink_linecard *linecard, void *priv,
+                       struct devlink_info_req *req,
+                       struct netlink_ext_ack *extack);
 };
 
 struct devlink_sb_pool_info {
@@ -628,7 +634,6 @@ struct devlink_flash_update_params {
 #define DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK    BIT(1)
 
 struct devlink_region;
-struct devlink_info_req;
 
 /**
  * struct devlink_region_ops - Region operations
index cd578645f94f274aeeb050777f2678431ffc3ee7..fb8c3864457f98cd72d89d759399f80c0b4c6bd4 100644 (file)
@@ -136,6 +136,8 @@ enum devlink_command {
        DEVLINK_CMD_LINECARD_NEW,
        DEVLINK_CMD_LINECARD_DEL,
 
+       DEVLINK_CMD_LINECARD_INFO_GET,          /* can dump */
+
        /* add new commands above here */
        __DEVLINK_CMD_MAX,
        DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
index 41d9631ceada24a4ea7caf8a0cc8755ccbb22f43..5facd10de64a90bb15da0f5add2dc19a3b043966 100644 (file)
@@ -2424,6 +2424,125 @@ static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
        return 0;
 }
 
+struct devlink_info_req {
+       struct sk_buff *msg;
+};
+
+static int
+devlink_nl_linecard_info_fill(struct sk_buff *msg, struct devlink *devlink,
+                             struct devlink_linecard *linecard,
+                             enum devlink_command cmd, u32 portid,
+                             u32 seq, int flags, struct netlink_ext_ack *extack)
+{
+       struct devlink_info_req req;
+       void *hdr;
+       int err;
+
+       hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
+       if (!hdr)
+               return -EMSGSIZE;
+
+       err = -EMSGSIZE;
+       if (devlink_nl_put_handle(msg, devlink))
+               goto nla_put_failure;
+       if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
+               goto nla_put_failure;
+
+       req.msg = msg;
+       err = linecard->ops->info_get(linecard, linecard->priv, &req, extack);
+       if (err)
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+       return 0;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return err;
+}
+
+static int devlink_nl_cmd_linecard_info_get_doit(struct sk_buff *skb,
+                                                struct genl_info *info)
+{
+       struct devlink_linecard *linecard = info->user_ptr[1];
+       struct devlink *devlink = linecard->devlink;
+       struct sk_buff *msg;
+       int err;
+
+       if (!linecard->ops->info_get)
+               return -EOPNOTSUPP;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       mutex_lock(&linecard->state_lock);
+       err = devlink_nl_linecard_info_fill(msg, devlink, linecard,
+                                           DEVLINK_CMD_LINECARD_INFO_GET,
+                                           info->snd_portid, info->snd_seq, 0,
+                                           info->extack);
+       mutex_unlock(&linecard->state_lock);
+       if (err) {
+               nlmsg_free(msg);
+               return err;
+       }
+
+       return genlmsg_reply(msg, info);
+}
+
+static int devlink_nl_cmd_linecard_info_get_dumpit(struct sk_buff *msg,
+                                                  struct netlink_callback *cb)
+{
+       struct devlink_linecard *linecard;
+       struct devlink *devlink;
+       int start = cb->args[0];
+       unsigned long index;
+       int idx = 0;
+       int err = 0;
+
+       mutex_lock(&devlink_mutex);
+       xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
+               if (!devlink_try_get(devlink))
+                       continue;
+
+               if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
+                       goto retry;
+
+               mutex_lock(&devlink->linecards_lock);
+               list_for_each_entry(linecard, &devlink->linecard_list, list) {
+                       if (idx < start || !linecard->ops->info_get) {
+                               idx++;
+                               continue;
+                       }
+                       mutex_lock(&linecard->state_lock);
+                       err = devlink_nl_linecard_info_fill(msg, devlink, linecard,
+                                                           DEVLINK_CMD_LINECARD_INFO_GET,
+                                                           NETLINK_CB(cb->skb).portid,
+                                                           cb->nlh->nlmsg_seq,
+                                                           NLM_F_MULTI,
+                                                           cb->extack);
+                       mutex_unlock(&linecard->state_lock);
+                       if (err) {
+                               mutex_unlock(&devlink->linecards_lock);
+                               devlink_put(devlink);
+                               goto out;
+                       }
+                       idx++;
+               }
+               mutex_unlock(&devlink->linecards_lock);
+retry:
+               devlink_put(devlink);
+       }
+out:
+       mutex_unlock(&devlink_mutex);
+
+       if (err != -EMSGSIZE)
+               return err;
+
+       cb->args[0] = idx;
+       return msg->len;
+}
+
 static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
                              struct devlink_sb *devlink_sb,
                              enum devlink_command cmd, u32 portid,
@@ -6416,10 +6535,6 @@ out_dev:
        return err;
 }
 
-struct devlink_info_req {
-       struct sk_buff *msg;
-};
-
 int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
 {
        return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
@@ -9139,6 +9254,13 @@ static const struct genl_small_ops devlink_nl_ops[] = {
                .flags = GENL_ADMIN_PERM,
                .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
        },
+       {
+               .cmd = DEVLINK_CMD_LINECARD_INFO_GET,
+               .doit = devlink_nl_cmd_linecard_info_get_doit,
+               .dumpit = devlink_nl_cmd_linecard_info_get_dumpit,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
+               /* can be retrieved by unprivileged users */
+       },
        {
                .cmd = DEVLINK_CMD_SB_GET,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,