@@ -1056,6 +1056,7 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
10561056 INIT_HLIST_NODE (& ifa -> addr_lst );
10571057 ifa -> scope = cfg -> scope ;
10581058 ifa -> prefix_len = cfg -> plen ;
1059+ ifa -> rt_priority = cfg -> rt_priority ;
10591060 ifa -> flags = cfg -> ifa_flags ;
10601061 /* No need to add the TENTATIVE flag for addresses with NODAD */
10611062 if (!(cfg -> ifa_flags & IFA_F_NODAD ))
@@ -1356,6 +1357,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp,
13561357
13571358 cfg .pfx = & addr ;
13581359 cfg .scope = ipv6_addr_scope (cfg .pfx );
1360+ cfg .rt_priority = 0 ;
13591361
13601362 ift = ipv6_add_addr (idev , & cfg , block , NULL );
13611363 if (IS_ERR (ift )) {
@@ -2314,12 +2316,13 @@ static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpad
23142316 */
23152317
23162318static void
2317- addrconf_prefix_route (struct in6_addr * pfx , int plen , struct net_device * dev ,
2318- unsigned long expires , u32 flags , gfp_t gfp_flags )
2319+ addrconf_prefix_route (struct in6_addr * pfx , int plen , u32 metric ,
2320+ struct net_device * dev , unsigned long expires ,
2321+ u32 flags , gfp_t gfp_flags )
23192322{
23202323 struct fib6_config cfg = {
23212324 .fc_table = l3mdev_fib_table (dev ) ? : RT6_TABLE_PREFIX ,
2322- .fc_metric = IP6_RT_PRIO_ADDRCONF ,
2325+ .fc_metric = metric ? : IP6_RT_PRIO_ADDRCONF ,
23232326 .fc_ifindex = dev -> ifindex ,
23242327 .fc_expires = expires ,
23252328 .fc_dst_len = plen ,
@@ -2683,7 +2686,8 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
26832686 expires = jiffies_to_clock_t (rt_expires );
26842687 }
26852688 addrconf_prefix_route (& pinfo -> prefix , pinfo -> prefix_len ,
2686- dev , expires , flags , GFP_ATOMIC );
2689+ 0 , dev , expires , flags ,
2690+ GFP_ATOMIC );
26872691 }
26882692 fib6_info_release (rt );
26892693 }
@@ -2891,8 +2895,9 @@ static int inet6_addr_add(struct net *net, int ifindex,
28912895 ifp = ipv6_add_addr (idev , cfg , true, extack );
28922896 if (!IS_ERR (ifp )) {
28932897 if (!(cfg -> ifa_flags & IFA_F_NOPREFIXROUTE )) {
2894- addrconf_prefix_route (& ifp -> addr , ifp -> prefix_len , dev ,
2895- expires , flags , GFP_KERNEL );
2898+ addrconf_prefix_route (& ifp -> addr , ifp -> prefix_len ,
2899+ ifp -> rt_priority , dev , expires ,
2900+ flags , GFP_KERNEL );
28962901 }
28972902
28982903 /* Send a netlink notification if DAD is enabled and
@@ -3056,7 +3061,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
30563061
30573062 if (addr .s6_addr32 [3 ]) {
30583063 add_addr (idev , & addr , plen , scope );
3059- addrconf_prefix_route (& addr , plen , idev -> dev , 0 , pflags ,
3064+ addrconf_prefix_route (& addr , plen , 0 , idev -> dev , 0 , pflags ,
30603065 GFP_ATOMIC );
30613066 return ;
30623067 }
@@ -3081,8 +3086,8 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
30813086 }
30823087
30833088 add_addr (idev , & addr , plen , flag );
3084- addrconf_prefix_route (& addr , plen , idev -> dev , 0 ,
3085- pflags , GFP_ATOMIC );
3089+ addrconf_prefix_route (& addr , plen , 0 , idev -> dev ,
3090+ 0 , pflags , GFP_ATOMIC );
30863091 }
30873092 }
30883093 }
@@ -3128,7 +3133,7 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
31283133
31293134 ifp = ipv6_add_addr (idev , & cfg , true, NULL );
31303135 if (!IS_ERR (ifp )) {
3131- addrconf_prefix_route (& ifp -> addr , ifp -> prefix_len , idev -> dev ,
3136+ addrconf_prefix_route (& ifp -> addr , ifp -> prefix_len , 0 , idev -> dev ,
31323137 0 , 0 , GFP_ATOMIC );
31333138 addrconf_dad_start (ifp );
31343139 in6_ifa_put (ifp );
@@ -3244,7 +3249,7 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
32443249 addrconf_add_linklocal (idev , & addr ,
32453250 IFA_F_STABLE_PRIVACY );
32463251 else if (prefix_route )
3247- addrconf_prefix_route (& addr , 64 , idev -> dev ,
3252+ addrconf_prefix_route (& addr , 64 , 0 , idev -> dev ,
32483253 0 , 0 , GFP_KERNEL );
32493254 break ;
32503255 case IN6_ADDR_GEN_MODE_EUI64 :
@@ -3255,7 +3260,7 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
32553260 if (ipv6_generate_eui64 (addr .s6_addr + 8 , idev -> dev ) == 0 )
32563261 addrconf_add_linklocal (idev , & addr , 0 );
32573262 else if (prefix_route )
3258- addrconf_prefix_route (& addr , 64 , idev -> dev ,
3263+ addrconf_prefix_route (& addr , 64 , 0 , idev -> dev ,
32593264 0 , 0 , GFP_KERNEL );
32603265 break ;
32613266 case IN6_ADDR_GEN_MODE_NONE :
@@ -3375,7 +3380,8 @@ static int fixup_permanent_addr(struct net *net,
33753380
33763381 if (!(ifp -> flags & IFA_F_NOPREFIXROUTE )) {
33773382 addrconf_prefix_route (& ifp -> addr , ifp -> prefix_len ,
3378- idev -> dev , 0 , 0 , GFP_ATOMIC );
3383+ ifp -> rt_priority , idev -> dev , 0 , 0 ,
3384+ GFP_ATOMIC );
33793385 }
33803386
33813387 if (ifp -> state == INET6_IFADDR_STATE_PREDAD )
@@ -4495,6 +4501,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
44954501 [IFA_LOCAL ] = { .len = sizeof (struct in6_addr ) },
44964502 [IFA_CACHEINFO ] = { .len = sizeof (struct ifa_cacheinfo ) },
44974503 [IFA_FLAGS ] = { .len = sizeof (u32 ) },
4504+ [IFA_RT_PRIORITY ] = { .len = sizeof (u32 ) },
44984505};
44994506
45004507static int
@@ -4527,6 +4534,37 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
45274534 ifm -> ifa_prefixlen );
45284535}
45294536
4537+ static int modify_prefix_route (struct inet6_ifaddr * ifp ,
4538+ unsigned long expires , u32 flags )
4539+ {
4540+ struct fib6_info * f6i ;
4541+
4542+ f6i = addrconf_get_prefix_route (& ifp -> addr ,
4543+ ifp -> prefix_len ,
4544+ ifp -> idev -> dev ,
4545+ 0 , RTF_GATEWAY | RTF_DEFAULT );
4546+ if (!f6i )
4547+ return - ENOENT ;
4548+
4549+ if (f6i -> fib6_metric != ifp -> rt_priority ) {
4550+ /* add new one */
4551+ addrconf_prefix_route (& ifp -> addr , ifp -> prefix_len ,
4552+ ifp -> rt_priority , ifp -> idev -> dev ,
4553+ expires , flags , GFP_KERNEL );
4554+ /* delete old one */
4555+ ip6_del_rt (dev_net (ifp -> idev -> dev ), f6i );
4556+ } else {
4557+ if (!expires )
4558+ fib6_clean_expires (f6i );
4559+ else
4560+ fib6_set_expires (f6i , expires );
4561+
4562+ fib6_info_release (f6i );
4563+ }
4564+
4565+ return 0 ;
4566+ }
4567+
45304568static int inet6_addr_modify (struct inet6_ifaddr * ifp , struct ifa6_config * cfg )
45314569{
45324570 u32 flags ;
@@ -4577,14 +4615,25 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
45774615 ifp -> valid_lft = cfg -> valid_lft ;
45784616 ifp -> prefered_lft = cfg -> preferred_lft ;
45794617
4618+ if (cfg -> rt_priority && cfg -> rt_priority != ifp -> rt_priority )
4619+ ifp -> rt_priority = cfg -> rt_priority ;
4620+
45804621 spin_unlock_bh (& ifp -> lock );
45814622 if (!(ifp -> flags & IFA_F_TENTATIVE ))
45824623 ipv6_ifa_notify (0 , ifp );
45834624
45844625 if (!(cfg -> ifa_flags & IFA_F_NOPREFIXROUTE )) {
4585- addrconf_prefix_route (& ifp -> addr , ifp -> prefix_len ,
4586- ifp -> idev -> dev , expires , flags ,
4587- GFP_KERNEL );
4626+ int rc = - ENOENT ;
4627+
4628+ if (had_prefixroute )
4629+ rc = modify_prefix_route (ifp , expires , flags );
4630+
4631+ /* prefix route could have been deleted; if so restore it */
4632+ if (rc == - ENOENT ) {
4633+ addrconf_prefix_route (& ifp -> addr , ifp -> prefix_len ,
4634+ ifp -> rt_priority , ifp -> idev -> dev ,
4635+ expires , flags , GFP_KERNEL );
4636+ }
45884637 } else if (had_prefixroute ) {
45894638 enum cleanup_prefix_rt_t action ;
45904639 unsigned long rt_expires ;
@@ -4643,6 +4692,9 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
46434692
46444693 cfg .peer_pfx = peer_pfx ;
46454694 cfg .plen = ifm -> ifa_prefixlen ;
4695+ if (tb [IFA_RT_PRIORITY ])
4696+ cfg .rt_priority = nla_get_u32 (tb [IFA_RT_PRIORITY ]);
4697+
46464698 cfg .valid_lft = INFINITY_LIFE_TIME ;
46474699 cfg .preferred_lft = INFINITY_LIFE_TIME ;
46484700
@@ -4745,7 +4797,8 @@ static inline int inet6_ifaddr_msgsize(void)
47454797 + nla_total_size (16 ) /* IFA_LOCAL */
47464798 + nla_total_size (16 ) /* IFA_ADDRESS */
47474799 + nla_total_size (sizeof (struct ifa_cacheinfo ))
4748- + nla_total_size (4 ) /* IFA_FLAGS */ ;
4800+ + nla_total_size (4 ) /* IFA_FLAGS */
4801+ + nla_total_size (4 ) /* IFA_RT_PRIORITY */ ;
47494802}
47504803
47514804static int inet6_fill_ifaddr (struct sk_buff * skb , struct inet6_ifaddr * ifa ,
@@ -4791,6 +4844,10 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
47914844 if (nla_put_in6_addr (skb , IFA_ADDRESS , & ifa -> addr ) < 0 )
47924845 goto error ;
47934846
4847+ if (ifa -> rt_priority &&
4848+ nla_put_u32 (skb , IFA_RT_PRIORITY , ifa -> rt_priority ))
4849+ goto error ;
4850+
47944851 if (put_cacheinfo (skb , ifa -> cstamp , ifa -> tstamp , preferred , valid ) < 0 )
47954852 goto error ;
47964853
@@ -5635,7 +5692,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
56355692 if (ifp -> idev -> cnf .forwarding )
56365693 addrconf_join_anycast (ifp );
56375694 if (!ipv6_addr_any (& ifp -> peer_addr ))
5638- addrconf_prefix_route (& ifp -> peer_addr , 128 ,
5695+ addrconf_prefix_route (& ifp -> peer_addr , 128 , 0 ,
56395696 ifp -> idev -> dev , 0 , 0 ,
56405697 GFP_ATOMIC );
56415698 break ;
0 commit comments