forked from Minki/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
@ -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 New Issue
Block a user