[NET]: IPV6 checksum offloading in network devices
The existing model for checksum offload does not correctly handle devices that can offload IPV4 and IPV6 only. The NETIF_F_HW_CSUM flag implies device can do any arbitrary protocol. This patch: * adds NETIF_F_IPV6_CSUM for those devices * fixes bnx2 and tg3 devices that need it * add NETIF_F_IPV6_CSUM to ipv6 output (incl GSO) * fixes assumptions about NETIF_F_ALL_CSUM in nat * adjusts bridge union of checksumming computation Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d3d6dd3ada
commit
d212f87b06
@ -6490,10 +6490,10 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
memcpy(dev->perm_addr, bp->mac_addr, 6);
|
||||
bp->name = board_info[ent->driver_data].name;
|
||||
|
||||
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
|
||||
if (CHIP_NUM(bp) == CHIP_NUM_5709)
|
||||
dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
|
||||
else
|
||||
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
|
||||
dev->features |= NETIF_F_IPV6_CSUM;
|
||||
|
||||
#ifdef BCM_VLAN
|
||||
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||
#endif
|
||||
|
@ -11944,12 +11944,11 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
|
||||
* checksumming.
|
||||
*/
|
||||
if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) {
|
||||
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
|
||||
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
|
||||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
|
||||
dev->features |= NETIF_F_HW_CSUM;
|
||||
else
|
||||
dev->features |= NETIF_F_IP_CSUM;
|
||||
dev->features |= NETIF_F_SG;
|
||||
dev->features |= NETIF_F_IPV6_CSUM;
|
||||
|
||||
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
|
||||
} else
|
||||
tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
|
||||
|
@ -314,9 +314,10 @@ struct net_device
|
||||
/* Net device features */
|
||||
unsigned long features;
|
||||
#define NETIF_F_SG 1 /* Scatter/gather IO. */
|
||||
#define NETIF_F_IP_CSUM 2 /* Can checksum only TCP/UDP over IPv4. */
|
||||
#define NETIF_F_IP_CSUM 2 /* Can checksum TCP/UDP over IPv4. */
|
||||
#define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */
|
||||
#define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */
|
||||
#define NETIF_F_IPV6_CSUM 16 /* Can checksum TCP/UDP over IPV6 */
|
||||
#define NETIF_F_HIGHDMA 32 /* Can DMA to high memory. */
|
||||
#define NETIF_F_FRAGLIST 64 /* Scatter/gather IO. */
|
||||
#define NETIF_F_HW_VLAN_TX 128 /* Transmit VLAN hw acceleration */
|
||||
@ -338,8 +339,11 @@ struct net_device
|
||||
/* List of features with software fallbacks. */
|
||||
#define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6)
|
||||
|
||||
|
||||
#define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
|
||||
#define NETIF_F_ALL_CSUM (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM)
|
||||
#define NETIF_F_V4_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
|
||||
#define NETIF_F_V6_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
|
||||
#define NETIF_F_ALL_CSUM (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
|
||||
|
||||
struct net_device *next_sched;
|
||||
|
||||
|
@ -368,10 +368,18 @@ void br_features_recompute(struct net_bridge *br)
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
unsigned long feature = p->dev->features;
|
||||
|
||||
/* if device needs checksumming, downgrade to hw checksumming */
|
||||
if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
|
||||
checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
|
||||
|
||||
/* if device can't do all checksum, downgrade to ipv4/ipv6 */
|
||||
if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
|
||||
checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
|
||||
checksum ^= NETIF_F_HW_CSUM
|
||||
| NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
|
||||
|
||||
if (checksum & NETIF_F_IPV6_CSUM && !(feature & NETIF_F_IPV6_CSUM))
|
||||
checksum &= ~NETIF_F_IPV6_CSUM;
|
||||
|
||||
if (!(feature & NETIF_F_IP_CSUM))
|
||||
checksum = 0;
|
||||
|
||||
|
@ -1509,9 +1509,11 @@ int dev_queue_xmit(struct sk_buff *skb)
|
||||
skb_set_transport_header(skb, skb->csum_start -
|
||||
skb_headroom(skb));
|
||||
|
||||
if (!(dev->features & NETIF_F_GEN_CSUM) &&
|
||||
(!(dev->features & NETIF_F_IP_CSUM) ||
|
||||
skb->protocol != htons(ETH_P_IP)))
|
||||
if (!(dev->features & NETIF_F_GEN_CSUM)
|
||||
|| ((dev->features & NETIF_F_IP_CSUM)
|
||||
&& skb->protocol == htons(ETH_P_IP))
|
||||
|| ((dev->features & NETIF_F_IPV6_CSUM)
|
||||
&& skb->protocol == htons(ETH_P_IPV6)))
|
||||
if (skb_checksum_help(skb))
|
||||
goto out_kfree_skb;
|
||||
}
|
||||
@ -3107,6 +3109,22 @@ int register_netdevice(struct net_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix illegal checksum combinations */
|
||||
if ((dev->features & NETIF_F_HW_CSUM) &&
|
||||
(dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
|
||||
printk(KERN_NOTICE "%s: mixed HW and IP checksum settings.\n",
|
||||
dev->name);
|
||||
dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
|
||||
}
|
||||
|
||||
if ((dev->features & NETIF_F_NO_CSUM) &&
|
||||
(dev->features & (NETIF_F_HW_CSUM|NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
|
||||
printk(KERN_NOTICE "%s: mixed no checksumming and other settings.\n",
|
||||
dev->name);
|
||||
dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM);
|
||||
}
|
||||
|
||||
|
||||
/* Fix illegal SG+CSUM combinations. */
|
||||
if ((dev->features & NETIF_F_SG) &&
|
||||
!(dev->features & NETIF_F_ALL_CSUM)) {
|
||||
|
@ -1170,6 +1170,9 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
|
||||
int ihl;
|
||||
int id;
|
||||
|
||||
if (!(features & NETIF_F_V4_CSUM))
|
||||
features &= ~NETIF_F_SG;
|
||||
|
||||
if (unlikely(skb_shinfo(skb)->gso_type &
|
||||
~(SKB_GSO_TCPV4 |
|
||||
SKB_GSO_UDP |
|
||||
|
@ -837,7 +837,7 @@ int ip_append_data(struct sock *sk,
|
||||
*/
|
||||
if (transhdrlen &&
|
||||
length + fragheaderlen <= mtu &&
|
||||
rt->u.dst.dev->features & NETIF_F_ALL_CSUM &&
|
||||
rt->u.dst.dev->features & NETIF_F_V4_CSUM &&
|
||||
!exthdrlen)
|
||||
csummode = CHECKSUM_PARTIAL;
|
||||
|
||||
|
@ -178,7 +178,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
|
||||
datalen = (*pskb)->len - iph->ihl*4;
|
||||
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
|
||||
if (!(rt->rt_flags & RTCF_LOCAL) &&
|
||||
(*pskb)->dev->features & NETIF_F_ALL_CSUM) {
|
||||
(*pskb)->dev->features & NETIF_F_V4_CSUM) {
|
||||
(*pskb)->ip_summed = CHECKSUM_PARTIAL;
|
||||
(*pskb)->csum_start = skb_headroom(*pskb) +
|
||||
skb_network_offset(*pskb) +
|
||||
@ -265,7 +265,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
|
||||
|
||||
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
|
||||
if (!(rt->rt_flags & RTCF_LOCAL) &&
|
||||
(*pskb)->dev->features & NETIF_F_ALL_CSUM) {
|
||||
(*pskb)->dev->features & NETIF_F_V4_CSUM) {
|
||||
(*pskb)->ip_summed = CHECKSUM_PARTIAL;
|
||||
(*pskb)->csum_start = skb_headroom(*pskb) +
|
||||
skb_network_offset(*pskb) +
|
||||
|
@ -123,7 +123,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
|
||||
struct ipv6hdr *ipv6h;
|
||||
struct inet6_protocol *ops;
|
||||
|
||||
if (!(features & NETIF_F_HW_CSUM))
|
||||
if (!(features & NETIF_F_V6_CSUM))
|
||||
features &= ~NETIF_F_SG;
|
||||
|
||||
if (unlikely(skb_shinfo(skb)->gso_type &
|
||||
|
Loading…
Reference in New Issue
Block a user