Skip to content

Commit

Permalink
ibmveth: Set CHECKSUM_PARTIAL if NULL TCP CSUM.
Browse files Browse the repository at this point in the history
TCP checksums on received packets may be set to NULL by the sender if CSO
is enabled. The hypervisor flags these packets as check-sum-ok and the
skb is then flagged CHECKSUM_UNNECESSARY. If these packets are then
forwarded the sender will not request CSO due to the CHECKSUM_UNNECESSARY
flag. The result is a TCP packet sent with a bad checksum. This change
sets up CHECKSUM_PARTIAL on these packets causing the sender to correctly
request CSUM offload.

Signed-off-by: David Wilder <dwilder@us.ibm.com>
Reviewed-by: Pradeep Satyanarayana <pradeeps@linux.vnet.ibm.com>
Tested-by: Cristobal Forno <cforno12@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Wilder authored and David S. Miller committed Jun 23, 2021
1 parent fe87797 commit 7525de2
Showing 1 changed file with 28 additions and 23 deletions.
51 changes: 28 additions & 23 deletions drivers/net/ethernet/ibm/ibmveth.c
Original file line number Diff line number Diff line change
Expand Up @@ -1285,36 +1285,41 @@ static void ibmveth_rx_csum_helper(struct sk_buff *skb,
iph_proto = iph6->nexthdr;
}

/* In OVS environment, when a flow is not cached, specifically for a
* new TCP connection, the first packet information is passed up
/* When CSO is enabled the TCP checksum may have be set to NULL by
* the sender given that we zeroed out TCP checksum field in
* transmit path (refer ibmveth_start_xmit routine). In this case set
* up CHECKSUM_PARTIAL. If the packet is forwarded, the checksum will
* then be recalculated by the destination NIC (CSO must be enabled
* on the destination NIC).
*
* In an OVS environment, when a flow is not cached, specifically for a
* new TCP connection, the first packet information is passed up to
* the user space for finding a flow. During this process, OVS computes
* checksum on the first packet when CHECKSUM_PARTIAL flag is set.
*
* Given that we zeroed out TCP checksum field in transmit path
* (refer ibmveth_start_xmit routine) as we set "no checksum bit",
* OVS computed checksum will be incorrect w/o TCP pseudo checksum
* in the packet. This leads to OVS dropping the packet and hence
* TCP retransmissions are seen.
*
* So, re-compute TCP pseudo header checksum.
* So, re-compute TCP pseudo header checksum when configured for
* trunk mode.
*/
if (iph_proto == IPPROTO_TCP && adapter->is_active_trunk) {
if (iph_proto == IPPROTO_TCP) {
struct tcphdr *tcph = (struct tcphdr *)(skb->data + iphlen);

tcphdrlen = skb->len - iphlen;

/* Recompute TCP pseudo header checksum */
if (skb_proto == ETH_P_IP)
tcph->check = ~csum_tcpudp_magic(iph->saddr,
if (tcph->check == 0x0000) {
/* Recompute TCP pseudo header checksum */
if (adapter->is_active_trunk) {
tcphdrlen = skb->len - iphlen;
if (skb_proto == ETH_P_IP)
tcph->check =
~csum_tcpudp_magic(iph->saddr,
iph->daddr, tcphdrlen, iph_proto, 0);
else if (skb_proto == ETH_P_IPV6)
tcph->check = ~csum_ipv6_magic(&iph6->saddr,
else if (skb_proto == ETH_P_IPV6)
tcph->check =
~csum_ipv6_magic(&iph6->saddr,
&iph6->daddr, tcphdrlen, iph_proto, 0);

/* Setup SKB fields for checksum offload */
skb_partial_csum_set(skb, iphlen,
offsetof(struct tcphdr, check));
skb_reset_network_header(skb);
}
/* Setup SKB fields for checksum offload */
skb_partial_csum_set(skb, iphlen,
offsetof(struct tcphdr, check));
skb_reset_network_header(skb);
}
}
}

Expand Down

0 comments on commit 7525de2

Please sign in to comment.