ethtool: specify which header flags are supported per command
authorJakub Kicinski <kuba@kernel.org>
Mon, 5 Oct 2020 22:07:39 +0000 (15:07 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 6 Oct 2020 13:25:55 +0000 (06:25 -0700)
Perform header flags validation through the policy.

Only pause command supports ETHTOOL_FLAG_STATS. Create a separate
policy to be able to express that in policy dumps to user space.

Note that even though the core will validate the header policy,
it cannot record multiple layers of attributes and we have to
re-parse header sub-attrs. When doing so we could skip attribute
validation, or use most permissive policy. Opt for the former.

We will no longer return the extack cookie for flags but since
we only added first new flag in this release it's not expected
that any user space had a chance to make use of it.

v2: - remove the re-validation in ethnl_parse_header_dev_get()

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ethtool/netlink.c
net/ethtool/netlink.h
net/ethtool/pause.c

index 10567e6ec0345d257b6f75b6dacf30d459ba5856..8a85a4e6be9b036aa4597b8503425558da2a09c0 100644 (file)
@@ -9,11 +9,24 @@ static struct genl_family ethtool_genl_family;
 static bool ethnl_ok __read_mostly;
 static u32 ethnl_bcast_seq;
 
+#define ETHTOOL_FLAGS_BASIC (ETHTOOL_FLAG_COMPACT_BITSETS |    \
+                            ETHTOOL_FLAG_OMIT_REPLY)
+#define ETHTOOL_FLAGS_STATS (ETHTOOL_FLAGS_BASIC | ETHTOOL_FLAG_STATS)
+
 const struct nla_policy ethnl_header_policy[] = {
        [ETHTOOL_A_HEADER_DEV_INDEX]    = { .type = NLA_U32 },
        [ETHTOOL_A_HEADER_DEV_NAME]     = { .type = NLA_NUL_STRING,
                                            .len = ALTIFNAMSIZ - 1 },
-       [ETHTOOL_A_HEADER_FLAGS]        = { .type = NLA_U32 },
+       [ETHTOOL_A_HEADER_FLAGS]        = NLA_POLICY_MASK(NLA_U32,
+                                                         ETHTOOL_FLAGS_BASIC),
+};
+
+const struct nla_policy ethnl_header_policy_stats[] = {
+       [ETHTOOL_A_HEADER_DEV_INDEX]    = { .type = NLA_U32 },
+       [ETHTOOL_A_HEADER_DEV_NAME]     = { .type = NLA_NUL_STRING,
+                                           .len = ALTIFNAMSIZ - 1 },
+       [ETHTOOL_A_HEADER_FLAGS]        = NLA_POLICY_MASK(NLA_U32,
+                                                         ETHTOOL_FLAGS_STATS),
 };
 
 /**
@@ -46,19 +59,15 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
                NL_SET_ERR_MSG(extack, "request header missing");
                return -EINVAL;
        }
+       /* No validation here, command policy should have a nested policy set
+        * for the header, therefore validation should have already been done.
+        */
        ret = nla_parse_nested(tb, ARRAY_SIZE(ethnl_header_policy) - 1, header,
-                              ethnl_header_policy, extack);
+                              NULL, extack);
        if (ret < 0)
                return ret;
-       if (tb[ETHTOOL_A_HEADER_FLAGS]) {
+       if (tb[ETHTOOL_A_HEADER_FLAGS])
                flags = nla_get_u32(tb[ETHTOOL_A_HEADER_FLAGS]);
-               if (flags & ~ETHTOOL_FLAG_ALL) {
-                       NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_HEADER_FLAGS],
-                                           "unrecognized request flags");
-                       nl_set_extack_cookie_u32(extack, ETHTOOL_FLAG_ALL);
-                       return -EOPNOTSUPP;
-               }
-       }
 
        devname_attr = tb[ETHTOOL_A_HEADER_DEV_NAME];
        if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) {
index 281d793d4557ac0216bd3d6c497b32a01174de42..3f5719786b0f33fcbcbc2b456d3ae9f75954e6b8 100644 (file)
@@ -346,6 +346,7 @@ extern const struct ethnl_request_ops ethnl_eee_request_ops;
 extern const struct ethnl_request_ops ethnl_tsinfo_request_ops;
 
 extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
+extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
 extern const struct nla_policy ethnl_strset_get_policy[ETHTOOL_A_STRSET_STRINGSETS + 1];
 extern const struct nla_policy ethnl_linkinfo_get_policy[ETHTOOL_A_LINKINFO_HEADER + 1];
 extern const struct nla_policy ethnl_linkinfo_set_policy[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL + 1];
index bf4013afd8b2ae5a24330b4524f6baf7c7faac36..09998dc5c185fc890c2ca705c6febc503a97a16f 100644 (file)
@@ -18,7 +18,7 @@ struct pause_reply_data {
 
 const struct nla_policy ethnl_pause_get_policy[] = {
        [ETHTOOL_A_PAUSE_HEADER]                =
-               NLA_POLICY_NESTED(ethnl_header_policy),
+               NLA_POLICY_NESTED(ethnl_header_policy_stats),
 };
 
 static void ethtool_stats_init(u64 *stats, unsigned int n)