]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/openvswitch/conntrack.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[karo-tx-linux.git] / net / openvswitch / conntrack.c
index d84312584ee46a5fa82040c1802b98897f4b5aef..b4069a90e375811334c1835ea02f73851d36ee77 100644 (file)
@@ -834,6 +834,17 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
        return 0;
 }
 
+static bool labels_nonzero(const struct ovs_key_ct_labels *labels)
+{
+       size_t i;
+
+       for (i = 0; i < sizeof(*labels); i++)
+               if (labels->ct_labels[i])
+                       return true;
+
+       return false;
+}
+
 /* Lookup connection and confirm if unconfirmed. */
 static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
                         const struct ovs_conntrack_info *info,
@@ -844,24 +855,32 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
        err = __ovs_ct_lookup(net, key, info, skb);
        if (err)
                return err;
-       /* This is a no-op if the connection has already been confirmed. */
+
+       /* Apply changes before confirming the connection so that the initial
+        * conntrack NEW netlink event carries the values given in the CT
+        * action.
+        */
+       if (info->mark.mask) {
+               err = ovs_ct_set_mark(skb, key, info->mark.value,
+                                     info->mark.mask);
+               if (err)
+                       return err;
+       }
+       if (labels_nonzero(&info->labels.mask)) {
+               err = ovs_ct_set_labels(skb, key, &info->labels.value,
+                                       &info->labels.mask);
+               if (err)
+                       return err;
+       }
+       /* This will take care of sending queued events even if the connection
+        * is already confirmed.
+        */
        if (nf_conntrack_confirm(skb) != NF_ACCEPT)
                return -EINVAL;
 
        return 0;
 }
 
-static bool labels_nonzero(const struct ovs_key_ct_labels *labels)
-{
-       size_t i;
-
-       for (i = 0; i < sizeof(*labels); i++)
-               if (labels->ct_labels[i])
-                       return true;
-
-       return false;
-}
-
 /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero
  * value if 'skb' is freed.
  */
@@ -886,19 +905,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
                err = ovs_ct_commit(net, key, info, skb);
        else
                err = ovs_ct_lookup(net, key, info, skb);
-       if (err)
-               goto err;
 
-       if (info->mark.mask) {
-               err = ovs_ct_set_mark(skb, key, info->mark.value,
-                                     info->mark.mask);
-               if (err)
-                       goto err;
-       }
-       if (labels_nonzero(&info->labels.mask))
-               err = ovs_ct_set_labels(skb, key, &info->labels.value,
-                                       &info->labels.mask);
-err:
        skb_push(skb, nh_ofs);
        if (err)
                kfree_skb(skb);
@@ -1155,6 +1162,20 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
                }
        }
 
+#ifdef CONFIG_NF_CONNTRACK_MARK
+       if (!info->commit && info->mark.mask) {
+               OVS_NLERR(log,
+                         "Setting conntrack mark requires 'commit' flag.");
+               return -EINVAL;
+       }
+#endif
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       if (!info->commit && labels_nonzero(&info->labels.mask)) {
+               OVS_NLERR(log,
+                         "Setting conntrack labels requires 'commit' flag.");
+               return -EINVAL;
+       }
+#endif
        if (rem > 0) {
                OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem);
                return -EINVAL;