]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/ipv4/datagram.c
net: Save TX flow hash in sock and set in skbuf on xmit
[karo-tx-linux.git] / net / ipv4 / datagram.c
index 8b5134c582f147a94938c34a01dd0691c288bb78..90c0e8386116177f4bbf412f2175aec93c64870c 100644 (file)
@@ -76,6 +76,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        inet->inet_daddr = fl4->daddr;
        inet->inet_dport = usin->sin_port;
        sk->sk_state = TCP_ESTABLISHED;
+       inet_set_txhash(sk);
        inet->inet_id = jiffies;
 
        sk_dst_set(sk, &rt->dst);
@@ -86,18 +87,26 @@ out:
 }
 EXPORT_SYMBOL(ip4_datagram_connect);
 
+/* Because UDP xmit path can manipulate sk_dst_cache without holding
+ * socket lock, we need to use sk_dst_set() here,
+ * even if we own the socket lock.
+ */
 void ip4_datagram_release_cb(struct sock *sk)
 {
        const struct inet_sock *inet = inet_sk(sk);
        const struct ip_options_rcu *inet_opt;
        __be32 daddr = inet->inet_daddr;
+       struct dst_entry *dst;
        struct flowi4 fl4;
        struct rtable *rt;
 
-       if (! __sk_dst_get(sk) || __sk_dst_check(sk, 0))
-               return;
-
        rcu_read_lock();
+
+       dst = __sk_dst_get(sk);
+       if (!dst || !dst->obsolete || dst->ops->check(dst, 0)) {
+               rcu_read_unlock();
+               return;
+       }
        inet_opt = rcu_dereference(inet->inet_opt);
        if (inet_opt && inet_opt->opt.srr)
                daddr = inet_opt->opt.faddr;
@@ -105,8 +114,10 @@ void ip4_datagram_release_cb(struct sock *sk)
                                   inet->inet_saddr, inet->inet_dport,
                                   inet->inet_sport, sk->sk_protocol,
                                   RT_CONN_FLAGS(sk), sk->sk_bound_dev_if);
-       if (!IS_ERR(rt))
-               __sk_dst_set(sk, &rt->dst);
+
+       dst = !IS_ERR(rt) ? &rt->dst : NULL;
+       sk_dst_set(sk, dst);
+
        rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ip4_datagram_release_cb);