@@ -24,6 +24,9 @@ struct mlxsw_sp_router_xm {
24
24
bool ipv6_supported ;
25
25
unsigned int entries_size ;
26
26
struct rhashtable ltable_ht ;
27
+ struct rhashtable flush_ht ; /* Stores items about to be flushed from cache */
28
+ unsigned int flush_count ;
29
+ bool flush_all_mode ;
27
30
};
28
31
29
32
struct mlxsw_sp_router_xm_ltable_node {
@@ -41,11 +44,20 @@ static const struct rhashtable_params mlxsw_sp_router_xm_ltable_ht_params = {
41
44
.automatic_shrinking = true,
42
45
};
43
46
47
+ struct mlxsw_sp_router_xm_flush_info {
48
+ bool all ;
49
+ enum mlxsw_sp_l3proto proto ;
50
+ u16 virtual_router ;
51
+ u8 prefix_len ;
52
+ unsigned char addr [sizeof (struct in6_addr )];
53
+ };
54
+
44
55
struct mlxsw_sp_router_xm_fib_entry {
45
56
bool committed ;
46
57
struct mlxsw_sp_router_xm_ltable_node * ltable_node ; /* Parent node */
47
58
u16 mindex ; /* Store for processing from commit op */
48
59
u8 lvalue ;
60
+ struct mlxsw_sp_router_xm_flush_info flush_info ;
49
61
};
50
62
51
63
#define MLXSW_SP_ROUTE_LL_XM_ENTRIES_MAX \
@@ -125,6 +137,7 @@ static void mlxsw_sp_router_ll_xm_fib_entry_pack(struct mlxsw_sp_fib_entry_op_ct
125
137
{
126
138
struct mlxsw_sp_fib_entry_op_ctx_xm * op_ctx_xm = (void * ) op_ctx -> ll_priv ;
127
139
struct mlxsw_sp_router_xm_fib_entry * fib_entry = (void * ) priv -> priv ;
140
+ struct mlxsw_sp_router_xm_flush_info * flush_info ;
128
141
enum mlxsw_reg_xmdr_c_ltr_op xmdr_c_ltr_op ;
129
142
unsigned int len ;
130
143
@@ -171,6 +184,15 @@ static void mlxsw_sp_router_ll_xm_fib_entry_pack(struct mlxsw_sp_fib_entry_op_ct
171
184
172
185
fib_entry -> lvalue = prefix_len > mlxsw_sp_router_xm_m_val [proto ] ?
173
186
prefix_len - mlxsw_sp_router_xm_m_val [proto ] : 0 ;
187
+
188
+ flush_info = & fib_entry -> flush_info ;
189
+ flush_info -> proto = proto ;
190
+ flush_info -> virtual_router = virtual_router ;
191
+ flush_info -> prefix_len = prefix_len ;
192
+ if (addr )
193
+ memcpy (flush_info -> addr , addr , sizeof (flush_info -> addr ));
194
+ else
195
+ memset (flush_info -> addr , 0 , sizeof (flush_info -> addr ));
174
196
}
175
197
176
198
static void
@@ -262,6 +284,231 @@ static int mlxsw_sp_router_xm_ltable_lvalue_set(struct mlxsw_sp *mlxsw_sp,
262
284
return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (xrmt ), xrmt_pl );
263
285
}
264
286
287
+ struct mlxsw_sp_router_xm_flush_node {
288
+ struct rhash_head ht_node ; /* Member of router_xm->flush_ht */
289
+ struct list_head list ;
290
+ struct mlxsw_sp_router_xm_flush_info flush_info ;
291
+ struct delayed_work dw ;
292
+ struct mlxsw_sp * mlxsw_sp ;
293
+ unsigned long start_jiffies ;
294
+ unsigned int reuses ; /* By how many flush calls this was reused. */
295
+ refcount_t refcnt ;
296
+ };
297
+
298
+ static const struct rhashtable_params mlxsw_sp_router_xm_flush_ht_params = {
299
+ .key_offset = offsetof(struct mlxsw_sp_router_xm_flush_node , flush_info ),
300
+ .head_offset = offsetof(struct mlxsw_sp_router_xm_flush_node , ht_node ),
301
+ .key_len = sizeof (struct mlxsw_sp_router_xm_flush_info ),
302
+ .automatic_shrinking = true,
303
+ };
304
+
305
+ static struct mlxsw_sp_router_xm_flush_node *
306
+ mlxsw_sp_router_xm_cache_flush_node_create (struct mlxsw_sp * mlxsw_sp ,
307
+ struct mlxsw_sp_router_xm_flush_info * flush_info )
308
+ {
309
+ struct mlxsw_sp_router_xm * router_xm = mlxsw_sp -> router -> xm ;
310
+ struct mlxsw_sp_router_xm_flush_node * flush_node ;
311
+ int err ;
312
+
313
+ flush_node = kzalloc (sizeof (* flush_node ), GFP_KERNEL );
314
+ if (!flush_node )
315
+ return ERR_PTR (- ENOMEM );
316
+
317
+ flush_node -> flush_info = * flush_info ;
318
+ err = rhashtable_insert_fast (& router_xm -> flush_ht , & flush_node -> ht_node ,
319
+ mlxsw_sp_router_xm_flush_ht_params );
320
+ if (err ) {
321
+ kfree (flush_node );
322
+ return ERR_PTR (err );
323
+ }
324
+ router_xm -> flush_count ++ ;
325
+ flush_node -> mlxsw_sp = mlxsw_sp ;
326
+ flush_node -> start_jiffies = jiffies ;
327
+ refcount_set (& flush_node -> refcnt , 1 );
328
+ return flush_node ;
329
+ }
330
+
331
+ static void
332
+ mlxsw_sp_router_xm_cache_flush_node_hold (struct mlxsw_sp_router_xm_flush_node * flush_node )
333
+ {
334
+ if (!flush_node )
335
+ return ;
336
+ refcount_inc (& flush_node -> refcnt );
337
+ }
338
+
339
+ static void
340
+ mlxsw_sp_router_xm_cache_flush_node_put (struct mlxsw_sp_router_xm_flush_node * flush_node )
341
+ {
342
+ if (!flush_node || !refcount_dec_and_test (& flush_node -> refcnt ))
343
+ return ;
344
+ kfree (flush_node );
345
+ }
346
+
347
+ static void
348
+ mlxsw_sp_router_xm_cache_flush_node_destroy (struct mlxsw_sp * mlxsw_sp ,
349
+ struct mlxsw_sp_router_xm_flush_node * flush_node )
350
+ {
351
+ struct mlxsw_sp_router_xm * router_xm = mlxsw_sp -> router -> xm ;
352
+
353
+ router_xm -> flush_count -- ;
354
+ rhashtable_remove_fast (& router_xm -> flush_ht , & flush_node -> ht_node ,
355
+ mlxsw_sp_router_xm_flush_ht_params );
356
+ mlxsw_sp_router_xm_cache_flush_node_put (flush_node );
357
+ }
358
+
359
+ static u32 mlxsw_sp_router_xm_flush_mask4 (u8 prefix_len )
360
+ {
361
+ return GENMASK (31 , 32 - prefix_len );
362
+ }
363
+
364
+ static unsigned char * mlxsw_sp_router_xm_flush_mask6 (u8 prefix_len )
365
+ {
366
+ static unsigned char mask [sizeof (struct in6_addr )];
367
+
368
+ memset (mask , 0 , sizeof (mask ));
369
+ memset (mask , 0xff , prefix_len / 8 );
370
+ mask [prefix_len / 8 ] = GENMASK (8 , 8 - prefix_len % 8 );
371
+ return mask ;
372
+ }
373
+
374
+ #define MLXSW_SP_ROUTER_XM_CACHE_PARALLEL_FLUSHES_LIMIT 15
375
+ #define MLXSW_SP_ROUTER_XM_CACHE_FLUSH_ALL_MIN_REUSES 15
376
+ #define MLXSW_SP_ROUTER_XM_CACHE_DELAY 50 /* usecs */
377
+ #define MLXSW_SP_ROUTER_XM_CACHE_MAX_WAIT (MLXSW_SP_ROUTER_XM_CACHE_DELAY * 10)
378
+
379
+ static void mlxsw_sp_router_xm_cache_flush_work (struct work_struct * work )
380
+ {
381
+ struct mlxsw_sp_router_xm_flush_info * flush_info ;
382
+ struct mlxsw_sp_router_xm_flush_node * flush_node ;
383
+ char rlcmld_pl [MLXSW_REG_RLCMLD_LEN ];
384
+ enum mlxsw_reg_rlcmld_select select ;
385
+ struct mlxsw_sp * mlxsw_sp ;
386
+ u32 addr4 ;
387
+ int err ;
388
+
389
+ flush_node = container_of (work , struct mlxsw_sp_router_xm_flush_node ,
390
+ dw .work );
391
+ mlxsw_sp = flush_node -> mlxsw_sp ;
392
+ flush_info = & flush_node -> flush_info ;
393
+
394
+ if (flush_info -> all ) {
395
+ char rlpmce_pl [MLXSW_REG_RLPMCE_LEN ];
396
+
397
+ mlxsw_reg_rlpmce_pack (rlpmce_pl , true, false);
398
+ err = mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (rlpmce ),
399
+ rlpmce_pl );
400
+ if (err )
401
+ dev_err (mlxsw_sp -> bus_info -> dev , "Failed to flush XM cache\n" );
402
+
403
+ if (flush_node -> reuses <
404
+ MLXSW_SP_ROUTER_XM_CACHE_FLUSH_ALL_MIN_REUSES )
405
+ /* Leaving flush-all mode. */
406
+ mlxsw_sp -> router -> xm -> flush_all_mode = false;
407
+ goto out ;
408
+ }
409
+
410
+ select = MLXSW_REG_RLCMLD_SELECT_M_AND_ML_ENTRIES ;
411
+
412
+ switch (flush_info -> proto ) {
413
+ case MLXSW_SP_L3_PROTO_IPV4 :
414
+ addr4 = * ((u32 * ) flush_info -> addr );
415
+ addr4 &= mlxsw_sp_router_xm_flush_mask4 (flush_info -> prefix_len );
416
+
417
+ /* In case the flush prefix length is bigger than M-value,
418
+ * it makes no sense to flush M entries. So just flush
419
+ * the ML entries.
420
+ */
421
+ if (flush_info -> prefix_len > MLXSW_SP_ROUTER_XM_M_VAL )
422
+ select = MLXSW_REG_RLCMLD_SELECT_ML_ENTRIES ;
423
+
424
+ mlxsw_reg_rlcmld_pack4 (rlcmld_pl , select ,
425
+ flush_info -> virtual_router , addr4 ,
426
+ mlxsw_sp_router_xm_flush_mask4 (flush_info -> prefix_len ));
427
+ break ;
428
+ case MLXSW_SP_L3_PROTO_IPV6 :
429
+ mlxsw_reg_rlcmld_pack6 (rlcmld_pl , select ,
430
+ flush_info -> virtual_router , flush_info -> addr ,
431
+ mlxsw_sp_router_xm_flush_mask6 (flush_info -> prefix_len ));
432
+ break ;
433
+ default :
434
+ WARN_ON (true);
435
+ goto out ;
436
+ }
437
+ err = mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (rlcmld ), rlcmld_pl );
438
+ if (err )
439
+ dev_err (mlxsw_sp -> bus_info -> dev , "Failed to flush XM cache\n" );
440
+
441
+ out :
442
+ mlxsw_sp_router_xm_cache_flush_node_destroy (mlxsw_sp , flush_node );
443
+ }
444
+
445
+ static bool
446
+ mlxsw_sp_router_xm_cache_flush_may_cancel (struct mlxsw_sp_router_xm_flush_node * flush_node )
447
+ {
448
+ unsigned long max_wait = usecs_to_jiffies (MLXSW_SP_ROUTER_XM_CACHE_MAX_WAIT );
449
+ unsigned long delay = usecs_to_jiffies (MLXSW_SP_ROUTER_XM_CACHE_DELAY );
450
+
451
+ /* In case there is the same flushing work pending, check
452
+ * if we can consolidate with it. We can do it up to MAX_WAIT.
453
+ * Cancel the delayed work. If the work was still pending.
454
+ */
455
+ if (time_is_before_jiffies (flush_node -> start_jiffies + max_wait - delay ) &&
456
+ cancel_delayed_work_sync (& flush_node -> dw ))
457
+ return true;
458
+ return false;
459
+ }
460
+
461
+ static int
462
+ mlxsw_sp_router_xm_cache_flush_schedule (struct mlxsw_sp * mlxsw_sp ,
463
+ struct mlxsw_sp_router_xm_flush_info * flush_info )
464
+ {
465
+ unsigned long delay = usecs_to_jiffies (MLXSW_SP_ROUTER_XM_CACHE_DELAY );
466
+ struct mlxsw_sp_router_xm_flush_info flush_all_info = {.all = true};
467
+ struct mlxsw_sp_router_xm * router_xm = mlxsw_sp -> router -> xm ;
468
+ struct mlxsw_sp_router_xm_flush_node * flush_node ;
469
+
470
+ /* Check if the queued number of flushes reached critical amount after
471
+ * which it is better to just flush the whole cache.
472
+ */
473
+ if (router_xm -> flush_count == MLXSW_SP_ROUTER_XM_CACHE_PARALLEL_FLUSHES_LIMIT )
474
+ /* Entering flush-all mode. */
475
+ router_xm -> flush_all_mode = true;
476
+
477
+ if (router_xm -> flush_all_mode )
478
+ flush_info = & flush_all_info ;
479
+
480
+ rcu_read_lock ();
481
+ flush_node = rhashtable_lookup_fast (& router_xm -> flush_ht , flush_info ,
482
+ mlxsw_sp_router_xm_flush_ht_params );
483
+ /* Take a reference so the object is not freed before possible
484
+ * delayed work cancel could be done.
485
+ */
486
+ mlxsw_sp_router_xm_cache_flush_node_hold (flush_node );
487
+ rcu_read_unlock ();
488
+
489
+ if (flush_node && mlxsw_sp_router_xm_cache_flush_may_cancel (flush_node )) {
490
+ flush_node -> reuses ++ ;
491
+ mlxsw_sp_router_xm_cache_flush_node_put (flush_node );
492
+ /* Original work was within wait period and was canceled.
493
+ * That means that the reference is still held and the
494
+ * flush_node_put() call above did not free the flush_node.
495
+ * Reschedule it with fresh delay.
496
+ */
497
+ goto schedule_work ;
498
+ } else {
499
+ mlxsw_sp_router_xm_cache_flush_node_put (flush_node );
500
+ }
501
+
502
+ flush_node = mlxsw_sp_router_xm_cache_flush_node_create (mlxsw_sp , flush_info );
503
+ if (IS_ERR (flush_node ))
504
+ return PTR_ERR (flush_node );
505
+ INIT_DELAYED_WORK (& flush_node -> dw , mlxsw_sp_router_xm_cache_flush_work );
506
+
507
+ schedule_work :
508
+ mlxsw_core_schedule_dw (& flush_node -> dw , delay );
509
+ return 0 ;
510
+ }
511
+
265
512
static int
266
513
mlxsw_sp_router_xm_ml_entry_add (struct mlxsw_sp * mlxsw_sp ,
267
514
struct mlxsw_sp_router_xm_fib_entry * fib_entry )
@@ -282,10 +529,18 @@ mlxsw_sp_router_xm_ml_entry_add(struct mlxsw_sp *mlxsw_sp,
282
529
ltable_node );
283
530
if (err )
284
531
goto err_lvalue_set ;
532
+
533
+ /* The L value for prefix/M is increased.
534
+ * Therefore, all entries in M and ML caches matching
535
+ * {prefix/M, proto, VR} need to be flushed. Set the flush
536
+ * prefix length to M to achieve that.
537
+ */
538
+ fib_entry -> flush_info .prefix_len = MLXSW_SP_ROUTER_XM_M_VAL ;
285
539
}
286
540
287
541
ltable_node -> lvalue_ref [lvalue ]++ ;
288
542
fib_entry -> ltable_node = ltable_node ;
543
+
289
544
return 0 ;
290
545
291
546
err_lvalue_set :
@@ -313,6 +568,13 @@ mlxsw_sp_router_xm_ml_entry_del(struct mlxsw_sp *mlxsw_sp,
313
568
314
569
ltable_node -> current_lvalue = new_lvalue ;
315
570
mlxsw_sp_router_xm_ltable_lvalue_set (mlxsw_sp , ltable_node );
571
+
572
+ /* The L value for prefix/M is decreased.
573
+ * Therefore, all entries in M and ML caches matching
574
+ * {prefix/M, proto, VR} need to be flushed. Set the flush
575
+ * prefix length to M to achieve that.
576
+ */
577
+ fib_entry -> flush_info .prefix_len = MLXSW_SP_ROUTER_XM_M_VAL ;
316
578
}
317
579
mlxsw_sp_router_xm_ltable_node_put (router_xm , ltable_node );
318
580
}
@@ -354,6 +616,23 @@ mlxsw_sp_router_xm_ml_entries_del(struct mlxsw_sp *mlxsw_sp,
354
616
}
355
617
}
356
618
619
+ static void
620
+ mlxsw_sp_router_xm_ml_entries_cache_flush (struct mlxsw_sp * mlxsw_sp ,
621
+ struct mlxsw_sp_fib_entry_op_ctx_xm * op_ctx_xm )
622
+ {
623
+ struct mlxsw_sp_router_xm_fib_entry * fib_entry ;
624
+ int err ;
625
+ int i ;
626
+
627
+ for (i = 0 ; i < op_ctx_xm -> entries_count ; i ++ ) {
628
+ fib_entry = op_ctx_xm -> entries [i ];
629
+ err = mlxsw_sp_router_xm_cache_flush_schedule (mlxsw_sp ,
630
+ & fib_entry -> flush_info );
631
+ if (err )
632
+ dev_err (mlxsw_sp -> bus_info -> dev , "Failed to flush XM cache\n" );
633
+ }
634
+ }
635
+
357
636
static int mlxsw_sp_router_ll_xm_fib_entry_commit (struct mlxsw_sp * mlxsw_sp ,
358
637
struct mlxsw_sp_fib_entry_op_ctx * op_ctx ,
359
638
bool * postponed_for_bulk )
@@ -414,6 +693,11 @@ static int mlxsw_sp_router_ll_xm_fib_entry_commit(struct mlxsw_sp *mlxsw_sp,
414
693
*/
415
694
mlxsw_sp_router_xm_ml_entries_del (mlxsw_sp , op_ctx_xm );
416
695
696
+ /* At the very end, do the XLT cache flushing to evict stale
697
+ * M and ML cache entries after prefixes were inserted/removed.
698
+ */
699
+ mlxsw_sp_router_xm_ml_entries_cache_flush (mlxsw_sp , op_ctx_xm );
700
+
417
701
out :
418
702
/* Next pack call is going to do reinitialization */
419
703
op_ctx -> initialized = false;
@@ -490,9 +774,15 @@ int mlxsw_sp_router_xm_init(struct mlxsw_sp *mlxsw_sp)
490
774
if (err )
491
775
goto err_ltable_ht_init ;
492
776
777
+ err = rhashtable_init (& router_xm -> flush_ht , & mlxsw_sp_router_xm_flush_ht_params );
778
+ if (err )
779
+ goto err_flush_ht_init ;
780
+
493
781
mlxsw_sp -> router -> xm = router_xm ;
494
782
return 0 ;
495
783
784
+ err_flush_ht_init :
785
+ rhashtable_destroy (& router_xm -> ltable_ht );
496
786
err_ltable_ht_init :
497
787
err_rxltm_write :
498
788
err_mindex_size_check :
@@ -509,6 +799,7 @@ void mlxsw_sp_router_xm_fini(struct mlxsw_sp *mlxsw_sp)
509
799
if (!mlxsw_sp -> bus_info -> xm_exists )
510
800
return ;
511
801
802
+ rhashtable_destroy (& router_xm -> flush_ht );
512
803
rhashtable_destroy (& router_xm -> ltable_ht );
513
804
kfree (router_xm );
514
805
}
0 commit comments