mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net/ipv6: Add support for onlink flag
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 <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									f4797b33db
								
							
						
					
					
						commit
						fc1e64e109
					
				
					 1 changed files with 50 additions and 1 deletions
				
			
		| 
						 | 
					@ -2470,6 +2470,31 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net,
 | 
				
			||||||
	return rt;
 | 
						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,
 | 
					static int ip6_route_check_nh(struct net *net,
 | 
				
			||||||
			      struct fib6_config *cfg,
 | 
								      struct fib6_config *cfg,
 | 
				
			||||||
			      struct net_device **_dev,
 | 
								      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)
 | 
						if (cfg->fc_metric == 0)
 | 
				
			||||||
		cfg->fc_metric = IP6_RT_PRIO_USER;
 | 
							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;
 | 
						err = -ENOBUFS;
 | 
				
			||||||
	if (cfg->fc_nlinfo.nlh &&
 | 
						if (cfg->fc_nlinfo.nlh &&
 | 
				
			||||||
	    !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
 | 
						    !(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;
 | 
									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)
 | 
								if (err)
 | 
				
			||||||
				goto out;
 | 
									goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -2774,6 +2819,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
 | 
				
			||||||
	if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
 | 
						if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
 | 
				
			||||||
	    !netif_carrier_ok(dev))
 | 
						    !netif_carrier_ok(dev))
 | 
				
			||||||
		rt->rt6i_nh_flags |= RTNH_F_LINKDOWN;
 | 
							rt->rt6i_nh_flags |= RTNH_F_LINKDOWN;
 | 
				
			||||||
 | 
						rt->rt6i_nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK);
 | 
				
			||||||
	rt->dst.dev = dev;
 | 
						rt->dst.dev = dev;
 | 
				
			||||||
	rt->rt6i_idev = idev;
 | 
						rt->rt6i_idev = idev;
 | 
				
			||||||
	rt->rt6i_table = table;
 | 
						rt->rt6i_table = table;
 | 
				
			||||||
| 
						 | 
					@ -3843,6 +3889,8 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
 | 
				
			||||||
	if (rtm->rtm_flags & RTM_F_CLONED)
 | 
						if (rtm->rtm_flags & RTM_F_CLONED)
 | 
				
			||||||
		cfg->fc_flags |= RTF_CACHE;
 | 
							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.portid = NETLINK_CB(skb).portid;
 | 
				
			||||||
	cfg->fc_nlinfo.nlh = nlh;
 | 
						cfg->fc_nlinfo.nlh = nlh;
 | 
				
			||||||
	cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
 | 
						cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
 | 
				
			||||||
| 
						 | 
					@ -4248,6 +4296,7 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt,
 | 
				
			||||||
			goto nla_put_failure;
 | 
								goto nla_put_failure;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*flags |= (rt->rt6i_nh_flags & RTNH_F_ONLINK);
 | 
				
			||||||
	if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD)
 | 
						if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD)
 | 
				
			||||||
		*flags |= RTNH_F_OFFLOAD;
 | 
							*flags |= RTNH_F_OFFLOAD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue