mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
net: hold netdev instance lock during ndo_bpf
Cover the paths that come via bpf system call and XSK bind. Cc: Saeed Mahameed <saeed@kernel.org> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20250305163732.2766420-10-sdf@fomichev.me Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
ad7c7b2172
commit
97246d6d21
6 changed files with 33 additions and 4 deletions
|
@ -4277,6 +4277,7 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
|
||||||
|
|
||||||
int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
|
int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
|
||||||
u8 dev_xdp_prog_count(struct net_device *dev);
|
u8 dev_xdp_prog_count(struct net_device *dev);
|
||||||
|
int netif_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf);
|
||||||
int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf);
|
int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf);
|
||||||
u8 dev_xdp_sb_prog_count(struct net_device *dev);
|
u8 dev_xdp_sb_prog_count(struct net_device *dev);
|
||||||
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
|
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
|
||||||
|
|
|
@ -528,10 +528,10 @@ struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
bpf_map_init_from_attr(&offmap->map, attr);
|
bpf_map_init_from_attr(&offmap->map, attr);
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
down_write(&bpf_devs_lock);
|
|
||||||
offmap->netdev = __dev_get_by_index(net, attr->map_ifindex);
|
offmap->netdev = __dev_get_by_index(net, attr->map_ifindex);
|
||||||
|
netdev_lock_ops(offmap->netdev);
|
||||||
|
down_write(&bpf_devs_lock);
|
||||||
err = bpf_dev_offload_check(offmap->netdev);
|
err = bpf_dev_offload_check(offmap->netdev);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_unlock;
|
goto err_unlock;
|
||||||
|
@ -548,12 +548,14 @@ struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr)
|
||||||
|
|
||||||
list_add_tail(&offmap->offloads, &ondev->maps);
|
list_add_tail(&offmap->offloads, &ondev->maps);
|
||||||
up_write(&bpf_devs_lock);
|
up_write(&bpf_devs_lock);
|
||||||
|
netdev_unlock_ops(offmap->netdev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
||||||
return &offmap->map;
|
return &offmap->map;
|
||||||
|
|
||||||
err_unlock:
|
err_unlock:
|
||||||
up_write(&bpf_devs_lock);
|
up_write(&bpf_devs_lock);
|
||||||
|
netdev_unlock_ops(offmap->netdev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
bpf_map_area_free(offmap);
|
bpf_map_area_free(offmap);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
|
|
@ -9852,7 +9852,7 @@ u8 dev_xdp_sb_prog_count(struct net_device *dev)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
|
int netif_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
|
||||||
{
|
{
|
||||||
if (!dev->netdev_ops->ndo_bpf)
|
if (!dev->netdev_ops->ndo_bpf)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -9872,7 +9872,6 @@ int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
|
||||||
|
|
||||||
return dev->netdev_ops->ndo_bpf(dev, bpf);
|
return dev->netdev_ops->ndo_bpf(dev, bpf);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dev_xdp_propagate);
|
|
||||||
|
|
||||||
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
|
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
|
||||||
{
|
{
|
||||||
|
@ -9902,6 +9901,8 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
|
||||||
struct netdev_bpf xdp;
|
struct netdev_bpf xdp;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
netdev_ops_assert_locked(dev);
|
||||||
|
|
||||||
if (dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
|
if (dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
|
||||||
prog && !prog->aux->xdp_has_frags) {
|
prog && !prog->aux->xdp_has_frags) {
|
||||||
NL_SET_ERR_MSG(extack, "unable to install XDP to device using tcp-data-split");
|
NL_SET_ERR_MSG(extack, "unable to install XDP to device using tcp-data-split");
|
||||||
|
@ -10134,7 +10135,9 @@ static void bpf_xdp_link_release(struct bpf_link *link)
|
||||||
* already NULL, in which case link was already auto-detached
|
* already NULL, in which case link was already auto-detached
|
||||||
*/
|
*/
|
||||||
if (xdp_link->dev) {
|
if (xdp_link->dev) {
|
||||||
|
netdev_lock_ops(xdp_link->dev);
|
||||||
WARN_ON(dev_xdp_detach_link(xdp_link->dev, NULL, xdp_link));
|
WARN_ON(dev_xdp_detach_link(xdp_link->dev, NULL, xdp_link));
|
||||||
|
netdev_unlock_ops(xdp_link->dev);
|
||||||
xdp_link->dev = NULL;
|
xdp_link->dev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10216,10 +10219,12 @@ static int bpf_xdp_link_update(struct bpf_link *link, struct bpf_prog *new_prog,
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netdev_lock_ops(xdp_link->dev);
|
||||||
mode = dev_xdp_mode(xdp_link->dev, xdp_link->flags);
|
mode = dev_xdp_mode(xdp_link->dev, xdp_link->flags);
|
||||||
bpf_op = dev_xdp_bpf_op(xdp_link->dev, mode);
|
bpf_op = dev_xdp_bpf_op(xdp_link->dev, mode);
|
||||||
err = dev_xdp_install(xdp_link->dev, mode, bpf_op, NULL,
|
err = dev_xdp_install(xdp_link->dev, mode, bpf_op, NULL,
|
||||||
xdp_link->flags, new_prog);
|
xdp_link->flags, new_prog);
|
||||||
|
netdev_unlock_ops(xdp_link->dev);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
|
@ -11005,7 +11010,9 @@ int register_netdevice(struct net_device *dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_uninit_notify;
|
goto err_uninit_notify;
|
||||||
|
|
||||||
|
netdev_lock_ops(dev);
|
||||||
__netdev_update_features(dev);
|
__netdev_update_features(dev);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default initial state at registry is that the
|
* Default initial state at registry is that the
|
||||||
|
@ -11945,7 +11952,9 @@ void unregister_netdevice_many_notify(struct list_head *head,
|
||||||
/* Shutdown queueing discipline. */
|
/* Shutdown queueing discipline. */
|
||||||
dev_shutdown(dev);
|
dev_shutdown(dev);
|
||||||
dev_tcx_uninstall(dev);
|
dev_tcx_uninstall(dev);
|
||||||
|
netdev_lock_ops(dev);
|
||||||
dev_xdp_uninstall(dev);
|
dev_xdp_uninstall(dev);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
bpf_dev_bound_netdev_unregister(dev);
|
bpf_dev_bound_netdev_unregister(dev);
|
||||||
dev_memory_provider_uninstall(dev);
|
dev_memory_provider_uninstall(dev);
|
||||||
|
|
||||||
|
|
|
@ -317,3 +317,15 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dev_set_mac_address);
|
EXPORT_SYMBOL(dev_set_mac_address);
|
||||||
|
|
||||||
|
int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
netdev_lock_ops(dev);
|
||||||
|
ret = netif_xdp_propagate(dev, bpf);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dev_xdp_propagate);
|
||||||
|
|
|
@ -1181,6 +1181,8 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
|
||||||
goto out_release;
|
goto out_release;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netdev_lock_ops(dev);
|
||||||
|
|
||||||
if (!xs->rx && !xs->tx) {
|
if (!xs->rx && !xs->tx) {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
@ -1315,6 +1317,7 @@ out_unlock:
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
WRITE_ONCE(xs->state, XSK_BOUND);
|
WRITE_ONCE(xs->state, XSK_BOUND);
|
||||||
}
|
}
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
out_release:
|
out_release:
|
||||||
mutex_unlock(&xs->mutex);
|
mutex_unlock(&xs->mutex);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#include <linux/netdevice.h>
|
||||||
#include <net/xsk_buff_pool.h>
|
#include <net/xsk_buff_pool.h>
|
||||||
#include <net/xdp_sock.h>
|
#include <net/xdp_sock.h>
|
||||||
#include <net/xdp_sock_drv.h>
|
#include <net/xdp_sock_drv.h>
|
||||||
|
@ -219,6 +220,7 @@ int xp_assign_dev(struct xsk_buff_pool *pool,
|
||||||
bpf.xsk.pool = pool;
|
bpf.xsk.pool = pool;
|
||||||
bpf.xsk.queue_id = queue_id;
|
bpf.xsk.queue_id = queue_id;
|
||||||
|
|
||||||
|
netdev_ops_assert_locked(netdev);
|
||||||
err = netdev->netdev_ops->ndo_bpf(netdev, &bpf);
|
err = netdev->netdev_ops->ndo_bpf(netdev, &bpf);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_unreg_pool;
|
goto err_unreg_pool;
|
||||||
|
|
Loading…
Add table
Reference in a new issue