netlink: introduce type-checking attribute iteration
authorJohannes Berg <johannes.berg@intel.com>
Thu, 28 Mar 2024 19:31:45 +0000 (20:31 +0100)
committerJakub Kicinski <kuba@kernel.org>
Fri, 29 Mar 2024 22:06:02 +0000 (15:06 -0700)
There are, especially with multi-attr arrays, many cases
of needing to iterate all attributes of a specific type
in a netlink message or a nested attribute. Add specific
macros to support that case.

Also convert many instances using this spatch:

    @@
    iterator nla_for_each_attr;
    iterator name nla_for_each_attr_type;
    identifier nla;
    expression head, len, rem;
    expression ATTR;
    type T;
    identifier x;
    @@
    -nla_for_each_attr(nla, head, len, rem)
    +nla_for_each_attr_type(nla, ATTR, head, len, rem)
     {
    <... T x; ...>
    -if (nla_type(nla) == ATTR) {
     ...
    -}
     }

    @@
    identifier nla;
    iterator nla_for_each_nested;
    iterator name nla_for_each_nested_type;
    expression attr, rem;
    expression ATTR;
    type T;
    identifier x;
    @@
    -nla_for_each_nested(nla, attr, rem)
    +nla_for_each_nested_type(nla, ATTR, attr, rem)
     {
    <... T x; ...>
    -if (nla_type(nla) == ATTR) {
     ...
    -}
     }

    @@
    iterator nla_for_each_attr;
    iterator name nla_for_each_attr_type;
    identifier nla;
    expression head, len, rem;
    expression ATTR;
    type T;
    identifier x;
    @@
    -nla_for_each_attr(nla, head, len, rem)
    +nla_for_each_attr_type(nla, ATTR, head, len, rem)
     {
    <... T x; ...>
    -if (nla_type(nla) != ATTR) continue;
     ...
     }

    @@
    identifier nla;
    iterator nla_for_each_nested;
    iterator name nla_for_each_nested_type;
    expression attr, rem;
    expression ATTR;
    type T;
    identifier x;
    @@
    -nla_for_each_nested(nla, attr, rem)
    +nla_for_each_nested_type(nla, ATTR, attr, rem)
     {
    <... T x; ...>
    -if (nla_type(nla) != ATTR) continue;
     ...
     }

Although I had to undo one bad change this made, and
I also adjusted some other code for whitespace and to
use direct variable initialization now.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Link: https://lore.kernel.org/r/20240328203144.b5a6c895fb80.I1869b44767379f204998ff44dd239803f39c23e0@changeid
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
14 files changed:
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
include/net/netlink.h
net/8021q/vlan_netlink.c
net/core/bpf_sk_storage.c
net/core/rtnetlink.c
net/devlink/dev.c
net/sched/sch_mqprio.c
net/sched/sch_taprio.c

index 388e80bf91f5ed17644d8bbc86c9f393b7cb9e93..b4db4b1aaffbfd1c0ff96523dac616727eaa9a1a 100644 (file)
@@ -14581,12 +14581,9 @@ static int bnxt_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
        if (!br_spec)
                return -EINVAL;
 
