From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Ahern Subject: [PATCH net-next 3/3] net/ipv6: Add support for onlink flag Date: Tue, 23 Jan 2018 19:00:04 -0800 Message-ID: <20180124030004.4016-4-dsahern@gmail.com> References: <20180124030004.4016-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-pf0-f196.google.com ([209.85.192.196]:34150 "EHLO mail-pf0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752409AbeAXDAO (ORCPT ); Tue, 23 Jan 2018 22:00:14 -0500 Received: by mail-pf0-f196.google.com with SMTP id e76so1961792pfk.1 for ; Tue, 23 Jan 2018 19:00:13 -0800 (PST) In-Reply-To: <20180124030004.4016-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 | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 00acf0103037..842b2646f1c0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2470,6 +2470,58 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net, return rt; } +static int ip6_route_onlink_check(struct fib6_config *cfg, + struct net_device *dev, + struct netlink_ext_ack *extack) +{ + u32 tbid; + + if (!dev) { + NL_SET_ERR_MSG(extack, "Nexthop device required for onlink"); + return -ENODEV; + } + + if (!(dev->flags & IFF_UP)) { + NL_SET_ERR_MSG(extack, "Nexthop device is not up"); + return -ENETDOWN; + } + + tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN; + if (cfg->fc_table && cfg->fc_table != tbid) { + NL_SET_ERR_MSG(extack, + "Table id mismatch between given table and device"); + return -EINVAL; + } + + cfg->fc_table = tbid; + + return 0; +} + +static int ip6_route_check_nh_onlink(struct net *net, + struct fib6_config *cfg, + struct net_device *dev, + struct netlink_ext_ack *extack) +{ + 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, 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, @@ -2571,6 +2623,12 @@ 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) { + err = ip6_route_onlink_check(cfg, dev, extack); + if (err) + goto out; + } + err = -ENOBUFS; if (cfg->fc_nlinfo.nlh && !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) { @@ -2731,7 +2789,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; } @@ -2767,6 +2830,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; @@ -3836,6 +3900,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); @@ -4241,6 +4307,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