@@ -3531,6 +3531,16 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
3531
3531
goto out ;
3532
3532
}
3533
3533
#endif
3534
+ if (cfg -> fc_nh_id ) {
3535
+ nh = nexthop_find_by_id (net , cfg -> fc_nh_id );
3536
+ if (!nh ) {
3537
+ NL_SET_ERR_MSG (extack , "Nexthop id does not exist" );
3538
+ goto out ;
3539
+ }
3540
+ err = fib6_check_nexthop (nh , cfg , extack );
3541
+ if (err )
3542
+ goto out ;
3543
+ }
3534
3544
3535
3545
err = - ENOBUFS ;
3536
3546
if (cfg -> fc_nlinfo .nlh &&
@@ -3762,6 +3772,30 @@ static int ip6_del_cached_rt(struct fib6_config *cfg, struct fib6_info *rt,
3762
3772
return 0 ;
3763
3773
}
3764
3774
3775
+ struct fib6_nh_del_cached_rt_arg {
3776
+ struct fib6_config * cfg ;
3777
+ struct fib6_info * f6i ;
3778
+ };
3779
+
3780
+ static int fib6_nh_del_cached_rt (struct fib6_nh * nh , void * _arg )
3781
+ {
3782
+ struct fib6_nh_del_cached_rt_arg * arg = _arg ;
3783
+ int rc ;
3784
+
3785
+ rc = ip6_del_cached_rt (arg -> cfg , arg -> f6i , nh );
3786
+ return rc != - ESRCH ? rc : 0 ;
3787
+ }
3788
+
3789
+ static int ip6_del_cached_rt_nh (struct fib6_config * cfg , struct fib6_info * f6i )
3790
+ {
3791
+ struct fib6_nh_del_cached_rt_arg arg = {
3792
+ .cfg = cfg ,
3793
+ .f6i = f6i
3794
+ };
3795
+
3796
+ return nexthop_for_each_fib6_nh (f6i -> nh , fib6_nh_del_cached_rt , & arg );
3797
+ }
3798
+
3765
3799
static int ip6_route_del (struct fib6_config * cfg ,
3766
3800
struct netlink_ext_ack * extack )
3767
3801
{
@@ -3787,29 +3821,51 @@ static int ip6_route_del(struct fib6_config *cfg,
3787
3821
for_each_fib6_node_rt_rcu (fn ) {
3788
3822
struct fib6_nh * nh ;
3789
3823
3790
- nh = rt -> fib6_nh ;
3791
- if (cfg -> fc_flags & RTF_CACHE ) {
3792
- int rc ;
3824
+ if (rt -> nh && rt -> nh -> id != cfg -> fc_nh_id )
3825
+ continue ;
3793
3826
3794
- rc = ip6_del_cached_rt (cfg , rt , nh );
3827
+ if (cfg -> fc_flags & RTF_CACHE ) {
3828
+ int rc = 0 ;
3829
+
3830
+ if (rt -> nh ) {
3831
+ rc = ip6_del_cached_rt_nh (cfg , rt );
3832
+ } else if (cfg -> fc_nh_id ) {
3833
+ continue ;
3834
+ } else {
3835
+ nh = rt -> fib6_nh ;
3836
+ rc = ip6_del_cached_rt (cfg , rt , nh );
3837
+ }
3795
3838
if (rc != - ESRCH ) {
3796
3839
rcu_read_unlock ();
3797
3840
return rc ;
3798
3841
}
3799
3842
continue ;
3800
3843
}
3801
3844
3845
+ if (cfg -> fc_metric && cfg -> fc_metric != rt -> fib6_metric )
3846
+ continue ;
3847
+ if (cfg -> fc_protocol &&
3848
+ cfg -> fc_protocol != rt -> fib6_protocol )
3849
+ continue ;
3850
+
3851
+ if (rt -> nh ) {
3852
+ if (!fib6_info_hold_safe (rt ))
3853
+ continue ;
3854
+ rcu_read_unlock ();
3855
+
3856
+ return __ip6_del_rt (rt , & cfg -> fc_nlinfo );
3857
+ }
3858
+ if (cfg -> fc_nh_id )
3859
+ continue ;
3860
+
3861
+ nh = rt -> fib6_nh ;
3802
3862
if (cfg -> fc_ifindex &&
3803
3863
(!nh -> fib_nh_dev ||
3804
3864
nh -> fib_nh_dev -> ifindex != cfg -> fc_ifindex ))
3805
3865
continue ;
3806
3866
if (cfg -> fc_flags & RTF_GATEWAY &&
3807
3867
!ipv6_addr_equal (& cfg -> fc_gateway , & nh -> fib_nh_gw6 ))
3808
3868
continue ;
3809
- if (cfg -> fc_metric && cfg -> fc_metric != rt -> fib6_metric )
3810
- continue ;
3811
- if (cfg -> fc_protocol && cfg -> fc_protocol != rt -> fib6_protocol )
3812
- continue ;
3813
3869
if (!fib6_info_hold_safe (rt ))
3814
3870
continue ;
3815
3871
rcu_read_unlock ();
@@ -4709,6 +4765,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
4709
4765
[RTA_IP_PROTO ] = { .type = NLA_U8 },
4710
4766
[RTA_SPORT ] = { .type = NLA_U16 },
4711
4767
[RTA_DPORT ] = { .type = NLA_U16 },
4768
+ [RTA_NH_ID ] = { .type = NLA_U32 },
4712
4769
};
4713
4770
4714
4771
static int rtm_to_fib6_config (struct sk_buff * skb , struct nlmsghdr * nlh ,
@@ -4755,6 +4812,16 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
4755
4812
4756
4813
cfg -> fc_flags |= (rtm -> rtm_flags & RTNH_F_ONLINK );
4757
4814
4815
+ if (tb [RTA_NH_ID ]) {
4816
+ if (tb [RTA_GATEWAY ] || tb [RTA_OIF ] ||
4817
+ tb [RTA_MULTIPATH ] || tb [RTA_ENCAP ]) {
4818
+ NL_SET_ERR_MSG (extack ,
4819
+ "Nexthop specification and nexthop id are mutually exclusive" );
4820
+ goto errout ;
4821
+ }
4822
+ cfg -> fc_nh_id = nla_get_u32 (tb [RTA_NH_ID ]);
4823
+ }
4824
+
4758
4825
if (tb [RTA_GATEWAY ]) {
4759
4826
cfg -> fc_gateway = nla_get_in6_addr (tb [RTA_GATEWAY ]);
4760
4827
cfg -> fc_flags |= RTF_GATEWAY ;
@@ -5089,6 +5156,12 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
5089
5156
if (err < 0 )
5090
5157
return err ;
5091
5158
5159
+ if (cfg .fc_nh_id &&
5160
+ !nexthop_find_by_id (sock_net (skb -> sk ), cfg .fc_nh_id )) {
5161
+ NL_SET_ERR_MSG (extack , "Nexthop id does not exist" );
5162
+ return - EINVAL ;
5163
+ }
5164
+
5092
5165
if (cfg .fc_mp )
5093
5166
return ip6_route_multipath_del (& cfg , extack );
5094
5167
else {
0 commit comments