On 5/20/22 04:42, Rosemarie O'Riorden wrote:
> When OVS sees a tunnel push with a nested list next, it will not
> clone the packet, as a clone is not needed. However, a clone action will
> still be created with the tunnel push encapulated inside. There is no
> need to create the clone action in this case, as extra parsing will need
> to be performed, which is less efficient.
> 
> Signed-off-by: Rosemarie O'Riorden <[email protected]>
> ---
> v2:
>  - Fixes tests that are affected by the change
> v3:
>  - Adds support for hardware offloading
> 
>  lib/netdev-offload-dpdk.c     | 36 +++++++++------
>  lib/netlink.c                 |  4 +-
>  lib/netlink.h                 |  2 +-
>  ofproto/ofproto-dpif-xlate.c  | 21 ++++++---
>  tests/nsh.at                  |  6 +--
>  tests/packet-type-aware.at    | 24 +++++-----
>  tests/tunnel-push-pop-ipv6.at | 20 ++++-----
>  tests/tunnel-push-pop.at      | 83 ++++++++++++++++++++++++++---------
>  8 files changed, 129 insertions(+), 67 deletions(-)

Hi, Rosemarie.  Thanks for the patch!

Some comments inline.

Best regards, Ilya Maximets.

> 
> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
> index 12d299603..8749a7e7f 100644
> --- a/lib/netdev-offload-dpdk.c
> +++ b/lib/netdev-offload-dpdk.c
> @@ -2058,6 +2058,19 @@ parse_vlan_push_action(struct flow_actions *actions,
>      return 0;
>  }
>  
> +static void
> +tunnel_push_action(struct flow_actions *actions,
> +                         const struct ovs_action_push_tnl *tnl_push) {

A few nitpicks:

 - Might be better to add the 'add_' suffix to the function name,
   so it will look more like other similar functions in this file.

 - Please, align the indentation of the second argument with the
   start of the first one.

 - The '{' should be on a separate line.

> +     struct rte_flow_action_raw_encap *raw_encap;

An empty line here would be nice.

> +     raw_encap = xzalloc(sizeof *raw_encap);
> +     raw_encap->data = (uint8_t *) tnl_push->header;
> +     raw_encap->preserve = NULL;
> +     raw_encap->size = tnl_push->header_len;
> +
> +     add_flow_action(actions, RTE_FLOW_ACTION_TYPE_RAW_ENCAP,
> +                            raw_encap);

This should fit in a single line, no need to split.

> +}
> +
>  static int
>  parse_clone_actions(struct netdev *netdev,
>                      struct flow_actions *actions,
> @@ -2072,20 +2085,7 @@ parse_clone_actions(struct netdev *netdev,
>  
>          if (clone_type == OVS_ACTION_ATTR_TUNNEL_PUSH) {
>              const struct ovs_action_push_tnl *tnl_push = nl_attr_get(ca);
> -            struct rte_flow_action_raw_encap *raw_encap;
> -
> -            if (tnl_push->tnl_type == OVS_VPORT_TYPE_VXLAN &&
> -                !add_vxlan_encap_action(actions, tnl_push->header)) {
> -                continue;
> -            }

You moved the check and special hanlding of vxlan encap to the new 'else if'
branch in parse_flow_actions(), but it's still needed here too.  I think, it
should be moved inside the new tunnel_push_action() function.  You will just
need to replace the 'continue' with 'return', IIUC.  This way the correct
check will be performed regardless of having a clone().

> -
> -            raw_encap = xzalloc(sizeof *raw_encap);
> -            raw_encap->data = (uint8_t *) tnl_push->header;
> -            raw_encap->preserve = NULL;
> -            raw_encap->size = tnl_push->header_len;
> -
> -            add_flow_action(actions, RTE_FLOW_ACTION_TYPE_RAW_ENCAP,
> -                            raw_encap);
> +            tunnel_push_action(actions, tnl_push);
>          } else if (clone_type == OVS_ACTION_ATTR_OUTPUT) {
>              if (add_output_action(netdev, actions, ca)) {
>                  return -1;
> @@ -2188,6 +2188,14 @@ parse_flow_actions(struct netdev *netdev,
>              }
>          } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_VLAN) {
>              add_flow_action(actions, RTE_FLOW_ACTION_TYPE_OF_POP_VLAN, NULL);
> +        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_TUNNEL_PUSH) {
> +            const struct ovs_action_push_tnl *tnl_push = nl_attr_get(nla);
> +
> +            if (tnl_push->tnl_type == OVS_VPORT_TYPE_VXLAN &&
> +                !add_vxlan_encap_action(actions, tnl_push->header)) {
> +                continue;
> +            }
> +            tunnel_push_action(actions, tnl_push);
>          } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CLONE &&
>                     left <= NLA_ALIGN(nla->nla_len)) {
>              const struct nlattr *clone_actions = nl_attr_get(nla);
> diff --git a/lib/netlink.c b/lib/netlink.c
> index 8204025a5..06929ff9c 100644
> --- a/lib/netlink.c
> +++ b/lib/netlink.c
> @@ -536,7 +536,7 @@ nl_msg_end_nested(struct ofpbuf *msg, size_t offset)
>  /* Cancel a nested Netlink attribute in 'msg'.  'offset' should be the value
>   * returned by nl_msg_start_nested(). */
>  void
> -nl_msg_cancel_nested(struct ofpbuf *msg, size_t offset)
> +nl_msg_reset_size(struct ofpbuf *msg, size_t offset)

It's probably better to just create a separate function, even if it's
exactly the same.  *_nested() has specific semantics and better be kept
intact.  And you didn't update the comments.

>  {
>      msg->size = offset;
>  }
> @@ -552,7 +552,7 @@ nl_msg_end_non_empty_nested(struct ofpbuf *msg, size_t 
> offset)
>  
>      struct nlattr *attr = ofpbuf_at_assert(msg, offset, sizeof *attr);
>      if (!nl_attr_get_size(attr)) {
> -        nl_msg_cancel_nested(msg, offset);
> +        nl_msg_reset_size(msg, offset);
>          return true;
>      } else {
>          return false;
> diff --git a/lib/netlink.h b/lib/netlink.h
> index b97470743..0f6916179 100644
> --- a/lib/netlink.h
> +++ b/lib/netlink.h
> @@ -82,7 +82,7 @@ void nl_msg_put_string(struct ofpbuf *, uint16_t type, 
> const char *value);
>  
>  size_t nl_msg_start_nested(struct ofpbuf *, uint16_t type);
>  void nl_msg_end_nested(struct ofpbuf *, size_t offset);
> -void nl_msg_cancel_nested(struct ofpbuf *, size_t offset);
> +void nl_msg_reset_size(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);
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index 8e5d030ac..44c3ce630 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -3727,7 +3727,10 @@ native_tunnel_output(struct xlate_ctx *ctx, const 
> struct xport *xport,
>      size_t clone_ofs = 0;
>      size_t push_action_size;
>  
> -    clone_ofs = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_CLONE);
> +    if (!is_last_action) {
> +        clone_ofs = nl_msg_start_nested(ctx->odp_actions,
> +                                OVS_ACTION_ATTR_CLONE);

Please, align the indentation of the second argument with the start
of the first one, i.e. shift it 8 spaces to the right.

> +    }
>      odp_put_tnl_push_action(ctx->odp_actions, &tnl_push_data);
>      push_action_size = ctx->odp_actions->size;
>  
> @@ -3758,6 +3761,7 @@ native_tunnel_output(struct xlate_ctx *ctx, const 
> struct xport *xport,
>          entry->tunnel_hdr.hdr_size = tnl_push_data.header_len;
>          entry->tunnel_hdr.operation = ADD;
>  
> +        size_t pre_patch_port_outp_size = ctx->odp_actions->size;

Looks like (pre_patch_port_outp_size == push_action_size) at this point.

>          patch_port_output(ctx, xport, out_dev, is_last_action);
>  
>          /* Similar to the stats update in revalidation, the x_cache entries
> @@ -3771,9 +3775,16 @@ native_tunnel_output(struct xlate_ctx *ctx, const 
> struct xport *xport,
>          xlate_cache_steal_entries(backup_xcache, ctx->xin->xcache);
>  
>          if (ctx->odp_actions->size > push_action_size) {
> -            nl_msg_end_non_empty_nested(ctx->odp_actions, clone_ofs);
> +            if (!is_last_action) {
> +                nl_msg_end_non_empty_nested(ctx->odp_actions, clone_ofs);
> +            }
>          } else {
> -            nl_msg_cancel_nested(ctx->odp_actions, clone_ofs);
> +            /* Cancels nested clone action */

It's better to write comments in imperative form.  Don't say what the
code does, but command what it has to do, unless it's a big comment where
you need to describe a lot of details.  So, 'Cancel' instead of 'Cancels'
in this case.  Same for other comments in this function.

> +            nl_msg_reset_size(ctx->odp_actions, clone_ofs);

This doesn't seem to be a clean implementation.  The clone_ofs is zero
in case it's a last action.  I don't think we should re-set it to zero
and then re-set back.  It's better to have this size reset under the
'if (!is_last_action)'.

> +            if (is_last_action) {
> +                /* Resets size since no actions added in patch port output */
> +                nl_msg_reset_size(ctx->odp_actions, 
> pre_patch_port_outp_size);

If patch_port_output() didn't add anything, the size stays equal
to the 'pre_patch_port_outp_size', so this reset is kind of
pointless.  We should re-set the size to the value before the
odp_put_tnl_push_action() to guarantee that we don't have tunnel
push action hanging in the end of the list.

> +            }
>          }
>  
>          /* Restore context status. */
> @@ -3785,7 +3796,7 @@ native_tunnel_output(struct xlate_ctx *ctx, const 
> struct xport *xport,
>          ctx->wc = backup_wc;
>      } else {
>          /* In order to maintain accurate stats, use recirc for
> -         * natvie tunneling.  */
> +         * native tunneling.  */
>          nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_RECIRC, 0);
>          nl_msg_end_nested(ctx->odp_actions, clone_ofs);
>      }
> @@ -5866,7 +5877,7 @@ clone_xlate_actions(const struct ofpact *actions, 
> size_t actions_len,
>              finish_freezing(ctx);
>          }
>          if (nl_msg_end_non_empty_nested(ctx->odp_actions, ac_offset)) {
> -            nl_msg_cancel_nested(ctx->odp_actions, offset);
> +            nl_msg_reset_size(ctx->odp_actions, offset);
>          } else {
>              nl_msg_put_u32(ctx->odp_actions, OVS_SAMPLE_ATTR_PROBABILITY,
>                             UINT32_MAX); /* 100% probability. */
> diff --git a/tests/nsh.at b/tests/nsh.at
> index 4d49f1201..acda379fd 100644
> --- a/tests/nsh.at
> +++ b/tests/nsh.at
> @@ -724,7 +724,7 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 
> | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789))
> +recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789)
>  
> tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3000,si=255),
>  packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x1)
>  
> tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x1),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no),
>  packets:1, bytes:84, used:0.0s, 
> actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
>  ])
> @@ -778,8 +778,8 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 
> | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789))
> -tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(spi=0x3020,si=255),
>  packets:1, bytes:108, used:0.0s, 
> actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789))
> +recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789)
> +tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(spi=0x3020,si=255),
>  packets:1, bytes:108, used:0.0s, 
> actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789)
>  
> tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3020,si=254),
>  packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x2)
>  
> tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x2),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no),
>  packets:1, bytes:84, used:0.0s, 
> actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
>  ])
> diff --git a/tests/packet-type-aware.at b/tests/packet-type-aware.at
> index 054dcc9cc..3b5c66fe5 100644
> --- a/tests/packet-type-aware.at
> +++ b/tests/packet-type-aware.at
> @@ -326,7 +326,7 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys))
> +recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys)
>  
> tunnel(src=30.0.0.1,dst=30.0.0.3,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no),
>  packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:03)),n3
>  ])
>  
> @@ -344,7 +344,7 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(gre_sys))
> +recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(gre_sys)
>  
> tunnel(src=20.0.0.1,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=46:1e:7d:1a:95:a1),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no),
>  packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:02)),n2
>  ])
>  
> @@ -362,7 +362,7 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys))
> +recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
>  
> tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=3a:6d:d2:09:9c:ab),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no),
>  packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:01)),n1
>  ])
>  
> @@ -380,8 +380,8 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys))
> -tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys))
> +recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
> +tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys)
>  
> tunnel(src=30.0.0.1,dst=30.0.0.3,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no),
>  packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:03)),n3
>  ])
>  
> @@ -399,9 +399,9 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys))
> +recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)
>  
> tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no),
>  packets:1, bytes:84, used:0.0s, 
> actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:01),n1
> -tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
>  packets:1, bytes:84, used:0.0s, 
> actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys))
> +tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no),
>  packets:1, bytes:84, used:0.0s, 
> actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
>  ])
>  
>  # Clear up megaflow cache
> @@ -418,7 +418,7 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys))
> +recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)
>  
> tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=46:1e:7d:1a:95:a1),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no),
>  packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:02)),n2
>  ])
>  
> @@ -504,7 +504,7 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys))
> +recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)
>  
> tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no),
>  packets:1, bytes:84, used:0.0s, actions:drop
>  ])
>  
> @@ -726,7 +726,7 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2)
> +recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2
>  ])
>  
>  AT_CHECK([
> @@ -814,7 +814,7 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2)
> +recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2
>  ])
>  
>  AT_CHECK([
> @@ -892,7 +892,7 @@ ovs-appctl time/warp 1000
>  AT_CHECK([
>      ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep 
> -v ipv6 | sort
>  ], [0], [flow-dump from the main thread:
> -recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:n1,pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2)
> +recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no),
>  packets:1, bytes:98, used:0.0s, 
> actions:n1,pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2
>  ])
>  
>  AT_CHECK([
> diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at
> index 3f58e3e8f..f18603467 100644
> --- a/tests/tunnel-push-pop-ipv6.at
> +++ b/tests/tunnel-push-pop-ipv6.at
> @@ -63,7 +63,7 @@ AT_CHECK([ovs-ofctl add-flow int-br action=2])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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(6),header(size=58,type=109,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=0x0,proto=0x6558))),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(6),header(size=58,type=109,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=0x0,proto=0x6558))),out_port(100)),1
>  ])
>  
>  OVS_VSWITCHD_STOP
> @@ -151,14 +151,14 @@ dnl Check ERSPAN v1 tunnel push
>  AT_CHECK([ovs-ofctl add-flow int-br action=2])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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(6),header(size=70,type=108,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),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(6),header(size=70,type=108,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),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)),1
>  ])
>  
>  dnl Check ERSPAN v2 tunnel push
>  AT_CHECK([ovs-ofctl mod-flows int-br action=3])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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(6),header(size=74,type=108,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=47,tclass=0x0,hlimit=64),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(6),header(size=74,type=108,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=47,tclass=0x0,hlimit=64),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)),1
>  ])
>  
>  ovs-appctl vlog/set dbg
> @@ -388,28 +388,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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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)),1
>  ])
>  
>  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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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)),1
>  ])
>  
>  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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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=109,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=109,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
>  ])
>  
>  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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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)),1
>  ])
>  
>  dnl Check Geneve tunnel push with options
> @@ -417,7 +417,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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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)),1
>  ])
>  
>  dnl Check decapsulation of GRE packet
> @@ -472,7 +472,7 @@ 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(src=36:b1:ee:7c:01:01,dst=36:b1:ee:7c:01:02),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:ca:fe,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:ca:fe,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
>  ])
>  
>  AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl
> @@ -490,7 +490,7 @@ 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(src=36:b1:ee:7c:01:01,dst=36:b1:ee:7c:01:02),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)),1
>  ])
>  
>  AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl
> diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
> index c63344196..dccf5cf48 100644
> --- a/tests/tunnel-push-pop.at
> +++ b/tests/tunnel-push-pop.at
> @@ -85,7 +85,7 @@ AT_CHECK([ovs-vsctl -- set Interface br0 
> options:pcap=br0.pcap])
>  AT_CHECK([ovs-ofctl add-flow int-br action=2])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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=50,type=107,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),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(3),header(size=50,type=107,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),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)),1
>  ])
>  
>  dnl Check ERSPAN v2 tunnel push
> @@ -93,7 +93,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br action=3])
>  AT_CHECK([ovs-appctl revalidator/wait])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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=54,type=107,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),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(3),header(size=54,type=107,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),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)),1
>  ])
>  
>  dnl Check ERSPAN v2 flow-based tunnel push
> @@ -101,7 +101,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br 
> "action=set_field:1.1.2.94->tun_dst,set_fie
>  AT_CHECK([ovs-appctl revalidator/wait])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x1c8,dir=1,hwid=0x1)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x1c8,dir=1,hwid=0x1)),out_port(100)),1
>  ])
>  
>  dnl Check ERSPAN v2 flow-based tunnel push, erspan_ver=flow
> @@ -110,7 +110,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br 
> "action=set_field:1.1.2.94->tun_dst,set_fie
>  AT_CHECK([ovs-appctl revalidator/wait])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x38,dir=1,hwid=0x1)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x38,dir=1,hwid=0x1)),out_port(100)),1
>  ])
>  
>  dnl Dynamically set erspan v1
> @@ -118,7 +118,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br 
> "action=set_field:1.1.2.94->tun_dst,set_fie
>  AT_CHECK([ovs-appctl revalidator/wait])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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=50,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x38,idx=0x1)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(3),header(size=50,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x38,idx=0x1)),out_port(100)),1
>  ])
>  
>  dnl Check ERSPAN v2 flow-based tunnel push
> @@ -126,7 +126,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br 
> "action=set_field:1.1.2.94->tun_dst,set_fie
>  AT_CHECK([ovs-appctl revalidator/wait])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x1c8,dir=1,hwid=0x1)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x1c8,dir=1,hwid=0x1)),out_port(100)),1
>  ])
>  
>  dnl Check ERSPAN v2 flow-based tunnel push, erspan_ver=flow
> @@ -135,7 +135,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br 
> "action=set_field:1.1.2.94->tun_dst,set_fie
>  AT_CHECK([ovs-appctl revalidator/wait])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x38,dir=1,hwid=0x1)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x38,dir=1,hwid=0x1)),out_port(100)),1
>  ])
>  
>  dnl Dynamically set erspan v1
> @@ -143,7 +143,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br 
> "action=set_field:1.1.2.94->tun_dst,set_fie
>  AT_CHECK([ovs-appctl revalidator/wait])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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=50,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x38,idx=0x1)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(3),header(size=50,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x38,idx=0x1)),out_port(100)),1
>  ])
>  
>  dnl Check ERSPAN tunnel pop
> @@ -431,49 +431,49 @@ 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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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)),1
>  ])
>  
>  dnl Check VXLAN GPE tunnel push
>  AT_CHECK([ovs-ofctl add-flow int-br action=8])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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=0xc000003,vni=0x159)),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=0xc000003,vni=0x159)),out_port(100)),1
>  ])
>  
>  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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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)),1
>  ])
>  
>  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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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)),1
>  ])
>  
>  dnl Check L3GRE tunnel push
>  AT_CHECK([ovs-ofctl add-flow int-br action=7])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),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: 
> pop_eth,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=0x800),key=0x1c8)),out_port(100)),1)
> +  [Datapath actions: 
> pop_eth,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=0x800),key=0x1c8)),out_port(100)),1
>  ])
>  
>  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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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)),1
>  ])
>  
>  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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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)),1
>  ])
>  
>  dnl Check Geneve tunnel push with options
> @@ -481,7 +481,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(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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)),1
>  ])
>  
>  dnl Check GTP-U tunnel push
> @@ -489,7 +489,7 @@ AT_CHECK([ovs-ofctl add-flow int-br "actions=9"])
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),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: 
> pop_eth,clone(tnl_push(tnl_port(2152),header(size=50,type=110,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=2152,csum=0x0),gtpu(flags=0x30,msgtype=255,teid=0x7b)),out_port(100)),1)
> +  [Datapath actions: 
> pop_eth,tnl_push(tnl_port(2152),header(size=50,type=110,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=2152,csum=0x0),gtpu(flags=0x30,msgtype=255,teid=0x7b)),out_port(100)),1
>  ])
>  AT_CHECK([ovs-ofctl del-flows int-br])
>  
> @@ -601,7 +601,7 @@ 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(src=36:b1:ee:7c:01:01,dst=36:b1:ee:7c:01:02),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:ca:fe,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:ca:fe,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
>  ])
>  
>  AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
> @@ -618,7 +618,7 @@ ovs-appctl time/warp 1000
>  dnl Check VXLAN tunnel push
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=36:b1:ee:7c:01:01,dst=36:b1:ee:7c:01:02),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)),1
>  ])
>  
>  AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
> @@ -794,7 +794,7 @@ AT_CHECK([ovs-ofctl add-flow int-br action=3])
>  
>  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=4789)'],
>  [0], [stdout])
>  AT_CHECK([tail -1 stdout], [0],
> -  [Datapath actions: 
> clone(tnl_push(tnl_port(3),header(size=46,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=0x3000,proto=0x6558),key=0x1c8,seq=0x0)),out_port(100)),1)
> +  [Datapath actions: 
> tnl_push(tnl_port(3),header(size=46,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=0x3000,proto=0x6558),key=0x1c8,seq=0x0)),out_port(100)),1
>  ])
>  
>  dnl Verify outer L2 and L3 header flow fields can be matched in the underlay 
> bridge
> @@ -915,3 +915,46 @@ out_port(100)),8)
>  
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
> +
> +AT_SETUP([tunnel_push_pop - no clone when is_last_action])
> +
> +dnl Create bridge that has a MAC address
> +OVS_VSWITCHD_START([set bridge br0 dnl
> +                    datapath_type=dummy -- set Interface dnl
> +                    br0 other-config:hwaddr=aa:55:aa:55:00:00])

Please, split lines before '--', not in the middle of the subcommand.
It's easier to read this way.  E.g.:

OVS_VSWITCHD_START([set bridge br0 datapath_type=dummy dnl
                    -- set Interface br0 other-config:hwaddr=aa:55:aa:55:00:00])

Same for other commands in the test.  You may use the previous test
as an example.

> +AT_CHECK([ovs-vsctl add-port br0 p8 -- set Interface p8 dnl
> +           type=dummy ofport_request=8])
> +
> +dnl Create another bridge
> +AT_CHECK([ovs-vsctl add-br ovs-tun0 -- set bridge ovs-tun0 
> datapath_type=dummy])
> +
> +dnl Add VXLAN port to this bridge
> +AT_CHECK([ovs-vsctl add-port ovs-tun0 tun0 -- set int tun0 dnl
> +          type=vxlan options:remote_ip=10.0.0.11 -- add-port ovs-tun0 p7 dnl
> +          -- set interface p7 type=dummy ofport_request=7])
> +
> +dnl Set IP address and route for br0
> +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 10.0.0.2/24], [0], [OK
> +])
> +AT_CHECK([ovs-appctl ovs/route/add 10.0.0.11/24 br0], [0], [OK
> +])
> +
> +dnl Send an ARP reply to port b8 on br0, so that packets will be forwarded
> +dnl to learned port
> +AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> +AT_CHECK([ovs-ofctl del-flows ovs-tun0])
> +AT_CHECK([ovs-ofctl add-flow ovs-tun0 "in_port=p7,actions=tun0"])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),dnl
> +   eth(src=aa:55:aa:66:00:00,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),dnl
> +   
> arp(sip=10.0.0.11,tip=10.0.0.2,op=2,sha=aa:55:aa:66:00:00,tha=00:00:00:00:00:00)'])
> +AT_CHECK([ovs-appctl ofproto/trace ovs-tun0 in_port=p7], [0], [stdout])
> +AT_CHECK([tail -2 stdout], [0], [dnl
> +Megaflow: recirc_id=0,eth,in_port=7,dl_type=0x0000
> +Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,dnl
> +eth(dst=aa:55:aa:66:00:00,src=aa:55:aa:55:00:00,dl_type=0x0800),dnl
> +ipv4(src=10.0.0.2,dst=10.0.0.11,proto=17,tos=0,ttl=64,frag=0x4000),dnl
> +udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x0)),out_port(100)),8
> +])

Since you're writing a separte test for this functionality, can we also have
a negative check here?  i.e. add a flow with more than one action and see if
clone() is still there.

> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP

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

Reply via email to