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

Commit f547fac6 authored by Sabrina Dubroca's avatar Sabrina Dubroca Committed by David S. Miller
Browse files

ipv6: rate-limit probes for neighbourless routes



When commit 27097255 ("[IPV6]: ROUTE: Add Router Reachability
Probing (RFC4191).") introduced router probing, the rt6_probe() function
required that a neighbour entry existed. This neighbour entry is used to
record the timestamp of the last probe via the ->updated field.

Later, commit 2152caea ("ipv6: Do not depend on rt->n in rt6_probe().")
removed the requirement for a neighbour entry. Neighbourless routes skip
the interval check and are not rate-limited.

This patch adds rate-limiting for neighbourless routes, by recording the
timestamp of the last probe in the fib6_info itself.

Fixes: 2152caea ("ipv6: Do not depend on rt->n in rt6_probe().")
Signed-off-by: default avatarSabrina Dubroca <sd@queasysnail.net>
Reviewed-by: default avatarStefano Brivio <sbrivio@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 64bd9c81
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -159,6 +159,10 @@ struct fib6_info {
	struct rt6_info * __percpu	*rt6i_pcpu;
	struct rt6_exception_bucket __rcu *rt6i_exception_bucket;

#ifdef CONFIG_IPV6_ROUTER_PREF
	unsigned long			last_probe;
#endif

	u32				fib6_metric;
	u8				fib6_protocol;
	u8				fib6_type;
+6 −6
Original line number Diff line number Diff line
@@ -520,10 +520,11 @@ static void rt6_probe_deferred(struct work_struct *w)

static void rt6_probe(struct fib6_info *rt)
{
	struct __rt6_probe_work *work;
	struct __rt6_probe_work *work = NULL;
	const struct in6_addr *nh_gw;
	struct neighbour *neigh;
	struct net_device *dev;
	struct inet6_dev *idev;

	/*
	 * Okay, this does not seem to be appropriate
@@ -539,15 +540,12 @@ static void rt6_probe(struct fib6_info *rt)
	nh_gw = &rt->fib6_nh.nh_gw;
	dev = rt->fib6_nh.nh_dev;
	rcu_read_lock_bh();
	idev = __in6_dev_get(dev);
	neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
	if (neigh) {
		struct inet6_dev *idev;

		if (neigh->nud_state & NUD_VALID)
			goto out;

		idev = __in6_dev_get(dev);
		work = NULL;
		write_lock(&neigh->lock);
		if (!(neigh->nud_state & NUD_VALID) &&
		    time_after(jiffies,
@@ -557,11 +555,13 @@ static void rt6_probe(struct fib6_info *rt)
				__neigh_set_probe_once(neigh);
		}
		write_unlock(&neigh->lock);
	} else {
	} else if (time_after(jiffies, rt->last_probe +
				       idev->cnf.rtr_probe_interval)) {
		work = kmalloc(sizeof(*work), GFP_ATOMIC);
	}

	if (work) {
		rt->last_probe = jiffies;
		INIT_WORK(&work->work, rt6_probe_deferred);
		work->target = *nh_gw;
		dev_hold(dev);