diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 4ee5d058a..d21515657 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -4970,8 +4970,24 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, case OVS_ACTION_ATTR_TUNNEL_PUSH: if (*depth < MAX_RECIRC_DEPTH) { + struct dp_packet_batch tnl_pkt; + struct dp_packet_batch *orig_packets_ = packets_; + int err; + + if (!may_steal) { + dp_packet_batch_clone(&tnl_pkt, packets_); + packets_ = &tnl_pkt; + dp_packet_batch_reset_cutlen(orig_packets_); + } + dp_packet_batch_apply_cutlen(packets_); - push_tnl_action(pmd, a, packets_); + + err = push_tnl_action(pmd, a, packets_); + if (!err) { + (*depth)++; + dp_netdev_recirculate(pmd, packets_); + (*depth)--; + } return; } break; diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index b308f21de..bc3a31022 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -424,10 +424,6 @@ const char *xlate_strerror(enum xlate_error error) static void xlate_action_set(struct xlate_ctx *ctx); static void xlate_commit_actions(struct xlate_ctx *ctx); -static void -apply_nested_clone_actions(struct xlate_ctx *ctx, const struct xport *in_dev, - struct xport *out_dev); - static void ctx_trigger_freeze(struct xlate_ctx *ctx) { @@ -3215,17 +3211,7 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport, } tnl_push_data.tnl_port = odp_to_u32(tunnel_odp_port); tnl_push_data.out_port = odp_to_u32(out_dev->odp_port); - - size_t push_action_size = 0; - size_t clone_ofs = nl_msg_start_nested(ctx->odp_actions, - OVS_ACTION_ATTR_CLONE); odp_put_tnl_push_action(ctx->odp_actions, &tnl_push_data); - push_action_size = ctx->odp_actions->size; - apply_nested_clone_actions(ctx, xport, out_dev); - if (ctx->odp_actions->size > push_action_size) { - /* Update the CLONE action only when combined */ - nl_msg_end_nested(ctx->odp_actions, clone_ofs); - } return 0; } @@ -3261,136 +3247,6 @@ xlate_flow_is_protected(const struct xlate_ctx *ctx, const struct flow *flow, co xport_in->xbundle->protected && xport_out->xbundle->protected); } -/* Populate and apply nested actions on 'out_dev'. - * The nested actions are applied on cloned packets in dp while outputting to - * either patch or tunnel ports. - * On output to a patch port, the output action will be replaced with set of - * nested actions on the peer patch port. - * Similarly on output to a tunnel port, the post nested actions on - * tunnel are chained up with the tunnel-push action. - */ -static void -apply_nested_clone_actions(struct xlate_ctx *ctx, const struct xport *in_dev, - struct xport *out_dev) -{ - struct flow *flow = &ctx->xin->flow; - struct flow old_flow = ctx->xin->flow; - struct flow_tnl old_flow_tnl_wc = ctx->wc->masks.tunnel; - bool old_conntrack = ctx->conntracked; - bool old_was_mpls = ctx->was_mpls; - ovs_version_t old_version = ctx->xin->tables_version; - struct ofpbuf old_stack = ctx->stack; - union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)]; - struct ofpbuf old_action_set = ctx->action_set; - struct ovs_list *old_trace = ctx->xin->trace; - uint64_t actset_stub[1024 / 8]; - - ofpbuf_use_stub(&ctx->stack, new_stack, sizeof new_stack); - ofpbuf_use_stub(&ctx->action_set, actset_stub, sizeof actset_stub); - flow->in_port.ofp_port = out_dev->ofp_port; - flow->metadata = htonll(0); - memset(&flow->tunnel, 0, sizeof flow->tunnel); - memset(&ctx->wc->masks.tunnel, 0, sizeof ctx->wc->masks.tunnel); - flow->tunnel.metadata.tab = - ofproto_get_tun_tab(&out_dev->xbridge->ofproto->up); - ctx->wc->masks.tunnel.metadata.tab = flow->tunnel.metadata.tab; - memset(flow->regs, 0, sizeof flow->regs); - flow->actset_output = OFPP_UNSET; - ctx->conntracked = false; - clear_conntrack(ctx); - ctx->xin->trace = xlate_report(ctx, OFT_BRIDGE, - "bridge(\"%s\")", - out_dev->xbridge->name); - mirror_mask_t old_mirrors = ctx->mirrors; - bool independent_mirrors = out_dev->xbridge != ctx->xbridge; - if (independent_mirrors) { - ctx->mirrors = 0; - } - ctx->xbridge = out_dev->xbridge; - - /* The bridge is now known so obtain its table version. */ - ctx->xin->tables_version - = ofproto_dpif_get_tables_version(ctx->xbridge->ofproto); - - if (!process_special(ctx, out_dev) && may_receive(out_dev, ctx)) { - if (xport_stp_forward_state(out_dev) && - xport_rstp_forward_state(out_dev)) { - xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, - false); - if (!ctx->freezing) { - xlate_action_set(ctx); - } - if (ctx->freezing) { - finish_freezing(ctx); - } - } else { - /* Forwarding is disabled by STP and RSTP. Let OFPP_NORMAL and - * the learning action look at the packet, then drop it. */ - struct flow old_base_flow = ctx->base_flow; - size_t old_size = ctx->odp_actions->size; - mirror_mask_t old_mirrors2 = ctx->mirrors; - - xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, - false); - ctx->mirrors = old_mirrors2; - ctx->base_flow = old_base_flow; - ctx->odp_actions->size = old_size; - - /* Undo changes that may have been done for freezing. */ - ctx_cancel_freeze(ctx); - } - } - - ctx->xin->trace = old_trace; - if (independent_mirrors) { - ctx->mirrors = old_mirrors; - } - ctx->xin->flow = old_flow; - ctx->xbridge = in_dev->xbridge; - ofpbuf_uninit(&ctx->action_set); - ctx->action_set = old_action_set; - ofpbuf_uninit(&ctx->stack); - ctx->stack = old_stack; - - /* Restore calling bridge's lookup version. */ - ctx->xin->tables_version = old_version; - - /* Restore to calling bridge tunneling information */ - ctx->wc->masks.tunnel = old_flow_tnl_wc; - - /* The out bridge popping MPLS should have no effect on the original - * bridge. */ - ctx->was_mpls = old_was_mpls; - - /* The out bridge's conntrack execution should have no effect on the - * original bridge. */ - ctx->conntracked = old_conntrack; - - /* The fact that the out bridge exits (for any reason) does not mean - * that the original bridge should exit. Specifically, if the out - * bridge freezes translation, the original bridge must continue - * processing with the original, not the frozen packet! */ - ctx->exit = false; - - /* Out bridge errors do not propagate back. */ - ctx->error = XLATE_OK; - - if (ctx->xin->resubmit_stats) { - netdev_vport_inc_tx(in_dev->netdev, ctx->xin->resubmit_stats); - netdev_vport_inc_rx(out_dev->netdev, ctx->xin->resubmit_stats); - if (out_dev->bfd) { - bfd_account_rx(out_dev->bfd, ctx->xin->resubmit_stats); - } - } - if (ctx->xin->xcache) { - struct xc_entry *entry; - entry = xlate_cache_add_entry(ctx->xin->xcache, XC_NETDEV); - entry->dev.tx = netdev_ref(in_dev->netdev); - entry->dev.rx = netdev_ref(out_dev->netdev); - entry->dev.bfd = bfd_ref(out_dev->bfd); - } -} - static void compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, const struct xlate_bond_recirc *xr, bool check_stp) @@ -3457,8 +3313,140 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, } if (xport->peer) { - apply_nested_clone_actions(ctx, xport, xport->peer); - return; + const struct xport *peer = xport->peer; + struct flow old_flow = ctx->xin->flow; + struct flow_tnl old_flow_tnl_wc = ctx->wc->masks.tunnel; + bool old_conntrack = ctx->conntracked; + bool old_was_mpls = ctx->was_mpls; + ovs_version_t old_version = ctx->xin->tables_version; + struct ofpbuf old_stack = ctx->stack; + uint8_t new_stack[1024]; + struct ofpbuf old_action_set = ctx->action_set; + struct ovs_list *old_trace = ctx->xin->trace; + uint64_t actset_stub[1024 / 8]; + + ofpbuf_use_stub(&ctx->stack, new_stack, sizeof new_stack); + ofpbuf_use_stub(&ctx->action_set, actset_stub, sizeof actset_stub); + flow->in_port.ofp_port = peer->ofp_port; + flow->metadata = htonll(0); + memset(&flow->tunnel, 0, sizeof flow->tunnel); + flow->tunnel.metadata.tab = ofproto_get_tun_tab( + &peer->xbridge->ofproto->up); + ctx->wc->masks.tunnel.metadata.tab = flow->tunnel.metadata.tab; + memset(flow->regs, 0, sizeof flow->regs); + flow->actset_output = OFPP_UNSET; + clear_conntrack(ctx); + ctx->xin->trace = xlate_report(ctx, OFT_BRIDGE, + "bridge(\"%s\")", peer->xbridge->name); + + /* When the patch port points to a different bridge, then the mirrors + * for that bridge clearly apply independently to the packet, so we + * reset the mirror bitmap to zero and then restore it after the packet + * returns. + * + * When the patch port points to the same bridge, this is more of a + * design decision: can mirrors be re-applied to the packet after it + * re-enters the bridge, or should we treat that as doubly mirroring a + * single packet? The former may be cleaner, since it respects the + * model in which a patch port is like a physical cable plugged from + * one switch port to another, but the latter may be less surprising to + * users. We take the latter choice, for now at least. (To use the + * former choice, hard-code 'independent_mirrors' to "true".) */ + mirror_mask_t old_mirrors = ctx->mirrors; + bool independent_mirrors = peer->xbridge != ctx->xbridge; + if (independent_mirrors) { + ctx->mirrors = 0; + } + ctx->xbridge = peer->xbridge; + + /* The bridge is now known so obtain its table version. */ + ctx->xin->tables_version + = ofproto_dpif_get_tables_version(ctx->xbridge->ofproto); + + if (!process_special(ctx, peer) && may_receive(peer, ctx)) { + if (xport_stp_forward_state(peer) && xport_rstp_forward_state(peer)) { + xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, + false); + if (!ctx->freezing) { + xlate_action_set(ctx); + } + if (ctx->freezing) { + finish_freezing(ctx); + } + } else { + /* Forwarding is disabled by STP and RSTP. Let OFPP_NORMAL and + * the learning action look at the packet, then drop it. */ + struct flow old_base_flow = ctx->base_flow; + size_t old_size = ctx->odp_actions->size; + mirror_mask_t old_mirrors2 = ctx->mirrors; + + xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, + false); + ctx->mirrors = old_mirrors2; + ctx->base_flow = old_base_flow; + ctx->odp_actions->size = old_size; + + /* Undo changes that may have been done for freezing. */ + ctx_cancel_freeze(ctx); + } + } + + ctx->xin->trace = old_trace; + if (independent_mirrors) { + ctx->mirrors = old_mirrors; + } + ctx->xin->flow = old_flow; + ctx->xbridge = xport->xbridge; + ofpbuf_uninit(&ctx->action_set); + ctx->action_set = old_action_set; + ofpbuf_uninit(&ctx->stack); + ctx->stack = old_stack; + + /* Restore calling bridge's lookup version. */ + ctx->xin->tables_version = old_version; + + /* Since this packet came in on a patch port (from the perspective of + * the peer bridge), it cannot have useful tunnel information. As a + * result, any wildcards generated on that tunnel also cannot be valid. + * The tunnel wildcards must be restored to their original version since + * the peer bridge uses a separate tunnel metadata table and therefore + * any generated wildcards will be garbage in the context of our + * metadata table. */ + ctx->wc->masks.tunnel = old_flow_tnl_wc; + + /* The peer bridge popping MPLS should have no effect on the original + * bridge. */ + ctx->was_mpls = old_was_mpls; + + /* The peer bridge's conntrack execution should have no effect on the + * original bridge. */ + ctx->conntracked = old_conntrack; + + /* The fact that the peer bridge exits (for any reason) does not mean + * that the original bridge should exit. Specifically, if the peer + * bridge freezes translation, the original bridge must continue + * processing with the original, not the frozen packet! */ + ctx->exit = false; + + /* Peer bridge errors do not propagate back. */ + ctx->error = XLATE_OK; + + if (ctx->xin->resubmit_stats) { + netdev_vport_inc_tx(xport->netdev, ctx->xin->resubmit_stats); + netdev_vport_inc_rx(peer->netdev, ctx->xin->resubmit_stats); + if (peer->bfd) { + bfd_account_rx(peer->bfd, ctx->xin->resubmit_stats); + } + } + if (ctx->xin->xcache) { + struct xc_entry *entry; + + entry = xlate_cache_add_entry(ctx->xin->xcache, XC_NETDEV); + entry->dev.tx = netdev_ref(xport->netdev); + entry->dev.rx = netdev_ref(peer->netdev); + entry->dev.bfd = bfd_ref(peer->bfd); + } + return; } memcpy(flow_vlans, flow->vlans, sizeof flow_vlans); diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index e52ab32b9..1f6cd8422 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -6257,6 +6257,15 @@ HEADER dgramSeqNo=1 ds=127.0.0.1>2:1000 fsSeqNo=1 + tunnel4_out_length=0 + tunnel4_out_protocol=47 + tunnel4_out_src=1.1.2.88 + tunnel4_out_dst=1.1.2.92 + tunnel4_out_src_port=0 + tunnel4_out_dst_port=0 + tunnel4_out_tcp_flags=0 + tunnel4_out_tos=0 + tunnel_out_vni=456 in_vlan=0 in_priority=0 out_vlan=0 @@ -6266,7 +6275,7 @@ HEADER dropEvents=0 in_ifindex=2011 in_format=0 - out_ifindex=2 + out_ifindex=1 out_format=2 hdr_prot=1 pkt_len=46 diff --git a/tests/ovn.at b/tests/ovn.at index e67d33b77..b30315e57 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -7140,11 +7140,7 @@ dst_ip=`ip_to_hex 192 168 1 3` expected=${dst_mac}${src_mac}08004500001c000000003f110100${src_ip}${dst_ip}0035111100080000 echo $expected >> hv2-vif1.expected -# The latest tunnel combine add only single combined rule in datapath instead -# of two. The following test case trying to match packet on non-existent second -# tunnel rule. -# Commenting the packet validation to avoid the test case failing. -# OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [hv2-vif1.expected]) +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [hv2-vif1.expected]) OVN_CLEANUP([hv1],[hv2],[hv3]) diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at index 593b85bf7..16dc571e2 100644 --- a/tests/tunnel-push-pop-ipv6.at +++ b/tests/tunnel-push-pop-ipv6.at @@ -90,28 +90,28 @@ dnl Check VXLAN tunnel push AT_CHECK([ovs-ofctl add-flow int-br action=2]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)) ]) dnl Check VXLAN tunnel push set tunnel id by flow and checksum AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::93,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::93,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)) ]) dnl Check GRE tunnel push AT_CHECK([ovs-ofctl add-flow int-br action=3]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(3),header(size=62,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(3),header(size=62,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)) ]) dnl Check Geneve tunnel push AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:2001:cafe::92->tun_ipv6_dst,5"]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(6081),header(size=70,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(6081),header(size=70,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100)) ]) dnl Check Geneve tunnel push with options @@ -119,7 +119,7 @@ AT_CHECK([ovs-ofctl add-tlv-map int-br "{class=0xffff,type=0x80,len=4}->tun_meta AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:2001:cafe::92->tun_ipv6_dst,set_field:0xa->tun_metadata0,5"]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(6081),header(size=78,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(6081),header(size=78,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100)) ]) dnl Check decapsulation of GRE packet diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index 294d28a24..4eeac4154 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -107,35 +107,35 @@ dnl Check VXLAN tunnel push AT_CHECK([ovs-ofctl add-flow int-br action=2]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)) ]) dnl Check VXLAN tunnel push set tunnel id by flow and checksum AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)) ]) dnl Check GRE tunnel push AT_CHECK([ovs-ofctl add-flow int-br action=3]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)) ]) dnl Check Geneve tunnel push AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:1.1.2.92->tun_dst,5"]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100)) ]) dnl Check Geneve tunnel push with pkt-mark AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:234,6"]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: set(skb_mark(0x4d2)),clone(tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(vni=0xea)),out_port(100)),1) + [Datapath actions: set(skb_mark(0x4d2)),tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(vni=0xea)),out_port(100)) ]) dnl Check Geneve tunnel push with options @@ -143,7 +143,7 @@ AT_CHECK([ovs-ofctl add-tlv-map int-br "{class=0xffff,type=0x80,len=4}->tun_meta AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:1.1.2.92->tun_dst,set_field:0xa->tun_metadata0,5"]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout]) AT_CHECK([tail -1 stdout], [0], - [Datapath actions: clone(tnl_push(tnl_port(6081),header(size=58,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100)),1) + [Datapath actions: tnl_push(tnl_port(6081),header(size=58,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100)) ]) dnl Check decapsulation of GRE packet