nfp: forbid disabling hw-tc-offload on representors while offload active
authorJakub Kicinski <jakub.kicinski@netronome.com>
Thu, 8 Feb 2018 04:55:24 +0000 (20:55 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 8 Feb 2018 15:01:27 +0000 (10:01 -0500)
All netdevs which can accept TC offloads must implement
.ndo_set_features().  nfp_reprs currently do not do that, which
means hw-tc-offload can be turned on and off even when offloads
are active.

Whether the offloads are active is really a question to nfp_ports,
so remove the per-app tc_busy callback indirection thing, and
simply count the number of offloaded items in nfp_port structure.

Fixes: 8a2768732a4d ("nfp: provide infrastructure for offloading flower based TC filters")
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Tested-by: Pieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/bpf/main.c
drivers/net/ethernet/netronome/nfp/flower/offload.c
drivers/net/ethernet/netronome/nfp/nfp_app.h
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
drivers/net/ethernet/netronome/nfp/nfp_port.c
drivers/net/ethernet/netronome/nfp/nfp_port.h

index 61898dda11cf5a8077fa7603c8de48a24f6cf2da..34e98aa6b95623b354e99d4235962cabec59d700 100644 (file)
@@ -182,6 +182,7 @@ static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
                return err;
 
        bv->tc_prog = cls_bpf->prog;
+       nn->port->tc_offload_cnt = !!bv->tc_prog;
        return 0;
 }
 
@@ -219,13 +220,6 @@ static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
        }
 }
 
-static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn)
-{
-       struct nfp_bpf_vnic *bv = nn->app_priv;
-
-       return !!bv->tc_prog;
-}
-
 static int
 nfp_bpf_change_mtu(struct nfp_app *app, struct net_device *netdev, int new_mtu)
 {
@@ -429,7 +423,6 @@ const struct nfp_app_type app_bpf = {
        .ctrl_msg_rx    = nfp_bpf_ctrl_msg_rx,
 
        .setup_tc       = nfp_bpf_setup_tc,
-       .tc_busy        = nfp_bpf_tc_busy,
        .bpf            = nfp_ndo_bpf,
        .xdp_offload    = nfp_bpf_xdp_offload,
 };
index 08c4c6dc5f7f26dedab581589a53036e4ba3fee8..eb5c13dea8f59234a31a105d84d7a55f390427a0 100644 (file)
@@ -349,6 +349,7 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
                       struct tc_cls_flower_offload *flow, bool egress)
 {
        enum nfp_flower_tun_type tun_type = NFP_FL_TUNNEL_NONE;
+       struct nfp_port *port = nfp_port_from_netdev(netdev);
        struct nfp_flower_priv *priv = app->priv;
        struct nfp_fl_payload *flow_pay;
        struct nfp_fl_key_ls *key_layer;
@@ -390,6 +391,7 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
        INIT_HLIST_NODE(&flow_pay->link);
        flow_pay->tc_flower_cookie = flow->cookie;
        hash_add_rcu(priv->flow_table, &flow_pay->link, flow->cookie);
+       port->tc_offload_cnt++;
 
        /* Deallocate flow payload when flower rule has been destroyed. */
        kfree(key_layer);
@@ -421,6 +423,7 @@ static int
 nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
                       struct tc_cls_flower_offload *flow)
 {
+       struct nfp_port *port = nfp_port_from_netdev(netdev);
        struct nfp_fl_payload *nfp_flow;
        int err;
 
@@ -442,6 +445,7 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
 
 err_free_flow:
        hash_del_rcu(&nfp_flow->link);
+       port->tc_offload_cnt--;
        kfree(nfp_flow->action_data);
        kfree(nfp_flow->mask_data);
        kfree(nfp_flow->unmasked_data);
index 437964afa8eef5c2cf4f8bb78c92734609cf7566..20546ae67909027c641a1df46e95e18fa979f456 100644 (file)
@@ -92,7 +92,6 @@ extern const struct nfp_app_type app_flower;
  * @stop:      stop application logic
  * @ctrl_msg_rx:    control message handler
  * @setup_tc:  setup TC ndo
- * @tc_busy:   TC HW offload busy (rules loaded)
  * @bpf:       BPF ndo offload-related calls
  * @xdp_offload:    offload an XDP program
  * @eswitch_mode_get:    get SR-IOV eswitch mode
@@ -135,7 +134,6 @@ struct nfp_app_type {
 
        int (*setup_tc)(struct nfp_app *app, struct net_device *netdev,
                        enum tc_setup_type type, void *type_data);
-       bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn);
        int (*bpf)(struct nfp_app *app, struct nfp_net *nn,
                   struct netdev_bpf *xdp);
        int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn,
@@ -301,13 +299,6 @@ static inline bool nfp_app_has_tc(struct nfp_app *app)
        return app && app->type->setup_tc;
 }
 
