Commit 1f49cc6f authored by Lance Richardson's avatar Lance Richardson Committed by Greg Kroah-Hartman

ipv4: allow local fragmentation in ip_finish_output_gso()

[ Upstream commit 9ee6c5dc ]

Some configurations (e.g. geneve interface with default
MTU of 1500 over an ethernet interface with 1500 MTU) result
in the transmission of packets that exceed the configured MTU.
While this should be considered to be a "bad" configuration,
it is still allowed and should not result in the sending
of packets that exceed the configured MTU.

Fix by dropping the assumption in ip_finish_output_gso() that
locally originated gso packets will never need fragmentation.
Basic testing using iperf (observing CPU usage and bandwidth)
have shown no measurable performance impact for traffic not
requiring fragmentation.

Fixes: c7ba65d7 ("net: ip: push gso skb forwarding handling down the stack")
Reported-by: default avatarJan Tluka <jtluka@redhat.com>
Signed-off-by: default avatarLance Richardson <lrichard@redhat.com>
Acked-by: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 842a858f
...@@ -47,7 +47,6 @@ struct inet_skb_parm { ...@@ -47,7 +47,6 @@ struct inet_skb_parm {
#define IPSKB_REROUTED BIT(4) #define IPSKB_REROUTED BIT(4)
#define IPSKB_DOREDIRECT BIT(5) #define IPSKB_DOREDIRECT BIT(5)
#define IPSKB_FRAG_PMTU BIT(6) #define IPSKB_FRAG_PMTU BIT(6)
#define IPSKB_FRAG_SEGS BIT(7)
u16 frag_max_size; u16 frag_max_size;
}; };
......
...@@ -117,7 +117,7 @@ int ip_forward(struct sk_buff *skb) ...@@ -117,7 +117,7 @@ int ip_forward(struct sk_buff *skb)
if (opt->is_strictroute && rt->rt_uses_gateway) if (opt->is_strictroute && rt->rt_uses_gateway)
goto sr_failed; goto sr_failed;
IPCB(skb)->flags |= IPSKB_FORWARDED | IPSKB_FRAG_SEGS; IPCB(skb)->flags |= IPSKB_FORWARDED;
mtu = ip_dst_mtu_maybe_forward(&rt->dst, true); mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);
if (ip_exceeds_mtu(skb, mtu)) { if (ip_exceeds_mtu(skb, mtu)) {
IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
......
...@@ -223,11 +223,9 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk, ...@@ -223,11 +223,9 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk,
struct sk_buff *segs; struct sk_buff *segs;
int ret = 0; int ret = 0;
/* common case: fragmentation of segments is not allowed, /* common case: seglen is <= mtu
* or seglen is <= mtu
*/ */
if (((IPCB(skb)->flags & IPSKB_FRAG_SEGS) == 0) || if (skb_gso_validate_mtu(skb, mtu))
skb_gso_validate_mtu(skb, mtu))
return ip_finish_output2(net, sk, skb); return ip_finish_output2(net, sk, skb);
/* Slowpath - GSO segment length is exceeding the dst MTU. /* Slowpath - GSO segment length is exceeding the dst MTU.
......
...@@ -63,7 +63,6 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, ...@@ -63,7 +63,6 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
int pkt_len = skb->len - skb_inner_network_offset(skb); int pkt_len = skb->len - skb_inner_network_offset(skb);
struct net *net = dev_net(rt->dst.dev); struct net *net = dev_net(rt->dst.dev);
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
int skb_iif = skb->skb_iif;
struct iphdr *iph; struct iphdr *iph;
int err; int err;
...@@ -73,16 +72,6 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, ...@@ -73,16 +72,6 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
skb_dst_set(skb, &rt->dst); skb_dst_set(skb, &rt->dst);
memset(IPCB(skb), 0, sizeof(*IPCB(skb))); memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
if (skb_iif && !(df & htons(IP_DF))) {
/* Arrived from an ingress interface, got encapsulated, with
* fragmentation of encapulating frames allowed.
* If skb is gso, the resulting encapsulated network segments
* may exceed dst mtu.
* Allow IP Fragmentation of segments.
*/
IPCB(skb)->flags |= IPSKB_FRAG_SEGS;
}
/* Push down and install the IP header. */ /* Push down and install the IP header. */
skb_push(skb, sizeof(struct iphdr)); skb_push(skb, sizeof(struct iphdr));
skb_reset_network_header(skb); skb_reset_network_header(skb);
......
...@@ -1749,7 +1749,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, ...@@ -1749,7 +1749,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
vif->dev->stats.tx_bytes += skb->len; vif->dev->stats.tx_bytes += skb->len;
} }
IPCB(skb)->flags |= IPSKB_FORWARDED | IPSKB_FRAG_SEGS; IPCB(skb)->flags |= IPSKB_FORWARDED;
/* RFC1584 teaches, that DVMRP/PIM router must deliver packets locally /* RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
* not only before forwarding, but after forwarding on all output * not only before forwarding, but after forwarding on all output
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment