break;
case OFPACT_RESUBMIT:
+ /* Recirculation complicates resubmit. There are two cases:
+ *
+ * - If mpls_pop has been executed, then the flow table lookup
+ * as part of resubmit might depend on fields that can only
+ * be obtained via recirculation, so the resubmit itself
+ * triggers recirculation and we need to make sure that the
+ * resubmit is executed again after recirculation.
+ * Therefore, in this case we trigger recirculation and let
+ * the code following this "switch" append the resubmit to
+ * the post-recirculation actions.
+ *
+ * - Otherwise, some action in the flow entry found by resubmit
+ * might trigger recirculation. If that happens, then we do
+ * not want to execute the resubmit again after
+ * recirculation, so we want to skip back to the head of the
+ * loop to avoid that, only adding any actions that follow
+ * the resubmit to the post-recirculation actions.
+ */
+ if (ctx->was_mpls) {
+ ctx_trigger_recirculation(ctx);
+ break;
+ }
xlate_ofpact_resubmit(ctx, ofpact_get_RESUBMIT(a));
- break;
+ continue;
case OFPACT_SET_TUNNEL:
flow->tunnel.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id);
OVS_VSWITCHD_STOP
AT_CLEANUP
+# This test verifies that "resubmit", when it triggers recirculation
+# indirectly through the flow that it recursively invokes, is not
+# re-executed when execution continues later post-recirculation.
+AT_SETUP([ofproto-dpif - recirculation after resubmit])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1], [2])
+
+AT_DATA([flows.txt], [dnl
+table=0 in_port=1 actions=resubmit(,1),2
+table=1 in_port=1 actions=debug_recirc
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+
+flow="in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)"
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow" -generate], [0], [stdout])
+AT_CHECK_UNQUOTED([tail -1 stdout], [0], [Datapath actions: recirc(0x1)
+])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow,recirc_id(1)" -generate], [0], [stdout])
+AT_CHECK_UNQUOTED([tail -1 stdout], [0], [Datapath actions: 2
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
# Two testcases below are for the ofproto/trace command
# The first one tests all correct syntax:
# ofproto/trace [dp_name] odp_flow [-generate|packet]