-static inline bool nfp_app_tc_busy(struct nfp_app *app, struct nfp_net *nn)
-{
-       if (!app || !app->type->tc_busy)
-               return false;
-       return app->type->tc_busy(app, nn);
-}
-
 static inline int nfp_app_setup_tc(struct nfp_app *app,
                                   struct net_device *netdev,
                                   enum tc_setup_type type, void *type_data)
index fe77ea8b656c09fb64e564d010a52824a0b2b9ea..19e989239af7085476bfc250d8e7d354d3d1b8ca 100644 (file)
@@ -3210,10 +3210,9 @@ static int nfp_net_set_features(struct net_device *netdev,
                        new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER;
        }
 
-       if (changed & NETIF_F_HW_TC && nfp_app_tc_busy(nn->app, nn)) {
-               nn_err(nn, "Cannot disable HW TC offload while in use\n");
-               return -EBUSY;
-       }
+       err = nfp_port_set_features(netdev, features);
+       if (err)
+               return err;
 
        nn_dbg(nn, "Feature change 0x%llx -> 0x%llx (changed=0x%llx)\n",
               netdev->features, features, changed);
index f67da6bde9da3ea5d5e12c74ff83f62115aa3eb4..619570524d2a4989fc0c91c25c42289f90ecd9c7 100644 (file)
@@ -265,6 +265,7 @@ const struct net_device_ops nfp_repr_netdev_ops = {
        .ndo_set_vf_spoofchk    = nfp_app_set_vf_spoofchk,
        .ndo_get_vf_config      = nfp_app_get_vf_config,
        .ndo_set_vf_link_state  = nfp_app_set_vf_link_state,
+       .ndo_set_features       = nfp_port_set_features,
 };
 
 static void nfp_repr_clean(struct nfp_repr *repr)
index 34a6e035fe9a207a8ee6a2ebc18a54391e37d826..7bd8be5c833b08f3416fff971e1101bf8791214d 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <linux/lockdep.h>
+#include <linux/netdevice.h>
 #include <net/switchdev.h>
 
 #include "nfpcore/nfp_cpp.h"
@@ -100,6 +101,23 @@ int nfp_port_setup_tc(struct net_device *netdev, enum tc_setup_type type,
        return nfp_app_setup_tc(port->app, netdev, type, type_data);
 }
 
+int nfp_port_set_features(struct net_device *netdev, netdev_features_t features)
+{
+       struct nfp_port *port;
+
+       port = nfp_port_from_netdev(netdev);
+       if (!port)
+               return 0;
+
+       if ((netdev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) &&
+           port->tc_offload_cnt) {
+               netdev_err(netdev, "Cannot disable HW TC offload while offloads active\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
 struct nfp_port *
 nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id)
 {
index 21bd4aa3264681ea0af49aad1b98a71e0c5c4958..fa7e669a969c6e5baa8aec30fedb410d29806793 100644 (file)
@@ -72,6 +72,8 @@ enum nfp_port_flags {
  * @netdev:    backpointer to associated netdev
  * @type:      what port type does the entity represent
  * @flags:     port flags
+ * @tc_offload_cnt:    number of active TC offloads, how offloads are counted
+ *                     is not defined, use as a boolean
  * @app:       backpointer to the app structure
  * @dl_port:   devlink port structure
  * @eth_id:    for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme
@@ -87,6 +89,7 @@ struct nfp_port {
        enum nfp_port_type type;
 
        unsigned long flags;
+       unsigned long tc_offload_cnt;
 
        struct nfp_app *app;
 
@@ -121,6 +124,9 @@ static inline bool nfp_port_is_vnic(const struct nfp_port *port)
        return port->type == NFP_PORT_PF_PORT || port->type == NFP_PORT_VF_PORT;
 }
 
+int
+nfp_port_set_features(struct net_device *netdev, netdev_features_t features);
+
 struct nfp_port *nfp_port_from_netdev(struct net_device *netdev);
 struct nfp_port *
 nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id);