Skip to content

Commit

Permalink
ipv6: probe routes asynchronous in rt6_probe
Browse files Browse the repository at this point in the history
Routes need to be probed asynchronous otherwise the call stack gets
exhausted when the kernel attemps to deliver another skb inline, like
e.g. xt_TEE does, and we probe at the same time.

We update neigh->updated still at once, otherwise we would send to
many probes.

Cc: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Hannes Frederic Sowa authored and David S. Miller committed Oct 21, 2013
1 parent 3a70417 commit c2f17e8
Showing 1 changed file with 31 additions and 7 deletions.
38 changes: 31 additions & 7 deletions net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,24 @@ static inline struct rt6_info *rt6_device_match(struct net *net,
}

#ifdef CONFIG_IPV6_ROUTER_PREF
struct __rt6_probe_work {
struct work_struct work;
struct in6_addr target;
struct net_device *dev;
};

static void rt6_probe_deferred(struct work_struct *w)
{
struct in6_addr mcaddr;
struct __rt6_probe_work *work =
container_of(w, struct __rt6_probe_work, work);

addrconf_addr_solict_mult(&work->target, &mcaddr);
ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL);
dev_put(work->dev);
kfree(w);
}

static void rt6_probe(struct rt6_info *rt)
{
struct neighbour *neigh;
Expand All @@ -499,17 +517,23 @@ static void rt6_probe(struct rt6_info *rt)

if (!neigh ||
time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
struct in6_addr mcaddr;
struct in6_addr *target;
struct __rt6_probe_work *work;

work = kmalloc(sizeof(*work), GFP_ATOMIC);

if (neigh) {
if (neigh && work)
neigh->updated = jiffies;

if (neigh)
write_unlock(&neigh->lock);
}

target = (struct in6_addr *)&rt->rt6i_gateway;
addrconf_addr_solict_mult(target, &mcaddr);
ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);
if (work) {
INIT_WORK(&work->work, rt6_probe_deferred);
work->target = rt->rt6i_gateway;
dev_hold(rt->dst.dev);
work->dev = rt->dst.dev;
schedule_work(&work->work);
}
} else {
out:
write_unlock(&neigh->lock);
Expand Down

0 comments on commit c2f17e8

Please sign in to comment.