Skip to content

Commit f5bc2c5

Browse files
ozshlomoSaeed Mahameed
authored andcommitted
net/mlx5e: Support TC indirect block notifications for eswitch uplink reprs
Towards using this mechanism as the means to offload tunnel decap rules set on SW tunnel devices instead of egdev, add the supporting structures and functions. Signed-off-by: Oz Shlomo <ozsh@mellanox.com> Reviewed-by: Eli Britstein <elibr@mellanox.com> Reviewed-by: Or Gerlitz <ogerlitz@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
1 parent ec1366c commit f5bc2c5

File tree

4 files changed

+210
-0
lines changed

4 files changed

+210
-0
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en_rep.c

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@
4949

5050
static const char mlx5e_rep_driver_name[] = "mlx5e_rep";
5151

52+
struct mlx5e_rep_indr_block_priv {
53+
struct net_device *netdev;
54+
struct mlx5e_rep_priv *rpriv;
55+
56+
struct list_head list;
57+
};
58+
59+
static void mlx5e_rep_indr_unregister_block(struct net_device *netdev);
60+
5261
static void mlx5e_rep_get_drvinfo(struct net_device *dev,
5362
struct ethtool_drvinfo *drvinfo)
5463
{
@@ -518,6 +527,166 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
518527
neigh_release(n);
519528
}
520529

530+
static struct mlx5e_rep_indr_block_priv *
531+
mlx5e_rep_indr_block_priv_lookup(struct mlx5e_rep_priv *rpriv,
532+
struct net_device *netdev)
533+
{
534+
struct mlx5e_rep_indr_block_priv *cb_priv;
535+
536+
/* All callback list access should be protected by RTNL. */
537+
ASSERT_RTNL();
538+
539+
list_for_each_entry(cb_priv,
540+
&rpriv->uplink_priv.tc_indr_block_priv_list,
541+
list)
542+
if (cb_priv->netdev == netdev)
543+
return cb_priv;
544+
545+
return NULL;
546+
}
547+
548+
static void mlx5e_rep_indr_clean_block_privs(struct mlx5e_rep_priv *rpriv)
549+
{
550+
struct mlx5e_rep_indr_block_priv *cb_priv, *temp;
551+
struct list_head *head = &rpriv->uplink_priv.tc_indr_block_priv_list;
552+
553+
list_for_each_entry_safe(cb_priv, temp, head, list) {
554+
mlx5e_rep_indr_unregister_block(cb_priv->netdev);
555+
kfree(cb_priv);
556+
}
557+
}
558+
559+
static int
560+
mlx5e_rep_indr_offload(struct net_device *netdev,
561+
struct tc_cls_flower_offload *flower,
562+
struct mlx5e_rep_indr_block_priv *indr_priv)
563+
{
564+
return -EOPNOTSUPP;
565+
}
566+
567+
static int mlx5e_rep_indr_setup_block_cb(enum tc_setup_type type,
568+
void *type_data, void *indr_priv)
569+
{
570+
struct mlx5e_rep_indr_block_priv *priv = indr_priv;
571+
572+
switch (type) {
573+
case TC_SETUP_CLSFLOWER:
574+
return mlx5e_rep_indr_offload(priv->netdev, type_data, priv);
575+
default:
576+
return -EOPNOTSUPP;
577+
}
578+
}
579+
580+
static int
581+
mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
582+
struct mlx5e_rep_priv *rpriv,
583+
struct tc_block_offload *f)
584+
{
585+
struct mlx5e_rep_indr_block_priv *indr_priv;
586+
int err = 0;
587+
588+
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
589+
return -EOPNOTSUPP;
590+
591+
switch (f->command) {
592+
case TC_BLOCK_BIND:
593+
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
594+
if (indr_priv)
595+
return -EEXIST;
596+
597+
indr_priv = kmalloc(sizeof(*indr_priv), GFP_KERNEL);
598+
if (!indr_priv)
599+
return -ENOMEM;
600+
601+
indr_priv->netdev = netdev;
602+
indr_priv->rpriv = rpriv;
603+
list_add(&indr_priv->list,
604+
&rpriv->uplink_priv.tc_indr_block_priv_list);
605+
606+
err = tcf_block_cb_register(f->block,
607+
mlx5e_rep_indr_setup_block_cb,
608+
netdev, indr_priv, f->extack);
609+
if (err) {
610+
list_del(&indr_priv->list);
611+
kfree(indr_priv);
612+
}
613+
614+
return err;
615+
case TC_BLOCK_UNBIND:
616+
tcf_block_cb_unregister(f->block,
617+
mlx5e_rep_indr_setup_block_cb,
618+
netdev);
619+
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
620+
if (indr_priv) {
621+
list_del(&indr_priv->list);
622+
kfree(indr_priv);
623+
}
624+
625+
return 0;
626+
default:
627+
return -EOPNOTSUPP;
628+
}
629+
return 0;
630+
}
631+
632+
static
633+
int mlx5e_rep_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv,
634+
enum tc_setup_type type, void *type_data)
635+
{
636+
switch (type) {
637+
case TC_SETUP_BLOCK:
638+
return mlx5e_rep_indr_setup_tc_block(netdev, cb_priv,
639+
type_data);
640+
default:
641+
return -EOPNOTSUPP;
642+
}
643+
}
644+
645+
static int mlx5e_rep_indr_register_block(struct mlx5e_rep_priv *rpriv,
646+
struct net_device *netdev)
647+
{
648+
int err;
649+
650+
err = __tc_indr_block_cb_register(netdev, rpriv,
651+
mlx5e_rep_indr_setup_tc_cb,
652+
netdev);
653+
if (err) {
654+
struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
655+
656+
mlx5_core_err(priv->mdev, "Failed to register remote block notifier for %s err=%d\n",
657+
netdev_name(netdev), err);
658+
}
659+
return err;
660+
}
661+
662+
static void mlx5e_rep_indr_unregister_block(struct net_device *netdev)
663+
{
664+
__tc_indr_block_cb_unregister(netdev, mlx5e_rep_indr_setup_tc_cb,
665+
netdev);
666+
}
667+
668+
static int mlx5e_nic_rep_netdevice_event(struct notifier_block *nb,
669+
unsigned long event, void *ptr)
670+
{
671+
struct mlx5e_rep_priv *rpriv = container_of(nb, struct mlx5e_rep_priv,
672+
uplink_priv.netdevice_nb);
673+
struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
674+
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
675+
676+
if (!mlx5e_tc_tun_device_to_offload(priv, netdev))
677+
return NOTIFY_OK;
678+
679+
switch (event) {
680+
case NETDEV_REGISTER:
681+
mlx5e_rep_indr_register_block(rpriv, netdev);
682+
break;
683+
case NETDEV_UNREGISTER:
684+
mlx5e_rep_indr_unregister_block(netdev);
685+
break;
686+
}
687+
return NOTIFY_OK;
688+
}
689+
521690
static struct mlx5e_neigh_hash_entry *
522691
mlx5e_rep_neigh_entry_lookup(struct mlx5e_priv *priv,
523692
struct mlx5e_neigh *m_neigh);
@@ -1262,8 +1431,19 @@ mlx5e_nic_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
12621431
if (err)
12631432
goto err_neigh_cleanup;
12641433

1434+
/* init indirect block notifications */
1435+
INIT_LIST_HEAD(&uplink_priv->tc_indr_block_priv_list);
1436+
uplink_priv->netdevice_nb.notifier_call = mlx5e_nic_rep_netdevice_event;
1437+
err = register_netdevice_notifier(&uplink_priv->netdevice_nb);
1438+
if (err) {
1439+
mlx5_core_err(priv->mdev, "Failed to register netdev notifier\n");
1440+
goto err_indirect_block_cleanup;
1441+
}
1442+
12651443
return 0;
12661444

1445+
err_indirect_block_cleanup:
1446+
mlx5e_tc_esw_cleanup(&uplink_priv->tc_ht);
12671447
err_neigh_cleanup:
12681448
mlx5e_rep_neigh_cleanup(rpriv);
12691449
err_remove_sqs:
@@ -1280,6 +1460,10 @@ mlx5e_nic_rep_unload(struct mlx5_eswitch_rep *rep)
12801460
if (test_bit(MLX5E_STATE_OPENED, &priv->state))
12811461
mlx5e_remove_sqs_fwd_rules(priv);
12821462

1463+
/* clean indirect TC block notifications */
1464+
unregister_netdevice_notifier(&rpriv->uplink_priv.netdevice_nb);
1465+
mlx5e_rep_indr_clean_block_privs(rpriv);
1466+
12831467
/* clean uplink offloaded TC rules, delete shared tc flow table */
12841468
mlx5e_tc_esw_cleanup(&rpriv->uplink_priv.tc_ht);
12851469

drivers/net/ethernet/mellanox/mlx5/core/en_rep.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ struct mlx5_rep_uplink_priv {
5858
* the uplink's VFs
5959
*/
6060
struct rhashtable tc_ht;
61+
62+
/* indirect block callbacks are invoked on bind/unbind events
63+
* on registered higher level devices (e.g. tunnel devices)
64+
*
65+
* tc_indr_block_cb_priv_list is used to lookup indirect callback
66+
* private data
67+
*
68+
* netdevice_nb is the netdev events notifier - used to register
69+
* tunnel devices for block events
70+
*
71+
*/
72+
struct list_head tc_indr_block_priv_list;
73+
struct notifier_block netdevice_nb;
6174
};
6275

6376
struct mlx5e_rep_priv {

drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2704,6 +2704,16 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv,
27042704
return err;
27052705
}
27062706

2707+
bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv,
2708+
struct net_device *netdev)
2709+
{
2710+
if (netif_is_vxlan(netdev) &&
2711+
MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap))
2712+
return true;
2713+
2714+
return false;
2715+
}
2716+
27072717
static int mlx5e_attach_encap(struct mlx5e_priv *priv,
27082718
struct ip_tunnel_info *tun_info,
27092719
struct net_device *mirred_dev,

drivers/net/ethernet/mellanox/mlx5/core/en_tc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe);
7070

7171
int mlx5e_tc_num_filters(struct mlx5e_priv *priv);
7272

73+
bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv,
74+
struct net_device *netdev);
75+
7376
#else /* CONFIG_MLX5_ESWITCH */
7477
static inline int mlx5e_tc_nic_init(struct mlx5e_priv *priv) { return 0; }
7578
static inline void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv) {}

0 commit comments

Comments
 (0)