sfc: bind indirect blocks for TC offload on EF100
authorEdward Cree <ecree.xilinx@gmail.com>
Mon, 26 Sep 2022 18:57:32 +0000 (19:57 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 28 Sep 2022 08:43:22 +0000 (09:43 +0100)
Bind indirect blocks for recognised tunnel netdevices.
Currently these connect to a stub efx_tc_flower() that only returns
 -EOPNOTSUPP; subsequent patches will implement flower offloads to the
 Match-Action Engine.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/tc.c
drivers/net/ethernet/sfc/tc_bindings.c
drivers/net/ethernet/sfc/tc_bindings.h

index 23c4325..cb7f76c 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include "tc.h"
+#include "tc_bindings.h"
 #include "mae.h"
 #include "ef100_rep.h"
 #include "efx.h"
@@ -217,6 +218,9 @@ int efx_init_tc(struct efx_nic *efx)
        if (rc)
                return rc;
        efx->tc->up = true;
+       rc = flow_indr_dev_register(efx_tc_indr_setup_cb, efx);
+       if (rc)
+               return rc;
        return 0;
 }
 
@@ -225,6 +229,8 @@ void efx_fini_tc(struct efx_nic *efx)
        /* We can get called even if efx_init_struct_tc() failed */
        if (!efx->tc)
                return;
+       if (efx->tc->up)
+               flow_indr_dev_unregister(efx_tc_indr_setup_cb, efx, efx_tc_block_unbind);
        efx_tc_deconfigure_rep_mport(efx);
        efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf);
        efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire);
index d9401ee..c18d645 100644 (file)
@@ -46,7 +46,7 @@ static int efx_tc_block_cb(enum tc_setup_type type, void *type_data,
        }
 }
 
-static void efx_tc_block_unbind(void *cb_priv)
+void efx_tc_block_unbind(void *cb_priv)
 {
        struct efx_tc_block_binding *binding = cb_priv;
 
@@ -135,6 +135,77 @@ int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx,
        }
 }
 
+int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch,
+                        void *cb_priv, enum tc_setup_type type,
+                        void *type_data, void *data,
+                        void (*cleanup)(struct flow_block_cb *block_cb))
+{
+       struct flow_block_offload *tcb = type_data;
+       struct efx_tc_block_binding *binding;
+       struct flow_block_cb *block_cb;
+       struct efx_nic *efx = cb_priv;
+       bool is_ovs_int_port;
+       int rc;
+
+       if (!net_dev)
+               return -EOPNOTSUPP;
+
+       if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
+           tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
+               return -EOPNOTSUPP;
+
+       is_ovs_int_port = netif_is_ovs_master(net_dev);
+       if (tcb->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
+           !is_ovs_int_port)
+               return -EOPNOTSUPP;
+
+       if (is_ovs_int_port)
+               return -EOPNOTSUPP;
+
+       switch (type) {
+       case TC_SETUP_BLOCK:
+               switch (tcb->command) {
+               case FLOW_BLOCK_BIND:
+                       binding = efx_tc_create_binding(efx, NULL, net_dev, tcb->block);
+                       if (IS_ERR(binding))
+                               return PTR_ERR(binding);
+                       block_cb = flow_indr_block_cb_alloc(efx_tc_block_cb, binding,
+                                                           binding, efx_tc_block_unbind,
+                                                           tcb, net_dev, sch, data, binding,
+                                                           cleanup);
+                       rc = PTR_ERR_OR_ZERO(block_cb);
+                       netif_dbg(efx, drv, efx->net_dev,
+                                 "bind indr block for device %s, rc %d\n",
+                                 net_dev ? net_dev->name : NULL, rc);
+                       if (rc) {
+                               list_del(&binding->list);
+                               kfree(binding);
+                       } else {
+                               flow_block_cb_add(block_cb, tcb);
+                       }
+                       return rc;
+               case FLOW_BLOCK_UNBIND:
+                       binding = efx_tc_find_binding(efx, net_dev);
+                       if (!binding)
+                               return -ENOENT;
+                       block_cb = flow_block_cb_lookup(tcb->block,
+                                                       efx_tc_block_cb,
+                                                       binding);
+                       if (!block_cb)
+                               return -ENOENT;
+                       flow_indr_block_cb_remove(block_cb, tcb);
+                       netif_dbg(efx, drv, efx->net_dev,
+                                 "unbind indr block for device %s\n",
+                                 net_dev ? net_dev->name : NULL);
+                       return 0;
+               default:
+                       return -EOPNOTSUPP;
+               }
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 /* .ndo_setup_tc implementation
  * Entry point for flower block and filter management.
  */
index bcd63c2..c210bb0 100644 (file)
 
 struct efx_rep;
 
+void efx_tc_block_unbind(void *cb_priv);
 int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx,
                       struct flow_block_offload *tcb, struct efx_rep *efv);
 int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type,
                 void *type_data);
+
+int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch,
+                        void *cb_priv, enum tc_setup_type type,
+                        void *type_data, void *data,
+                        void (*cleanup)(struct flow_block_cb *block_cb));
 #endif /* EFX_TC_BINDINGS_H */