ipv4: Consolidate route lookups from IPv4 sockets.
Subsystems (4)
cover ipv4: Consolidate route lookups from IPv4 sockets.
Create inet_sk_init_flowi4() so that the different IPv4 code paths that need to do a route lookup based on an IPv4 socket don't need to reimplement that logic.
Guillaume Nault (5):
ipv4: Define inet_sk_init_flowi4() and use it in
inet_sk_rebuild_header().
ipv4: Use inet_sk_init_flowi4() in ip4_datagram_release_cb().
ipv4: Use inet_sk_init_flowi4() in inet_csk_rebuild_route().
ipv4: Use inet_sk_init_flowi4() in __ip_queue_xmit().
l2tp: Use inet_sk_init_flowi4() in l2tp_ip_sendmsg().
include/net/route.h | 28 ++++++++++++++++++++++++++++ net/ipv4/af_inet.c | 14 ++------------ net/ipv4/datagram.c | 11 ++--------- net/ipv4/inet_connection_sock.c | 11 ++--------- net/ipv4/ip_output.c | 16 ++++------------ net/l2tp/l2tp_ip.c | 19 ++++++------------- 6 files changed, 44 insertions(+), 55 deletions(-)
Signature · 1 line
2.39.2
PATCH 1/5 ipv4: Define inet_sk_init_flowi4() and use it in inet_sk_rebuild_header().
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.
--- include/net/route.h | 28 ++++++++++++++++++++++++++++ net/ipv4/af_inet.c | 14 ++------------ 2 files changed, 30 insertions(+), 12 deletions(-)
include/net/route.h +28 -0
@@ -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,
net/ipv4/af_inet.c +2 -12
@@ -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);
Signature · 1 line
2.39.2
PATCH 2/5 ipv4: Use inet_sk_init_flowi4() in ip4_datagram_release_cb().
In reply to Guillaume NaultUse inet_sk_init_flowi4() to automatically initialise the flowi4 structure in ip4_datagram_release_cb() instead of passing parameters manually to ip_route_output_ports().
--- net/ipv4/datagram.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-)
net/ipv4/datagram.c +2 -9
@@ -102,8 +102,6 @@ EXPORT_SYMBOL(ip4_datagram_connect);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;
@@ -115,14 +113,9 @@ void ip4_datagram_release_cb(struct sock *sk)rcu_read_unlock ();return ; } - inet_opt =rcu_dereference (inet->inet_opt); -if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; - 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); dst = !IS_ERR (rt) ? &rt->dst :NULL ;sk_dst_set (sk, dst);
Signature · 1 line
2.39.2
PATCH 3/5 ipv4: Use inet_sk_init_flowi4() in inet_csk_rebuild_route().
In reply to Guillaume NaultUse inet_sk_init_flowi4() to automatically initialise the flowi4 structure in inet_csk_rebuild_route() instead of passing parameters manually to ip_route_output_ports().
--- net/ipv4/inet_connection_sock.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-)
net/ipv4/inet_connection_sock.c +2 -9
@@ -1561,20 +1561,13 @@ EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr);static struct dst_entry *inet_csk_rebuild_route (struct sock *sk,struct flowi *fl) {const struct inet_sock *inet =inet_sk (sk); -const struct ip_options_rcu *inet_opt; -__be32 daddr = inet->inet_daddr;struct flowi4 *fl4;struct rtable *rt;rcu_read_lock (); - inet_opt =rcu_dereference (inet->inet_opt); -if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; fl4 = &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)) rt =NULL ;if (rt)
Signature · 1 line
2.39.2
PATCH 4/5 ipv4: Use inet_sk_init_flowi4() in __ip_queue_xmit().
In reply to Guillaume NaultUse inet_sk_init_flowi4() to automatically initialise the flowi4 structure in __ip_queue_xmit() instead of passing parameters manually to ip_route_output_ports().
Override ->flowi4_tos with the value passed as parameter since that's required by SCTP.
--- net/ipv4/ip_output.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-)
net/ipv4/ip_output.c +4 -12
@@ -478,24 +478,16 @@ int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,/* Make sure we can route this packet. */ rt =dst_rtable (__sk_dst_check (sk,0 ));if (!rt) { -__be32 daddr; +inet_sk_init_flowi4 (inet, fl4); -/* Use correct destination address if we have options. */ - daddr = inet->inet_daddr; -if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; +/* sctp_v4_xmit() uses its own DSCP value */ + fl4->flowi4_tos = tos &INET_DSCP_MASK ;/* If this fails, retransmit mechanism of transport layer will * keep trying until route appears or the connection times * itself out. */ - rt =ip_route_output_ports (net, fl4, sk, - daddr, inet->inet_saddr, - inet->inet_dport, - inet->inet_sport, - sk->sk_protocol, - tos &INET_DSCP_MASK , - sk->sk_bound_dev_if); + rt =ip_route_output_flow (net, fl4, sk);if (IS_ERR (rt)) goto no_route;sk_setup_caps (sk, &rt->dst);
Signature · 1 line
2.39.2
PATCH 5/5 l2tp: Use inet_sk_init_flowi4() in l2tp_ip_sendmsg().
In reply to Guillaume NaultUse inet_sk_init_flowi4() to automatically initialise the flowi4 structure in l2tp_ip_sendmsg() instead of passing parameters manually to ip_route_output_ports().
Override ->daddr with the value passed in the msghdr structure if provided.
--- net/l2tp/l2tp_ip.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-)
net/l2tp/l2tp_ip.c +6 -13
@@ -425,7 +425,6 @@ static int l2tp_ip_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)int rc;struct inet_sock *inet =inet_sk (sk);struct rtable *rt =NULL ; -struct flowi4 *fl4;int connected =0 ;__be32 daddr;
@@ -455,7 +454,6 @@ static int l2tp_ip_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)if (sk->sk_state !=TCP_ESTABLISHED ) goto out; - daddr = inet->inet_daddr; connected =1 ; }
@@ -482,29 +480,24 @@ static int l2tp_ip_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) goto error; } - fl4 = &inet->cork.fl.u.ip4;if (connected) rt =dst_rtable (__sk_dst_check (sk,0 ));rcu_read_lock ();if (!rt) { -const struct ip_options_rcu *inet_opt; +struct flowi4 *fl4 = &inet->cork.fl.u.ip4; - inet_opt =rcu_dereference (inet->inet_opt); +inet_sk_init_flowi4 (inet, fl4); -/* Use correct destination address if we have options. */ -if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; +/* Overwrite ->daddr if msg->msg_name was provided */ +if (!connected) + fl4->daddr = daddr;/* If this fails, retransmit mechanism of transport layer will * keep trying until route appears or the connection times * itself out. */ - 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); + rt =ip_route_output_flow (sock_net (sk), fl4, sk);if (IS_ERR (rt)) goto no_route;if (connected) {
Signature · 1 line
2.39.2
Re: [PATCH net-next 5/5] l2tp: Use inet_sk_init_flowi4() in l2tp_ip_sendmsg().
Quoted 8 lines · Guillaume Nault
Use
inet_sk_init_flowi4()to automatically initialise the flowi4 structure inl2tp_ip_sendmsg()instead of passing parameters manually toip_route_output_ports().Override ->daddr with the value passed in the msghdr structure if provided.
Signed-off-by Guillaume Nault <[email protected]>
This all looks good to me.
This series was applied to netdev/net-next.git (main) by Jakub Kicinski <[email protected]>:
Hello:
This series was applied to netdev/net-next.git (main) by Jakub Kicinski <[email protected]>:
Quoted 12 lines · On Mon, 16 Dec 2024 18:21:40 +0100 you wrote:
Create
inet_sk_init_flowi4()so that the different IPv4 code paths that need to do a route lookup based on an IPv4 socket don't need to reimplement that logic.Guillaume Nault (5):
ipv4: Defineinet_sk_init_flowi4()and use it in
inet_sk_rebuild_header().
ipv4: Useinet_sk_init_flowi4()inip4_datagram_release_cb().
ipv4: Useinet_sk_init_flowi4()ininet_csk_rebuild_route().
ipv4: Useinet_sk_init_flowi4()in__ip_queue_xmit().
l2tp: Useinet_sk_init_flowi4()inl2tp_ip_sendmsg().
Quoted 1 line
[...]
Here is the summary with links:
- [net-next,1/5] ipv4: Define inet_sk_init_flowi4() and use it in inet_sk_rebuild_header().
https://git.kernel.org/netdev/net-next/c/1dbdce30f040 - [net-next,2/5] ipv4: Use inet_sk_init_flowi4() in ip4_datagram_release_cb(). https://git.kernel.org/netdev/net-next/c/5be1323b5041 - [net-next,3/5] ipv4: Use inet_sk_init_flowi4() in inet_csk_rebuild_route(). https://git.kernel.org/netdev/net-next/c/42e5ffc385f3 - [net-next,4/5] ipv4: Use inet_sk_init_flowi4() in __ip_queue_xmit(). https://git.kernel.org/netdev/net-next/c/148721f8e04a - [net-next,5/5] l2tp: Use inet_sk_init_flowi4() in l2tp_ip_sendmsg(). https://git.kernel.org/netdev/net-next/c/c63e9f3b89d3
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html