summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-04-26 13:28:44 -0700
committerDavid S. Miller <davem@davemloft.net>2011-04-27 13:59:04 -0700
commit2d7192d6cbab20e153c47fa1559ffd41ceef0e79 (patch)
treeaac4c4132f5b4a173ad8f8d0bf24427e039bbc89 /include
parent15ecd039b7182d725f4294e01f2fb12c3a88db17 (diff)
ipv4: Sanitize and simplify ip_route_{connect,newports}()
These functions are used together as a unit for route resolution during connect(). They address the chicken-and-egg problem that exists when ports need to be allocated during connect() processing, yet such port allocations require addressing information from the routing code. It's currently more heavy handed than it needs to be, and in particular we allocate and initialize a flow object twice. Let the callers provide the on-stack flow object. That way we only need to initialize it once in the ip_route_connect() call. Later, if ip_route_newports() needs to do anything, it re-uses that flow object as-is except for the ports which it updates before the route re-lookup. Also, describe why this set of facilities are needed and how it works in a big comment. Signed-off-by: David S. Miller <davem@davemloft.net> Reviewed-by: Eric Dumazet <eric.dumazet@gmail.com>
Diffstat (limited to 'include')
-rw-r--r--include/net/route.h88
1 files changed, 56 insertions, 32 deletions
diff --git a/include/net/route.h b/include/net/route.h
index 3684c3edbae..79530da31b3 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -217,17 +217,37 @@ static inline char rt_tos2priority(u8 tos)
return ip_tos2prio[IPTOS_TOS(tos)>>1];
}
-static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos,
- int oif, u8 protocol,
- __be16 sport, __be16 dport,
- struct sock *sk, bool can_sleep)
+/* ip_route_connect() and ip_route_newports() work in tandem whilst
+ * binding a socket for a new outgoing connection.
+ *
+ * In order to use IPSEC properly, we must, in the end, have a
+ * route that was looked up using all available keys including source
+ * and destination ports.
+ *
+ * However, if a source port needs to be allocated (the user specified
+ * a wildcard source port) we need to obtain addressing information
+ * in order to perform that allocation.
+ *
+ * So ip_route_connect() looks up a route using wildcarded source and
+ * destination ports in the key, simply so that we can get a pair of
+ * addresses to use for port allocation.
+ *
+ * Later, once the ports are allocated, ip_route_newports() will make
+ * another route lookup if needed to make sure we catch any IPSEC
+ * rules keyed on the port information.
+ *
+ * The callers allocate the flow key on their stack, and must pass in
+ * the same flowi4 object to both the ip_route_connect() and the
+ * ip_route_newports() calls.
+ */
+
+static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 src,
+ u32 tos, int oif, u8 protocol,
+ __be16 sport, __be16 dport,
+ struct sock *sk, bool can_sleep)
{
- struct net *net = sock_net(sk);
- struct rtable *rt;
- struct flowi4 fl4;
- __u8 flow_flags;
+ __u8 flow_flags = 0;
- flow_flags = 0;
if (inet_sk(sk)->transparent)
flow_flags |= FLOWI_FLAG_ANYSRC;
if (protocol == IPPROTO_TCP)
@@ -235,41 +255,45 @@ static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos,
if (can_sleep)
flow_flags |= FLOWI_FLAG_CAN_SLEEP;
- flowi4_init_output(&fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE,
+ flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE,
protocol, flow_flags, dst, src, dport, sport);
+}
+
+static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
+ __be32 dst, __be32 src, u32 tos,
+ int oif, u8 protocol,
+ __be16 sport, __be16 dport,
+ struct sock *sk, bool can_sleep)
+{
+ struct net *net = sock_net(sk);
+ struct rtable *rt;
+
+ ip_route_connect_init(fl4, dst, src, tos, oif, protocol,
+ sport, dport, sk, can_sleep);
if (!dst || !src) {
- rt = __ip_route_output_key(net, &fl4);
+ rt = __ip_route_output_key(net, fl4);
if (IS_ERR(rt))
return rt;
- fl4.daddr = rt->rt_dst;
- fl4.saddr = rt->rt_src;
+ fl4->daddr = rt->rt_dst;
+ fl4->saddr = rt->rt_src;
ip_rt_put(rt);
}
- security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
- return ip_route_output_flow(net, &fl4, sk);
+ security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
+ return ip_route_output_flow(net, fl4, sk);
}
-static inline struct rtable *ip_route_newports(struct rtable *rt,
- u8 protocol, __be16 orig_sport,
- __be16 orig_dport, __be16 sport,
- __be16 dport, struct sock *sk)
+static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable *rt,
+ __be16 orig_sport, __be16 orig_dport,
+ __be16 sport, __be16 dport,
+ struct sock *sk)
{
if (sport != orig_sport || dport != orig_dport) {
- struct flowi4 fl4;
- __u8 flow_flags;
-
- flow_flags = 0;
- if (inet_sk(sk)->transparent)
- flow_flags |= FLOWI_FLAG_ANYSRC;
- if (protocol == IPPROTO_TCP)
- flow_flags |= FLOWI_FLAG_PRECOW_METRICS;
- flowi4_init_output(&fl4, rt->rt_oif, rt->rt_mark, rt->rt_tos,
- RT_SCOPE_UNIVERSE, protocol, flow_flags,
- rt->rt_dst, rt->rt_src, dport, sport);
+ fl4->fl4_dport = dport;
+ fl4->fl4_sport = sport;
ip_rt_put(rt);
- security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
- return ip_route_output_flow(sock_net(sk), &fl4, sk);
+ security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
+ return ip_route_output_flow(sock_net(sk), fl4, sk);
}
return rt;
}