Skip to content

Commit

Permalink
Merge branch 'nfp-fix-disabling-TC-offloads-in-flower-max-TSO-segs-an…
Browse files Browse the repository at this point in the history
…d-module-version'

Jakub Kicinski says:

====================
nfp: fix disabling TC offloads in flower, max TSO segs and module version

This set corrects the way nfp deals with the NETIF_F_HW_TC flag.
It has slipped the review that flower offload does not currently
refuse disabling this flag when filter offload is active.

nfp's flower offload does not actually keep track of how many filters
for each port are offloaded.  The accounting of the number of filters
is added to the nfp core structures, and BPF moved to use these
structures as well.

If users are allowed to disable TC offloads while filters are active,
not only is it incorrect behaviour, but actually the NFP will never
be told to remove the flows, leading to use-after-free when stats
arrive.

Fourth patch makes sure we declare the max number of TSO segments.
FW should drop longer packets cleanly (otherwise this would be a
security problem for untrusted VFs) but dropping longer TSO frames
is not nice and driver should prevent them from being generated.

Last small addition populates MODULE_VERSION with kernel version.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Feb 8, 2018
2 parents 5c487bb + 1a5e8e3 commit c702558
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 23 deletions.
21 changes: 13 additions & 8 deletions drivers/net/ethernet/netronome/nfp/bpf/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include "../nfpcore/nfp_cpp.h"
#include "../nfpcore/nfp_nffw.h"
#include "../nfpcore/nfp_nsp.h"
#include "../nfp_app.h"
#include "../nfp_main.h"
#include "../nfp_net.h"
Expand Down Expand Up @@ -87,9 +88,20 @@ static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
static int
nfp_bpf_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
{
struct nfp_pf *pf = app->pf;
struct nfp_bpf_vnic *bv;
int err;

if (!pf->eth_tbl) {
nfp_err(pf->cpp, "No ETH table\n");
return -EINVAL;
}
if (pf->max_data_vnics != pf->eth_tbl->count) {
nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n",
pf->max_data_vnics, pf->eth_tbl->count);
return -EINVAL;
}

bv = kzalloc(sizeof(*bv), GFP_KERNEL);
if (!bv)
return -ENOMEM;
Expand Down Expand Up @@ -170,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;
}

Expand Down Expand Up @@ -207,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)
{
Expand Down Expand Up @@ -417,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,
};
4 changes: 4 additions & 0 deletions drivers/net/ethernet/netronome/nfp/flower/offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down
9 changes: 0 additions & 9 deletions drivers/net/ethernet/netronome/nfp/nfp_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/netronome/nfp/nfp_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,3 +649,4 @@ MODULE_FIRMWARE("netronome/nic_AMDA0099-0001_2x25.nffw");
MODULE_AUTHOR("Netronome Systems <[email protected]>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("The Netronome Flow Processor (NFP) driver.");
MODULE_VERSION(UTS_RELEASE);
11 changes: 6 additions & 5 deletions drivers/net/ethernet/netronome/nfp/nfp_net_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -3734,7 +3733,7 @@ static void nfp_net_netdev_init(struct nfp_net *nn)

netdev->features = netdev->hw_features;

if (nfp_app_has_tc(nn->app))
if (nfp_app_has_tc(nn->app) && nn->port)
netdev->hw_features |= NETIF_F_HW_TC;

/* Advertise but disable TSO by default. */
Expand All @@ -3751,6 +3750,8 @@ static void nfp_net_netdev_init(struct nfp_net *nn)
netdev->min_mtu = ETH_MIN_MTU;
netdev->max_mtu = nn->max_mtu;

netdev->gso_max_segs = NFP_NET_LSO_MAX_SEGS;

netif_carrier_off(netdev);

nfp_net_set_ethtool_ops(netdev);
Expand Down
5 changes: 4 additions & 1 deletion drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,12 @@
#define NFP_NET_RX_OFFSET 32

/**
* Maximum header size supported for LSO frames
* LSO parameters
* %NFP_NET_LSO_MAX_HDR_SZ: Maximum header size supported for LSO frames
* %NFP_NET_LSO_MAX_SEGS: Maximum number of segments LSO frame can produce
*/
#define NFP_NET_LSO_MAX_HDR_SZ 255
#define NFP_NET_LSO_MAX_SEGS 64

/**
* Prepend field types
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions drivers/net/ethernet/netronome/nfp/nfp_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*/

#include <linux/lockdep.h>
#include <linux/netdevice.h>
#include <net/switchdev.h>

#include "nfpcore/nfp_cpp.h"
Expand Down Expand Up @@ -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)
{
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/ethernet/netronome/nfp/nfp_port.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -87,6 +89,7 @@ struct nfp_port {
enum nfp_port_type type;

unsigned long flags;
unsigned long tc_offload_cnt;

struct nfp_app *app;

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit c702558

Please sign in to comment.