Exemple #1
0
struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
			    int oif, int strict)
{
	struct fib6_node *fn;
	struct rt6_info *rt;

	read_lock_bh(&rt6_lock);
	fn = fib6_lookup(&ip6_routing_table, daddr, saddr);
	rt = rt6_device_match(fn->leaf, oif, strict);
	dst_hold(&rt->u.dst);
	rt->u.dst.__use++;
	read_unlock_bh(&rt6_lock);

	rt->u.dst.lastuse = jiffies;
	if (rt->u.dst.error == 0)
		return rt;
	dst_release(&rt->u.dst);
	return NULL;
}
struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
			    int oif, int flags)
{
	struct fib6_node *fn;
	struct rt6_info *rt;

	read_lock_bh(&rt6_lock);
	fn = fib6_lookup(&ip6_routing_table, daddr, saddr);
	rt = rt6_device_match(fn->leaf, oif, !!(flags & RT6_LOOKUP_FLAG_STRICT));
	dst_hold(&rt->u.dst);
	rt->u.dst.__use++;
	read_unlock_bh(&rt6_lock);

	if (!(flags & RT6_LOOKUP_FLAG_NOUSE))
		rt->u.dst.lastuse = jiffies;
	if (rt->u.dst.error == 0)
		return rt;
	dst_release(&rt->u.dst);
	return NULL;
}
Exemple #3
0
struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
{
	struct fib6_node *fn;
	struct rt6_info *rt;
	int strict;
	int attempts = 3;

	strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);

relookup:
	read_lock_bh(&rt6_lock);

	fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr,
			 fl->nl_u.ip6_u.saddr);

restart:
	rt = fn->leaf;

	if ((rt->rt6i_flags & RTF_CACHE)) {
		if (ip6_rt_policy == 0) {
			rt = rt6_device_match(rt, fl->oif, strict);
			BACKTRACK();
			dst_hold(&rt->u.dst);
			goto out;
		}

#ifdef CONFIG_RT6_POLICY
		if ((rt->rt6i_flags & RTF_FLOW)) {
			struct rt6_info *sprt;

			for (sprt = rt; sprt; sprt = sprt->u.next) {
				if (rt6_flow_match_out(sprt, sk)) {
					rt = sprt;
					dst_hold(&rt->u.dst);
					goto out;
				}
			}
		}
#endif
	}
	if (rt->rt6i_flags & RTF_DEFAULT) {
		if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)
			rt = rt6_best_dflt(rt, fl->oif);
	} else {
		rt = rt6_device_match(rt, fl->oif, strict);
		BACKTRACK();
	}

	if (ip6_rt_policy == 0) {
		if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
			read_unlock_bh(&rt6_lock);

			rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
				     fl->nl_u.ip6_u.saddr);
			
			if (rt->u.dst.error != -EEXIST || --attempts <= 0)
				goto out2;

			/* Race condition! In the gap, when rt6_lock was
			   released someone could insert this route.  Relookup.
			 */
			goto relookup;
		}
		dst_hold(&rt->u.dst);
	} else {
#ifdef CONFIG_RT6_POLICY
		rt = rt6_flow_lookup_out(rt, sk, fl);
#else
		/* NEVER REACHED */
#endif
	}

out:
	read_unlock_bh(&rt6_lock);
out2:
	rt->u.dst.lastuse = jiffies;
	rt->u.dst.__use++;
	return &rt->u.dst;
}
Exemple #4
0
void ip6_route_input(struct sk_buff *skb)
{
	struct fib6_node *fn;
	struct rt6_info *rt;
	int strict;
	int attempts = 3;

	strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);

relookup:
	read_lock_bh(&rt6_lock);

	fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr,
			 &skb->nh.ipv6h->saddr);

restart:
	rt = fn->leaf;

	if ((rt->rt6i_flags & RTF_CACHE)) {
		if (ip6_rt_policy == 0) {
			rt = rt6_device_match(rt, skb->dev->ifindex, strict);
			BACKTRACK();
			dst_hold(&rt->u.dst);
			goto out;
		}

#ifdef CONFIG_RT6_POLICY
		if ((rt->rt6i_flags & RTF_FLOW)) {
			struct rt6_info *sprt;

			for (sprt = rt; sprt; sprt = sprt->u.next) {
				if (rt6_flow_match_in(sprt, skb)) {
					rt = sprt;
					dst_hold(&rt->u.dst);
					goto out;
				}
			}
		}
#endif
	}

	rt = rt6_device_match(rt, skb->dev->ifindex, 0);
	BACKTRACK();

	if (ip6_rt_policy == 0) {
		if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
			read_unlock_bh(&rt6_lock);

			rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
				     &skb->nh.ipv6h->saddr);
			
			if (rt->u.dst.error != -EEXIST || --attempts <= 0)
				goto out2;
			/* Race condition! In the gap, when rt6_lock was
			   released someone could insert this route.  Relookup.
			 */
			goto relookup;
		}
		dst_hold(&rt->u.dst);
	} else {
#ifdef CONFIG_RT6_POLICY
		rt = rt6_flow_lookup_in(rt, skb);
#else
		/* NEVER REACHED */
#endif
	}

out:
	read_unlock_bh(&rt6_lock);
out2:
	rt->u.dst.lastuse = jiffies;
	rt->u.dst.__use++;
	skb->dst = (struct dst_entry *) rt;
}