|
@@ -49,6 +49,14 @@
|
|
|
#include <net/mpls.h>
|
|
|
|
|
|
#include "flow_netlink.h"
|
|
|
+#include "vport-vxlan.h"
|
|
|
+
|
|
|
+struct ovs_len_tbl {
|
|
|
+ int len;
|
|
|
+ const struct ovs_len_tbl *next;
|
|
|
+};
|
|
|
+
|
|
|
+#define OVS_ATTR_NESTED -1
|
|
|
|
|
|
static void update_range(struct sw_flow_match *match,
|
|
|
size_t offset, size_t size, bool is_mask)
|
|
@@ -261,6 +269,9 @@ size_t ovs_tun_key_attr_size(void)
|
|
|
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
|
|
|
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
|
|
|
+ nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
|
|
|
+ /* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS is mutually exclusive with
|
|
|
+ * OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it.
|
|
|
+ */
|
|
|
+ nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
|
|
|
+ nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
|
|
|
}
|
|
@@ -289,29 +300,45 @@ size_t ovs_key_attr_size(void)
|
|
|
+ nla_total_size(28); /* OVS_KEY_ATTR_ND */
|
|
|
}
|
|
|
|
|
|
+static const struct ovs_len_tbl ovs_tunnel_key_lens[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 = 1 },
|
|
|
+ [OVS_TUNNEL_KEY_ATTR_TTL] = { .len = 1 },
|
|
|
+ [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = { .len = 0 },
|
|
|
+ [OVS_TUNNEL_KEY_ATTR_CSUM] = { .len = 0 },
|
|
|
+ [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) },
|
|
|
+ [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
|
|
|
+ [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
|
|
|
+ [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED },
|
|
|
+ [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED },
|
|
|
+};
|
|
|
+
|
|
|
/* 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_RECIRC_ID] = sizeof(u32),
|
|
|
- [OVS_KEY_ATTR_DP_HASH] = sizeof(u32),
|
|
|
- [OVS_KEY_ATTR_TUNNEL] = -1,
|
|
|
- [OVS_KEY_ATTR_MPLS] = sizeof(struct ovs_key_mpls),
|
|
|
+static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
|
|
|
+ [OVS_KEY_ATTR_ENCAP] = { .len = OVS_ATTR_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_RECIRC_ID] = { .len = sizeof(u32) },
|
|
|
+ [OVS_KEY_ATTR_DP_HASH] = { .len = sizeof(u32) },
|
|
|
+ [OVS_KEY_ATTR_TUNNEL] = { .len = OVS_ATTR_NESTED,
|
|
|
+ .next = ovs_tunnel_key_lens, },
|
|
|
+ [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) },
|
|
|
};
|
|
|
|
|
|
static bool is_all_zero(const u8 *fp, size_t size)
|
|
@@ -352,8 +379,8 @@ static int __parse_flow_nlattrs(const struct nlattr *attr,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- expected_len = ovs_key_lens[type];
|
|
|
- if (nla_len(nla) != expected_len && expected_len != -1) {
|
|
|
+ expected_len = ovs_key_lens[type].len;
|
|
|
+ if (nla_len(nla) != expected_len && expected_len != OVS_ATTR_NESTED) {
|
|
|
OVS_NLERR(log, "Key %d has unexpected len %d expected %d",
|
|
|
type, nla_len(nla), expected_len);
|
|
|
return -EINVAL;
|
|
@@ -432,13 +459,47 @@ static int genev_tun_opt_from_nlattr(const struct nlattr *a,
|
|
|
SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
|
|
|
}
|
|
|
|
|
|
- opt_key_offset = (unsigned long)GENEVE_OPTS((struct sw_flow_key *)0,
|
|
|
- nla_len(a));
|
|
|
+ opt_key_offset = TUN_METADATA_OFFSET(nla_len(a));
|
|
|
SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a),
|
|
|
nla_len(a), is_mask);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static const struct nla_policy vxlan_opt_policy[OVS_VXLAN_EXT_MAX + 1] = {
|
|
|
+ [OVS_VXLAN_EXT_GBP] = { .type = NLA_U32 },
|
|
|
+};
|
|
|
+
|
|
|
+static int vxlan_tun_opt_from_nlattr(const struct nlattr *a,
|
|
|
+ struct sw_flow_match *match, bool is_mask,
|
|
|
+ bool log)
|
|
|
+{
|
|
|
+ struct nlattr *tb[OVS_VXLAN_EXT_MAX+1];
|
|
|
+ unsigned long opt_key_offset;
|
|
|
+ struct ovs_vxlan_opts opts;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
|
|
|
+
|
|
|
+ err = nla_parse_nested(tb, OVS_VXLAN_EXT_MAX, a, vxlan_opt_policy);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ memset(&opts, 0, sizeof(opts));
|
|
|
+
|
|
|
+ if (tb[OVS_VXLAN_EXT_GBP])
|
|
|
+ opts.gbp = nla_get_u32(tb[OVS_VXLAN_EXT_GBP]);
|
|
|
+
|
|
|
+ if (!is_mask)
|
|
|
+ SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false);
|
|
|
+ else
|
|
|
+ SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
|
|
|
+
|
|
|
+ opt_key_offset = TUN_METADATA_OFFSET(sizeof(opts));
|
|
|
+ SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, &opts, sizeof(opts),
|
|
|
+ is_mask);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int ipv4_tun_from_nlattr(const struct nlattr *attr,
|
|
|
struct sw_flow_match *match, bool is_mask,
|
|
|
bool log)
|
|
@@ -447,35 +508,22 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
|
|
|
int rem;
|
|
|
bool ttl = false;
|
|
|
__be16 tun_flags = 0;
|
|
|
+ int opts_type = 0;
|
|
|
|
|
|
nla_for_each_nested(a, attr, rem) {
|
|
|
int type = nla_type(a);
|
|
|
int err;
|
|
|
|
|
|
- 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,
|
|
|
- };
|
|
|
-
|
|
|
if (type > OVS_TUNNEL_KEY_ATTR_MAX) {
|
|
|
OVS_NLERR(log, "Tunnel attr %d out of range max %d",
|
|
|
type, OVS_TUNNEL_KEY_ATTR_MAX);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- if (ovs_tunnel_key_lens[type] != nla_len(a) &&
|
|
|
- ovs_tunnel_key_lens[type] != -1) {
|
|
|
+ if (ovs_tunnel_key_lens[type].len != nla_len(a) &&
|
|
|
+ ovs_tunnel_key_lens[type].len != OVS_ATTR_NESTED) {
|
|
|
OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d",
|
|
|
- type, nla_len(a), ovs_tunnel_key_lens[type]);
|
|
|
+ type, nla_len(a), ovs_tunnel_key_lens[type].len);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -520,11 +568,30 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
|
|
|
tun_flags |= TUNNEL_OAM;
|
|
|
break;
|
|
|
case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
|
|
|
+ if (opts_type) {
|
|
|
+ OVS_NLERR(log, "Multiple metadata blocks provided");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
err = genev_tun_opt_from_nlattr(a, match, is_mask, log);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
- tun_flags |= TUNNEL_OPTIONS_PRESENT;
|
|
|
+ tun_flags |= TUNNEL_GENEVE_OPT;
|
|
|
+ opts_type = type;
|
|
|
+ break;
|
|
|
+ case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
|
|
|
+ if (opts_type) {
|
|
|
+ OVS_NLERR(log, "Multiple metadata blocks provided");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = vxlan_tun_opt_from_nlattr(a, match, is_mask, log);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ tun_flags |= TUNNEL_VXLAN_OPT;
|
|
|
+ opts_type = type;
|
|
|
break;
|
|
|
default:
|
|
|
OVS_NLERR(log, "Unknown IPv4 tunnel attribute %d",
|
|
@@ -553,13 +620,29 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ return opts_type;
|
|
|
+}
|
|
|
+
|
|
|
+static int vxlan_opt_to_nlattr(struct sk_buff *skb,
|
|
|
+ const void *tun_opts, int swkey_tun_opts_len)
|
|
|
+{
|
|
|
+ const struct ovs_vxlan_opts *opts = tun_opts;
|
|
|
+ struct nlattr *nla;
|
|
|
+
|
|
|
+ nla = nla_nest_start(skb, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
|
|
|
+ if (!nla)
|
|
|
+ return -EMSGSIZE;
|
|
|
+
|
|
|
+ if (nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
|
|
|
+ return -EMSGSIZE;
|
|
|
+
|
|
|
+ nla_nest_end(skb, nla);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
|
|
|
const struct ovs_key_ipv4_tunnel *output,
|
|
|
- const struct geneve_opt *tun_opts,
|
|
|
- int swkey_tun_opts_len)
|
|
|
+ const void *tun_opts, int swkey_tun_opts_len)
|
|
|
{
|
|
|
if (output->tun_flags & TUNNEL_KEY &&
|
|
|
nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id))
|
|
@@ -590,18 +673,22 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
|
|
|
if ((output->tun_flags & TUNNEL_OAM) &&
|
|
|
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
|
|
|
return -EMSGSIZE;
|
|
|
- if (tun_opts &&
|
|
|
- nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
|
|
|
- swkey_tun_opts_len, tun_opts))
|
|
|
- return -EMSGSIZE;
|
|
|
+ if (tun_opts) {
|
|
|
+ if (output->tun_flags & TUNNEL_GENEVE_OPT &&
|
|
|
+ nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
|
|
|
+ swkey_tun_opts_len, tun_opts))
|
|
|
+ return -EMSGSIZE;
|
|
|
+ else if (output->tun_flags & TUNNEL_VXLAN_OPT &&
|
|
|
+ vxlan_opt_to_nlattr(skb, tun_opts, swkey_tun_opts_len))
|
|
|
+ return -EMSGSIZE;
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int ipv4_tun_to_nlattr(struct sk_buff *skb,
|
|
|
const struct ovs_key_ipv4_tunnel *output,
|
|
|
- const struct geneve_opt *tun_opts,
|
|
|
- int swkey_tun_opts_len)
|
|
|
+ const void *tun_opts, int swkey_tun_opts_len)
|
|
|
{
|
|
|
struct nlattr *nla;
|
|
|
int err;
|
|
@@ -675,7 +762,7 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
|
|
|
}
|
|
|
if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) {
|
|
|
if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
|
|
|
- is_mask, log))
|
|
|
+ is_mask, log) < 0)
|
|
|
return -EINVAL;
|
|
|
*attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);
|
|
|
}
|
|
@@ -915,18 +1002,16 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void nlattr_set(struct nlattr *attr, u8 val, bool is_attr_mask_key)
|
|
|
+static void nlattr_set(struct nlattr *attr, u8 val,
|
|
|
+ const struct ovs_len_tbl *tbl)
|
|
|
{
|
|
|
struct nlattr *nla;
|
|
|
int rem;
|
|
|
|
|
|
/* 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)
|
|
|
- nlattr_set(nla, val, false);
|
|
|
+ if (tbl && tbl[nla_type(nla)].len == OVS_ATTR_NESTED)
|
|
|
+ nlattr_set(nla, val, tbl[nla_type(nla)].next);
|
|
|
else
|
|
|
memset(nla_data(nla), val, nla_len(nla));
|
|
|
}
|
|
@@ -934,7 +1019,7 @@ static void nlattr_set(struct nlattr *attr, u8 val, bool is_attr_mask_key)
|
|
|
|
|
|
static void mask_set_nlattr(struct nlattr *attr, u8 val)
|
|
|
{
|
|
|
- nlattr_set(attr, val, true);
|
|
|
+ nlattr_set(attr, val, ovs_key_lens);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1148,10 +1233,10 @@ int ovs_nla_put_flow(const struct sw_flow_key *swkey,
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
if ((swkey->tun_key.ipv4_dst || is_mask)) {
|
|
|
- const struct geneve_opt *opts = NULL;
|
|
|
+ const void *opts = NULL;
|
|
|
|
|
|
if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT)
|
|
|
- opts = GENEVE_OPTS(output, swkey->tun_opts_len);
|
|
|
+ opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len);
|
|
|
|
|
|
if (ipv4_tun_to_nlattr(skb, &output->tun_key, opts,
|
|
|
swkey->tun_opts_len))
|
|
@@ -1540,6 +1625,34 @@ void ovs_match_init(struct sw_flow_match *match,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int validate_geneve_opts(struct sw_flow_key *key)
|
|
|
+{
|
|
|
+ struct geneve_opt *option;
|
|
|
+ int opts_len = key->tun_opts_len;
|
|
|
+ bool crit_opt = false;
|
|
|
+
|
|
|
+ option = (struct geneve_opt *)TUN_METADATA_OPTS(key, key->tun_opts_len);
|
|
|
+ while (opts_len > 0) {
|
|
|
+ int len;
|
|
|
+
|
|
|
+ if (opts_len < sizeof(*option))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ len = sizeof(*option) + option->length * 4;
|
|
|
+ if (len > opts_len)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ crit_opt |= !!(option->type & GENEVE_CRIT_OPT_TYPE);
|
|
|
+
|
|
|
+ option = (struct geneve_opt *)((u8 *)option + len);
|
|
|
+ opts_len -= len;
|
|
|
+ };
|
|
|
+
|
|
|
+ key->tun_key.tun_flags |= crit_opt ? TUNNEL_CRIT_OPT : 0;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int validate_and_copy_set_tun(const struct nlattr *attr,
|
|
|
struct sw_flow_actions **sfa, bool log)
|
|
|
{
|
|
@@ -1547,36 +1660,23 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
|
|
|
struct sw_flow_key key;
|
|
|
struct ovs_tunnel_info *tun_info;
|
|
|
struct nlattr *a;
|
|
|
- int err, start;
|
|
|
+ int err, start, opts_type;
|
|
|
|
|
|
ovs_match_init(&match, &key, NULL);
|
|
|
- err = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
+ opts_type = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log);
|
|
|
+ if (opts_type < 0)
|
|
|
+ return opts_type;
|
|
|
|
|
|
if (key.tun_opts_len) {
|
|
|
- struct geneve_opt *option = GENEVE_OPTS(&key,
|
|
|
- key.tun_opts_len);
|
|
|
- int opts_len = key.tun_opts_len;
|
|
|
- bool crit_opt = false;
|
|
|
-
|
|
|
- while (opts_len > 0) {
|
|
|
- int len;
|
|
|
-
|
|
|
- if (opts_len < sizeof(*option))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- len = sizeof(*option) + option->length * 4;
|
|
|
- if (len > opts_len)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- crit_opt |= !!(option->type & GENEVE_CRIT_OPT_TYPE);
|
|
|
-
|
|
|
- option = (struct geneve_opt *)((u8 *)option + len);
|
|
|
- opts_len -= len;
|
|
|
- };
|
|
|
-
|
|
|
- key.tun_key.tun_flags |= crit_opt ? TUNNEL_CRIT_OPT : 0;
|
|
|
+ switch (opts_type) {
|
|
|
+ case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
|
|
|
+ err = validate_geneve_opts(&key);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ break;
|
|
|
+ case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
|
|
|
+ break;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET, log);
|
|
@@ -1597,9 +1697,9 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
|
|
|
* everything else will go away after flow setup. We can append
|
|
|
* it to tun_info and then point there.
|
|
|
*/
|
|
|
- memcpy((tun_info + 1), GENEVE_OPTS(&key, key.tun_opts_len),
|
|
|
- key.tun_opts_len);
|
|
|
- tun_info->options = (struct geneve_opt *)(tun_info + 1);
|
|
|
+ memcpy((tun_info + 1),
|
|
|
+ TUN_METADATA_OPTS(&key, key.tun_opts_len), key.tun_opts_len);
|
|
|
+ tun_info->options = (tun_info + 1);
|
|
|
} else {
|
|
|
tun_info->options = NULL;
|
|
|
}
|
|
@@ -1622,8 +1722,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_lens[key_type].len != nla_len(ovs_key) &&
|
|
|
+ ovs_key_lens[key_type].len != OVS_ATTR_NESTED))
|
|
|
return -EINVAL;
|
|
|
|
|
|
switch (key_type) {
|