aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Gross <jesse@nicira.com>2014-12-24 01:37:26 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-26 17:20:56 -0500
commit5f35227ea34bb616c436d9da47fc325866c428f3 (patch)
treee6f997cb2f1f1bce1d2b5be613e1be667b9f927f
parent6e4ab361b6f3eb41ffe63224a8b5770fc68ef710 (diff)
net: Generalize ndo_gso_check to ndo_features_check
GSO isn't the only offload feature with restrictions that potentially can't be expressed with the current features mechanism. Checksum is another although it's a general issue that could in theory apply to anything. Even if it may be possible to implement these restrictions in other ways, it can result in duplicate code or inefficient per-packet behavior. This generalizes ndo_gso_check so that drivers can remove any features that don't make sense for a given packet, similar to netif_skb_features(). It also converts existing driver restrictions to the new format, completing the work that was done to support tunnel protocols since the issues apply to checksums as well. By actually removing features from the set that are used to do offloading, it solves another problem with the existing interface. In these cases, GSO would run with the original set of features and not do anything because it appears that segmentation is not required. CC: Tom Herbert <therbert@google.com> CC: Joe Stringer <joestringer@nicira.com> CC: Eric Dumazet <edumazet@google.com> CC: Hayes Wang <hayeswang@realtek.com> Signed-off-by: Jesse Gross <jesse@nicira.com> Acked-by: Tom Herbert <therbert@google.com> Fixes: 04ffcb255f22 ("net: Add ndo_gso_check") Tested-by: Hayes Wang <hayeswang@realtek.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c8
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c10
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c8
-rw-r--r--include/linux/netdevice.h20
-rw-r--r--include/net/vxlan.h28
-rw-r--r--net/core/dev.c23
7 files changed, 70 insertions, 35 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 9f5e38769a29..72eef9fc883e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -12553,9 +12553,11 @@ static int bnx2x_get_phys_port_id(struct net_device *netdev,
12553 return 0; 12553 return 0;
12554} 12554}
12555 12555
12556static bool bnx2x_gso_check(struct sk_buff *skb, struct net_device *dev) 12556static netdev_features_t bnx2x_features_check(struct sk_buff *skb,
12557 struct net_device *dev,
12558 netdev_features_t features)
12557{ 12559{
12558 return vxlan_gso_check(skb); 12560 return vxlan_features_check(skb, features);
12559} 12561}
12560 12562
12561static const struct net_device_ops bnx2x_netdev_ops = { 12563static const struct net_device_ops bnx2x_netdev_ops = {
@@ -12589,7 +12591,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
12589#endif 12591#endif
12590 .ndo_get_phys_port_id = bnx2x_get_phys_port_id, 12592 .ndo_get_phys_port_id = bnx2x_get_phys_port_id,
12591 .ndo_set_vf_link_state = bnx2x_set_vf_link_state, 12593 .ndo_set_vf_link_state = bnx2x_set_vf_link_state,
12592 .ndo_gso_check = bnx2x_gso_check, 12594 .ndo_features_check = bnx2x_features_check,
12593}; 12595};
12594 12596
12595static int bnx2x_set_coherency_mask(struct bnx2x *bp) 12597static int bnx2x_set_coherency_mask(struct bnx2x *bp)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 196073110e32..41a0a5498da7 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -4459,9 +4459,11 @@ done:
4459 adapter->vxlan_port_count--; 4459 adapter->vxlan_port_count--;
4460} 4460}
4461 4461
4462static bool be_gso_check(struct sk_buff *skb, struct net_device *dev) 4462static netdev_features_t be_features_check(struct sk_buff *skb,
4463 struct net_device *dev,
4464 netdev_features_t features)
4463{ 4465{
4464 return vxlan_gso_check(skb); 4466 return vxlan_features_check(skb, features);
4465} 4467}
4466#endif 4468#endif
4467 4469
@@ -4492,7 +4494,7 @@ static const struct net_device_ops be_netdev_ops = {
4492#ifdef CONFIG_BE2NET_VXLAN 4494#ifdef CONFIG_BE2NET_VXLAN
4493 .ndo_add_vxlan_port = be_add_vxlan_port, 4495 .ndo_add_vxlan_port = be_add_vxlan_port,
4494 .ndo_del_vxlan_port = be_del_vxlan_port, 4496 .ndo_del_vxlan_port = be_del_vxlan_port,
4495 .ndo_gso_check = be_gso_check, 4497 .ndo_features_check = be_features_check,
4496#endif 4498#endif
4497}; 4499};
4498 4500
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 190cbd931f6b..d0d6dc1b8e46 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -2365,9 +2365,11 @@ static void mlx4_en_del_vxlan_port(struct net_device *dev,
2365 queue_work(priv->mdev->workqueue, &priv->vxlan_del_task); 2365 queue_work(priv->mdev->workqueue, &priv->vxlan_del_task);
2366} 2366}
2367 2367
2368static bool mlx4_en_gso_check(struct sk_buff *skb, struct net_device *dev) 2368static netdev_features_t mlx4_en_features_check(struct sk_buff *skb,
2369 struct net_device *dev,
2370 netdev_features_t features)
2369{ 2371{
2370 return vxlan_gso_check(skb); 2372 return vxlan_features_check(skb, features);
2371} 2373}
2372#endif 2374#endif
2373 2375
@@ -2400,7 +2402,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
2400#ifdef CONFIG_MLX4_EN_VXLAN 2402#ifdef CONFIG_MLX4_EN_VXLAN
2401 .ndo_add_vxlan_port = mlx4_en_add_vxlan_port, 2403 .ndo_add_vxlan_port = mlx4_en_add_vxlan_port,
2402 .ndo_del_vxlan_port = mlx4_en_del_vxlan_port, 2404 .ndo_del_vxlan_port = mlx4_en_del_vxlan_port,
2403 .ndo_gso_check = mlx4_en_gso_check, 2405 .ndo_features_check = mlx4_en_features_check,
2404#endif 2406#endif
2405}; 2407};
2406 2408
@@ -2434,7 +2436,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
2434#ifdef CONFIG_MLX4_EN_VXLAN 2436#ifdef CONFIG_MLX4_EN_VXLAN
2435 .ndo_add_vxlan_port = mlx4_en_add_vxlan_port, 2437 .ndo_add_vxlan_port = mlx4_en_add_vxlan_port,
2436 .ndo_del_vxlan_port = mlx4_en_del_vxlan_port, 2438 .ndo_del_vxlan_port = mlx4_en_del_vxlan_port,
2437 .ndo_gso_check = mlx4_en_gso_check, 2439 .ndo_features_check = mlx4_en_features_check,
2438#endif 2440#endif
2439}; 2441};
2440 2442
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 1aa25b13ace1..9929b97cfb36 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -505,9 +505,11 @@ static void qlcnic_del_vxlan_port(struct net_device *netdev,
505 adapter->flags |= QLCNIC_DEL_VXLAN_PORT; 505 adapter->flags |= QLCNIC_DEL_VXLAN_PORT;
506} 506}
507 507
508static bool qlcnic_gso_check(struct sk_buff *skb, struct net_device *dev) 508static netdev_features_t qlcnic_features_check(struct sk_buff *skb,
509 struct net_device *dev,
510 netdev_features_t features)
509{ 511{
510 return vxlan_gso_check(skb); 512 return vxlan_features_check(skb, features);
511} 513}
512#endif 514#endif
513 515
@@ -532,7 +534,7 @@ static const struct net_device_ops qlcnic_netdev_ops = {
532#ifdef CONFIG_QLCNIC_VXLAN 534#ifdef CONFIG_QLCNIC_VXLAN
533 .ndo_add_vxlan_port = qlcnic_add_vxlan_port, 535 .ndo_add_vxlan_port = qlcnic_add_vxlan_port,
534 .ndo_del_vxlan_port = qlcnic_del_vxlan_port, 536 .ndo_del_vxlan_port = qlcnic_del_vxlan_port,
535 .ndo_gso_check = qlcnic_gso_check, 537 .ndo_features_check = qlcnic_features_check,
536#endif 538#endif
537#ifdef CONFIG_NET_POLL_CONTROLLER 539#ifdef CONFIG_NET_POLL_CONTROLLER
538 .ndo_poll_controller = qlcnic_poll_controller, 540 .ndo_poll_controller = qlcnic_poll_controller,
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c31f74d76ebd..679e6e90aa4c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1012,12 +1012,15 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
1012 * Callback to use for xmit over the accelerated station. This 1012 * Callback to use for xmit over the accelerated station. This
1013 * is used in place of ndo_start_xmit on accelerated net 1013 * is used in place of ndo_start_xmit on accelerated net
1014 * devices. 1014 * devices.
1015 * bool (*ndo_gso_check) (struct sk_buff *skb, 1015 * netdev_features_t (*ndo_features_check) (struct sk_buff *skb,
1016 * struct net_device *dev); 1016 * struct net_device *dev
1017 * netdev_features_t features);
1017 * Called by core transmit path to determine if device is capable of 1018 * Called by core transmit path to determine if device is capable of
1018 * performing GSO on a packet. The device returns true if it is 1019 * performing offload operations on a given packet. This is to give
1019 * able to GSO the packet, false otherwise. If the return value is 1020 * the device an opportunity to implement any restrictions that cannot
1020 * false the stack will do software GSO. 1021 * be otherwise expressed by feature flags. The check is called with
1022 * the set of features that the stack has calculated and it returns
1023 * those the driver believes to be appropriate.
1021 * 1024 *
1022 * int (*ndo_switch_parent_id_get)(struct net_device *dev, 1025 * int (*ndo_switch_parent_id_get)(struct net_device *dev,
1023 * struct netdev_phys_item_id *psid); 1026 * struct netdev_phys_item_id *psid);
@@ -1178,8 +1181,9 @@ struct net_device_ops {
1178 struct net_device *dev, 1181 struct net_device *dev,
1179 void *priv); 1182 void *priv);
1180 int (*ndo_get_lock_subclass)(struct net_device *dev); 1183 int (*ndo_get_lock_subclass)(struct net_device *dev);
1181 bool (*ndo_gso_check) (struct sk_buff *skb, 1184 netdev_features_t (*ndo_features_check) (struct sk_buff *skb,
1182 struct net_device *dev); 1185 struct net_device *dev,
1186 netdev_features_t features);
1183#ifdef CONFIG_NET_SWITCHDEV 1187#ifdef CONFIG_NET_SWITCHDEV
1184 int (*ndo_switch_parent_id_get)(struct net_device *dev, 1188 int (*ndo_switch_parent_id_get)(struct net_device *dev,
1185 struct netdev_phys_item_id *psid); 1189 struct netdev_phys_item_id *psid);
@@ -3611,8 +3615,6 @@ static inline bool netif_needs_gso(struct net_device *dev, struct sk_buff *skb,
3611 netdev_features_t features) 3615 netdev_features_t features)
3612{ 3616{
3613 return skb_is_gso(skb) && (!skb_gso_ok(skb, features) || 3617 return skb_is_gso(skb) && (!skb_gso_ok(skb, features) ||
3614 (dev->netdev_ops->ndo_gso_check &&
3615 !dev->netdev_ops->ndo_gso_check(skb, dev)) ||
3616 unlikely((skb->ip_summed != CHECKSUM_PARTIAL) && 3618 unlikely((skb->ip_summed != CHECKSUM_PARTIAL) &&
3617 (skb->ip_summed != CHECKSUM_UNNECESSARY))); 3619 (skb->ip_summed != CHECKSUM_UNNECESSARY)));
3618} 3620}
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index 57cccd0052e5..903461aa5644 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -1,6 +1,9 @@
1#ifndef __NET_VXLAN_H 1#ifndef __NET_VXLAN_H
2#define __NET_VXLAN_H 1 2#define __NET_VXLAN_H 1
3 3
4#include <linux/ip.h>
5#include <linux/ipv6.h>
6#include <linux/if_vlan.h>
4#include <linux/skbuff.h> 7#include <linux/skbuff.h>
5#include <linux/netdevice.h> 8#include <linux/netdevice.h>
6#include <linux/udp.h> 9#include <linux/udp.h>
@@ -51,16 +54,33 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
51 __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, 54 __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
52 __be16 src_port, __be16 dst_port, __be32 vni, bool xnet); 55 __be16 src_port, __be16 dst_port, __be32 vni, bool xnet);
53 56
54static inline bool vxlan_gso_check(struct sk_buff *skb) 57static inline netdev_features_t vxlan_features_check(struct sk_buff *skb,
58 netdev_features_t features)
55{ 59{
56 if ((skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL) && 60 u8 l4_hdr = 0;
61
62 if (!skb->encapsulation)
63 return features;
64
65 switch (vlan_get_protocol(skb)) {
66 case htons(ETH_P_IP):
67 l4_hdr = ip_hdr(skb)->protocol;
68 break;
69 case htons(ETH_P_IPV6):
70 l4_hdr = ipv6_hdr(skb)->nexthdr;
71 break;
72 default:
73 return features;;
74 }
75
76 if ((l4_hdr == IPPROTO_UDP) &&
57 (skb->inner_protocol_type != ENCAP_TYPE_ETHER || 77 (skb->inner_protocol_type != ENCAP_TYPE_ETHER ||
58 skb->inner_protocol != htons(ETH_P_TEB) || 78 skb->inner_protocol != htons(ETH_P_TEB) ||
59 (skb_inner_mac_header(skb) - skb_transport_header(skb) != 79 (skb_inner_mac_header(skb) - skb_transport_header(skb) !=
60 sizeof(struct udphdr) + sizeof(struct vxlanhdr)))) 80 sizeof(struct udphdr) + sizeof(struct vxlanhdr))))
61 return false; 81 return features & ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK);
62 82
63 return true; 83 return features;
64} 84}
65 85
66/* IP header + UDP + VXLAN + Ethernet header */ 86/* IP header + UDP + VXLAN + Ethernet header */
diff --git a/net/core/dev.c b/net/core/dev.c
index 0094562b732a..683d493aa1bf 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2563,7 +2563,7 @@ static netdev_features_t harmonize_features(struct sk_buff *skb,
2563 2563
2564netdev_features_t netif_skb_features(struct sk_buff *skb) 2564netdev_features_t netif_skb_features(struct sk_buff *skb)
2565{ 2565{
2566 const struct net_device *dev = skb->dev; 2566 struct net_device *dev = skb->dev;
2567 netdev_features_t features = dev->features; 2567 netdev_features_t features = dev->features;
2568 u16 gso_segs = skb_shinfo(skb)->gso_segs; 2568 u16 gso_segs = skb_shinfo(skb)->gso_segs;
2569 __be16 protocol = skb->protocol; 2569 __be16 protocol = skb->protocol;
@@ -2571,13 +2571,20 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
2571 if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs) 2571 if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs)
2572 features &= ~NETIF_F_GSO_MASK; 2572 features &= ~NETIF_F_GSO_MASK;
2573 2573
2574 /* If encapsulation offload request, verify we are testing
2575 * hardware encapsulation features instead of standard
2576 * features for the netdev
2577 */
2578 if (skb->encapsulation)
2579 features &= dev->hw_enc_features;
2580
2574 if (!vlan_tx_tag_present(skb)) { 2581 if (!vlan_tx_tag_present(skb)) {
2575 if (unlikely(protocol == htons(ETH_P_8021Q) || 2582 if (unlikely(protocol == htons(ETH_P_8021Q) ||
2576 protocol == htons(ETH_P_8021AD))) { 2583 protocol == htons(ETH_P_8021AD))) {
2577 struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; 2584 struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
2578 protocol = veh->h_vlan_encapsulated_proto; 2585 protocol = veh->h_vlan_encapsulated_proto;
2579 } else { 2586 } else {
2580 return harmonize_features(skb, features); 2587 goto finalize;
2581 } 2588 }
2582 } 2589 }
2583 2590
@@ -2595,6 +2602,11 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
2595 NETIF_F_HW_VLAN_CTAG_TX | 2602 NETIF_F_HW_VLAN_CTAG_TX |
2596 NETIF_F_HW_VLAN_STAG_TX); 2603 NETIF_F_HW_VLAN_STAG_TX);
2597 2604
2605finalize:
2606 if (dev->netdev_ops->ndo_features_check)
2607 features &= dev->netdev_ops->ndo_features_check(skb, dev,
2608 features);
2609
2598 return harmonize_features(skb, features); 2610 return harmonize_features(skb, features);
2599} 2611}
2600EXPORT_SYMBOL(netif_skb_features); 2612EXPORT_SYMBOL(netif_skb_features);
@@ -2665,13 +2677,6 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device
2665 if (unlikely(!skb)) 2677 if (unlikely(!skb))
2666 goto out_null; 2678 goto out_null;
2667 2679
2668 /* If encapsulation offload request, verify we are testing
2669 * hardware encapsulation features instead of standard
2670 * features for the netdev
2671 */
2672 if (skb->encapsulation)
2673 features &= dev->hw_enc_features;
2674
2675 if (netif_needs_gso(dev, skb, features)) { 2680 if (netif_needs_gso(dev, skb, features)) {
2676 struct sk_buff *segs; 2681 struct sk_buff *segs;
2677 2682