@@ -158,6 +158,15 @@ static const struct rhashtable_params rhash_fte = {
158
158
.min_size = 1 ,
159
159
};
160
160
161
+ static const struct rhashtable_params rhash_fg = {
162
+ .key_len = FIELD_SIZEOF (struct mlx5_flow_group , mask ),
163
+ .key_offset = offsetof(struct mlx5_flow_group , mask ),
164
+ .head_offset = offsetof(struct mlx5_flow_group , hash ),
165
+ .automatic_shrinking = true,
166
+ .min_size = 1 ,
167
+
168
+ };
169
+
161
170
static void del_rule (struct fs_node * node );
162
171
static void del_flow_table (struct fs_node * node );
163
172
static void del_flow_group (struct fs_node * node );
@@ -318,12 +327,22 @@ static bool check_valid_mask(u8 match_criteria_enable, const u32 *match_criteria
318
327
return check_last_reserved (match_criteria );
319
328
}
320
329
321
- static bool compare_match_criteria (u8 match_criteria_enable1 ,
322
- u8 match_criteria_enable2 ,
323
- void * mask1 , void * mask2 )
330
+ static bool check_valid_spec (const struct mlx5_flow_spec * spec )
324
331
{
325
- return match_criteria_enable1 == match_criteria_enable2 &&
326
- !memcmp (mask1 , mask2 , MLX5_ST_SZ_BYTES (fte_match_param ));
332
+ int i ;
333
+
334
+ if (!check_valid_mask (spec -> match_criteria_enable , spec -> match_criteria )) {
335
+ pr_warn ("mlx5_core: Match criteria given mismatches match_criteria_enable\n" );
336
+ return false;
337
+ }
338
+
339
+ for (i = 0 ; i < MLX5_ST_SZ_DW_MATCH_PARAM ; i ++ )
340
+ if (spec -> match_value [i ] & ~spec -> match_criteria [i ]) {
341
+ pr_warn ("mlx5_core: match_value differs from match_criteria\n" );
342
+ return false;
343
+ }
344
+
345
+ return check_last_reserved (spec -> match_value );
327
346
}
328
347
329
348
static struct mlx5_flow_root_namespace * find_root (struct fs_node * node )
@@ -365,6 +384,7 @@ static void del_flow_table(struct fs_node *node)
365
384
if (err )
366
385
mlx5_core_warn (dev , "flow steering can't destroy ft\n" );
367
386
ida_destroy (& ft -> fte_allocator );
387
+ rhltable_destroy (& ft -> fgs_hash );
368
388
fs_get_obj (prio , ft -> node .parent );
369
389
prio -> num_ft -- ;
370
390
}
@@ -454,6 +474,7 @@ static void del_flow_group(struct fs_node *node)
454
474
struct mlx5_flow_group * fg ;
455
475
struct mlx5_flow_table * ft ;
456
476
struct mlx5_core_dev * dev ;
477
+ int err ;
457
478
458
479
fs_get_obj (fg , node );
459
480
fs_get_obj (ft , fg -> node .parent );
@@ -463,6 +484,10 @@ static void del_flow_group(struct fs_node *node)
463
484
ft -> autogroup .num_groups -- ;
464
485
465
486
rhashtable_destroy (& fg -> ftes_hash );
487
+ err = rhltable_remove (& ft -> fgs_hash ,
488
+ & fg -> hash ,
489
+ rhash_fg );
490
+ WARN_ON (err );
466
491
if (mlx5_cmd_destroy_flow_group (dev , ft , fg -> id ))
467
492
mlx5_core_warn (dev , "flow steering can't destroy fg %d of ft %d\n" ,
468
493
fg -> id , ft -> id );
@@ -525,10 +550,17 @@ static struct mlx5_flow_table *alloc_flow_table(int level, u16 vport, int max_ft
525
550
u32 flags )
526
551
{
527
552
struct mlx5_flow_table * ft ;
553
+ int ret ;
528
554
529
555
ft = kzalloc (sizeof (* ft ), GFP_KERNEL );
530
556
if (!ft )
531
- return NULL ;
557
+ return ERR_PTR (- ENOMEM );
558
+
559
+ ret = rhltable_init (& ft -> fgs_hash , & rhash_fg );
560
+ if (ret ) {
561
+ kfree (ft );
562
+ return ERR_PTR (ret );
563
+ }
532
564
533
565
ft -> level = level ;
534
566
ft -> node .type = FS_TYPE_FLOW_TABLE ;
@@ -829,8 +861,8 @@ static struct mlx5_flow_table *__mlx5_create_flow_table(struct mlx5_flow_namespa
829
861
ft_attr -> max_fte ? roundup_pow_of_two (ft_attr -> max_fte ) : 0 ,
830
862
root -> table_type ,
831
863
op_mod , ft_attr -> flags );
832
- if (! ft ) {
833
- err = - ENOMEM ;
864
+ if (IS_ERR ( ft ) ) {
865
+ err = PTR_ERR ( ft ) ;
834
866
goto unlock_root ;
835
867
}
836
868
@@ -942,10 +974,14 @@ static struct mlx5_flow_group *create_flow_group_common(struct mlx5_flow_table *
942
974
if (IS_ERR (fg ))
943
975
return fg ;
944
976
945
- err = mlx5_cmd_create_flow_group ( dev , ft , fg_in , & fg -> id );
977
+ err = rhltable_insert ( & ft -> fgs_hash , & fg -> hash , rhash_fg );
946
978
if (err )
947
979
goto err_free_fg ;
948
980
981
+ err = mlx5_cmd_create_flow_group (dev , ft , fg_in , & fg -> id );
982
+ if (err )
983
+ goto err_remove_fg ;
984
+
949
985
if (ft -> autogroup .active )
950
986
ft -> autogroup .num_groups ++ ;
951
987
/* Add node to tree */
@@ -956,6 +992,10 @@ static struct mlx5_flow_group *create_flow_group_common(struct mlx5_flow_table *
956
992
957
993
return fg ;
958
994
995
+ err_remove_fg :
996
+ WARN_ON (rhltable_remove (& ft -> fgs_hash ,
997
+ & fg -> hash ,
998
+ rhash_fg ));
959
999
err_free_fg :
960
1000
rhashtable_destroy (& fg -> ftes_hash );
961
1001
kfree (fg );
@@ -1291,18 +1331,13 @@ static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg,
1291
1331
u32 * match_value ,
1292
1332
struct mlx5_flow_act * flow_act ,
1293
1333
struct mlx5_flow_destination * dest ,
1294
- int dest_num )
1334
+ int dest_num ,
1335
+ struct fs_fte * fte )
1295
1336
{
1296
- u32 masked_val [sizeof (fg -> mask .match_criteria )];
1297
1337
struct mlx5_flow_handle * handle ;
1298
1338
struct mlx5_flow_table * ft ;
1299
- struct fs_fte * fte ;
1300
1339
int i ;
1301
1340
1302
- nested_lock_ref_node (& fg -> node , FS_MUTEX_PARENT );
1303
- for (i = 0 ; i < sizeof (masked_val ); i ++ )
1304
- masked_val [i ] = match_value [i ] & fg -> mask .match_criteria [i ];
1305
- fte = rhashtable_lookup_fast (& fg -> ftes_hash , masked_val , rhash_fte );
1306
1341
if (fte ) {
1307
1342
int old_action ;
1308
1343
int ret ;
@@ -1324,23 +1359,20 @@ static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg,
1324
1359
} else {
1325
1360
goto add_rules ;
1326
1361
}
1327
- unlock_ref_node (& fte -> node );
1328
1362
}
1329
1363
fs_get_obj (ft , fg -> node .parent );
1330
1364
1331
1365
fte = create_fte (fg , match_value , flow_act );
1332
- if (IS_ERR (fte )) {
1333
- handle = (void * )fte ;
1334
- goto unlock_fg ;
1335
- }
1366
+ if (IS_ERR (fte ))
1367
+ return (void * )fte ;
1336
1368
tree_init_node (& fte -> node , 0 , del_fte );
1337
1369
nested_lock_ref_node (& fte -> node , FS_MUTEX_CHILD );
1338
1370
handle = add_rule_fte (fte , fg , dest , dest_num , false);
1339
1371
if (IS_ERR (handle )) {
1340
1372
unlock_ref_node (& fte -> node );
1341
1373
destroy_fte (fte , fg );
1342
1374
kfree (fte );
1343
- goto unlock_fg ;
1375
+ return handle ;
1344
1376
}
1345
1377
1346
1378
tree_add_node (& fte -> node , & fg -> node );
@@ -1353,8 +1385,6 @@ static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg,
1353
1385
}
1354
1386
unlock_fte :
1355
1387
unlock_ref_node (& fte -> node );
1356
- unlock_fg :
1357
- unlock_ref_node (& fg -> node );
1358
1388
return handle ;
1359
1389
}
1360
1390
@@ -1402,6 +1432,96 @@ static bool dest_is_valid(struct mlx5_flow_destination *dest,
1402
1432
return true;
1403
1433
}
1404
1434
1435
+ static struct mlx5_flow_handle *
1436
+ try_add_to_existing_fg (struct mlx5_flow_table * ft ,
1437
+ struct mlx5_flow_spec * spec ,
1438
+ struct mlx5_flow_act * flow_act ,
1439
+ struct mlx5_flow_destination * dest ,
1440
+ int dest_num )
1441
+ {
1442
+ struct mlx5_flow_group * g ;
1443
+ struct mlx5_flow_handle * rule = ERR_PTR (- ENOENT );
1444
+ struct rhlist_head * tmp , * list ;
1445
+ struct match_list {
1446
+ struct list_head list ;
1447
+ struct mlx5_flow_group * g ;
1448
+ } match_list , * iter ;
1449
+ LIST_HEAD (match_head );
1450
+
1451
+ rcu_read_lock ();
1452
+ /* Collect all fgs which has a matching match_criteria */
1453
+ list = rhltable_lookup (& ft -> fgs_hash , spec , rhash_fg );
1454
+ rhl_for_each_entry_rcu (g , tmp , list , hash ) {
1455
+ struct match_list * curr_match ;
1456
+
1457
+ if (likely (list_empty (& match_head ))) {
1458
+ match_list .g = g ;
1459
+ list_add_tail (& match_list .list , & match_head );
1460
+ continue ;
1461
+ }
1462
+ curr_match = kmalloc (sizeof (* curr_match ), GFP_ATOMIC );
1463
+
1464
+ if (!curr_match ) {
1465
+ rcu_read_unlock ();
1466
+ rule = ERR_PTR (- ENOMEM );
1467
+ goto free_list ;
1468
+ }
1469
+ curr_match -> g = g ;
1470
+ list_add_tail (& curr_match -> list , & match_head );
1471
+ }
1472
+ rcu_read_unlock ();
1473
+
1474
+ /* Try to find a fg that already contains a matching fte */
1475
+ list_for_each_entry (iter , & match_head , list ) {
1476
+ struct fs_fte * fte ;
1477
+
1478
+ g = iter -> g ;
1479
+ nested_lock_ref_node (& g -> node , FS_MUTEX_PARENT );
1480
+ fte = rhashtable_lookup_fast (& g -> ftes_hash , spec -> match_value ,
1481
+ rhash_fte );
1482
+ if (fte ) {
1483
+ rule = add_rule_fg (g , spec -> match_value ,
1484
+ flow_act , dest , dest_num , fte );
1485
+ unlock_ref_node (& g -> node );
1486
+ goto free_list ;
1487
+ }
1488
+ unlock_ref_node (& g -> node );
1489
+ }
1490
+
1491
+ /* No group with matching fte found. Try to add a new fte to any
1492
+ * matching fg.
1493
+ */
1494
+ list_for_each_entry (iter , & match_head , list ) {
1495
+ g = iter -> g ;
1496
+
1497
+ nested_lock_ref_node (& g -> node , FS_MUTEX_PARENT );
1498
+ rule = add_rule_fg (g , spec -> match_value ,
1499
+ flow_act , dest , dest_num , NULL );
1500
+ if (!IS_ERR (rule ) || PTR_ERR (rule ) != - ENOSPC ) {
1501
+ unlock_ref_node (& g -> node );
1502
+ goto free_list ;
1503
+ }
1504
+ unlock_ref_node (& g -> node );
1505
+ }
1506
+
1507
+ free_list :
1508
+ if (!list_empty (& match_head )) {
1509
+ struct match_list * match_tmp ;
1510
+
1511
+ /* The most common case is having one FG. Since we want to
1512
+ * optimize this case, we save the first on the stack.
1513
+ * Therefore, no need to free it.
1514
+ */
1515
+ list_del (& list_first_entry (& match_head , typeof (* iter ), list )-> list );
1516
+ list_for_each_entry_safe (iter , match_tmp , & match_head , list ) {
1517
+ list_del (& iter -> list );
1518
+ kfree (iter );
1519
+ }
1520
+ }
1521
+
1522
+ return rule ;
1523
+ }
1524
+
1405
1525
static struct mlx5_flow_handle *
1406
1526
_mlx5_add_flow_rules (struct mlx5_flow_table * ft ,
1407
1527
struct mlx5_flow_spec * spec ,
@@ -1414,8 +1534,7 @@ _mlx5_add_flow_rules(struct mlx5_flow_table *ft,
1414
1534
struct mlx5_flow_handle * rule ;
1415
1535
int i ;
1416
1536
1417
- if (!check_valid_mask (spec -> match_criteria_enable ,
1418
- spec -> match_criteria ))
1537
+ if (!check_valid_spec (spec ))
1419
1538
return ERR_PTR (- EINVAL );
1420
1539
1421
1540
for (i = 0 ; i < dest_num ; i ++ ) {
@@ -1424,16 +1543,9 @@ _mlx5_add_flow_rules(struct mlx5_flow_table *ft,
1424
1543
}
1425
1544
1426
1545
nested_lock_ref_node (& ft -> node , FS_MUTEX_GRANDPARENT );
1427
- fs_for_each_fg (g , ft )
1428
- if (compare_match_criteria (g -> mask .match_criteria_enable ,
1429
- spec -> match_criteria_enable ,
1430
- g -> mask .match_criteria ,
1431
- spec -> match_criteria )) {
1432
- rule = add_rule_fg (g , spec -> match_value ,
1433
- flow_act , dest , dest_num );
1434
- if (!IS_ERR (rule ) || PTR_ERR (rule ) != - ENOSPC )
1435
- goto unlock ;
1436
- }
1546
+ rule = try_add_to_existing_fg (ft , spec , flow_act , dest , dest_num );
1547
+ if (!IS_ERR (rule ))
1548
+ goto unlock ;
1437
1549
1438
1550
g = create_autogroup (ft , spec -> match_criteria_enable ,
1439
1551
spec -> match_criteria );
@@ -1442,7 +1554,8 @@ _mlx5_add_flow_rules(struct mlx5_flow_table *ft,
1442
1554
goto unlock ;
1443
1555
}
1444
1556
1445
- rule = add_rule_fg (g , spec -> match_value , flow_act , dest , dest_num );
1557
+ rule = add_rule_fg (g , spec -> match_value , flow_act , dest ,
1558
+ dest_num , NULL );
1446
1559
if (IS_ERR (rule )) {
1447
1560
/* Remove assumes refcount > 0 and autogroup creates a group
1448
1561
* with a refcount = 0.
0 commit comments