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

Commit 29f6af77 authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki Committed by David S. Miller
Browse files

[IPV6] FIB6RULE: Find source address during looking up route.



When looking up route for destination with rules with
source address restrictions, we may need to find a source
address for the traffic if not given.

Based on patch from Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>.

Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ea2f10a3
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -5,10 +5,13 @@
#include <linux/rtnetlink.h>

/* rule is permanent, and cannot be deleted */
#define FIB_RULE_PERMANENT	1
#define FIB_RULE_INVERT		2
#define FIB_RULE_UNRESOLVED	4
#define FIB_RULE_DEV_DETACHED	8
#define FIB_RULE_PERMANENT	0x00000001
#define FIB_RULE_INVERT		0x00000002
#define FIB_RULE_UNRESOLVED	0x00000004
#define FIB_RULE_DEV_DETACHED	0x00000008

/* try to find source address in routing lookups */
#define FIB_RULE_FIND_SADDR	0x00010000

struct fib_rule_hdr
{
+31 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

#include <net/fib_rules.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
#include <net/ip6_route.h>
#include <net/netlink.h>

@@ -95,8 +96,27 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
	if (table)
		rt = lookup(table, flp, flags);

	if (rt != &ip6_null_entry)
	if (rt != &ip6_null_entry) {
		struct fib6_rule *r = (struct fib6_rule *)rule;

		/*
		 * If we need to find a source address for this traffic,
		 * we check the result if it meets requirement of the rule.
		 */
		if ((rule->flags & FIB_RULE_FIND_SADDR) &&
		    r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) {
			struct in6_addr saddr;
			if (ipv6_get_saddr(&rt->u.dst, &flp->fl6_dst,
					   &saddr))
				goto again;
			if (!ipv6_prefix_equal(&saddr, &r->src.addr,
					       r->src.plen))
				goto again;
			ipv6_addr_copy(&flp->fl6_src, &saddr);
		}
		goto out;
	}
again:
	dst_release(&rt->u.dst);
	rt = NULL;
	goto out;
@@ -117,9 +137,17 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
	    !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
		return 0;

	/*
	 * If FIB_RULE_FIND_SADDR is set and we do not have a
	 * source address for the traffic, we defer check for
	 * source address.
	 */
	if (r->src.plen) {
		if (!(flags & RT6_LOOKUP_F_HAS_SADDR) ||
		    !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
		if (flags & RT6_LOOKUP_F_HAS_SADDR) {
			if (!ipv6_prefix_equal(&fl->fl6_src, &r->src.addr,
					       r->src.plen))
				return 0;
		} else if (!(r->common.flags & FIB_RULE_FIND_SADDR))
			return 0;
	}