]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipv4: Define inet_sk_init_flowi4() and use it in inet_sk_rebuild_header().
authorGuillaume Nault <gnault@redhat.com>
Mon, 16 Dec 2024 17:21:44 +0000 (18:21 +0100)
committerJakub Kicinski <kuba@kernel.org>
Fri, 20 Dec 2024 21:50:09 +0000 (13:50 -0800)
IPv4 code commonly has to initialise a flowi4 structure from an IPv4
socket. This requires looking at potential IPv4 options to set the
proper destination address, call flowi4_init_output() with the correct
set of parameters and run the sk_classify_flow security hook.

Instead of reimplementing these operations in different parts of the
stack, let's define inet_sk_init_flowi4() which does all these
operations.

The first user is inet_sk_rebuild_header(), where inet_sk_init_flowi4()
replaces ip_route_output_ports(). Unlike ip_route_output_ports(), which
sets the flowi4 structure and performs the route lookup in one go,
inet_sk_init_flowi4() only initialises the flow. The route lookup is
then done by ip_route_output_flow(). Decoupling flow initialisation
from route lookup makes this new interface applicable more broadly as
it will allow some users to overwrite specific struct flowi4 members
before the route lookup.

Signed-off-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/fd416275262b1f518d5abfcef740ce4f4a1a6522.1734357769.git.gnault@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/route.h
net/ipv4/af_inet.c

index 6947a155d50117e1b08705f2baae56073c0c6aaf..f86775be3e2934697533a61f566aca1ef196d74e 100644 (file)
@@ -28,6 +28,7 @@
 #include <net/arp.h>
 #include <net/ndisc.h>
 #include <net/inet_dscp.h>
+#include <net/sock.h>
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/rcupdate.h>
@@ -129,6 +130,33 @@ struct in_device;
 int ip_rt_init(void);
 void rt_cache_flush(struct net *net);
 void rt_flush_dev(struct net_device *dev);
+
+static inline void inet_sk_init_flowi4(const struct inet_sock *inet,
+                                      struct flowi4 *fl4)
+{
+       const struct ip_options_rcu *ip4_opt;
+       const struct sock *sk;
+       __be32 daddr;
+
+       rcu_read_lock();
+       ip4_opt = rcu_dereference(inet->inet_opt);
+
+       /* Source routing option overrides the socket destination address */
+       if (ip4_opt && ip4_opt->opt.srr)
+               daddr = ip4_opt->opt.faddr;
+       else
+               daddr = inet->inet_daddr;
+       rcu_read_unlock();
+
+       sk = &inet->sk;
+       flowi4_init_output(fl4, sk->sk_bound_dev_if, READ_ONCE(sk->sk_mark),
+                          ip_sock_rt_tos(sk), ip_sock_rt_scope(sk),
+                          sk->sk_protocol, inet_sk_flowi_flags(sk), daddr,
+                          inet->inet_saddr, inet->inet_dport,
+                          inet->inet_sport, sk->sk_uid);
+       security_sk_classify_flow(sk, flowi4_to_flowi_common(fl4));
+}
+
 struct rtable *ip_route_output_key_hash(struct net *net, struct flowi4 *flp,
                                        const struct sk_buff *skb);
 struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *flp,
index 8095e82de8083d6f4c9ffacf497d6c4a1a3b3d84..21f46ee7b6e95329a2f7f0e0429eebf1648e7f9d 100644 (file)
@@ -1309,8 +1309,6 @@ int inet_sk_rebuild_header(struct sock *sk)
 {
        struct rtable *rt = dst_rtable(__sk_dst_check(sk, 0));
        struct inet_sock *inet = inet_sk(sk);
-       __be32 daddr;
-       struct ip_options_rcu *inet_opt;
        struct flowi4 *fl4;
        int err;
 
@@ -1319,17 +1317,9 @@ int inet_sk_rebuild_header(struct sock *sk)
                return 0;
 
        /* Reroute. */
-       rcu_read_lock();
-       inet_opt = rcu_dereference(inet->inet_opt);
-       daddr = inet->inet_daddr;
-       if (inet_opt && inet_opt->opt.srr)
-               daddr = inet_opt->opt.faddr;
-       rcu_read_unlock();
        fl4 = &inet->cork.fl.u.ip4;
-       rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr,
-                                  inet->inet_dport, inet->inet_sport,
-                                  sk->sk_protocol, ip_sock_rt_tos(sk),
-                                  sk->sk_bound_dev_if);
+       inet_sk_init_flowi4(inet, fl4);
+       rt = ip_route_output_flow(sock_net(sk), fl4, sk);
        if (!IS_ERR(rt)) {
                err = 0;
                sk_setup_caps(sk, &rt->dst);