aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-07-16 06:28:06 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-16 06:28:06 -0400
commit80d0a69fc57715dc9080c0567df1ed911b78abea (patch)
treefeb310b5075d3a4f118fcdde7bc44970b1c3f07e /net/ipv4
parent141e369de698f2e17bf716b83fcc647ddcb2220c (diff)
ipv4: Add helper inet_csk_update_pmtu().
This abstracts away the call to dst_ops->update_pmtu() so that we can transparently handle the fact that, in the future, the dst itself can be invalidated by the PMTU update (when we have non-host routes cached in sockets). So we try to rebuild the socket cached route after the method invocation if necessary. This isn't used by SCTP because it needs to cache dsts per-transport, and thus will need it's own local version of this helper. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/inet_connection_sock.c46
-rw-r--r--net/ipv4/tcp_ipv4.c11
2 files changed, 48 insertions, 9 deletions
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 76825be3b643..200d21809379 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -803,3 +803,49 @@ int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
803} 803}
804EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt); 804EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt);
805#endif 805#endif
806
807static struct dst_entry *inet_csk_rebuild_route(struct sock *sk, struct flowi *fl)
808{
809 struct inet_sock *inet = inet_sk(sk);
810 struct ip_options_rcu *inet_opt;
811 __be32 daddr = inet->inet_daddr;
812 struct flowi4 *fl4;
813 struct rtable *rt;
814
815 rcu_read_lock();
816 inet_opt = rcu_dereference(inet->inet_opt);
817 if (inet_opt && inet_opt->opt.srr)
818 daddr = inet_opt->opt.faddr;
819 fl4 = &fl->u.ip4;
820 rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr,
821 inet->inet_saddr, inet->inet_dport,
822 inet->inet_sport, sk->sk_protocol,
823 RT_CONN_FLAGS(sk), sk->sk_bound_dev_if);
824 if (IS_ERR(rt))
825 rt = NULL;
826 if (rt)
827 sk_setup_caps(sk, &rt->dst);
828 rcu_read_unlock();
829
830 return &rt->dst;
831}
832
833struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu)
834{
835 struct dst_entry *dst = __sk_dst_check(sk, 0);
836 struct inet_sock *inet = inet_sk(sk);
837
838 if (!dst) {
839 dst = inet_csk_rebuild_route(sk, &inet->cork.fl);
840 if (!dst)
841 goto out;
842 }
843 dst->ops->update_pmtu(dst, mtu);
844
845 dst = __sk_dst_check(sk, 0);
846 if (!dst)
847 dst = inet_csk_rebuild_route(sk, &inet->cork.fl);
848out:
849 return dst;
850}
851EXPORT_SYMBOL_GPL(inet_csk_update_pmtu);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 7a0062cb4ed0..b8e7e0595407 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -289,17 +289,10 @@ static void do_pmtu_discovery(struct sock *sk, const struct iphdr *iph, u32 mtu)
289 if (sk->sk_state == TCP_LISTEN) 289 if (sk->sk_state == TCP_LISTEN)
290 return; 290 return;
291 291
292 /* We don't check in the destentry if pmtu discovery is forbidden 292 dst = inet_csk_update_pmtu(sk, mtu);
293 * on this route. We just assume that no packet_to_big packets 293 if (!dst)
294 * are send back when pmtu discovery is not active.
295 * There is a small race when the user changes this flag in the
296 * route, but I think that's acceptable.
297 */
298 if ((dst = __sk_dst_check(sk, 0)) == NULL)
299 return; 294 return;
300 295
301 dst->ops->update_pmtu(dst, mtu);
302
303 /* Something is about to be wrong... Remember soft error 296 /* Something is about to be wrong... Remember soft error
304 * for the case, if this connection will not able to recover. 297 * for the case, if this connection will not able to recover.
305 */ 298 */