During the transition towards checksum offloading, the function to
handle software fallback of IPv4 checksums didn't account for the
options field.
Fixes: 5d11c47d3ebe ("userspace: Enable IP checksum offloading by default.")
Reported-by: Jun Wang <[email protected]>
Signed-off-by: Mike Pattrick <[email protected]>
---
v2:
- Added tests
- Added additional checks
---
lib/dp-packet.h | 31 ++++++++++++++++++++++++++++---
tests/dpif-netdev.at | 24 ++++++++++++++++++++++++
2 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/lib/dp-packet.h b/lib/dp-packet.h
index a75b1c5cd..e816b9f20 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)
{
@@ -1390,11 +1400,26 @@ dp_packet_hwol_l3_ipv4(const struct dp_packet *b)
static inline void
dp_packet_ip_set_header_csum(struct dp_packet *p, bool inner)
{
- struct ip_header *ip = (inner) ? dp_packet_inner_l3(p) : dp_packet_l3(p);
+ struct ip_header *ip;
+ size_t l3_size;
+ size_t ip_len;
+
+ if (inner) {
+ ip = dp_packet_inner_l3(p);
+ l3_size = dp_packet_inner_l3_size(p);
+ } else {
+ ip = dp_packet_l3(p);
+ l3_size = dp_packet_l3_size(p);
+ }
ovs_assert(ip);
- ip->ip_csum = 0;
- ip->ip_csum = csum(ip, sizeof *ip);
+
+ ip_len = IP_IHL(ip->ip_ihl_ver) * 4;
+
+ if (OVS_LIKELY(ip_len >= IP_HEADER_LEN && ip_len < l3_size)) {
+ ip->ip_csum = 0;
+ ip->ip_csum = csum(ip, ip_len);
+ }
}
/* Returns 'true' if the packet 'p' has good integrity and the
diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
index bdc24cc30..d31f13931 100644
--- a/tests/dpif-netdev.at
+++ b/tests/dpif-netdev.at
@@ -807,6 +807,30 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${bad_frame}])
AT_CHECK([ovs-pcap p2.pcap > p2.pcap.txt 2>&1])
AT_CHECK_UNQUOTED([tail -n 1 p2.pcap.txt], [0], [${good_expected}
])
+
+dnl Test with IP optional fields in a valid packet.
+optpkt=dnl
+["aaaaaaaaaaaabbbbbbbbbbbb0800"]dnl
+["4f000044abab00004001eeee0a0000010a000002"]dnl
+["07270c010203040a00000300000000"]dnl
+["00000000000000000000000000000000"]dnl
+["00000000000000000008003e2fb6d00000"]
+
+dnl IP header is indicates optional fields but doesn't contain any
+microgram="aaaaaaaaaaaabbbbbbbbbbbb08004f000044abab00004001eeee0a0000010a000002"
+
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_csum=true])
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_csum_set_good=true])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${optpkt}])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${microgram}])
+AT_CHECK([ovs-pcap p2.pcap > p2.pcap.txt 2>&1])
+dnl The first packet has a checksum and the second doesn't
+AT_CHECK_UNQUOTED([tail -n 2 p2.pcap.txt], [0], [dnl
+[aaaaaaaaaaaabbbbbbbbbbbb08004f000044abab00004001dd2e0a000001c0a80101]dnl
+[07270c010203040a0000030000000000000000000000000000000000000000000000]dnl
+[00000000000008003e2fb6d00000]
+[aaaaaaaaaaaabbbbbbbbbbbb08004f000044abab00004001eeee0a0000010a000002]
+])
OVS_VSWITCHD_STOP
AT_CLEANUP
--
2.43.5
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev