* @rss_cfg:            RSS configuration
  * @rss_key:            RSS secret key
  * @rss_itbl:           RSS indirection table
- * @xdp_flags:         Flags with which XDP prog was loaded
- * @xdp_prog:          XDP prog (for ctrl path, both DRV and HW modes)
+ * @xdp:               Information about the attached XDP program
  * @max_r_vecs:                Number of allocated interrupt vectors for RX/TX
  * @max_tx_rings:       Maximum number of TX rings supported by the Firmware
  * @max_rx_rings:       Maximum number of RX rings supported by the Firmware
        u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ];
        u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ];
 
-       u32 xdp_flags;
-       struct bpf_prog *xdp_prog;
+       struct xdp_attachment_info xdp;
 
        unsigned int max_tx_rings;
        unsigned int max_rx_rings;
 
        return nfp_net_ring_reconfig(nn, dp, extack);
 }
 
-static int
-nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags,
-                 struct netlink_ext_ack *extack)
+static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_bpf *bpf)
 {
        struct bpf_prog *drv_prog, *offload_prog;
        int err;
 
-       if (nn->xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES)
+       if (!xdp_attachment_flags_ok(&nn->xdp, bpf))
                return -EBUSY;
 
        /* Load both when no flags set to allow easy activation of driver path
         * when program is replaced by one which can't be offloaded.
         */
-       drv_prog     = flags & XDP_FLAGS_HW_MODE  ? NULL : prog;
-       offload_prog = flags & XDP_FLAGS_DRV_MODE ? NULL : prog;
+       drv_prog     = bpf->flags & XDP_FLAGS_HW_MODE  ? NULL : bpf->prog;
+       offload_prog = bpf->flags & XDP_FLAGS_DRV_MODE ? NULL : bpf->prog;
 
-       err = nfp_net_xdp_setup_drv(nn, drv_prog, extack);
+       err = nfp_net_xdp_setup_drv(nn, drv_prog, bpf->extack);
        if (err)
                return err;
 
-       err = nfp_app_xdp_offload(nn->app, nn, offload_prog, extack);
-       if (err && flags & XDP_FLAGS_HW_MODE)
+       err = nfp_app_xdp_offload(nn->app, nn, offload_prog, bpf->extack);
+       if (err && bpf->flags & XDP_FLAGS_HW_MODE)
                return err;
 
-       if (nn->xdp_prog)
-               bpf_prog_put(nn->xdp_prog);
-       nn->xdp_prog = prog;
-       nn->xdp_flags = flags;
+       xdp_attachment_setup(&nn->xdp, bpf);
 
        return 0;
 }
        switch (xdp->command) {
        case XDP_SETUP_PROG:
        case XDP_SETUP_PROG_HW:
-               return nfp_net_xdp_setup(nn, xdp->prog, xdp->flags,
-                                        xdp->extack);
+               return nfp_net_xdp_setup(nn, xdp);
        case XDP_QUERY_PROG:
-               xdp->prog_id = nn->xdp_prog ? nn->xdp_prog->aux->id : 0;
-               xdp->prog_flags = nn->xdp_prog ? nn->xdp_flags : 0;
-               return 0;
+               return xdp_attachment_query(&nn->xdp, xdp);
        default:
                return nfp_app_bpf(nn->app, nn, xdp);
        }
 
 {
        int err;
 
-       if (ns->xdp_prog && (bpf->flags ^ ns->xdp_flags) & XDP_FLAGS_MODES) {
-               NSIM_EA(bpf->extack, "program loaded with different flags");
+       if (!xdp_attachment_flags_ok(&ns->xdp, bpf))
                return -EBUSY;
-       }
 
        if (bpf->command == XDP_SETUP_PROG && !ns->bpf_xdpdrv_accept) {
                NSIM_EA(bpf->extack, "driver XDP disabled in DebugFS");
                        return err;
        }
 
-       if (ns->xdp_prog)
-               bpf_prog_put(ns->xdp_prog);
-
-       ns->xdp_prog = bpf->prog;
-       ns->xdp_flags = bpf->flags;
+       xdp_attachment_setup(&ns->xdp, bpf);
 
        if (!bpf->prog)
                ns->xdp_prog_mode = XDP_ATTACHED_NONE;
                nsim_bpf_destroy_prog(bpf->offload.prog);
                return 0;
        case XDP_QUERY_PROG:
-               bpf->prog_id = ns->xdp_prog ? ns->xdp_prog->aux->id : 0;
-               bpf->prog_flags = ns->xdp_prog ? ns->xdp_flags : 0;
-               return 0;
+               return xdp_attachment_query(&ns->xdp, bpf);
        case XDP_SETUP_PROG:
                err = nsim_setup_prog_checks(ns, bpf);
                if (err)
 {
        WARN_ON(!list_empty(&ns->bpf_bound_progs));
        WARN_ON(!list_empty(&ns->bpf_bound_maps));
-       WARN_ON(ns->xdp_prog);
+       WARN_ON(ns->xdp.prog);
        WARN_ON(ns->bpf_offloaded);
 }
 
 #include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/u64_stats_sync.h>
+#include <net/xdp.h>
 
 #define DRV_NAME       "netdevsim"
 
        struct bpf_prog *bpf_offloaded;
        u32 bpf_offloaded_id;
 
-       u32 xdp_flags;
+       struct xdp_attachment_info xdp;
        int xdp_prog_mode;
-       struct bpf_prog *xdp_prog;
 
        u32 prog_id_gen;
 
 
        return unlikely(xdp->data_meta > xdp->data);
 }
 
