Commit ae418e95 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'ipv4-consolidate-route-lookups-from-ipv4-sockets'

Guillaume Nault says:

====================
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.
====================

Link: https://patch.msgid.link/cover.1734357769.git.gnault@redhat.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 6ed34721 c63e9f3b
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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,
+2 −12
Original line number Diff line number Diff line
@@ -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);
+2 −9
Original line number Diff line number Diff line
@@ -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);

+2 −9
Original line number Diff line number Diff line
@@ -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)
+4 −12
Original line number Diff line number Diff line
@@ -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);
Loading