forked from mirrors/linux
		
	Merge branch 'stacked_vlan_tso'
Toshiaki Makita says: ==================== Stacked vlan TSO On the basis of Netdev 0.1 discussion[1], I made a patch set to enable TSO for packets with multiple vlans. Currently, packets with multiple vlans are always segmented by software, which is caused by that netif_skb_features() drops most feature flags for multiple tagged packets. To allow NICs to segment them, we need to get rid of that check from core. Fortunately, recently introduced ndo_features_check() can be used to move the check to each driver, and this patch set is based on the idea. For the initial patch set, I chose 3 drivers, bonding, team, and igb, as candidates to enable TSO. I tested them and confirmed they works fine with this change. Here are samples of performance test results. As I expected, %sys gets pretty lower than before. * TEST1: vlan (.1Q) on vlan (.1ad) on igb (I350) - before $ netperf -t TCP_STREAM -H 192.168.10.1 -l 60 Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 60.02 933.72 Average: CPU %user %nice %system %iowait %steal %idle Average: all 0.13 0.00 11.28 0.01 0.00 88.58 - after $ netperf -t TCP_STREAM -H 192.168.10.1 -l 60 Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 60.01 936.13 Average: CPU %user %nice %system %iowait %steal %idle Average: all 0.24 0.00 4.17 0.01 0.00 95.58 * TEST2: vlan (.1Q) on bridge (.1ad vlan filtering) on team on igb (I350) - before $ netperf -t TCP_STREAM -H 192.168.10.1 -l 60 Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 60.01 936.28 Average: CPU %user %nice %system %iowait %steal %idle Average: all 0.41 0.00 11.57 0.01 0.00 88.01 - after $ netperf -t TCP_STREAM -H 192.168.10.1 -l 60 Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 60.02 935.72 Average: CPU %user %nice %system %iowait %steal %idle Average: all 0.14 0.00 7.66 0.01 0.00 92.19 In addition to above, I tested these configurations: - vlan (.1Q) on vlan (1.ad) on bonding on igb (I350) - vlan (.1Q) on vlan (1.Q) on igb (I350) - vlan (.1Q) on vlan (1.Q) on team on igb (I350) And didn't find any problem. [1] https://netdev01.org/sessions/18 https://netdev01.org/docs/netdev01_bof_8021ad_makita_150212.pdf ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
						commit
						afb0bc972b
					
				
					 10 changed files with 96 additions and 22 deletions
				
			
		| 
						 | 
					@ -4038,6 +4038,7 @@ static const struct net_device_ops bond_netdev_ops = {
 | 
				
			||||||
	.ndo_fix_features	= bond_fix_features,
 | 
						.ndo_fix_features	= bond_fix_features,
 | 
				
			||||||
	.ndo_bridge_setlink	= ndo_dflt_netdev_switch_port_bridge_setlink,
 | 
						.ndo_bridge_setlink	= ndo_dflt_netdev_switch_port_bridge_setlink,
 | 
				
			||||||
	.ndo_bridge_dellink	= ndo_dflt_netdev_switch_port_bridge_dellink,
 | 
						.ndo_bridge_dellink	= ndo_dflt_netdev_switch_port_bridge_dellink,
 | 
				
			||||||
 | 
						.ndo_features_check	= passthru_features_check,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct device_type bond_type = {
 | 
					static const struct device_type bond_type = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12557,6 +12557,7 @@ static netdev_features_t bnx2x_features_check(struct sk_buff *skb,
 | 
				
			||||||
					      struct net_device *dev,
 | 
										      struct net_device *dev,
 | 
				
			||||||
					      netdev_features_t features)
 | 
										      netdev_features_t features)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						features = vlan_features_check(skb, features);
 | 
				
			||||||
	return vxlan_features_check(skb, features);
 | 
						return vxlan_features_check(skb, features);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2093,6 +2093,7 @@ static const struct net_device_ops igb_netdev_ops = {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	.ndo_fix_features	= igb_fix_features,
 | 
						.ndo_fix_features	= igb_fix_features,
 | 
				
			||||||
	.ndo_set_features	= igb_set_features,
 | 
						.ndo_set_features	= igb_set_features,
 | 
				
			||||||
 | 
						.ndo_features_check	= passthru_features_check,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2373,6 +2373,7 @@ static netdev_features_t mlx4_en_features_check(struct sk_buff *skb,
 | 
				
			||||||
						struct net_device *dev,
 | 
											struct net_device *dev,
 | 
				
			||||||
						netdev_features_t features)
 | 
											netdev_features_t features)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						features = vlan_features_check(skb, features);
 | 
				
			||||||
	return vxlan_features_check(skb, features);
 | 
						return vxlan_features_check(skb, features);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -507,6 +507,7 @@ static netdev_features_t qlcnic_features_check(struct sk_buff *skb,
 | 
				
			||||||
					       struct net_device *dev,
 | 
										       struct net_device *dev,
 | 
				
			||||||
					       netdev_features_t features)
 | 
										       netdev_features_t features)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						features = vlan_features_check(skb, features);
 | 
				
			||||||
	return vxlan_features_check(skb, features);
 | 
						return vxlan_features_check(skb, features);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1979,6 +1979,7 @@ static const struct net_device_ops team_netdev_ops = {
 | 
				
			||||||
	.ndo_change_carrier     = team_change_carrier,
 | 
						.ndo_change_carrier     = team_change_carrier,
 | 
				
			||||||
	.ndo_bridge_setlink     = ndo_dflt_netdev_switch_port_bridge_setlink,
 | 
						.ndo_bridge_setlink     = ndo_dflt_netdev_switch_port_bridge_setlink,
 | 
				
			||||||
	.ndo_bridge_dellink     = ndo_dflt_netdev_switch_port_bridge_dellink,
 | 
						.ndo_bridge_dellink     = ndo_dflt_netdev_switch_port_bridge_dellink,
 | 
				
			||||||
 | 
						.ndo_features_check	= passthru_features_check,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/***********************
 | 
					/***********************
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -561,4 +561,71 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb,
 | 
				
			||||||
		skb->protocol = htons(ETH_P_802_2);
 | 
							skb->protocol = htons(ETH_P_802_2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * skb_vlan_tagged - check if skb is vlan tagged.
 | 
				
			||||||
 | 
					 * @skb: skbuff to query
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns true if the skb is tagged, regardless of whether it is hardware
 | 
				
			||||||
 | 
					 * accelerated or not.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline bool skb_vlan_tagged(const struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!skb_vlan_tag_present(skb) &&
 | 
				
			||||||
 | 
						    likely(skb->protocol != htons(ETH_P_8021Q) &&
 | 
				
			||||||
 | 
							   skb->protocol != htons(ETH_P_8021AD)))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * skb_vlan_tagged_multi - check if skb is vlan tagged with multiple headers.
 | 
				
			||||||
 | 
					 * @skb: skbuff to query
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns true if the skb is tagged with multiple vlan headers, regardless
 | 
				
			||||||
 | 
					 * of whether it is hardware accelerated or not.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__be16 protocol = skb->protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!skb_vlan_tag_present(skb)) {
 | 
				
			||||||
 | 
							struct vlan_ethhdr *veh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (likely(protocol != htons(ETH_P_8021Q) &&
 | 
				
			||||||
 | 
								   protocol != htons(ETH_P_8021AD)))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							veh = (struct vlan_ethhdr *)skb->data;
 | 
				
			||||||
 | 
							protocol = veh->h_vlan_encapsulated_proto;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (protocol != htons(ETH_P_8021Q) && protocol != htons(ETH_P_8021AD))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * vlan_features_check - drop unsafe features for skb with multiple tags.
 | 
				
			||||||
 | 
					 * @skb: skbuff to query
 | 
				
			||||||
 | 
					 * @features: features to be checked
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns features without unsafe ones if the skb has multiple tags.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline netdev_features_t vlan_features_check(const struct sk_buff *skb,
 | 
				
			||||||
 | 
											    netdev_features_t features)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (skb_vlan_tagged_multi(skb))
 | 
				
			||||||
 | 
							features = netdev_intersect_features(features,
 | 
				
			||||||
 | 
											     NETIF_F_SG |
 | 
				
			||||||
 | 
											     NETIF_F_HIGHDMA |
 | 
				
			||||||
 | 
											     NETIF_F_FRAGLIST |
 | 
				
			||||||
 | 
											     NETIF_F_GEN_CSUM |
 | 
				
			||||||
 | 
											     NETIF_F_HW_VLAN_CTAG_TX |
 | 
				
			||||||
 | 
											     NETIF_F_HW_VLAN_STAG_TX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return features;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* !(_LINUX_IF_VLAN_H_) */
 | 
					#endif /* !(_LINUX_IF_VLAN_H_) */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3657,6 +3657,9 @@ void netdev_change_features(struct net_device *dev);
 | 
				
			||||||
void netif_stacked_transfer_operstate(const struct net_device *rootdev,
 | 
					void netif_stacked_transfer_operstate(const struct net_device *rootdev,
 | 
				
			||||||
					struct net_device *dev);
 | 
										struct net_device *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					netdev_features_t passthru_features_check(struct sk_buff *skb,
 | 
				
			||||||
 | 
										  struct net_device *dev,
 | 
				
			||||||
 | 
										  netdev_features_t features);
 | 
				
			||||||
netdev_features_t netif_skb_features(struct sk_buff *skb);
 | 
					netdev_features_t netif_skb_features(struct sk_buff *skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline bool net_gso_ok(netdev_features_t features, int gso_type)
 | 
					static inline bool net_gso_ok(netdev_features_t features, int gso_type)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -554,6 +554,7 @@ static int vlan_dev_init(struct net_device *dev)
 | 
				
			||||||
	if (dev->features & NETIF_F_VLAN_FEATURES)
 | 
						if (dev->features & NETIF_F_VLAN_FEATURES)
 | 
				
			||||||
		netdev_warn(real_dev, "VLAN features are set incorrectly.  Q-in-Q configurations may not work correctly.\n");
 | 
							netdev_warn(real_dev, "VLAN features are set incorrectly.  Q-in-Q configurations may not work correctly.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->vlan_features = real_dev->vlan_features & ~NETIF_F_ALL_FCOE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* ipv6 shared card related stuff */
 | 
						/* ipv6 shared card related stuff */
 | 
				
			||||||
	dev->dev_id = real_dev->dev_id;
 | 
						dev->dev_id = real_dev->dev_id;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2562,12 +2562,26 @@ static netdev_features_t harmonize_features(struct sk_buff *skb,
 | 
				
			||||||
	return features;
 | 
						return features;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					netdev_features_t passthru_features_check(struct sk_buff *skb,
 | 
				
			||||||
 | 
										  struct net_device *dev,
 | 
				
			||||||
 | 
										  netdev_features_t features)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return features;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(passthru_features_check);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static netdev_features_t dflt_features_check(const struct sk_buff *skb,
 | 
				
			||||||
 | 
										     struct net_device *dev,
 | 
				
			||||||
 | 
										     netdev_features_t features)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return vlan_features_check(skb, features);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
netdev_features_t netif_skb_features(struct sk_buff *skb)
 | 
					netdev_features_t netif_skb_features(struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct net_device *dev = skb->dev;
 | 
						struct net_device *dev = skb->dev;
 | 
				
			||||||
	netdev_features_t features = dev->features;
 | 
						netdev_features_t features = dev->features;
 | 
				
			||||||
	u16 gso_segs = skb_shinfo(skb)->gso_segs;
 | 
						u16 gso_segs = skb_shinfo(skb)->gso_segs;
 | 
				
			||||||
	__be16 protocol = skb->protocol;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs)
 | 
						if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs)
 | 
				
			||||||
		features &= ~NETIF_F_GSO_MASK;
 | 
							features &= ~NETIF_F_GSO_MASK;
 | 
				
			||||||
| 
						 | 
					@ -2579,34 +2593,17 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
 | 
				
			||||||
	if (skb->encapsulation)
 | 
						if (skb->encapsulation)
 | 
				
			||||||
		features &= dev->hw_enc_features;
 | 
							features &= dev->hw_enc_features;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!skb_vlan_tag_present(skb)) {
 | 
						if (skb_vlan_tagged(skb))
 | 
				
			||||||
		if (unlikely(protocol == htons(ETH_P_8021Q) ||
 | 
					 | 
				
			||||||
			     protocol == htons(ETH_P_8021AD))) {
 | 
					 | 
				
			||||||
			struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
 | 
					 | 
				
			||||||
			protocol = veh->h_vlan_encapsulated_proto;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			goto finalize;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	features = netdev_intersect_features(features,
 | 
					 | 
				
			||||||
					     dev->vlan_features |
 | 
					 | 
				
			||||||
					     NETIF_F_HW_VLAN_CTAG_TX |
 | 
					 | 
				
			||||||
					     NETIF_F_HW_VLAN_STAG_TX);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD))
 | 
					 | 
				
			||||||
		features = netdev_intersect_features(features,
 | 
							features = netdev_intersect_features(features,
 | 
				
			||||||
						     NETIF_F_SG |
 | 
											     dev->vlan_features |
 | 
				
			||||||
						     NETIF_F_HIGHDMA |
 | 
					 | 
				
			||||||
						     NETIF_F_FRAGLIST |
 | 
					 | 
				
			||||||
						     NETIF_F_GEN_CSUM |
 | 
					 | 
				
			||||||
						     NETIF_F_HW_VLAN_CTAG_TX |
 | 
											     NETIF_F_HW_VLAN_CTAG_TX |
 | 
				
			||||||
						     NETIF_F_HW_VLAN_STAG_TX);
 | 
											     NETIF_F_HW_VLAN_STAG_TX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
finalize:
 | 
					 | 
				
			||||||
	if (dev->netdev_ops->ndo_features_check)
 | 
						if (dev->netdev_ops->ndo_features_check)
 | 
				
			||||||
		features &= dev->netdev_ops->ndo_features_check(skb, dev,
 | 
							features &= dev->netdev_ops->ndo_features_check(skb, dev,
 | 
				
			||||||
								features);
 | 
													features);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							features &= dflt_features_check(skb, dev, features);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return harmonize_features(skb, features);
 | 
						return harmonize_features(skb, features);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue