Message ID | 20240827203122.192761-1-mkp@redhat.com |
---|---|
State | Changes Requested, archived |
Delegated to: | Eelco Chaudron |
Headers | show |
Series | [ovs-dev,v7,1/2] Userspace: Software fallback for UDP encapsulated TCP segmentation. | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | success | apply and check: success |
ovsrobot/github-robot-_Build_and_Test | success | github build: passed |
ovsrobot/intel-ovs-compilation | fail | test: fail |
On 27 Aug 2024, at 22:31, Mike Pattrick wrote: > When sending packets that are flagged as requiring segmentation to an > interface that does not support this feature, send the packet to the TSO > software fallback instead of dropping it. > > Reviewed-by: David Marchand <david.marchand@redhat.com> > Signed-off-by: Mike Pattrick <mkp@redhat.com> I think the code looks good, I did some style cleanups on the unit tests. See the diffs below, if there are no technical blocking comments coming, we could apply these during the commit. Cheers, Eelco > --- > v2: > - Fixed udp tunnel length > - Added test that UDP headers are correct > - Split inner and outer ip_id into different counters > - Set tunnel flags in reset_tcp_seg > > v3: > - Changed logic of netdev_send() to account for NICs that support > tunnel offload but not checksum offload > - Adjusted udp tunnel header length during software tso > > v4: > - Moved a bugfix into its own patch > - Fixed an indentation issue > - Changed the scope of ip_hdr > > v5: > - Change order of tso fallback check > - Added a unit test > v6: > - Removed segsize adjustment patch, adjusted tests to accomidate. > Signed-off-by: Mike Pattrick <mkp@redhat.com> > --- > lib/dp-packet-gso.c | 90 ++++++++++++++++----- > lib/dp-packet.h | 34 ++++++++ > lib/netdev.c | 44 +++++----- > tests/dpif-netdev.at | 173 ++++++++++++++++++++++++++++++++++++++++ > tests/system-traffic.at | 95 ++++++++++++++++++++++ > 5 files changed, 395 insertions(+), 41 deletions(-) > > diff --git a/lib/dp-packet-gso.c b/lib/dp-packet-gso.c > index 847685ad9..04ebb19da 100644 > --- a/lib/dp-packet-gso.c > +++ b/lib/dp-packet-gso.c > @@ -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))) { > diff --git a/lib/dp-packet.h b/lib/dp-packet.h > index a75b1c5cd..af1ff088f 100644 > --- a/lib/dp-packet.h > +++ b/lib/dp-packet.h > @@ -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; > } > > diff --git a/lib/netdev.c b/lib/netdev.c > index f2d921ed6..02beac9d0 100644 > --- a/lib/netdev.c > +++ b/lib/netdev.c > @@ -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); > } > } > } > diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at > index bdc24cc30..2977bfe77 100644 > --- a/tests/dpif-netdev.at > +++ b/tests/dpif-netdev.at > @@ -884,6 +884,179 @@ AT_CHECK_UNQUOTED([ovs-pcap p2.pcap], [0], [dnl > OVS_VSWITCHD_STOP > AT_CLEANUP > > +AT_SETUP([userspace offload - tunnel tso fallback]) This test could use some cleanup to be <80 chars where possible. Here is a diff: diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at index fddad7839..36cea6aa9 100644 --- a/tests/dpif-netdev.at +++ b/tests/dpif-netdev.at @@ -921,8 +921,10 @@ 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]) + -- 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 \ @@ -937,12 +939,12 @@ AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy \ 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), \ +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), \ +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. @@ -952,7 +954,8 @@ 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/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 ]) @@ -965,8 +968,10 @@ AT_CHECK([ovs-vsctl set Interface p1 options:tx_pcap=p1.pcap -- \ 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]) +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 @@ -979,7 +984,7 @@ 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. +dnl These are sorted since OVS may send payloads to the tunnels in any order. zero400=$(printf '0%.0s' $(seq 800)) zero100=$(printf '0%.0s' $(seq 200)) AT_CHECK_UNQUOTED([ovs-pcap p1.pcap | sort], [0], [dnl > +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)) > +zero100=$(printf '0%.0s' $(seq 200)) > +AT_CHECK_UNQUOTED([ovs-pcap p1.pcap | sort], [0], [dnl > +[aabbcc000001aa55aa55000308004500026200004000401131d6010102580101025ce01312b5024e5f360800000000007b00]dnl > +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000092d4781451000000000000000050100000edfd0000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004500026200004000401131d6010102580101025ce01317c1024efcd10000655800007b00]dnl > +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000092d4781451000000000000000050100000edfd0000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004500026200014000401131d5010102580101025ce01312b5024e5f360800000000007b00]dnl > +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000092d4781451000001f40000000050100000ec090000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004500026200014000401131d5010102580101025ce01317c1024efcd10000655800007b00]dnl > +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000092d4781451000001f40000000050100000ec090000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004500026200024000401131d4010102580101025ce01312b5024e5f360800000000007b00]dnl > +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000092d4781451000003e80000000050100000ea150000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004500026200024000401131d4010102580101025ce01317c1024efcd10000655800007b00]dnl > +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000092d4781451000003e80000000050100000ea150000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004500026200034000401131d3010102580101025ce01312b5024e5f360800000000007b00]dnl > +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000092d4781451000005dc0000000050100000e8210000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004500026200034000401131d3010102580101025ce01317c1024efcd10000655800007b00]dnl > +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000092d4781451000005dc0000000050100000e8210000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004501024e00004000401131e9010102580101025ce01312b5023abd990800000000007b00]dnl > +[0a8f394fe0738abf7e2f058408004501021c0000000040060187c0a87b02c0a87b01d4781451000000000000000050100000]dnl > +[4dc20000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004501024e00004000401131e9010102580101025ce01317c1023a5b350000655800007b00]dnl > +[0a8f394fe0738abf7e2f058408004501021c0000000040060187c0a87b02c0a87b01d4781451000000000000000050100000]dnl > +[4dc20000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004501024e00014000401131e8010102580101025ce01312b5023abd990800000000007b00]dnl > +[0a8f394fe0738abf7e2f058408004501021c0001000040060186c0a87b02c0a87b01d4781451000001f40000000050100000]dnl > +[4bce0000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004501024e00014000401131e8010102580101025ce01317c1023a5b350000655800007b00]dnl > +[0a8f394fe0738abf7e2f058408004501021c0001000040060186c0a87b02c0a87b01d4781451000001f40000000050100000]dnl > +[4bce0000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004501024e00024000401131e7010102580101025ce01312b5023abd990800000000007b00]dnl > +[0a8f394fe0738abf7e2f058408004501021c0002000040060185c0a87b02c0a87b01d4781451000003e80000000050100000]dnl > +[49da0000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004501024e00024000401131e7010102580101025ce01317c1023a5b350000655800007b00]dnl > +[0a8f394fe0738abf7e2f058408004501021c0002000040060185c0a87b02c0a87b01d4781451000003e80000000050100000]dnl > +[49da0000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004501024e00034000401131e6010102580101025ce01312b5023abd990800000000007b00]dnl > +[0a8f394fe0738abf7e2f058408004501021c0003000040060184c0a87b02c0a87b01d4781451000005dc0000000050100000]dnl > +[47e60000${zero100}${zero400}] > +[aabbcc000001aa55aa55000308004501024e00034000401131e6010102580101025ce01317c1023a5b350000655800007b00]dnl > +[0a8f394fe0738abf7e2f058408004501021c0003000040060184c0a87b02c0a87b01d4781451000005dc0000000050100000]dnl > +[47e60000${zero100}${zero400}] > +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01312b5024e8ed10800000000007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl > +[00000000000000882001cafe000000000000000000000092d4781451000000000000000050100000edfd0000${zero100}]dnl > +[${zero400}] > +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01312b5024e8ed10800000000007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl > +[00000000000000882001cafe000000000000000000000092d4781451000001f40000000050100000ec090000${zero100}]dnl > +[${zero400}] > +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01312b5024e8ed10800000000007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl > +[00000000000000882001cafe000000000000000000000092d4781451000003e80000000050100000ea150000${zero100}]dnl > +[${zero400}] > +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01312b5024e8ed10800000000007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl > +[00000000000000882001cafe000000000000000000000092d4781451000005dc0000000050100000e8210000${zero100}]dnl > +[${zero400}] > +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01317c1024e2c6d0000655800007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl > +[00000000000000882001cafe000000000000000000000092d4781451000000000000000050100000edfd0000${zero100}]dnl > +[${zero400}] > +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01317c1024e2c6d0000655800007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl > +[00000000000000882001cafe000000000000000000000092d4781451000001f40000000050100000ec090000${zero100}]dnl > +[${zero400}] > +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01317c1024e2c6d0000655800007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl > +[00000000000000882001cafe000000000000000000000092d4781451000003e80000000050100000ea150000${zero100}]dnl > +[${zero400}] > +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01317c1024e2c6d0000655800007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl > +[00000000000000882001cafe000000000000000000000092d4781451000005dc0000000050100000e8210000${zero100}]dnl > +[${zero400}] > +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01312b5023aed340800000000007b000a8f394fe0738abf7e2f058408004501021c0000000040060187c0a87b02]dnl > +[c0a87b01d47814510000000000000000501000004dc20000${zero100}${zero400}] > +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01312b5023aed340800000000007b000a8f394fe0738abf7e2f058408004501021c0001000040060186c0a87b02]dnl > +[c0a87b01d4781451000001f400000000501000004bce0000${zero100}${zero400}] > +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01312b5023aed340800000000007b000a8f394fe0738abf7e2f058408004501021c0002000040060185c0a87b02]dnl > +[c0a87b01d4781451000003e8000000005010000049da0000${zero100}${zero400}] > +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01312b5023aed340800000000007b000a8f394fe0738abf7e2f058408004501021c0003000040060184c0a87b02]dnl > +[c0a87b01d4781451000005dc000000005010000047e60000${zero100}${zero400}] > +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01317c1023a8ad00000655800007b000a8f394fe0738abf7e2f058408004501021c0000000040060187c0a87b02]dnl > +[c0a87b01d47814510000000000000000501000004dc20000${zero100}${zero400}] > +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01317c1023a8ad00000655800007b000a8f394fe0738abf7e2f058408004501021c0001000040060186c0a87b02]dnl > +[c0a87b01d4781451000001f400000000501000004bce0000${zero100}${zero400}] > +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01317c1023a8ad00000655800007b000a8f394fe0738abf7e2f058408004501021c0002000040060185c0a87b02]dnl > +[c0a87b01d4781451000003e8000000005010000049da0000${zero100}${zero400}] > +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl > +[00000093e01317c1023a8ad00000655800007b000a8f394fe0738abf7e2f058408004501021c0003000040060184c0a87b02]dnl > +[c0a87b01d4781451000005dc000000005010000047e60000${zero100}${zero400}] > +]) > + > +OVS_VSWITCHD_STOP > +AT_CLEANUP > + > AT_SETUP([dpif-netdev - revalidators handle dp modification fail correctly]) > OVS_VSWITCHD_START( > [add-port br0 p1 \ > diff --git a/tests/system-traffic.at b/tests/system-traffic.at > index 202ff0492..02d5ccbcb 100644 > --- a/tests/system-traffic.at > +++ b/tests/system-traffic.at > @@ -351,6 +351,101 @@ 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 Set MTU for tunnel to generate 1500 byte packets. > +AT_CHECK([ip link set dev br0 mtu 1400]) > + > +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 sleep 5 I guess this is a test leftover which should be removed. > +OVS_WAIT_WHILE([test $(stat -c %s p0.pcap) -le 68000 ]) > + > +dnl Stop OVS and tcpdump and verify the results. > + > +AT_CHECK([kill -15 $(cat tcpdump.pid)]) > + > +OVS_WAIT_WHILE([kill -0 $(cat tcpdump.pid)]) > + > +ovs-pcap p0.pcap Also a left over. > +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]) > + I cleaned up this test to be 80 chars wide and removed some cr/lf and the leftover commands. This is the diff: diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 02d5ccbcb..724b25fa9 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -373,7 +373,7 @@ 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. +dnl Test the case where 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]) @@ -384,19 +384,21 @@ 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]) +ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], + [10.1.1.1/24], [id 0 dstport 4789]) dnl Set MTU for tunnel to generate 1500 byte packets. AT_CHECK([ip link set dev br0 mtu 1400]) 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 +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 +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 ]) @@ -420,19 +422,14 @@ 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 sleep 5 OVS_WAIT_WHILE([test $(stat -c %s p0.pcap) -le 68000 ]) dnl Stop OVS and tcpdump and verify the results. - 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. +dnl The exact number of packets sent will vary, but we check that the largest +dnl segments have the correct 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) > +OVS_TRAFFIC_VSWITCHD_STOP > +AT_CLEANUP > + > AT_SETUP([datapath - ping vlan over vxlan tunnel]) > OVS_CHECK_TUNNEL_TSO() > OVS_CHECK_VXLAN() > -- > 2.43.5 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff --git a/lib/dp-packet-gso.c b/lib/dp-packet-gso.c index 847685ad9..04ebb19da 100644 --- a/lib/dp-packet-gso.c +++ b/lib/dp-packet-gso.c @@ -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))) { diff --git a/lib/dp-packet.h b/lib/dp-packet.h index a75b1c5cd..af1ff088f 100644 --- a/lib/dp-packet.h +++ b/lib/dp-packet.h @@ -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; } diff --git a/lib/netdev.c b/lib/netdev.c index f2d921ed6..02beac9d0 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -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); } } } diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at index bdc24cc30..2977bfe77 100644 --- a/tests/dpif-netdev.at +++ b/tests/dpif-netdev.at @@ -884,6 +884,179 @@ 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)) +zero100=$(printf '0%.0s' $(seq 200)) +AT_CHECK_UNQUOTED([ovs-pcap p1.pcap | sort], [0], [dnl +[aabbcc000001aa55aa55000308004500026200004000401131d6010102580101025ce01312b5024e5f360800000000007b00]dnl +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000092d4781451000000000000000050100000edfd0000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004500026200004000401131d6010102580101025ce01317c1024efcd10000655800007b00]dnl +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000092d4781451000000000000000050100000edfd0000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004500026200014000401131d5010102580101025ce01312b5024e5f360800000000007b00]dnl +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000092d4781451000001f40000000050100000ec090000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004500026200014000401131d5010102580101025ce01317c1024efcd10000655800007b00]dnl +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000092d4781451000001f40000000050100000ec090000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004500026200024000401131d4010102580101025ce01312b5024e5f360800000000007b00]dnl +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000092d4781451000003e80000000050100000ea150000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004500026200024000401131d4010102580101025ce01317c1024efcd10000655800007b00]dnl +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000092d4781451000003e80000000050100000ea150000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004500026200034000401131d3010102580101025ce01312b5024e5f360800000000007b00]dnl +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000092d4781451000005dc0000000050100000e8210000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004500026200034000401131d3010102580101025ce01317c1024efcd10000655800007b00]dnl +[0a8f394fe0738abf7e2f058486dd60000000020806002001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000092d4781451000005dc0000000050100000e8210000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004501024e00004000401131e9010102580101025ce01312b5023abd990800000000007b00]dnl +[0a8f394fe0738abf7e2f058408004501021c0000000040060187c0a87b02c0a87b01d4781451000000000000000050100000]dnl +[4dc20000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004501024e00004000401131e9010102580101025ce01317c1023a5b350000655800007b00]dnl +[0a8f394fe0738abf7e2f058408004501021c0000000040060187c0a87b02c0a87b01d4781451000000000000000050100000]dnl +[4dc20000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004501024e00014000401131e8010102580101025ce01312b5023abd990800000000007b00]dnl +[0a8f394fe0738abf7e2f058408004501021c0001000040060186c0a87b02c0a87b01d4781451000001f40000000050100000]dnl +[4bce0000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004501024e00014000401131e8010102580101025ce01317c1023a5b350000655800007b00]dnl +[0a8f394fe0738abf7e2f058408004501021c0001000040060186c0a87b02c0a87b01d4781451000001f40000000050100000]dnl +[4bce0000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004501024e00024000401131e7010102580101025ce01312b5023abd990800000000007b00]dnl +[0a8f394fe0738abf7e2f058408004501021c0002000040060185c0a87b02c0a87b01d4781451000003e80000000050100000]dnl +[49da0000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004501024e00024000401131e7010102580101025ce01317c1023a5b350000655800007b00]dnl +[0a8f394fe0738abf7e2f058408004501021c0002000040060185c0a87b02c0a87b01d4781451000003e80000000050100000]dnl +[49da0000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004501024e00034000401131e6010102580101025ce01312b5023abd990800000000007b00]dnl +[0a8f394fe0738abf7e2f058408004501021c0003000040060184c0a87b02c0a87b01d4781451000005dc0000000050100000]dnl +[47e60000${zero100}${zero400}] +[aabbcc000001aa55aa55000308004501024e00034000401131e6010102580101025ce01317c1023a5b350000655800007b00]dnl +[0a8f394fe0738abf7e2f058408004501021c0003000040060184c0a87b02c0a87b01d4781451000005dc0000000050100000]dnl +[47e60000${zero100}${zero400}] +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01312b5024e8ed10800000000007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl +[00000000000000882001cafe000000000000000000000092d4781451000000000000000050100000edfd0000${zero100}]dnl +[${zero400}] +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01312b5024e8ed10800000000007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl +[00000000000000882001cafe000000000000000000000092d4781451000001f40000000050100000ec090000${zero100}]dnl +[${zero400}] +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01312b5024e8ed10800000000007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl +[00000000000000882001cafe000000000000000000000092d4781451000003e80000000050100000ea150000${zero100}]dnl +[${zero400}] +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01312b5024e8ed10800000000007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl +[00000000000000882001cafe000000000000000000000092d4781451000005dc0000000050100000e8210000${zero100}]dnl +[${zero400}] +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01317c1024e2c6d0000655800007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl +[00000000000000882001cafe000000000000000000000092d4781451000000000000000050100000edfd0000${zero100}]dnl +[${zero400}] +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01317c1024e2c6d0000655800007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl +[00000000000000882001cafe000000000000000000000092d4781451000001f40000000050100000ec090000${zero100}]dnl +[${zero400}] +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01317c1024e2c6d0000655800007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl +[00000000000000882001cafe000000000000000000000092d4781451000003e80000000050100000ea150000${zero100}]dnl +[${zero400}] +[aabbcc000006aa55aa55000386dd60000000024e11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01317c1024e2c6d0000655800007b000a8f394fe0738abf7e2f058486dd60000000020806002001cafe00000000]dnl +[00000000000000882001cafe000000000000000000000092d4781451000005dc0000000050100000e8210000${zero100}]dnl +[${zero400}] +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01312b5023aed340800000000007b000a8f394fe0738abf7e2f058408004501021c0000000040060187c0a87b02]dnl +[c0a87b01d47814510000000000000000501000004dc20000${zero100}${zero400}] +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01312b5023aed340800000000007b000a8f394fe0738abf7e2f058408004501021c0001000040060186c0a87b02]dnl +[c0a87b01d4781451000001f400000000501000004bce0000${zero100}${zero400}] +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01312b5023aed340800000000007b000a8f394fe0738abf7e2f058408004501021c0002000040060185c0a87b02]dnl +[c0a87b01d4781451000003e8000000005010000049da0000${zero100}${zero400}] +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01312b5023aed340800000000007b000a8f394fe0738abf7e2f058408004501021c0003000040060184c0a87b02]dnl +[c0a87b01d4781451000005dc000000005010000047e60000${zero100}${zero400}] +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01317c1023a8ad00000655800007b000a8f394fe0738abf7e2f058408004501021c0000000040060187c0a87b02]dnl +[c0a87b01d47814510000000000000000501000004dc20000${zero100}${zero400}] +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01317c1023a8ad00000655800007b000a8f394fe0738abf7e2f058408004501021c0001000040060186c0a87b02]dnl +[c0a87b01d4781451000001f400000000501000004bce0000${zero100}${zero400}] +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01317c1023a8ad00000655800007b000a8f394fe0738abf7e2f058408004501021c0002000040060185c0a87b02]dnl +[c0a87b01d4781451000003e8000000005010000049da0000${zero100}${zero400}] +[aabbcc000006aa55aa55000386dd60100000023a11402001cafe0000000000000000000000882001cafe0000000000000000]dnl +[00000093e01317c1023a8ad00000655800007b000a8f394fe0738abf7e2f058408004501021c0003000040060184c0a87b02]dnl +[c0a87b01d4781451000005dc000000005010000047e60000${zero100}${zero400}] +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([dpif-netdev - revalidators handle dp modification fail correctly]) OVS_VSWITCHD_START( [add-port br0 p1 \ diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 202ff0492..02d5ccbcb 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -351,6 +351,101 @@ 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 Set MTU for tunnel to generate 1500 byte packets. +AT_CHECK([ip link set dev br0 mtu 1400]) + +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 sleep 5 +OVS_WAIT_WHILE([test $(stat -c %s p0.pcap) -le 68000 ]) + +dnl Stop OVS and tcpdump and verify the results. + +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]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([datapath - ping vlan over vxlan tunnel]) OVS_CHECK_TUNNEL_TSO() OVS_CHECK_VXLAN()