return nfp_map_ptrs_record(nfp_prog->bpf, nfp_prog, prog);
 }
 
-static int nfp_bpf_destroy(struct nfp_net *nn, struct bpf_prog *prog)
+static void nfp_bpf_destroy(struct bpf_prog *prog)
 {
        struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv;
 
        kvfree(nfp_prog->prog);
        nfp_map_ptrs_forget(nfp_prog->bpf, nfp_prog);
        nfp_prog_free(nfp_prog);
-
-       return 0;
 }
 
 /* Atomic engine requires values to be in big endian, we need to byte swap
 int nfp_ndo_bpf(struct nfp_app *app, struct nfp_net *nn, struct netdev_bpf *bpf)
 {
        switch (bpf->command) {
-       case BPF_OFFLOAD_DESTROY:
-               return nfp_bpf_destroy(nn, bpf->offload.prog);
        case BPF_OFFLOAD_MAP_ALLOC:
                return nfp_bpf_map_alloc(app->priv, bpf->offmap);
        case BPF_OFFLOAD_MAP_FREE:
        .finalize       = nfp_bpf_finalize,
        .prepare        = nfp_bpf_verifier_prep,
        .translate      = nfp_bpf_translate,
+       .destroy        = nfp_bpf_destroy,
 };
 
        .finalize       = nsim_bpf_finalize,
        .prepare        = nsim_bpf_verifier_prep,
        .translate      = nsim_bpf_translate,
+       .destroy        = nsim_bpf_destroy_prog,
 };
 
 static int nsim_setup_prog_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
        ASSERT_RTNL();
 
        switch (bpf->command) {
-       case BPF_OFFLOAD_DESTROY:
-               nsim_bpf_destroy_prog(bpf->offload.prog);
-               return 0;
        case XDP_QUERY_PROG:
                return xdp_attachment_query(&ns->xdp, bpf);
        case XDP_QUERY_PROG_HW:
 
        int (*finalize)(struct bpf_verifier_env *env);
        int (*prepare)(struct net_device *netdev, struct bpf_verifier_env *env);
        int (*translate)(struct net_device *netdev, struct bpf_prog *prog);
+       void (*destroy)(struct bpf_prog *prog);
 };
 
 struct bpf_prog_offload {
 
        XDP_QUERY_PROG,
        XDP_QUERY_PROG_HW,
        /* BPF program for offload callbacks, invoked at program load time. */
-       BPF_OFFLOAD_DESTROY,
        BPF_OFFLOAD_MAP_ALLOC,
        BPF_OFFLOAD_MAP_FREE,
        XDP_QUERY_XSK_UMEM,
                        /* flags with which program was installed */
                        u32 prog_flags;
                };
-               /* BPF_OFFLOAD_DESTROY */
-               struct {
-                       struct bpf_prog *prog;
-               } offload;
                /* BPF_OFFLOAD_MAP_ALLOC, BPF_OFFLOAD_MAP_FREE */
                struct {
                        struct bpf_offloaded_map *offmap;
 
        return err;
 }
 
-static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd,
-                            struct netdev_bpf *data)
-{
-       struct bpf_prog_offload *offload = prog->aux->offload;
-       struct net_device *netdev;
-
-       ASSERT_RTNL();
-
-       if (!offload)
-               return -ENODEV;
-       netdev = offload->netdev;
-
-       data->command = cmd;
-
-       return netdev->netdev_ops->ndo_bpf(netdev, data);
-}
-
 int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env)
 {
        struct bpf_prog_offload *offload;
 static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
 {
        struct bpf_prog_offload *offload = prog->aux->offload;
-       struct netdev_bpf data = {};
-
-       data.offload.prog = prog;
 
        if (offload->dev_state)
-               WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data));
+               offload->offdev->ops->destroy(prog);
 
        /* Make sure BPF_PROG_GET_NEXT_ID can't find this dead program */
        bpf_prog_free_id(prog, true);
 
 void bpf_prog_offload_destroy(struct bpf_prog *prog)
 {
-       rtnl_lock();
        down_write(&bpf_devs_lock);
        if (prog->aux->offload)
                __bpf_prog_offload_destroy(prog);
        up_write(&bpf_devs_lock);
-       rtnl_unlock();
 }
 
 static int bpf_prog_offload_translate(struct bpf_prog *prog)