]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - net/openvswitch/flow_netlink.c
Merge tag 'driver-core-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-artful-kernel.git] / net / openvswitch / flow_netlink.c
index c87d359b9b37a07711c65e61a1cb882148f76ee0..6f5fa50f716d066333b30edde43e5165b9fe94be 100644 (file)
@@ -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);
 }
@@ -1056,14 +1072,14 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
                        return -EINVAL;
                }
 
-               SW_FLOW_KEY_PUT(match, ct.state, ct_state, is_mask);
+               SW_FLOW_KEY_PUT(match, ct_state, ct_state, is_mask);
                *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE);
        }
        if (*attrs & (1 << OVS_KEY_ATTR_CT_ZONE) &&
            ovs_ct_verify(net, OVS_KEY_ATTR_CT_ZONE)) {
                u16 ct_zone = nla_get_u16(a[OVS_KEY_ATTR_CT_ZONE]);
 
-               SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask);
+               SW_FLOW_KEY_PUT(match, ct_zone, ct_zone, is_mask);
                *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);
        }
        if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) &&
@@ -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,26 @@ 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;
 
+       key->ct_state = 0;
+       key->ct_zone = 0;
+       key->ct_orig_proto = 0;
        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 +1632,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) {