From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Ahern Subject: [PATCH v2 net-next 3/3] net/ipv6: Add support for onlink flag Date: Thu, 25 Jan 2018 16:55:09 -0800 Message-ID: <20180126005509.14318-4-dsahern@gmail.com> References: <20180126005509.14318-1-dsahern@gmail.com> Cc: yoshfuji@linux-ipv6.org, idosch@mellanox.com, roopa@cumulusnetworks.com, David Ahern To: netdev@vger.kernel.org Return-path: Received: from mail-pg0-f67.google.com ([74.125.83.67]:45998 "EHLO mail-pg0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751552AbeAZAzU (ORCPT ); Thu, 25 Jan 2018 19:55:20 -0500 Received: by mail-pg0-f67.google.com with SMTP id m136so6182383pga.12 for ; Thu, 25 Jan 2018 16:55:20 -0800 (PST) In-Reply-To: <20180126005509.14318-1-dsahern@gmail.com> Sender: netdev-owner@vger.kernel.org List-ID: Similar to IPv4 allow routes to be added with the RTNH_F_ONLINK flag. The onlink option requires a gateway and a nexthop device. Any unicast gateway is allowed (including IPv4 mapped addresses and unresolved ones) as long as the gateway is not a local address and if it resolves it must match the given device. Signed-off-by: David Ahern --- net/ipv6/route.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 3e0a1c67eb9f..8fecdb25fd1e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2470,6 +2470,31 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net, return rt; } +static int ip6_route_check_nh_onlink(struct net *net, + struct fib6_config *cfg, + struct net_device *dev, + struct netlink_ext_ack *extack) +{ + u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_LOCAL; + const struct in6_addr *gw_addr = &cfg->fc_gateway; + u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT; + struct rt6_info *grt; + int err; + + err = 0; + grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0); + if (grt) { + if (grt->rt6i_flags & flags || dev != grt->dst.dev) { + NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway"); + err = -EINVAL; + } + + ip6_rt_put(grt); + } + + return err; +} + static int ip6_route_check_nh(struct net *net, struct fib6_config *cfg, struct net_device **_dev, @@ -2572,6 +2597,21 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, if (cfg->fc_metric == 0) cfg->fc_metric = IP6_RT_PRIO_USER; + if (cfg->fc_flags & RTNH_F_ONLINK) { + if (!dev) { + NL_SET_ERR_MSG(extack, + "Nexthop device required for onlink"); + err = -ENODEV; + goto out; + } + + if (!(dev->flags & IFF_UP)) { + NL_SET_ERR_MSG(extack, "Nexthop device is not up"); + err = -ENETDOWN; + goto out; + } + } + err = -ENOBUFS; if (cfg->fc_nlinfo.nlh && !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) { @@ -2732,7 +2772,12 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, goto out; } - err = ip6_route_check_nh(net, cfg, &dev, &idev); + if (cfg->fc_flags & RTNH_F_ONLINK) { + err = ip6_route_check_nh_onlink(net, cfg, dev, + extack); + } else { + err = ip6_route_check_nh(net, cfg, &dev, &idev); + } if (err) goto out; } @@ -2768,6 +2813,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) && !netif_carrier_ok(dev)) rt->rt6i_nh_flags |= RTNH_F_LINKDOWN; + rt->rt6i_nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK); rt->dst.dev = dev; rt->rt6i_idev = idev; rt->rt6i_table = table; @@ -3837,6 +3883,8 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, if (rtm->rtm_flags & RTM_F_CLONED) cfg->fc_flags |= RTF_CACHE; + cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK); + cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; cfg->fc_nlinfo.nlh = nlh; cfg->fc_nlinfo.nl_net = sock_net(skb->sk); @@ -4242,6 +4290,7 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt, goto nla_put_failure; } + *flags |= (rt->rt6i_nh_flags & RTNH_F_ONLINK); if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD) *flags |= RTNH_F_OFFLOAD; -- 2.11.0