diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2016-11-28 17:16:54 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-30 10:27:20 -0500 |
commit | 85de8576a0b14aecc99136cfbf90e367fa2142cb (patch) | |
tree | 30b716ce4c318a241ef2456bf2ed1be29991bcab /net/core/dev.c | |
parent | 0f29f05bd7064bdf0c9629511bcba7650ce364d5 (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.c | 20 |
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 | */ |
6698 | int dev_change_xdp_fd(struct net_device *dev, int fd) | 6699 | int 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); |