netlink: add support for ext_ack missing attributes
authorJakub Kicinski <kuba@kernel.org>
Fri, 26 Aug 2022 03:09:31 +0000 (20:09 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 30 Aug 2022 10:20:43 +0000 (12:20 +0200)
There is currently no way to report via extack in a structured way
that an attribute is missing. This leads to families resorting to
string messages.

Add a pair of attributes - @offset and @type for machine-readable
way of reporting missing attributes. The @offset points to the
nest which should have contained the attribute, @type is the
expected nla_type. The offset will be skipped if the attribute
is missing at the message level rather than inside a nest.

User space should be able to figure out which attribute enum
(AKA attribute space AKA attribute set) the nest pointed to by
@offset is using.

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Documentation/userspace-api/netlink/intro.rst
include/linux/netlink.h
include/uapi/linux/netlink.h
net/netlink/af_netlink.c

index 94337f7..8f12207 100644 (file)
@@ -359,8 +359,8 @@ compatibility this feature has to be explicitly enabled by setting
 the ``NETLINK_EXT_ACK`` setsockopt() to ``1``.
 
 Types of extended ack attributes are defined in enum nlmsgerr_attrs.
-The two most commonly used attributes are ``NLMSGERR_ATTR_MSG``
-and ``NLMSGERR_ATTR_OFFS``.
+The most commonly used attributes are ``NLMSGERR_ATTR_MSG``,
+``NLMSGERR_ATTR_OFFS`` and ``NLMSGERR_ATTR_MISS_*``.
 
 ``NLMSGERR_ATTR_MSG`` carries a message in English describing
 the encountered problem. These messages are far more detailed
@@ -368,6 +368,9 @@ than what can be expressed thru standard UNIX error codes.
 
 ``NLMSGERR_ATTR_OFFS`` points to the attribute which caused the problem.
 
+``NLMSGERR_ATTR_MISS_TYPE`` and ``NLMSGERR_ATTR_MISS_NEST``
+inform about a missing attribute.
+
 Extended ACKs can be reported on errors as well as in case of success.
 The latter should be treated as a warning.
 
index bda1c38..1619221 100644 (file)
@@ -71,6 +71,8 @@ netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
  *     %NL_SET_ERR_MSG
  * @bad_attr: attribute with error
  * @policy: policy for a bad attribute
+ * @miss_type: attribute type which was missing
+ * @miss_nest: nest missing an attribute (%NULL if missing top level attr)
  * @cookie: cookie data to return to userspace (for success)
  * @cookie_len: actual cookie data length
  */
@@ -78,6 +80,8 @@ struct netlink_ext_ack {
        const char *_msg;
        const struct nlattr *bad_attr;
        const struct nla_policy *policy;
+       const struct nlattr *miss_nest;
+       u16 miss_type;
        u8 cookie[NETLINK_MAX_COOKIE_LEN];
        u8 cookie_len;
 };
@@ -126,6 +130,15 @@ struct netlink_ext_ack {
 #define NL_SET_ERR_MSG_ATTR(extack, attr, msg)         \
        NL_SET_ERR_MSG_ATTR_POL(extack, attr, NULL, msg)
 
+#define NL_SET_ERR_ATTR_MISS(extack, nest, type)  do { \
+       struct netlink_ext_ack *__extack = (extack);    \
+                                                       \
+       if (__extack) {                                 \
+               __extack->miss_nest = (nest);           \
+               __extack->miss_type = (type);           \
+       }                                               \
+} while (0)
+
 static inline void nl_set_extack_cookie_u64(struct netlink_ext_ack *extack,
                                            u64 cookie)
 {
index e0ab261..e0689db 100644 (file)
@@ -140,6 +140,10 @@ struct nlmsgerr {
  *     be used - in the success case - to identify a created
  *     object or operation or similar (binary)
  * @NLMSGERR_ATTR_POLICY: policy for a rejected attribute
+ * @NLMSGERR_ATTR_MISS_TYPE: type of a missing required attribute,
+ *     %NLMSGERR_ATTR_MISS_NEST will not be present if the attribute was
+ *     missing at the message level
+ * @NLMSGERR_ATTR_MISS_NEST: offset of the nest where attribute was missing
  * @__NLMSGERR_ATTR_MAX: number of attributes
  * @NLMSGERR_ATTR_MAX: highest attribute number
  */
@@ -149,6 +153,8 @@ enum nlmsgerr_attrs {
        NLMSGERR_ATTR_OFFS,
        NLMSGERR_ATTR_COOKIE,
        NLMSGERR_ATTR_POLICY,
+       NLMSGERR_ATTR_MISS_TYPE,
+       NLMSGERR_ATTR_MISS_NEST,
 
        __NLMSGERR_ATTR_MAX,
        NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
index 7eae157..f89ba30 100644 (file)
@@ -2423,6 +2423,10 @@ netlink_ack_tlv_len(struct netlink_sock *nlk, int err,
                tlvlen += nla_total_size(sizeof(u32));
        if (extack->policy)
                tlvlen += netlink_policy_dump_attr_size_estimate(extack->policy);
+       if (extack->miss_type)
+               tlvlen += nla_total_size(sizeof(u32));
+       if (extack->miss_nest)
+               tlvlen += nla_total_size(sizeof(u32));
 
        return tlvlen;
 }
@@ -2449,6 +2453,14 @@ netlink_ack_tlv_fill(struct sk_buff *in_skb, struct sk_buff *skb,
        if (extack->policy)
                netlink_policy_dump_write_attr(skb, extack->policy,
                                               NLMSGERR_ATTR_POLICY);
+       if (extack->miss_type)
+               WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_TYPE,
+                                   extack->miss_type));
+       if (extack->miss_nest &&
+           !WARN_ON((u8 *)extack->miss_nest < in_skb->data ||
+                    (u8 *)extack->miss_nest > in_skb->data + in_skb->len))
+               WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_NEST,
+                                   (u8 *)extack->miss_nest - (u8 *)nlh));
 }
 
 void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,