Commit 2df0987e8222 moved OFPACT_CT_CLEAR to the non-reversible list, so
clone(ct_clear, ...) goes through the datapath-clone path and the
ct_clear is isolated from the outer context.

reversible_actions() only inspects the immediate actions of the clone.
When those actions are just a resubmit (or goto_table, group, nested
clone), the clone is still classified as reversible.  The rule reached
through that indirection can still issue ct_clear (or ct/nat).  On a
tracked packet, the reversible path then emits that inner ct_clear
inline, which clears ct_state on the original packet, so a later
ct_clear after the clone becomes a no-op.

Example flow:
    table=1,ct_state=+trk,ip,actions=clone(resubmit(,10)),
                                     ct_clear,resubmit(,20)
    table=10,ip,actions=ct_clear,output:2
The original packet loses its ct_state inside the clone and the outer
ct_clear is skipped.

Treat resubmit, goto_table, group and nested clone as non-reversible
when the packet is tracked.  The clone body is then wrapped in a
datapath clone() and its conntrack effects stay inside the clone.
Untracked packets keep the existing optimization.

Test added in tests/ofproto-dpif.at.

Fixes: 2df0987e8222 ("ofproto-dpif-xlate: Classify ct_clear as non-reversible 
for clone().")
Signed-off-by: Naveen Yerramneni <[email protected]>
---
 ofproto/ofproto-dpif-xlate.c | 26 +++++++++++++++++++-------
 tests/ofproto-dpif.at        | 21 +++++++++++++++++++++
 2 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index c1ba447e9..6ac525e1d 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -6113,9 +6113,15 @@ xlate_sample_action(struct xlate_ctx *ctx,
  *
  * Openflow actions that do not emit datapath actions are trivially
  * reversible. Reversiblity of other actions depends on nature of
- * action and their translation.  */
+ * action and their translation.
+ *
+ * if conntracked is true, actions that indirectly run other OF actions
+ * (resubmit, goto_table, group, nested clone) are treated as non-reversible
+ * since they may reach a ct_clear/ct/nat that would mutate the original
+ * tracked packet. */
 static bool
-reversible_actions(const struct ofpact *ofpacts, size_t ofpacts_len)
+reversible_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+                   bool conntracked)
 {
     const struct ofpact *a;
 
@@ -6123,7 +6129,6 @@ reversible_actions(const struct ofpact *ofpacts, size_t 
ofpacts_len)
         switch (a->type) {
         case OFPACT_BUNDLE:
         case OFPACT_CLEAR_ACTIONS:
-        case OFPACT_CLONE:
         case OFPACT_CONJUNCTION:
         case OFPACT_CONTROLLER:
         case OFPACT_DEBUG_RECIRC:
@@ -6133,8 +6138,6 @@ reversible_actions(const struct ofpact *ofpacts, size_t 
ofpacts_len)
         case OFPACT_ENQUEUE:
         case OFPACT_EXIT:
         case OFPACT_FIN_TIMEOUT:
-        case OFPACT_GOTO_TABLE:
-        case OFPACT_GROUP:
         case OFPACT_LEARN:
         case OFPACT_MULTIPATH:
         case OFPACT_NOTE:
@@ -6145,7 +6148,6 @@ reversible_actions(const struct ofpact *ofpacts, size_t 
ofpacts_len)
         case OFPACT_PUSH_MPLS:
         case OFPACT_PUSH_VLAN:
         case OFPACT_REG_MOVE:
-        case OFPACT_RESUBMIT:
         case OFPACT_SAMPLE:
         case OFPACT_SET_ETH_DST:
         case OFPACT_SET_ETH_SRC:
@@ -6174,6 +6176,15 @@ reversible_actions(const struct ofpact *ofpacts, size_t 
ofpacts_len)
         case OFPACT_DELETE_FIELD:
             break;
 
+        case OFPACT_CLONE:
+        case OFPACT_GOTO_TABLE:
+        case OFPACT_GROUP:
+        case OFPACT_RESUBMIT:
+            if (conntracked) {
+                return false;
+            }
+            break;
+
         case OFPACT_CT:
         case OFPACT_CT_CLEAR:
         case OFPACT_METER:
@@ -6198,7 +6209,8 @@ clone_xlate_actions(const struct ofpact *actions, size_t 
actions_len,
 
     retained_state = xretain_state_save(ctx);
 
-    if (reversible_actions(actions, actions_len) || is_last_action) {
+    if (reversible_actions(actions, actions_len, ctx->conntracked)
+        || is_last_action) {
         do_xlate_actions(actions, actions_len, ctx, is_last_action, false);
         if (!ctx->freezing) {
             xlate_action_set(ctx);
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index dcab7bba4..0cc8c90d5 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -9322,6 +9322,27 @@ Datapath actions: ct,recirc(X)
 Datapath actions: clone(ct_clear,2),ct_clear,3
 ])
 
+dnl On a tracked packet, a resubmit/goto_table/group/nested-clone inside
+dnl clone() may reach a ct_clear in another table.  Such an inner ct_clear
+dnl must be emitted inside a datapath clone() wrapper so it cannot mutate
+dnl the original packet, and the outer ct_clear must still take effect.
+AT_DATA([flows.txt], [dnl
+table=0,in_port=1,ip,actions=ct(table=1)
+table=1,ct_state=+trk,ip,actions=clone(resubmit(,10)),ct_clear,resubmit(,20)
+table=10,ip,actions=ct_clear,output:2
+table=20,ct_state=+trk,ip,actions=drop
+table=20,priority=10,ip,actions=output:3
+])
+AT_CHECK([ovs-ofctl del-flows br0])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt], [0], [ignore])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'],
 [0], [stdout])
+
+AT_CHECK([grep Datapath stdout | sed 's/recirc(.*)/recirc(X)/'], [0], [dnl
+Datapath actions: ct,recirc(X)
+Datapath actions: clone(ct_clear,2),ct_clear,3
+])
+
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
-- 
2.43.5

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to