Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d212f87b authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller
Browse files

[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: default avatarDavid S. Miller <davem@davemloft.net>
parent d3d6dd3a
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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;

	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;
	if (CHIP_NUM(bp) == CHIP_NUM_5709)
		dev->features |= NETIF_F_IPV6_CSUM;

#ifdef BCM_VLAN
	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
+3 −4
Original line number Diff line number Diff line
@@ -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;
+6 −2
Original line number Diff line number Diff line
@@ -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;

+9 −1
Original line number Diff line number Diff line
@@ -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;

+21 −3
Original line number Diff line number Diff line
@@ -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)) {
Loading