فهرست منبع

Merge branch 'frag-udp-tunneled-skbs'

Shmulik Ladkani says:

====================
net: Consider fragmentation of udp tunneled skbs in 'ip_finish_output_gso'

Currently IP fragmentation of GSO segments that exceed dst mtu is
considered only in the ipv4 forwarding case.

There are cases where GSO skbs that are bridged and then udp-tunneled
may have gso_size exceeding the egress device mtu.
It makes sense to fragment them, as in the non GSOed code path.

The exact cases where this behavior is needed is described and addressed
in the 2nd patch.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
David S. Miller 9 سال پیش
والد
کامیت
7e0433b395
5فایلهای تغییر یافته به همراه16 افزوده شده و 4 حذف شده
  1. 1 0
      include/net/ip.h
  2. 1 1
      net/ipv4/ip_forward.c
  3. 4 2
      net/ipv4/ip_output.c
  4. 9 0
      net/ipv4/ip_tunnel_core.c
  5. 1 1
      net/ipv4/ipmr.c

+ 1 - 0
include/net/ip.h

@@ -47,6 +47,7 @@ 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;
 };
 };

+ 1 - 1
net/ipv4/ip_forward.c

@@ -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;
+	IPCB(skb)->flags |= IPSKB_FORWARDED | IPSKB_FRAG_SEGS;
 	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);

+ 4 - 2
net/ipv4/ip_output.c

@@ -223,8 +223,10 @@ 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: locally created skb or seglen is <= mtu */
-	if (((IPCB(skb)->flags & IPSKB_FORWARDED) == 0) ||
+	/* common case: fragmentation of segments is not allowed,
+	 * or seglen is <= mtu
+	 */
+	if (((IPCB(skb)->flags & IPSKB_FRAG_SEGS) == 0) ||
 	      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);
 
 

+ 9 - 0
net/ipv4/ip_tunnel_core.c

@@ -63,6 +63,7 @@ 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;
 
 
@@ -72,6 +73,14 @@ 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 && proto == IPPROTO_UDP) {
+		/* Arrived from an ingress interface and got udp encapuslated.
+		 * The encapsulated network segment length 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);

+ 1 - 1
net/ipv4/ipmr.c

@@ -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;
+	IPCB(skb)->flags |= IPSKB_FORWARDED | IPSKB_FRAG_SEGS;
 
 
 	/* 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