@@ -96,22 +96,15 @@ bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
9696}
9797EXPORT_SYMBOL_GPL (mpls_pkt_too_big );
9898
99- static struct mpls_nh * mpls_select_multipath (struct mpls_route * rt ,
100- struct sk_buff * skb , bool bos )
99+ static u32 mpls_multipath_hash (struct mpls_route * rt ,
100+ struct sk_buff * skb , bool bos )
101101{
102102 struct mpls_entry_decoded dec ;
103103 struct mpls_shim_hdr * hdr ;
104104 bool eli_seen = false;
105105 int label_index ;
106- int nh_index = 0 ;
107106 u32 hash = 0 ;
108107
109- /* No need to look further into packet if there's only
110- * one path
111- */
112- if (rt -> rt_nhn == 1 )
113- goto out ;
114-
115108 for (label_index = 0 ; label_index < MAX_MP_SELECT_LABELS && !bos ;
116109 label_index ++ ) {
117110 if (!pskb_may_pull (skb , sizeof (* hdr ) * label_index ))
@@ -165,7 +158,38 @@ static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
165158 }
166159 }
167160
168- nh_index = hash % rt -> rt_nhn ;
161+ return hash ;
162+ }
163+
164+ static struct mpls_nh * mpls_select_multipath (struct mpls_route * rt ,
165+ struct sk_buff * skb , bool bos )
166+ {
167+ int alive = ACCESS_ONCE (rt -> rt_nhn_alive );
168+ u32 hash = 0 ;
169+ int nh_index = 0 ;
170+ int n = 0 ;
171+
172+ /* No need to look further into packet if there's only
173+ * one path
174+ */
175+ if (rt -> rt_nhn == 1 )
176+ goto out ;
177+
178+ if (alive <= 0 )
179+ return NULL ;
180+
181+ hash = mpls_multipath_hash (rt , skb , bos );
182+ nh_index = hash % alive ;
183+ if (alive == rt -> rt_nhn )
184+ goto out ;
185+ for_nexthops (rt ) {
186+ if (nh -> nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN ))
187+ continue ;
188+ if (n == nh_index )
189+ return nh ;
190+ n ++ ;
191+ } endfor_nexthops (rt );
192+
169193out :
170194 return & rt -> rt_nh [nh_index ];
171195}
@@ -365,6 +389,7 @@ static struct mpls_route *mpls_rt_alloc(int num_nh, u8 max_alen)
365389 GFP_KERNEL );
366390 if (rt ) {
367391 rt -> rt_nhn = num_nh ;
392+ rt -> rt_nhn_alive = num_nh ;
368393 rt -> rt_max_alen = max_alen_aligned ;
369394 }
370395
@@ -536,6 +561,16 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
536561
537562 RCU_INIT_POINTER (nh -> nh_dev , dev );
538563
564+ if (!(dev -> flags & IFF_UP )) {
565+ nh -> nh_flags |= RTNH_F_DEAD ;
566+ } else {
567+ unsigned int flags ;
568+
569+ flags = dev_get_flags (dev );
570+ if (!(flags & (IFF_RUNNING | IFF_LOWER_UP )))
571+ nh -> nh_flags |= RTNH_F_LINKDOWN ;
572+ }
573+
539574 return 0 ;
540575
541576errout :
@@ -570,15 +605,18 @@ static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
570605 if (err )
571606 goto errout ;
572607
608+ if (nh -> nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN ))
609+ rt -> rt_nhn_alive -- ;
610+
573611 return 0 ;
574612
575613errout :
576614 return err ;
577615}
578616
579617static int mpls_nh_build (struct net * net , struct mpls_route * rt ,
580- struct mpls_nh * nh , int oif ,
581- struct nlattr * via , struct nlattr * newdst )
618+ struct mpls_nh * nh , int oif , struct nlattr * via ,
619+ struct nlattr * newdst )
582620{
583621 int err = - ENOMEM ;
584622
@@ -681,11 +719,13 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
681719 goto errout ;
682720
683721 err = mpls_nh_build (cfg -> rc_nlinfo .nl_net , rt , nh ,
684- rtnh -> rtnh_ifindex , nla_via ,
685- nla_newdst );
722+ rtnh -> rtnh_ifindex , nla_via , nla_newdst );
686723 if (err )
687724 goto errout ;
688725
726+ if (nh -> nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN ))
727+ rt -> rt_nhn_alive -- ;
728+
689729 rtnh = rtnh_next (rtnh , & remaining );
690730 nhs ++ ;
691731 } endfor_nexthops (rt );
@@ -875,55 +915,124 @@ static struct mpls_dev *mpls_add_dev(struct net_device *dev)
875915 return ERR_PTR (err );
876916}
877917
878- static void mpls_ifdown (struct net_device * dev )
918+ static void mpls_ifdown (struct net_device * dev , int event )
879919{
880920 struct mpls_route __rcu * * platform_label ;
881921 struct net * net = dev_net (dev );
882- struct mpls_dev * mdev ;
883922 unsigned index ;
884923
885924 platform_label = rtnl_dereference (net -> mpls .platform_label );
886925 for (index = 0 ; index < net -> mpls .platform_labels ; index ++ ) {
887926 struct mpls_route * rt = rtnl_dereference (platform_label [index ]);
927+
888928 if (!rt )
889929 continue ;
890- for_nexthops (rt ) {
930+
931+ change_nexthops (rt ) {
891932 if (rtnl_dereference (nh -> nh_dev ) != dev )
892933 continue ;
893- nh -> nh_dev = NULL ;
934+ switch (event ) {
935+ case NETDEV_DOWN :
936+ case NETDEV_UNREGISTER :
937+ nh -> nh_flags |= RTNH_F_DEAD ;
938+ /* fall through */
939+ case NETDEV_CHANGE :
940+ nh -> nh_flags |= RTNH_F_LINKDOWN ;
941+ ACCESS_ONCE (rt -> rt_nhn_alive ) = rt -> rt_nhn_alive - 1 ;
942+ break ;
943+ }
944+ if (event == NETDEV_UNREGISTER )
945+ RCU_INIT_POINTER (nh -> nh_dev , NULL );
894946 } endfor_nexthops (rt );
895947 }
896948
897- mdev = mpls_dev_get (dev );
898- if (!mdev )
899- return ;
900949
901- mpls_dev_sysctl_unregister (mdev );
950+ return ;
951+ }
952+
953+ static void mpls_ifup (struct net_device * dev , unsigned int nh_flags )
954+ {
955+ struct mpls_route __rcu * * platform_label ;
956+ struct net * net = dev_net (dev );
957+ unsigned index ;
958+ int alive ;
959+
960+ platform_label = rtnl_dereference (net -> mpls .platform_label );
961+ for (index = 0 ; index < net -> mpls .platform_labels ; index ++ ) {
962+ struct mpls_route * rt = rtnl_dereference (platform_label [index ]);
963+
964+ if (!rt )
965+ continue ;
966+
967+ alive = 0 ;
968+ change_nexthops (rt ) {
969+ struct net_device * nh_dev =
970+ rtnl_dereference (nh -> nh_dev );
971+
972+ if (!(nh -> nh_flags & nh_flags )) {
973+ alive ++ ;
974+ continue ;
975+ }
976+ if (nh_dev != dev )
977+ continue ;
978+ alive ++ ;
979+ nh -> nh_flags &= ~nh_flags ;
980+ } endfor_nexthops (rt );
902981
903- RCU_INIT_POINTER (dev -> mpls_ptr , NULL );
982+ ACCESS_ONCE (rt -> rt_nhn_alive ) = alive ;
983+ }
904984
905- kfree_rcu ( mdev , rcu ) ;
985+ return ;
906986}
907987
908988static int mpls_dev_notify (struct notifier_block * this , unsigned long event ,
909989 void * ptr )
910990{
911991 struct net_device * dev = netdev_notifier_info_to_dev (ptr );
912992 struct mpls_dev * mdev ;
993+ unsigned int flags ;
913994
914- switch (event ) {
915- case NETDEV_REGISTER :
995+ if (event == NETDEV_REGISTER ) {
916996 /* For now just support ethernet devices */
917997 if ((dev -> type == ARPHRD_ETHER ) ||
918998 (dev -> type == ARPHRD_LOOPBACK )) {
919999 mdev = mpls_add_dev (dev );
9201000 if (IS_ERR (mdev ))
9211001 return notifier_from_errno (PTR_ERR (mdev ));
9221002 }
923- break ;
1003+ return NOTIFY_OK ;
1004+ }
9241005
1006+ mdev = mpls_dev_get (dev );
1007+ if (!mdev )
1008+ return NOTIFY_OK ;
1009+
1010+ switch (event ) {
1011+ case NETDEV_DOWN :
1012+ mpls_ifdown (dev , event );
1013+ break ;
1014+ case NETDEV_UP :
1015+ flags = dev_get_flags (dev );
1016+ if (flags & (IFF_RUNNING | IFF_LOWER_UP ))
1017+ mpls_ifup (dev , RTNH_F_DEAD | RTNH_F_LINKDOWN );
1018+ else
1019+ mpls_ifup (dev , RTNH_F_DEAD );
1020+ break ;
1021+ case NETDEV_CHANGE :
1022+ flags = dev_get_flags (dev );
1023+ if (flags & (IFF_RUNNING | IFF_LOWER_UP ))
1024+ mpls_ifup (dev , RTNH_F_DEAD | RTNH_F_LINKDOWN );
1025+ else
1026+ mpls_ifdown (dev , event );
1027+ break ;
9251028 case NETDEV_UNREGISTER :
926- mpls_ifdown (dev );
1029+ mpls_ifdown (dev , event );
1030+ mdev = mpls_dev_get (dev );
1031+ if (mdev ) {
1032+ mpls_dev_sysctl_unregister (mdev );
1033+ RCU_INIT_POINTER (dev -> mpls_ptr , NULL );
1034+ kfree_rcu (mdev , rcu );
1035+ }
9271036 break ;
9281037 case NETDEV_CHANGENAME :
9291038 mdev = mpls_dev_get (dev );
@@ -1237,9 +1346,15 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
12371346 dev = rtnl_dereference (nh -> nh_dev );
12381347 if (dev && nla_put_u32 (skb , RTA_OIF , dev -> ifindex ))
12391348 goto nla_put_failure ;
1349+ if (nh -> nh_flags & RTNH_F_LINKDOWN )
1350+ rtm -> rtm_flags |= RTNH_F_LINKDOWN ;
1351+ if (nh -> nh_flags & RTNH_F_DEAD )
1352+ rtm -> rtm_flags |= RTNH_F_DEAD ;
12401353 } else {
12411354 struct rtnexthop * rtnh ;
12421355 struct nlattr * mp ;
1356+ int dead = 0 ;
1357+ int linkdown = 0 ;
12431358
12441359 mp = nla_nest_start (skb , RTA_MULTIPATH );
12451360 if (!mp )
@@ -1253,6 +1368,15 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
12531368 dev = rtnl_dereference (nh -> nh_dev );
12541369 if (dev )
12551370 rtnh -> rtnh_ifindex = dev -> ifindex ;
1371+ if (nh -> nh_flags & RTNH_F_LINKDOWN ) {
1372+ rtnh -> rtnh_flags |= RTNH_F_LINKDOWN ;
1373+ linkdown ++ ;
1374+ }
1375+ if (nh -> nh_flags & RTNH_F_DEAD ) {
1376+ rtnh -> rtnh_flags |= RTNH_F_DEAD ;
1377+ dead ++ ;
1378+ }
1379+
12561380 if (nh -> nh_labels && nla_put_labels (skb , RTA_NEWDST ,
12571381 nh -> nh_labels ,
12581382 nh -> nh_label ))
@@ -1266,6 +1390,11 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
12661390 rtnh -> rtnh_len = nlmsg_get_pos (skb ) - (void * )rtnh ;
12671391 } endfor_nexthops (rt );
12681392
1393+ if (linkdown == rt -> rt_nhn )
1394+ rtm -> rtm_flags |= RTNH_F_LINKDOWN ;
1395+ if (dead == rt -> rt_nhn )
1396+ rtm -> rtm_flags |= RTNH_F_DEAD ;
1397+
12691398 nla_nest_end (skb , mp );
12701399 }
12711400
0 commit comments