nfp: bpf: keep track of the offloaded program

After TC offloads were converted to callbacks we have no choice
but keep track of the offloaded filter in the driver.

The check for nn->dp.bpf_offload_xdp was a stop gap solution
to make sure failed TC offload won't disable XDP, it's no longer
necessary.  nfp_net_bpf_offload() will return -EBUSY on
TC vs XDP conflicts.

Fixes: 3f7889c4c7 ("net: sched: cls_bpf: call block callbacks for offload")
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jakub Kicinski 2017-12-19 13:32:14 -08:00 committed by David S. Miller
parent 102740bd94
commit d3f89b98e3
2 changed files with 51 additions and 4 deletions

View File

@ -82,10 +82,33 @@ static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
return nfp_net_ebpf_capable(nn) ? "BPF" : ""; return nfp_net_ebpf_capable(nn) ? "BPF" : "";
} }
static int
nfp_bpf_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
{
int err;
nn->app_priv = kzalloc(sizeof(struct nfp_bpf_vnic), GFP_KERNEL);
if (!nn->app_priv)
return -ENOMEM;
err = nfp_app_nic_vnic_alloc(app, nn, id);
if (err)
goto err_free_priv;
return 0;
err_free_priv:
kfree(nn->app_priv);
return err;
}
static void nfp_bpf_vnic_free(struct nfp_app *app, struct nfp_net *nn) static void nfp_bpf_vnic_free(struct nfp_app *app, struct nfp_net *nn)
{ {
struct nfp_bpf_vnic *bv = nn->app_priv;
if (nn->dp.bpf_offload_xdp) if (nn->dp.bpf_offload_xdp)
nfp_bpf_xdp_offload(app, nn, NULL); nfp_bpf_xdp_offload(app, nn, NULL);
WARN_ON(bv->tc_prog);
kfree(bv);
} }
static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type, static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
@ -93,6 +116,9 @@ static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
{ {
struct tc_cls_bpf_offload *cls_bpf = type_data; struct tc_cls_bpf_offload *cls_bpf = type_data;
struct nfp_net *nn = cb_priv; struct nfp_net *nn = cb_priv;
struct bpf_prog *oldprog;
struct nfp_bpf_vnic *bv;
int err;
if (type != TC_SETUP_CLSBPF || if (type != TC_SETUP_CLSBPF ||
!tc_can_offload(nn->dp.netdev) || !tc_can_offload(nn->dp.netdev) ||
@ -100,8 +126,6 @@ static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
cls_bpf->common.protocol != htons(ETH_P_ALL) || cls_bpf->common.protocol != htons(ETH_P_ALL) ||
cls_bpf->common.chain_index) cls_bpf->common.chain_index)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (nn->dp.bpf_offload_xdp)
return -EBUSY;
/* Only support TC direct action */ /* Only support TC direct action */
if (!cls_bpf->exts_integrated || if (!cls_bpf->exts_integrated ||
@ -113,7 +137,22 @@ static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
if (cls_bpf->command != TC_CLSBPF_OFFLOAD) if (cls_bpf->command != TC_CLSBPF_OFFLOAD)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return nfp_net_bpf_offload(nn, cls_bpf->prog, cls_bpf->oldprog); bv = nn->app_priv;
oldprog = cls_bpf->oldprog;
/* Don't remove if oldprog doesn't match driver's state */
if (bv->tc_prog != oldprog) {
oldprog = NULL;
if (!cls_bpf->prog)
return 0;
}
err = nfp_net_bpf_offload(nn, cls_bpf->prog, oldprog);
if (err)
return err;
bv->tc_prog = cls_bpf->prog;
return 0;
} }
static int nfp_bpf_setup_tc_block(struct net_device *netdev, static int nfp_bpf_setup_tc_block(struct net_device *netdev,
@ -161,7 +200,7 @@ const struct nfp_app_type app_bpf = {
.extra_cap = nfp_bpf_extra_cap, .extra_cap = nfp_bpf_extra_cap,
.vnic_alloc = nfp_app_nic_vnic_alloc, .vnic_alloc = nfp_bpf_vnic_alloc,
.vnic_free = nfp_bpf_vnic_free, .vnic_free = nfp_bpf_vnic_free,
.setup_tc = nfp_bpf_setup_tc, .setup_tc = nfp_bpf_setup_tc,

View File

@ -172,6 +172,14 @@ struct nfp_prog {
struct list_head insns; struct list_head insns;
}; };
/**
* struct nfp_bpf_vnic - per-vNIC BPF priv structure
* @tc_prog: currently loaded cls_bpf program
*/
struct nfp_bpf_vnic {
struct bpf_prog *tc_prog;
};
int nfp_bpf_jit(struct nfp_prog *prog); int nfp_bpf_jit(struct nfp_prog *prog);
extern const struct bpf_ext_analyzer_ops nfp_bpf_analyzer_ops; extern const struct bpf_ext_analyzer_ops nfp_bpf_analyzer_ops;