Commit 12b0004d1d1e2a9aa667412d479041e403bcafae

Authored by Cong Wang
Committed by David S. Miller
1 parent 25060d8f3f

net: adjust skb_gso_segment() for calling in rx path

skb_gso_segment() is almost always called in tx path,
except for openvswitch. It calls this function when
it receives the packet and tries to queue it to user-space.
In this special case, the ->ip_summed check inside
skb_gso_segment() is no longer true, as ->ip_summed value
has different meanings on rx path.

This patch adjusts skb_gso_segment() so that we can at least
avoid such warnings on checksum.

Cc: Jesse Gross <jesse@nicira.com>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 3 changed files with 26 additions and 8 deletions Side-by-side Diff

include/linux/netdevice.h
... ... @@ -2662,8 +2662,15 @@
2662 2662 extern void netdev_upper_dev_unlink(struct net_device *dev,
2663 2663 struct net_device *upper_dev);
2664 2664 extern int skb_checksum_help(struct sk_buff *skb);
2665   -extern struct sk_buff *skb_gso_segment(struct sk_buff *skb,
2666   - netdev_features_t features);
  2665 +extern struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
  2666 + netdev_features_t features, bool tx_path);
  2667 +
  2668 +static inline
  2669 +struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features)
  2670 +{
  2671 + return __skb_gso_segment(skb, features, true);
  2672 +}
  2673 +
2667 2674 #ifdef CONFIG_BUG
2668 2675 extern void netdev_rx_csum_fault(struct net_device *dev);
2669 2676 #else
... ... @@ -2327,18 +2327,29 @@
2327 2327 }
2328 2328 EXPORT_SYMBOL(skb_checksum_help);
2329 2329  
  2330 +/* openvswitch calls this on rx path, so we need a different check.
  2331 + */
  2332 +static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path)
  2333 +{
  2334 + if (tx_path)
  2335 + return skb->ip_summed != CHECKSUM_PARTIAL;
  2336 + else
  2337 + return skb->ip_summed == CHECKSUM_NONE;
  2338 +}
  2339 +
2330 2340 /**
2331   - * skb_gso_segment - Perform segmentation on skb.
  2341 + * __skb_gso_segment - Perform segmentation on skb.
2332 2342 * @skb: buffer to segment
2333 2343 * @features: features for the output path (see dev->features)
  2344 + * @tx_path: whether it is called in TX path
2334 2345 *
2335 2346 * This function segments the given skb and returns a list of segments.
2336 2347 *
2337 2348 * It may return NULL if the skb requires no segmentation. This is
2338 2349 * only possible when GSO is used for verifying header integrity.
2339 2350 */
2340   -struct sk_buff *skb_gso_segment(struct sk_buff *skb,
2341   - netdev_features_t features)
  2351 +struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
  2352 + netdev_features_t features, bool tx_path)
2342 2353 {
2343 2354 struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
2344 2355 struct packet_offload *ptype;
... ... @@ -2361,7 +2372,7 @@
2361 2372 skb->mac_len = skb->network_header - skb->mac_header;
2362 2373 __skb_pull(skb, skb->mac_len);
2363 2374  
2364   - if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
  2375 + if (unlikely(skb_needs_check(skb, tx_path))) {
2365 2376 skb_warn_bad_offload(skb);
2366 2377  
2367 2378 if (skb_header_cloned(skb) &&
... ... @@ -2390,7 +2401,7 @@
2390 2401  
2391 2402 return segs;
2392 2403 }
2393   -EXPORT_SYMBOL(skb_gso_segment);
  2404 +EXPORT_SYMBOL(__skb_gso_segment);
2394 2405  
2395 2406 /* Take action when hardware reception checksum errors are detected. */
2396 2407 #ifdef CONFIG_BUG
net/openvswitch/datapath.c
... ... @@ -301,7 +301,7 @@
301 301 struct sk_buff *segs, *nskb;
302 302 int err;
303 303  
304   - segs = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM);
  304 + segs = __skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM, false);
305 305 if (IS_ERR(segs))
306 306 return PTR_ERR(segs);
307 307