Reduce duplicate code by using nla_policy and nla_parse_strict().

Signed-off-by: Joe Stringer <joestrin...@nicira.com>
---
v3: Fix match_validate()
    Make ovs_key_from_nlattrs(),metadata_from_nlattrs() not change the
      attrs they are given
    Remove extraneous check for duplicate attributes
    Use NLA_FLAG, NLA_NESTED for policies
v2: Remove attrs bitmasks from most functions.
    Remove key/mask wrappers for parse_nlattrs().
    Rebase against flag-based nla_parse_strict().
v1: Initial post.
---
 datapath/flow_netlink.c |  401 ++++++++++++++++++++---------------------------
 1 file changed, 168 insertions(+), 233 deletions(-)

diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index a3f34f1..5bc2d17 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -111,11 +111,26 @@ static void update_range(struct sw_flow_match *match,
                               sizeof((match)->key->field));                \
        } while (0)
 
+static u64 attrs_to_bitmask(const struct nlattr **a, size_t len)
+{
+       size_t i;
+       u64 mask = 0;
+
+       for (i = 0; i < len; i++)
+               if (a[i])
+                       mask |= (1ULL << i);
+       return mask;
+}
+
 static bool match_validate(const struct sw_flow_match *match,
-                          u64 key_attrs, u64 mask_attrs)
+                          const struct nlattr **key_attrs,
+                          const struct nlattr **mask_attrs)
 {
        u64 key_expected = 1ULL << OVS_KEY_ATTR_ETHERNET;
-       u64 mask_allowed = key_attrs;  /* At most allow all key attributes */
+       u64 attrs, mask_allowed;
+
+       /* At most allow all key attributes */
+       mask_allowed = attrs_to_bitmask(key_attrs, OVS_KEY_ATTR_MAX);
 
        /* The following mask attributes allowed only if they
         * pass the validation tests. */
@@ -229,17 +244,19 @@ static bool match_validate(const struct sw_flow_match 
*match,
                }
        }
 
-       if ((key_attrs & key_expected) != key_expected) {
+       attrs = attrs_to_bitmask(key_attrs, OVS_KEY_ATTR_MAX);
+       if ((attrs & key_expected) != key_expected) {
                /* Key attributes check failed. */
                OVS_NLERR("Missing expected key attributes (key_attrs=%llx, 
expected=%llx).\n",
-                               (unsigned long long)key_attrs, (unsigned long 
long)key_expected);
+                               (unsigned long long)attrs, (unsigned long 
long)key_expected);
                return false;
        }
 
-       if ((mask_attrs & mask_allowed) != mask_attrs) {
+       attrs = attrs_to_bitmask(mask_attrs, OVS_KEY_ATTR_MAX);
+       if ((attrs & mask_allowed) != attrs) {
                /* Mask attributes check failed. */
                OVS_NLERR("Contain more than allowed mask fields 
(mask_attrs=%llx, mask_allowed=%llx).\n",
-                               (unsigned long long)mask_attrs, (unsigned long 
long)mask_allowed);
+                               (unsigned long long)attrs, (unsigned long 
long)mask_allowed);
                return false;
        }
 
@@ -286,162 +303,109 @@ size_t ovs_key_attr_size(void)
                + nla_total_size(28); /* OVS_KEY_ATTR_ND */
 }
 
-/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute.  */
-static const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
-       [OVS_KEY_ATTR_ENCAP] = -1,
-       [OVS_KEY_ATTR_PRIORITY] = sizeof(u32),
-       [OVS_KEY_ATTR_IN_PORT] = sizeof(u32),
-       [OVS_KEY_ATTR_SKB_MARK] = sizeof(u32),
-       [OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet),
-       [OVS_KEY_ATTR_VLAN] = sizeof(__be16),
-       [OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16),
-       [OVS_KEY_ATTR_IPV4] = sizeof(struct ovs_key_ipv4),
-       [OVS_KEY_ATTR_IPV6] = sizeof(struct ovs_key_ipv6),
-       [OVS_KEY_ATTR_TCP] = sizeof(struct ovs_key_tcp),
-       [OVS_KEY_ATTR_TCP_FLAGS] = sizeof(__be16),
-       [OVS_KEY_ATTR_UDP] = sizeof(struct ovs_key_udp),
-       [OVS_KEY_ATTR_SCTP] = sizeof(struct ovs_key_sctp),
-       [OVS_KEY_ATTR_ICMP] = sizeof(struct ovs_key_icmp),
-       [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6),
-       [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp),
-       [OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd),
-       [OVS_KEY_ATTR_DP_HASH] = sizeof(u32),
-       [OVS_KEY_ATTR_RECIRC_ID] = sizeof(u32),
-       [OVS_KEY_ATTR_TUNNEL] = -1,
-       [OVS_KEY_ATTR_MPLS] = sizeof(struct ovs_key_mpls),
+/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute.
+ * Lengths specified here are exact lengths for nla_parse_strict(). */
+static const struct nla_policy ovs_key_policy[OVS_KEY_ATTR_MAX + 1] = {
+       [OVS_KEY_ATTR_ENCAP] = { .type = NLA_NESTED },
+       [OVS_KEY_ATTR_PRIORITY] = { .len = sizeof(u32) },
+       [OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) },
+       [OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) },
+       [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) },
+       [OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) },
+       [OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) },
+       [OVS_KEY_ATTR_IPV4] = { .len = sizeof(struct ovs_key_ipv4) },
+       [OVS_KEY_ATTR_IPV6] = { .len = sizeof(struct ovs_key_ipv6) },
+       [OVS_KEY_ATTR_TCP] = { .len = sizeof(struct ovs_key_tcp) },
+       [OVS_KEY_ATTR_TCP_FLAGS] = { .len = sizeof(__be16) },
+       [OVS_KEY_ATTR_UDP] = { .len = sizeof(struct ovs_key_udp) },
+       [OVS_KEY_ATTR_SCTP] = { .len = sizeof(struct ovs_key_sctp) },
+       [OVS_KEY_ATTR_ICMP] = { .len = sizeof(struct ovs_key_icmp) },
+       [OVS_KEY_ATTR_ICMPV6] = { .len = sizeof(struct ovs_key_icmpv6) },
+       [OVS_KEY_ATTR_ARP] = { .len = sizeof(struct ovs_key_arp) },
+       [OVS_KEY_ATTR_ND] = { .len = sizeof(struct ovs_key_nd) },
+       [OVS_KEY_ATTR_DP_HASH] = { .len = sizeof(u32) },
+       [OVS_KEY_ATTR_RECIRC_ID] = { .len = sizeof(u32) },
+       [OVS_KEY_ATTR_TUNNEL] = { .type = NLA_NESTED },
+       [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) },
 };
 
-static bool is_all_zero(const u8 *fp, size_t size)
-{
-       int i;
-
-       if (!fp)
-               return false;
-
-       for (i = 0; i < size; i++)
-               if (fp[i])
-                       return false;
-
-       return true;
-}
-
-static int __parse_flow_nlattrs(const struct nlattr *attr,
-                               const struct nlattr *a[],
-                               u64 *attrsp, bool nz)
+static int parse_nlattrs(const struct nlattr *attr,
+                        const struct nlattr *a[], int maxtype,
+                        const struct nla_policy *policy, bool dup, bool nz)
 {
-       const struct nlattr *nla;
-       u64 attrs;
-       int rem;
-
-       attrs = *attrsp;
-       nla_for_each_nested(nla, attr, rem) {
-               u16 type = nla_type(nla);
-               int expected_len;
-
-               if (type > OVS_KEY_ATTR_MAX) {
-                       OVS_NLERR("Unknown key attribute (type=%d, max=%d).\n",
-                                 type, OVS_KEY_ATTR_MAX);
-                       return -EINVAL;
-               }
-
-               if (attrs & (1ULL << type)) {
-                       OVS_NLERR("Duplicate key attribute (type %d).\n", type);
-                       return -EINVAL;
-               }
+       int err;
+       u8 flags = NLA_PARSE_F_NOINIT | NLA_PARSE_F_UNKNOWN
+                  | NLA_PARSE_F_TRAILING | NLA_PARSE_F_EXACT_LEN;
 
-               expected_len = ovs_key_lens[type];
-               if (nla_len(nla) != expected_len && expected_len != -1) {
-                       OVS_NLERR("Key attribute has unexpected length (type=%d"
-                                 ", length=%d, expected=%d).\n", type,
-                                 nla_len(nla), expected_len);
-                       return -EINVAL;
-               }
+       if (!dup)
+               flags |= NLA_PARSE_F_DUPLICATE;
+       if (nz)
+               flags |= NLA_PARSE_F_NONZERO;
 
-               if (!nz || !is_all_zero(nla_data(nla), expected_len)) {
-                       attrs |= 1ULL << type;
-                       a[type] = nla;
-               }
-       }
-       if (rem) {
-               OVS_NLERR("Message has %d unknown bytes.\n", rem);
-               return -EINVAL;
-       }
+       err = nla_parse_strict(a, maxtype, nla_data(attr), nla_len(attr),
+                              policy, flags);
+       if (err)
+               return err;
 
-       *attrsp = attrs;
        return 0;
 }
 
-static int parse_flow_mask_nlattrs(const struct nlattr *attr,
-                                  const struct nlattr *a[], u64 *attrsp)
-{
-       return __parse_flow_nlattrs(attr, a, attrsp, true);
-}
-
-static int parse_flow_nlattrs(const struct nlattr *attr,
-                             const struct nlattr *a[], u64 *attrsp)
-{
-       return __parse_flow_nlattrs(attr, a, attrsp, false);
-}
-
 static int ipv4_tun_from_nlattr(const struct nlattr *attr,
                                struct sw_flow_match *match, bool is_mask)
 {
-       struct nlattr *a;
-       int rem;
+       static const struct nla_policy 
ovs_tunnel_key_policy[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
+               [OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) },
+               [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) },
+               [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = { .len = sizeof(u32) },
+               [OVS_TUNNEL_KEY_ATTR_TOS] = { .len = sizeof(u8) },
+               [OVS_TUNNEL_KEY_ATTR_TTL] = { .len = sizeof(u8) },
+               [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = { .type = NLA_FLAG },
+               [OVS_TUNNEL_KEY_ATTR_CSUM] = { .type = NLA_FLAG },
+               [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) },
+               [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
+               [OVS_TUNNEL_KEY_ATTR_OAM] = { .type = NLA_FLAG },
+               [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .type = NLA_NESTED },
+       };
+       const struct nlattr *a[OVS_TUNNEL_KEY_ATTR_MAX + 1];
        bool ttl = false;
        __be16 tun_flags = 0;
+       enum ovs_tunnel_key_attr type;
+       int err;
 
-       nla_for_each_nested(a, attr, rem) {
-               int type = nla_type(a);
-               static const u32 ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 
1] = {
-                       [OVS_TUNNEL_KEY_ATTR_ID] = sizeof(u64),
-                       [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = sizeof(u32),
-                       [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = sizeof(u32),
-                       [OVS_TUNNEL_KEY_ATTR_TOS] = 1,
-                       [OVS_TUNNEL_KEY_ATTR_TTL] = 1,
-                       [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0,
-                       [OVS_TUNNEL_KEY_ATTR_CSUM] = 0,
-                       [OVS_TUNNEL_KEY_ATTR_TP_SRC] = sizeof(u16),
-                       [OVS_TUNNEL_KEY_ATTR_TP_DST] = sizeof(u16),
-                       [OVS_TUNNEL_KEY_ATTR_OAM] = 0,
-                       [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1,
-               };
+       memset(a, 0, sizeof(*a) * (OVS_TUNNEL_KEY_ATTR_MAX + 1));
+       err = parse_nlattrs(attr, a, OVS_TUNNEL_KEY_ATTR_MAX,
+                           ovs_tunnel_key_policy, true, is_mask);
+       if (err)
+               return err;
 
-               if (type > OVS_TUNNEL_KEY_ATTR_MAX) {
-                       OVS_NLERR("Unknown IPv4 tunnel attribute (type=%d, 
max=%d).\n",
-                       type, OVS_TUNNEL_KEY_ATTR_MAX);
-                       return -EINVAL;
-               }
+       for (type = 0; type <= OVS_TUNNEL_KEY_ATTR_MAX; type++) {
+               const struct nlattr *nla;
 
-               if (ovs_tunnel_key_lens[type] != nla_len(a) &&
-                   ovs_tunnel_key_lens[type] != -1) {
-                       OVS_NLERR("IPv4 tunnel attribute type has unexpected "
-                                 " length (type=%d, length=%d, 
expected=%d).\n",
-                                 type, nla_len(a), ovs_tunnel_key_lens[type]);
-                       return -EINVAL;
-               }
+               if (!a[type])
+                       continue;
 
+               nla = a[type];
                switch (type) {
                case OVS_TUNNEL_KEY_ATTR_ID:
                        SW_FLOW_KEY_PUT(match, tun_key.tun_id,
-                                       nla_get_be64(a), is_mask);
+                                       nla_get_be64(nla), is_mask);
                        tun_flags |= TUNNEL_KEY;
                        break;
                case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
                        SW_FLOW_KEY_PUT(match, tun_key.ipv4_src,
-                                       nla_get_be32(a), is_mask);
+                                       nla_get_be32(nla), is_mask);
                        break;
                case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
                        SW_FLOW_KEY_PUT(match, tun_key.ipv4_dst,
-                                       nla_get_be32(a), is_mask);
+                                       nla_get_be32(nla), is_mask);
                        break;
                case OVS_TUNNEL_KEY_ATTR_TOS:
                        SW_FLOW_KEY_PUT(match, tun_key.ipv4_tos,
-                                       nla_get_u8(a), is_mask);
+                                       nla_get_u8(nla), is_mask);
                        break;
                case OVS_TUNNEL_KEY_ATTR_TTL:
                        SW_FLOW_KEY_PUT(match, tun_key.ipv4_ttl,
-                                       nla_get_u8(a), is_mask);
+                                       nla_get_u8(nla), is_mask);
                        ttl = true;
                        break;
                case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
