devlink: add version reporting to devlink info API
authorJakub Kicinski <jakub.kicinski@netronome.com>
Thu, 31 Jan 2019 18:50:41 +0000 (10:50 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 1 Feb 2019 23:30:30 +0000 (15:30 -0800)
ethtool -i has a few fixed-size fields which can be used to report
firmware version and expansion ROM version. Unfortunately, modern
hardware has more firmware components. There is usually some
datapath microcode, management controller, PXE drivers, and a
CPLD load. Running ethtool -i on modern controllers reveals the
fact that vendors cram multiple values into firmware version field.

Here are some examples from systems I could lay my hands on quickly:

tg3:  "FFV20.2.17 bc 5720-v1.39"
i40e: "6.01 0x800034a4 1.1747.0"
nfp:  "0.0.3.5 0.25 sriov-2.1.16 nic"

Add a new devlink API to allow retrieving multiple versions, and
provide user-readable name for those versions.

While at it break down the versions into three categories:
 - fixed - this is the board/fixed component version, usually vendors
           report information like the board version in the PCI VPD,
           but it will benefit from naming and common API as well;
 - running - this is the running firmware version;
 - stored - this is firmware in the flash, after firmware update
            this value will reflect the flashed version, while the
            running version may only be updated after reboot.

v3:
 - add per-type helpers instead of using the special argument (Jiri).
RFCv2:
 - remove the nesting in attr DEVLINK_ATTR_INFO_VERSIONS (now
   versions are mixed with other info attrs)l
 - have the driver report versions from the same callback as
   other info.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/devlink.h
include/uapi/linux/devlink.h
net/core/devlink.c

index a6d0a530483d41f1dd2b7a5fdbbb15243bc03217..6dc0ef964392a3e365a7e66c9ba4a3a895dc4468 100644 (file)
@@ -614,6 +614,15 @@ int devlink_info_serial_number_put(struct devlink_info_req *req,
                                   const char *sn);
 int devlink_info_driver_name_put(struct devlink_info_req *req,
                                 const char *name);
+int devlink_info_version_fixed_put(struct devlink_info_req *req,
+                                  const char *version_name,
+                                  const char *version_value);
+int devlink_info_version_stored_put(struct devlink_info_req *req,
+                                   const char *version_name,
+                                   const char *version_value);
+int devlink_info_version_running_put(struct devlink_info_req *req,
+                                    const char *version_name,
+                                    const char *version_value);
 
 #else
 
@@ -923,6 +932,30 @@ devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
 {
        return 0;
 }
+
+static inline int
+devlink_info_version_fixed_put(struct devlink_info_req *req,
+                              const char *version_name,
+                              const char *version_value)
+{
+       return 0;
+}
+
+static inline int
+devlink_info_version_stored_put(struct devlink_info_req *req,
+                               const char *version_name,
+                               const char *version_value)
+{
+       return 0;
+}
+
+static inline int
+devlink_info_version_running_put(struct devlink_info_req *req,
+                                const char *version_name,
+                                const char *version_value)
+{
+       return 0;
+}
 #endif
 
 #endif /* _NET_DEVLINK_H_ */
index 142710d450930424cc5afeb87d84c483a36ec29d..7fffd879c32876af0d831f7a5896ac3c46270fbf 100644 (file)
@@ -294,6 +294,11 @@ enum devlink_attr {
 
        DEVLINK_ATTR_INFO_DRIVER_NAME,          /* string */
        DEVLINK_ATTR_INFO_SERIAL_NUMBER,        /* string */
+       DEVLINK_ATTR_INFO_VERSION_FIXED,        /* nested */
+       DEVLINK_ATTR_INFO_VERSION_RUNNING,      /* nested */
+       DEVLINK_ATTR_INFO_VERSION_STORED,       /* nested */
+       DEVLINK_ATTR_INFO_VERSION_NAME,         /* string */
+       DEVLINK_ATTR_INFO_VERSION_VALUE,        /* string */
 
        /* add new attributes above here, update the policy in devlink.c */
 
index f456f6aa3d402673a427c6bca94dfa3a14b2ffdf..e31b6d617837051f5af9cb3be334aa568af37945 100644 (file)
@@ -3730,6 +3730,63 @@ int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
 }
 EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
 
+static int devlink_info_version_put(struct devlink_info_req *req, int attr,
+                                   const char *version_name,
+                                   const char *version_value)
+{
+       struct nlattr *nest;
+       int err;
+
+       nest = nla_nest_start(req->msg, attr);
+       if (!nest)
+               return -EMSGSIZE;
+
+       err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
+                            version_name);
+       if (err)
+               goto nla_put_failure;
+
+       err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
+                            version_value);
+       if (err)
+               goto nla_put_failure;
+
+       nla_nest_end(req->msg, nest);
+
+       return 0;
+
+nla_put_failure:
+       nla_nest_cancel(req->msg, nest);
+       return err;
+}
+
+int devlink_info_version_fixed_put(struct devlink_info_req *req,
+                                  const char *version_name,
+                                  const char *version_value)
+{
+       return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
+                                       version_name, version_value);
+}
+EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
+
+int devlink_info_version_stored_put(struct devlink_info_req *req,
+                                   const char *version_name,
+                                   const char *version_value)
+{
+       return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
+                                       version_name, version_value);
+}
+EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
+
+int devlink_info_version_running_put(struct devlink_info_req *req,
+                                    const char *version_name,
+                                    const char *version_value)
+{
+       return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
+                                       version_name, version_value);
+}
+EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
+
 static int
 devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
                     enum devlink_command cmd, u32 portid,