Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68d0c6d3 authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parent 903ab86d
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -512,12 +512,17 @@ extern void ip6_flush_pending_frames(struct sock *sk);
extern int			ip6_dst_lookup(struct sock *sk,
					       struct dst_entry **dst,
					       struct flowi *fl);
extern struct dst_entry *	ip6_dst_lookup_flow(struct sock *sk,
						    struct flowi *fl,
						    const struct in6_addr *final_dst,
						    bool want_blackhole);
extern struct dst_entry *	ip6_sk_dst_lookup_flow(struct sock *sk,
						       struct flowi *fl,
						       const struct in6_addr *final_dst,
						       bool want_blackhole);
extern int			ip6_dst_blackhole(struct sock *sk,
						  struct dst_entry **dst,
						  struct flowi *fl);
extern int			ip6_sk_dst_lookup(struct sock *sk,
						  struct dst_entry **dst,
						  struct flowi *fl);

/*
 *	skb processing functions
+20 −45
Original line number Diff line number Diff line
@@ -162,15 +162,9 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
			fl.fl_ip_sport = inet->inet_sport;
			security_sk_classify_flow(sk, &fl);

			err = ip6_dst_lookup(sk, &dst, &fl);
			if (err) {
				sk->sk_err_soft = -err;
				goto out;
			}

			err = xfrm_lookup(net, &dst, &fl, sk, 0);
			if (err < 0) {
				sk->sk_err_soft = -err;
			dst = ip6_dst_lookup_flow(sk, &fl, NULL, false);
			if (IS_ERR(dst)) {
				sk->sk_err_soft = -PTR_ERR(dst);
				goto out;
			}
		} else
@@ -267,16 +261,12 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,

	final_p = fl6_update_dst(&fl, opt, &final);

	err = ip6_dst_lookup(sk, &dst, &fl);
	if (err)
		goto done;

	if (final_p)
		ipv6_addr_copy(&fl.fl6_dst, final_p);

	err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0);
	if (err < 0)
	dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
	if (IS_ERR(dst)) {
		err = PTR_ERR(dst);
		dst = NULL;
		goto done;
	}

	skb = dccp_make_response(sk, dst, req);
	if (skb != NULL) {
@@ -338,15 +328,14 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
	security_skb_classify_flow(rxskb, &fl);

	/* sk = NULL, but it is safe for now. RST socket required. */
	if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
		if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
	dst = ip6_dst_lookup_flow(ctl_sk, &fl, NULL, false);
	if (!IS_ERR(dst)) {
		skb_dst_set(skb, dst);
		ip6_xmit(ctl_sk, skb, &fl, NULL);
		DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
		DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
		return;
	}
	}

	kfree_skb(skb);
}
@@ -550,13 +539,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
		fl.fl_ip_sport = inet_rsk(req)->loc_port;
		security_sk_classify_flow(sk, &fl);

		if (ip6_dst_lookup(sk, &dst, &fl))
			goto out;

		if (final_p)
			ipv6_addr_copy(&fl.fl6_dst, final_p);

		if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
		dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
		if (IS_ERR(dst))
			goto out;
	}

@@ -979,18 +963,9 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,

	final_p = fl6_update_dst(&fl, np->opt, &final);

	err = ip6_dst_lookup(sk, &dst, &fl);
	if (err)
		goto failure;

	if (final_p)
		ipv6_addr_copy(&fl.fl6_dst, final_p);

	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
	if (err < 0) {
		if (err == -EREMOTE)
			err = ip6_dst_blackhole(sk, &dst, &fl);
		if (err < 0)
	dst = ip6_dst_lookup_flow(sk, &fl, final_p, true);
	if (IS_ERR(dst)) {
		err = PTR_ERR(dst);
		goto failure;
	}

+5 −12
Original line number Diff line number Diff line
@@ -644,9 +644,8 @@ EXPORT_SYMBOL(inet6_unregister_protosw);

int inet6_sk_rebuild_header(struct sock *sk)
{
	int err;
	struct dst_entry *dst;
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct dst_entry *dst;

	dst = __sk_dst_check(sk, np->dst_cookie);

@@ -668,17 +667,11 @@ int inet6_sk_rebuild_header(struct sock *sk)

		final_p = fl6_update_dst(&fl, np->opt, &final);

		err = ip6_dst_lookup(sk, &dst, &fl);
		if (err) {
		dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
		if (IS_ERR(dst)) {
			sk->sk_route_caps = 0;
			return err;
		}
		if (final_p)
			ipv6_addr_copy(&fl.fl6_dst, final_p);

		if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) {
			sk->sk_err_soft = -err;
			return err;
			sk->sk_err_soft = -PTR_ERR(dst);
			return PTR_ERR(dst);
		}

		__ip6_dst_store(sk, dst, NULL, NULL);
+4 −11
Original line number Diff line number Diff line
@@ -162,17 +162,10 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
	opt = flowlabel ? flowlabel->opt : np->opt;
	final_p = fl6_update_dst(&fl, opt, &final);

	err = ip6_dst_lookup(sk, &dst, &fl);
	if (err)
		goto out;
	if (final_p)
		ipv6_addr_copy(&fl.fl6_dst, final_p);

	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
	if (err < 0) {
		if (err == -EREMOTE)
			err = ip6_dst_blackhole(sk, &dst, &fl);
		if (err < 0)
	dst = ip6_dst_lookup_flow(sk, &fl, final_p, true);
	err = 0;
	if (IS_ERR(dst)) {
		err = PTR_ERR(dst);
		goto out;
	}

+6 −19
Original line number Diff line number Diff line
@@ -74,13 +74,8 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,
	fl.fl_ip_sport = inet_rsk(req)->loc_port;
	security_req_classify_flow(req, &fl);

	if (ip6_dst_lookup(sk, &dst, &fl))
		return NULL;

	if (final_p)
		ipv6_addr_copy(&fl.fl6_dst, final_p);

	if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
	dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
	if (IS_ERR(dst))
		return NULL;

	return dst;
@@ -234,21 +229,13 @@ int inet6_csk_xmit(struct sk_buff *skb)
	dst = __inet6_csk_dst_check(sk, np->dst_cookie);

	if (dst == NULL) {
		int err = ip6_dst_lookup(sk, &dst, &fl);

		if (err) {
			sk->sk_err_soft = -err;
			kfree_skb(skb);
			return err;
		}

		if (final_p)
			ipv6_addr_copy(&fl.fl6_dst, final_p);
		dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);

		if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) {
		if (IS_ERR(dst)) {
			sk->sk_err_soft = -PTR_ERR(dst);
			sk->sk_route_caps = 0;
			kfree_skb(skb);
			return err;
			return PTR_ERR(dst);
		}

		__inet6_csk_dst_store(sk, dst, NULL, NULL);
Loading