net: more accurate checksumming in validate_xmit_skb()
skb_csum_hwoffload_help() uses netdev features and skb->csum_not_inet to
determine if skb needs software computation of Internet Checksum or crc32c
(or nothing, if this computation can be done by the hardware). Use it in
place of skb_checksum_help() in validate_xmit_skb() to avoid corruption
of non-GSO SCTP packets having skb->ip_summed equal to CHECKSUM_PARTIAL.
While at it, remove references to skb_csum_off_chk* functions, since they
are not present anymore in Linux _ see commit cf53b1da73
("Revert
"net: Add driver helper functions to determine checksum offloadability"").
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
dba003067a
commit
43c26a1a45
|
@ -35,6 +35,9 @@ This interface only allows a single checksum to be offloaded. Where
|
||||||
encapsulation is used, the packet may have multiple checksum fields in
|
encapsulation is used, the packet may have multiple checksum fields in
|
||||||
different header layers, and the rest will have to be handled by another
|
different header layers, and the rest will have to be handled by another
|
||||||
mechanism such as LCO or RCO.
|
mechanism such as LCO or RCO.
|
||||||
|
CRC32c can also be offloaded using this interface, by means of filling
|
||||||
|
skb->csum_start and skb->csum_offset as described above, and setting
|
||||||
|
skb->csum_not_inet: see skbuff.h comment (section 'D') for more details.
|
||||||
No offloading of the IP header checksum is performed; it is always done in
|
No offloading of the IP header checksum is performed; it is always done in
|
||||||
software. This is OK because when we build the IP header, we obviously
|
software. This is OK because when we build the IP header, we obviously
|
||||||
have it in cache, so summing it isn't expensive. It's also rather short.
|
have it in cache, so summing it isn't expensive. It's also rather short.
|
||||||
|
@ -49,9 +52,9 @@ A driver declares its offload capabilities in netdev->hw_features; see
|
||||||
and csum_offset given in the SKB; if it tries to deduce these itself in
|
and csum_offset given in the SKB; if it tries to deduce these itself in
|
||||||
hardware (as some NICs do) the driver should check that the values in the
|
hardware (as some NICs do) the driver should check that the values in the
|
||||||
SKB match those which the hardware will deduce, and if not, fall back to
|
SKB match those which the hardware will deduce, and if not, fall back to
|
||||||
checksumming in software instead (with skb_checksum_help or one of the
|
checksumming in software instead (with skb_csum_hwoffload_help() or one of
|
||||||
skb_csum_off_chk* functions as mentioned in include/linux/skbuff.h). This
|
the skb_checksum_help() / skb_crc32c_csum_help functions, as mentioned in
|
||||||
is a pain, but that's what you get when hardware tries to be clever.
|
include/linux/skbuff.h).
|
||||||
|
|
||||||
The stack should, for the most part, assume that checksum offload is
|
The stack should, for the most part, assume that checksum offload is
|
||||||
supported by the underlying device. The only place that should check is
|
supported by the underlying device. The only place that should check is
|
||||||
|
@ -60,7 +63,7 @@ The stack should, for the most part, assume that checksum offload is
|
||||||
may include other offloads besides TX Checksum Offload) and, if they are
|
may include other offloads besides TX Checksum Offload) and, if they are
|
||||||
not supported or enabled on the device (determined by netdev->features),
|
not supported or enabled on the device (determined by netdev->features),
|
||||||
performs the corresponding offload in software. In the case of TX
|
performs the corresponding offload in software. In the case of TX
|
||||||
Checksum Offload, that means calling skb_checksum_help(skb).
|
Checksum Offload, that means calling skb_csum_hwoffload_help(skb, features).
|
||||||
|
|
||||||
|
|
||||||
LCO: Local Checksum Offload
|
LCO: Local Checksum Offload
|
||||||
|
|
|
@ -3930,6 +3930,9 @@ void netdev_rss_key_fill(void *buffer, size_t len);
|
||||||
int dev_get_nest_level(struct net_device *dev);
|
int dev_get_nest_level(struct net_device *dev);
|
||||||
int skb_checksum_help(struct sk_buff *skb);
|
int skb_checksum_help(struct sk_buff *skb);
|
||||||
int skb_crc32c_csum_help(struct sk_buff *skb);
|
int skb_crc32c_csum_help(struct sk_buff *skb);
|
||||||
|
int skb_csum_hwoffload_help(struct sk_buff *skb,
|
||||||
|
const netdev_features_t features);
|
||||||
|
|
||||||
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
|
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
|
||||||
netdev_features_t features, bool tx_path);
|
netdev_features_t features, bool tx_path);
|
||||||
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
|
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
|
||||||
|
|
|
@ -162,14 +162,11 @@
|
||||||
*
|
*
|
||||||
* NETIF_F_IP_CSUM and NETIF_F_IPV6_CSUM are being deprecated in favor of
|
* NETIF_F_IP_CSUM and NETIF_F_IPV6_CSUM are being deprecated in favor of
|
||||||
* NETIF_F_HW_CSUM. New devices should use NETIF_F_HW_CSUM to indicate
|
* NETIF_F_HW_CSUM. New devices should use NETIF_F_HW_CSUM to indicate
|
||||||
* checksum offload capability. If a device has limited checksum capabilities
|
* checksum offload capability.
|
||||||
* (for instance can only perform NETIF_F_IP_CSUM or NETIF_F_IPV6_CSUM as
|
* skb_csum_hwoffload_help() can be called to resolve CHECKSUM_PARTIAL based
|
||||||
* described above) a helper function can be called to resolve
|
* on network device checksumming capabilities: if a packet does not match
|
||||||
* CHECKSUM_PARTIAL. The helper functions are skb_csum_off_chk*. The helper
|
* them, skb_checksum_help or skb_crc32c_help (depending on the value of
|
||||||
* function takes a spec argument that describes the protocol layer that is
|
* csum_not_inet, see item D.) is called to resolve the checksum.
|
||||||
* supported for checksum offload and can be called for each packet. If a
|
|
||||||
* packet does not match the specification for offload, skb_checksum_help
|
|
||||||
* is called to resolve the checksum.
|
|
||||||
*
|
*
|
||||||
* CHECKSUM_NONE:
|
* CHECKSUM_NONE:
|
||||||
*
|
*
|
||||||
|
|
|
@ -2996,6 +2996,17 @@ static struct sk_buff *validate_xmit_vlan(struct sk_buff *skb,
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int skb_csum_hwoffload_help(struct sk_buff *skb,
|
||||||
|
const netdev_features_t features)
|
||||||
|
{
|
||||||
|
if (unlikely(skb->csum_not_inet))
|
||||||
|
return !!(features & NETIF_F_SCTP_CRC) ? 0 :
|
||||||
|
skb_crc32c_csum_help(skb);
|
||||||
|
|
||||||
|
return !!(features & NETIF_F_CSUM_MASK) ? 0 : skb_checksum_help(skb);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(skb_csum_hwoffload_help);
|
||||||
|
|
||||||
static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
|
static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
|
||||||
{
|
{
|
||||||
netdev_features_t features;
|
netdev_features_t features;
|
||||||
|
@ -3034,8 +3045,7 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device
|
||||||
else
|
else
|
||||||
skb_set_transport_header(skb,
|
skb_set_transport_header(skb,
|
||||||
skb_checksum_start_offset(skb));
|
skb_checksum_start_offset(skb));
|
||||||
if (!(features & NETIF_F_CSUM_MASK) &&
|
if (skb_csum_hwoffload_help(skb, features))
|
||||||
skb_checksum_help(skb))
|
|
||||||
goto out_kfree_skb;
|
goto out_kfree_skb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue