|
@@ -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" : "";
|
|
|
}
|
|
|
|
|
|
+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)
|
|
|
{
|
|
|
+ struct nfp_bpf_vnic *bv = nn->app_priv;
|
|
|
+
|
|
|
if (nn->dp.bpf_offload_xdp)
|
|
|
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,
|
|
@@ -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 nfp_net *nn = cb_priv;
|
|
|
+ struct bpf_prog *oldprog;
|
|
|
+ struct nfp_bpf_vnic *bv;
|
|
|
+ int err;
|
|
|
|
|
|
if (type != TC_SETUP_CLSBPF ||
|
|
|
!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.chain_index)
|
|
|
return -EOPNOTSUPP;
|
|
|
- if (nn->dp.bpf_offload_xdp)
|
|
|
- return -EBUSY;
|
|
|
|
|
|
/* Only support TC direct action */
|
|
|
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)
|
|
|
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,
|
|
@@ -161,7 +200,7 @@ const struct nfp_app_type app_bpf = {
|
|
|
|
|
|
.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,
|
|
|
|
|
|
.setup_tc = nfp_bpf_setup_tc,
|