@@ -47,6 +47,8 @@ dp_packet_gso_seg_new(const struct dp_packet *p, size_t hdr_len,
seg->l2_5_ofs = p->l2_5_ofs;
seg->l3_ofs = p->l3_ofs;
seg->l4_ofs = p->l4_ofs;
+ seg->inner_l3_ofs = p->inner_l3_ofs;
+ seg->inner_l4_ofs = p->inner_l4_ofs;
/* The protocol headers remain the same, so preserve hash and mark. */
*dp_packet_rss_ptr(seg) = *dp_packet_rss_ptr(p);
@@ -71,7 +73,12 @@ dp_packet_gso_nr_segs(struct dp_packet *p)
const char *data_tail;
const char *data_pos;
- data_pos = dp_packet_get_tcp_payload(p);
+ if (dp_packet_hwol_is_tunnel_vxlan(p) ||
+ dp_packet_hwol_is_tunnel_geneve(p)) {
+ data_pos = dp_packet_get_inner_tcp_payload(p);
+ } else {
+ data_pos = dp_packet_get_tcp_payload(p);
+ }
data_tail = (char *) dp_packet_tail(p) - dp_packet_l2_pad_size(p);
return DIV_ROUND_UP(data_tail - data_pos, segsz);
@@ -89,14 +96,16 @@ dp_packet_gso(struct dp_packet *p, struct dp_packet_batch **batches)
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
struct dp_packet_batch *curr_batch = *batches;
struct tcp_header *tcp_hdr;
- struct ip_header *ip_hdr;
+ uint16_t inner_ip_id = 0;
+ uint16_t outer_ip_id = 0;
struct dp_packet *seg;
uint16_t tcp_offset;
uint16_t tso_segsz;
uint32_t tcp_seq;
- uint16_t ip_id;
+ bool outer_ipv4;
int hdr_len;
int seg_len;
+ bool tnl;
tso_segsz = dp_packet_get_tso_segsz(p);
if (!tso_segsz) {
@@ -105,20 +114,37 @@ dp_packet_gso(struct dp_packet *p, struct dp_packet_batch **batches)
return false;
}
- tcp_hdr = dp_packet_l4(p);
+ if (dp_packet_hwol_is_tunnel_vxlan(p) ||
+ dp_packet_hwol_is_tunnel_geneve(p)) {
+ outer_ipv4 = dp_packet_hwol_is_outer_ipv4(p);
+ tcp_hdr = dp_packet_inner_l4(p);
+ tnl = true;
+
+ if (outer_ipv4) {
+ outer_ip_id = ntohs(((struct ip_header *) dp_packet_l3(p))->ip_id);
+ }
+ if (dp_packet_hwol_is_ipv4(p)) {
+ struct ip_header *ip_hdr = dp_packet_inner_l3(p);
+ inner_ip_id = ntohs(ip_hdr->ip_id);
+ }
+ } else {
+ outer_ipv4 = dp_packet_hwol_is_ipv4(p);
+ tcp_hdr = dp_packet_l4(p);
+ tnl = false;
+
+ if (outer_ipv4) {
+ struct ip_header *ip_hdr = dp_packet_l3(p);
+ outer_ip_id = ntohs(ip_hdr->ip_id);
+ }
+ }
+
tcp_offset = TCP_OFFSET(tcp_hdr->tcp_ctl);
tcp_seq = ntohl(get_16aligned_be32(&tcp_hdr->tcp_seq));
- hdr_len = ((char *) dp_packet_l4(p) - (char *) dp_packet_eth(p))
+ hdr_len = ((char *) tcp_hdr - (char *) dp_packet_eth(p))
+ tcp_offset * 4;
- ip_id = 0;
- if (dp_packet_hwol_is_ipv4(p)) {
- ip_hdr = dp_packet_l3(p);
- ip_id = ntohs(ip_hdr->ip_id);
- }
-
const char *data_tail = (char *) dp_packet_tail(p)
- dp_packet_l2_pad_size(p);
- const char *data_pos = dp_packet_get_tcp_payload(p);
+ const char *data_pos = (char *) tcp_hdr + tcp_offset * 4;
int n_segs = dp_packet_gso_nr_segs(p);
for (int i = 0; i < n_segs; i++) {
@@ -130,14 +156,36 @@ dp_packet_gso(struct dp_packet *p, struct dp_packet_batch **batches)
seg = dp_packet_gso_seg_new(p, hdr_len, data_pos, seg_len);
data_pos += seg_len;
+ if (tnl) {
+ /* Update tunnel UDP header length. */
+ struct udp_header *tnl_hdr;
+
+ tnl_hdr = dp_packet_l4(seg);
+ tnl_hdr->udp_len = htons(dp_packet_l4_size(seg));
+
+ /* Update tunnel inner L3 header. */
+ if (dp_packet_hwol_is_ipv4(seg)) {
+ struct ip_header *ip_hdr = dp_packet_inner_l3(seg);
+ ip_hdr->ip_tot_len = htons(dp_packet_inner_l3_size(seg));
+ ip_hdr->ip_id = htons(inner_ip_id);
+ ip_hdr->ip_csum = 0;
+ inner_ip_id++;
+ } else {
+ struct ovs_16aligned_ip6_hdr *ip6_hdr;
+
+ ip6_hdr = dp_packet_inner_l3(seg);
+ ip6_hdr->ip6_ctlun.ip6_un1.ip6_un1_plen
+ = htons(dp_packet_inner_l3_size(seg) - sizeof *ip6_hdr);
+ }
+ }
+
/* Update L3 header. */
- if (dp_packet_hwol_is_ipv4(seg)) {
- ip_hdr = dp_packet_l3(seg);
- ip_hdr->ip_tot_len = htons(sizeof *ip_hdr +
- dp_packet_l4_size(seg));
- ip_hdr->ip_id = htons(ip_id);
+ if (outer_ipv4) {
+ struct ip_header *ip_hdr = dp_packet_l3(seg);
+ ip_hdr->ip_tot_len = htons(dp_packet_l3_size(seg));
+ ip_hdr->ip_id = htons(outer_ip_id);
ip_hdr->ip_csum = 0;
- ip_id++;
+ outer_ip_id++;
} else {
struct ovs_16aligned_ip6_hdr *ip6_hdr = dp_packet_l3(seg);
@@ -146,7 +194,11 @@ dp_packet_gso(struct dp_packet *p, struct dp_packet_batch **batches)
}
/* Update L4 header. */
- tcp_hdr = dp_packet_l4(seg);
+ if (tnl) {
+ tcp_hdr = dp_packet_inner_l4(seg);
+ } else {
+ tcp_hdr = dp_packet_l4(seg);
+ }
put_16aligned_be32(&tcp_hdr->tcp_seq, htonl(tcp_seq));
tcp_seq += seg_len;
if (OVS_LIKELY(i < (n_segs - 1))) {
@@ -529,6 +529,16 @@ dp_packet_inner_l3(const struct dp_packet *b)
: NULL;
}
+static inline size_t
+dp_packet_inner_l3_size(const struct dp_packet *b)
+{
+ return OVS_LIKELY(b->inner_l3_ofs != UINT16_MAX)
+ ? (const char *) dp_packet_tail(b)
+ - (const char *) dp_packet_inner_l3(b)
+ - dp_packet_l2_pad_size(b)
+ : 0;
+}
+
static inline void *
dp_packet_inner_l4(const struct dp_packet *b)
{
@@ -563,6 +573,22 @@ dp_packet_get_tcp_payload(const struct dp_packet *b)
return NULL;
}
+static inline const void *
+dp_packet_get_inner_tcp_payload(const struct dp_packet *b)
+{
+ size_t l4_size = dp_packet_inner_l4_size(b);
+
+ if (OVS_LIKELY(l4_size >= TCP_HEADER_LEN)) {
+ struct tcp_header *tcp = dp_packet_inner_l4(b);
+ int tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4;
+
+ if (OVS_LIKELY(tcp_len >= TCP_HEADER_LEN && tcp_len <= l4_size)) {
+ return (const char *) tcp + tcp_len;
+ }
+ }
+ return NULL;
+}
+
static inline uint32_t
dp_packet_get_tcp_payload_length(const struct dp_packet *pkt)
{
@@ -1320,6 +1346,14 @@ dp_packet_hwol_reset_tcp_seg(struct dp_packet *p)
ol_flags |= DP_PACKET_OL_TX_IP_CKSUM;
}
+ if (ol_flags & (DP_PACKET_OL_TX_TUNNEL_VXLAN |
+ DP_PACKET_OL_TX_TUNNEL_GENEVE)) {
+ if (ol_flags & DP_PACKET_OL_TX_OUTER_IPV4) {
+ ol_flags |= DP_PACKET_OL_TX_OUTER_IP_CKSUM;
+ }
+ ol_flags |= DP_PACKET_OL_TX_OUTER_UDP_CKSUM;
+ }
+
*dp_packet_ol_flags_ptr(p) = ol_flags;
}
@@ -69,8 +69,6 @@ COVERAGE_DEFINE(netdev_received);
COVERAGE_DEFINE(netdev_sent);
COVERAGE_DEFINE(netdev_add_router);
COVERAGE_DEFINE(netdev_get_stats);
-COVERAGE_DEFINE(netdev_vxlan_tso_drops);
-COVERAGE_DEFINE(netdev_geneve_tso_drops);
COVERAGE_DEFINE(netdev_push_header_drops);
COVERAGE_DEFINE(netdev_soft_seg_good);
COVERAGE_DEFINE(netdev_soft_seg_drops);
@@ -910,28 +908,30 @@ netdev_send(struct netdev *netdev, int qid, struct dp_packet_batch *batch,
struct dp_packet *packet;
int error;
- if (userspace_tso_enabled() &&
- !(netdev_flags & NETDEV_TX_OFFLOAD_TCP_TSO)) {
- DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
- if (dp_packet_hwol_is_tso(packet)) {
- if (dp_packet_hwol_is_tunnel_vxlan(packet)
- && !(netdev_flags & NETDEV_TX_VXLAN_TNL_TSO)) {
- VLOG_WARN_RL(&rl, "%s: No VXLAN TSO support",
- netdev_get_name(netdev));
- COVERAGE_INC(netdev_vxlan_tso_drops);
- dp_packet_delete_batch(batch, true);
- return false;
+ if (userspace_tso_enabled()) {
+ if (!(netdev_flags & NETDEV_TX_OFFLOAD_TCP_TSO)) {
+ DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
+ if (dp_packet_hwol_is_tso(packet)) {
+ return netdev_send_tso(netdev, qid, batch, concurrent_txq);
}
-
- if (dp_packet_hwol_is_tunnel_geneve(packet)
- && !(netdev_flags & NETDEV_TX_GENEVE_TNL_TSO)) {
- VLOG_WARN_RL(&rl, "%s: No GENEVE TSO support",
- netdev_get_name(netdev));
- COVERAGE_INC(netdev_geneve_tso_drops);
- dp_packet_delete_batch(batch, true);
- return false;
+ }
+ } else if (!(netdev_flags & (NETDEV_TX_VXLAN_TNL_TSO |
+ NETDEV_TX_GENEVE_TNL_TSO))) {
+ DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
+ if (dp_packet_hwol_is_tso(packet) &&
+ (dp_packet_hwol_is_tunnel_vxlan(packet) ||
+ dp_packet_hwol_is_tunnel_geneve(packet))) {
+ return netdev_send_tso(netdev, qid, batch, concurrent_txq);
+ }
+ }
+ } else if (!(netdev_flags & NETDEV_TX_OFFLOAD_OUTER_UDP_CKSUM)) {
+ DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
+ if (dp_packet_hwol_is_tso(packet) &&
+ (dp_packet_hwol_is_tunnel_vxlan(packet) ||
+ dp_packet_hwol_is_tunnel_geneve(packet)) &&
+ dp_packet_hwol_is_outer_udp_cksum(packet)) {
+ return netdev_send_tso(netdev, qid, batch, concurrent_txq);
}
- return netdev_send_tso(netdev, qid, batch, concurrent_txq);
}
}
}
@@ -884,6 +884,208 @@ AT_CHECK_UNQUOTED([ovs-pcap p2.pcap], [0], [dnl
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([userspace offload - tunnel tso fallback])
+OVS_VSWITCHD_START([set Open_vSwitch . other_config:userspace-tso-enable=true \
+ -- add-br br1 -- set bridge br1 datapath-type=dummy other-config:hwaddr=aa:55:aa:55:00:03 \
+ -- add-port br1 p1 -- set Interface p1 type=dummy ofport_request=1])
+AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy \
+ -- add-port int-br t1 -- set Interface t1 type=vxlan \
+ options:remote_ip=1.1.2.92 options:key=123 \
+ options:csum=true ofport_request=2 \
+ -- add-port int-br t2 -- set Interface t2 type=geneve \
+ options:remote_ip=1.1.2.92 options:key=123 \
+ options:csum=true ofport_request=3 \
+ -- add-port int-br t3 -- set Interface t3 type=vxlan \
+ options:remote_ip=2001:cafe::93 options:key=123 \
+ options:csum=true ofport_request=4 \
+ -- add-port int-br t4 -- set Interface t4 type=geneve \
+ options:remote_ip=2001:cafe::93 options:key=123 \
+ options:csum=true ofport_request=5], [0])
+
+flow_s="eth(src=8a:bf:7e:2f:05:84,dst=0a:8f:39:4f:e0:73),eth_type(0x0800), \
+ ipv4(src=192.168.123.2,dst=192.168.123.1,proto=6,tos=1,ttl=64,frag=no), \
+ tcp(src=54392,dst=5201),tcp_flags(ack)"
+
+flow_s_v6="eth(src=8a:bf:7e:2f:05:84,dst=0a:8f:39:4f:e0:73),eth_type(0x86dd), \
+ ipv6(src=2001:cafe::88,dst=2001:cafe::92,proto=6), \
+ tcp(src=54392,dst=5201),tcp_flags(ack)"
+
+dnl Setup dummy interface tunnel connectivity.
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br1 1.1.2.88/24], [0], [OK
+])
+AT_CHECK([ovs-appctl netdev-dummy/ip6addr br1 2001:cafe::88/24], [0], [OK
+])
+AT_CHECK([ovs-appctl tnl/neigh/set br1 1.1.2.92 aa:bb:cc:00:00:01], [0], [OK
+])
+AT_CHECK([ovs-appctl tnl/neigh/set br1 2001:cafe::93 aa:bb:cc:00:00:06], [0], [OK
+])
+AT_CHECK([ovs-appctl tnl/egress_port_range 57363 57363], [0], [OK
+])
+AT_CHECK([ovs-ofctl add-flow br1 action=normal])
+AT_CHECK([ovs-ofctl add-flow int-br action=normal])
+
+dnl Configure the TX interface to segment.
+AT_CHECK([ovs-vsctl set Interface p1 options:tx_pcap=p1.pcap -- \
+ set Interface int-br options:ol_ip_csum=true -- \
+ set Interface int-br options:ol_ip_csum_set_good=false -- \
+ set Interface int-br options:ol_tso_segsz=500])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive int-br "in_port(2),${flow_s}" --len 2054])
+AT_CHECK([ovs-appctl netdev-dummy/receive int-br "in_port(2),${flow_s_v6}" --len 2074])
+
+dnl Check that first we have the following packets:
+dnl - IPv4 VXLAN tunnel with IPv4 payload
+dnl - IPv4 VXLAN tunnel with IPv6 payload
+dnl - IPv6 VXLAN tunnel with IPv4 payload
+dnl - IPv6 VXLAN tunnel with IPv6 payload
+dnl - IPv4 Geneve tunnel with IPv4 payload
+dnl - IPv4 Geneve tunnel with IPv6 payload
+dnl - IPv6 Geneve tunnel with IPv4 payload
+dnl - IPv6 Geneve tunnel with IPv6 payload
+dnl - IPv6 Geneve tunnel with IPv4 payload
+dnl - IPv6 Geneve tunnel with IPv6 payload
+dnl These are sorted because OVS may send the payloads to the tunnels in any order.
+zero400=$(printf '0%.0s' $(seq 800))
+zero200=$(printf '0%.0s' $(seq 400))
+zero100=$(printf '0%.0s' $(seq 200))
+zero50=$(printf '0%.0s' $(seq 100))
+zero25=$(printf '0%.0s' $(seq 50))
+AT_CHECK_UNQUOTED([ovs-pcap p1.pcap | sort], [0], [dnl
+[aabbcc000001aa55aa55000308004500013600044000401132fe010102580101025ce01312b50122618e0800000000007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000000dc06002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000007080000000050100000e8210000${zero200}]
+[aabbcc000001aa55aa55000308004500013600044000401132fe010102580101025ce01317c10122ff290000655800007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000000dc06002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000007080000000050100000e8210000${zero200}]
+[aabbcc000001aa55aa5500030800450002300000400040113208010102580101025ce01312b5021c5f9a0800000000007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000001d606002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000000000000000050100000ee2f0000${zero50}${zero400}]
+[aabbcc000001aa55aa5500030800450002300000400040113208010102580101025ce01317c1021cfd350000655800007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000001d606002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000000000000000050100000ee2f0000${zero50}${zero400}]
+[aabbcc000001aa55aa5500030800450002300001400040113207010102580101025ce01312b5021c5f9a0800000000007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000001d606002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000001c20000000050100000ec6d0000${zero50}${zero400}]
+[aabbcc000001aa55aa5500030800450002300001400040113207010102580101025ce01317c1021cfd350000655800007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000001d606002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000001c20000000050100000ec6d0000${zero50}${zero400}]
+[aabbcc000001aa55aa5500030800450002300002400040113206010102580101025ce01312b5021c5f9a0800000000007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000001d606002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000003840000000050100000eaab0000${zero50}${zero400}]
+[aabbcc000001aa55aa5500030800450002300002400040113206010102580101025ce01317c1021cfd350000655800007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000001d606002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000003840000000050100000eaab0000${zero50}${zero400}]
+[aabbcc000001aa55aa5500030800450002300003400040113205010102580101025ce01312b5021c5f9a0800000000007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000001d606002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000005460000000050100000e8e90000${zero50}${zero400}]
+[aabbcc000001aa55aa5500030800450002300003400040113205010102580101025ce01317c1021cfd350000655800007b00]dnl
+[0a8f394fe0738abf7e2f058486dd6000000001d606002001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000092d4781451000005460000000050100000e8e90000${zero50}${zero400}]
+[aabbcc000001aa55aa5500030800450101220004400040113311010102580101025ce01312b5010ebec50800000000007b00]dnl
+[0a8f394fe0738abf7e2f05840800450100f000040000400602afc0a87b02c0a87b01d4781451000007080000000050100000]dnl
+[47e60000${zero200}]
+[aabbcc000001aa55aa5500030800450101220004400040113311010102580101025ce01317c1010e5c610000655800007b00]dnl
+[0a8f394fe0738abf7e2f05840800450100f000040000400602afc0a87b02c0a87b01d4781451000007080000000050100000]dnl
+[47e60000${zero200}]
+[aabbcc000001aa55aa55000308004501021c000040004011321b010102580101025ce01312b50208bdcb0800000000007b00]dnl
+[0a8f394fe0738abf7e2f05840800450101ea00000000400601b9c0a87b02c0a87b01d4781451000000000000000050100000]dnl
+[4df40000${zero50}${zero400}]
+[aabbcc000001aa55aa55000308004501021c000040004011321b010102580101025ce01317c102085b670000655800007b00]dnl
+[0a8f394fe0738abf7e2f05840800450101ea00000000400601b9c0a87b02c0a87b01d4781451000000000000000050100000]dnl
+[4df40000${zero50}${zero400}]
+[aabbcc000001aa55aa55000308004501021c000140004011321a010102580101025ce01312b50208bdcb0800000000007b00]dnl
+[0a8f394fe0738abf7e2f05840800450101ea00010000400601b8c0a87b02c0a87b01d4781451000001c20000000050100000]dnl
+[4c320000${zero50}${zero400}]
+[aabbcc000001aa55aa55000308004501021c000140004011321a010102580101025ce01317c102085b670000655800007b00]dnl
+[0a8f394fe0738abf7e2f05840800450101ea00010000400601b8c0a87b02c0a87b01d4781451000001c20000000050100000]dnl
+[4c320000${zero50}${zero400}]
+[aabbcc000001aa55aa55000308004501021c0002400040113219010102580101025ce01312b50208bdcb0800000000007b00]dnl
+[0a8f394fe0738abf7e2f05840800450101ea00020000400601b7c0a87b02c0a87b01d4781451000003840000000050100000]dnl
+[4a700000${zero50}${zero400}]
+[aabbcc000001aa55aa55000308004501021c0002400040113219010102580101025ce01317c102085b670000655800007b00]dnl
+[0a8f394fe0738abf7e2f05840800450101ea00020000400601b7c0a87b02c0a87b01d4781451000003840000000050100000]dnl
+[4a700000${zero50}${zero400}]
+[aabbcc000001aa55aa55000308004501021c0003400040113218010102580101025ce01312b50208bdcb0800000000007b00]dnl
+[0a8f394fe0738abf7e2f05840800450101ea00030000400601b6c0a87b02c0a87b01d4781451000005460000000050100000]dnl
+[48ae0000${zero50}${zero400}]
+[aabbcc000001aa55aa55000308004501021c0003400040113218010102580101025ce01317c102085b670000655800007b00]dnl
+[0a8f394fe0738abf7e2f05840800450101ea00030000400601b6c0a87b02c0a87b01d4781451000005460000000050100000]dnl
+[48ae0000${zero50}${zero400}]
+[aabbcc000006aa55aa55000386dd60000000017211402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b5017290890800000000007b000a8f394fe0738abf7e2f058486dd60000000012c06002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d4781451000006b80000000050100000e82100000000000000]dnl
+[${zero25}${zero50}${zero200}]
+[aabbcc000006aa55aa55000386dd60000000017211402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c101722e250000655800007b000a8f394fe0738abf7e2f058486dd60000000012c06002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d4781451000006b80000000050100000e82100000000000000]dnl
+[${zero25}${zero50}${zero200}]
+[aabbcc000006aa55aa55000386dd60000000020811402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b502088f5d0800000000007b000a8f394fe0738abf7e2f058486dd6000000001c206002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d4781451000000000000000050100000ee4300000000000000]dnl
+[${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd60000000020811402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b502088f5d0800000000007b000a8f394fe0738abf7e2f058486dd6000000001c206002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d4781451000001ae0000000050100000ec9500000000000000]dnl
+[${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd60000000020811402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b502088f5d0800000000007b000a8f394fe0738abf7e2f058486dd6000000001c206002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d47814510000035c0000000050100000eae700000000000000]dnl
+[${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd60000000020811402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b502088f5d0800000000007b000a8f394fe0738abf7e2f058486dd6000000001c206002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d47814510000050a0000000050100000e93900000000000000]dnl
+[${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd60000000020811402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c102082cf90000655800007b000a8f394fe0738abf7e2f058486dd6000000001c206002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d4781451000000000000000050100000ee4300000000000000]dnl
+[${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd60000000020811402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c102082cf90000655800007b000a8f394fe0738abf7e2f058486dd6000000001c206002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d4781451000001ae0000000050100000ec9500000000000000]dnl
+[${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd60000000020811402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c102082cf90000655800007b000a8f394fe0738abf7e2f058486dd6000000001c206002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d47814510000035c0000000050100000eae700000000000000]dnl
+[${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd60000000020811402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c102082cf90000655800007b000a8f394fe0738abf7e2f058486dd6000000001c206002001cafe00000000]dnl
+[00000000000000882001cafe000000000000000000000092d47814510000050a0000000050100000e93900000000000000]dnl
+[${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd60100000015e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b5015eee100800000000007b000a8f394fe0738abf7e2f0584080045010140000400004006025fc0a87b02]dnl
+[c0a87b01d4781451000006b8000000005010000047e600000000000000${zero25}${zero50}${zero200}]
+[aabbcc000006aa55aa55000386dd60100000015e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c1015e8bac0000655800007b000a8f394fe0738abf7e2f0584080045010140000400004006025fc0a87b02]dnl
+[c0a87b01d4781451000006b8000000005010000047e600000000000000${zero25}${zero50}${zero200}]
+[aabbcc000006aa55aa55000386dd6010000001f411402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b501f4ed7a0800000000007b000a8f394fe0738abf7e2f05840800450101d600000000400601cdc0a87b02]dnl
+[c0a87b01d47814510000000000000000501000004e0800000000000000${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd6010000001f411402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b501f4ed7a0800000000007b000a8f394fe0738abf7e2f05840800450101d600010000400601ccc0a87b02]dnl
+[c0a87b01d4781451000001ae00000000501000004c5a00000000000000${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd6010000001f411402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b501f4ed7a0800000000007b000a8f394fe0738abf7e2f05840800450101d600020000400601cbc0a87b02]dnl
+[c0a87b01d47814510000035c00000000501000004aac00000000000000${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd6010000001f411402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01312b501f4ed7a0800000000007b000a8f394fe0738abf7e2f05840800450101d600030000400601cac0a87b02]dnl
+[c0a87b01d47814510000050a000000005010000048fe00000000000000${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd6010000001f411402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c101f48b160000655800007b000a8f394fe0738abf7e2f05840800450101d600000000400601cdc0a87b02]dnl
+[c0a87b01d47814510000000000000000501000004e0800000000000000${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd6010000001f411402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c101f48b160000655800007b000a8f394fe0738abf7e2f05840800450101d600010000400601ccc0a87b02]dnl
+[c0a87b01d4781451000001ae00000000501000004c5a00000000000000${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd6010000001f411402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c101f48b160000655800007b000a8f394fe0738abf7e2f05840800450101d600020000400601cbc0a87b02]dnl
+[c0a87b01d47814510000035c00000000501000004aac00000000000000${zero25}${zero400}]
+[aabbcc000006aa55aa55000386dd6010000001f411402001cafe0000000000000000000000882001cafe0000000000000000]dnl
+[00000093e01317c101f48b160000655800007b000a8f394fe0738abf7e2f05840800450101d600030000400601cac0a87b02]dnl
+[c0a87b01d47814510000050a000000005010000048fe00000000000000${zero25}${zero400}]
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([dpif-netdev - revalidators handle dp modification fail correctly])
OVS_VSWITCHD_START(
[add-port br0 p1 \
@@ -351,6 +351,96 @@ OVS_WAIT_UNTIL([diff -q payload.bin udp_data])
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([datapath - tcp over vxlan tunnel with software fallback])
+AT_SKIP_IF([test $HAVE_NC = no])
+AT_SKIP_IF([test $HAVE_TCPDUMP = no])
+OVS_CHECK_VXLAN()
+
+dnl This test is only valid with tso. If the kernel segments the packets, the
+dnl packet lengths in the final test will be different.
+m4_ifndef([CHECK_SYSTEM_TSO], [AT_SKIP_IF(:)])
+
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-underlay])
+
+AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
+AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"])
+
+ADD_NAMESPACES(at_ns0)
+
+dnl Set up underlay link from host into the namespace using veth pair.
+ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24")
+AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"])
+AT_CHECK([ip link set dev br-underlay up])
+
+dnl Test the case where only one side has all checksum and tso offload disabled.
+AT_CHECK([ethtool -K ovs-p0 tso off], [0], [ignore], [ignore])
+AT_CHECK([ethtool -K ovs-p0 sg off], [0], [ignore], [ignore])
+
+dnl Reinitialize.
+AT_CHECK([ovs-vsctl del-port ovs-p0])
+AT_CHECK([ovs-vsctl add-port br-underlay ovs-p0])
+
+dnl Set up tunnel endpoints on OVS outside the namespace and with a native
+dnl linux device inside the namespace.
+ADD_OVS_TUNNEL([vxlan], [br0], [at_vxlan0], [172.31.1.1], [10.1.1.100/24])
+ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], [10.1.1.1/24],
+ [id 0 dstport 4789])
+
+dnl First, check the underlay.
+NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 172.31.1.100 | FORMAT_PING], [0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+dnl Check that the tunnel is up.
+NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -W 2 10.1.1.100 | FORMAT_PING], [0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+dnl Start tcpdump to capture the encapsulated packets.
+OVS_DAEMONIZE([tcpdump -i ovs-p0 -w p0.pcap], [tcpdump.pid])
+
+dnl Wait until the pcap is written, which happens after the interface
+dnl is opened by tcpdump.
+OVS_WAIT_UNTIL([test -e p0.pcap])
+
+dnl Initialize the listener before it is needed.
+NETNS_DAEMONIZE([at_ns0], [nc -l 10.1.1.1 1234 > data2], [nc.pid])
+
+dnl Verify that ncat is ready.
+OVS_WAIT_UNTIL([NS_EXEC([at_ns0], [netstat -ln | grep :1234])])
+
+dnl Large TCP transfer aimed towards ovs-p0, which has TSO disabled.
+AT_CHECK([dd if=/dev/urandom of=payload.bin bs=60000 count=1 2> /dev/null])
+AT_CHECK([nc $NC_EOF_OPT 10.1.1.1 1234 < payload.bin])
+
+dnl Wait until transfer completes before checking.
+OVS_WAIT_WHILE([kill -0 $(cat nc.pid)])
+AT_CHECK([diff -q payload.bin data2], [0])
+
+dnl Stop OVS and tcpdump and verify the results.
+OVS_TRAFFIC_VSWITCHD_STOP
+
+AT_CHECK([kill -15 $(cat tcpdump.pid)])
+
+OVS_WAIT_WHILE([kill -0 $(cat tcpdump.pid)])
+
+ovs-pcap p0.pcap
+
+dnl The exact number of packets sent will vary, but we check that the largest segments have the correct
+dnl lengths and certain other fields.
+AT_CHECK([test $(ovs-pcap p0.pcap | grep -Ec dnl
+"^.{24}0800"dnl Ethernet
+"450005aa....4000..11....ac1f0164ac1f0101"dnl IP(len=1450, DF, UDP, 172.31.1.100->172.31.1.1)
+"....12b505960000"dnl UDP(len=1430, dport=4789)
+"0800000000000000"dnl VXLAN(gpid=0, vni=0)
+".{24}0800"dnl Ethernet
+"45000578....4000..06....0a0101640a010101"dnl IP(len=1400, DF, TCP, 10.1.1.100->10.1.1.1)
+"....04d2............................0000"dnl TCP(dport=1234
+) -ge 20])
+
+AT_CLEANUP
+
AT_SETUP([datapath - ping vlan over vxlan tunnel])
OVS_CHECK_TUNNEL_TSO()
OVS_CHECK_VXLAN()