+struct xdp_attachment_info {
+       struct bpf_prog *prog;
+       u32 flags;
+};
+
+struct netdev_bpf;
+int xdp_attachment_query(struct xdp_attachment_info *info,
+                        struct netdev_bpf *bpf);
+bool xdp_attachment_flags_ok(struct xdp_attachment_info *info,
+                            struct netdev_bpf *bpf);
+void xdp_attachment_setup(struct xdp_attachment_info *info,
+                         struct netdev_bpf *bpf);
+
 #endif /* __LINUX_NET_XDP_H__ */
 
  * Copyright (c) 2017 Jesper Dangaard Brouer, Red Hat Inc.
  * Released under terms in GPL version 2.  See COPYING.
  */
+#include <linux/bpf.h>
+#include <linux/filter.h>
 #include <linux/types.h>
 #include <linux/mm.h>
+#include <linux/netdevice.h>
 #include <linux/slab.h>
 #include <linux/idr.h>
 #include <linux/rhashtable.h>
        __xdp_return(xdp->data, &xdp->rxq->mem, true, xdp->handle);
 }
 EXPORT_SYMBOL_GPL(xdp_return_buff);
+
+int xdp_attachment_query(struct xdp_attachment_info *info,
+                        struct netdev_bpf *bpf)
+{
+       bpf->prog_id = info->prog ? info->prog->aux->id : 0;
+       bpf->prog_flags = info->prog ? info->flags : 0;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xdp_attachment_query);
+
+bool xdp_attachment_flags_ok(struct xdp_attachment_info *info,
+                            struct netdev_bpf *bpf)
+{
+       if (info->prog && (bpf->flags ^ info->flags) & XDP_FLAGS_MODES) {
+               NL_SET_ERR_MSG(bpf->extack,
+                              "program loaded with different flags");
+               return false;
+       }
+       return true;
+}
+EXPORT_SYMBOL_GPL(xdp_attachment_flags_ok);
+
+void xdp_attachment_setup(struct xdp_attachment_info *info,
+                         struct netdev_bpf *bpf)
+{
+       if (info->prog)
+               bpf_prog_put(info->prog);
+       info->prog = bpf->prog;
+       info->flags = bpf->flags;
+}
+EXPORT_SYMBOL_GPL(xdp_attachment_setup);
 
     ret, _, err = sim.set_xdp(obj, "", force=True,
                               fail=False, include_stderr=True)
     fail(ret == 0, "Replaced XDP program with a program in different mode")
-    check_extack_nsim(err, "program loaded with different flags.", args)
+    check_extack(err, "program loaded with different flags.", args)
 
     start_test("Test XDP prog remove with bad flags...")
     ret, _, err = sim.unset_xdp("offload", force=True,
     ret, _, err = sim.unset_xdp("", force=True,
                                 fail=False, include_stderr=True)
     fail(ret == 0, "Removed program with a bad mode")
-    check_extack_nsim(err, "program loaded with different flags.", args)
+    check_extack(err, "program loaded with different flags.", args)
 
     start_test("Test MTU restrictions...")
     ret, _ = sim.set_mtu(9000, fail=False)