Skip to content

Commit aa8d3a7

Browse files
anakryikoAlexei Starovoitov
authored and
Alexei Starovoitov
committed
bpf, xdp: Add bpf_link-based XDP attachment API
Add bpf_link-based API (bpf_xdp_link) to attach BPF XDP program through BPF_LINK_CREATE command. bpf_xdp_link is mutually exclusive with direct BPF program attachment, previous BPF program should be detached prior to attempting to create a new bpf_xdp_link attachment (for a given XDP mode). Once BPF link is attached, it can't be replaced by other BPF program attachment or link attachment. It will be detached only when the last BPF link FD is closed. bpf_xdp_link will be auto-detached when net_device is shutdown, similarly to how other BPF links behave (cgroup, flow_dissector). At that point bpf_link will become defunct, but won't be destroyed until last FD is closed. Signed-off-by: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20200722064603.3350758-5-andriin@fb.com
1 parent d4baa93 commit aa8d3a7

File tree

4 files changed

+178
-7
lines changed

4 files changed

+178
-7
lines changed

include/linux/netdevice.h

+4
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,7 @@ struct bpf_prog_offload_ops;
888888
struct netlink_ext_ack;
889889
struct xdp_umem;
890890
struct xdp_dev_bulk_queue;
891+
struct bpf_xdp_link;
891892

892893
enum bpf_xdp_mode {
893894
XDP_MODE_SKB = 0,
@@ -898,6 +899,7 @@ enum bpf_xdp_mode {
898899

899900
struct bpf_xdp_entity {
900901
struct bpf_prog *prog;
902+
struct bpf_xdp_link *link;
901903
};
902904

903905
struct netdev_bpf {
@@ -3831,7 +3833,9 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
38313833
typedef int (*bpf_op_t)(struct net_device *dev, struct netdev_bpf *bpf);
38323834
int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
38333835
int fd, int expected_fd, u32 flags);
3836+
int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
38343837
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
3838+
38353839
int xdp_umem_query(struct net_device *dev, u16 queue_id);
38363840

38373841
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);

include/uapi/linux/bpf.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ enum bpf_attach_type {
230230
BPF_CGROUP_INET_SOCK_RELEASE,
231231
BPF_XDP_CPUMAP,
232232
BPF_SK_LOOKUP,
233+
BPF_XDP,
233234
__MAX_BPF_ATTACH_TYPE
234235
};
235236

@@ -242,6 +243,7 @@ enum bpf_link_type {
242243
BPF_LINK_TYPE_CGROUP = 3,
243244
BPF_LINK_TYPE_ITER = 4,
244245
BPF_LINK_TYPE_NETNS = 5,
246+
BPF_LINK_TYPE_XDP = 6,
245247

246248
MAX_BPF_LINK_TYPE,
247249
};
@@ -614,7 +616,10 @@ union bpf_attr {
614616

615617
struct { /* struct used by BPF_LINK_CREATE command */
616618
__u32 prog_fd; /* eBPF program to attach */
617-
__u32 target_fd; /* object to attach to */
619+
union {
620+
__u32 target_fd; /* object to attach to */
621+
__u32 target_ifindex; /* target ifindex */
622+
};
618623
__u32 attach_type; /* attach type */
619624
__u32 flags; /* extra flags */
620625
} link_create;

kernel/bpf/syscall.c

+5
Original file line numberDiff line numberDiff line change
@@ -2824,6 +2824,8 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
28242824
return BPF_PROG_TYPE_TRACING;
28252825
case BPF_SK_LOOKUP:
28262826
return BPF_PROG_TYPE_SK_LOOKUP;
2827+
case BPF_XDP:
2828+
return BPF_PROG_TYPE_XDP;
28272829
default:
28282830
return BPF_PROG_TYPE_UNSPEC;
28292831
}
@@ -3921,6 +3923,9 @@ static int link_create(union bpf_attr *attr)
39213923
case BPF_PROG_TYPE_SK_LOOKUP:
39223924
ret = netns_bpf_link_create(attr, prog);
39233925
break;
3926+
case BPF_PROG_TYPE_XDP:
3927+
ret = bpf_xdp_link_attach(attr, prog);
3928+
break;
39243929
default:
39253930
ret = -EINVAL;
39263931
}

net/core/dev.c

+163-6
Original file line numberDiff line numberDiff line change
@@ -8716,6 +8716,12 @@ int dev_change_proto_down_generic(struct net_device *dev, bool proto_down)
87168716
}
87178717
EXPORT_SYMBOL(dev_change_proto_down_generic);
87188718

8719+
struct bpf_xdp_link {
8720+
struct bpf_link link;
8721+
struct net_device *dev; /* protected by rtnl_lock, no refcnt held */
8722+
int flags;
8723+
};
8724+
87198725
static enum bpf_xdp_mode dev_xdp_mode(u32 flags)
87208726
{
87218727
if (flags & XDP_FLAGS_HW_MODE)
@@ -8738,9 +8744,19 @@ static bpf_op_t dev_xdp_bpf_op(struct net_device *dev, enum bpf_xdp_mode mode)
87388744
};
87398745
}
87408746

8747+
static struct bpf_xdp_link *dev_xdp_link(struct net_device *dev,
8748+
enum bpf_xdp_mode mode)
8749+
{
8750+
return dev->xdp_state[mode].link;
8751+
}
8752+
87418753
static struct bpf_prog *dev_xdp_prog(struct net_device *dev,
87428754
enum bpf_xdp_mode mode)
87438755
{
8756+
struct bpf_xdp_link *link = dev_xdp_link(dev, mode);
8757+
8758+
if (link)
8759+
return link->link.prog;
87448760
return dev->xdp_state[mode].prog;
87458761
}
87468762

@@ -8751,9 +8767,17 @@ u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
87518767
return prog ? prog->aux->id : 0;
87528768
}
87538769

8770+
static void dev_xdp_set_link(struct net_device *dev, enum bpf_xdp_mode mode,
8771+
struct bpf_xdp_link *link)
8772+
{
8773+
dev->xdp_state[mode].link = link;
8774+
dev->xdp_state[mode].prog = NULL;
8775+
}
8776+
87548777
static void dev_xdp_set_prog(struct net_device *dev, enum bpf_xdp_mode mode,
87558778
struct bpf_prog *prog)
87568779
{
8780+
dev->xdp_state[mode].link = NULL;
87578781
dev->xdp_state[mode].prog = prog;
87588782
}
87598783

@@ -8793,6 +8817,7 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
87938817

87948818
static void dev_xdp_uninstall(struct net_device *dev)
87958819
{
8820+
struct bpf_xdp_link *link;
87968821
struct bpf_prog *prog;
87978822
enum bpf_xdp_mode mode;
87988823
bpf_op_t bpf_op;
@@ -8810,14 +8835,20 @@ static void dev_xdp_uninstall(struct net_device *dev)
88108835

88118836
WARN_ON(dev_xdp_install(dev, mode, bpf_op, NULL, 0, NULL));
88128837

8813-
bpf_prog_put(prog);
8814-
dev_xdp_set_prog(dev, mode, NULL);
8838+
/* auto-detach link from net device */
8839+
link = dev_xdp_link(dev, mode);
8840+
if (link)
8841+
link->dev = NULL;
8842+
else
8843+
bpf_prog_put(prog);
8844+
8845+
dev_xdp_set_link(dev, mode, NULL);
88158846
}
88168847
}
88178848

88188849
static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack,
8819-
struct bpf_prog *new_prog, struct bpf_prog *old_prog,
8820-
u32 flags)
8850+
struct bpf_xdp_link *link, struct bpf_prog *new_prog,
8851+
struct bpf_prog *old_prog, u32 flags)
88218852
{
88228853
struct bpf_prog *cur_prog;
88238854
enum bpf_xdp_mode mode;
@@ -8826,6 +8857,14 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
88268857

88278858
ASSERT_RTNL();
88288859

8860+
/* either link or prog attachment, never both */
8861+
if (link && (new_prog || old_prog))
8862+
return -EINVAL;
8863+
/* link supports only XDP mode flags */
8864+
if (link && (flags & ~XDP_FLAGS_MODES)) {
8865+
NL_SET_ERR_MSG(extack, "Invalid XDP flags for BPF link attachment");
8866+
return -EINVAL;
8867+
}
88298868
/* just one XDP mode bit should be set, zero defaults to SKB mode */
88308869
if (hweight32(flags & XDP_FLAGS_MODES) > 1) {
88318870
NL_SET_ERR_MSG(extack, "Only one XDP mode flag can be set");
@@ -8838,7 +8877,18 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
88388877
}
88398878

88408879
mode = dev_xdp_mode(flags);
8880+
/* can't replace attached link */
8881+
if (dev_xdp_link(dev, mode)) {
8882+
NL_SET_ERR_MSG(extack, "Can't replace active BPF XDP link");
8883+
return -EBUSY;
8884+
}
8885+
88418886
cur_prog = dev_xdp_prog(dev, mode);
8887+
/* can't replace attached prog with link */
8888+
if (link && cur_prog) {
8889+
NL_SET_ERR_MSG(extack, "Can't replace active XDP program with BPF link");
8890+
return -EBUSY;
8891+
}
88428892
if ((flags & XDP_FLAGS_REPLACE) && cur_prog != old_prog) {
88438893
NL_SET_ERR_MSG(extack, "Active program does not match expected");
88448894
return -EEXIST;
@@ -8848,6 +8898,10 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
88488898
return -EBUSY;
88498899
}
88508900

8901+
/* put effective new program into new_prog */
8902+
if (link)
8903+
new_prog = link->link.prog;
8904+
88518905
if (new_prog) {
88528906
bool offload = mode == XDP_MODE_HW;
88538907
enum bpf_xdp_mode other_mode = mode == XDP_MODE_SKB
@@ -8884,13 +8938,116 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
88848938
return err;
88858939
}
88868940

8887-
dev_xdp_set_prog(dev, mode, new_prog);
8941+
if (link)
8942+
dev_xdp_set_link(dev, mode, link);
8943+
else
8944+
dev_xdp_set_prog(dev, mode, new_prog);
88888945
if (cur_prog)
88898946
bpf_prog_put(cur_prog);
88908947

88918948
return 0;
88928949
}
88938950

8951+
static int dev_xdp_attach_link(struct net_device *dev,
8952+
struct netlink_ext_ack *extack,
8953+
struct bpf_xdp_link *link)
8954+
{
8955+
return dev_xdp_attach(dev, extack, link, NULL, NULL, link->flags);
8956+
}
8957+
8958+
static int dev_xdp_detach_link(struct net_device *dev,
8959+
struct netlink_ext_ack *extack,
8960+
struct bpf_xdp_link *link)
8961+
{
8962+
enum bpf_xdp_mode mode;
8963+
bpf_op_t bpf_op;
8964+
8965+
ASSERT_RTNL();
8966+
8967+
mode = dev_xdp_mode(link->flags);
8968+
if (dev_xdp_link(dev, mode) != link)
8969+
return -EINVAL;
8970+
8971+
bpf_op = dev_xdp_bpf_op(dev, mode);
8972+
WARN_ON(dev_xdp_install(dev, mode, bpf_op, NULL, 0, NULL));
8973+
dev_xdp_set_link(dev, mode, NULL);
8974+
return 0;
8975+
}
8976+
8977+
static void bpf_xdp_link_release(struct bpf_link *link)
8978+
{
8979+
struct bpf_xdp_link *xdp_link = container_of(link, struct bpf_xdp_link, link);
8980+
8981+
rtnl_lock();
8982+
8983+
/* if racing with net_device's tear down, xdp_link->dev might be
8984+
* already NULL, in which case link was already auto-detached
8985+
*/
8986+
if (xdp_link->dev)
8987+
WARN_ON(dev_xdp_detach_link(xdp_link->dev, NULL, xdp_link));
8988+
8989+
rtnl_unlock();
8990+
}
8991+
8992+
static void bpf_xdp_link_dealloc(struct bpf_link *link)
8993+
{
8994+
struct bpf_xdp_link *xdp_link = container_of(link, struct bpf_xdp_link, link);
8995+
8996+
kfree(xdp_link);
8997+
}
8998+
8999+
static const struct bpf_link_ops bpf_xdp_link_lops = {
9000+
.release = bpf_xdp_link_release,
9001+
.dealloc = bpf_xdp_link_dealloc,
9002+
};
9003+
9004+
int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
9005+
{
9006+
struct net *net = current->nsproxy->net_ns;
9007+
struct bpf_link_primer link_primer;
9008+
struct bpf_xdp_link *link;
9009+
struct net_device *dev;
9010+
int err, fd;
9011+
9012+
dev = dev_get_by_index(net, attr->link_create.target_ifindex);
9013+
if (!dev)
9014+
return -EINVAL;
9015+
9016+
link = kzalloc(sizeof(*link), GFP_USER);
9017+
if (!link) {
9018+
err = -ENOMEM;
9019+
goto out_put_dev;
9020+
}
9021+
9022+
bpf_link_init(&link->link, BPF_LINK_TYPE_XDP, &bpf_xdp_link_lops, prog);
9023+
link->dev = dev;
9024+
link->flags = attr->link_create.flags;
9025+
9026+
err = bpf_link_prime(&link->link, &link_primer);
9027+
if (err) {
9028+
kfree(link);
9029+
goto out_put_dev;
9030+
}
9031+
9032+
rtnl_lock();
9033+
err = dev_xdp_attach_link(dev, NULL, link);
9034+
rtnl_unlock();
9035+
9036+
if (err) {
9037+
bpf_link_cleanup(&link_primer);
9038+
goto out_put_dev;
9039+
}
9040+
9041+
fd = bpf_link_settle(&link_primer);
9042+
/* link itself doesn't hold dev's refcnt to not complicate shutdown */
9043+
dev_put(dev);
9044+
return fd;
9045+
9046+
out_put_dev:
9047+
dev_put(dev);
9048+
return err;
9049+
}
9050+
88949051
/**
88959052
* dev_change_xdp_fd - set or clear a bpf program for a device rx path
88969053
* @dev: device
@@ -8927,7 +9084,7 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
89279084
}
89289085
}
89299086

8930-
err = dev_xdp_attach(dev, extack, new_prog, old_prog, flags);
9087+
err = dev_xdp_attach(dev, extack, NULL, new_prog, old_prog, flags);
89319088

89329089
err_out:
89339090
if (err && new_prog)

0 commit comments

Comments
 (0)