aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/route.c140
1 files changed, 103 insertions, 37 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index aa4411c81e7e..fe3966a9c999 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2440,7 +2440,8 @@ static int ip6_convert_metrics(struct mx6_config *mxc,
2440 2440
2441static struct rt6_info *ip6_nh_lookup_table(struct net *net, 2441static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2442 struct fib6_config *cfg, 2442 struct fib6_config *cfg,
2443 const struct in6_addr *gw_addr) 2443 const struct in6_addr *gw_addr,
2444 u32 tbid, int flags)
2444{ 2445{
2445 struct flowi6 fl6 = { 2446 struct flowi6 fl6 = {
2446 .flowi6_oif = cfg->fc_ifindex, 2447 .flowi6_oif = cfg->fc_ifindex,
@@ -2449,15 +2450,15 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2449 }; 2450 };
2450 struct fib6_table *table; 2451 struct fib6_table *table;
2451 struct rt6_info *rt; 2452 struct rt6_info *rt;
2452 int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
2453 2453
2454 table = fib6_get_table(net, cfg->fc_table); 2454 table = fib6_get_table(net, tbid);
2455 if (!table) 2455 if (!table)
2456 return NULL; 2456 return NULL;
2457 2457
2458 if (!ipv6_addr_any(&cfg->fc_prefsrc)) 2458 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2459 flags |= RT6_LOOKUP_F_HAS_SADDR; 2459 flags |= RT6_LOOKUP_F_HAS_SADDR;
2460 2460
2461 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
2461 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags); 2462 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags);
2462 2463
2463 /* if table lookup failed, fall back to full lookup */ 2464 /* if table lookup failed, fall back to full lookup */
@@ -2469,6 +2470,82 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2469 return rt; 2470 return rt;
2470} 2471}
2471 2472
2473static int ip6_route_check_nh_onlink(struct net *net,
2474 struct fib6_config *cfg,
2475 struct net_device *dev,
2476 struct netlink_ext_ack *extack)
2477{
2478 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_LOCAL;
2479 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2480 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
2481 struct rt6_info *grt;
2482 int err;
2483
2484 err = 0;
2485 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
2486 if (grt) {
2487 if (grt->rt6i_flags & flags || dev != grt->dst.dev) {
2488 NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
2489 err = -EINVAL;
2490 }
2491
2492 ip6_rt_put(grt);
2493 }
2494
2495 return err;
2496}
2497
2498static int ip6_route_check_nh(struct net *net,
2499 struct fib6_config *cfg,
2500 struct net_device **_dev,
2501 struct inet6_dev **idev)
2502{
2503 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2504 struct net_device *dev = _dev ? *_dev : NULL;
2505 struct rt6_info *grt = NULL;
2506 int err = -EHOSTUNREACH;
2507
2508 if (cfg->fc_table) {
2509 int flags = RT6_LOOKUP_F_IFACE;
2510
2511 grt = ip6_nh_lookup_table(net, cfg, gw_addr,
2512 cfg->fc_table, flags);
2513 if (grt) {
2514 if (grt->rt6i_flags & RTF_GATEWAY ||
2515 (dev && dev != grt->dst.dev)) {
2516 ip6_rt_put(grt);
2517 grt = NULL;
2518 }
2519 }
2520 }
2521
2522 if (!grt)
2523 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
2524
2525 if (!grt)
2526 goto out;
2527
2528 if (dev) {
2529 if (dev != grt->dst.dev) {
2530 ip6_rt_put(grt);
2531 goto out;
2532 }
2533 } else {
2534 *_dev = dev = grt->dst.dev;
2535 *idev = grt->rt6i_idev;
2536 dev_hold(dev);
2537 in6_dev_hold(grt->rt6i_idev);
2538 }
2539
2540 if (!(grt->rt6i_flags & RTF_GATEWAY))
2541 err = 0;
2542
2543 ip6_rt_put(grt);
2544
2545out:
2546 return err;
2547}
2548
2472static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, 2549static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
2473 struct netlink_ext_ack *extack) 2550 struct netlink_ext_ack *extack)
2474{ 2551{
@@ -2520,6 +2597,21 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
2520 if (cfg->fc_metric == 0) 2597 if (cfg->fc_metric == 0)
2521 cfg->fc_metric = IP6_RT_PRIO_USER; 2598 cfg->fc_metric = IP6_RT_PRIO_USER;
2522 2599
2600 if (cfg->fc_flags & RTNH_F_ONLINK) {
2601 if (!dev) {
2602 NL_SET_ERR_MSG(extack,
2603 "Nexthop device required for onlink");
2604 err = -ENODEV;
2605 goto out;
2606 }
2607
2608 if (!(dev->flags & IFF_UP)) {
2609 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
2610 err = -ENETDOWN;
2611 goto out;
2612 }
2613 }
2614
2523 err = -ENOBUFS; 2615 err = -ENOBUFS;
2524 if (cfg->fc_nlinfo.nlh && 2616 if (cfg->fc_nlinfo.nlh &&
2525 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) { 2617 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
@@ -2664,8 +2756,6 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
2664 rt->rt6i_gateway = *gw_addr; 2756 rt->rt6i_gateway = *gw_addr;
2665 2757
2666 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { 2758 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
2667 struct rt6_info *grt = NULL;
2668
2669 /* IPv6 strictly inhibits using not link-local 2759 /* IPv6 strictly inhibits using not link-local
2670 addresses as nexthop address. 2760 addresses as nexthop address.
2671 Otherwise, router will not able to send redirects. 2761 Otherwise, router will not able to send redirects.
@@ -2682,40 +2772,12 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
2682 goto out; 2772 goto out;
2683 } 2773 }
2684 2774
2685 if (cfg->fc_table) { 2775 if (cfg->fc_flags & RTNH_F_ONLINK) {
2686 grt = ip6_nh_lookup_table(net, cfg, gw_addr); 2776 err = ip6_route_check_nh_onlink(net, cfg, dev,
2687 2777 extack);
2688 if (grt) {
2689 if (grt->rt6i_flags & RTF_GATEWAY ||
2690 (dev && dev != grt->dst.dev)) {
2691 ip6_rt_put(grt);
2692 grt = NULL;
2693 }
2694 }
2695 }
2696
2697 if (!grt)
2698 grt = rt6_lookup(net, gw_addr, NULL,
2699 cfg->fc_ifindex, 1);
2700
2701 err = -EHOSTUNREACH;
2702 if (!grt)
2703 goto out;
2704 if (dev) {
2705 if (dev != grt->dst.dev) {
2706 ip6_rt_put(grt);
2707 goto out;
2708 }
2709 } else { 2778 } else {
2710 dev = grt->dst.dev; 2779 err = ip6_route_check_nh(net, cfg, &dev, &idev);
2711 idev = grt->rt6i_idev;
2712 dev_hold(dev);
2713 in6_dev_hold(grt->rt6i_idev);
2714 } 2780 }
2715 if (!(grt->rt6i_flags & RTF_GATEWAY))
2716 err = 0;
2717 ip6_rt_put(grt);
2718
2719 if (err) 2781 if (err)
2720 goto out; 2782 goto out;
2721 } 2783 }
@@ -2757,6 +2819,7 @@ install_route:
2757 if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) && 2819 if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
2758 !netif_carrier_ok(dev)) 2820 !netif_carrier_ok(dev))
2759 rt->rt6i_nh_flags |= RTNH_F_LINKDOWN; 2821 rt->rt6i_nh_flags |= RTNH_F_LINKDOWN;
2822 rt->rt6i_nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK);
2760 rt->dst.dev = dev; 2823 rt->dst.dev = dev;
2761 rt->rt6i_idev = idev; 2824 rt->rt6i_idev = idev;
2762 rt->rt6i_table = table; 2825 rt->rt6i_table = table;
@@ -3826,6 +3889,8 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
3826 if (rtm->rtm_flags & RTM_F_CLONED) 3889 if (rtm->rtm_flags & RTM_F_CLONED)
3827 cfg->fc_flags |= RTF_CACHE; 3890 cfg->fc_flags |= RTF_CACHE;
3828 3891
3892 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
3893
3829 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; 3894 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
3830 cfg->fc_nlinfo.nlh = nlh; 3895 cfg->fc_nlinfo.nlh = nlh;
3831 cfg->fc_nlinfo.nl_net = sock_net(skb->sk); 3896 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
@@ -4231,6 +4296,7 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt,
4231 goto nla_put_failure; 4296 goto nla_put_failure;
4232 } 4297 }
4233 4298
4299 *flags |= (rt->rt6i_nh_flags & RTNH_F_ONLINK);
4234 if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD) 4300 if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD)
4235 *flags |= RTNH_F_OFFLOAD; 4301 *flags |= RTNH_F_OFFLOAD;
4236 4302