@@ -452,29 +416,29 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
                        break;
                case OVS_TUNNEL_KEY_ATTR_TP_SRC:
                        SW_FLOW_KEY_PUT(match, tun_key.tp_src,
-                                       nla_get_be16(a), is_mask);
+                                       nla_get_be16(nla), is_mask);
                        break;
                case OVS_TUNNEL_KEY_ATTR_TP_DST:
                        SW_FLOW_KEY_PUT(match, tun_key.tp_dst,
-                                       nla_get_be16(a), is_mask);
+                                       nla_get_be16(nla), is_mask);
                        break;
                case OVS_TUNNEL_KEY_ATTR_OAM:
                        tun_flags |= TUNNEL_OAM;
                        break;
                case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
                        tun_flags |= TUNNEL_OPTIONS_PRESENT;
-                       if (nla_len(a) > sizeof(match->key->tun_opts)) {
+                       if (nla_len(nla) > sizeof(match->key->tun_opts)) {
                                OVS_NLERR("Geneve option length exceeds "
                                          "maximum size (len %d, max %zu).\n",
-                                         nla_len(a),
+                                         nla_len(nla),
                                          sizeof(match->key->tun_opts));
                                return -EINVAL;
                        }
 
-                       if (nla_len(a) % 4 != 0) {
+                       if (nla_len(nla) % 4 != 0) {
                                OVS_NLERR("Geneve option length is not "
                                          "a multiple of 4 (len %d).\n",
-                                         nla_len(a));
+                                         nla_len(nla));
                                return -EINVAL;
                        }
 
@@ -483,7 +447,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
                         * additional options will be silently matched.
                         */
                        if (!is_mask) {
-                               SW_FLOW_KEY_PUT(match, tun_opts_len, nla_len(a),
+                               SW_FLOW_KEY_PUT(match, tun_opts_len, 
nla_len(nla),
                                                false);
                        } else {
                                /* This is somewhat unusual because it looks at
@@ -496,10 +460,10 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
                                 * variable length and we won't have the
                                 * information later.
                                 */
-                               if (match->key->tun_opts_len != nla_len(a)) {
+                               if (match->key->tun_opts_len != nla_len(nla)) {
                                        OVS_NLERR("Geneve option key length 
(%d)"
                                           " is different from mask length 
(%d).",
-                                          match->key->tun_opts_len, 
nla_len(a));
+                                          match->key->tun_opts_len, 
nla_len(nla));
                                        return -EINVAL;
                                }
 
@@ -509,8 +473,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
 
                        SW_FLOW_KEY_MEMCPY_OFFSET(match,
                                (unsigned long)GENEVE_OPTS((struct sw_flow_key 
*)0,
-                                                          nla_len(a)),
-                               nla_data(a), nla_len(a), is_mask);
+                                                          nla_len(nla)),
+                               nla_data(nla), nla_len(nla), is_mask);
                        break;
                default:
                        OVS_NLERR("Unknown IPv4 tunnel attribute (%d).\n", 
type);
@@ -520,11 +484,6 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
 
        SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask);
 
-       if (rem > 0) {
-               OVS_NLERR("IPv4 tunnel attribute has %d unknown bytes.\n", rem);
-               return -EINVAL;
-       }
-
        if (!is_mask) {
                if (!match->key->tun_key.ipv4_dst) {
                        OVS_NLERR("IPv4 tunnel destination address is zero.\n");
@@ -611,30 +570,28 @@ int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb,
                                    egress_tun_info->options_len);
 }
 
-static int metadata_from_nlattrs(struct sw_flow_match *match,  u64 *attrs,
+static int metadata_from_nlattrs(struct sw_flow_match *match,
                                 const struct nlattr **a, bool is_mask)
 {
-       if (*attrs & (1ULL << OVS_KEY_ATTR_DP_HASH)) {
+       if (a[OVS_KEY_ATTR_DP_HASH]) {
                u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]);
 
                SW_FLOW_KEY_PUT(match, ovs_flow_hash, hash_val, is_mask);
-               *attrs &= ~(1ULL << OVS_KEY_ATTR_DP_HASH);
        }
 
-       if (*attrs & (1ULL << OVS_KEY_ATTR_RECIRC_ID)) {
+       if (a[OVS_KEY_ATTR_RECIRC_ID]) {
                u32 recirc_id = nla_get_u32(a[OVS_KEY_ATTR_RECIRC_ID]);
 
                SW_FLOW_KEY_PUT(match, recirc_id, recirc_id, is_mask);
-               *attrs &= ~(1ULL << OVS_KEY_ATTR_RECIRC_ID);
        }
 
-       if (*attrs & (1ULL << OVS_KEY_ATTR_PRIORITY)) {
-               SW_FLOW_KEY_PUT(match, phy.priority,
-                         nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]), is_mask);
-               *attrs &= ~(1ULL << OVS_KEY_ATTR_PRIORITY);
+       if (a[OVS_KEY_ATTR_PRIORITY]) {
+               u32 priority = nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]);
+
+               SW_FLOW_KEY_PUT(match, phy.priority, priority, is_mask);
        }
 
-       if (*attrs & (1ULL << OVS_KEY_ATTR_IN_PORT)) {
+       if (a[OVS_KEY_ATTR_IN_PORT]) {
                u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]);
 
                if (is_mask) {
@@ -646,36 +603,33 @@ static int metadata_from_nlattrs(struct sw_flow_match 
*match,  u64 *attrs,
                }
 
                SW_FLOW_KEY_PUT(match, phy.in_port, in_port, is_mask);
-               *attrs &= ~(1ULL << OVS_KEY_ATTR_IN_PORT);
        } else if (!is_mask) {
                SW_FLOW_KEY_PUT(match, phy.in_port, DP_MAX_PORTS, is_mask);
        }
 
-       if (*attrs & (1ULL << OVS_KEY_ATTR_SKB_MARK)) {
+       if (a[OVS_KEY_ATTR_SKB_MARK]) {
                uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]);
 
                SW_FLOW_KEY_PUT(match, phy.skb_mark, mark, is_mask);
-               *attrs &= ~(1ULL << OVS_KEY_ATTR_SKB_MARK);
        }
-       if (*attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) {
+       if (a[OVS_KEY_ATTR_TUNNEL]) {
                if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
                                         is_mask))
                        return -EINVAL;
-               *attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL);
        }
        return 0;
 }
 
-static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
+static int ovs_key_from_nlattrs(struct sw_flow_match *match,
                                const struct nlattr **a, bool is_mask)
 {
        int err;
 
-       err = metadata_from_nlattrs(match, &attrs, a, is_mask);
+       err = metadata_from_nlattrs(match, a, is_mask);
        if (err)
                return err;
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) {
+       if (a[OVS_KEY_ATTR_ETHERNET]) {
                const struct ovs_key_ethernet *eth_key;
 
                eth_key = nla_data(a[OVS_KEY_ATTR_ETHERNET]);
@@ -683,10 +637,9 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                                eth_key->eth_src, ETH_ALEN, is_mask);
                SW_FLOW_KEY_MEMCPY(match, eth.dst,
                                eth_key->eth_dst, ETH_ALEN, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERNET);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_VLAN)) {
+       if (a[OVS_KEY_ATTR_VLAN]) {
                __be16 tci;
 
                tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
@@ -700,10 +653,9 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                }
 
                SW_FLOW_KEY_PUT(match, eth.tci, tci, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_VLAN);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) {
+       if (a[OVS_KEY_ATTR_ETHERTYPE]) {
                __be16 eth_type;
 
                eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
@@ -717,12 +669,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                }
 
                SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE);
        } else if (!is_mask) {
                SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_IPV4)) {
+       if (a[OVS_KEY_ATTR_IPV4]) {
                const struct ovs_key_ipv4 *ipv4_key;
 
                ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]);
@@ -743,10 +694,9 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                                ipv4_key->ipv4_src, is_mask);
                SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
                                ipv4_key->ipv4_dst, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_IPV6)) {
+       if (a[OVS_KEY_ATTR_IPV6]) {
                const struct ovs_key_ipv6 *ipv6_key;
 
                ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]);
@@ -778,11 +728,9 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                                ipv6_key->ipv6_dst,
                                sizeof(match->key->ipv6.addr.dst),
                                is_mask);
-
-               attrs &= ~(1ULL << OVS_KEY_ATTR_IPV6);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_ARP)) {
+       if (a[OVS_KEY_ATTR_ARP]) {
                const struct ovs_key_arp *arp_key;
 
                arp_key = nla_data(a[OVS_KEY_ATTR_ARP]);
@@ -802,55 +750,47 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                                arp_key->arp_sha, ETH_ALEN, is_mask);
                SW_FLOW_KEY_MEMCPY(match, ipv4.arp.tha,
                                arp_key->arp_tha, ETH_ALEN, is_mask);
-
-               attrs &= ~(1ULL << OVS_KEY_ATTR_ARP);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_MPLS)) {
+       if (a[OVS_KEY_ATTR_MPLS]) {
                const struct ovs_key_mpls *mpls_key;
 
                mpls_key = nla_data(a[OVS_KEY_ATTR_MPLS]);
                SW_FLOW_KEY_PUT(match, mpls.top_lse,
                                mpls_key->mpls_lse, is_mask);
-
-               attrs &= ~(1ULL << OVS_KEY_ATTR_MPLS);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_TCP)) {
+       if (a[OVS_KEY_ATTR_TCP]) {
                const struct ovs_key_tcp *tcp_key;
 
                tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]);
                SW_FLOW_KEY_PUT(match, tp.src, tcp_key->tcp_src, is_mask);
                SW_FLOW_KEY_PUT(match, tp.dst, tcp_key->tcp_dst, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_TCP);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_TCP_FLAGS)) {
+       if (a[OVS_KEY_ATTR_TCP_FLAGS]) {
                SW_FLOW_KEY_PUT(match, tp.flags,
                                nla_get_be16(a[OVS_KEY_ATTR_TCP_FLAGS]),
                                is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_TCP_FLAGS);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_UDP)) {
+       if (a[OVS_KEY_ATTR_UDP]) {
                const struct ovs_key_udp *udp_key;
 
                udp_key = nla_data(a[OVS_KEY_ATTR_UDP]);
                SW_FLOW_KEY_PUT(match, tp.src, udp_key->udp_src, is_mask);
                SW_FLOW_KEY_PUT(match, tp.dst, udp_key->udp_dst, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_UDP);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_SCTP)) {
+       if (a[OVS_KEY_ATTR_SCTP]) {
                const struct ovs_key_sctp *sctp_key;
 
                sctp_key = nla_data(a[OVS_KEY_ATTR_SCTP]);
                SW_FLOW_KEY_PUT(match, tp.src, sctp_key->sctp_src, is_mask);
                SW_FLOW_KEY_PUT(match, tp.dst, sctp_key->sctp_dst, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_SCTP);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_ICMP)) {
+       if (a[OVS_KEY_ATTR_ICMP]) {
                const struct ovs_key_icmp *icmp_key;
 
                icmp_key = nla_data(a[OVS_KEY_ATTR_ICMP]);
@@ -858,10 +798,9 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                                htons(icmp_key->icmp_type), is_mask);
                SW_FLOW_KEY_PUT(match, tp.dst,
                                htons(icmp_key->icmp_code), is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_ICMP);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_ICMPV6)) {
+       if (a[OVS_KEY_ATTR_ICMPV6]) {
                const struct ovs_key_icmpv6 *icmpv6_key;
 
                icmpv6_key = nla_data(a[OVS_KEY_ATTR_ICMPV6]);
@@ -869,10 +808,9 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                                htons(icmpv6_key->icmpv6_type), is_mask);
                SW_FLOW_KEY_PUT(match, tp.dst,
                                htons(icmpv6_key->icmpv6_code), is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_ICMPV6);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_ND)) {
+       if (a[OVS_KEY_ATTR_ND]) {
                const struct ovs_key_nd *nd_key;
 
                nd_key = nla_data(a[OVS_KEY_ATTR_ND]);
@@ -884,13 +822,6 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                        nd_key->nd_sll, ETH_ALEN, is_mask);
                SW_FLOW_KEY_MEMCPY(match, ipv6.nd.tll,
                                nd_key->nd_tll, ETH_ALEN, is_mask);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_ND);
-       }
-
-       if (attrs != 0) {
-               OVS_NLERR("Unknown key attributes (%llx).\n",
-                         (unsigned long long)attrs);
-               return -EINVAL;
        }
 
        return 0;
@@ -903,10 +834,8 @@ static void nlattr_set(struct nlattr *attr, u8 val, bool 
is_attr_mask_key)
 
        /* The nlattr stream should already have been validated */
        nla_for_each_nested(nla, attr, rem) {
-               /* We assume that ovs_key_lens[type] == -1 means that type is a
-                * nested attribute
-                */
-               if (is_attr_mask_key && ovs_key_lens[nla_type(nla)] == -1)
+               if (is_attr_mask_key &&
+                   ovs_key_policy[nla_type(nla)].type == NLA_NESTED)
                        nlattr_set(nla, val, false);
                else
                        memset(nla_data(nla), val, nla_len(nla));
@@ -934,37 +863,40 @@ int ovs_nla_get_match(struct sw_flow_match *match,
                      const struct nlattr *nla_key,
                      const struct nlattr *nla_mask)
 {
-       const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
+       const struct nlattr *key_attrs[OVS_KEY_ATTR_MAX + 1];
+       const struct nlattr *mask_attrs[OVS_KEY_ATTR_MAX + 1];
        const struct nlattr *encap;
        struct nlattr *newmask = NULL;
-       u64 key_attrs = 0;
-       u64 mask_attrs = 0;
        bool encap_valid = false;
        int err;
 
-       err = parse_flow_nlattrs(nla_key, a, &key_attrs);
+       memset(key_attrs, 0, sizeof(*key_attrs) * (OVS_KEY_ATTR_MAX + 1));
+       memset(mask_attrs, 0, sizeof(*mask_attrs) * (OVS_KEY_ATTR_MAX + 1));
+       err = parse_nlattrs(nla_key, key_attrs, OVS_KEY_ATTR_MAX, 
ovs_key_policy,
+                           false, false);
        if (err)
                return err;
 
-       if ((key_attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) &&
-           (key_attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) &&
-           (nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) == htons(ETH_P_8021Q))) {
+       if (key_attrs[OVS_KEY_ATTR_ETHERNET] &&
+           key_attrs[OVS_KEY_ATTR_ETHERTYPE] &&
+           nla_get_be16(key_attrs[OVS_KEY_ATTR_ETHERTYPE]) == 
htons(ETH_P_8021Q)) {
                __be16 tci;
 
-               if (!((key_attrs & (1ULL << OVS_KEY_ATTR_VLAN)) &&
-                     (key_attrs & (1ULL << OVS_KEY_ATTR_ENCAP)))) {
+               if (!(key_attrs[OVS_KEY_ATTR_VLAN] &&
+                     key_attrs[OVS_KEY_ATTR_ENCAP])) {
                        OVS_NLERR("Invalid Vlan frame.\n");
                        return -EINVAL;
                }
 
-               key_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE);
-               tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
-               encap = a[OVS_KEY_ATTR_ENCAP];
-               key_attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP);
+               key_attrs[OVS_KEY_ATTR_ETHERTYPE] = NULL;
+               tci = nla_get_be16(key_attrs[OVS_KEY_ATTR_VLAN]);
+               encap = key_attrs[OVS_KEY_ATTR_ENCAP];
+               key_attrs[OVS_KEY_ATTR_ENCAP] = NULL;
                encap_valid = true;
 
                if (tci & htons(VLAN_TAG_PRESENT)) {
-                       err = parse_flow_nlattrs(encap, a, &key_attrs);
+                       err = parse_nlattrs(encap, key_attrs, OVS_KEY_ATTR_MAX,
+                                           ovs_key_policy, false, false);
                        if (err)
                                return err;
                } else if (!tci) {
@@ -979,7 +911,7 @@ int ovs_nla_get_match(struct sw_flow_match *match,
                }
        }
 
-       err = ovs_key_from_nlattrs(match, key_attrs, a, false);
+       err = ovs_key_from_nlattrs(match, key_attrs, false);
        if (err)
                return err;
 
@@ -1014,14 +946,15 @@ int ovs_nla_get_match(struct sw_flow_match *match,
                        nla_mask = newmask;
                }
 
-               err = parse_flow_mask_nlattrs(nla_mask, a, &mask_attrs);
+               err = parse_nlattrs(nla_mask, mask_attrs, OVS_KEY_ATTR_MAX,
+                                   ovs_key_policy, false, true);
                if (err)
                        goto free_newmask;
 
                /* Always match on tci. */
                SW_FLOW_KEY_PUT(match, eth.tci, htons(0xffff), true);
 
-               if (mask_attrs & 1ULL << OVS_KEY_ATTR_ENCAP) {
+               if (mask_attrs[OVS_KEY_ATTR_ENCAP]) {
                        __be16 eth_type = 0;
                        __be16 tci = 0;
 
@@ -1031,14 +964,15 @@ int ovs_nla_get_match(struct sw_flow_match *match,
                                goto free_newmask;
                        }
 
-                       mask_attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP);
-                       if (a[OVS_KEY_ATTR_ETHERTYPE])
-                               eth_type = 
nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
+                       mask_attrs[OVS_KEY_ATTR_ENCAP] = NULL;
+                       if (mask_attrs[OVS_KEY_ATTR_ETHERTYPE])
+                               eth_type = 
nla_get_be16(mask_attrs[OVS_KEY_ATTR_ETHERTYPE]);
 
                        if (eth_type == htons(0xffff)) {
-                               mask_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE);
-                               encap = a[OVS_KEY_ATTR_ENCAP];
-                               err = parse_flow_mask_nlattrs(encap, a, 
&mask_attrs);
+                               mask_attrs[OVS_KEY_ATTR_ETHERTYPE] = NULL;
+                               encap = mask_attrs[OVS_KEY_ATTR_ENCAP];
+                               err = parse_nlattrs(encap, mask_attrs, 
OVS_KEY_ATTR_MAX,
+                                                   ovs_key_policy, false, 
true);
                                if (err)
                                        goto free_newmask;
                        } else {
@@ -1048,8 +982,8 @@ int ovs_nla_get_match(struct sw_flow_match *match,
                                goto free_newmask;
                        }
 
-                       if (a[OVS_KEY_ATTR_VLAN])
-                               tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
+                       if (mask_attrs[OVS_KEY_ATTR_VLAN])
+                               tci = 
nla_get_be16(mask_attrs[OVS_KEY_ATTR_VLAN]);
 
                        if (!(tci & htons(VLAN_TAG_PRESENT))) {
                                OVS_NLERR("VLAN tag present bit must have an 
exact match (tci_mask=%x).\n", ntohs(tci));
@@ -1058,7 +992,7 @@ int ovs_nla_get_match(struct sw_flow_match *match,
                        }
                }
 
-               err = ovs_key_from_nlattrs(match, mask_attrs, a, true);
+               err = ovs_key_from_nlattrs(match, mask_attrs, true);
                if (err)
                        goto free_newmask;
        }
@@ -1087,10 +1021,11 @@ int ovs_nla_get_flow_metadata(const struct nlattr *attr,
 {
        const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
        struct sw_flow_match match;
-       u64 attrs = 0;
        int err;
 
-       err = parse_flow_nlattrs(attr, a, &attrs);
+       memset(a, 0, sizeof(*a) * (OVS_KEY_ATTR_MAX + 1));
+       err = parse_nlattrs(attr, a, OVS_KEY_ATTR_MAX, ovs_key_policy,
+                           false, false);
        if (err)
                return -EINVAL;
 
@@ -1100,7 +1035,7 @@ int ovs_nla_get_flow_metadata(const struct nlattr *attr,
        memset(key, 0, OVS_SW_FLOW_KEY_METADATA_SIZE);
        key->phy.in_port = DP_MAX_PORTS;
 
-       return metadata_from_nlattrs(&match, &attrs, a, false);
+       return metadata_from_nlattrs(&match, a, false);
 }
 
 int ovs_nla_put_flow(const struct sw_flow_key *swkey,
@@ -1605,8 +1540,8 @@ static int validate_set(const struct nlattr *a,
                return -EINVAL;
 
        if (key_type > OVS_KEY_ATTR_MAX ||
-           (ovs_key_lens[key_type] != nla_len(ovs_key) &&
-            ovs_key_lens[key_type] != -1))
+           (ovs_key_policy[key_type].len != nla_len(ovs_key) &&
+            ovs_key_policy[key_type].type != NLA_NESTED))
                return -EINVAL;
 
        switch (key_type) {
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to