@@ -447,6 +447,7 @@ enum ovs_tunnel_key_attr {
#ifndef __KERNEL__
/* Only used within userspace data path. */
OVS_TUNNEL_KEY_ATTR_GTPU_OPTS, /* struct gtpu_metadata */
+ OVS_TUNNEL_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */
#endif
__OVS_TUNNEL_KEY_ATTR_MAX
};
@@ -127,6 +127,9 @@ void match_set_tun_gtpu_flags_masked(struct match *match, uint8_t flags,
void match_set_tun_gtpu_msgtype(struct match *match, uint8_t msgtype);
void match_set_tun_gtpu_msgtype_masked(struct match *match, uint8_t msgtype,
uint8_t mask);
+void match_set_tun_eth_type(struct match *, ovs_be16 eth_type);
+void match_set_tun_eth_type_masked(struct match *match, ovs_be16 eth_type,
+ uint16_t mask);
void match_set_in_port(struct match *, ofp_port_t ofp_port);
void match_set_pkt_mark(struct match *, uint32_t pkt_mark);
void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t mask);
@@ -304,6 +304,20 @@ enum OVS_PACKED_ENUM mf_field_id {
*/
MFF_TUN_ID,
+ /* "tun_eth_type".
+ *
+ * Packet's Tunnel Ethernet type.
+ *
+ * Type: be16.
+ * Maskable: no.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read-only.
+ * NXM: none.
+ * OXM: none.
+ */
+ MFF_TUN_ETH_TYPE,
+
/* "tun_src".
*
* The IPv4 source address in the outer IP header of a tunneled packet.
@@ -45,7 +45,8 @@ struct flow_tnl {
uint8_t erspan_hwid;
uint8_t gtpu_flags;
uint8_t gtpu_msgtype;
- uint8_t pad1[4]; /* Pad to 64 bits. */
+ ovs_be16 eth_type;
+ uint8_t pad1[2]; /* Pad to 64 bits. */
struct tun_metadata metadata;
};
@@ -1323,6 +1323,9 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
match_set_tun_flags(flow_metadata,
flow->tunnel.flags & FLOW_TNL_PUB_F_MASK);
}
+ if (flow->tunnel.eth_type) {
+ match_set_tun_eth_type(flow_metadata, flow->tunnel.eth_type);
+ }
if (flow->tunnel.ip_src) {
match_set_tun_src(flow_metadata, flow->tunnel.ip_src);
}
@@ -402,6 +402,20 @@ match_set_tun_gtpu_msgtype(struct match *match, uint8_t msgtype)
match_set_tun_gtpu_msgtype_masked(match, msgtype, UINT8_MAX);
}
+void
+match_set_tun_eth_type_masked(struct match *match, ovs_be16 eth_type,
+ uint16_t mask)
+{
+ match->wc.masks.tunnel.eth_type = eth_type;
+ match->flow.tunnel.eth_type = eth_type & mask;
+}
+
+void
+match_set_tun_eth_type(struct match *match, ovs_be16 eth_type)
+{
+ match_set_tun_eth_type_masked(match, eth_type, OVS_BE16_MAX);
+}
+
void
match_set_in_port(struct match *match, ofp_port_t ofp_port)
{
@@ -1391,6 +1405,9 @@ format_flow_tunnel(struct ds *s, const struct match *match)
if (wc->masks.tunnel.gtpu_msgtype) {
ds_put_format(s, "gtpu_msgtype=%"PRIu8",", tnl->gtpu_msgtype);
}
+ if (wc->masks.tunnel.eth_type) {
+ ds_put_format(s, "tun_eth_type=0x%04"PRIx16",", ntohs(tnl->eth_type));
+ }
if (wc->masks.tunnel.flags & FLOW_TNL_F_MASK) {
format_flags_masked(s, "tun_flags", flow_tun_flag_to_string,
tnl->flags & FLOW_TNL_F_MASK,
@@ -213,6 +213,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
return !wc->masks.packet_type;
case MFF_CONJ_ID:
return !wc->masks.conj_id;
+ case MFF_TUN_ETH_TYPE:
+ return !wc->masks.tunnel.eth_type;
case MFF_TUN_SRC:
return !wc->masks.tunnel.ip_src;
case MFF_TUN_DST:
@@ -524,6 +526,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
case MFF_PACKET_TYPE:
case MFF_CONJ_ID:
case MFF_TUN_ID:
+ case MFF_TUN_ETH_TYPE:
case MFF_TUN_SRC:
case MFF_TUN_DST:
case MFF_TUN_IPV6_SRC:
@@ -680,6 +683,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
case MFF_TUN_ID:
value->be64 = flow->tunnel.tun_id;
break;
+ case MFF_TUN_ETH_TYPE:
+ value->be16 = flow->tunnel.eth_type;
+ break;
case MFF_TUN_SRC:
value->be32 = flow->tunnel.ip_src;
break;
@@ -1017,6 +1023,9 @@ mf_set_value(const struct mf_field *mf,
case MFF_TUN_ID:
match_set_tun_id(match, value->be64);
break;
+ case MFF_TUN_ETH_TYPE:
+ match_set_tun_eth_type(match, value->be16);
+ break;
case MFF_TUN_SRC:
match_set_tun_src(match, value->be32);
break;
@@ -1439,6 +1448,9 @@ mf_set_flow_value(const struct mf_field *mf,
case MFF_TUN_ID:
flow->tunnel.tun_id = value->be64;
break;
+ case MFF_TUN_ETH_TYPE:
+ flow->tunnel.eth_type = value->be16;
+ break;
case MFF_TUN_SRC:
flow->tunnel.ip_src = value->be32;
break;
@@ -1823,6 +1835,7 @@ mf_is_any_metadata(const struct mf_field *mf)
return true;
case MFF_TUN_ID:
+ case MFF_TUN_ETH_TYPE:
case MFF_TUN_SRC:
case MFF_TUN_DST:
case MFF_TUN_IPV6_SRC:
@@ -1917,6 +1930,7 @@ mf_is_pipeline_field(const struct mf_field *mf)
{
switch (mf->id) {
case MFF_TUN_ID:
+ case MFF_TUN_ETH_TYPE:
case MFF_TUN_SRC:
case MFF_TUN_DST:
case MFF_TUN_IPV6_SRC:
@@ -2075,6 +2089,9 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
case MFF_TUN_ID:
match_set_tun_id_masked(match, htonll(0), htonll(0));
break;
+ case MFF_TUN_ETH_TYPE:
+ match_set_tun_eth_type_masked(match, 0, 0);
+ break;
case MFF_TUN_SRC:
match_set_tun_src_masked(match, htonl(0), htonl(0));
break;
@@ -2487,6 +2504,9 @@ mf_set(const struct mf_field *mf,
case MFF_TUN_ID:
match_set_tun_id_masked(match, value->be64, mask->be64);
break;
+ case MFF_TUN_ETH_TYPE:
+ match_set_tun_eth_type_masked(match, value->be16, mask->be16);
+ break;
case MFF_TUN_SRC:
match_set_tun_src_masked(match, value->be32, mask->be32);
break;
@@ -1508,6 +1508,7 @@ ovs-ofctl add-flow br-int 'in_port=3,tun_src=192.168.1.1,tun_id=5001 actions=1'
</diagram>
</field>
+ <field id="MFF_TUN_ETH_TYPE" title="Tunnel Ethernet type" internal="yes"/>
<field id="MFF_TUN_SRC" title="Tunnel IPv4 Source">
<p>
When a packet is received from a tunnel, this field is the
@@ -95,6 +95,7 @@ ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
void *nh;
struct ip_header *ip;
struct ovs_16aligned_ip6_hdr *ip6;
+ const struct eth_header *eth;
void *l4;
int l3_size;
@@ -175,6 +176,11 @@ ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
return NULL;
}
+ eth = dp_packet_eth(packet);
+ if (eth) {
+ tnl->eth_type = eth->eth_type;
+ }
+
return l4;
}
@@ -1253,6 +1253,9 @@ parse_tnl_ip_match(struct flow_patterns *patterns,
return -1;
}
+ /* Temporary ignore. */
+ match->wc.masks.tunnel.eth_type = 0;
+
return 0;
}
@@ -2877,6 +2877,7 @@ static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX +
[OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = 16 },
[OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS] = { .len = ATTR_LEN_VARIABLE },
[OVS_TUNNEL_KEY_ATTR_GTPU_OPTS] = { .len = ATTR_LEN_VARIABLE },
+ [OVS_TUNNEL_KEY_ATTR_ETHERTYPE] = { .len = 2 },
};
const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = {
@@ -3278,6 +3279,9 @@ odp_tun_key_from_attr__(const struct nlattr *attr, bool is_mask,
tun->gtpu_msgtype = opts->msgtype;
break;
}
+ case OVS_TUNNEL_KEY_ATTR_ETHERTYPE:
+ tun->eth_type = nl_attr_get_be16(a);
+ break;
default:
/* Allow this to show up as unexpected, if there are unknown
@@ -3402,6 +3406,11 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
nl_msg_put_unspec(a, OVS_TUNNEL_KEY_ATTR_GTPU_OPTS,
&opts, sizeof(opts));
}
+
+ if (tun_key->eth_type) {
+ nl_msg_put_be16(a, OVS_TUNNEL_KEY_ATTR_ETHERTYPE, tun_key->eth_type);
+ }
+
nl_msg_end_nested(a, tun_key_ofs);
}
@@ -4177,6 +4186,10 @@ format_odp_tun_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
format_odp_tun_gtpu_opt(a, ma, ds, verbose);
ds_put_cstr(ds, "),");
break;
+ case OVS_TUNNEL_KEY_ATTR_ETHERTYPE:
+ format_be16x(ds, "eth_type", nl_attr_get_be16(a),
+ ma ? nl_attr_get(ma) : NULL, verbose);
+ break;
case __OVS_TUNNEL_KEY_ATTR_MAX:
default:
format_unknown_key(ds, a, ma);
@@ -6064,6 +6077,8 @@ parse_odp_key_mask_attr__(struct parse_odp_context *context, const char *s,
SCAN_BEGIN_NESTED("tunnel(", OVS_KEY_ATTR_TUNNEL) {
SCAN_FIELD_NESTED("tun_id=", ovs_be64, be64, OVS_TUNNEL_KEY_ATTR_ID);
+ SCAN_FIELD_NESTED("eth_type=", ovs_be16, be16,
+ OVS_TUNNEL_KEY_ATTR_ETHERTYPE);
SCAN_FIELD_NESTED("src=", ovs_be32, ipv4, OVS_TUNNEL_KEY_ATTR_IPV4_SRC);
SCAN_FIELD_NESTED("dst=", ovs_be32, ipv4, OVS_TUNNEL_KEY_ATTR_IPV4_DST);
SCAN_FIELD_NESTED("ipv6_src=", struct in6_addr, in6_addr, OVS_TUNNEL_KEY_ATTR_IPV6_SRC);
@@ -207,7 +207,10 @@ int odp_flow_from_string(const char *s, const struct simap *port_names,
\
/* If true, it means that the datapath supports the IPv6 Neigh \
* Discovery Extension bits. */ \
- ODP_SUPPORT_FIELD(bool, nd_ext, "IPv6 ND Extension")
+ ODP_SUPPORT_FIELD(bool, nd_ext, "IPv6 ND Extension") \
+ \
+ /* Tunnel ethernet type matching supported. */ \
+ ODP_SUPPORT_FIELD(bool, tun_eth_type, "Tunnel Ethernet Type")
/* Indicates support for various fields. This defines how flows will be
* serialised. */
@@ -8081,6 +8081,8 @@ xlate_wc_init(struct xlate_ctx *ctx)
static void
xlate_wc_finish(struct xlate_ctx *ctx)
{
+ struct ofproto_dpif *ofproto = ctx->xbridge->ofproto;
+ struct dpif_backer *backer = ofproto->backer;
int i;
/* Clear the metadata and register wildcard masks, because we won't
@@ -8148,9 +8150,14 @@ xlate_wc_finish(struct xlate_ctx *ctx)
ctx->wc->masks.vlans[i].tci = 0;
}
}
- /* Clear tunnel wc bits if original packet is non-tunnel. */
+ /* Handle tunnel wildcarding and unwildcarding. */
if (!flow_tnl_dst_is_set(&ctx->xin->upcall_flow->tunnel)) {
+ /* Clear tunnel wc bits if original packet is non-tunnel. */
memset(&ctx->wc->masks.tunnel, 0, sizeof ctx->wc->masks.tunnel);
+ } else if (backer->rt_support.odp.tun_eth_type &&
+ ctx->xin->upcall_flow->tunnel.eth_type != 0) {
+ /* Unwildcard tunnel eth_type when supported and present. */
+ ctx->wc->masks.tunnel.eth_type = OVS_BE16_MAX;
}
}
@@ -1659,6 +1659,75 @@ check_psample(struct dpif_backer *backer)
return supported;
}
+static bool
+check_tun_eth_type(struct dpif_backer *backer)
+{
+ struct flow flow;
+ struct odputil_keybuf keybuf;
+ struct ofpbuf key;
+ struct ofpbuf reply;
+ struct dpif_flow returned_flow;
+ uint64_t stub[DPIF_FLOW_BUFSIZE / 8];
+ bool enable = false;
+ ovs_be16 expected_eth_type = htons(ETH_TYPE_IP);
+ struct odp_flow_key_parms odp_parms = {
+ .flow = &flow,
+ .support = {
+ .tun_eth_type = true,
+ },
+ };
+
+ memset(&flow, 0, sizeof flow);
+ flow.tunnel.eth_type = expected_eth_type;
+ flow.tunnel.ip_dst = htonl(0x01020304);
+ flow.tunnel.ip_src = htonl(0x05060708);
+ flow.dl_type = htons(ETH_TYPE_IP);
+
+ ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
+ odp_flow_key_from_flow(&odp_parms, &key);
+
+ /* Try to install the flow */
+ int error = dpif_flow_put(backer->dpif,
+ DPIF_FP_CREATE | DPIF_FP_PROBE,
+ key.data, key.size, NULL, 0,
+ NULL, 0, NULL, NON_PMD_CORE_ID, NULL);
+ if (error) {
+ goto out;
+ }
+
+ /* Read it back and verify the field is preserved */
+ ofpbuf_use_stack(&reply, &stub, sizeof stub);
+ error = dpif_flow_get(backer->dpif, key.data, key.size, NULL,
+ NON_PMD_CORE_ID, &reply, &returned_flow);
+ if (error) {
+ goto cleanup;
+ }
+
+ /* Parse the returned flow and check if eth_type matches */
+ struct flow returned_flow_struct;
+ error = odp_flow_key_to_flow(returned_flow.key, returned_flow.key_len,
+ &returned_flow_struct, NULL);
+ if (!error && returned_flow_struct.tunnel.eth_type == expected_eth_type) {
+ enable = true;
+ }
+
+cleanup:
+ /* Clean up the test flow */
+ dpif_flow_del(backer->dpif, key.data, key.size, NULL,
+ NON_PMD_CORE_ID, NULL);
+
+out:
+ if (enable) {
+ VLOG_INFO("%s: Datapath supports tun_eth_type",
+ dpif_name(backer->dpif));
+ } else {
+ VLOG_INFO("%s: Datapath does not support tun_eth_type",
+ dpif_name(backer->dpif));
+ }
+
+ return enable;
+}
+
#define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE, ETHTYPE) \
static bool \
check_##NAME(struct dpif_backer *backer) \
@@ -1759,6 +1828,7 @@ check_support(struct dpif_backer *backer)
backer->rt_support.odp.ct_orig_tuple = check_ct_orig_tuple(backer);
backer->rt_support.odp.ct_orig_tuple6 = check_ct_orig_tuple6(backer);
backer->rt_support.odp.nd_ext = check_nd_extensions(backer);
+ backer->rt_support.odp.tun_eth_type = check_tun_eth_type(backer);
}
/* TC does not support offloading the explicit drop action. As such we need to
@@ -5924,6 +5994,7 @@ get_datapath_cap(const char *datapath_type, struct smap *cap)
smap_add(cap, "ct_orig_tuple", s->odp.ct_orig_tuple ? "true" : "false");
smap_add(cap, "ct_orig_tuple6", s->odp.ct_orig_tuple6 ? "true" : "false");
smap_add(cap, "nd_ext", s->odp.nd_ext ? "true" : "false");
+ smap_add(cap, "tun_eth_type", s->odp.tun_eth_type ? "true" : "false");
/* DPIF_SUPPORT_FIELDS */
smap_add(cap, "masked_set_action",
@@ -381,6 +381,7 @@ tnl_wc_init(struct flow *flow, struct flow_wildcards *wc)
* wildcarded, not to unwildcard them here. */
wc->masks.tunnel.tp_src = 0;
wc->masks.tunnel.tp_dst = 0;
+ wc->masks.tunnel.eth_type = 0;
if (is_ip_any(flow)
&& IP_ECN_is_ce(flow->tunnel.ip_tos)) {
@@ -719,8 +719,8 @@ 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),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),tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(+df-csum+key)),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)
-recirc_id(0x1),tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(+df-csum+key)),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
+recirc_id(0),tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,eth_type=0x800,flags(+df-csum+key)),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)
+recirc_id(0x1),tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,eth_type=0x800,flags(+df-csum+key)),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
])
AT_CHECK([
@@ -773,9 +773,9 @@ 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),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)
-recirc_id(0),tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(+df-csum+key)),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)
-recirc_id(0),tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(+df-csum+key)),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)
-recirc_id(0x2),tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(+df-csum+key)),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
+recirc_id(0),tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,eth_type=0x800,flags(+df-csum+key)),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)
+recirc_id(0),tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,eth_type=0x800,flags(+df-csum+key)),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)
+recirc_id(0x2),tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,eth_type=0x800,flags(+df-csum+key)),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
])
AT_CHECK([
@@ -324,7 +324,7 @@ 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: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),tunnel(src=30.0.0.1,dst=30.0.0.3,flags(+df-csum)),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
+recirc_id(0),tunnel(src=30.0.0.1,dst=30.0.0.3,eth_type=0x800,flags(+df-csum)),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
])
# Clear up megaflow cache
@@ -342,7 +342,7 @@ 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: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),tunnel(src=20.0.0.1,dst=20.0.0.2,flags(+df-csum)),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
+recirc_id(0),tunnel(src=20.0.0.1,dst=20.0.0.2,eth_type=0x800,flags(+df-csum)),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
])
# Clear up megaflow cache
@@ -360,7 +360,7 @@ 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: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),tunnel(src=10.0.0.2,dst=10.0.0.1,flags(+df-csum)),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
+recirc_id(0),tunnel(src=10.0.0.2,dst=10.0.0.1,eth_type=0x800,flags(+df-csum)),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
])
# Clear up megaflow cache
@@ -378,8 +378,8 @@ 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: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),tunnel(src=10.0.0.2,dst=10.0.0.1,flags(+df-csum)),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)
-recirc_id(0),tunnel(src=30.0.0.1,dst=30.0.0.3,flags(+df-csum)),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
+recirc_id(0),tunnel(src=10.0.0.2,dst=10.0.0.1,eth_type=0x800,flags(+df-csum)),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)
+recirc_id(0),tunnel(src=30.0.0.1,dst=30.0.0.3,eth_type=0x800,flags(+df-csum)),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
])
# Clear up megaflow cache
@@ -397,8 +397,8 @@ 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,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),tunnel(src=10.0.0.2,dst=10.0.0.1,flags(+df-csum)),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
-recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,flags(+df-csum)),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)
+recirc_id(0),tunnel(src=10.0.0.2,dst=10.0.0.1,eth_type=0x800,flags(+df-csum)),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
+recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,eth_type=0x800,flags(+df-csum)),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
@@ -416,7 +416,7 @@ 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: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),tunnel(src=20.0.0.3,dst=20.0.0.2,flags(+df-csum)),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
+recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,eth_type=0x800,flags(+df-csum)),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
])
### Check the received packets
@@ -502,7 +502,7 @@ 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,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),tunnel(src=20.0.0.3,dst=20.0.0.2,flags(+df-csum)),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
+recirc_id(0),tunnel(src=20.0.0.3,dst=20.0.0.2,eth_type=0x800,flags(+df-csum)),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
])
OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
@@ -1015,8 +1015,8 @@ 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(p0),packet_type(ns=0,id=0),eth(src=aa:bb:cc:00:00:02,dst=aa:bb:cc:00:00:01),eth_type(0x0800),ipv4(dst=20.0.0.1,proto=47,frag=no), packets:3, bytes:378, used:0.0s, actions:tnl_pop(gre_sys)
-recirc_id(0),tunnel(src=20.0.0.2,dst=20.0.0.1,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x8847),eth_type(0x8847),mpls(label=999/0x0,tc=0/0,ttl=64/0x0,bos=1/1), packets:3, bytes:264, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00),pop_mpls(eth_type=0x800),recirc(0x1)
-recirc_id(0x1),tunnel(src=20.0.0.2,dst=20.0.0.1,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=1,ttl=64,frag=no), packets:3, bytes:294, used:0.0s, actions:set(ipv4(ttl=63)),int-br
+recirc_id(0),tunnel(src=20.0.0.2,dst=20.0.0.1,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=1,id=0x8847),eth_type(0x8847),mpls(label=999/0x0,tc=0/0,ttl=64/0x0,bos=1/1), packets:3, bytes:264, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00),pop_mpls(eth_type=0x800),recirc(0x1)
+recirc_id(0x1),tunnel(src=20.0.0.2,dst=20.0.0.1,eth_type=0x800,flags(+df-csum)),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=1,ttl=64,frag=no), packets:3, bytes:294, used:0.0s, actions:set(ipv4(ttl=63)),int-br
])
ovs-appctl time/warp 1000
@@ -571,7 +571,7 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 5'], [0], [dnl
port 5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=?
])
AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)'], [0], [dnl
-recirc_id(0),tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,controller(reason=1,dont_send=0,continuation=0,recirc_id=3,rule_cookie=0,controller_id=0,max_len=65535))
+recirc_id(0),tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),eth_type=0x86dd,flags(-df-csum+key)),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,controller(reason=1,dont_send=0,continuation=0,recirc_id=3,rule_cookie=0,controller_id=0,max_len=65535))
])
dnl Receive VXLAN with different MAC and verify that the neigh cache gets updated
@@ -684,7 +684,7 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 5'], [0], [dnl
port 5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=?
])
AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)' | sed -e 's/recirc_id=[[0-9]]*/recirc_id=<cleared>/g'], [0], [dnl
-recirc_id(0),tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(+df-csum+key)),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,controller(reason=1,dont_send=0,continuation=0,recirc_id=<cleared>,rule_cookie=0,controller_id=0,max_len=65535))
+recirc_id(0),tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),eth_type=0x800,flags(+df-csum+key)),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,controller(reason=1,dont_send=0,continuation=0,recirc_id=<cleared>,rule_cookie=0,controller_id=0,max_len=65535))
])
dnl Receive VXLAN with different MAC and verify that the neigh cache gets updated
@@ -1354,3 +1354,47 @@ AT_CHECK_UNQUOTED([tail -1 stdout], [0],
OVS_VSWITCHD_STOP
AT_CLEANUP
+
+AT_SETUP([tunnel - decap and re-encap with outer IP version conversion])
+OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])
+AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0])
+AT_CHECK([ovs-vsctl add-port int-br t1 -- set Interface t1 type=vxlan \
+ options:remote_ip=1.1.1.1 options:key=122 \
+ -- add-port int-br t2 -- set Interface t2 type=geneve \
+ options:remote_ip=2001:cafe::1 options:key=123 \
+ ], [0])
+
+dnl Setup dummy interface IP addresses.
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.1.2/24], [0], [OK
+])
+AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::2/24], [0], [OK
+])
+dnl Checking that a local routes for added IPs were successfully installed.
+AT_CHECK([ovs-appctl ovs/route/show | grep Cached | sort], [0], [dnl
+Cached: 1.1.1.0/24 dev br0 SRC 1.1.1.2 local
+Cached: 2001:ca00::/24 dev br0 SRC 2001:cafe::2 local
+])
+
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+AT_CHECK([ovs-appctl revalidator/wait])
+
+dnl Add entries
+AT_CHECK([ovs-appctl tnl/neigh/set br0 1.1.1.1 aa:bb:cc:00:00:01], [0], [OK
+])
+AT_CHECK([ovs-appctl tnl/neigh/set br0 2001:cafe::1 aa:bb:cc:00:00:01], [0], [OK
+])
+
+AT_CHECK([ovs-ofctl add-flow int-br 'in_port=t1,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_id=0x7a,actions=set_field:2001:cafe::2->tun_ipv6_src,set_field:2001:cafe::1->tun_ipv6_dst,set_field:0x7b->tun_id,set_field:0.0.0.0->tun_src,set_field:0.0.0.0->tun_dst,t2'])
+AT_CHECK([ovs-ofctl add-flow int-br 'in_port=t2,tun_ipv6_src=2001:cafe::1,tun_ipv6_dst=2001:cafe::2,tun_id=0x7b,actions=set_field:1.1.1.2->tun_src,set_field:1.1.1.1->tun_dst,set_field:0x7a->tun_id,t1'])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e000140004011369a010101010101010212b512b5003a05e30800000000007a00fe71d883724fbeb6f4e1494a08004500001c000140004001fedd1e0000011e0000020000ffff00000000'])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6486dd60000000003a11402001cafe0000000000000000000000012001cafe00000000000000000000000217c117c1003acb740000655800007b00fe71d883724fbeb6f4e1494a08004500001c000140004001fedd1e0000011e0000020000ffff00000000'])
+
+AT_CHECK([ovs-appctl dpctl/dump-flows | strip_ufid | strip_used | strip_stats | grep tunnel | sort], [0],
+ [recirc_id(0),tunnel(tun_id=0x7a,src=1.1.1.1,dst=1.1.1.2,eth_type=0x800,flags(+df+csum+key)),in_port(4789),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:0, bytes:0, used:never, actions:tnl_push(tnl_port(6081),header(size=70,type=5,eth(dst=00:1b:21:3c:ab:64,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::2,dst=2001:cafe::1,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100)),1
+recirc_id(0),tunnel(tun_id=0x7b,ipv6_src=2001:cafe::1,ipv6_dst=2001:cafe::2,geneve(),eth_type=0x86dd,flags(-df+csum+key)),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:0, bytes:0, used:never, actions:tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=00:1b:21:3c:ab:64,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.1.2,dst=1.1.1.1,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7a)),out_port(100)),1
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP