aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-03-29 16:33:32 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-29 16:33:32 -0400
commitafb0bc972b5269a2046a1194c475d929c62fc1a3 (patch)
tree1c51d0aad72f03283affc7cc91e8106f3e67d672
parent608cd71a9c7c9db76e78a792c5a4101e12fea43f (diff)
parent1abbc98a8ac5c6cc016e672e5888b6416ae243f6 (diff)
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>
-rw-r--r--drivers/net/bonding/bond_main.c1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c1
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c1
-rw-r--r--drivers/net/team/team.c1
-rw-r--r--include/linux/if_vlan.h67
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--net/8021q/vlan_dev.c1
-rw-r--r--net/core/dev.c41
10 files changed, 96 insertions, 22 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index c026ce9cd7b6..7b4684ccdb3f 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4038,6 +4038,7 @@ static const struct net_device_ops bond_netdev_ops = {
4038 .ndo_fix_features = bond_fix_features, 4038 .ndo_fix_features = bond_fix_features,
4039 .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink, 4039 .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink,
4040 .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink, 4040 .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink,
4041 .ndo_features_check = passthru_features_check,
4041}; 4042};
4042 4043
4043static const struct device_type bond_type = { 4044static const struct device_type bond_type = {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 9677431c582a..039b0c1f480e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -12557,6 +12557,7 @@ static netdev_features_t bnx2x_features_check(struct sk_buff *skb,
12557 struct net_device *dev, 12557 struct net_device *dev,
12558 netdev_features_t features) 12558 netdev_features_t features)
12559{ 12559{
12560 features = vlan_features_check(skb, features);
12560 return vxlan_features_check(skb, features); 12561 return vxlan_features_check(skb, features);
12561} 12562}
12562 12563
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 0e07545ccc97..8457d0306e3a 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2093,6 +2093,7 @@ static const struct net_device_ops igb_netdev_ops = {
2093#endif 2093#endif
2094 .ndo_fix_features = igb_fix_features, 2094 .ndo_fix_features = igb_fix_features,
2095 .ndo_set_features = igb_set_features, 2095 .ndo_set_features = igb_set_features,
2096 .ndo_features_check = passthru_features_check,
2096}; 2097};
2097 2098
2098/** 2099/**
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index a8339e98ad24..ebc93a101c93 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -2373,6 +2373,7 @@ static netdev_features_t mlx4_en_features_check(struct sk_buff *skb,
2373 struct net_device *dev, 2373 struct net_device *dev,
2374 netdev_features_t features) 2374 netdev_features_t features)
2375{ 2375{
2376 features = vlan_features_check(skb, features);
2376 return vxlan_features_check(skb, features); 2377 return vxlan_features_check(skb, features);
2377} 2378}
2378#endif 2379#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index a430a34a4434..367f3976df56 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -507,6 +507,7 @@ static netdev_features_t qlcnic_features_check(struct sk_buff *skb,
507 struct net_device *dev, 507 struct net_device *dev,
508 netdev_features_t features) 508 netdev_features_t features)
509{ 509{
510 features = vlan_features_check(skb, features);
510 return vxlan_features_check(skb, features); 511 return vxlan_features_check(skb, features);
511} 512}
512#endif 513#endif
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index a23319fc78ca..6928448f6b7f 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1979,6 +1979,7 @@ static const struct net_device_ops team_netdev_ops = {
1979 .ndo_change_carrier = team_change_carrier, 1979 .ndo_change_carrier = team_change_carrier,
1980 .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink, 1980 .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink,
1981 .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink, 1981 .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink,
1982 .ndo_features_check = passthru_features_check,
1982}; 1983};
1983 1984
1984/*********************** 1985/***********************
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index b11b28a30b9e..920e4457ce6e 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -561,4 +561,71 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb,
561 skb->protocol = htons(ETH_P_802_2); 561 skb->protocol = htons(ETH_P_802_2);
562} 562}
563 563
564/**
565 * skb_vlan_tagged - check if skb is vlan tagged.
566 * @skb: skbuff to query
567 *
568 * Returns true if the skb is tagged, regardless of whether it is hardware
569 * accelerated or not.
570 */
571static inline bool skb_vlan_tagged(const struct sk_buff *skb)
572{
573 if (!skb_vlan_tag_present(skb) &&
574 likely(skb->protocol != htons(ETH_P_8021Q) &&
575 skb->protocol != htons(ETH_P_8021AD)))
576 return false;
577
578 return true;
579}
580
581/**
582 * skb_vlan_tagged_multi - check if skb is vlan tagged with multiple headers.
583 * @skb: skbuff to query
584 *
585 * Returns true if the skb is tagged with multiple vlan headers, regardless
586 * of whether it is hardware accelerated or not.
587 */
588static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
589{
590 __be16 protocol = skb->protocol;
591
592 if (!skb_vlan_tag_present(skb)) {
593 struct vlan_ethhdr *veh;
594
595 if (likely(protocol != htons(ETH_P_8021Q) &&
596 protocol != htons(ETH_P_8021AD)))
597 return false;
598
599 veh = (struct vlan_ethhdr *)skb->data;
600 protocol = veh->h_vlan_encapsulated_proto;
601 }
602
603 if (protocol != htons(ETH_P_8021Q) && protocol != htons(ETH_P_8021AD))
604 return false;
605
606 return true;
607}
608
609/**
610 * vlan_features_check - drop unsafe features for skb with multiple tags.
611 * @skb: skbuff to query
612 * @features: features to be checked
613 *
614 * Returns features without unsafe ones if the skb has multiple tags.
615 */
616static inline netdev_features_t vlan_features_check(const struct sk_buff *skb,
617 netdev_features_t features)
618{
619 if (skb_vlan_tagged_multi(skb))
620 features = netdev_intersect_features(features,
621 NETIF_F_SG |
622 NETIF_F_HIGHDMA |
623 NETIF_F_FRAGLIST |
624 NETIF_F_GEN_CSUM |
625 NETIF_F_HW_VLAN_CTAG_TX |
626 NETIF_F_HW_VLAN_STAG_TX);
627
628 return features;
629}
630
564#endif /* !(_LINUX_IF_VLAN_H_) */ 631#endif /* !(_LINUX_IF_VLAN_H_) */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 08c4ab37189f..967bb4c8caf1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3657,6 +3657,9 @@ void netdev_change_features(struct net_device *dev);
3657void netif_stacked_transfer_operstate(const struct net_device *rootdev, 3657void netif_stacked_transfer_operstate(const struct net_device *rootdev,
3658 struct net_device *dev); 3658 struct net_device *dev);
3659 3659
3660netdev_features_t passthru_features_check(struct sk_buff *skb,
3661 struct net_device *dev,
3662 netdev_features_t features);
3660netdev_features_t netif_skb_features(struct sk_buff *skb); 3663netdev_features_t netif_skb_features(struct sk_buff *skb);
3661 3664
3662static inline bool net_gso_ok(netdev_features_t features, int gso_type) 3665static inline bool net_gso_ok(netdev_features_t features, int gso_type)
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index f196552ec3c4..8b5ab9033b41 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -554,6 +554,7 @@ static int vlan_dev_init(struct net_device *dev)
554 if (dev->features & NETIF_F_VLAN_FEATURES) 554 if (dev->features & NETIF_F_VLAN_FEATURES)
555 netdev_warn(real_dev, "VLAN features are set incorrectly. Q-in-Q configurations may not work correctly.\n"); 555 netdev_warn(real_dev, "VLAN features are set incorrectly. Q-in-Q configurations may not work correctly.\n");
556 556
557 dev->vlan_features = real_dev->vlan_features & ~NETIF_F_ALL_FCOE;
557 558
558 /* ipv6 shared card related stuff */ 559 /* ipv6 shared card related stuff */
559 dev->dev_id = real_dev->dev_id; 560 dev->dev_id = real_dev->dev_id;
diff --git a/net/core/dev.c b/net/core/dev.c
index a0408d497dae..3a06003ecafd 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2562,12 +2562,26 @@ static netdev_features_t harmonize_features(struct sk_buff *skb,
2562 return features; 2562 return features;
2563} 2563}
2564 2564
2565netdev_features_t passthru_features_check(struct sk_buff *skb,
2566 struct net_device *dev,
2567 netdev_features_t features)
2568{
2569 return features;
2570}
2571EXPORT_SYMBOL(passthru_features_check);
2572
2573static netdev_features_t dflt_features_check(const struct sk_buff *skb,
2574 struct net_device *dev,
2575 netdev_features_t features)
2576{
2577 return vlan_features_check(skb, features);
2578}
2579
2565netdev_features_t netif_skb_features(struct sk_buff *skb) 2580netdev_features_t netif_skb_features(struct sk_buff *skb)
2566{ 2581{
2567 struct net_device *dev = skb->dev; 2582 struct net_device *dev = skb->dev;
2568 netdev_features_t features = dev->features; 2583 netdev_features_t features = dev->features;
2569 u16 gso_segs = skb_shinfo(skb)->gso_segs; 2584 u16 gso_segs = skb_shinfo(skb)->gso_segs;
2570 __be16 protocol = skb->protocol;
2571 2585
2572 if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs) 2586 if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs)
2573 features &= ~NETIF_F_GSO_MASK; 2587 features &= ~NETIF_F_GSO_MASK;
@@ -2579,34 +2593,17 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
2579 if (skb->encapsulation) 2593 if (skb->encapsulation)
2580 features &= dev->hw_enc_features; 2594 features &= dev->hw_enc_features;
2581 2595
2582 if (!skb_vlan_tag_present(skb)) { 2596 if (skb_vlan_tagged(skb))
2583 if (unlikely(protocol == htons(ETH_P_8021Q) ||
2584 protocol == htons(ETH_P_8021AD))) {
2585 struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
2586 protocol = veh->h_vlan_encapsulated_proto;
2587 } else {
2588 goto finalize;
2589 }
2590 }
2591
2592 features = netdev_intersect_features(features,
2593 dev->vlan_features |
2594 NETIF_F_HW_VLAN_CTAG_TX |
2595 NETIF_F_HW_VLAN_STAG_TX);
2596
2597 if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD))
2598 features = netdev_intersect_features(features, 2597 features = netdev_intersect_features(features,
2599 NETIF_F_SG | 2598 dev->vlan_features |
2600 NETIF_F_HIGHDMA |
2601 NETIF_F_FRAGLIST |
2602 NETIF_F_GEN_CSUM |
2603 NETIF_F_HW_VLAN_CTAG_TX | 2599 NETIF_F_HW_VLAN_CTAG_TX |
2604 NETIF_F_HW_VLAN_STAG_TX); 2600 NETIF_F_HW_VLAN_STAG_TX);
2605 2601
2606finalize:
2607 if (dev->netdev_ops->ndo_features_check) 2602 if (dev->netdev_ops->ndo_features_check)
2608 features &= dev->netdev_ops->ndo_features_check(skb, dev, 2603 features &= dev->netdev_ops->ndo_features_check(skb, dev,
2609 features); 2604 features);
2605 else
2606 features &= dflt_features_check(skb, dev, features);
2610 2607
2611 return harmonize_features(skb, features); 2608 return harmonize_features(skb, features);
2612} 2609}