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