aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-06-15 01:21:46 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-15 01:22:07 -0400
commit36393395536064e483b73d173f6afc103eadfbc4 (patch)
treeb45113cce1bdfc4be92a856700690a253f1bb088
parentb3908e22ad8bb6074934496ef171fd83605d7d3e (diff)
ipv4: Handle PMTU in all ICMP error handlers.
With ip_rt_frag_needed() removed, we have to explicitly update PMTU information in every ICMP error handler. Create two helper functions to facilitate this. 1) ipv4_sk_update_pmtu() This updates the PMTU when we have a socket context to work with. 2) ipv4_update_pmtu() Raw version, used when no socket context is available. For this interface, we essentially just pass in explicit arguments for the flow identity information we would have extracted from the socket. And you'll notice that ipv4_sk_update_pmtu() is simply implemented in terms of ipv4_update_pmtu() Note that __ip_route_output_key() is used, rather than something like ip_route_output_flow() or ip_route_output_key(). This is because we absolutely do not want to end up with a route that does IPSEC encapsulation and the like. Instead, we only want the route that would get us to the node described by the outermost IP header. Reported-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/route.h5
-rw-r--r--net/ipv4/ah4.c1
-rw-r--r--net/ipv4/esp4.c1
-rw-r--r--net/ipv4/ip_gre.c14
-rw-r--r--net/ipv4/ipcomp.c1
-rw-r--r--net/ipv4/ipip.c15
-rw-r--r--net/ipv4/ping.c1
-rw-r--r--net/ipv4/raw.c3
-rw-r--r--net/ipv4/route.c28
-rw-r--r--net/ipv4/udp.c1
-rw-r--r--net/ipv6/sit.c15
11 files changed, 72 insertions, 13 deletions
diff --git a/include/net/route.h b/include/net/route.h
index a36ae429ed5d..47eb25ac1f7f 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -215,7 +215,10 @@ static inline int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 s
215 return ip_route_input_common(skb, dst, src, tos, devin, true); 215 return ip_route_input_common(skb, dst, src, tos, devin, true);
216} 216}
217 217
218extern void ip_rt_send_redirect(struct sk_buff *skb); 218extern void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
219 int oif, u32 mark, u8 protocol, int flow_flags);
220extern void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu);
221extern void ip_rt_send_redirect(struct sk_buff *skb);
219 222
220extern unsigned int inet_addr_type(struct net *net, __be32 addr); 223extern unsigned int inet_addr_type(struct net *net, __be32 addr);
221extern unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr); 224extern unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr);
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index e8f2617ecd47..916d5ecaf6c6 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -408,6 +408,7 @@ static void ah4_err(struct sk_buff *skb, u32 info)
408 return; 408 return;
409 pr_debug("pmtu discovery on SA AH/%08x/%08x\n", 409 pr_debug("pmtu discovery on SA AH/%08x/%08x\n",
410 ntohl(ah->spi), ntohl(iph->daddr)); 410 ntohl(ah->spi), ntohl(iph->daddr));
411 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
411 xfrm_state_put(x); 412 xfrm_state_put(x);
412} 413}
413 414
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index cb982a61536f..7b95b49a36ce 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -494,6 +494,7 @@ static void esp4_err(struct sk_buff *skb, u32 info)
494 return; 494 return;
495 NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n", 495 NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n",
496 ntohl(esph->spi), ntohl(iph->daddr)); 496 ntohl(esph->spi), ntohl(iph->daddr));
497 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
497 xfrm_state_put(x); 498 xfrm_state_put(x);
498} 499}
499 500
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index f49047b79609..594cec35ac4d 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -516,9 +516,6 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
516 case ICMP_PORT_UNREACH: 516 case ICMP_PORT_UNREACH:
517 /* Impossible event. */ 517 /* Impossible event. */
518 return; 518 return;
519 case ICMP_FRAG_NEEDED:
520 /* Soft state for pmtu is maintained by IP core. */
521 return;
522 default: 519 default:
523 /* All others are translated to HOST_UNREACH. 520 /* All others are translated to HOST_UNREACH.
524 rfc2003 contains "deep thoughts" about NET_UNREACH, 521 rfc2003 contains "deep thoughts" about NET_UNREACH,
@@ -538,7 +535,16 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
538 flags & GRE_KEY ? 535 flags & GRE_KEY ?
539 *(((__be32 *)p) + (grehlen / 4) - 1) : 0, 536 *(((__be32 *)p) + (grehlen / 4) - 1) : 0,
540 p[1]); 537 p[1]);
541 if (t == NULL || t->parms.iph.daddr == 0 || 538 if (t == NULL)
539 goto out;
540
541 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
542 ipv4_update_pmtu(skb, dev_net(skb->dev), info,
543 t->parms.link, 0, IPPROTO_GRE, 0);
544 goto out;
545 }
546
547 if (t->parms.iph.daddr == 0 ||
542 ipv4_is_multicast(t->parms.iph.daddr)) 548 ipv4_is_multicast(t->parms.iph.daddr))
543 goto out; 549 goto out;
544 550
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 63b64c45a826..b91375482d84 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -42,6 +42,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
42 return; 42 return;
43 NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI4\n", 43 NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI4\n",
44 spi, &iph->daddr); 44 spi, &iph->daddr);
45 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
45 xfrm_state_put(x); 46 xfrm_state_put(x);
46} 47}
47 48
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 2d0f99bf61b3..715338a1b205 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -348,9 +348,6 @@ static int ipip_err(struct sk_buff *skb, u32 info)
348 case ICMP_PORT_UNREACH: 348 case ICMP_PORT_UNREACH:
349 /* Impossible event. */ 349 /* Impossible event. */
350 return 0; 350 return 0;
351 case ICMP_FRAG_NEEDED:
352 /* Soft state for pmtu is maintained by IP core. */
353 return 0;
354 default: 351 default:
355 /* All others are translated to HOST_UNREACH. 352 /* All others are translated to HOST_UNREACH.
356 rfc2003 contains "deep thoughts" about NET_UNREACH, 353 rfc2003 contains "deep thoughts" about NET_UNREACH,
@@ -369,7 +366,17 @@ static int ipip_err(struct sk_buff *skb, u32 info)
369 366
370 rcu_read_lock(); 367 rcu_read_lock();
371 t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); 368 t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
372 if (t == NULL || t->parms.iph.daddr == 0) 369 if (t == NULL)
370 goto out;
371
372 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
373 ipv4_update_pmtu(skb, dev_net(skb->dev), info,
374 t->dev->ifindex, 0, IPPROTO_IPIP, 0);
375 err = 0;
376 goto out;
377 }
378
379 if (t->parms.iph.daddr == 0)
373 goto out; 380 goto out;
374 381
375 err = 0; 382 err = 0;
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 2c00e8bf684d..340fcf29a966 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -371,6 +371,7 @@ void ping_err(struct sk_buff *skb, u32 info)
371 break; 371 break;
372 case ICMP_DEST_UNREACH: 372 case ICMP_DEST_UNREACH:
373 if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ 373 if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
374 ipv4_sk_update_pmtu(skb, sk, info);
374 if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) { 375 if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
375 err = EMSGSIZE; 376 err = EMSGSIZE;
376 harderr = 1; 377 harderr = 1;
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 4032b818f3e4..659ddfb10947 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -216,6 +216,9 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
216 int err = 0; 216 int err = 0;
217 int harderr = 0; 217 int harderr = 0;
218 218
219 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
220 ipv4_sk_update_pmtu(skb, sk, info);
221
219 /* Report error on raw socket, if: 222 /* Report error on raw socket, if:
220 1. User requested ip_recverr. 223 1. User requested ip_recverr.
221 2. Socket is connected (otherwise the error indication 224 2. Socket is connected (otherwise the error indication
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 655506af47ca..41df5297a412 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1711,6 +1711,34 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
1711 } 1711 }
1712} 1712}
1713 1713
1714void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
1715 int oif, u32 mark, u8 protocol, int flow_flags)
1716{
1717 const struct iphdr *iph = (const struct iphdr *)skb->data;
1718 struct flowi4 fl4;
1719 struct rtable *rt;
1720
1721 flowi4_init_output(&fl4, oif, mark, RT_TOS(iph->tos), RT_SCOPE_UNIVERSE,
1722 protocol, flow_flags | FLOWI_FLAG_PRECOW_METRICS,
1723 iph->daddr, iph->saddr, 0, 0);
1724 rt = __ip_route_output_key(net, &fl4);
1725 if (!IS_ERR(rt)) {
1726 ip_rt_update_pmtu(&rt->dst, mtu);
1727 ip_rt_put(rt);
1728 }
1729}
1730EXPORT_SYMBOL_GPL(ipv4_update_pmtu);
1731
1732void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
1733{
1734 const struct inet_sock *inet = inet_sk(sk);
1735
1736 return ipv4_update_pmtu(skb, sock_net(sk), mtu,
1737 sk->sk_bound_dev_if, sk->sk_mark,
1738 inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
1739 inet_sk_flowi_flags(sk));
1740}
1741EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu);
1714 1742
1715static void ipv4_validate_peer(struct rtable *rt) 1743static void ipv4_validate_peer(struct rtable *rt)
1716{ 1744{
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index eaca73644e79..db017efb76ea 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -615,6 +615,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
615 break; 615 break;
616 case ICMP_DEST_UNREACH: 616 case ICMP_DEST_UNREACH:
617 if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ 617 if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
618 ipv4_sk_update_pmtu(skb, sk, info);
618 if (inet->pmtudisc != IP_PMTUDISC_DONT) { 619 if (inet->pmtudisc != IP_PMTUDISC_DONT) {
619 err = EMSGSIZE; 620 err = EMSGSIZE;
620 harderr = 1; 621 harderr = 1;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 60415711563f..49aea94c9be3 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -527,9 +527,6 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
527 case ICMP_PORT_UNREACH: 527 case ICMP_PORT_UNREACH:
528 /* Impossible event. */ 528 /* Impossible event. */
529 return 0; 529 return 0;
530 case ICMP_FRAG_NEEDED:
531 /* Soft state for pmtu is maintained by IP core. */
532 return 0;
533 default: 530 default:
534 /* All others are translated to HOST_UNREACH. 531 /* All others are translated to HOST_UNREACH.
535 rfc2003 contains "deep thoughts" about NET_UNREACH, 532 rfc2003 contains "deep thoughts" about NET_UNREACH,
@@ -551,7 +548,17 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
551 skb->dev, 548 skb->dev,
552 iph->daddr, 549 iph->daddr,
553 iph->saddr); 550 iph->saddr);
554 if (t == NULL || t->parms.iph.daddr == 0) 551 if (t == NULL)
552 goto out;
553
554 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
555 ipv4_update_pmtu(skb, dev_net(skb->dev), info,
556 t->dev->ifindex, 0, IPPROTO_IPV6, 0);
557 err = 0;
558 goto out;
559 }
560
561 if (t->parms.iph.daddr == 0)
555 goto out; 562 goto out;
556 563
557 err = 0; 564 err = 0;