-       nla_for_each_nested(attr, br_spec, rem) {
+       nla_for_each_nested_type(attr, IFLA_BRIDGE_MODE, br_spec, rem) {
                u16 mode;
 
-               if (nla_type(attr) != IFLA_BRIDGE_MODE)
-                       continue;
-
                mode = nla_get_u16(attr);
                if (mode == bp->br_mode)
                        break;
index ad862ed7888ac40cd51a2cb01f058331e73cfb7e..a8596ebcdfd60e8d7418b63a3dedf8ed1af29d9b 100644 (file)
@@ -4982,10 +4982,7 @@ static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
        if (!br_spec)
                return -EINVAL;
 
-       nla_for_each_nested(attr, br_spec, rem) {
-               if (nla_type(attr) != IFLA_BRIDGE_MODE)
-                       continue;
-
+       nla_for_each_nested_type(attr, IFLA_BRIDGE_MODE, br_spec, rem) {
                mode = nla_get_u16(attr);
                if (BE3_chip(adapter) && mode == BRIDGE_MODE_VEPA)
                        return -EOPNOTSUPP;
index f86578857e8aee4136287816933d23125947bc3c..e427e65af205bc5f6736dfcda5fc22197063ee1c 100644 (file)
@@ -13108,13 +13108,9 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev,
        if (!br_spec)
                return -EINVAL;
 
-       nla_for_each_nested(attr, br_spec, rem) {
-               __u16 mode;
+       nla_for_each_nested_type(attr, IFLA_BRIDGE_MODE, br_spec, rem) {
+               __u16 mode = nla_get_u16(attr);
 
-               if (nla_type(attr) != IFLA_BRIDGE_MODE)
-                       continue;
-
-               mode = nla_get_u16(attr);
                if ((mode != BRIDGE_MODE_VEPA) &&
                    (mode != BRIDGE_MODE_VEB))
                        return -EINVAL;
index f2b7d6ca8805e5426cd4c5eda0c4a2a949ada8ea..618570f235804d1293a13238cf8a93158c05b076 100644 (file)
@@ -7993,12 +7993,9 @@ ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
        if (!br_spec)
                return -EINVAL;
 
-       nla_for_each_nested(attr, br_spec, rem) {
-               __u16 mode;
+       nla_for_each_nested_type(attr, IFLA_BRIDGE_MODE, br_spec, rem) {
+               __u16 mode = nla_get_u16(attr);
 
-               if (nla_type(attr) != IFLA_BRIDGE_MODE)
-                       continue;
-               mode = nla_get_u16(attr);
                if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB)
                        return -EINVAL;
                /* Continue  if bridge mode is not being flipped */
index f985252c8c8d6ebe84556774c0d9d6cf419b08fe..ed05af665466d21343aa89ac54456a520e5e78bc 100644 (file)
@@ -10061,15 +10061,10 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
        if (!br_spec)
                return -EINVAL;
 
-       nla_for_each_nested(attr, br_spec, rem) {
-               int status;
-               __u16 mode;
+       nla_for_each_nested_type(attr, IFLA_BRIDGE_MODE, br_spec, rem) {
+               __u16 mode = nla_get_u16(attr);
+               int status = ixgbe_configure_bridge_mode(adapter, mode);
 
-               if (nla_type(attr) != IFLA_BRIDGE_MODE)
-                       continue;
-
-               mode = nla_get_u16(attr);
-               status = ixgbe_configure_bridge_mode(adapter, mode);
                if (status)
                        return status;
 
index 91848eae45655fd57d7dcc3365f8ad5094f61f3d..81e1c1e401f9f94ec7430a5b08685c39e1b68a11 100644 (file)
@@ -4950,10 +4950,7 @@ static int mlx5e_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
        if (!br_spec)
                return -EINVAL;
 
-       nla_for_each_nested(attr, br_spec, rem) {
-               if (nla_type(attr) != IFLA_BRIDGE_MODE)
-                       continue;
-
+       nla_for_each_nested_type(attr, IFLA_BRIDGE_MODE, br_spec, rem) {
                mode = nla_get_u16(attr);
                if (mode > BRIDGE_MODE_VEPA)
                        return -EINVAL;
index f28e769e6fdadab091d447f3de4cb8df1d2b4d3e..997cc4fcffdbfd4ea8727351b45593dbb679609f 100644 (file)
@@ -2289,10 +2289,7 @@ static int nfp_net_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
        if (!br_spec)
                return -EINVAL;
 
-       nla_for_each_nested(attr, br_spec, rem) {
-               if (nla_type(attr) != IFLA_BRIDGE_MODE)
-                       continue;
-
+       nla_for_each_nested_type(attr, IFLA_BRIDGE_MODE, br_spec, rem) {
                new_ctrl = nn->dp.ctrl;
                mode = nla_get_u16(attr);
                if (mode == BRIDGE_MODE_VEPA)
index c19ff921b661adbf7face59f282f7880e2db6293..1d2bbcc50212db0f062f830e9e22e48c8fd6ffc0 100644 (file)
  *   nla_parse()                       parse and validate stream of attrs
  *   nla_parse_nested()                        parse nested attributes
  *   nla_for_each_attr()               loop over all attributes
+ *   nla_for_each_attr_type()          loop over all attributes with the
+ *                                     given type
  *   nla_for_each_nested()             loop over the nested attributes
+ *   nla_for_each_nested_type()                loop over the nested attributes with
+ *                                     the given type
  *=========================================================================
  */
 
@@ -2070,6 +2074,18 @@ static inline int nla_total_size_64bit(int payload)
             nla_ok(pos, rem); \
             pos = nla_next(pos, &(rem)))
 
+/**
+ * nla_for_each_attr_type - iterate over a stream of attributes
+ * @pos: loop counter, set to current attribute
+ * @type: required attribute type for @pos
+ * @head: head of attribute stream
+ * @len: length of attribute stream
+ * @rem: initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_attr_type(pos, type, head, len, rem) \
+       nla_for_each_attr(pos, head, len, rem) \
+               if (nla_type(pos) == type)
+
 /**
  * nla_for_each_nested - iterate over nested attributes
  * @pos: loop counter, set to current attribute
@@ -2079,6 +2095,17 @@ static inline int nla_total_size_64bit(int payload)
 #define nla_for_each_nested(pos, nla, rem) \
        nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem)
 
+/**
+ * nla_for_each_nested_type - iterate over nested attributes
+ * @pos: loop counter, set to current attribute
+ * @type: required attribute type for @pos
+ * @nla: attribute containing the nested attributes
+ * @rem: initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_nested_type(pos, type, nla, rem) \
+       nla_for_each_nested(pos, nla, rem) \
+               if (nla_type(pos) == type)
+
 /**
  * nla_is_last - Test if attribute is last in stream
  * @nla: attribute to test
index a3b68243fd4b18492220339f8a2151598cf6e98a..cf5219df7903c9120abba770b21c6bfeeeeb7d3e 100644 (file)
@@ -117,17 +117,15 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[],
                        return err;
        }
        if (data[IFLA_VLAN_INGRESS_QOS]) {
-               nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
-                       if (nla_type(attr) != IFLA_VLAN_QOS_MAPPING)
-                               continue;
+               nla_for_each_nested_type(attr, IFLA_VLAN_QOS_MAPPING,
+                                        data[IFLA_VLAN_INGRESS_QOS], rem) {
                        m = nla_data(attr);
                        vlan_dev_set_ingress_priority(dev, m->to, m->from);
                }
        }
        if (data[IFLA_VLAN_EGRESS_QOS]) {
-               nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
-                       if (nla_type(attr) != IFLA_VLAN_QOS_MAPPING)
-                               continue;
+               nla_for_each_nested_type(attr, IFLA_VLAN_QOS_MAPPING,
+                                        data[IFLA_VLAN_EGRESS_QOS], rem) {
                        m = nla_data(attr);
                        err = vlan_dev_set_egress_priority(dev, m->from, m->to);
                        if (err)
index 6c4d90b24d467e35aec7b227af1ead927d7979e3..bc01b3aa6b0fad4de6986fd854ad05bdc48960fa 100644 (file)
@@ -496,27 +496,22 @@ bpf_sk_storage_diag_alloc(const struct nlattr *nla_stgs)
        if (!bpf_capable())
                return ERR_PTR(-EPERM);
 
-       nla_for_each_nested(nla, nla_stgs, rem) {
-               if (nla_type(nla) == SK_DIAG_BPF_STORAGE_REQ_MAP_FD) {
-                       if (nla_len(nla) != sizeof(u32))
-                               return ERR_PTR(-EINVAL);
-                       nr_maps++;
-               }
+       nla_for_each_nested_type(nla, SK_DIAG_BPF_STORAGE_REQ_MAP_FD,
+                                nla_stgs, rem) {
+               if (nla_len(nla) != sizeof(u32))
+                       return ERR_PTR(-EINVAL);
+               nr_maps++;
        }
 
        diag = kzalloc(struct_size(diag, maps, nr_maps), GFP_KERNEL);
        if (!diag)
                return ERR_PTR(-ENOMEM);
 
-       nla_for_each_nested(nla, nla_stgs, rem) {
-               struct bpf_map *map;
-               int map_fd;
-
-               if (nla_type(nla) != SK_DIAG_BPF_STORAGE_REQ_MAP_FD)
-                       continue;
+       nla_for_each_nested_type(nla, SK_DIAG_BPF_STORAGE_REQ_MAP_FD,
+                                nla_stgs, rem) {
+               int map_fd = nla_get_u32(nla);
+               struct bpf_map *map = bpf_map_get(map_fd);
 
-               map_fd = nla_get_u32(nla);
-               map = bpf_map_get(map_fd);
                if (IS_ERR(map)) {
                        err = PTR_ERR(map);
                        goto err_free;
index a3d7847ce69d36401051526acf30211d96e2b24e..283e42f48af68504af193ed5763d4e0fcd667d99 100644 (file)
@@ -5245,15 +5245,14 @@ static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
        if (br_spec) {
-               nla_for_each_nested(attr, br_spec, rem) {
-                       if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
-                               if (nla_len(attr) < sizeof(flags))
-                                       return -EINVAL;
+               nla_for_each_nested_type(attr, IFLA_BRIDGE_FLAGS, br_spec,
+                                        rem) {
+                       if (nla_len(attr) < sizeof(flags))
+                               return -EINVAL;
 
-                               have_flags = true;
-                               flags = nla_get_u16(attr);
-                               break;
-                       }
+                       have_flags = true;
+                       flags = nla_get_u16(attr);
+                       break;
                }
        }
 
index 19dbf540748abbc07e32bf95f711d0c0b76a0cac..c609deb42e889021af5bd2c3c5be191acecadfc2 100644 (file)
@@ -1202,17 +1202,13 @@ static void __devlink_compat_running_version(struct devlink *devlink,
        if (err)
                goto free_msg;
 
-       nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
+       nla_for_each_attr_type(nlattr, DEVLINK_ATTR_INFO_VERSION_RUNNING,
+                              (void *)msg->data, msg->len, rem) {
                const struct nlattr *kv;
                int rem_kv;
 
-               if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
-                       continue;
-
-               nla_for_each_nested(kv, nlattr, rem_kv) {
-                       if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
-                               continue;
-
+               nla_for_each_nested_type(kv, DEVLINK_ATTR_INFO_VERSION_VALUE,
+                                        nlattr, rem_kv) {
                        strlcat(buf, nla_data(kv), len);
                        strlcat(buf, " ", len);
                }
index 225353fbb3f1510a1d74eb12859afb62f811d2f9..51d4013b612198de19943b9984ec2ee1e0c4bbb9 100644 (file)
@@ -215,10 +215,8 @@ static int mqprio_parse_tc_entries(struct Qdisc *sch, struct nlattr *nlattr_opt,
        for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++)
                fp[tc] = priv->fp[tc];
 
-       nla_for_each_attr(n, nlattr_opt, nlattr_opt_len, rem) {
-               if (nla_type(n) != TCA_MQPRIO_TC_ENTRY)
-                       continue;
-
+       nla_for_each_attr_type(n, TCA_MQPRIO_TC_ENTRY, nlattr_opt,
+                              nlattr_opt_len, rem) {
                err = mqprio_parse_tc_entry(fp, n, &seen_tcs, extack);
                if (err)
                        goto out;
index a0d54b422186fb5983019791ce688b3685cd18ec..1ab17e8a72605385280fad9b7f656a6771236acc 100644 (file)
@@ -1752,10 +1752,7 @@ static int taprio_parse_tc_entries(struct Qdisc *sch,
                fp[tc] = q->fp[tc];
        }
 
-       nla_for_each_nested(n, opt, rem) {
-               if (nla_type(n) != TCA_TAPRIO_ATTR_TC_ENTRY)
-                       continue;
-
+       nla_for_each_nested_type(n, TCA_TAPRIO_ATTR_TC_ENTRY, opt, rem) {
                err = taprio_parse_tc_entry(sch, n, max_sdu, fp, &seen_tcs,
                                            extack);
                if (err)