@@ -2470,6 +2470,31 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2470
2470
return rt ;
2471
2471
}
2472
2472
2473
+ static 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
+
2473
2498
static int ip6_route_check_nh (struct net * net ,
2474
2499
struct fib6_config * cfg ,
2475
2500
struct net_device * * _dev ,
@@ -2572,6 +2597,21 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
2572
2597
if (cfg -> fc_metric == 0 )
2573
2598
cfg -> fc_metric = IP6_RT_PRIO_USER ;
2574
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
+
2575
2615
err = - ENOBUFS ;
2576
2616
if (cfg -> fc_nlinfo .nlh &&
2577
2617
!(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,
2732
2772
goto out ;
2733
2773
}
2734
2774
2735
- err = ip6_route_check_nh (net , cfg , & dev , & idev );
2775
+ if (cfg -> fc_flags & RTNH_F_ONLINK ) {
2776
+ err = ip6_route_check_nh_onlink (net , cfg , dev ,
2777
+ extack );
2778
+ } else {
2779
+ err = ip6_route_check_nh (net , cfg , & dev , & idev );
2780
+ }
2736
2781
if (err )
2737
2782
goto out ;
2738
2783
}
@@ -2774,6 +2819,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
2774
2819
if (!(rt -> rt6i_flags & (RTF_LOCAL | RTF_ANYCAST )) &&
2775
2820
!netif_carrier_ok (dev ))
2776
2821
rt -> rt6i_nh_flags |= RTNH_F_LINKDOWN ;
2822
+ rt -> rt6i_nh_flags |= (cfg -> fc_flags & RTNH_F_ONLINK );
2777
2823
rt -> dst .dev = dev ;
2778
2824
rt -> rt6i_idev = idev ;
2779
2825
rt -> rt6i_table = table ;
@@ -3843,6 +3889,8 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
3843
3889
if (rtm -> rtm_flags & RTM_F_CLONED )
3844
3890
cfg -> fc_flags |= RTF_CACHE ;
3845
3891
3892
+ cfg -> fc_flags |= (rtm -> rtm_flags & RTNH_F_ONLINK );
3893
+
3846
3894
cfg -> fc_nlinfo .portid = NETLINK_CB (skb ).portid ;
3847
3895
cfg -> fc_nlinfo .nlh = nlh ;
3848
3896
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,
4248
4296
goto nla_put_failure ;
4249
4297
}
4250
4298
4299
+ * flags |= (rt -> rt6i_nh_flags & RTNH_F_ONLINK );
4251
4300
if (rt -> rt6i_nh_flags & RTNH_F_OFFLOAD )
4252
4301
* flags |= RTNH_F_OFFLOAD ;
4253
4302
0 commit comments