Signed-off-by: Joe Stringer <joestrin...@nicira.com>
---
 datapath/flow_netlink.c |   85 ++++++++++++++++++++++-------------------------
 1 file changed, 39 insertions(+), 46 deletions(-)

diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index 933b2a1..01f6e49 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -350,60 +350,58 @@ static int parse_flow_nlattrs(const struct nlattr *attr,
 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 int 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_OAM] = 0,
+               [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1,
+       };
+       const struct nlattr *a[OVS_TUNNEL_KEY_ATTR_MAX + 1];
        bool ttl = false;
        __be16 tun_flags = 0;
+       enum ovs_tunnel_key_attr type;
+       u64 attrs = 0;
+       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_OAM] = 0,
-                       [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1,
-               };
+       err = parse_nlattrs(attr, a, ovs_tunnel_key_lens,
+                           OVS_TUNNEL_KEY_ATTR_MAX + 1, true, "IPv4 tunnel",
+                           &attrs, 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 (!(attrs & (1ULL << 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:
@@ -417,18 +415,18 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
                        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;
                        }
 
@@ -437,7 +435,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
@@ -450,10 +448,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;
                                }
 
@@ -463,8 +461,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);
@@ -474,11 +472,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");
-- 
1.7.10.4

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

Reply via email to