@@ -3035,11 +3035,11 @@ mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)
3035
3035
3036
3036
static struct mlxsw_sp_fib6_entry *
3037
3037
mlxsw_sp_fib6_node_mp_entry_find (const struct mlxsw_sp_fib_node * fib_node ,
3038
- const struct rt6_info * nrt )
3038
+ const struct rt6_info * nrt , bool replace )
3039
3039
{
3040
3040
struct mlxsw_sp_fib6_entry * fib6_entry ;
3041
3041
3042
- if (!mlxsw_sp_fib6_rt_can_mp (nrt ))
3042
+ if (!mlxsw_sp_fib6_rt_can_mp (nrt ) || replace )
3043
3043
return NULL ;
3044
3044
3045
3045
list_for_each_entry (fib6_entry , & fib_node -> entry_list , common .list ) {
@@ -3371,9 +3371,9 @@ static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,
3371
3371
3372
3372
static struct mlxsw_sp_fib6_entry *
3373
3373
mlxsw_sp_fib6_node_entry_find (const struct mlxsw_sp_fib_node * fib_node ,
3374
- const struct rt6_info * nrt )
3374
+ const struct rt6_info * nrt , bool replace )
3375
3375
{
3376
- struct mlxsw_sp_fib6_entry * fib6_entry ;
3376
+ struct mlxsw_sp_fib6_entry * fib6_entry , * fallback = NULL ;
3377
3377
3378
3378
list_for_each_entry (fib6_entry , & fib_node -> entry_list , common .list ) {
3379
3379
struct rt6_info * rt = mlxsw_sp_fib6_entry_rt (fib6_entry );
@@ -3382,21 +3382,32 @@ mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
3382
3382
continue ;
3383
3383
if (rt -> rt6i_table -> tb6_id != nrt -> rt6i_table -> tb6_id )
3384
3384
break ;
3385
+ if (replace && rt -> rt6i_metric == nrt -> rt6i_metric ) {
3386
+ if (mlxsw_sp_fib6_rt_can_mp (rt ) ==
3387
+ mlxsw_sp_fib6_rt_can_mp (nrt ))
3388
+ return fib6_entry ;
3389
+ if (mlxsw_sp_fib6_rt_can_mp (nrt ))
3390
+ fallback = fallback ?: fib6_entry ;
3391
+ }
3385
3392
if (rt -> rt6i_metric > nrt -> rt6i_metric )
3386
- return fib6_entry ;
3393
+ return fallback ?: fib6_entry ;
3387
3394
}
3388
3395
3389
- return NULL ;
3396
+ return fallback ;
3390
3397
}
3391
3398
3392
3399
static int
3393
- mlxsw_sp_fib6_node_list_insert (struct mlxsw_sp_fib6_entry * new6_entry )
3400
+ mlxsw_sp_fib6_node_list_insert (struct mlxsw_sp_fib6_entry * new6_entry ,
3401
+ bool replace )
3394
3402
{
3395
3403
struct mlxsw_sp_fib_node * fib_node = new6_entry -> common .fib_node ;
3396
3404
struct rt6_info * nrt = mlxsw_sp_fib6_entry_rt (new6_entry );
3397
3405
struct mlxsw_sp_fib6_entry * fib6_entry ;
3398
3406
3399
- fib6_entry = mlxsw_sp_fib6_node_entry_find (fib_node , nrt );
3407
+ fib6_entry = mlxsw_sp_fib6_node_entry_find (fib_node , nrt , replace );
3408
+
3409
+ if (replace && WARN_ON (!fib6_entry ))
3410
+ return - EINVAL ;
3400
3411
3401
3412
if (fib6_entry ) {
3402
3413
list_add_tail (& new6_entry -> common .list ,
@@ -3430,11 +3441,12 @@ mlxsw_sp_fib6_node_list_remove(struct mlxsw_sp_fib6_entry *fib6_entry)
3430
3441
}
3431
3442
3432
3443
static int mlxsw_sp_fib6_node_entry_link (struct mlxsw_sp * mlxsw_sp ,
3433
- struct mlxsw_sp_fib6_entry * fib6_entry )
3444
+ struct mlxsw_sp_fib6_entry * fib6_entry ,
3445
+ bool replace )
3434
3446
{
3435
3447
int err ;
3436
3448
3437
- err = mlxsw_sp_fib6_node_list_insert (fib6_entry );
3449
+ err = mlxsw_sp_fib6_node_list_insert (fib6_entry , replace );
3438
3450
if (err )
3439
3451
return err ;
3440
3452
@@ -3489,8 +3501,25 @@ mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,
3489
3501
return NULL ;
3490
3502
}
3491
3503
3504
+ static void mlxsw_sp_fib6_entry_replace (struct mlxsw_sp * mlxsw_sp ,
3505
+ struct mlxsw_sp_fib6_entry * fib6_entry ,
3506
+ bool replace )
3507
+ {
3508
+ struct mlxsw_sp_fib_node * fib_node = fib6_entry -> common .fib_node ;
3509
+ struct mlxsw_sp_fib6_entry * replaced ;
3510
+
3511
+ if (!replace )
3512
+ return ;
3513
+
3514
+ replaced = list_next_entry (fib6_entry , common .list );
3515
+
3516
+ mlxsw_sp_fib6_node_entry_unlink (mlxsw_sp , replaced );
3517
+ mlxsw_sp_fib6_entry_destroy (mlxsw_sp , replaced );
3518
+ mlxsw_sp_fib_node_put (mlxsw_sp , fib_node );
3519
+ }
3520
+
3492
3521
static int mlxsw_sp_router_fib6_add (struct mlxsw_sp * mlxsw_sp ,
3493
- struct rt6_info * rt )
3522
+ struct rt6_info * rt , bool replace )
3494
3523
{
3495
3524
struct mlxsw_sp_fib6_entry * fib6_entry ;
3496
3525
struct mlxsw_sp_fib_node * fib_node ;
@@ -3513,7 +3542,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
3513
3542
/* Before creating a new entry, try to append route to an existing
3514
3543
* multipath entry.
3515
3544
*/
3516
- fib6_entry = mlxsw_sp_fib6_node_mp_entry_find (fib_node , rt );
3545
+ fib6_entry = mlxsw_sp_fib6_node_mp_entry_find (fib_node , rt , replace );
3517
3546
if (fib6_entry ) {
3518
3547
err = mlxsw_sp_fib6_entry_nexthop_add (mlxsw_sp , fib6_entry , rt );
3519
3548
if (err )
@@ -3527,10 +3556,12 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
3527
3556
goto err_fib6_entry_create ;
3528
3557
}
3529
3558
3530
- err = mlxsw_sp_fib6_node_entry_link (mlxsw_sp , fib6_entry );
3559
+ err = mlxsw_sp_fib6_node_entry_link (mlxsw_sp , fib6_entry , replace );
3531
3560
if (err )
3532
3561
goto err_fib6_node_entry_link ;
3533
3562
3563
+ mlxsw_sp_fib6_entry_replace (mlxsw_sp , fib6_entry , replace );
3564
+
3534
3565
return 0 ;
3535
3566
3536
3567
err_fib6_node_entry_link :
@@ -3795,13 +3826,16 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
3795
3826
container_of (work , struct mlxsw_sp_fib_event_work , work );
3796
3827
struct mlxsw_sp * mlxsw_sp = fib_work -> mlxsw_sp ;
3797
3828
struct fib_rule * rule ;
3829
+ bool replace ;
3798
3830
int err ;
3799
3831
3800
3832
rtnl_lock ();
3801
3833
switch (fib_work -> event ) {
3834
+ case FIB_EVENT_ENTRY_REPLACE : /* fall through */
3802
3835
case FIB_EVENT_ENTRY_ADD :
3836
+ replace = fib_work -> event == FIB_EVENT_ENTRY_REPLACE ;
3803
3837
err = mlxsw_sp_router_fib6_add (mlxsw_sp ,
3804
- fib_work -> fen6_info .rt );
3838
+ fib_work -> fen6_info .rt , replace );
3805
3839
if (err )
3806
3840
mlxsw_sp_router_fib_abort (mlxsw_sp );
3807
3841
mlxsw_sp_rt6_release (fib_work -> fen6_info .rt );
@@ -3853,6 +3887,7 @@ static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
3853
3887
struct fib_notifier_info * info )
3854
3888
{
3855
3889
switch (fib_work -> event ) {
3890
+ case FIB_EVENT_ENTRY_REPLACE : /* fall through */
3856
3891
case FIB_EVENT_ENTRY_ADD : /* fall through */
3857
3892
case FIB_EVENT_ENTRY_DEL :
3858
3893
memcpy (& fib_work -> fen6_info , info , sizeof (fib_work -> fen6_info ));
0 commit comments