@@ -4989,51 +4989,13 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
49894989 kfree (mlxsw_sp_rt6 );
49904990}
49914991
4992- static bool mlxsw_sp_fib6_rt_can_mp (const struct fib6_info * rt )
4993- {
4994- /* RTF_CACHE routes are ignored */
4995- return !(rt -> fib6_flags & RTF_ADDRCONF ) &&
4996- rt -> fib6_nh -> fib_nh_gw_family ;
4997- }
4998-
49994992static struct fib6_info *
50004993mlxsw_sp_fib6_entry_rt (const struct mlxsw_sp_fib6_entry * fib6_entry )
50014994{
50024995 return list_first_entry (& fib6_entry -> rt6_list , struct mlxsw_sp_rt6 ,
50034996 list )-> rt ;
50044997}
50054998
5006- static struct mlxsw_sp_fib6_entry *
5007- mlxsw_sp_fib6_node_mp_entry_find (const struct mlxsw_sp_fib_node * fib_node ,
5008- const struct fib6_info * nrt , bool replace )
5009- {
5010- struct mlxsw_sp_fib6_entry * fib6_entry ;
5011-
5012- if (!mlxsw_sp_fib6_rt_can_mp (nrt ) || replace )
5013- return NULL ;
5014-
5015- list_for_each_entry (fib6_entry , & fib_node -> entry_list , common .list ) {
5016- struct fib6_info * rt = mlxsw_sp_fib6_entry_rt (fib6_entry );
5017-
5018- /* RT6_TABLE_LOCAL and RT6_TABLE_MAIN share the same
5019- * virtual router.
5020- */
5021- if (rt -> fib6_table -> tb6_id > nrt -> fib6_table -> tb6_id )
5022- continue ;
5023- if (rt -> fib6_table -> tb6_id != nrt -> fib6_table -> tb6_id )
5024- break ;
5025- if (rt -> fib6_metric < nrt -> fib6_metric )
5026- continue ;
5027- if (rt -> fib6_metric == nrt -> fib6_metric &&
5028- mlxsw_sp_fib6_rt_can_mp (rt ))
5029- return fib6_entry ;
5030- if (rt -> fib6_metric > nrt -> fib6_metric )
5031- break ;
5032- }
5033-
5034- return NULL ;
5035- }
5036-
50374999static struct mlxsw_sp_rt6 *
50385000mlxsw_sp_fib6_entry_rt_find (const struct mlxsw_sp_fib6_entry * fib6_entry ,
50395001 const struct fib6_info * rt )
@@ -5424,86 +5386,13 @@ static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,
54245386 kfree (fib6_entry );
54255387}
54265388
5427- static struct mlxsw_sp_fib6_entry *
5428- mlxsw_sp_fib6_node_entry_find (const struct mlxsw_sp_fib_node * fib_node ,
5429- const struct fib6_info * nrt , bool replace )
5430- {
5431- struct mlxsw_sp_fib6_entry * fib6_entry , * fallback = NULL ;
5432-
5433- list_for_each_entry (fib6_entry , & fib_node -> entry_list , common .list ) {
5434- struct fib6_info * rt = mlxsw_sp_fib6_entry_rt (fib6_entry );
5435-
5436- if (rt -> fib6_table -> tb6_id > nrt -> fib6_table -> tb6_id )
5437- continue ;
5438- if (rt -> fib6_table -> tb6_id != nrt -> fib6_table -> tb6_id )
5439- break ;
5440- if (replace && rt -> fib6_metric == nrt -> fib6_metric ) {
5441- if (mlxsw_sp_fib6_rt_can_mp (rt ) ==
5442- mlxsw_sp_fib6_rt_can_mp (nrt ))
5443- return fib6_entry ;
5444- if (mlxsw_sp_fib6_rt_can_mp (nrt ))
5445- fallback = fallback ?: fib6_entry ;
5446- }
5447- if (rt -> fib6_metric > nrt -> fib6_metric )
5448- return fallback ?: fib6_entry ;
5449- }
5450-
5451- return fallback ;
5452- }
5453-
5454- static int
5455- mlxsw_sp_fib6_node_list_insert (struct mlxsw_sp_fib6_entry * new6_entry ,
5456- bool * p_replace )
5457- {
5458- struct mlxsw_sp_fib_node * fib_node = new6_entry -> common .fib_node ;
5459- struct fib6_info * nrt = mlxsw_sp_fib6_entry_rt (new6_entry );
5460- struct mlxsw_sp_fib6_entry * fib6_entry ;
5461-
5462- fib6_entry = mlxsw_sp_fib6_node_entry_find (fib_node , nrt , * p_replace );
5463-
5464- if (* p_replace && !fib6_entry )
5465- * p_replace = false;
5466-
5467- if (fib6_entry ) {
5468- list_add_tail (& new6_entry -> common .list ,
5469- & fib6_entry -> common .list );
5470- } else {
5471- struct mlxsw_sp_fib6_entry * last ;
5472-
5473- list_for_each_entry (last , & fib_node -> entry_list , common .list ) {
5474- struct fib6_info * rt = mlxsw_sp_fib6_entry_rt (last );
5475-
5476- if (nrt -> fib6_table -> tb6_id > rt -> fib6_table -> tb6_id )
5477- break ;
5478- fib6_entry = last ;
5479- }
5480-
5481- if (fib6_entry )
5482- list_add (& new6_entry -> common .list ,
5483- & fib6_entry -> common .list );
5484- else
5485- list_add (& new6_entry -> common .list ,
5486- & fib_node -> entry_list );
5487- }
5488-
5489- return 0 ;
5490- }
5491-
5492- static void
5493- mlxsw_sp_fib6_node_list_remove (struct mlxsw_sp_fib6_entry * fib6_entry )
5494- {
5495- list_del (& fib6_entry -> common .list );
5496- }
5497-
54985389static int mlxsw_sp_fib6_node_entry_link (struct mlxsw_sp * mlxsw_sp ,
5499- struct mlxsw_sp_fib6_entry * fib6_entry ,
5500- bool * p_replace )
5390+ struct mlxsw_sp_fib6_entry * fib6_entry )
55015391{
5392+ struct mlxsw_sp_fib_node * fib_node = fib6_entry -> common .fib_node ;
55025393 int err ;
55035394
5504- err = mlxsw_sp_fib6_node_list_insert (fib6_entry , p_replace );
5505- if (err )
5506- return err ;
5395+ list_add (& fib6_entry -> common .list , & fib_node -> entry_list );
55075396
55085397 err = mlxsw_sp_fib_node_entry_add (mlxsw_sp , & fib6_entry -> common );
55095398 if (err )
@@ -5512,7 +5401,7 @@ static int mlxsw_sp_fib6_node_entry_link(struct mlxsw_sp *mlxsw_sp,
55125401 return 0 ;
55135402
55145403err_fib_node_entry_add :
5515- mlxsw_sp_fib6_node_list_remove ( fib6_entry );
5404+ list_del ( & fib6_entry -> common . list );
55165405 return err ;
55175406}
55185407
@@ -5521,7 +5410,7 @@ mlxsw_sp_fib6_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
55215410 struct mlxsw_sp_fib6_entry * fib6_entry )
55225411{
55235412 mlxsw_sp_fib_node_entry_del (mlxsw_sp , & fib6_entry -> common );
5524- mlxsw_sp_fib6_node_list_remove ( fib6_entry );
5413+ list_del ( & fib6_entry -> common . list );
55255414}
55265415
55275416static struct mlxsw_sp_fib6_entry *
@@ -5557,25 +5446,25 @@ mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,
55575446}
55585447
55595448static void mlxsw_sp_fib6_entry_replace (struct mlxsw_sp * mlxsw_sp ,
5560- struct mlxsw_sp_fib6_entry * fib6_entry ,
5561- bool replace )
5449+ struct mlxsw_sp_fib6_entry * fib6_entry )
55625450{
55635451 struct mlxsw_sp_fib_node * fib_node = fib6_entry -> common .fib_node ;
55645452 struct mlxsw_sp_fib6_entry * replaced ;
55655453
5566- if (! replace )
5454+ if (list_is_singular ( & fib_node -> entry_list ) )
55675455 return ;
55685456
5457+ /* We inserted the new entry before replaced one */
55695458 replaced = list_next_entry (fib6_entry , common .list );
55705459
55715460 mlxsw_sp_fib6_node_entry_unlink (mlxsw_sp , replaced );
55725461 mlxsw_sp_fib6_entry_destroy (mlxsw_sp , replaced );
55735462 mlxsw_sp_fib_node_put (mlxsw_sp , fib_node );
55745463}
55755464
5576- static int mlxsw_sp_router_fib6_add (struct mlxsw_sp * mlxsw_sp ,
5577- struct fib6_info * * rt_arr ,
5578- unsigned int nrt6 , bool replace )
5465+ static int mlxsw_sp_router_fib6_replace (struct mlxsw_sp * mlxsw_sp ,
5466+ struct fib6_info * * rt_arr ,
5467+ unsigned int nrt6 )
55795468{
55805469 struct mlxsw_sp_fib6_entry * fib6_entry ;
55815470 struct mlxsw_sp_fib_node * fib_node ;
@@ -5599,36 +5488,68 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
55995488 if (IS_ERR (fib_node ))
56005489 return PTR_ERR (fib_node );
56015490
5602- /* Before creating a new entry, try to append route to an existing
5603- * multipath entry.
5604- */
5605- fib6_entry = mlxsw_sp_fib6_node_mp_entry_find (fib_node , rt , replace );
5606- if (fib6_entry ) {
5607- err = mlxsw_sp_fib6_entry_nexthop_add (mlxsw_sp , fib6_entry ,
5608- rt_arr , nrt6 );
5609- if (err )
5610- goto err_fib6_entry_nexthop_add ;
5611- return 0 ;
5612- }
5613-
56145491 fib6_entry = mlxsw_sp_fib6_entry_create (mlxsw_sp , fib_node , rt_arr ,
56155492 nrt6 );
56165493 if (IS_ERR (fib6_entry )) {
56175494 err = PTR_ERR (fib6_entry );
56185495 goto err_fib6_entry_create ;
56195496 }
56205497
5621- err = mlxsw_sp_fib6_node_entry_link (mlxsw_sp , fib6_entry , & replace );
5498+ err = mlxsw_sp_fib6_node_entry_link (mlxsw_sp , fib6_entry );
56225499 if (err )
56235500 goto err_fib6_node_entry_link ;
56245501
5625- mlxsw_sp_fib6_entry_replace (mlxsw_sp , fib6_entry , replace );
5502+ mlxsw_sp_fib6_entry_replace (mlxsw_sp , fib6_entry );
56265503
56275504 return 0 ;
56285505
56295506err_fib6_node_entry_link :
56305507 mlxsw_sp_fib6_entry_destroy (mlxsw_sp , fib6_entry );
56315508err_fib6_entry_create :
5509+ mlxsw_sp_fib_node_put (mlxsw_sp , fib_node );
5510+ return err ;
5511+ }
5512+
5513+ static int mlxsw_sp_router_fib6_append (struct mlxsw_sp * mlxsw_sp ,
5514+ struct fib6_info * * rt_arr ,
5515+ unsigned int nrt6 )
5516+ {
5517+ struct mlxsw_sp_fib6_entry * fib6_entry ;
5518+ struct mlxsw_sp_fib_node * fib_node ;
5519+ struct fib6_info * rt = rt_arr [0 ];
5520+ int err ;
5521+
5522+ if (mlxsw_sp -> router -> aborted )
5523+ return 0 ;
5524+
5525+ if (rt -> fib6_src .plen )
5526+ return - EINVAL ;
5527+
5528+ if (mlxsw_sp_fib6_rt_should_ignore (rt ))
5529+ return 0 ;
5530+
5531+ fib_node = mlxsw_sp_fib_node_get (mlxsw_sp , rt -> fib6_table -> tb6_id ,
5532+ & rt -> fib6_dst .addr ,
5533+ sizeof (rt -> fib6_dst .addr ),
5534+ rt -> fib6_dst .plen ,
5535+ MLXSW_SP_L3_PROTO_IPV6 );
5536+ if (IS_ERR (fib_node ))
5537+ return PTR_ERR (fib_node );
5538+
5539+ if (WARN_ON_ONCE (list_empty (& fib_node -> entry_list ))) {
5540+ mlxsw_sp_fib_node_put (mlxsw_sp , fib_node );
5541+ return - EINVAL ;
5542+ }
5543+
5544+ fib6_entry = list_first_entry (& fib_node -> entry_list ,
5545+ struct mlxsw_sp_fib6_entry , common .list );
5546+ err = mlxsw_sp_fib6_entry_nexthop_add (mlxsw_sp , fib6_entry , rt_arr ,
5547+ nrt6 );
5548+ if (err )
5549+ goto err_fib6_entry_nexthop_add ;
5550+
5551+ return 0 ;
5552+
56325553err_fib6_entry_nexthop_add :
56335554 mlxsw_sp_fib_node_put (mlxsw_sp , fib_node );
56345555 return err ;
@@ -6039,25 +5960,29 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
60395960 struct mlxsw_sp_fib_event_work * fib_work =
60405961 container_of (work , struct mlxsw_sp_fib_event_work , work );
60415962 struct mlxsw_sp * mlxsw_sp = fib_work -> mlxsw_sp ;
6042- bool replace ;
60435963 int err ;
60445964
60455965 rtnl_lock ();
60465966 mlxsw_sp_span_respin (mlxsw_sp );
60475967
60485968 switch (fib_work -> event ) {
6049- case FIB_EVENT_ENTRY_REPLACE : /* fall through */
6050- case FIB_EVENT_ENTRY_ADD :
6051- replace = fib_work -> event == FIB_EVENT_ENTRY_REPLACE ;
6052- err = mlxsw_sp_router_fib6_add (mlxsw_sp ,
6053- fib_work -> fib6_work .rt_arr ,
6054- fib_work -> fib6_work .nrt6 ,
6055- replace );
5969+ case FIB_EVENT_ENTRY_REPLACE_TMP :
5970+ err = mlxsw_sp_router_fib6_replace (mlxsw_sp ,
5971+ fib_work -> fib6_work .rt_arr ,
5972+ fib_work -> fib6_work .nrt6 );
60565973 if (err )
60575974 mlxsw_sp_router_fib_abort (mlxsw_sp );
60585975 mlxsw_sp_router_fib6_work_fini (& fib_work -> fib6_work );
60595976 break ;
6060- case FIB_EVENT_ENTRY_DEL :
5977+ case FIB_EVENT_ENTRY_APPEND :
5978+ err = mlxsw_sp_router_fib6_append (mlxsw_sp ,
5979+ fib_work -> fib6_work .rt_arr ,
5980+ fib_work -> fib6_work .nrt6 );
5981+ if (err )
5982+ mlxsw_sp_router_fib_abort (mlxsw_sp );
5983+ mlxsw_sp_router_fib6_work_fini (& fib_work -> fib6_work );
5984+ break ;
5985+ case FIB_EVENT_ENTRY_DEL_TMP :
60615986 mlxsw_sp_router_fib6_del (mlxsw_sp ,
60625987 fib_work -> fib6_work .rt_arr ,
60635988 fib_work -> fib6_work .nrt6 );
@@ -6143,9 +6068,9 @@ static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
61436068 int err ;
61446069
61456070 switch (fib_work -> event ) {
6146- case FIB_EVENT_ENTRY_REPLACE : /* fall through */
6147- case FIB_EVENT_ENTRY_ADD : /* fall through */
6148- case FIB_EVENT_ENTRY_DEL :
6071+ case FIB_EVENT_ENTRY_REPLACE_TMP : /* fall through */
6072+ case FIB_EVENT_ENTRY_APPEND : /* fall through */
6073+ case FIB_EVENT_ENTRY_DEL_TMP :
61496074 fen6_info = container_of (info , struct fib6_entry_notifier_info ,
61506075 info );
61516076 err = mlxsw_sp_router_fib6_work_init (& fib_work -> fib6_work ,
@@ -6248,7 +6173,9 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
62486173 router -> mlxsw_sp );
62496174 return notifier_from_errno (err );
62506175 case FIB_EVENT_ENTRY_ADD : /* fall through */
6251- case FIB_EVENT_ENTRY_REPLACE :
6176+ case FIB_EVENT_ENTRY_REPLACE : /* fall through */
6177+ case FIB_EVENT_ENTRY_REPLACE_TMP : /* fall through */
6178+ case FIB_EVENT_ENTRY_APPEND :
62526179 if (router -> aborted ) {
62536180 NL_SET_ERR_MSG_MOD (info -> extack , "FIB offload was aborted. Not configuring route" );
62546181 return notifier_from_errno (- EINVAL );
0 commit comments