While processing OpenFlow clone() action, current code makes decisions
to skip the datapath level clone() based on incorrect assumption that
checking immediate OpenFlow actions is enough to make a decision. But
that is absolutely not true. Some OpenFlow actions may be reversible
or not reversible depending on which datapath action we'll end up
using, e.g. dec_ttl can be implemented reversibly by setting a new TTL
value, or it can be non-reversable if the dec_ttl datapath action is
used. Also, things like groups, resubmits, goto-table and output to
patch ports are completely unpredictable as there is no visibility if
they will produce non-reversible actions or not until they are fully
translated. But they are marked as reversible for some reason in the
current code. This causes problems where clones are omitted in cases
where they must not be, breaking the traffic or applying modifications
to packets that should not be modified.
There were multiple attempts to add small tweaks here and there to
make the code more accurate without producing excessive amount of
clone() actions on the datapath level, which are expensive. But none
of them addressed the core of the issue - that decisions are made
based on the wrong information which is OpenFlow action list. And so,
none of these solutions can fully solve the problem.
To fix this, we need to actually translate all the actions and check
if the result is reversible or not on the datapath actions level.
There are few tricky cases here:
- All the PUSH/POP/ENCAP/DECAP actions are not reversible as they for
the most part require packet re-parsing, except for VLAN and MPLS
ones that can be reverted on xlate commit. However, ADD_MPLS is
not reversible as it changes the packet type and requires extra
manipulations with the ethernet header.
- HASH is not reversible, because it sets the hash using the current
set of headers and we need to re-hash if something changes. There
is no hash-clear action, so it may be wrongly reused.
- RECIRC is reversible, because datapath will clone whenever it's not
the last action.
- DEC_TTL is not reversible as the TTL value is not being matched in
this case and so we don't know to which value to revert and there is
no INC_TTL.
- CHECK_PKT_LEN doesn't internally clone the packet, so we need to
recursively check action lists in both branches.
A bunch of tests added to cover most of the cases.
One issue with this change is that in order to be able to make a
cloning decision after the translation is done, we must commit all the
pending actions before translating the clone. This way the actions
for the clone will be the same regardless of wrapping. But it means
that if there are header updates before the clone and there are some
inside the clone and we omit the actual clone, then both SET actions
will remain, potentially changing the same field one after another.
This is not optimal and does produce larger action sets, as seen in
the tests, but should not be a big problem.
Getting rid of those would require translating the whole thing twice,
which is not good for performance, or doing some sort of surgical
collapsing of the SET actions after the fact, which is tricky.
Another side effect is that hash action is now wrapped in tunnel
tests, for these we need to properly track the last action through
the NORMAL pipeline, which should be done as a separate change.
Fixes: eee693934aac ("xlate: Emit datapath clone only when necessary.")
Signed-off-by: Ilya Maximets <[email protected]>
---
lib/netlink.c | 11 ++
lib/netlink.h | 2 +
ofproto/ofproto-dpif-xlate.c | 288 +++++++++++++++-------------
tests/ofproto-dpif.at | 342 +++++++++++++++++++++++++---------
tests/tunnel-push-pop-ipv6.at | 4 +-
tests/tunnel-push-pop.at | 4 +-
6 files changed, 428 insertions(+), 223 deletions(-)
diff --git a/lib/netlink.c b/lib/netlink.c
index fbfc20e7c..a0c59acb1 100644
--- a/lib/netlink.c
+++ b/lib/netlink.c
@@ -579,6 +579,17 @@ nl_msg_put_nested(struct ofpbuf *msg,
nl_msg_end_nested(msg, offset);
}
+/* Inserts a Netlink attribute header of the given 'type' at 'offset' in
+ * 'msg', enclosing 'size' bytes of existing data as its payload. */
+void
+nl_msg_wrap_nested(struct ofpbuf *msg, uint16_t type,
+ size_t offset, size_t size)
+{
+ struct nlattr nla = { .nla_len = NLA_HDRLEN + size, .nla_type = type };
+
+ ofpbuf_insert(msg, offset, &nla, sizeof nla);
+}
+
/* Reset message size to offset. */
void
nl_msg_reset_size(struct ofpbuf *msg, size_t offset)
diff --git a/lib/netlink.h b/lib/netlink.h
index d98ef3a98..28b127b2f 100644
--- a/lib/netlink.h
+++ b/lib/netlink.h
@@ -87,6 +87,8 @@ void nl_msg_cancel_nested(struct ofpbuf *, size_t offset);
bool nl_msg_end_non_empty_nested(struct ofpbuf *, size_t offset);
void nl_msg_put_nested(struct ofpbuf *, uint16_t type,
const void *data, size_t size);
+void nl_msg_wrap_nested(struct ofpbuf *, uint16_t type,
+ size_t offset, size_t size);
void nl_msg_reset_size(struct ofpbuf *, size_t offset);
/* Prepending attributes. */
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index c1ba447e9..3fdd66216 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -6108,80 +6108,107 @@ xlate_sample_action(struct xlate_ctx *ctx,
compose_sample_action(ctx, &compose_args);
}
-/* Determine if an datapath action translated from the openflow action
- * can be reversed by another datapath action.
+/* Returns true if all datapath actions in [data, data + size) are reversible,
+ * i.e., the commit mechanism can produce datapath actions to undo their
+ * effects on the packet.
*
- * Openflow actions that do not emit datapath actions are trivially
- * reversible. Reversiblity of other actions depends on nature of
- * action and their translation. */
+ * Datapath clone() and sample() already isolate their inner actions and don't
+ * need inspection. check_pkt_len() branches need recursive inspection.
+ *
+ * Push/pop for VLAN and MPLS are reversible by the commit mechanism, while
+ * the same is not the case for ETH or NSH, as well as ADD_MPLS that changes
+ * the packet type and cannot be easily undone.
+ *
+ * hash() is not considered reversible as it hashes the current set of headers
+ * and needs to be recalculated whenever headers change, and there is no action
+ * to clear the hash.
+ *
+ * recirc() is reversible because the packet is always cloned on recirculation
+ * by the datapath, unless it is the last action.
+ *
+ * dec_ttl() is not reversible, as there is no equivalent inc_ttl(). The
+ * commit mechanism cannot undo the change since the original TTL value is not
+ * matched.
+ *
+ * ct()/ct_clear() are not reversible as they work with the external state
+ * that cannot be easily restored.
+ */
static bool
-reversible_actions(const struct ofpact *ofpacts, size_t ofpacts_len)
+odp_actions_are_reversible(const void *data, size_t size)
{
- const struct ofpact *a;
+ const struct nlattr *a;
+ unsigned int left;
- OFPACT_FOR_EACH (a, ofpacts, 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:
- case OFPACT_DEBUG_SLOW:
- case OFPACT_DEC_MPLS_TTL:
- case OFPACT_DEC_TTL:
- 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:
- case OFPACT_OUTPUT:
- case OFPACT_OUTPUT_REG:
- case OFPACT_POP_MPLS:
- case OFPACT_POP_QUEUE:
- 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:
- case OFPACT_SET_FIELD:
- case OFPACT_SET_IP_DSCP:
- case OFPACT_SET_IP_ECN:
- case OFPACT_SET_IP_TTL:
- case OFPACT_SET_IPV4_DST:
- case OFPACT_SET_IPV4_SRC:
- case OFPACT_SET_L4_DST_PORT:
- case OFPACT_SET_L4_SRC_PORT:
- case OFPACT_SET_MPLS_LABEL:
- case OFPACT_SET_MPLS_TC:
- case OFPACT_SET_MPLS_TTL:
- case OFPACT_SET_QUEUE:
- case OFPACT_SET_TUNNEL:
- case OFPACT_SET_VLAN_PCP:
- case OFPACT_SET_VLAN_VID:
- case OFPACT_STACK_POP:
- case OFPACT_STACK_PUSH:
- case OFPACT_STRIP_VLAN:
- case OFPACT_UNROLL_XLATE:
- case OFPACT_WRITE_ACTIONS:
- case OFPACT_WRITE_METADATA:
- case OFPACT_CHECK_PKT_LARGER:
- case OFPACT_DELETE_FIELD:
+ NL_ATTR_FOR_EACH (a, left, data, size) {
+ enum ovs_action_attr type = nl_attr_type(a);
+
+ switch (type) {
+ case OVS_ACTION_ATTR_UNSPEC:
+ case __OVS_ACTION_ATTR_MAX:
+ OVS_NOT_REACHED();
+
+ /* Reversible: do not modify the packet, or undone by commit. */
+ case OVS_ACTION_ATTR_OUTPUT:
+ case OVS_ACTION_ATTR_USERSPACE:
+ case OVS_ACTION_ATTR_SET:
+ case OVS_ACTION_ATTR_PUSH_VLAN:
+ case OVS_ACTION_ATTR_POP_VLAN:
+ case OVS_ACTION_ATTR_SAMPLE:
+ case OVS_ACTION_ATTR_RECIRC:
+ case OVS_ACTION_ATTR_PUSH_MPLS:
+ case OVS_ACTION_ATTR_POP_MPLS:
+ case OVS_ACTION_ATTR_SET_MASKED:
+ case OVS_ACTION_ATTR_CLONE:
+ case OVS_ACTION_ATTR_PSAMPLE:
+ case OVS_ACTION_ATTR_LB_OUTPUT:
break;
- case OFPACT_CT:
- case OFPACT_CT_CLEAR:
- case OFPACT_METER:
- case OFPACT_NAT:
- case OFPACT_OUTPUT_TRUNC:
- case OFPACT_ENCAP:
- case OFPACT_DECAP:
- case OFPACT_DEC_NSH_TTL:
+ /* Nested: recurse into sub-action lists. */
+ case OVS_ACTION_ATTR_CHECK_PKT_LEN: {
+ const struct nlattr *nested;
+ unsigned int nested_left;
+
+ NL_ATTR_FOR_EACH (nested, nested_left,
+ nl_attr_get(a), nl_attr_get_size(a)) {
+ enum ovs_check_pkt_len_attr attr;
+
+ attr = nl_attr_type(nested);
+ switch (attr) {
+ case OVS_CHECK_PKT_LEN_ATTR_UNSPEC:
+ case __OVS_CHECK_PKT_LEN_ATTR_MAX:
+ OVS_NOT_REACHED();
+
+ case OVS_CHECK_PKT_LEN_ATTR_PKT_LEN:
+ break;
+
+ case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER:
+ case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL:
+ if (!odp_actions_are_reversible(
+ nl_attr_get(nested),
+ nl_attr_get_size(nested))) {
+ return false;
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ /* Non-reversible. */
+ case OVS_ACTION_ATTR_HASH:
+ case OVS_ACTION_ATTR_CT:
+ case OVS_ACTION_ATTR_TRUNC:
+ case OVS_ACTION_ATTR_PUSH_ETH:
+ case OVS_ACTION_ATTR_POP_ETH:
+ case OVS_ACTION_ATTR_CT_CLEAR:
+ case OVS_ACTION_ATTR_PUSH_NSH:
+ case OVS_ACTION_ATTR_POP_NSH:
+ case OVS_ACTION_ATTR_METER:
+ case OVS_ACTION_ATTR_ADD_MPLS:
+ case OVS_ACTION_ATTR_DEC_TTL:
+ case OVS_ACTION_ATTR_DROP:
+ case OVS_ACTION_ATTR_TUNNEL_PUSH:
+ case OVS_ACTION_ATTR_TUNNEL_POP:
return false;
}
}
@@ -6194,86 +6221,81 @@ clone_xlate_actions(const struct ofpact *actions,
size_t actions_len,
bool group_bucket_action OVS_UNUSED)
{
struct xretained_state *retained_state;
- size_t offset, ac_offset;
-
- retained_state = xretain_state_save(ctx);
-
- if (reversible_actions(actions, actions_len) || is_last_action) {
- do_xlate_actions(actions, actions_len, ctx, is_last_action, false);
- if (!ctx->freezing) {
- xlate_action_set(ctx);
- }
- if (ctx->freezing) {
- finish_freezing(ctx);
- }
- goto xlate_done;
+ bool old_was_mpls, old_conntracked;
+ size_t body_offset, body_size;
+
+ /* Commit pending datapath actions before translating the clone body
+ * so that body_offset accurately marks the start of the clone body's
+ * own actions. Not needed for the last action since nothing follows
+ * that could be affected by the clone body's effects. */
+ if (!is_last_action) {
+ xlate_commit_actions(ctx);
}
- /* Commit datapath actions before emitting the clone action to
- * avoid emitting those actions twice. Once inside
- * the clone, another time for the action after clone. */
- xlate_commit_actions(ctx);
+ retained_state = xretain_state_save(ctx);
xretain_base_flow_save(ctx, retained_state);
- bool old_was_mpls = ctx->was_mpls;
- bool old_conntracked = ctx->conntracked;
+ old_was_mpls = ctx->was_mpls;
+ old_conntracked = ctx->conntracked;
- /* The actions are not reversible, a datapath clone action is
- * required to encode the translation. Select the clone action
- * based on datapath capabilities. */
- if (ctx->xbridge->support.clone) { /* Use clone action */
- /* Use clone action as datapath clone. */
- offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_CLONE);
- do_xlate_actions(actions, actions_len, ctx, true, false);
- if (!ctx->freezing) {
- xlate_action_set(ctx);
- }
- if (ctx->freezing) {
- finish_freezing(ctx);
- }
- nl_msg_end_non_empty_nested(ctx->odp_actions, offset);
- goto dp_clone_done;
+ body_offset = ctx->odp_actions->size;
+
+ /* Translate the clone body. Pass is_last_action=true to avoid
+ * unnecessary nesting within the clone body itself. */
+ do_xlate_actions(actions, actions_len, ctx, true, false);
+ if (!ctx->freezing) {
+ xlate_action_set(ctx);
+ }
+ if (ctx->freezing) {
+ finish_freezing(ctx);
}
- if (ctx->xbridge->support.sample_nesting > 3) {
- /* Use sample action as datapath clone. */
- offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_SAMPLE);
- ac_offset = nl_msg_start_nested(ctx->odp_actions,
- OVS_SAMPLE_ATTR_ACTIONS);
- do_xlate_actions(actions, actions_len, ctx, true, false);
- if (!ctx->freezing) {
- xlate_action_set(ctx);
- }
- if (ctx->freezing) {
- finish_freezing(ctx);
- }
- if (nl_msg_end_non_empty_nested(ctx->odp_actions, ac_offset)) {
- nl_msg_cancel_nested(ctx->odp_actions, offset);
- } else {
+ body_size = ctx->odp_actions->size - body_offset;
+
+ if (!is_last_action && body_size > 0
+ && !odp_actions_are_reversible(
+ (char *) ctx->odp_actions->data + body_offset, body_size)) {
+ size_t observe_shift = 0;
+
+ if (ctx->xbridge->support.clone) {
+ nl_msg_wrap_nested(ctx->odp_actions, OVS_ACTION_ATTR_CLONE,
+ body_offset, body_size);
+ observe_shift = NLA_HDRLEN;
+ } else if (ctx->xbridge->support.sample_nesting > 3) {
+ /* Use sample action as datapath clone fallback. */
+ nl_msg_wrap_nested(ctx->odp_actions, OVS_SAMPLE_ATTR_ACTIONS,
+ body_offset, body_size);
nl_msg_put_u32(ctx->odp_actions, OVS_SAMPLE_ATTR_PROBABILITY,
UINT32_MAX); /* 100% probability. */
- nl_msg_end_nested(ctx->odp_actions, offset);
+ nl_msg_wrap_nested(ctx->odp_actions, OVS_ACTION_ATTR_SAMPLE,
+ body_offset,
+ ctx->odp_actions->size - body_offset);
+ observe_shift = 2 * NLA_HDRLEN;
+ } else {
+ /* Datapath does not support clone. Discard the clone body
+ * since we cannot isolate its non-reversible effects. */
+ ctx->odp_actions->size = body_offset;
+ xlate_report_error(ctx, "Failed to compose clone action");
}
- goto dp_clone_done;
- }
- /* Datapath does not support clone, skip xlate 'oc' and
- * report an error */
- xlate_report_error(ctx, "Failed to compose clone action");
+ if (ctx->xout->last_observe_offset != UINT32_MAX
+ && ctx->xout->last_observe_offset >= body_offset) {
+ ctx->xout->last_observe_offset += observe_shift;
+ }
-dp_clone_done:
- /* The clone's conntrack execution should have no effect on the original
- * packet. */
- ctx->conntracked = old_conntracked;
+ /* Datapath's clone isolates all packet modifications, so restore
+ * base_flow to match the packet's actual state after the clone. */
+ xretain_base_flow_restore(ctx, retained_state);
+ }
+ /* When not wrapped, base_flow is NOT restored: it reflects the packet
+ * state after the inlined actions, so the commit mechanism will emit
+ * reverse actions to undo them. */
- /* Popping MPLS from the clone should have no effect on the original
- * packet. */
+ /* The clone's conntrack and MPLS state changes should have no
+ * effect on the original packet. */
+ ctx->conntracked = old_conntracked;
ctx->was_mpls = old_was_mpls;
- /* Restore the 'base_flow' for the next action. */
- xretain_base_flow_restore(ctx, retained_state);
-
-xlate_done:
xretain_state_restore_and_free(ctx, retained_state);
}
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 73213634e..cb96972de 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -9231,90 +9231,243 @@ AT_SETUP([ofproto-dpif - clone action])
OVS_VSWITCHD_START
add_of_ports br0 1 2 3 4
-dnl Reversible open flow clone actions, no datapath clone action should be
generated.
+AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 \
+ 'meter=1 pktps bands=type=drop rate=100'])
+
+m4_define([TRACE_PKT], [m4_join([,],
+ [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)])])
+
+m4_define([TRACE_PKT_VLAN], [m4_join([,],
+ [in_port(1)],
+ [eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a)],
+ [eth_type(0x8100)],
+ [vlan(vid=100,pcp=0)],
+ [encap(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))])])
+
+m4_define([CHECK_CLONE_ACTION], [
+ AT_CHECK([ovs-ofctl --bundle replace-flows br0 $1])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy '$2'], [0], [stdout])
+ AT_CHECK([grep Datapath stdout | sed 's/recirc(.*)/recirc(X)/'], [0], [$3])
+])
+
+dnl Reversible clone actions - not wrapped.
AT_DATA([flows.txt], [dnl
-in_port=1, ip,
actions=clone(set_field:192.168.3.3->ip_src),clone(set_field:192.168.4.4->ip_dst,output:2),clone(mod_dl_src:80:81:81:81:81:81,set_field:192.168.5.5->ip_dst,output:3),output:4
+in_port=1,ip,actions=clone(set_field:192.168.3.3->ip_src),clone(set_field:192.168.4.4->ip_dst,output:2),clone(mod_dl_src:80:81:81:81:81:81,set_field:192.168.5.5->ip_dst,output:3),output:4
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions:
set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),set(eth(src=80:81:81:81:81:81)),set(ipv4(dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(dst=10.10.10.1)),4
])
-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=1,ttl=128,frag=no),icmp(type=8,code=0)'],
[0], [stdout])
+dnl Mixed reversible and irreversible clone actions - ct(commit) wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(set_field:192.168.3.3->ip_src),clone(set_field:192.168.4.4->ip_dst,output:2),clone(ct(commit),output:3),output:4
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions:
set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),clone(ct(commit),3),4
+])
-AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions:
set(ipv4(dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(dst=10.10.10.1)),4
+dnl Same, with sample() action fallback.
+AT_CHECK([ovs-appctl dpif/set-dp-features br0 clone false])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions:
set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),sample(sample=100.0%,actions(ct(commit),3)),4
])
-dnl Test flow xlate openflow clone action without using datapath clone action.
-AT_CHECK([ovs-appctl dpif/set-dp-features br0 clone false], [0], [ignore])
+dnl Same, with no clone or sample support - non-reversible actions discarded.
+AT_CHECK([ovs-appctl dpif/set-dp-features br0 sample_nesting 2])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),4
+])
+AT_CHECK([grep "Failed to compose clone action" stdout], [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=1,ttl=128,frag=no),icmp(type=8,code=0)'],
[0], [stdout])
+dnl Direct ct_clear inside clone - wrapped; outer ct_clear still emitted.
+AT_CHECK([ovs-appctl dpif/set-dp-features br0 clone true])
+AT_CHECK([ovs-appctl dpif/set-dp-features br0 sample_nesting 10])
+AT_DATA([flows.txt], [dnl
+table=0,in_port=1,ip,actions=ct(table=1)
+table=1,in_port=1,actions=clone(ct_clear,output:2),ct_clear,output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: ct,recirc(X)
+Datapath actions: clone(ct_clear,2),ct_clear,3
+])
-AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions:
set(ipv4(dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(dst=10.10.10.1)),4
+dnl clone(resubmit) reaching ct_clear on tracked packet - wrapped.
+AT_DATA([flows.txt], [dnl
+table=0,in_port=1,ip,actions=ct(table=1)
+table=1,in_port=1,ip,actions=clone(resubmit(,10)),ct_clear,output:3
+table=10,ip,actions=ct_clear,output:2
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: ct,recirc(X)
+Datapath actions: clone(ct_clear,2),ct_clear,3
])
-AT_CHECK([ovs-appctl dpif/set-dp-features br0 sample_nesting 2], [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=1,ttl=128,frag=no),icmp(type=8,code=0)'],
[0], [stdout])
+dnl clone(resubmit) reaching ct(commit) - wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(resubmit(,10)),output:3
+table=10,ip,actions=ct(commit),output:2
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: clone(ct(commit),2),3
+])
-AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions:
set(ipv4(dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(dst=10.10.10.1)),4
+dnl clone(resubmit) reaching only reversible actions - not wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(resubmit(,10)),output:3
+table=10,ip,actions=set_field:192.168.1.1->ip_dst,output:2
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: set(ipv4(dst=192.168.1.1)),2,set(ipv4(dst=10.10.10.1)),3
])
-dnl Mixing reversible and irreversible open flow clone actions. Datapath clone
action
-dnl should be generated when necessary.
+dnl clone(resubmit) reaching meter - wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(resubmit(,10)),output:3
+table=10,ip,actions=meter:1,output:2
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: clone(meter(0),2),3
+])
-dnl Restore the datapath support level.
-AT_CHECK([ovs-appctl dpif/set-dp-features br0 clone true], [0], [])
-AT_CHECK([ovs-appctl dpif/set-dp-features br0 sample_nesting 10], [0], [])
+dnl Non-reversible clone as last action - not wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(ct(commit),output:2)
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: ct(commit),2
+])
+dnl Nested clone: inner non-reversible wrapped, outer not wrapped.
AT_DATA([flows.txt], [dnl
-in_port=1, ip,
actions=clone(set_field:192.168.3.3->ip_src),clone(set_field:192.168.4.4->ip_dst,output:2),clone(ct(commit),output:3),output:4
+in_port=1,ip,actions=clone(clone(ct(commit),output:2),output:3),output:4
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: clone(ct(commit),2),3,4
])
-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=1,ttl=128,frag=no),icmp(type=8,code=0)'],
[0], [stdout])
+dnl clone(group) with non-reversible bucket - wrapped.
+AT_CHECK([ovs-ofctl -O OpenFlow13 add-group br0 \
+
'group_id=1,type=all,bucket=actions=resubmit(,10),bucket=actions=resubmit(,11)'])
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(group:1),output:4
+table=10,ip,actions=ct(commit),output:2
+table=11,ip,actions=set_field:192.168.1.1->ip_dst,output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: clone(ct(commit),2,set(ipv4(dst=192.168.1.1)),3),4
+])
-AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions:
set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),clone(ct(commit),3),4
+dnl clone(group) with all reversible buckets - not wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(group:1),output:4
+table=10,ip,actions=set_field:192.168.2.2->ip_dst,output:2
+table=11,ip,actions=set_field:192.168.1.1->ip_dst,output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions:
set(ipv4(dst=192.168.2.2)),2,set(ipv4(dst=192.168.1.1)),3,set(ipv4(dst=10.10.10.1)),4
])
-AT_CHECK([ovs-appctl dpif/set-dp-features br0 clone false], [0], [ignore])
+dnl clone() with check_pkt_larger, non-reversible branch - wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(check_pkt_larger(200)->NXM_NX_REG0[[0]],resubmit(,10)),output:3
+table=10,priority=200,reg0=0x1/0x1,ip,actions=ct(commit),output:2
+table=10,priority=100,ip,actions=output:4
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: clone(check_pkt_len(size=200,gt(ct(commit),2),le(4))),3
+])
-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=1,ttl=128,frag=no),icmp(type=8,code=0)'],
[0], [stdout])
+dnl clone() with check_pkt_larger, only reversible branches - not wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(check_pkt_larger(200)->NXM_NX_REG0[[0]],resubmit(,10)),output:3
+table=10,priority=200,reg0=0x1/0x1,ip,actions=set_field:192.168.1.1->ip_dst,output:2
+table=10,priority=100,ip,actions=output:4
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions:
check_pkt_len(size=200,gt(set(ipv4(dst=192.168.1.1)),2),le(4)),3
+])
-AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions:
set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),sample(sample=100.0%,actions(ct(commit),3)),4
+dnl Pending SET before reversible clone - commit splits SET actions.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=set_field:192.168.1.1->ip_src,clone(set_field:192.168.2.2->ip_dst,output:2),output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions:
set(ipv4(src=192.168.1.1)),set(ipv4(dst=192.168.2.2)),2,set(ipv4(dst=10.10.10.1)),3
])
-AT_CHECK([ovs-appctl dpif/set-dp-features br0 sample_nesting 2], [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=1,ttl=128,frag=no),icmp(type=8,code=0)'],
[0], [stdout])
+dnl Pending SET before non-reversible clone - commit before wrap.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=set_field:192.168.1.1->ip_src,clone(ct(commit),output:2),output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: set(ipv4(src=192.168.1.1)),clone(ct(commit),2),3
+])
-AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions: set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),4
+dnl No pending changes before clone - commit is a no-op.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(set_field:192.168.2.2->ip_dst,output:2),output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: set(ipv4(dst=192.168.2.2)),2,set(ipv4(dst=10.10.10.1)),3
])
-AT_CHECK([grep "Failed to compose clone action" stdout], [0], [ignore])
-dnl ct_clear inside clone() is irreversible. A datapath clone action
-dnl should be generated and any ct_clear after the clone must still be
-dnl emitted.
+dnl VLAN push inside clone - not wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(mod_vlan_vid:100,output:2),output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: push_vlan(vid=100,pcp=0),2,pop_vlan,3
+])
-dnl Restore the datapath support level.
-AT_CHECK([ovs-appctl dpif/set-dp-features br0 clone true])
-AT_CHECK([ovs-appctl dpif/set-dp-features br0 sample_nesting 10])
+dnl VLAN pop inside clone - not wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,vlan_tci=0x1000/0x1000,actions=clone(strip_vlan,output:2),output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT_VLAN], [dnl
+Datapath actions: pop_vlan,2,push_vlan(vid=100,pcp=0),3
+])
-dnl Recirculate after ct() so the conntracked flag is set when the
-dnl clone is processed.
+dnl VLAN push + ct(commit) inside clone - wrapped.
AT_DATA([flows.txt], [dnl
-table=0,in_port=1,ip,actions=ct(table=1)
-table=1,in_port=1,actions=clone(ct_clear,output:2),ct_clear,output:3
+in_port=1,ip,actions=clone(mod_vlan_vid:100,ct(commit),output:2),output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions: clone(push_vlan(vid=100,pcp=0),ct(commit),2),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])
+dnl MPLS push inside clone - not wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(push_mpls:0x8847,output:2),output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions:
push_mpls(label=0,tc=0,ttl=64,bos=1,eth_type=0x8847),2,pop_mpls(eth_type=0x800),3
+])
-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
+dnl MPLS encap inside clone is non-reversible (add_mpls) - wrapped.
+AT_DATA([flows.txt], [dnl
+in_port=1,ip,actions=clone(encap(mpls),encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:2),output:3
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions:
clone(add_mpls(label=0,tc=0,ttl=64,bos=1,eth_type=0x8847),push_eth(src=00:00:00:00:00:01,dst=00:00:00:00:00:02),2),3
+])
+
+dnl 4 nested clones via resubmit: levels 1 and 3 wrapped (ct),
+dnl levels 2 and 4 not wrapped (set+output).
+AT_DATA([flows.txt], [dnl
+table=0,in_port=1,ip,actions=clone(resubmit(,1)),output:4
+table=1,ip,actions=ct(commit),clone(resubmit(,2)),output:3
+table=2,ip,actions=set_field:192.168.1.1->ip_dst,clone(resubmit(,3)),output:2
+table=3,ip,actions=ct(commit),clone(resubmit(,4)),output:3
+table=4,ip,actions=set_field:192.168.2.2->ip_dst,output:2
+])
+CHECK_CLONE_ACTION([flows.txt], [TRACE_PKT], [dnl
+Datapath actions:
clone(ct(commit),set(ipv4(dst=192.168.1.1)),clone(ct(commit),set(ipv4(dst=192.168.2.2)),2,set(ipv4(dst=192.168.1.1)),3),2,set(ipv4(dst=10.10.10.1)),3),4
])
OVS_VSWITCHD_STOP
@@ -10145,12 +10298,12 @@ OVS_VSWITCHD_STOP
AT_CLEANUP
-AT_SETUP([ofproto-dpif - patch ports - meter (clone)])
-
+AT_SETUP([ofproto-dpif - patch ports - clone])
OVS_VSWITCHD_START(
[add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 -- \
add-port br0 p1 -- set Interface p1 type=patch \
options:peer=p2 ofport_request=2 -- \
+ add-port br0 p4 -- set Interface p4 type=dummy ofport_request=4 -- \
add-br br1 -- \
set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \
set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \
@@ -10159,51 +10312,68 @@ OVS_VSWITCHD_START(
options:peer=p1 -- \
add-port br1 p3 -- set Interface p3 type=dummy ofport_request=3])
-AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br1 'meter=1 pktps stats
bands=type=drop rate=2'])
-AT_CHECK([ovs-ofctl del-flows br0])
-AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 in_port=local,ip,actions=2,1])
-AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 in_port=1,ip,actions=meter:1,3])
+m4_define([TRACE_PKT], [m4_join([,],
+ [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)])])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy
'in_port(100),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x0800),ipv4(src=10.1.1.22,dst=10.0.0.3,proto=6,tos=0,ttl=64,frag=no),tcp(src=53295,dst=8080)'],
[0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
- [Datapath actions: clone(meter(0),3),1
+m4_define([CHECK_CLONE_ACTION], [
+ AT_CHECK([ovs-ofctl --bundle replace-flows br0 $1])
+ AT_CHECK([ovs-ofctl --bundle replace-flows br1 $2])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy '$3' --ct-next 'trk,est'],
[0], [stdout])
+ AT_CHECK([grep Datapath stdout | sed 's/recirc(.*)/recirc(X)/'], [0], [$4])
])
-OVS_VSWITCHD_STOP
-AT_CLEANUP
-
-AT_SETUP([ofproto-dpif - patch ports - no additional clone])
-OVS_VSWITCHD_START(
- [add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 -- dnl
- add-port br0 p1 -- set Interface p1 type=patch dnl
- options:peer=p2 ofport_request=2 -- dnl
- add-br br1 -- dnl
- set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- dnl
- set bridge br1 datapath-type=dummy other-config:datapath-id=1234 dnl
- fail-mode=secure -- dnl
- add-port br1 p2 -- set Interface p2 type=patch dnl
- options:peer=p1 -- dnl
- add-port br1 p3 -- set Interface p3 type=dummy ofport_request=3])
+dnl Meter on peer bridge - wrapped.
+AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br1 \
+ 'meter=1 pktps stats bands=type=drop rate=2'])
+AT_DATA([flows-br0.txt], [dnl
+in_port=p0,ip,actions=p1,output:p4
+])
+AT_DATA([flows-br1.txt], [dnl
+in_port=p2,ip,actions=meter:1,output:p3
+])
+CHECK_CLONE_ACTION([flows-br0.txt], [flows-br1.txt], [TRACE_PKT], [dnl
+Datapath actions: clone(meter(0),3),4
+])
+dnl CT on peer bridge as last action - not wrapped (trailing clone unwrapped).
AT_DATA([flows-br0.txt], [dnl
-priority=10,tcp,action=push:NXM_OF_IN_PORT[],resubmit(,65),pop:NXM_OF_IN_PORT[]
+priority=10,ip,action=push:NXM_OF_IN_PORT[],resubmit(,65),pop:NXM_OF_IN_PORT[]
table=65,priority=10,ip,in_port=p0,action=p1
])
-
AT_DATA([flows-br1.txt], [dnl
-priority=100,in_port=p2,tcp,ct_state=-trk,action=ct(table=0,zone=1)
-priority=100,in_port=p2,tcp,ct_state=+trk+est,ct_zone=1,action=p3
+priority=100,in_port=p2,ip,ct_state=-trk,action=ct(table=0,zone=1)
+priority=100,in_port=p2,ip,ct_state=+trk+est,ct_zone=1,action=p3
+])
+CHECK_CLONE_ACTION([flows-br0.txt], [flows-br1.txt], [TRACE_PKT], [dnl
+Datapath actions: ct(zone=1),recirc(X)
+Datapath actions: 3
])
-AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt])
-AT_CHECK([ovs-ofctl --bundle add-flows br1 flows-br1.txt])
+dnl Non-reversible through resubmit on peer - wrapped.
+AT_DATA([flows-br0.txt], [dnl
+in_port=p0,ip,actions=p1,output:p4
+])
+AT_DATA([flows-br1.txt], [dnl
+in_port=p2,ip,actions=resubmit(,1)
+table=1,ip,actions=ct(commit),output:p3
+])
+CHECK_CLONE_ACTION([flows-br0.txt], [flows-br1.txt], [TRACE_PKT], [dnl
+Datapath actions: clone(ct(commit),3),4
+])
-AT_CHECK([ovs-appctl ofproto/trace br0 in_port=p0,tcp --ct-next 'trk,est' | dnl
- grep "Datapath actions:" | grep -q clone],
- [1], [], [],
- [ovs-appctl ofproto/trace br0 in_port=p0,tcp --ct-next 'trk,est'])
+dnl Only reversible actions on peer - not wrapped.
+AT_DATA([flows-br1.txt], [dnl
+in_port=p2,ip,actions=set_field:192.168.1.1->ip_dst,output:p3
+])
+CHECK_CLONE_ACTION([flows-br0.txt], [flows-br1.txt], [TRACE_PKT], [dnl
+Datapath actions: set(ipv4(dst=192.168.1.1)),3,set(ipv4(dst=10.10.10.1)),4
+])
-OVS_TRAFFIC_VSWITCHD_STOP
+OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([ofproto-dpif - offload - ovs-appctl dpif/offload/])
@@ -13278,7 +13448,7 @@ table=1,in_port=1,priority=0,ip
actions=clone(set_field:192.168.3.3->ip_src),clo
AT_CHECK([ovs-ofctl --protocols=OpenFlow10 add-flows br0 flows.txt])
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=1,ttl=128,frag=no),icmp(type=8,code=0)'],
[0], [stdout])
AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions:
check_pkt_len(size=200,gt(set(ipv4(dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(dst=10.10.10.1)),4),le(set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),clone(ct(commit),3),4))
+Datapath actions:
check_pkt_len(size=200,gt(set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),set(eth(src=80:81:81:81:81:81)),set(ipv4(dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(dst=10.10.10.1)),4),le(set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),clone(ct(commit),3),4))
])
AT_DATA([flows.txt], [dnl
diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at
index df626e0a3..80c080710 100644
--- a/tests/tunnel-push-pop-ipv6.at
+++ b/tests/tunnel-push-pop-ipv6.at
@@ -847,7 +847,7 @@ Datapath actions:
tnl_push(tnl_port(6081),header(size=70,type=5,dnl
eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),dnl
ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),dnl
udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100)),dnl
-hash(l4(0)),recirc(0x1)
+clone(hash(l4(0)),recirc(0x1))
])
dnl Now check that the packet is actually encapsulated and delivered.
@@ -879,7 +879,7 @@ actions:tnl_push(tnl_port(6081),header(size=70,type=5,dnl
eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),dnl
ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),dnl
udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100)),dnl
-hash(l4(0)),recirc(0x2)
+clone(hash(l4(0)),recirc(0x2))
])
OVS_VSWITCHD_STOP
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
index 50306ceff..3f709d2a1 100644
--- a/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
@@ -1373,7 +1373,7 @@ Datapath actions:
tnl_push(tnl_port(6081),header(size=50,type=5,dnl
eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),dnl
ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),dnl
udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100)),dnl
-hash(l4(0)),recirc(0x1)
+clone(hash(l4(0)),recirc(0x1))
])
dnl Now check that the packet is actually encapsulated and delivered.
@@ -1406,7 +1406,7 @@ actions:tnl_push(tnl_port(6081),header(size=50,type=5,dnl
eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),dnl
ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),dnl
udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100)),dnl
-hash(l4(0)),recirc(0x2)
+clone(hash(l4(0)),recirc(0x2))
])
OVS_VSWITCHD_STOP
--
2.54.0
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev