aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-03-01 13:19:07 -0800
committerDavid S. Miller <davem@davemloft.net>2011-03-01 13:19:07 -0800
commit68d0c6d34d586a893292d4fb633a3bf8c547b222 (patch)
treeb6d812307621873cf16000171563c1f68b5bc255 /net/ipv6/ip6_output.c
parentudp: Add lockless transmit path (diff)
downloadlinux-dev-68d0c6d34d586a893292d4fb633a3bf8c547b222.tar.xz
linux-dev-68d0c6d34d586a893292d4fb633a3bf8c547b222.zip
ipv6: Consolidate route lookup sequences.
Route lookups follow a general pattern in the ipv6 code wherein we first find the non-IPSEC route, potentially override the flow destination address due to ipv6 options settings, and then finally make an IPSEC search using either xfrm_lookup() or __xfrm_lookup(). __xfrm_lookup() is used when we want to generate a blackhole route if the key manager needs to resolve the IPSEC rules (in this case -EREMOTE is returned and the original 'dst' is left unchanged). Otherwise plain xfrm_lookup() is used and when asynchronous IPSEC resolution is necessary, we simply fail the lookup completely. All of these cases are encapsulated into two routines, ip6_dst_lookup_flow and ip6_sk_dst_lookup_flow. The latter of which handles unconnected UDP datagram sockets. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c80
1 files changed, 69 insertions, 11 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 5c618f20523e..28209b2d254d 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1002,29 +1002,87 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
EXPORT_SYMBOL_GPL(ip6_dst_lookup);
/**
- * ip6_sk_dst_lookup - perform socket cached route lookup on flow
+ * ip6_dst_lookup_flow - perform route lookup on flow with ipsec
+ * @sk: socket which provides route info
+ * @fl: flow to lookup
+ * @final_dst: final destination address for ipsec lookup
+ * @want_blackhole: IPSEC blackhole handling desired
+ *
+ * This function performs a route lookup on the given flow.
+ *
+ * It returns a valid dst pointer on success, or a pointer encoded
+ * error code.
+ */
+struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
+ const struct in6_addr *final_dst,
+ bool want_blackhole)
+{
+ struct dst_entry *dst = NULL;
+ int err;
+
+ err = ip6_dst_lookup_tail(sk, &dst, fl);
+ if (err)
+ return ERR_PTR(err);
+ if (final_dst)
+ ipv6_addr_copy(&fl->fl6_dst, final_dst);
+ if (want_blackhole) {
+ err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
+ if (err == -EREMOTE)
+ err = ip6_dst_blackhole(sk, &dst, fl);
+ if (err)
+ return ERR_PTR(err);
+ } else {
+ err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
+ if (err)
+ return ERR_PTR(err);
+ }
+ return dst;
+}
+EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
+
+/**
+ * ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow
* @sk: socket which provides the dst cache and route info
- * @dst: pointer to dst_entry * for result
* @fl: flow to lookup
+ * @final_dst: final destination address for ipsec lookup
+ * @want_blackhole: IPSEC blackhole handling desired
*
* This function performs a route lookup on the given flow with the
* possibility of using the cached route in the socket if it is valid.
* It will take the socket dst lock when operating on the dst cache.
* As a result, this function can only be used in process context.
*
- * It returns zero on success, or a standard errno code on error.
+ * It returns a valid dst pointer on success, or a pointer encoded
+ * error code.
*/
-int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
+struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
+ const struct in6_addr *final_dst,
+ bool want_blackhole)
{
- *dst = NULL;
- if (sk) {
- *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
- *dst = ip6_sk_dst_check(sk, *dst, fl);
- }
+ struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
+ int err;
- return ip6_dst_lookup_tail(sk, dst, fl);
+ dst = ip6_sk_dst_check(sk, dst, fl);
+
+ err = ip6_dst_lookup_tail(sk, &dst, fl);
+ if (err)
+ return ERR_PTR(err);
+ if (final_dst)
+ ipv6_addr_copy(&fl->fl6_dst, final_dst);
+ if (want_blackhole) {
+ err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
+ if (err == -EREMOTE)
+ err = ip6_dst_blackhole(sk, &dst, fl);
+ if (err)
+ return ERR_PTR(err);
+ } else {
+ err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
+ if (err)
+ return ERR_PTR(err);
+ }
+ return dst;
}
-EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup);
+EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
static inline int ip6_ufo_append_data(struct sock *sk,
int getfrag(void *from, char *to, int offset, int len,