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
|
||||
different header layers, and the rest will have to be handled by another
|
||||
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
|
||||
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.
|
||||
|
@ -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
|
||||
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
|
||||
checksumming in software instead (with skb_checksum_help or one of the
|
||||
skb_csum_off_chk* functions as mentioned in include/linux/skbuff.h). This
|
||||
is a pain, but that's what you get when hardware tries to be clever.
|
||||
checksumming in software instead (with skb_csum_hwoffload_help() or one of
|
||||
the skb_checksum_help() / skb_crc32c_csum_help functions, as mentioned in
|
||||
include/linux/skbuff.h).
|
||||
|
||||
The stack should, for the most part, assume that checksum offload 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
|
||||
not supported or enabled on the device (determined by netdev->features),
|
||||
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
|
||||
|
|
|
@ -3930,6 +3930,9 @@ void netdev_rss_key_fill(void *buffer, size_t len);
|
|||
int dev_get_nest_level(struct net_device *dev);
|
||||
int skb_checksum_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,
|
||||
netdev_features_t features, bool tx_path);
|
||||
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_HW_CSUM. New devices should use NETIF_F_HW_CSUM to indicate
|
||||
* checksum offload capability. If a device has limited checksum capabilities
|
||||
* (for instance can only perform NETIF_F_IP_CSUM or NETIF_F_IPV6_CSUM as
|
||||
* described above) a helper function can be called to resolve
|
||||
* CHECKSUM_PARTIAL. The helper functions are skb_csum_off_chk*. The helper
|
||||
* function takes a spec argument that describes the protocol layer that is
|
||||
* 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 offload capability.
|
||||
* skb_csum_hwoffload_help() can be called to resolve CHECKSUM_PARTIAL based
|
||||
* on network device checksumming capabilities: if a packet does not match
|
||||
* them, skb_checksum_help or skb_crc32c_help (depending on the value of
|
||||
* csum_not_inet, see item D.) is called to resolve the checksum.
|
||||
*
|
||||
* CHECKSUM_NONE:
|
||||
*
|
||||
|
|
|
@ -2996,6 +2996,17 @@ static struct sk_buff *validate_xmit_vlan(struct sk_buff *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)
|
||||
{
|
||||
netdev_features_t features;
|
||||
|
@ -3034,8 +3045,7 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device
|
|||
else
|
||||
skb_set_transport_header(skb,
|
||||
skb_checksum_start_offset(skb));
|
||||
if (!(features & NETIF_F_CSUM_MASK) &&
|
||||
skb_checksum_help(skb))
|
||||
if (skb_csum_hwoffload_help(skb, features))
|
||||
goto out_kfree_skb;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue