From ac0ad5eff81d50170261845b3b805885011ef929 Mon Sep 17 00:00:00 2001 From: Michael Pfeiffer Date: Tue, 1 Sep 2020 11:47:55 +0200 Subject: [PATCH] net: calculate checksum of packet with IPv4 options Currently, rte_ipv4_cksum() and rte_ipv4_udptcp_cksum() assume all IPv4 headers have sizeof(struct rte_ipv4_hdr) bytes. This is not true for those (rare) packets with IPv4 options. Thus, both IPv4 and TCP/UDP checksums are calculated wrong. This patch fixes the issue by using the actual IPv4 header length from the packet's IHL field. Signed-off-by: Michael Pfeiffer Reviewed-by: Andrew Rybchenko Acked-by: Olivier Matz --- lib/librte_net/rte_ip.h | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h index fcd1eb342d..bb55ebb6fa 100644 --- a/lib/librte_net/rte_ip.h +++ b/lib/librte_net/rte_ip.h @@ -269,7 +269,7 @@ static inline uint16_t rte_ipv4_cksum(const struct rte_ipv4_hdr *ipv4_hdr) { uint16_t cksum; - cksum = rte_raw_cksum(ipv4_hdr, sizeof(struct rte_ipv4_hdr)); + cksum = rte_raw_cksum(ipv4_hdr, (ipv4_hdr->version_ihl & 0xf) * 4); return (uint16_t)~cksum; } @@ -302,6 +302,9 @@ rte_ipv4_phdr_cksum(const struct rte_ipv4_hdr *ipv4_hdr, uint64_t ol_flags) uint16_t len; /* L4 length. */ } psd_hdr; + uint32_t l3_len; + uint8_t ip_hdr_len; + psd_hdr.src_addr = ipv4_hdr->src_addr; psd_hdr.dst_addr = ipv4_hdr->dst_addr; psd_hdr.zero = 0; @@ -309,9 +312,9 @@ rte_ipv4_phdr_cksum(const struct rte_ipv4_hdr *ipv4_hdr, uint64_t ol_flags) if (ol_flags & PKT_TX_TCP_SEG) { psd_hdr.len = 0; } else { - psd_hdr.len = rte_cpu_to_be_16( - (uint16_t)(rte_be_to_cpu_16(ipv4_hdr->total_length) - - sizeof(struct rte_ipv4_hdr))); + l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length); + ip_hdr_len = (ipv4_hdr->version_ihl & 0xf) * 4; + psd_hdr.len = rte_cpu_to_be_16((uint16_t)(l3_len - ip_hdr_len)); } return rte_raw_cksum(&psd_hdr, sizeof(psd_hdr)); } @@ -319,8 +322,8 @@ rte_ipv4_phdr_cksum(const struct rte_ipv4_hdr *ipv4_hdr, uint64_t ol_flags) /** * Process the IPv4 UDP or TCP checksum. * - * The IPv4 header should not contains options. The IP and layer 4 - * checksum must be set to 0 in the packet by the caller. + * The IP and layer 4 checksum must be set to 0 in the packet by + * the caller. * * @param ipv4_hdr * The pointer to the contiguous IPv4 header. @@ -334,12 +337,14 @@ rte_ipv4_udptcp_cksum(const struct rte_ipv4_hdr *ipv4_hdr, const void *l4_hdr) { uint32_t cksum; uint32_t l3_len, l4_len; + uint8_t ip_hdr_len; + ip_hdr_len = (ipv4_hdr->version_ihl & 0xf) * 4; l3_len = rte_be_to_cpu_16(ipv4_hdr->total_length); - if (l3_len < sizeof(struct rte_ipv4_hdr)) + if (l3_len < ip_hdr_len) return 0; - l4_len = l3_len - sizeof(struct rte_ipv4_hdr); + l4_len = l3_len - ip_hdr_len; cksum = rte_raw_cksum(l4_hdr, l4_len); cksum += rte_ipv4_phdr_cksum(ipv4_hdr, 0); -- 2.20.1