diff options
author | David S. Miller <davem@davemloft.net> | 2011-03-02 00:19:07 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-02 00:19:07 +0300 |
commit | 68d0c6d34d586a893292d4fb633a3bf8c547b222 (patch) | |
tree | b6d812307621873cf16000171563c1f68b5bc255 /net/ipv6/ip6_output.c | |
parent | 903ab86d195cca295379699299c5fc10beba31c7 (diff) | |
download | linux-68d0c6d34d586a893292d4fb633a3bf8c547b222.tar.xz |
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.c | 80 |
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, |