[RFC PATCH v2 bpf-next 04/15] xdp: Export dev_check_xdp and dev_change_xdp
From: Toshiaki Makita <hidden>
Date: 2019-10-18 05:03:01
Also in:
bpf
Subsystem:
networking drivers, networking [general], the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Factor out the check and change logic from dev_change_xdp_fd(), and export them for the following commit. Signed-off-by: Toshiaki Makita <redacted> --- include/linux/netdevice.h | 4 ++ net/core/dev.c | 111 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 95 insertions(+), 20 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3207e0b..c338a73 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h@@ -3707,6 +3707,10 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, int *ret); typedef int (*bpf_op_t)(struct net_device *dev, struct netdev_bpf *bpf); +int dev_check_xdp(struct net_device *dev, struct netlink_ext_ack *extack, + bool do_install, u32 *prog_id_p, u32 flags); +int dev_change_xdp(struct net_device *dev, struct netlink_ext_ack *extack, + struct bpf_prog *prod, u32 flags); int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, int fd, u32 flags); u32 __dev_xdp_query(struct net_device *dev, bpf_op_t xdp_op,
diff --git a/net/core/dev.c b/net/core/dev.c
index 8bc3dce..9965675 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c@@ -8317,23 +8317,24 @@ static void dev_xdp_uninstall(struct net_device *dev) } /** - * dev_change_xdp_fd - set or clear a bpf program for a device rx path + * dev_check_xdp - check if xdp prog can be [un]installed * @dev: device * @extack: netlink extended ack - * @fd: new program fd or negative value to clear + * @install: flag to install or uninstall + * @prog_id_p: pointer to a storage for program id * @flags: xdp-related flags * - * Set or clear a bpf program for a device + * Check if xdp prog can be [un]installed + * If a program is already loaded, store the prog id to prog_id_p */ -int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, - int fd, u32 flags) +int dev_check_xdp(struct net_device *dev, struct netlink_ext_ack *extack, + bool install, u32 *prog_id_p, u32 flags) { const struct net_device_ops *ops = dev->netdev_ops; enum bpf_netdev_command query; - struct bpf_prog *prog = NULL; bpf_op_t bpf_op, bpf_chk; bool offload; - int err; + u32 prog_id; ASSERT_RTNL();
@@ -8350,28 +8351,64 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, if (bpf_op == bpf_chk) bpf_chk = generic_xdp_install; - if (fd >= 0) { - u32 prog_id; - + if (install) { if (!offload && __dev_xdp_query(dev, bpf_chk, XDP_QUERY_PROG)) { NL_SET_ERR_MSG(extack, "native and generic XDP can't be active at the same time"); return -EEXIST; } prog_id = __dev_xdp_query(dev, bpf_op, query); + if (prog_id_p) + *prog_id_p = prog_id; if ((flags & XDP_FLAGS_UPDATE_IF_NOEXIST) && prog_id) { NL_SET_ERR_MSG(extack, "XDP program already attached"); return -EBUSY; } + } else { + prog_id = __dev_xdp_query(dev, bpf_op, query); + if (prog_id_p) + *prog_id_p = prog_id; + if (!prog_id) + return -ENOENT; + } - prog = bpf_prog_get_type_dev(fd, BPF_PROG_TYPE_XDP, - bpf_op == ops->ndo_bpf); - if (IS_ERR(prog)) - return PTR_ERR(prog); + return 0; +} +EXPORT_SYMBOL_GPL(dev_check_xdp); + +/** + * dev_change_xdp - set or clear a bpf program for a device rx path + * @dev: device + * @extack: netlink extended ack + * @prog: bpf progam + * @flags: xdp-related flags + * + * Set or clear a bpf program for a device. + * Caller must call dev_check_xdp before calling this function to + * check if xdp prog can be [un]installed. + */ +int dev_change_xdp(struct net_device *dev, struct netlink_ext_ack *extack, + struct bpf_prog *prog, u32 flags) +{ + const struct net_device_ops *ops = dev->netdev_ops; + enum bpf_netdev_command query; + bpf_op_t bpf_op; + bool offload; + + ASSERT_RTNL(); + + offload = flags & XDP_FLAGS_HW_MODE; + query = offload ? XDP_QUERY_PROG_HW : XDP_QUERY_PROG; + + bpf_op = ops->ndo_bpf; + if (!bpf_op || (flags & XDP_FLAGS_SKB_MODE)) + bpf_op = generic_xdp_install; + + if (prog) { + u32 prog_id = __dev_xdp_query(dev, bpf_op, query); if (!offload && bpf_prog_is_dev_bound(prog->aux)) { NL_SET_ERR_MSG(extack, "using device-bound program without HW_MODE flag is not supported"); - bpf_prog_put(prog); return -EINVAL; }
@@ -8379,13 +8416,47 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, bpf_prog_put(prog); return 0; } - } else { - if (!__dev_xdp_query(dev, bpf_op, query)) - return 0; } - err = dev_xdp_install(dev, bpf_op, extack, flags, prog); - if (err < 0 && prog) + return dev_xdp_install(dev, bpf_op, extack, flags, prog); +} +EXPORT_SYMBOL_GPL(dev_change_xdp); + +/** + * dev_change_xdp_fd - set or clear a bpf program for a device rx path + * @dev: device + * @extack: netlink extended ack + * @fd: new program fd or negative value to clear + * @flags: xdp-related flags + * + * Set or clear a bpf program for a device + */ +int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, + int fd, u32 flags) +{ + struct bpf_prog *prog = NULL; + bool install = fd >= 0; + int err; + + err = dev_check_xdp(dev, extack, install, NULL, flags); + if (err) { + if (!install && err == -ENOENT) + err = 0; + return err; + } + + if (install) { + bool attach_drv; + + attach_drv = dev->netdev_ops->ndo_bpf && + !(flags & XDP_FLAGS_SKB_MODE); + prog = bpf_prog_get_type_dev(fd, BPF_PROG_TYPE_XDP, attach_drv); + if (IS_ERR(prog)) + return PTR_ERR(prog); + } + + err = dev_change_xdp(dev, extack, prog, flags); + if (err && prog) bpf_prog_put(prog); return err;
--
1.8.3.1