@@ -5316,29 +5316,131 @@ struct rt6_nh {
5316
5316
struct fib6_info * fib6_info ;
5317
5317
struct fib6_config r_cfg ;
5318
5318
struct list_head list ;
5319
+ int weight ;
5319
5320
};
5320
5321
5321
- static int ip6_route_info_append (struct list_head * rt6_nh_list ,
5322
- struct fib6_info * rt ,
5323
- struct fib6_config * r_cfg )
5322
+ static void ip6_route_mpath_info_cleanup (struct list_head * rt6_nh_list )
5324
5323
{
5325
- struct rt6_nh * nh ;
5326
- int err = - EEXIST ;
5324
+ struct rt6_nh * nh , * nh_next ;
5327
5325
5328
- list_for_each_entry (nh , rt6_nh_list , list ) {
5329
- /* check if fib6_info already exists */
5330
- if (rt6_duplicate_nexthop (nh -> fib6_info , rt ))
5331
- return err ;
5326
+ list_for_each_entry_safe (nh , nh_next , rt6_nh_list , list ) {
5327
+ struct fib6_info * rt = nh -> fib6_info ;
5328
+
5329
+ if (rt ) {
5330
+ free_percpu (rt -> fib6_nh -> nh_common .nhc_pcpu_rth_output );
5331
+ free_percpu (rt -> fib6_nh -> rt6i_pcpu );
5332
+ ip_fib_metrics_put (rt -> fib6_metrics );
5333
+ kfree (rt );
5334
+ }
5335
+
5336
+ list_del (& nh -> list );
5337
+ kfree (nh );
5332
5338
}
5339
+ }
5333
5340
5334
- nh = kzalloc (sizeof (* nh ), GFP_KERNEL );
5335
- if (!nh )
5336
- return - ENOMEM ;
5337
- nh -> fib6_info = rt ;
5338
- memcpy (& nh -> r_cfg , r_cfg , sizeof (* r_cfg ));
5339
- list_add_tail (& nh -> list , rt6_nh_list );
5341
+ static int ip6_route_mpath_info_create (struct list_head * rt6_nh_list ,
5342
+ struct fib6_config * cfg ,
5343
+ struct netlink_ext_ack * extack )
5344
+ {
5345
+ struct rtnexthop * rtnh ;
5346
+ int remaining ;
5347
+ int err ;
5348
+
5349
+ remaining = cfg -> fc_mp_len ;
5350
+ rtnh = (struct rtnexthop * )cfg -> fc_mp ;
5351
+
5352
+ /* Parse a Multipath Entry and build a list (rt6_nh_list) of
5353
+ * fib6_info structs per nexthop
5354
+ */
5355
+ while (rtnh_ok (rtnh , remaining )) {
5356
+ struct fib6_config r_cfg ;
5357
+ struct fib6_info * rt ;
5358
+ struct rt6_nh * nh ;
5359
+ int attrlen ;
5360
+
5361
+ nh = kzalloc (sizeof (* nh ), GFP_KERNEL );
5362
+ if (!nh ) {
5363
+ err = - ENOMEM ;
5364
+ goto err ;
5365
+ }
5366
+
5367
+ list_add_tail (& nh -> list , rt6_nh_list );
5368
+
5369
+ memcpy (& r_cfg , cfg , sizeof (* cfg ));
5370
+ if (rtnh -> rtnh_ifindex )
5371
+ r_cfg .fc_ifindex = rtnh -> rtnh_ifindex ;
5372
+
5373
+ attrlen = rtnh_attrlen (rtnh );
5374
+ if (attrlen > 0 ) {
5375
+ struct nlattr * nla , * attrs = rtnh_attrs (rtnh );
5376
+
5377
+ nla = nla_find (attrs , attrlen , RTA_GATEWAY );
5378
+ if (nla ) {
5379
+ r_cfg .fc_gateway = nla_get_in6_addr (nla );
5380
+ r_cfg .fc_flags |= RTF_GATEWAY ;
5381
+ }
5382
+
5383
+ r_cfg .fc_encap = nla_find (attrs , attrlen , RTA_ENCAP );
5384
+ nla = nla_find (attrs , attrlen , RTA_ENCAP_TYPE );
5385
+ if (nla )
5386
+ r_cfg .fc_encap_type = nla_get_u16 (nla );
5387
+ }
5388
+
5389
+ r_cfg .fc_flags |= (rtnh -> rtnh_flags & RTNH_F_ONLINK );
5390
+
5391
+ rt = ip6_route_info_create (& r_cfg , GFP_KERNEL , extack );
5392
+ if (IS_ERR (rt )) {
5393
+ err = PTR_ERR (rt );
5394
+ goto err ;
5395
+ }
5396
+
5397
+ nh -> fib6_info = rt ;
5398
+ nh -> weight = rtnh -> rtnh_hops + 1 ;
5399
+ memcpy (& nh -> r_cfg , & r_cfg , sizeof (r_cfg ));
5400
+
5401
+ rtnh = rtnh_next (rtnh , & remaining );
5402
+ }
5340
5403
5341
5404
return 0 ;
5405
+ err :
5406
+ ip6_route_mpath_info_cleanup (rt6_nh_list );
5407
+ return err ;
5408
+ }
5409
+
5410
+ static int ip6_route_mpath_info_create_nh (struct list_head * rt6_nh_list ,
5411
+ struct netlink_ext_ack * extack )
5412
+ {
5413
+ struct rt6_nh * nh , * nh_next , * nh_tmp ;
5414
+ LIST_HEAD (tmp );
5415
+ int err ;
5416
+
5417
+ list_for_each_entry_safe (nh , nh_next , rt6_nh_list , list ) {
5418
+ struct fib6_info * rt = nh -> fib6_info ;
5419
+
5420
+ err = ip6_route_info_create_nh (rt , & nh -> r_cfg , extack );
5421
+ if (err ) {
5422
+ nh -> fib6_info = NULL ;
5423
+ goto err ;
5424
+ }
5425
+
5426
+ rt -> fib6_nh -> fib_nh_weight = nh -> weight ;
5427
+
5428
+ list_move_tail (& nh -> list , & tmp );
5429
+
5430
+ list_for_each_entry (nh_tmp , rt6_nh_list , list ) {
5431
+ /* check if fib6_info already exists */
5432
+ if (rt6_duplicate_nexthop (nh_tmp -> fib6_info , rt )) {
5433
+ err = - EEXIST ;
5434
+ goto err ;
5435
+ }
5436
+ }
5437
+ }
5438
+ out :
5439
+ list_splice (& tmp , rt6_nh_list );
5440
+ return err ;
5441
+ err :
5442
+ ip6_route_mpath_info_cleanup (rt6_nh_list );
5443
+ goto out ;
5342
5444
}
5343
5445
5344
5446
static void ip6_route_mpath_notify (struct fib6_info * rt ,
@@ -5397,75 +5499,28 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
5397
5499
{
5398
5500
struct fib6_info * rt_notif = NULL , * rt_last = NULL ;
5399
5501
struct nl_info * info = & cfg -> fc_nlinfo ;
5400
- struct fib6_config r_cfg ;
5401
- struct rtnexthop * rtnh ;
5402
- struct fib6_info * rt ;
5403
- struct rt6_nh * err_nh ;
5404
5502
struct rt6_nh * nh , * nh_safe ;
5503
+ LIST_HEAD (rt6_nh_list );
5504
+ struct rt6_nh * err_nh ;
5405
5505
__u16 nlflags ;
5406
- int remaining ;
5407
- int attrlen ;
5408
- int err = 1 ;
5409
5506
int nhn = 0 ;
5410
- int replace = (cfg -> fc_nlinfo .nlh &&
5411
- (cfg -> fc_nlinfo .nlh -> nlmsg_flags & NLM_F_REPLACE ));
5412
- LIST_HEAD (rt6_nh_list );
5507
+ int replace ;
5508
+ int err ;
5509
+
5510
+ replace = (cfg -> fc_nlinfo .nlh &&
5511
+ (cfg -> fc_nlinfo .nlh -> nlmsg_flags & NLM_F_REPLACE ));
5413
5512
5414
5513
nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE ;
5415
5514
if (info -> nlh && info -> nlh -> nlmsg_flags & NLM_F_APPEND )
5416
5515
nlflags |= NLM_F_APPEND ;
5417
5516
5418
- remaining = cfg -> fc_mp_len ;
5419
- rtnh = (struct rtnexthop * )cfg -> fc_mp ;
5420
-
5421
- /* Parse a Multipath Entry and build a list (rt6_nh_list) of
5422
- * fib6_info structs per nexthop
5423
- */
5424
- while (rtnh_ok (rtnh , remaining )) {
5425
- memcpy (& r_cfg , cfg , sizeof (* cfg ));
5426
- if (rtnh -> rtnh_ifindex )
5427
- r_cfg .fc_ifindex = rtnh -> rtnh_ifindex ;
5428
-
5429
- attrlen = rtnh_attrlen (rtnh );
5430
- if (attrlen > 0 ) {
5431
- struct nlattr * nla , * attrs = rtnh_attrs (rtnh );
5432
-
5433
- nla = nla_find (attrs , attrlen , RTA_GATEWAY );
5434
- if (nla ) {
5435
- r_cfg .fc_gateway = nla_get_in6_addr (nla );
5436
- r_cfg .fc_flags |= RTF_GATEWAY ;
5437
- }
5438
-
5439
- r_cfg .fc_encap = nla_find (attrs , attrlen , RTA_ENCAP );
5440
- nla = nla_find (attrs , attrlen , RTA_ENCAP_TYPE );
5441
- if (nla )
5442
- r_cfg .fc_encap_type = nla_get_u16 (nla );
5443
- }
5444
-
5445
- r_cfg .fc_flags |= (rtnh -> rtnh_flags & RTNH_F_ONLINK );
5446
- rt = ip6_route_info_create (& r_cfg , GFP_KERNEL , extack );
5447
- if (IS_ERR (rt )) {
5448
- err = PTR_ERR (rt );
5449
- rt = NULL ;
5450
- goto cleanup ;
5451
- }
5452
-
5453
- err = ip6_route_info_create_nh (rt , & r_cfg , extack );
5454
- if (err ) {
5455
- rt = NULL ;
5456
- goto cleanup ;
5457
- }
5458
-
5459
- rt -> fib6_nh -> fib_nh_weight = rtnh -> rtnh_hops + 1 ;
5460
-
5461
- err = ip6_route_info_append (& rt6_nh_list , rt , & r_cfg );
5462
- if (err ) {
5463
- fib6_info_release (rt );
5464
- goto cleanup ;
5465
- }
5517
+ err = ip6_route_mpath_info_create (& rt6_nh_list , cfg , extack );
5518
+ if (err )
5519
+ return err ;
5466
5520
5467
- rtnh = rtnh_next (rtnh , & remaining );
5468
- }
5521
+ err = ip6_route_mpath_info_create_nh (& rt6_nh_list , extack );
5522
+ if (err )
5523
+ goto cleanup ;
5469
5524
5470
5525
/* for add and replace send one notification with all nexthops.
5471
5526
* Skip the notification in fib6_add_rt2node and send one with
0 commit comments