@@ -56,12 +56,14 @@ struct mlx5_nic_flow_attr {
56
56
u32 action ;
57
57
u32 flow_tag ;
58
58
u32 mod_hdr_id ;
59
+ u32 hairpin_tirn ;
59
60
};
60
61
61
62
enum {
62
63
MLX5E_TC_FLOW_ESWITCH = BIT (0 ),
63
64
MLX5E_TC_FLOW_NIC = BIT (1 ),
64
65
MLX5E_TC_FLOW_OFFLOADED = BIT (2 ),
66
+ MLX5E_TC_FLOW_HAIRPIN = BIT (3 ),
65
67
};
66
68
67
69
struct mlx5e_tc_flow {
@@ -71,6 +73,7 @@ struct mlx5e_tc_flow {
71
73
struct mlx5_flow_handle * rule ;
72
74
struct list_head encap ; /* flows sharing the same encap ID */
73
75
struct list_head mod_hdr ; /* flows sharing the same mod hdr ID */
76
+ struct list_head hairpin ; /* flows sharing the same hairpin */
74
77
union {
75
78
struct mlx5_esw_flow_attr esw_attr [0 ];
76
79
struct mlx5_nic_flow_attr nic_attr [0 ];
@@ -101,6 +104,17 @@ struct mlx5e_hairpin {
101
104
u32 tirn ;
102
105
};
103
106
107
+ struct mlx5e_hairpin_entry {
108
+ /* a node of a hash table which keeps all the hairpin entries */
109
+ struct hlist_node hairpin_hlist ;
110
+
111
+ /* flows sharing the same hairpin */
112
+ struct list_head flows ;
113
+
114
+ int peer_ifindex ;
115
+ struct mlx5e_hairpin * hp ;
116
+ };
117
+
104
118
struct mod_hdr_key {
105
119
int num_actions ;
106
120
void * actions ;
@@ -319,14 +333,106 @@ static void mlx5e_hairpin_destroy(struct mlx5e_hairpin *hp)
319
333
kvfree (hp );
320
334
}
321
335
336
+ static struct mlx5e_hairpin_entry * mlx5e_hairpin_get (struct mlx5e_priv * priv ,
337
+ int peer_ifindex )
338
+ {
339
+ struct mlx5e_hairpin_entry * hpe ;
340
+
341
+ hash_for_each_possible (priv -> fs .tc .hairpin_tbl , hpe ,
342
+ hairpin_hlist , peer_ifindex ) {
343
+ if (hpe -> peer_ifindex == peer_ifindex )
344
+ return hpe ;
345
+ }
346
+
347
+ return NULL ;
348
+ }
349
+
350
+ static int mlx5e_hairpin_flow_add (struct mlx5e_priv * priv ,
351
+ struct mlx5e_tc_flow * flow ,
352
+ struct mlx5e_tc_flow_parse_attr * parse_attr )
353
+ {
354
+ int peer_ifindex = parse_attr -> mirred_ifindex ;
355
+ struct mlx5_hairpin_params params ;
356
+ struct mlx5e_hairpin_entry * hpe ;
357
+ struct mlx5e_hairpin * hp ;
358
+ int err ;
359
+
360
+ if (!MLX5_CAP_GEN (priv -> mdev , hairpin )) {
361
+ netdev_warn (priv -> netdev , "hairpin is not supported\n" );
362
+ return - EOPNOTSUPP ;
363
+ }
364
+
365
+ hpe = mlx5e_hairpin_get (priv , peer_ifindex );
366
+ if (hpe )
367
+ goto attach_flow ;
368
+
369
+ hpe = kzalloc (sizeof (* hpe ), GFP_KERNEL );
370
+ if (!hpe )
371
+ return - ENOMEM ;
372
+
373
+ INIT_LIST_HEAD (& hpe -> flows );
374
+ hpe -> peer_ifindex = peer_ifindex ;
375
+
376
+ params .log_data_size = 15 ;
377
+ params .log_data_size = min_t (u8 , params .log_data_size ,
378
+ MLX5_CAP_GEN (priv -> mdev , log_max_hairpin_wq_data_sz ));
379
+ params .log_data_size = max_t (u8 , params .log_data_size ,
380
+ MLX5_CAP_GEN (priv -> mdev , log_min_hairpin_wq_data_sz ));
381
+ params .q_counter = priv -> q_counter ;
382
+
383
+ hp = mlx5e_hairpin_create (priv , & params , peer_ifindex );
384
+ if (IS_ERR (hp )) {
385
+ err = PTR_ERR (hp );
386
+ goto create_hairpin_err ;
387
+ }
388
+
389
+ netdev_dbg (priv -> netdev , "add hairpin: tirn %x rqn %x peer %s sqn %x log data size %d\n" ,
390
+ hp -> tirn , hp -> pair -> rqn , hp -> pair -> peer_mdev -> priv .name ,
391
+ hp -> pair -> sqn , params .log_data_size );
392
+
393
+ hpe -> hp = hp ;
394
+ hash_add (priv -> fs .tc .hairpin_tbl , & hpe -> hairpin_hlist , peer_ifindex );
395
+
396
+ attach_flow :
397
+ flow -> nic_attr -> hairpin_tirn = hpe -> hp -> tirn ;
398
+ list_add (& flow -> hairpin , & hpe -> flows );
399
+ return 0 ;
400
+
401
+ create_hairpin_err :
402
+ kfree (hpe );
403
+ return err ;
404
+ }
405
+
406
+ static void mlx5e_hairpin_flow_del (struct mlx5e_priv * priv ,
407
+ struct mlx5e_tc_flow * flow )
408
+ {
409
+ struct list_head * next = flow -> hairpin .next ;
410
+
411
+ list_del (& flow -> hairpin );
412
+
413
+ /* no more hairpin flows for us, release the hairpin pair */
414
+ if (list_empty (next )) {
415
+ struct mlx5e_hairpin_entry * hpe ;
416
+
417
+ hpe = list_entry (next , struct mlx5e_hairpin_entry , flows );
418
+
419
+ netdev_dbg (priv -> netdev , "del hairpin: peer %s\n" ,
420
+ hpe -> hp -> pair -> peer_mdev -> priv .name );
421
+
422
+ mlx5e_hairpin_destroy (hpe -> hp );
423
+ hash_del (& hpe -> hairpin_hlist );
424
+ kfree (hpe );
425
+ }
426
+ }
427
+
322
428
static struct mlx5_flow_handle *
323
429
mlx5e_tc_add_nic_flow (struct mlx5e_priv * priv ,
324
430
struct mlx5e_tc_flow_parse_attr * parse_attr ,
325
431
struct mlx5e_tc_flow * flow )
326
432
{
327
433
struct mlx5_nic_flow_attr * attr = flow -> nic_attr ;
328
434
struct mlx5_core_dev * dev = priv -> mdev ;
329
- struct mlx5_flow_destination dest = {};
435
+ struct mlx5_flow_destination dest [ 2 ] = {};
330
436
struct mlx5_flow_act flow_act = {
331
437
.action = attr -> action ,
332
438
.flow_tag = attr -> flow_tag ,
@@ -335,18 +441,33 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
335
441
struct mlx5_fc * counter = NULL ;
336
442
struct mlx5_flow_handle * rule ;
337
443
bool table_created = false;
338
- int err ;
444
+ int err , dest_ix = 0 ;
339
445
340
446
if (attr -> action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST ) {
341
- dest .type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE ;
342
- dest .ft = priv -> fs .vlan .ft .t ;
343
- } else if (attr -> action & MLX5_FLOW_CONTEXT_ACTION_COUNT ) {
344
- counter = mlx5_fc_create (dev , true);
345
- if (IS_ERR (counter ))
346
- return ERR_CAST (counter );
447
+ if (flow -> flags & MLX5E_TC_FLOW_HAIRPIN ) {
448
+ err = mlx5e_hairpin_flow_add (priv , flow , parse_attr );
449
+ if (err ) {
450
+ rule = ERR_PTR (err );
451
+ goto err_add_hairpin_flow ;
452
+ }
453
+ dest [dest_ix ].type = MLX5_FLOW_DESTINATION_TYPE_TIR ;
454
+ dest [dest_ix ].tir_num = attr -> hairpin_tirn ;
455
+ } else {
456
+ dest [dest_ix ].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE ;
457
+ dest [dest_ix ].ft = priv -> fs .vlan .ft .t ;
458
+ }
459
+ dest_ix ++ ;
460
+ }
347
461
348
- dest .type = MLX5_FLOW_DESTINATION_TYPE_COUNTER ;
349
- dest .counter = counter ;
462
+ if (attr -> action & MLX5_FLOW_CONTEXT_ACTION_COUNT ) {
463
+ counter = mlx5_fc_create (dev , true);
464
+ if (IS_ERR (counter )) {
465
+ rule = ERR_CAST (counter );
466
+ goto err_fc_create ;
467
+ }
468
+ dest [dest_ix ].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER ;
469
+ dest [dest_ix ].counter = counter ;
470
+ dest_ix ++ ;
350
471
}
351
472
352
473
if (attr -> action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR ) {
@@ -389,7 +510,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
389
510
390
511
parse_attr -> spec .match_criteria_enable = MLX5_MATCH_OUTER_HEADERS ;
391
512
rule = mlx5_add_flow_rules (priv -> fs .tc .t , & parse_attr -> spec ,
392
- & flow_act , & dest , 1 );
513
+ & flow_act , dest , dest_ix );
393
514
394
515
if (IS_ERR (rule ))
395
516
goto err_add_rule ;
@@ -406,7 +527,10 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
406
527
mlx5e_detach_mod_hdr (priv , flow );
407
528
err_create_mod_hdr_id :
408
529
mlx5_fc_destroy (dev , counter );
409
-
530
+ err_fc_create :
531
+ if (flow -> flags & MLX5E_TC_FLOW_HAIRPIN )
532
+ mlx5e_hairpin_flow_del (priv , flow );
533
+ err_add_hairpin_flow :
410
534
return rule ;
411
535
}
412
536
@@ -427,6 +551,9 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
427
551
428
552
if (attr -> action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR )
429
553
mlx5e_detach_mod_hdr (priv , flow );
554
+
555
+ if (flow -> flags & MLX5E_TC_FLOW_HAIRPIN )
556
+ mlx5e_hairpin_flow_del (priv , flow );
430
557
}
431
558
432
559
static void mlx5e_detach_encap (struct mlx5e_priv * priv ,
@@ -1519,6 +1646,20 @@ static bool actions_match_supported(struct mlx5e_priv *priv,
1519
1646
return true;
1520
1647
}
1521
1648
1649
+ static bool same_hw_devs (struct mlx5e_priv * priv , struct mlx5e_priv * peer_priv )
1650
+ {
1651
+ struct mlx5_core_dev * fmdev , * pmdev ;
1652
+ u16 func_id , peer_id ;
1653
+
1654
+ fmdev = priv -> mdev ;
1655
+ pmdev = peer_priv -> mdev ;
1656
+
1657
+ func_id = (u16 )((fmdev -> pdev -> bus -> number << 8 ) | PCI_SLOT (fmdev -> pdev -> devfn ));
1658
+ peer_id = (u16 )((pmdev -> pdev -> bus -> number << 8 ) | PCI_SLOT (pmdev -> pdev -> devfn ));
1659
+
1660
+ return (func_id == peer_id );
1661
+ }
1662
+
1522
1663
static int parse_tc_nic_actions (struct mlx5e_priv * priv , struct tcf_exts * exts ,
1523
1664
struct mlx5e_tc_flow_parse_attr * parse_attr ,
1524
1665
struct mlx5e_tc_flow * flow )
@@ -1563,6 +1704,23 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
1563
1704
return - EOPNOTSUPP ;
1564
1705
}
1565
1706
1707
+ if (is_tcf_mirred_egress_redirect (a )) {
1708
+ struct net_device * peer_dev = tcf_mirred_dev (a );
1709
+
1710
+ if (priv -> netdev -> netdev_ops == peer_dev -> netdev_ops &&
1711
+ same_hw_devs (priv , netdev_priv (peer_dev ))) {
1712
+ parse_attr -> mirred_ifindex = peer_dev -> ifindex ;
1713
+ flow -> flags |= MLX5E_TC_FLOW_HAIRPIN ;
1714
+ attr -> action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1715
+ MLX5_FLOW_CONTEXT_ACTION_COUNT ;
1716
+ } else {
1717
+ netdev_warn (priv -> netdev , "device %s not on same HW, can't offload\n" ,
1718
+ peer_dev -> name );
1719
+ return - EINVAL ;
1720
+ }
1721
+ continue ;
1722
+ }
1723
+
1566
1724
if (is_tcf_skbedit_mark (a )) {
1567
1725
u32 mark = tcf_skbedit_mark (a );
1568
1726
@@ -2285,6 +2443,7 @@ int mlx5e_tc_init(struct mlx5e_priv *priv)
2285
2443
struct mlx5e_tc_table * tc = & priv -> fs .tc ;
2286
2444
2287
2445
hash_init (tc -> mod_hdr_tbl );
2446
+ hash_init (tc -> hairpin_tbl );
2288
2447
2289
2448
tc -> ht_params = mlx5e_tc_flow_ht_params ;
2290
2449
return rhashtable_init (& tc -> ht , & tc -> ht_params );
0 commit comments