From 96818159c3c08911330e84f86b3becf71aeeaac8 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Tue, 3 Apr 2018 15:00:08 +0300 Subject: [PATCH] ipv6: allow to cache dst for a connected sk in ip6_sk_dst_lookup_flow() Add 'connected' parameter to ip6_sk_dst_lookup_flow() and update the cache only if ip6_sk_dst_check() returns NULL and a socket is connected. The function is used as before, the new behavior for UDP sockets in udpv6_sendmsg() will be enabled in the next patch. Signed-off-by: Alexey Kodanev Signed-off-by: David S. Miller --- include/net/ipv6.h | 3 ++- net/ipv6/ip6_output.c | 15 ++++++++++++--- net/ipv6/ping.c | 2 +- net/ipv6/udp.c | 2 +- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9b6e7f51b1d4..836f31af1369 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -965,7 +965,8 @@ int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst, struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6, const struct in6_addr *final_dst); struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst); + const struct in6_addr *final_dst, + bool connected); struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *orig_dst); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e6eaa4dd9f60..66a768b7b8fb 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1105,23 +1105,32 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); * @sk: socket which provides the dst cache and route info * @fl6: flow to lookup * @final_dst: final destination address for ipsec lookup + * @connected: whether @sk is connected or not * * This function performs a route lookup on the given flow with the * possibility of using the cached route in the socket if it is valid. * It will take the socket dst lock when operating on the dst cache. * As a result, this function can only be used in process context. * + * In addition, for a connected socket, cache the dst in the socket + * if the current cache is not valid. + * * It returns a valid dst pointer on success, or a pointer encoded * error code. */ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst) + const struct in6_addr *final_dst, + bool connected) { struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); dst = ip6_sk_dst_check(sk, dst, fl6); - if (!dst) - dst = ip6_dst_lookup_flow(sk, fl6, final_dst); + if (dst) + return dst; + + dst = ip6_dst_lookup_flow(sk, fl6, final_dst); + if (connected && !IS_ERR(dst)) + ip6_sk_dst_store_flow(sk, dst_clone(dst), fl6); return dst; } diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index d12c55dad7d1..746eeae7f581 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -121,7 +121,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ipc6.tclass = np->tclass; fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); - dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr); + dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, false); if (IS_ERR(dst)) return PTR_ERR(dst); rt = (struct rt6_info *) dst; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 6861ed479469..fc13a1e2d789 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1308,7 +1308,7 @@ do_udp_sendmsg: fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); - dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p); + dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p, false); if (IS_ERR(dst)) { err = PTR_ERR(dst); dst = NULL; -- 2.30.2