|
@@ -129,7 +129,9 @@ static bool match_validate(const struct sw_flow_match *match,
|
|
|
/* The following mask attributes allowed only if they
|
|
|
* pass the validation tests. */
|
|
|
mask_allowed &= ~((1 << OVS_KEY_ATTR_IPV4)
|
|
|
+ | (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4)
|
|
|
| (1 << OVS_KEY_ATTR_IPV6)
|
|
|
+ | (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6)
|
|
|
| (1 << OVS_KEY_ATTR_TCP)
|
|
|
| (1 << OVS_KEY_ATTR_TCP_FLAGS)
|
|
|
| (1 << OVS_KEY_ATTR_UDP)
|
|
@@ -161,8 +163,10 @@ static bool match_validate(const struct sw_flow_match *match,
|
|
|
|
|
|
if (match->key->eth.type == htons(ETH_P_IP)) {
|
|
|
key_expected |= 1 << OVS_KEY_ATTR_IPV4;
|
|
|
- if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
|
|
|
+ if (match->mask && match->mask->key.eth.type == htons(0xffff)) {
|
|
|
mask_allowed |= 1 << OVS_KEY_ATTR_IPV4;
|
|
|
+ mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4;
|
|
|
+ }
|
|
|
|
|
|
if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {
|
|
|
if (match->key->ip.proto == IPPROTO_UDP) {
|
|
@@ -196,8 +200,10 @@ static bool match_validate(const struct sw_flow_match *match,
|
|
|
|
|
|
if (match->key->eth.type == htons(ETH_P_IPV6)) {
|
|
|
key_expected |= 1 << OVS_KEY_ATTR_IPV6;
|
|
|
- if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
|
|
|
+ if (match->mask && match->mask->key.eth.type == htons(0xffff)) {
|
|
|
mask_allowed |= 1 << OVS_KEY_ATTR_IPV6;
|
|
|
+ mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6;
|
|
|
+ }
|
|
|
|
|
|
if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {
|
|
|
if (match->key->ip.proto == IPPROTO_UDP) {
|
|
@@ -230,6 +236,12 @@ static bool match_validate(const struct sw_flow_match *match,
|
|
|
htons(NDISC_NEIGHBOUR_SOLICITATION) ||
|
|
|
match->key->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {
|
|
|
key_expected |= 1 << OVS_KEY_ATTR_ND;
|
|
|
+ /* Original direction conntrack tuple
|
|
|
+ * uses the same space as the ND fields
|
|
|
+ * in the key, so both are not allowed
|
|
|
+ * at the same time.
|
|
|
+ */
|
|
|
+ mask_allowed &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6);
|
|
|
if (match->mask && (match->mask->key.tp.src == htons(0xff)))
|
|
|
mask_allowed |= 1 << OVS_KEY_ATTR_ND;
|
|
|
}
|
|
@@ -282,7 +294,7 @@ size_t ovs_key_attr_size(void)
|
|
|
/* Whenever adding new OVS_KEY_ FIELDS, we should consider
|
|
|
* updating this function.
|
|
|
*/
|
|
|
- BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 26);
|
|
|
+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 28);
|
|
|
|
|
|
return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
|
|
|
+ nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
|
|
@@ -295,6 +307,7 @@ size_t ovs_key_attr_size(void)
|
|
|
+ nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
|
|
|
+ nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
|
|
|
+ nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */
|
|
|
+ + nla_total_size(40) /* OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6 */
|
|
|
+ nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
|
|
|
+ nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
|
|
|
+ nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
|
|
@@ -355,6 +368,10 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
|
|
|
[OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) },
|
|
|
[OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) },
|
|
|
[OVS_KEY_ATTR_CT_LABELS] = { .len = sizeof(struct ovs_key_ct_labels) },
|
|
|
+ [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4] = {
|
|
|
+ .len = sizeof(struct ovs_key_ct_tuple_ipv4) },
|
|
|
+ [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = {
|
|
|
+ .len = sizeof(struct ovs_key_ct_tuple_ipv6) },
|
|
|
};
|
|
|
|
|
|
static bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
|
|
@@ -430,9 +447,8 @@ static int parse_flow_mask_nlattrs(const struct nlattr *attr,
|
|
|
return __parse_flow_nlattrs(attr, a, attrsp, log, true);
|
|
|
}
|
|
|
|
|
|
-static int parse_flow_nlattrs(const struct nlattr *attr,
|
|
|
- const struct nlattr *a[], u64 *attrsp,
|
|
|
- bool log)
|
|
|
+int parse_flow_nlattrs(const struct nlattr *attr, const struct nlattr *a[],
|
|
|
+ u64 *attrsp, bool log)
|
|
|
{
|
|
|
return __parse_flow_nlattrs(attr, a, attrsp, log, false);
|
|
|
}
|
|
@@ -1082,6 +1098,34 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
|
|
|
sizeof(*cl), is_mask);
|
|
|
*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABELS);
|
|
|
}
|
|
|
+ if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4)) {
|
|
|
+ const struct ovs_key_ct_tuple_ipv4 *ct;
|
|
|
+
|
|
|
+ ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4]);
|
|
|
+
|
|
|
+ SW_FLOW_KEY_PUT(match, ipv4.ct_orig.src, ct->ipv4_src, is_mask);
|
|
|
+ SW_FLOW_KEY_PUT(match, ipv4.ct_orig.dst, ct->ipv4_dst, is_mask);
|
|
|
+ SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask);
|
|
|
+ SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask);
|
|
|
+ SW_FLOW_KEY_PUT(match, ct.orig_proto, ct->ipv4_proto, is_mask);
|
|
|
+ *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4);
|
|
|
+ }
|
|
|
+ if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6)) {
|
|
|
+ const struct ovs_key_ct_tuple_ipv6 *ct;
|
|
|
+
|
|
|
+ ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]);
|
|
|
+
|
|
|
+ SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.src, &ct->ipv6_src,
|
|
|
+ sizeof(match->key->ipv6.ct_orig.src),
|
|
|
+ is_mask);
|
|
|
+ SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.dst, &ct->ipv6_dst,
|
|
|
+ sizeof(match->key->ipv6.ct_orig.dst),
|
|
|
+ is_mask);
|
|
|
+ SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask);
|
|
|
+ SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask);
|
|
|
+ SW_FLOW_KEY_PUT(match, ct.orig_proto, ct->ipv6_proto, is_mask);
|
|
|
+ *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6);
|
|
|
+ }
|
|
|
|
|
|
/* For layer 3 packets the Ethernet type is provided
|
|
|
* and treated as metadata but no MAC addresses are provided.
|
|
@@ -1493,9 +1537,12 @@ u32 ovs_nla_get_ufid_flags(const struct nlattr *attr)
|
|
|
|
|
|
/**
|
|
|
* ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key.
|
|
|
- * @key: Receives extracted in_port, priority, tun_key and skb_mark.
|
|
|
- * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
|
|
|
- * sequence.
|
|
|
+ * @net: Network namespace.
|
|
|
+ * @key: Receives extracted in_port, priority, tun_key, skb_mark and conntrack
|
|
|
+ * metadata.
|
|
|
+ * @a: Array of netlink attributes holding parsed %OVS_KEY_ATTR_* Netlink
|
|
|
+ * attributes.
|
|
|
+ * @attrs: Bit mask for the netlink attributes included in @a.
|
|
|
* @log: Boolean to allow kernel error logging. Normally true, but when
|
|
|
* probing for feature compatibility this should be passed in as false to
|
|
|
* suppress unnecessary error logging.
|
|
@@ -1504,25 +1551,23 @@ u32 ovs_nla_get_ufid_flags(const struct nlattr *attr)
|
|
|
* take the same form accepted by flow_from_nlattrs(), but only enough of it to
|
|
|
* get the metadata, that is, the parts of the flow key that cannot be
|
|
|
* extracted from the packet itself.
|
|
|
+ *
|
|
|
+ * This must be called before the packet key fields are filled in 'key'.
|
|
|
*/
|
|
|
|
|
|
-int ovs_nla_get_flow_metadata(struct net *net, const struct nlattr *attr,
|
|
|
- struct sw_flow_key *key,
|
|
|
- bool log)
|
|
|
+int ovs_nla_get_flow_metadata(struct net *net,
|
|
|
+ const struct nlattr *a[OVS_KEY_ATTR_MAX + 1],
|
|
|
+ u64 attrs, struct sw_flow_key *key, bool log)
|
|
|
{
|
|
|
- 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, log);
|
|
|
- if (err)
|
|
|
- return -EINVAL;
|
|
|
|
|
|
memset(&match, 0, sizeof(match));
|
|
|
match.key = key;
|
|
|
|
|
|
memset(&key->ct, 0, sizeof(key->ct));
|
|
|
+ memset(&key->ipv4.ct_orig, 0, sizeof(key->ipv4.ct_orig));
|
|
|
+ memset(&key->ipv6.ct_orig, 0, sizeof(key->ipv6.ct_orig));
|
|
|
+
|
|
|
key->phy.in_port = DP_MAX_PORTS;
|
|
|
|
|
|
return metadata_from_nlattrs(net, &match, &attrs, a, false, log);
|
|
@@ -1584,7 +1629,7 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
|
|
|
if (nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark))
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
- if (ovs_ct_put_key(output, skb))
|
|
|
+ if (ovs_ct_put_key(swkey, output, skb))
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
if (ovs_key_mac_proto(swkey) == MAC_PROTO_ETHERNET) {
|