Skip to content

Commit 5b98324

Browse files
dsaherndavem330
authored andcommitted
ipv6: Allow routes to use nexthop objects
Add support for RTA_NH_ID attribute to allow a user to specify a nexthop id to use with a route. fc_nh_id is added to fib6_config to hold the value passed in the RTA_NH_ID attribute. If a nexthop id is given, the gateway, device, encap and multipath attributes can not be set. Update ip6_route_del to check metric and protocol before nexthop specs. If fc_nh_id is set, then it must match the id in the route entry. Since IPv6 allows delete of a cached entry (an exception), add ip6_del_cached_rt_nh to cycle through all of the fib6_nh in a fib entry if it is using a nexthop. Signed-off-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6c48ea5 commit 5b98324

File tree

2 files changed

+82
-8
lines changed

2 files changed

+82
-8
lines changed

include/net/ip6_fib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct fib6_config {
4949
u16 fc_delete_all_nh : 1,
5050
fc_ignore_dev_down:1,
5151
__unused : 14;
52+
u32 fc_nh_id;
5253

5354
struct in6_addr fc_dst;
5455
struct in6_addr fc_src;

net/ipv6/route.c

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3531,6 +3531,16 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
35313531
goto out;
35323532
}
35333533
#endif
3534+
if (cfg->fc_nh_id) {
3535+
nh = nexthop_find_by_id(net, cfg->fc_nh_id);
3536+
if (!nh) {
3537+
NL_SET_ERR_MSG(extack, "Nexthop id does not exist");
3538+
goto out;
3539+
}
3540+
err = fib6_check_nexthop(nh, cfg, extack);
3541+
if (err)
3542+
goto out;
3543+
}
35343544

35353545
err = -ENOBUFS;
35363546
if (cfg->fc_nlinfo.nlh &&
@@ -3762,6 +3772,30 @@ static int ip6_del_cached_rt(struct fib6_config *cfg, struct fib6_info *rt,
37623772
return 0;
37633773
}
37643774

3775+
struct fib6_nh_del_cached_rt_arg {
3776+
struct fib6_config *cfg;
3777+
struct fib6_info *f6i;
3778+
};
3779+
3780+
static int fib6_nh_del_cached_rt(struct fib6_nh *nh, void *_arg)
3781+
{
3782+
struct fib6_nh_del_cached_rt_arg *arg = _arg;
3783+
int rc;
3784+
3785+
rc = ip6_del_cached_rt(arg->cfg, arg->f6i, nh);
3786+
return rc != -ESRCH ? rc : 0;
3787+
}
3788+
3789+
static int ip6_del_cached_rt_nh(struct fib6_config *cfg, struct fib6_info *f6i)
3790+
{
3791+
struct fib6_nh_del_cached_rt_arg arg = {
3792+
.cfg = cfg,
3793+
.f6i = f6i
3794+
};
3795+
3796+
return nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_del_cached_rt, &arg);
3797+
}
3798+
37653799
static int ip6_route_del(struct fib6_config *cfg,
37663800
struct netlink_ext_ack *extack)
37673801
{
@@ -3787,29 +3821,51 @@ static int ip6_route_del(struct fib6_config *cfg,
37873821
for_each_fib6_node_rt_rcu(fn) {
37883822
struct fib6_nh *nh;
37893823

3790-
nh = rt->fib6_nh;
3791-
if (cfg->fc_flags & RTF_CACHE) {
3792-
int rc;
3824+
if (rt->nh && rt->nh->id != cfg->fc_nh_id)
3825+
continue;
37933826

3794-
rc = ip6_del_cached_rt(cfg, rt, nh);
3827+
if (cfg->fc_flags & RTF_CACHE) {
3828+
int rc = 0;
3829+
3830+
if (rt->nh) {
3831+
rc = ip6_del_cached_rt_nh(cfg, rt);
3832+
} else if (cfg->fc_nh_id) {
3833+
continue;
3834+
} else {
3835+
nh = rt->fib6_nh;
3836+
rc = ip6_del_cached_rt(cfg, rt, nh);
3837+
}
37953838
if (rc != -ESRCH) {
37963839
rcu_read_unlock();
37973840
return rc;
37983841
}
37993842
continue;
38003843
}
38013844

3845+
if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
3846+
continue;
3847+
if (cfg->fc_protocol &&
3848+
cfg->fc_protocol != rt->fib6_protocol)
3849+
continue;
3850+
3851+
if (rt->nh) {
3852+
if (!fib6_info_hold_safe(rt))
3853+
continue;
3854+
rcu_read_unlock();
3855+
3856+
return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3857+
}
3858+
if (cfg->fc_nh_id)
3859+
continue;
3860+
3861+
nh = rt->fib6_nh;
38023862
if (cfg->fc_ifindex &&
38033863
(!nh->fib_nh_dev ||
38043864
nh->fib_nh_dev->ifindex != cfg->fc_ifindex))
38053865
continue;
38063866
if (cfg->fc_flags & RTF_GATEWAY &&
38073867
!ipv6_addr_equal(&cfg->fc_gateway, &nh->fib_nh_gw6))
38083868
continue;
3809-
if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
3810-
continue;
3811-
if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
3812-
continue;
38133869
if (!fib6_info_hold_safe(rt))
38143870
continue;
38153871
rcu_read_unlock();
@@ -4709,6 +4765,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
47094765
[RTA_IP_PROTO] = { .type = NLA_U8 },
47104766
[RTA_SPORT] = { .type = NLA_U16 },
47114767
[RTA_DPORT] = { .type = NLA_U16 },
4768+
[RTA_NH_ID] = { .type = NLA_U32 },
47124769
};
47134770

47144771
static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -4755,6 +4812,16 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
47554812

47564813
cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
47574814

4815+
if (tb[RTA_NH_ID]) {
4816+
if (tb[RTA_GATEWAY] || tb[RTA_OIF] ||
4817+
tb[RTA_MULTIPATH] || tb[RTA_ENCAP]) {
4818+
NL_SET_ERR_MSG(extack,
4819+
"Nexthop specification and nexthop id are mutually exclusive");
4820+
goto errout;
4821+
}
4822+
cfg->fc_nh_id = nla_get_u32(tb[RTA_NH_ID]);
4823+
}
4824+
47584825
if (tb[RTA_GATEWAY]) {
47594826
cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
47604827
cfg->fc_flags |= RTF_GATEWAY;
@@ -5089,6 +5156,12 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
50895156
if (err < 0)
50905157
return err;
50915158

5159+
if (cfg.fc_nh_id &&
5160+
!nexthop_find_by_id(sock_net(skb->sk), cfg.fc_nh_id)) {
5161+
NL_SET_ERR_MSG(extack, "Nexthop id does not exist");
5162+
return -EINVAL;
5163+
}
5164+
50925165
if (cfg.fc_mp)
50935166
return ip6_route_multipath_del(&cfg, extack);
50945167
else {

0 commit comments

Comments
 (0)