net: Add driver helper functions to determine checksum offloadability

Add skb_csum_offload_chk driver helper function to determine if a
device with limited checksum offload capabilities is able to offload the
checksum for a given packet.

This patch includes:
  - The skb_csum_offload_chk function. Returns true if checksum is
    offloadable, else false. Optionally, in the case that the checksum
    is not offloable, the function can call skb_checksum_help to resolve
    the checksum. skb_csum_offload_chk also returns whether the checksum
    refers to an encapsulated checksum.
  - Definition of skb_csum_offl_spec structure that caller uses to
    indicate rules about what it can offload (e.g. IPv4/v6, TCP/UDP only,
    whether encapsulated checksums can be offloaded, whether checksum with
    IPv6 extension headers can be offloaded).
  - Ancilary functions called skb_csum_offload_chk_help,
    skb_csum_off_chk_help_cmn, skb_csum_off_chk_help_cmn_v4_only.

Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Tom Herbert
2015-12-14 11:19:46 -08:00
committed by David S. Miller
parent 9a49850d0a
commit 6ae23ad362
2 changed files with 214 additions and 0 deletions

View File

@@ -2522,6 +2522,71 @@ static inline void skb_gro_remcsum_cleanup(struct sk_buff *skb,
remcsum_unadjust((__sum16 *)ptr, grc->delta);
}
struct skb_csum_offl_spec {
__u16 ipv4_okay:1,
ipv6_okay:1,
encap_okay:1,
ip_options_okay:1,
ext_hdrs_okay:1,
tcp_okay:1,
udp_okay:1,
sctp_okay:1,
vlan_okay:1,
no_encapped_ipv6:1,
no_not_encapped:1;
};
bool __skb_csum_offload_chk(struct sk_buff *skb,
const struct skb_csum_offl_spec *spec,
bool *csum_encapped,
bool csum_help);
static inline bool skb_csum_offload_chk(struct sk_buff *skb,
const struct skb_csum_offl_spec *spec,
bool *csum_encapped,
bool csum_help)
{
if (skb->ip_summed != CHECKSUM_PARTIAL)
return false;
return __skb_csum_offload_chk(skb, spec, csum_encapped, csum_help);
}
static inline bool skb_csum_offload_chk_help(struct sk_buff *skb,
const struct skb_csum_offl_spec *spec)
{
bool csum_encapped;
return skb_csum_offload_chk(skb, spec, &csum_encapped, true);
}
static inline bool skb_csum_off_chk_help_cmn(struct sk_buff *skb)
{
static const struct skb_csum_offl_spec csum_offl_spec = {
.ipv4_okay = 1,
.ip_options_okay = 1,
.ipv6_okay = 1,
.vlan_okay = 1,
.tcp_okay = 1,
.udp_okay = 1,
};
return skb_csum_offload_chk_help(skb, &csum_offl_spec);
}
static inline bool skb_csum_off_chk_help_cmn_v4_only(struct sk_buff *skb)
{
static const struct skb_csum_offl_spec csum_offl_spec = {
.ipv4_okay = 1,
.ip_options_okay = 1,
.tcp_okay = 1,
.udp_okay = 1,
.vlan_okay = 1,
};
return skb_csum_offload_chk_help(skb, &csum_offl_spec);
}
static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
const void *daddr, const void *saddr,
@@ -3711,6 +3776,19 @@ static inline bool can_checksum_protocol(netdev_features_t features,
}
}
/* Map an ethertype into IP protocol if possible */
static inline int eproto_to_ipproto(int eproto)
{
switch (eproto) {
case htons(ETH_P_IP):
return IPPROTO_IP;
case htons(ETH_P_IPV6):
return IPPROTO_IPV6;
default:
return -1;
}
}
#ifdef CONFIG_BUG
void netdev_rx_csum_fault(struct net_device *dev);
#else