Please ignore this version, I've made a mistake with the stack and action_set buffer,it will be fixed in v7.
On Fri, Oct 14, 2022 at 2:21 PM Ales Musil <[email protected]> wrote: > When the packet was traveling through patch port boundary > OvS would check if any of the actions is reversible, > if not it would clone the packet. However, the check > was only at the first level of the second bridge. > That caused some issues when the packet had gone > through more actions, some of them might have been > irreversible. > > In order to keep the semantics the same we might > need to run the actions twice in the worst case > scenario. During the clone there are 4 scenarios > that can happen. > > 1) The action is last one for that flow, > in that case we just continue without clone. > > 2) There is irreversible action in the action > set (first level). In this case we know that > there is at leas one irreversible action which > is enough to do clone. > > 3) All actions in first level are reversible, > we can try to run all actions as if we don't > need any clone and inspect the ofpbuf at the > end. In positive case there are no irreversible > actions so we will just submit the buffer and continue. > > 4) This is same as 3) with the difference that > there is irreversible action in the ofpbuf. > To keep the semantics we need to re-run the actions > and treat it as clone. This requires resotration > of the xlate_ctx. > > Add test cases for all irreversible actions > to see if they are properly cloned. > > Signed-off-by: Ales Musil <[email protected]> > --- > v4: Rebase on top of current master. > Address comments from Eelco. > v5: Make the code more readable and reduce duplication. > v6: Rebase on top of current master. > Address comments from Eelco. > --- > lib/odp-util.c | 125 ++++++++++++++++++++++ > lib/odp-util.h | 1 + > ofproto/ofproto-dpif-trace.c | 2 +- > ofproto/ofproto-dpif-trace.h | 1 + > ofproto/ofproto-dpif-xlate.c | 194 ++++++++++++++++++++++++++--------- > tests/ofproto-dpif.at | 129 +++++++++++++++++++++++ > 6 files changed, 404 insertions(+), 48 deletions(-) > > diff --git a/lib/odp-util.c b/lib/odp-util.c > index ba5be4bb3..e8cc247cb 100644 > --- a/lib/odp-util.c > +++ b/lib/odp-util.c > @@ -8768,3 +8768,128 @@ commit_odp_actions(const struct flow *flow, struct > flow *base, > > return slow1 ? slow1 : slow2; > } > + > +static inline bool > +nlattr_action_is_irreversible(const uint16_t type) > +{ > + switch ((enum ovs_action_attr) type) { > + case OVS_ACTION_ATTR_CT: > + case OVS_ACTION_ATTR_CT_CLEAR: > + case OVS_ACTION_ATTR_TRUNC: > + case OVS_ACTION_ATTR_PUSH_ETH: > + case OVS_ACTION_ATTR_POP_ETH: > + case OVS_ACTION_ATTR_PUSH_NSH: > + case OVS_ACTION_ATTR_POP_NSH: > + case OVS_ACTION_ATTR_METER: > + case OVS_ACTION_ATTR_TUNNEL_PUSH: > + case OVS_ACTION_ATTR_TUNNEL_POP: > + case __OVS_ACTION_ATTR_MAX: > + return true; > + > + case OVS_ACTION_ATTR_UNSPEC: > + 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_HASH: > + case OVS_ACTION_ATTR_SET_MASKED: > + case OVS_ACTION_ATTR_CLONE: > + case OVS_ACTION_ATTR_CHECK_PKT_LEN: > + case OVS_ACTION_ATTR_LB_OUTPUT: > + case OVS_ACTION_ATTR_ADD_MPLS: > + case OVS_ACTION_ATTR_PUSH_MPLS: > + case OVS_ACTION_ATTR_POP_MPLS: > + case OVS_ACTION_ATTR_DROP: > + return false; > + } > + return true; > +} > + > +static bool > +odp_cpl_contains_irreversible_actions(const struct nlattr *attr) > +{ > + static const struct nl_policy ovs_cpl_policy[] = { > + [OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] = {.type = NL_A_U16}, > + [OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER] = {.type = > NL_A_NESTED}, > + [OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL] = {.type = > NL_A_NESTED}, > + }; > + struct nlattr *a[ARRAY_SIZE(ovs_cpl_policy)]; > + > + if (!nl_parse_nested(attr, ovs_cpl_policy, a, ARRAY_SIZE(a))) { > + return false; > + } > + > + const struct nlattr *greater = > + a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER]; > + const struct nlattr *less = > + a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL]; > + const void *greater_data = nl_attr_get(greater); > + const void *less_data = nl_attr_get(less); > + size_t greater_len = nl_attr_get_size(greater); > + size_t less_len = nl_attr_get_size(less); > + > + return odp_contains_irreversible_action(greater_data, greater_len) || > + odp_contains_irreversible_action(less_data, less_len); > +} > + > +/* Check if any of the actions in the ofpbuf is irreversible. */ > +bool > +odp_contains_irreversible_action(const void *attrs, size_t attrs_len) > +{ > + const struct nlattr *attr; > + int left; > + > + NL_ATTR_FOR_EACH (attr, left, attrs, attrs_len) { > + uint16_t type = attr->nla_type; > + > + switch ((enum ovs_action_attr) type) { > + /* Skip "clone" or "sample" because it already encapsulates > + * irreversible actions. */ > + case OVS_ACTION_ATTR_CLONE: > + case OVS_ACTION_ATTR_SAMPLE: > + continue; > + /* Check nested actions of "check_packet_len". */ > + case OVS_ACTION_ATTR_CHECK_PKT_LEN: > + if (odp_cpl_contains_irreversible_actions(attr)) { > + return true; > + } > + continue; > + /* Check any other action. */ > + case OVS_ACTION_ATTR_CT: > + case OVS_ACTION_ATTR_CT_CLEAR: > + case OVS_ACTION_ATTR_TRUNC: > + case OVS_ACTION_ATTR_PUSH_ETH: > + case OVS_ACTION_ATTR_POP_ETH: > + case OVS_ACTION_ATTR_PUSH_NSH: > + case OVS_ACTION_ATTR_POP_NSH: > + case OVS_ACTION_ATTR_METER: > + case OVS_ACTION_ATTR_TUNNEL_PUSH: > + case OVS_ACTION_ATTR_TUNNEL_POP: > + case OVS_ACTION_ATTR_UNSPEC: > + 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_RECIRC: > + case OVS_ACTION_ATTR_HASH: > + case OVS_ACTION_ATTR_SET_MASKED: > + case OVS_ACTION_ATTR_LB_OUTPUT: > + case OVS_ACTION_ATTR_ADD_MPLS: > + case OVS_ACTION_ATTR_PUSH_MPLS: > + case OVS_ACTION_ATTR_POP_MPLS: > + case OVS_ACTION_ATTR_DROP: > + if (nlattr_action_is_irreversible(type)) { > + return true; > + } > + continue; > + case __OVS_ACTION_ATTR_MAX: > + break; > + } > + return true; > + } > + return false; > +} > diff --git a/lib/odp-util.h b/lib/odp-util.h > index a1d0d0fba..d842974ba 100644 > --- a/lib/odp-util.h > +++ b/lib/odp-util.h > @@ -373,6 +373,7 @@ void odp_put_pop_eth_action(struct ofpbuf > *odp_actions); > void odp_put_push_eth_action(struct ofpbuf *odp_actions, > const struct eth_addr *eth_src, > const struct eth_addr *eth_dst); > +bool odp_contains_irreversible_action(const void *attrs, size_t > attrs_len); > > struct attr_len_tbl { > int len; > diff --git a/ofproto/ofproto-dpif-trace.c b/ofproto/ofproto-dpif-trace.c > index 527e2f17e..15e79c353 100644 > --- a/ofproto/ofproto-dpif-trace.c > +++ b/ofproto/ofproto-dpif-trace.c > @@ -108,7 +108,7 @@ oftrace_add_recirc_node(struct ovs_list *recirc_queue, > return true; > } > > -static void > +void > oftrace_recirc_node_destroy(struct oftrace_recirc_node *node) > { > if (node) { > diff --git a/ofproto/ofproto-dpif-trace.h b/ofproto/ofproto-dpif-trace.h > index f579a5ca4..629327495 100644 > --- a/ofproto/ofproto-dpif-trace.h > +++ b/ofproto/ofproto-dpif-trace.h > @@ -96,6 +96,7 @@ bool oftrace_add_recirc_node(struct ovs_list > *recirc_queue, > const struct ofpact_nat *, > const struct dp_packet *, uint32_t recirc_id, > const uint16_t zone); > +void oftrace_recirc_node_destroy(struct oftrace_recirc_node *node); > > void ofproto_append_ports_to_map(struct ofputil_port_map *, struct hmap > ports); > > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c > index 6ea71eb52..5766503cd 100644 > --- a/ofproto/ofproto-dpif-xlate.c > +++ b/ofproto/ofproto-dpif-xlate.c > @@ -5771,6 +5771,114 @@ xlate_sample_action(struct xlate_ctx *ctx, > compose_sample_action(ctx, probability, &cookie, tunnel_out_port, > false); > } > > +/* Struct to store the xlate_ctx that needs to be restored after > +* clone is finished. */ > +struct xlate_ctx_clone_state { > + union mf_subvalue stack_buffer[1024 / sizeof(union mf_subvalue)]; > + struct ofpbuf stack; > + > + uint64_t action_set_buffer[1024 / 8]; > + struct ofpbuf action_set; > + > + uint32_t odp_actions_size; > + > + struct flow xin_flow; > + struct flow base_flow; > + > + bool was_mpls; > + bool conntracked; > + > + size_t recirc_size; > + > + int resubmit; > + uint32_t sflow_n_outputs; > +}; > + > +static struct xlate_ctx_clone_state > +xlate_ctx_clone_state_store(struct xlate_ctx *ctx) > +{ > + struct xlate_ctx_clone_state state = { > + .stack = ctx->stack, > + .action_set = ctx->action_set, > + .odp_actions_size = ctx->odp_actions->size, > + .xin_flow = ctx->xin->flow, > + .base_flow = ctx->base_flow, > + .was_mpls = ctx->was_mpls, > + .conntracked = ctx->conntracked, > + .recirc_size = ctx->xin->recirc_queue > + ? ovs_list_size(ctx->xin->recirc_queue) > + : 0, > + .resubmit = ctx->resubmits, > + .sflow_n_outputs = ctx->sflow_n_outputs, > + }; > + > + /* Set up a new stack from the provided stack buffer. */ > + ofpbuf_use_stub(&ctx->stack, state.stack_buffer, > + sizeof state.stack_buffer); > + ofpbuf_put(&ctx->stack, state.stack.data, state.stack.size); > + > + /* Set up a new action_set from the provided stack buffer. */ > + ofpbuf_use_stub(&ctx->action_set, state.action_set_buffer, > + sizeof state.action_set_buffer); > + ofpbuf_put(&ctx->action_set, state.action_set.data, > state.action_set.size); > + > + return state; > +} > + > +/* Restore xlate_ctx member to the old_state, with additional steps for > + * revert. */ > +static void > +xlate_ctx_clone_state_restore(struct xlate_ctx *ctx, > + struct xlate_ctx_clone_state *old_state, > + bool no_clone_restore, bool revert) > +{ > + ofpbuf_uninit(&ctx->stack); > + ofpbuf_uninit(&ctx->action_set); > + > + ctx->stack = old_state->stack; > + ctx->action_set = old_state->action_set; > + ctx->xin->flow = old_state->xin_flow; > + > + /* Restore just common parts when we don't clone. */ > + if (no_clone_restore) { > + return; > + } > + > + /* The clone's conntrack execution should have no effect on the > original > + * packet. */ > + ctx->conntracked = old_state->conntracked; > + > + /* Popping MPLS from the clone should have no effect on the original > + * packet. */ > + ctx->was_mpls = old_state->was_mpls; > + > + /* Restore the 'base_flow' for the next action. */ > + ctx->base_flow = old_state->base_flow; > + > + if (revert) { > + ctx->resubmits = old_state->resubmit; > + ctx->sflow_n_outputs = old_state->sflow_n_outputs; > + > + /* Revert the actions that were added by non-clone path. */ > + ctx->odp_actions->size = old_state->odp_actions_size; > + > + /* Clear recirculations that were added by non-clone path so that > + * packets are not recirculated twice. */ > + size_t old_recirc_size = old_state->recirc_size; > + size_t recirc_size = ctx->xin->recirc_queue > + ? ovs_list_size(ctx->xin->recirc_queue) > + : 0; > + > + for (; old_recirc_size < recirc_size; old_recirc_size++) { > + struct oftrace_recirc_node *node = > + CONTAINER_OF(ovs_list_pop_back(ctx->xin->recirc_queue), > + struct oftrace_recirc_node, node); > + > + oftrace_recirc_node_destroy(node); > + } > + } > +} > + > /* Determine if an datapath action translated from the openflow action > * can be reversed by another datapath action. > * > @@ -5852,37 +5960,18 @@ reversible_actions(const struct ofpact *ofpacts, > size_t ofpacts_len) > } > > static void > -clone_xlate_actions(const struct ofpact *actions, size_t actions_len, > - struct xlate_ctx *ctx, bool is_last_action, > - bool group_bucket_action OVS_UNUSED) > +do_clone_xlate_actions(const struct ofpact *actions, size_t actions_len, > + struct xlate_ctx *ctx) > { > - struct ofpbuf old_stack = ctx->stack; > - union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)]; > - ofpbuf_use_stub(&ctx->stack, new_stack, sizeof new_stack); > - ofpbuf_put(&ctx->stack, old_stack.data, old_stack.size); > - > - struct ofpbuf old_action_set = ctx->action_set; > - uint64_t actset_stub[1024 / 8]; > - ofpbuf_use_stub(&ctx->action_set, actset_stub, sizeof actset_stub); > - ofpbuf_put(&ctx->action_set, old_action_set.data, > old_action_set.size); > - > size_t offset, ac_offset; > - struct flow old_flow = ctx->xin->flow; > - > - if (reversible_actions(actions, actions_len) || is_last_action) { > - old_flow = ctx->xin->flow; > - do_xlate_actions(actions, actions_len, ctx, is_last_action, > false); > - xlate_ctx_process_freezing(ctx); > - goto xlate_done; > - } > + struct xlate_ctx_clone_state old_state = > xlate_ctx_clone_state_store(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); > - struct flow old_base = ctx->base_flow; > - bool old_was_mpls = ctx->was_mpls; > - bool old_conntracked = ctx->conntracked; > + /* The base needs to be stored after xlate_commit_actions. */ > + old_state.base_flow = ctx->base_flow; > > /* The actions are not reversible, a datapath clone action is > * required to encode the translation. Select the clone action > @@ -5893,10 +5982,7 @@ clone_xlate_actions(const struct ofpact *actions, > size_t actions_len, > do_xlate_actions(actions, actions_len, ctx, true, false); > xlate_ctx_process_freezing(ctx); > nl_msg_end_non_empty_nested(ctx->odp_actions, offset); > - goto dp_clone_done; > - } > - > - if (ctx->xbridge->support.sample_nesting > 3) { > + } else 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, > @@ -5910,31 +5996,45 @@ clone_xlate_actions(const struct ofpact *actions, > size_t actions_len, > UINT32_MAX); /* 100% probability. */ > nl_msg_end_nested(ctx->odp_actions, offset); > } > - goto dp_clone_done; > + } else { > + /* Datapath does not support clone, skip xlate 'oc' and > + * report an error */ > + xlate_report_error(ctx, "Failed to compose clone action"); > } > + xlate_ctx_clone_state_restore(ctx, &old_state, false, false); > +} > > - /* Datapath does not support clone, skip xlate 'oc' and > - * report an error */ > - xlate_report_error(ctx, "Failed to compose clone action"); > +static void > +clone_xlate_actions(const struct ofpact *actions, size_t actions_len, > + struct xlate_ctx *ctx, bool is_last_action, > + bool group_bucket_action OVS_UNUSED) > +{ > + /* We have to clone if any of the actions is irreversible. */ > + if (!is_last_action && !reversible_actions(actions, actions_len)) { > + do_clone_xlate_actions(actions, actions_len, ctx); > + return; > + } > > -dp_clone_done: > - /* The clone's conntrack execution should have no effect on the > original > - * packet. */ > - ctx->conntracked = old_conntracked; > + /* Let's run the actions as if they are reversible, if we find out > that > + * there was any irreversible action we can restore the xlate_ctx and > run > + * the do_clone instead. If the action is last we don't have to check > and > + * can just proceed with the actions. */ > + struct xlate_ctx_clone_state old_state = > xlate_ctx_clone_state_store(ctx); > > - /* Popping MPLS from the clone should have no effect on the original > - * packet. */ > - ctx->was_mpls = old_was_mpls; > + do_xlate_actions(actions, actions_len, ctx, is_last_action, false); > > - /* Restore the 'base_flow' for the next action. */ > - ctx->base_flow = old_base; > + void *added_actions = > + ofpbuf_at_assert(ctx->odp_actions, old_state.odp_actions_size, 0); > + uint32_t added_size = ctx->odp_actions->size - > old_state.odp_actions_size; > > -xlate_done: > - ofpbuf_uninit(&ctx->action_set); > - ctx->action_set = old_action_set; > - ofpbuf_uninit(&ctx->stack); > - ctx->stack = old_stack; > - ctx->xin->flow = old_flow; > + if (is_last_action > + || !odp_contains_irreversible_action(added_actions, added_size)) { > + xlate_ctx_process_freezing(ctx); > + xlate_ctx_clone_state_restore(ctx, &old_state, true, false); > + } else { > + xlate_ctx_clone_state_restore(ctx, &old_state, false, true); > + do_clone_xlate_actions(actions, actions_len, ctx); > + } > } > > static void > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > index 8e993c585..92a9d48ff 100644 > --- a/tests/ofproto-dpif.at > +++ b/tests/ofproto-dpif.at > @@ -11943,3 +11943,132 @@ AT_CHECK([test 1 = `ovs-ofctl parse-pcap > p2-tx.pcap | wc -l`]) > > OVS_VSWITCHD_STOP > AT_CLEANUP > + > +AT_SETUP([ofproto-dpif - nested patch ports clone]) > + > +OVS_VSWITCHD_START( > + [add-port br0 br0-p0 -- set Interface br0-p0 type=dummy > ofport_request=1 -- \ > + add-port br0 br0-p1 -- set Interface br0-p1 type=patch > options:peer=br1-p0 -- \ > + add-br br1 -- \ > + set bridge br1 other-config:hwaddr=aa:66:aa:66:00:01 -- \ > + set bridge br1 datapath-type=dummy other-config:datapath-id=1111 > fail-mode=secure -- \ > + add-port br1 br1-p0 -- set Interface br1-p0 type=patch > options:peer=br0-p1 -- \ > + add-port br1 br1-p1 -- set Interface br1-p1 type=patch > options:peer=br2-p0 -- \ > + add-port br1 br1-p2 -- set Interface br1-p2 type=dummy > ofport_request=2 --\ > + add-br br2 -- \ > + set bridge br2 other-config:hwaddr=aa:66:aa:66:00:02 -- \ > + set bridge br2 datapath-type=dummy other-config:datapath-id=2222 > fail-mode=secure -- \ > + add-port br2 br2-p0 -- set Interface br2-p0 type=patch > options:peer=br1-p1 -- \ > + add-port br2 br2-p1 -- set Interface br2-p1 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 -O OpenFlow13 add-meter br2 '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=br0-p1,br0-p0]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > in_port=br1-p0,ip,actions=meter:1,br1-p1,br1-p2]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br2 > in_port=br2-p0,ip,actions=meter:1,br2-p1]) > + > +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port(local),ip" | grep > "Datapath actions:"], [0], [dnl > +Datapath actions: clone(meter(0),clone(meter(1),102),101),100 > +]) > + > +OVS_VSWITCHD_STOP > +AT_CLEANUP > + > +AT_SETUP([ofproto-dpif - patch ports - ct (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-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 > fail-mode=secure -- \ > + add-port br1 p2 -- set Interface p2 type=patch options:peer=p1 -- \ > + add-port br1 p3 -- set Interface p3 type=dummy ofport_request=3]) > + > +AT_CHECK([ovs-ofctl del-flows br0]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 > in_port=local,ip,actions=p1,p0]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "in_port=1,ip,actions=resubmit(,3)"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "table=3,in_port=1,ip,ct_state=-trk,actions=ct(table=0)"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "table=3,in_port=1,ip,ct_state=+trk,actions=p3"]) > + > +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port(local),ip" | strip_recirc > | grep "Datapath actions:"], [0], [dnl > +Datapath actions: clone(ct,recirc(<recirc>)),1 > +Datapath actions: 3 > +]) > + > +OVS_VSWITCHD_STOP > +AT_CLEANUP > + > + > +AT_SETUP([ofproto-dpif - patch ports - trunc (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-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 > fail-mode=secure -- \ > + add-port br1 p2 -- set Interface p2 type=patch options:peer=p1 -- \ > + add-port br1 p3 -- set Interface p3 type=dummy ofport_request=3]) > + > +AT_CHECK([ovs-ofctl del-flows br0]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 > in_port=local,ip,actions=p1,p0]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "in_port=1,ip,actions=resubmit(,3)"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "table=3,in_port=1,ip,actions=output(port=p3, max_len=20)"]) > + > +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port(local),ip" | grep > "Datapath actions:"], [0], [dnl > +Datapath actions: clone(trunc(20),3),1 > +]) > + > +OVS_VSWITCHD_STOP > +AT_CLEANUP > + > +AT_SETUP([ofproto-dpif - patch ports - encap (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-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 > fail-mode=secure -- \ > + add-port br1 p2 -- set Interface p2 type=patch options:peer=p1 -- \ > + add-port br1 p3 -- set Interface p3 type=dummy ofport_request=3]) > + > +AT_CHECK([ovs-ofctl del-flows br0]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 > "in_port=local,ip,actions=encap(nsh()),encap(ethernet),p1,p0"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "in_port=1,dl_type=0x894f,actions=decap(),decap(),p3"]) > + > +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port(local),ip" | strip_recirc > | grep "Datapath actions:"], [0], [dnl > +Datapath actions: > push_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x0,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00),clone(pop_eth,pop_nsh(),recirc(<recirc>)),1 > +]) > + > +OVS_VSWITCHD_STOP > +AT_CLEANUP > + > +AT_SETUP([ofproto-dpif - patch ports - check_pkt_larger (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-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 > fail-mode=secure -- \ > + add-port br1 p2 -- set Interface p2 type=patch options:peer=p1 -- \ > + add-port br1 p3 -- set Interface p3 type=dummy ofport_request=3]) > + > + > +AT_CHECK([ovs-ofctl del-flows br0]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 > "in_port=local,ip,actions=p1,p0"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "table=0,in_port=1,actions=check_pkt_larger(200)->reg0[[0]],resubmit(,1)"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "table=1,in_port=1,priority=200,reg0=0x1/0x1,ip,actions=ct(table=1)"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "table=1,in_port=1,ip,ct_state=+trk,actions=p3"]) > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 > "table=1,in_port=1,priority=0,ip,actions=p3"]) > + > +AT_CHECK([ovs-appctl ofproto/trace br0 "in_port(local),ip" | strip_recirc > | grep "Datapath actions:"], [0], [dnl > +Datapath actions: > clone(check_pkt_len(size=200,gt(ct,recirc(<recirc>)),le(3))),1 > +Datapath actions: 3 > +]) > + > +OVS_VSWITCHD_STOP > +AT_CLEANUP > -- > 2.37.3 > > -- Ales Musil Senior Software Engineer - OVN Core Red Hat EMEA <https://www.redhat.com> [email protected] IM: amusil <https://red.ht/sig> _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
