aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/dev.c
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2016-11-28 17:16:54 -0500
committerDavid S. Miller <davem@davemloft.net>2016-11-30 10:27:20 -0500
commit85de8576a0b14aecc99136cfbf90e367fa2142cb (patch)
tree30b716ce4c318a241ef2456bf2ed1be29991bcab /net/core/dev.c
parent0f29f05bd7064bdf0c9629511bcba7650ce364d5 (diff)
bpf, xdp: allow to pass flags to dev_change_xdp_fd
Add an IFLA_XDP_FLAGS attribute that can be passed for setting up XDP along with IFLA_XDP_FD, which eventually allows user space to implement typical add/replace/delete logic for programs. Right now, calling into dev_change_xdp_fd() will always replace previous programs. When passed XDP_FLAGS_UPDATE_IF_NOEXIST, we can handle this more graceful when requested by returning -EBUSY in case we try to attach a new program, but we find that another one is already attached. This will be used by upcoming front-end for iproute2 as well. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 048b46b7c92a..bffb5253e778 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6692,26 +6692,42 @@ EXPORT_SYMBOL(dev_change_proto_down);
6692 * dev_change_xdp_fd - set or clear a bpf program for a device rx path 6692 * dev_change_xdp_fd - set or clear a bpf program for a device rx path
6693 * @dev: device 6693 * @dev: device
6694 * @fd: new program fd or negative value to clear 6694 * @fd: new program fd or negative value to clear
6695 * @flags: xdp-related flags
6695 * 6696 *
6696 * Set or clear a bpf program for a device 6697 * Set or clear a bpf program for a device
6697 */ 6698 */
6698int dev_change_xdp_fd(struct net_device *dev, int fd) 6699int dev_change_xdp_fd(struct net_device *dev, int fd, u32 flags)
6699{ 6700{
6700 const struct net_device_ops *ops = dev->netdev_ops; 6701 const struct net_device_ops *ops = dev->netdev_ops;
6701 struct bpf_prog *prog = NULL; 6702 struct bpf_prog *prog = NULL;
6702 struct netdev_xdp xdp = {}; 6703 struct netdev_xdp xdp;
6703 int err; 6704 int err;
6704 6705
6706 ASSERT_RTNL();
6707
6705 if (!ops->ndo_xdp) 6708 if (!ops->ndo_xdp)
6706 return -EOPNOTSUPP; 6709 return -EOPNOTSUPP;
6707 if (fd >= 0) { 6710 if (fd >= 0) {
6711 if (flags & XDP_FLAGS_UPDATE_IF_NOEXIST) {
6712 memset(&xdp, 0, sizeof(xdp));
6713 xdp.command = XDP_QUERY_PROG;
6714
6715 err = ops->ndo_xdp(dev, &xdp);
6716 if (err < 0)
6717 return err;
6718 if (xdp.prog_attached)
6719 return -EBUSY;
6720 }
6721
6708 prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP); 6722 prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
6709 if (IS_ERR(prog)) 6723 if (IS_ERR(prog))
6710 return PTR_ERR(prog); 6724 return PTR_ERR(prog);
6711 } 6725 }
6712 6726
6727 memset(&xdp, 0, sizeof(xdp));
6713 xdp.command = XDP_SETUP_PROG; 6728 xdp.command = XDP_SETUP_PROG;
6714 xdp.prog = prog; 6729 xdp.prog = prog;
6730
6715 err = ops->ndo_xdp(dev, &xdp); 6731 err = ops->ndo_xdp(dev, &xdp);
6716 if (err < 0 && prog) 6732 if (err < 0 && prog)
6717 bpf_prog_put(prog); 6733 bpf_prog_put(prog);