net: xdp: make the stack take care of the tear down
authorJakub Kicinski <jakub.kicinski@netronome.com>
Fri, 1 Dec 2017 23:08:57 +0000 (15:08 -0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Sat, 2 Dec 2017 23:27:57 +0000 (00:27 +0100)
Since day one of XDP drivers had to remember to free the program
on the remove path.  This leads to code duplication and is error
prone.  Make the stack query the installed programs on unregister
and if something is installed, remove the program.  Freeing of
program attached to XDP generic is moved from free_netdev() as well.

Because the remove will now be called before notifiers are
invoked, BPF offload state of the program will not get destroyed
before uninstall.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/netronome/nfp/bpf/main.c
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/qlogic/qede/qede_main.c
drivers/net/tun.c
net/core/dev.c

index c5c38d4b7d1ccd04044f972777c5d3844e755a02..8c1dd60eab6fe2bd0763d274b31087ca4d873321 100644 (file)
@@ -7800,8 +7800,6 @@ static void bnxt_remove_one(struct pci_dev *pdev)
        bnxt_dcb_free(bp);
        kfree(bp->edev);
        bp->edev = NULL;
-       if (bp->xdp_prog)
-               bpf_prog_put(bp->xdp_prog);
        bnxt_cleanup_pci(bp);
        free_netdev(dev);
 }
index d2b057a3e512c1144d741ccffd5bf47b5f138a01..0f5c012de52eaa723f2e53f29328ed30a6f5d77b 100644 (file)
@@ -4308,9 +4308,6 @@ static void mlx5e_nic_cleanup(struct mlx5e_priv *priv)
 {
        mlx5e_ipsec_cleanup(priv);
        mlx5e_vxlan_cleanup(priv);
-
-       if (priv->channels.params.xdp_prog)
-               bpf_prog_put(priv->channels.params.xdp_prog);
 }
 
 static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
index e379b78e86efa7c02dca2bc95afc1f79afc7800a..54bfd7846f6d8c1a8165c5ec40384740d3ca3f41 100644 (file)
@@ -82,12 +82,6 @@ static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
        return nfp_net_ebpf_capable(nn) ? "BPF" : "";
 }
 
-static void nfp_bpf_vnic_free(struct nfp_app *app, struct nfp_net *nn)
-{
-       if (nn->dp.bpf_offload_xdp)
-               nfp_bpf_xdp_offload(app, nn, NULL);
-}
-
 static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
                                     void *type_data, void *cb_priv)
 {
@@ -168,7 +162,6 @@ const struct nfp_app_type app_bpf = {
        .extra_cap      = nfp_bpf_extra_cap,
 
        .vnic_alloc     = nfp_app_nic_vnic_alloc,
-       .vnic_free      = nfp_bpf_vnic_free,
 
        .setup_tc       = nfp_bpf_setup_tc,
        .tc_busy        = nfp_bpf_tc_busy,
index ea6bbf1efefc5749b891c88af6e60bbe81b6cceb..ad3e9f6a61e5cc8e2fad9f0a89f00d63e7cc9812 100644 (file)
@@ -3562,9 +3562,6 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, bool needs_netdev,
  */
 void nfp_net_free(struct nfp_net *nn)
 {
-       if (nn->xdp_prog)
-               bpf_prog_put(nn->xdp_prog);
-
        if (nn->dp.netdev)
                free_netdev(nn->dp.netdev);
        else
index 8f9b3eb821377648ac1400bf31598fc44de6545a..57332b3e5e6481459d13acba5a08bd1c5a8a2197 100644 (file)
@@ -1068,10 +1068,6 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode)
 
        pci_set_drvdata(pdev, NULL);
 
-       /* Release edev's reference to XDP's bpf if such exist */
-       if (edev->xdp_prog)
-               bpf_prog_put(edev->xdp_prog);
-
        /* Use global ops since we've freed edev */
        qed_ops->common->slowpath_stop(cdev);
        if (system_state == SYSTEM_POWER_OFF)
index 95749006d687b971a49894c903fcc611bc25c375..6746e498dc61aea76d6caadc872e0ebf94d94f45 100644 (file)
@@ -673,7 +673,6 @@ static void tun_detach(struct tun_file *tfile, bool clean)
 static void tun_detach_all(struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
-       struct bpf_prog *xdp_prog = rtnl_dereference(tun->xdp_prog);
        struct tun_file *tfile, *tmp;
        int i, n = tun->numqueues;
 
@@ -708,9 +707,6 @@ static void tun_detach_all(struct net_device *dev)
        }
        BUG_ON(tun->numdisabled != 0);
 
-       if (xdp_prog)
-               bpf_prog_put(xdp_prog);
-
        if (tun->flags & IFF_PERSIST)
                module_put(THIS_MODULE);
 }
index 3f271c9cb5e05d0b8b10faa7401f2d3b7fcec3e7..6bea8931bb622f37129dc75b13a60243ea57360b 100644 (file)
@@ -7110,6 +7110,27 @@ static int dev_xdp_install(struct net_device *dev, bpf_op_t bpf_op,
        return bpf_op(dev, &xdp);
 }
 
+static void dev_xdp_uninstall(struct net_device *dev)
+{
+       struct netdev_bpf xdp;
+       bpf_op_t ndo_bpf;
+
+       /* Remove generic XDP */
+       WARN_ON(dev_xdp_install(dev, generic_xdp_install, NULL, 0, NULL));
+
+       /* Remove from the driver */
+       ndo_bpf = dev->netdev_ops->ndo_bpf;
+       if (!ndo_bpf)
+               return;
+
+       __dev_xdp_query(dev, ndo_bpf, &xdp);
+       if (xdp.prog_attached == XDP_ATTACHED_NONE)
+               return;
+
+       /* Program removal should always succeed */
+       WARN_ON(dev_xdp_install(dev, ndo_bpf, NULL, xdp.prog_flags, NULL));
+}
+
 /**
  *     dev_change_xdp_fd - set or clear a bpf program for a device rx path
  *     @dev: device
@@ -7240,6 +7261,7 @@ static void rollback_registered_many(struct list_head *head)
                /* Shutdown queueing discipline. */
                dev_shutdown(dev);
 
+               dev_xdp_uninstall(dev);
 
                /* Notify protocols, that we are about to destroy
                 * this device. They should clean all the things.
@@ -8199,7 +8221,6 @@ EXPORT_SYMBOL(alloc_netdev_mqs);
 void free_netdev(struct net_device *dev)
 {
        struct napi_struct *p, *n;
-       struct bpf_prog *prog;
 
        might_sleep();
        netif_free_tx_queues(dev);
@@ -8218,12 +8239,6 @@ void free_netdev(struct net_device *dev)
        free_percpu(dev->pcpu_refcnt);
        dev->pcpu_refcnt = NULL;
 
-       prog = rcu_dereference_protected(dev->xdp_prog, 1);
-       if (prog) {
-               bpf_prog_put(prog);
-               static_key_slow_dec(&generic_xdp_needed);
-       }
-
        /*  Compatibility with error handling in drivers */
        if (dev->reg_state == NETREG_UNINITIALIZED) {
                netdev_freemem(dev);