diff options
| author | Pravin B Shelar <pshelar@nicira.com> | 2013-02-14 04:44:55 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-02-15 15:16:03 -0500 |
| commit | 05e8ef4ab2d8087d360e814d14da20b9f7fb2283 (patch) | |
| tree | f5161c863bff859fd1c52e36d88fe4a10b84af0f | |
| parent | 14bbd6a565e1bcdc240d44687edb93f721cfdf99 (diff) | |
net: factor out skb_mac_gso_segment() from skb_gso_segment()
This function will be used in next GRE_GSO patch. This patch does
not change any functionality. It only exports skb_mac_gso_segment()
function.
[ Use skb_reset_mac_len() -DaveM ]
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/linux/netdevice.h | 2 | ||||
| -rw-r--r-- | net/core/dev.c | 79 |
2 files changed, 50 insertions, 31 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9deb672d999f..920361bc27e7 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
| @@ -2671,6 +2671,8 @@ extern void netdev_upper_dev_unlink(struct net_device *dev, | |||
| 2671 | extern int skb_checksum_help(struct sk_buff *skb); | 2671 | extern int skb_checksum_help(struct sk_buff *skb); |
| 2672 | extern struct sk_buff *__skb_gso_segment(struct sk_buff *skb, | 2672 | extern struct sk_buff *__skb_gso_segment(struct sk_buff *skb, |
| 2673 | netdev_features_t features, bool tx_path); | 2673 | netdev_features_t features, bool tx_path); |
| 2674 | extern struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, | ||
| 2675 | netdev_features_t features); | ||
| 2674 | 2676 | ||
| 2675 | static inline | 2677 | static inline |
| 2676 | struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features) | 2678 | struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features) |
diff --git a/net/core/dev.c b/net/core/dev.c index f44473696b8b..67deae60214c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -2327,37 +2327,20 @@ out: | |||
| 2327 | } | 2327 | } |
| 2328 | EXPORT_SYMBOL(skb_checksum_help); | 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 | |||
| 2340 | /** | 2330 | /** |
| 2341 | * __skb_gso_segment - Perform segmentation on skb. | 2331 | * skb_mac_gso_segment - mac layer segmentation handler. |
| 2342 | * @skb: buffer to segment | 2332 | * @skb: buffer to segment |
| 2343 | * @features: features for the output path (see dev->features) | 2333 | * @features: features for the output path (see dev->features) |
| 2344 | * @tx_path: whether it is called in TX path | ||
| 2345 | * | ||
| 2346 | * This function segments the given skb and returns a list of segments. | ||
| 2347 | * | ||
| 2348 | * It may return NULL if the skb requires no segmentation. This is | ||
| 2349 | * only possible when GSO is used for verifying header integrity. | ||
| 2350 | */ | 2334 | */ |
| 2351 | struct sk_buff *__skb_gso_segment(struct sk_buff *skb, | 2335 | struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, |
| 2352 | netdev_features_t features, bool tx_path) | 2336 | netdev_features_t features) |
| 2353 | { | 2337 | { |
| 2354 | struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); | 2338 | struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); |
| 2355 | struct packet_offload *ptype; | 2339 | struct packet_offload *ptype; |
| 2356 | __be16 type = skb->protocol; | 2340 | __be16 type = skb->protocol; |
| 2357 | int vlan_depth = ETH_HLEN; | ||
| 2358 | int err; | ||
| 2359 | 2341 | ||
| 2360 | while (type == htons(ETH_P_8021Q)) { | 2342 | while (type == htons(ETH_P_8021Q)) { |
| 2343 | int vlan_depth = ETH_HLEN; | ||
| 2361 | struct vlan_hdr *vh; | 2344 | struct vlan_hdr *vh; |
| 2362 | 2345 | ||
| 2363 | if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) | 2346 | if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) |
| @@ -2368,22 +2351,14 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb, | |||
| 2368 | vlan_depth += VLAN_HLEN; | 2351 | vlan_depth += VLAN_HLEN; |
| 2369 | } | 2352 | } |
| 2370 | 2353 | ||
| 2371 | skb_reset_mac_header(skb); | ||
| 2372 | skb->mac_len = skb->network_header - skb->mac_header; | ||
| 2373 | __skb_pull(skb, skb->mac_len); | 2354 | __skb_pull(skb, skb->mac_len); |
| 2374 | 2355 | ||
| 2375 | if (unlikely(skb_needs_check(skb, tx_path))) { | ||
| 2376 | skb_warn_bad_offload(skb); | ||
| 2377 | |||
| 2378 | if (skb_header_cloned(skb) && | ||
| 2379 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | ||
| 2380 | return ERR_PTR(err); | ||
| 2381 | } | ||
| 2382 | |||
| 2383 | rcu_read_lock(); | 2356 | rcu_read_lock(); |
| 2384 | list_for_each_entry_rcu(ptype, &offload_base, list) { | 2357 | list_for_each_entry_rcu(ptype, &offload_base, list) { |
| 2385 | if (ptype->type == type && ptype->callbacks.gso_segment) { | 2358 | if (ptype->type == type && ptype->callbacks.gso_segment) { |
| 2386 | if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { | 2359 | if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { |
| 2360 | int err; | ||
| 2361 | |||
| 2387 | err = ptype->callbacks.gso_send_check(skb); | 2362 | err = ptype->callbacks.gso_send_check(skb); |
| 2388 | segs = ERR_PTR(err); | 2363 | segs = ERR_PTR(err); |
| 2389 | if (err || skb_gso_ok(skb, features)) | 2364 | if (err || skb_gso_ok(skb, features)) |
| @@ -2401,6 +2376,48 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb, | |||
| 2401 | 2376 | ||
| 2402 | return segs; | 2377 | return segs; |
| 2403 | } | 2378 | } |
| 2379 | EXPORT_SYMBOL(skb_mac_gso_segment); | ||
| 2380 | |||
| 2381 | |||
| 2382 | /* openvswitch calls this on rx path, so we need a different check. | ||
| 2383 | */ | ||
| 2384 | static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path) | ||
| 2385 | { | ||
| 2386 | if (tx_path) | ||
| 2387 | return skb->ip_summed != CHECKSUM_PARTIAL; | ||
| 2388 | else | ||
| 2389 | return skb->ip_summed == CHECKSUM_NONE; | ||
| 2390 | } | ||
| 2391 | |||
| 2392 | /** | ||
| 2393 | * __skb_gso_segment - Perform segmentation on skb. | ||
| 2394 | * @skb: buffer to segment | ||
| 2395 | * @features: features for the output path (see dev->features) | ||
| 2396 | * @tx_path: whether it is called in TX path | ||
| 2397 | * | ||
| 2398 | * This function segments the given skb and returns a list of segments. | ||
| 2399 | * | ||
| 2400 | * It may return NULL if the skb requires no segmentation. This is | ||
| 2401 | * only possible when GSO is used for verifying header integrity. | ||
| 2402 | */ | ||
| 2403 | struct sk_buff *__skb_gso_segment(struct sk_buff *skb, | ||
| 2404 | netdev_features_t features, bool tx_path) | ||
| 2405 | { | ||
| 2406 | if (unlikely(skb_needs_check(skb, tx_path))) { | ||
| 2407 | int err; | ||
| 2408 | |||
| 2409 | skb_warn_bad_offload(skb); | ||
| 2410 | |||
| 2411 | if (skb_header_cloned(skb) && | ||
| 2412 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | ||
| 2413 | return ERR_PTR(err); | ||
| 2414 | } | ||
| 2415 | |||
| 2416 | skb_reset_mac_header(skb); | ||
| 2417 | skb_reset_mac_len(skb); | ||
| 2418 | |||
| 2419 | return skb_mac_gso_segment(skb, features); | ||
| 2420 | } | ||
| 2404 | EXPORT_SYMBOL(__skb_gso_segment); | 2421 | EXPORT_SYMBOL(__skb_gso_segment); |
| 2405 | 2422 | ||
| 2406 | /* Take action when hardware reception checksum errors are detected. */ | 2423 | /* Take action when hardware reception checksum errors are detected. */ |
