diff options
author | Andrii Nakryiko <andriin@fb.com> | 2020-07-21 23:45:58 -0700 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2020-07-25 20:37:02 -0700 |
commit | 026a4c28e1db3b0cb99cd9a3e495d4a8b632fa74 (patch) | |
tree | aaf5102f8f78022807ee0b083782e41e6b2ad527 /net/core/dev.c | |
parent | aa8d3a716b59db6c1ad6c68fb8aa05e31980da60 (diff) | |
download | linux-026a4c28e1db3b0cb99cd9a3e495d4a8b632fa74.tar.bz2 |
bpf, xdp: Implement LINK_UPDATE for BPF XDP link
Add support for LINK_UPDATE command for BPF XDP link to enable reliable
replacement of underlying BPF program.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200722064603.3350758-6-andriin@fb.com
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index e24248f3d675..49f284f51a22 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -8996,9 +8996,52 @@ static void bpf_xdp_link_dealloc(struct bpf_link *link) kfree(xdp_link); } +static int bpf_xdp_link_update(struct bpf_link *link, struct bpf_prog *new_prog, + struct bpf_prog *old_prog) +{ + struct bpf_xdp_link *xdp_link = container_of(link, struct bpf_xdp_link, link); + enum bpf_xdp_mode mode; + bpf_op_t bpf_op; + int err = 0; + + rtnl_lock(); + + /* link might have been auto-released already, so fail */ + if (!xdp_link->dev) { + err = -ENOLINK; + goto out_unlock; + } + + if (old_prog && link->prog != old_prog) { + err = -EPERM; + goto out_unlock; + } + old_prog = link->prog; + if (old_prog == new_prog) { + /* no-op, don't disturb drivers */ + bpf_prog_put(new_prog); + goto out_unlock; + } + + mode = dev_xdp_mode(xdp_link->flags); + bpf_op = dev_xdp_bpf_op(xdp_link->dev, mode); + err = dev_xdp_install(xdp_link->dev, mode, bpf_op, NULL, + xdp_link->flags, new_prog); + if (err) + goto out_unlock; + + old_prog = xchg(&link->prog, new_prog); + bpf_prog_put(old_prog); + +out_unlock: + rtnl_unlock(); + return err; +} + static const struct bpf_link_ops bpf_xdp_link_lops = { .release = bpf_xdp_link_release, .dealloc = bpf_xdp_link_dealloc, + .update_prog = bpf_xdp_link_update, }; int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) |