diff options
-rw-r--r-- | include/linux/skbuff.h | 14 | ||||
-rw-r--r-- | net/bridge/br_forward.c | 2 | ||||
-rw-r--r-- | net/core/skbuff.c | 8 | ||||
-rw-r--r-- | net/ipv4/ip_forward.c | 3 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 3 |
5 files changed, 29 insertions, 1 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 299ec4b31412..2220b9e2dab0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -1702,6 +1702,20 @@ static inline int skb_is_gso_v6(const struct sk_buff *skb) | |||
1702 | return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6; | 1702 | return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6; |
1703 | } | 1703 | } |
1704 | 1704 | ||
1705 | extern void __skb_warn_lro_forwarding(const struct sk_buff *skb); | ||
1706 | |||
1707 | static inline bool skb_warn_if_lro(const struct sk_buff *skb) | ||
1708 | { | ||
1709 | /* LRO sets gso_size but not gso_type, whereas if GSO is really | ||
1710 | * wanted then gso_type will be set. */ | ||
1711 | struct skb_shared_info *shinfo = skb_shinfo(skb); | ||
1712 | if (shinfo->gso_size != 0 && unlikely(shinfo->gso_type == 0)) { | ||
1713 | __skb_warn_lro_forwarding(skb); | ||
1714 | return true; | ||
1715 | } | ||
1716 | return false; | ||
1717 | } | ||
1718 | |||
1705 | static inline void skb_forward_csum(struct sk_buff *skb) | 1719 | static inline void skb_forward_csum(struct sk_buff *skb) |
1706 | { | 1720 | { |
1707 | /* Unfortunately we don't support this one. Any brave souls? */ | 1721 | /* Unfortunately we don't support this one. Any brave souls? */ |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 512645727f51..bdd9ccea17ce 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -89,7 +89,7 @@ void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) | |||
89 | /* called with rcu_read_lock */ | 89 | /* called with rcu_read_lock */ |
90 | void br_forward(const struct net_bridge_port *to, struct sk_buff *skb) | 90 | void br_forward(const struct net_bridge_port *to, struct sk_buff *skb) |
91 | { | 91 | { |
92 | if (should_deliver(to, skb)) { | 92 | if (!skb_warn_if_lro(skb) && should_deliver(to, skb)) { |
93 | __br_forward(to, skb); | 93 | __br_forward(to, skb); |
94 | return; | 94 | return; |
95 | } | 95 | } |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3e18f8525e82..2df012be973d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -2583,6 +2583,13 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off) | |||
2583 | return true; | 2583 | return true; |
2584 | } | 2584 | } |
2585 | 2585 | ||
2586 | void __skb_warn_lro_forwarding(const struct sk_buff *skb) | ||
2587 | { | ||
2588 | if (net_ratelimit()) | ||
2589 | pr_warning("%s: received packets cannot be forwarded" | ||
2590 | " while LRO is enabled\n", skb->dev->name); | ||
2591 | } | ||
2592 | |||
2586 | EXPORT_SYMBOL(___pskb_trim); | 2593 | EXPORT_SYMBOL(___pskb_trim); |
2587 | EXPORT_SYMBOL(__kfree_skb); | 2594 | EXPORT_SYMBOL(__kfree_skb); |
2588 | EXPORT_SYMBOL(kfree_skb); | 2595 | EXPORT_SYMBOL(kfree_skb); |
@@ -2616,6 +2623,7 @@ EXPORT_SYMBOL(skb_seq_read); | |||
2616 | EXPORT_SYMBOL(skb_abort_seq_read); | 2623 | EXPORT_SYMBOL(skb_abort_seq_read); |
2617 | EXPORT_SYMBOL(skb_find_text); | 2624 | EXPORT_SYMBOL(skb_find_text); |
2618 | EXPORT_SYMBOL(skb_append_datato_frags); | 2625 | EXPORT_SYMBOL(skb_append_datato_frags); |
2626 | EXPORT_SYMBOL(__skb_warn_lro_forwarding); | ||
2619 | 2627 | ||
2620 | EXPORT_SYMBOL_GPL(skb_to_sgvec); | 2628 | EXPORT_SYMBOL_GPL(skb_to_sgvec); |
2621 | EXPORT_SYMBOL_GPL(skb_cow_data); | 2629 | EXPORT_SYMBOL_GPL(skb_cow_data); |
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 37d36a3f33cd..da14725916d3 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c | |||
@@ -56,6 +56,9 @@ int ip_forward(struct sk_buff *skb) | |||
56 | struct rtable *rt; /* Route we use */ | 56 | struct rtable *rt; /* Route we use */ |
57 | struct ip_options * opt = &(IPCB(skb)->opt); | 57 | struct ip_options * opt = &(IPCB(skb)->opt); |
58 | 58 | ||
59 | if (skb_warn_if_lro(skb)) | ||
60 | goto drop; | ||
61 | |||
59 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) | 62 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) |
60 | goto drop; | 63 | goto drop; |
61 | 64 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 40a2813a63d1..fd7cd1bfe151 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -407,6 +407,9 @@ int ip6_forward(struct sk_buff *skb) | |||
407 | if (ipv6_devconf.forwarding == 0) | 407 | if (ipv6_devconf.forwarding == 0) |
408 | goto error; | 408 | goto error; |
409 | 409 | ||
410 | if (skb_warn_if_lro(skb)) | ||
411 | goto drop; | ||
412 | |||
410 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { | 413 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { |
411 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); | 414 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
412 | goto drop; | 415 | goto drop; |