Commit 858296c8 authored by Alexander Duyck's avatar Alexander Duyck Committed by Jeff Kirsher

i40e/i40evf: Fix i40e_rx_checksum

There are a couple of issues I found in i40e_rx_checksum while doing some
recent testing.  As a result I have found the Rx checksum logic is pretty
much broken and returning that the checksum is valid for tunnels in cases
where it is not.

First the inner types are not the correct values to use to test for if a
tunnel is present or not.  In addition the inner protocol types are not a
bitmask as such performing an OR of the values doesn't make sense.  I have
instead changed the code so that the inner protocol types are used to
determine if we report CHECKSUM_UNNECESSARY or not.  For anything that does
not end in UDP, TCP, or SCTP it doesn't make much sense to report a
checksum offload since it won't contain a checksum anyway.

This leaves us with the need to set the csum_level based on some value.
For that purpose I am using the tunnel_type field.  If the tunnel type is
GRENAT or greater then this means we have a GRE or UDP tunnel with an inner
header.  In the case of GRE or UDP we will have a possible checksum present
so for this reason it should be safe to set the csum_level to 1 to indicate
that we are reporting the state of the inner header.
Signed-off-by: default avatarAlexander Duyck <aduyck@mirantis.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 005db31d
...@@ -1280,8 +1280,8 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -1280,8 +1280,8 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
union i40e_rx_desc *rx_desc) union i40e_rx_desc *rx_desc)
{ {
struct i40e_rx_ptype_decoded decoded; struct i40e_rx_ptype_decoded decoded;
bool ipv4, ipv6, tunnel = false;
u32 rx_error, rx_status; u32 rx_error, rx_status;
bool ipv4, ipv6;
u8 ptype; u8 ptype;
u64 qword; u64 qword;
...@@ -1336,19 +1336,23 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -1336,19 +1336,23 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT))
return; return;
/* The hardware supported by this driver does not validate outer /* If there is an outer header present that might contain a checksum
* checksums for tunneled VXLAN or GENEVE frames. I don't agree * we need to bump the checksum level by 1 to reflect the fact that
* with it but the specification states that you "MAY validate", it * we are indicating we validated the inner checksum.
* doesn't make it a hard requirement so if we have validated the
* inner checksum report CHECKSUM_UNNECESSARY.
*/ */
if (decoded.inner_prot & (I40E_RX_PTYPE_INNER_PROT_TCP | if (decoded.tunnel_type >= I40E_RX_PTYPE_TUNNEL_IP_GRENAT)
I40E_RX_PTYPE_INNER_PROT_UDP | skb->csum_level = 1;
I40E_RX_PTYPE_INNER_PROT_SCTP))
tunnel = true; /* Only report checksum unnecessary for TCP, UDP, or SCTP */
switch (decoded.inner_prot) {
case I40E_RX_PTYPE_INNER_PROT_TCP:
case I40E_RX_PTYPE_INNER_PROT_UDP:
case I40E_RX_PTYPE_INNER_PROT_SCTP:
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->csum_level = tunnel ? 1 : 0; /* fall though */
default:
break;
}
return; return;
......
...@@ -752,8 +752,8 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -752,8 +752,8 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
union i40e_rx_desc *rx_desc) union i40e_rx_desc *rx_desc)
{ {
struct i40e_rx_ptype_decoded decoded; struct i40e_rx_ptype_decoded decoded;
bool ipv4, ipv6, tunnel = false;
u32 rx_error, rx_status; u32 rx_error, rx_status;
bool ipv4, ipv6;
u8 ptype; u8 ptype;
u64 qword; u64 qword;
...@@ -808,19 +808,23 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -808,19 +808,23 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT))
return; return;
/* The hardware supported by this driver does not validate outer /* If there is an outer header present that might contain a checksum
* checksums for tunneled VXLAN or GENEVE frames. I don't agree * we need to bump the checksum level by 1 to reflect the fact that
* with it but the specification states that you "MAY validate", it * we are indicating we validated the inner checksum.
* doesn't make it a hard requirement so if we have validated the
* inner checksum report CHECKSUM_UNNECESSARY.
*/ */
if (decoded.inner_prot & (I40E_RX_PTYPE_INNER_PROT_TCP | if (decoded.tunnel_type >= I40E_RX_PTYPE_TUNNEL_IP_GRENAT)
I40E_RX_PTYPE_INNER_PROT_UDP | skb->csum_level = 1;
I40E_RX_PTYPE_INNER_PROT_SCTP))
tunnel = true; /* Only report checksum unnecessary for TCP, UDP, or SCTP */
switch (decoded.inner_prot) {
case I40E_RX_PTYPE_INNER_PROT_TCP:
case I40E_RX_PTYPE_INNER_PROT_UDP:
case I40E_RX_PTYPE_INNER_PROT_SCTP:
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->csum_level = tunnel ? 1 : 0; /* fall though */
default:
break;
}
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment