ipv6: Handle all fib6_nh in a nexthop in rt6_device_match
Add a hook in rt6_device_match to handle nexthop struct in a fib6_info. The new rt6_nh_dev_match uses nexthop_for_each_fib6_nh to walk each fib6_nh in a nexthop and call __rt6_device_match. On match, rt6_nh_dev_match returns the fib6_nh and rt6_device_match uses it to setup fib6_result. Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2ab75bfb17
commit
962b680383
|
@ -490,6 +490,45 @@ static bool __rt6_device_match(struct net *net, const struct fib6_nh *nh,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct fib6_nh_dm_arg {
|
||||||
|
struct net *net;
|
||||||
|
const struct in6_addr *saddr;
|
||||||
|
int oif;
|
||||||
|
int flags;
|
||||||
|
struct fib6_nh *nh;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __rt6_nh_dev_match(struct fib6_nh *nh, void *_arg)
|
||||||
|
{
|
||||||
|
struct fib6_nh_dm_arg *arg = _arg;
|
||||||
|
|
||||||
|
arg->nh = nh;
|
||||||
|
return __rt6_device_match(arg->net, nh, arg->saddr, arg->oif,
|
||||||
|
arg->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns fib6_nh from nexthop or NULL */
|
||||||
|
static struct fib6_nh *rt6_nh_dev_match(struct net *net, struct nexthop *nh,
|
||||||
|
struct fib6_result *res,
|
||||||
|
const struct in6_addr *saddr,
|
||||||
|
int oif, int flags)
|
||||||
|
{
|
||||||
|
struct fib6_nh_dm_arg arg = {
|
||||||
|
.net = net,
|
||||||
|
.saddr = saddr,
|
||||||
|
.oif = oif,
|
||||||
|
.flags = flags,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (nexthop_is_blackhole(nh))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (nexthop_for_each_fib6_nh(nh, __rt6_nh_dev_match, &arg))
|
||||||
|
return arg.nh;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void rt6_device_match(struct net *net, struct fib6_result *res,
|
static void rt6_device_match(struct net *net, struct fib6_result *res,
|
||||||
const struct in6_addr *saddr, int oif, int flags)
|
const struct in6_addr *saddr, int oif, int flags)
|
||||||
{
|
{
|
||||||
|
@ -510,8 +549,19 @@ static void rt6_device_match(struct net *net, struct fib6_result *res,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) {
|
for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) {
|
||||||
nh = spf6i->fib6_nh;
|
bool matched = false;
|
||||||
if (__rt6_device_match(net, nh, saddr, oif, flags)) {
|
|
||||||
|
if (unlikely(spf6i->nh)) {
|
||||||
|
nh = rt6_nh_dev_match(net, spf6i->nh, res, saddr,
|
||||||
|
oif, flags);
|
||||||
|
if (nh)
|
||||||
|
matched = true;
|
||||||
|
} else {
|
||||||
|
nh = spf6i->fib6_nh;
|
||||||
|
if (__rt6_device_match(net, nh, saddr, oif, flags))
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
if (matched) {
|
||||||
res->f6i = spf6i;
|
res->f6i = spf6i;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue