The OVN test suite identified a bug in dp_packet_ol_send_prepare() where
a double encapsulated BFD packet would trigger a seg fault. This
happened because we had assumed that if IP checksumming was marked as
offloaded, that checksum would occur in the innermost packet.

This change will check that the inner packet has an L3 and L4 before
checksumming those parts. And if missing, will resume checksumming the
outer components.

Fixes: 8b5fe2dc6080 ("userspace: Add Generic Segmentation Offloading.")
Reported-by: Dumitru Ceara <[email protected]>
Reported-at: https://issues.redhat.com/browse/FDP-300
Signed-off-by: Mike Pattrick <[email protected]>
---
 lib/dp-packet.h | 10 ++++++++--
 lib/packets.c   |  6 +++---
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/lib/dp-packet.h b/lib/dp-packet.h
index 939bec5c8..81b01f331 100644
--- a/lib/dp-packet.h
+++ b/lib/dp-packet.h
@@ -537,7 +537,7 @@ dp_packet_inner_l4(const struct dp_packet *b)
 static inline size_t
 dp_packet_inner_l4_size(const struct dp_packet *b)
 {
-    return OVS_LIKELY(b->l4_ofs != UINT16_MAX)
+    return OVS_LIKELY(b->inner_l4_ofs != UINT16_MAX)
            ? (const char *) dp_packet_tail(b)
            - (const char *) dp_packet_inner_l4(b)
            - dp_packet_l2_pad_size(b)
@@ -1385,7 +1385,13 @@ dp_packet_ip_checksum_bad(const struct dp_packet *p)
 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;
+
+    if (inner && dp_packet_inner_l3(p)) {
+        ip = dp_packet_inner_l3(p);
+    } else {
+        ip = dp_packet_l3(p);
+    }
 
     ovs_assert(ip);
     ip->ip_csum = 0;
diff --git a/lib/packets.c b/lib/packets.c
index f23d25420..921862b0d 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -2004,7 +2004,7 @@ packet_tcp_complete_csum(struct dp_packet *p, bool inner)
     void *ip_hdr;
     bool is_v4;
 
-    if (inner) {
+    if (inner && dp_packet_inner_l4(p)) {
         tcp = dp_packet_inner_l4(p);
         ip_hdr = dp_packet_inner_l3(p);
         tcp_sz = dp_packet_inner_l4_size(p);
@@ -2050,7 +2050,7 @@ packet_udp_complete_csum(struct dp_packet *p, bool inner)
     void *ip_hdr;
     bool is_v4;
 
-    if (inner) {
+    if (inner && dp_packet_inner_l4(p)) {
         udp = dp_packet_inner_l4(p);
         ip_hdr = dp_packet_inner_l3(p);
         udp_sz = dp_packet_inner_l4_size(p);
@@ -2104,7 +2104,7 @@ packet_sctp_complete_csum(struct dp_packet *p, bool inner)
     uint16_t tp_len;
     ovs_be32 csum;
 
-    if (inner) {
+    if (inner && dp_packet_inner_l4(p)) {
         sh = dp_packet_inner_l4(p);
         tp_len = dp_packet_inner_l4_size(p);
     } else {
-- 
2.39.3

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

Reply via email to