46
46
#define mlxsw_sp_prefix_usage_for_each (prefix , prefix_usage ) \
47
47
for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
48
48
49
+ static bool
50
+ mlxsw_sp_prefix_usage_subset (struct mlxsw_sp_prefix_usage * prefix_usage1 ,
51
+ struct mlxsw_sp_prefix_usage * prefix_usage2 )
52
+ {
53
+ unsigned char prefix ;
54
+
55
+ mlxsw_sp_prefix_usage_for_each (prefix , prefix_usage1 ) {
56
+ if (!test_bit (prefix , prefix_usage2 -> b ))
57
+ return false;
58
+ }
59
+ return true;
60
+ }
61
+
49
62
static bool
50
63
mlxsw_sp_prefix_usage_eq (struct mlxsw_sp_prefix_usage * prefix_usage1 ,
51
64
struct mlxsw_sp_prefix_usage * prefix_usage2 )
52
65
{
53
66
return !memcmp (prefix_usage1 , prefix_usage2 , sizeof (* prefix_usage1 ));
54
67
}
55
68
69
+ static bool
70
+ mlxsw_sp_prefix_usage_none (struct mlxsw_sp_prefix_usage * prefix_usage )
71
+ {
72
+ struct mlxsw_sp_prefix_usage prefix_usage_none = {{ 0 } };
73
+
74
+ return mlxsw_sp_prefix_usage_eq (prefix_usage , & prefix_usage_none );
75
+ }
76
+
77
+ static void
78
+ mlxsw_sp_prefix_usage_cpy (struct mlxsw_sp_prefix_usage * prefix_usage1 ,
79
+ struct mlxsw_sp_prefix_usage * prefix_usage2 )
80
+ {
81
+ memcpy (prefix_usage1 , prefix_usage2 , sizeof (* prefix_usage1 ));
82
+ }
83
+
84
+ static void
85
+ mlxsw_sp_prefix_usage_zero (struct mlxsw_sp_prefix_usage * prefix_usage )
86
+ {
87
+ memset (prefix_usage , 0 , sizeof (* prefix_usage ));
88
+ }
89
+
56
90
static void
57
91
mlxsw_sp_prefix_usage_set (struct mlxsw_sp_prefix_usage * prefix_usage ,
58
92
unsigned char prefix_len )
@@ -307,6 +341,199 @@ static void mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
307
341
}
308
342
}
309
343
344
+ static struct mlxsw_sp_vr * mlxsw_sp_vr_find_unused (struct mlxsw_sp * mlxsw_sp )
345
+ {
346
+ struct mlxsw_sp_vr * vr ;
347
+ int i ;
348
+
349
+ for (i = 0 ; i < MLXSW_SP_VIRTUAL_ROUTER_MAX ; i ++ ) {
350
+ vr = & mlxsw_sp -> router .vrs [i ];
351
+ if (!vr -> used )
352
+ return vr ;
353
+ }
354
+ return NULL ;
355
+ }
356
+
357
+ static int mlxsw_sp_vr_lpm_tree_bind (struct mlxsw_sp * mlxsw_sp ,
358
+ struct mlxsw_sp_vr * vr )
359
+ {
360
+ char raltb_pl [MLXSW_REG_RALTB_LEN ];
361
+
362
+ mlxsw_reg_raltb_pack (raltb_pl , vr -> id , vr -> proto , vr -> lpm_tree -> id );
363
+ return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (raltb ), raltb_pl );
364
+ }
365
+
366
+ static int mlxsw_sp_vr_lpm_tree_unbind (struct mlxsw_sp * mlxsw_sp ,
367
+ struct mlxsw_sp_vr * vr )
368
+ {
369
+ char raltb_pl [MLXSW_REG_RALTB_LEN ];
370
+
371
+ /* Bind to tree 0 which is default */
372
+ mlxsw_reg_raltb_pack (raltb_pl , vr -> id , vr -> proto , 0 );
373
+ return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (raltb ), raltb_pl );
374
+ }
375
+
376
+ static u32 mlxsw_sp_fix_tb_id (u32 tb_id )
377
+ {
378
+ /* For our purpose, squash main and local table into one */
379
+ if (tb_id == RT_TABLE_LOCAL )
380
+ tb_id = RT_TABLE_MAIN ;
381
+ return tb_id ;
382
+ }
383
+
384
+ static struct mlxsw_sp_vr * mlxsw_sp_vr_find (struct mlxsw_sp * mlxsw_sp ,
385
+ u32 tb_id ,
386
+ enum mlxsw_sp_l3proto proto )
387
+ {
388
+ struct mlxsw_sp_vr * vr ;
389
+ int i ;
390
+
391
+ tb_id = mlxsw_sp_fix_tb_id (tb_id );
392
+ for (i = 0 ; i < MLXSW_SP_VIRTUAL_ROUTER_MAX ; i ++ ) {
393
+ vr = & mlxsw_sp -> router .vrs [i ];
394
+ if (vr -> used && vr -> proto == proto && vr -> tb_id == tb_id )
395
+ return vr ;
396
+ }
397
+ return NULL ;
398
+ }
399
+
400
+ static struct mlxsw_sp_vr * mlxsw_sp_vr_create (struct mlxsw_sp * mlxsw_sp ,
401
+ unsigned char prefix_len ,
402
+ u32 tb_id ,
403
+ enum mlxsw_sp_l3proto proto )
404
+ {
405
+ struct mlxsw_sp_prefix_usage req_prefix_usage ;
406
+ struct mlxsw_sp_lpm_tree * lpm_tree ;
407
+ struct mlxsw_sp_vr * vr ;
408
+ int err ;
409
+
410
+ vr = mlxsw_sp_vr_find_unused (mlxsw_sp );
411
+ if (!vr )
412
+ return ERR_PTR (- EBUSY );
413
+ vr -> fib = mlxsw_sp_fib_create ();
414
+ if (IS_ERR (vr -> fib ))
415
+ return ERR_CAST (vr -> fib );
416
+
417
+ vr -> proto = proto ;
418
+ vr -> tb_id = tb_id ;
419
+ mlxsw_sp_prefix_usage_zero (& req_prefix_usage );
420
+ mlxsw_sp_prefix_usage_set (& req_prefix_usage , prefix_len );
421
+ lpm_tree = mlxsw_sp_lpm_tree_get (mlxsw_sp , & req_prefix_usage ,
422
+ proto , true);
423
+ if (IS_ERR (lpm_tree )) {
424
+ err = PTR_ERR (lpm_tree );
425
+ goto err_tree_get ;
426
+ }
427
+ vr -> lpm_tree = lpm_tree ;
428
+ err = mlxsw_sp_vr_lpm_tree_bind (mlxsw_sp , vr );
429
+ if (err )
430
+ goto err_tree_bind ;
431
+
432
+ vr -> used = true;
433
+ return vr ;
434
+
435
+ err_tree_bind :
436
+ mlxsw_sp_lpm_tree_put (mlxsw_sp , vr -> lpm_tree );
437
+ err_tree_get :
438
+ mlxsw_sp_fib_destroy (vr -> fib );
439
+
440
+ return ERR_PTR (err );
441
+ }
442
+
443
+ static void mlxsw_sp_vr_destroy (struct mlxsw_sp * mlxsw_sp ,
444
+ struct mlxsw_sp_vr * vr )
445
+ {
446
+ mlxsw_sp_vr_lpm_tree_unbind (mlxsw_sp , vr );
447
+ mlxsw_sp_lpm_tree_put (mlxsw_sp , vr -> lpm_tree );
448
+ mlxsw_sp_fib_destroy (vr -> fib );
449
+ vr -> used = false;
450
+ }
451
+
452
+ static int
453
+ mlxsw_sp_vr_lpm_tree_check (struct mlxsw_sp * mlxsw_sp , struct mlxsw_sp_vr * vr ,
454
+ struct mlxsw_sp_prefix_usage * req_prefix_usage )
455
+ {
456
+ struct mlxsw_sp_lpm_tree * lpm_tree ;
457
+
458
+ if (mlxsw_sp_prefix_usage_eq (req_prefix_usage ,
459
+ & vr -> lpm_tree -> prefix_usage ))
460
+ return 0 ;
461
+
462
+ lpm_tree = mlxsw_sp_lpm_tree_get (mlxsw_sp , req_prefix_usage ,
463
+ vr -> proto , false);
464
+ if (IS_ERR (lpm_tree )) {
465
+ /* We failed to get a tree according to the required
466
+ * prefix usage. However, the current tree might be still good
467
+ * for us if our requirement is subset of the prefixes used
468
+ * in the tree.
469
+ */
470
+ if (mlxsw_sp_prefix_usage_subset (req_prefix_usage ,
471
+ & vr -> lpm_tree -> prefix_usage ))
472
+ return 0 ;
473
+ return PTR_ERR (lpm_tree );
474
+ }
475
+
476
+ mlxsw_sp_vr_lpm_tree_unbind (mlxsw_sp , vr );
477
+ mlxsw_sp_lpm_tree_put (mlxsw_sp , vr -> lpm_tree );
478
+ vr -> lpm_tree = lpm_tree ;
479
+ return mlxsw_sp_vr_lpm_tree_bind (mlxsw_sp , vr );
480
+ }
481
+
482
+ static struct mlxsw_sp_vr * mlxsw_sp_vr_get (struct mlxsw_sp * mlxsw_sp ,
483
+ unsigned char prefix_len ,
484
+ u32 tb_id ,
485
+ enum mlxsw_sp_l3proto proto )
486
+ {
487
+ struct mlxsw_sp_vr * vr ;
488
+ int err ;
489
+
490
+ tb_id = mlxsw_sp_fix_tb_id (tb_id );
491
+ vr = mlxsw_sp_vr_find (mlxsw_sp , tb_id , proto );
492
+ if (!vr ) {
493
+ vr = mlxsw_sp_vr_create (mlxsw_sp , prefix_len , tb_id , proto );
494
+ if (IS_ERR (vr ))
495
+ return vr ;
496
+ } else {
497
+ struct mlxsw_sp_prefix_usage req_prefix_usage ;
498
+
499
+ mlxsw_sp_prefix_usage_cpy (& req_prefix_usage ,
500
+ & vr -> fib -> prefix_usage );
501
+ mlxsw_sp_prefix_usage_set (& req_prefix_usage , prefix_len );
502
+ /* Need to replace LPM tree in case new prefix is required. */
503
+ err = mlxsw_sp_vr_lpm_tree_check (mlxsw_sp , vr ,
504
+ & req_prefix_usage );
505
+ if (err )
506
+ return ERR_PTR (err );
507
+ }
508
+ return vr ;
509
+ }
510
+
511
+ static void mlxsw_sp_vr_put (struct mlxsw_sp * mlxsw_sp , struct mlxsw_sp_vr * vr )
512
+ {
513
+ /* Destroy virtual router entity in case the associated FIB is empty
514
+ * and allow it to be used for other tables in future. Otherwise,
515
+ * check if some prefix usage did not disappear and change tree if
516
+ * that is the case. Note that in case new, smaller tree cannot be
517
+ * allocated, the original one will be kept being used.
518
+ */
519
+ if (mlxsw_sp_prefix_usage_none (& vr -> fib -> prefix_usage ))
520
+ mlxsw_sp_vr_destroy (mlxsw_sp , vr );
521
+ else
522
+ mlxsw_sp_vr_lpm_tree_check (mlxsw_sp , vr ,
523
+ & vr -> fib -> prefix_usage );
524
+ }
525
+
526
+ static void mlxsw_sp_vrs_init (struct mlxsw_sp * mlxsw_sp )
527
+ {
528
+ struct mlxsw_sp_vr * vr ;
529
+ int i ;
530
+
531
+ for (i = 0 ; i < MLXSW_SP_VIRTUAL_ROUTER_MAX ; i ++ ) {
532
+ vr = & mlxsw_sp -> router .vrs [i ];
533
+ vr -> id = i ;
534
+ }
535
+ }
536
+
310
537
static int __mlxsw_sp_router_init (struct mlxsw_sp * mlxsw_sp )
311
538
{
312
539
char rgcr_pl [MLXSW_REG_RGCR_LEN ];
@@ -332,6 +559,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
332
559
if (err )
333
560
return err ;
334
561
mlxsw_sp_lpm_init (mlxsw_sp );
562
+ mlxsw_sp_vrs_init (mlxsw_sp );
335
563
return 0 ;
336
564
}
337
565
0 commit comments