@@ -2128,15 +2128,20 @@ static int mlxsw_sp_fib4_node_list_append(struct mlxsw_sp_fib_entry *fib_entry,
21282128static int
21292129mlxsw_sp_fib4_node_list_insert (struct mlxsw_sp_fib_node * fib_node ,
21302130 struct mlxsw_sp_fib_entry * new_entry ,
2131- bool append )
2131+ bool replace , bool append )
21322132{
21332133 struct mlxsw_sp_fib_entry * fib_entry ;
21342134
21352135 fib_entry = mlxsw_sp_fib4_node_entry_find (fib_node , & new_entry -> params );
21362136
21372137 if (append )
21382138 return mlxsw_sp_fib4_node_list_append (fib_entry , new_entry );
2139+ if (replace && WARN_ON (!fib_entry ))
2140+ return - EINVAL ;
21392141
2142+ /* Insert new entry before replaced one, so that we can later
2143+ * remove the second.
2144+ */
21402145 if (fib_entry ) {
21412146 list_add_tail (& new_entry -> list , & fib_entry -> list );
21422147 } else {
@@ -2207,12 +2212,13 @@ mlxsw_sp_fib4_node_entry_del(struct mlxsw_sp *mlxsw_sp,
22072212
22082213static int mlxsw_sp_fib4_node_entry_link (struct mlxsw_sp * mlxsw_sp ,
22092214 struct mlxsw_sp_fib_entry * fib_entry ,
2210- bool append )
2215+ bool replace , bool append )
22112216{
22122217 struct mlxsw_sp_fib_node * fib_node = fib_entry -> fib_node ;
22132218 int err ;
22142219
2215- err = mlxsw_sp_fib4_node_list_insert (fib_node , fib_entry , append );
2220+ err = mlxsw_sp_fib4_node_list_insert (fib_node , fib_entry , replace ,
2221+ append );
22162222 if (err )
22172223 return err ;
22182224
@@ -2240,10 +2246,28 @@ mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
22402246 mlxsw_sp_fib4_node_list_remove (fib_entry );
22412247}
22422248
2249+ static void mlxsw_sp_fib4_entry_replace (struct mlxsw_sp * mlxsw_sp ,
2250+ struct mlxsw_sp_fib_entry * fib_entry ,
2251+ bool replace )
2252+ {
2253+ struct mlxsw_sp_fib_node * fib_node = fib_entry -> fib_node ;
2254+ struct mlxsw_sp_fib_entry * replaced ;
2255+
2256+ if (!replace )
2257+ return ;
2258+
2259+ /* We inserted the new entry before replaced one */
2260+ replaced = list_next_entry (fib_entry , list );
2261+
2262+ mlxsw_sp_fib4_node_entry_unlink (mlxsw_sp , replaced );
2263+ mlxsw_sp_fib4_entry_destroy (mlxsw_sp , replaced );
2264+ mlxsw_sp_fib4_node_put (mlxsw_sp , fib_node );
2265+ }
2266+
22432267static int
22442268mlxsw_sp_router_fib4_add (struct mlxsw_sp * mlxsw_sp ,
22452269 const struct fib_entry_notifier_info * fen_info ,
2246- bool append )
2270+ bool replace , bool append )
22472271{
22482272 struct mlxsw_sp_fib_entry * fib_entry ;
22492273 struct mlxsw_sp_fib_node * fib_node ;
@@ -2265,12 +2289,15 @@ mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp,
22652289 goto err_fib4_entry_create ;
22662290 }
22672291
2268- err = mlxsw_sp_fib4_node_entry_link (mlxsw_sp , fib_entry , append );
2292+ err = mlxsw_sp_fib4_node_entry_link (mlxsw_sp , fib_entry , replace ,
2293+ append );
22692294 if (err ) {
22702295 dev_warn (mlxsw_sp -> bus_info -> dev , "Failed to link FIB entry to node\n" );
22712296 goto err_fib4_node_entry_link ;
22722297 }
22732298
2299+ mlxsw_sp_fib4_entry_replace (mlxsw_sp , fib_entry , replace );
2300+
22742301 return 0 ;
22752302
22762303err_fib4_node_entry_link :
@@ -2479,17 +2506,19 @@ static void mlxsw_sp_router_fib_event_work(struct work_struct *work)
24792506 struct mlxsw_sp_fib_event_work * fib_work =
24802507 container_of (work , struct mlxsw_sp_fib_event_work , work );
24812508 struct mlxsw_sp * mlxsw_sp = fib_work -> mlxsw_sp ;
2482- bool append ;
2509+ bool replace , append ;
24832510 int err ;
24842511
24852512 /* Protect internal structures from changes */
24862513 rtnl_lock ();
24872514 switch (fib_work -> event ) {
2515+ case FIB_EVENT_ENTRY_REPLACE : /* fall through */
24882516 case FIB_EVENT_ENTRY_APPEND : /* fall through */
24892517 case FIB_EVENT_ENTRY_ADD :
2518+ replace = fib_work -> event == FIB_EVENT_ENTRY_REPLACE ;
24902519 append = fib_work -> event == FIB_EVENT_ENTRY_APPEND ;
24912520 err = mlxsw_sp_router_fib4_add (mlxsw_sp , & fib_work -> fen_info ,
2492- append );
2521+ replace , append );
24932522 if (err )
24942523 mlxsw_sp_router_fib4_abort (mlxsw_sp );
24952524 fib_info_put (fib_work -> fen_info .fi );
@@ -2533,6 +2562,7 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
25332562 fib_work -> event = event ;
25342563
25352564 switch (event ) {
2565+ case FIB_EVENT_ENTRY_REPLACE : /* fall through */
25362566 case FIB_EVENT_ENTRY_APPEND : /* fall through */
25372567 case FIB_EVENT_ENTRY_ADD : /* fall through */
25382568 case FIB_EVENT_ENTRY_DEL :
0 commit comments