1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
3 #include <uapi/linux/if_link.h>
4 #include <test_progs.h>
5 #include "test_xdp_link.skel.h"
9 void test_xdp_link(void)
11 __u32 duration
= 0, id1
, id2
, id0
= 0, prog_fd1
, prog_fd2
, err
;
12 DECLARE_LIBBPF_OPTS(bpf_xdp_set_link_opts
, opts
, .old_fd
= -1);
13 struct test_xdp_link
*skel1
= NULL
, *skel2
= NULL
;
14 struct bpf_link_info link_info
;
15 struct bpf_prog_info prog_info
;
16 struct bpf_link
*link
;
17 __u32 link_info_len
= sizeof(link_info
);
18 __u32 prog_info_len
= sizeof(prog_info
);
20 skel1
= test_xdp_link__open_and_load();
21 if (CHECK(!skel1
, "skel_load", "skeleton open and load failed\n"))
23 prog_fd1
= bpf_program__fd(skel1
->progs
.xdp_handler
);
25 skel2
= test_xdp_link__open_and_load();
26 if (CHECK(!skel2
, "skel_load", "skeleton open and load failed\n"))
28 prog_fd2
= bpf_program__fd(skel2
->progs
.xdp_handler
);
30 memset(&prog_info
, 0, sizeof(prog_info
));
31 err
= bpf_obj_get_info_by_fd(prog_fd1
, &prog_info
, &prog_info_len
);
32 if (CHECK(err
, "fd_info1", "failed %d\n", -errno
))
36 memset(&prog_info
, 0, sizeof(prog_info
));
37 err
= bpf_obj_get_info_by_fd(prog_fd2
, &prog_info
, &prog_info_len
);
38 if (CHECK(err
, "fd_info2", "failed %d\n", -errno
))
42 /* set initial prog attachment */
43 err
= bpf_set_link_xdp_fd_opts(IFINDEX_LO
, prog_fd1
, XDP_FLAGS_REPLACE
, &opts
);
44 if (CHECK(err
, "fd_attach", "initial prog attach failed: %d\n", err
))
47 /* validate prog ID */
48 err
= bpf_get_link_xdp_id(IFINDEX_LO
, &id0
, 0);
49 CHECK(err
|| id0
!= id1
, "id1_check",
50 "loaded prog id %u != id1 %u, err %d", id0
, id1
, err
);
52 /* BPF link is not allowed to replace prog attachment */
53 link
= bpf_program__attach_xdp(skel1
->progs
.xdp_handler
, IFINDEX_LO
);
54 if (CHECK(!IS_ERR(link
), "link_attach_fail", "unexpected success\n")) {
55 bpf_link__destroy(link
);
56 /* best-effort detach prog */
57 opts
.old_fd
= prog_fd1
;
58 bpf_set_link_xdp_fd_opts(IFINDEX_LO
, -1, XDP_FLAGS_REPLACE
, &opts
);
62 /* detach BPF program */
63 opts
.old_fd
= prog_fd1
;
64 err
= bpf_set_link_xdp_fd_opts(IFINDEX_LO
, -1, XDP_FLAGS_REPLACE
, &opts
);
65 if (CHECK(err
, "prog_detach", "failed %d\n", err
))
68 /* now BPF link should attach successfully */
69 link
= bpf_program__attach_xdp(skel1
->progs
.xdp_handler
, IFINDEX_LO
);
70 if (CHECK(IS_ERR(link
), "link_attach", "failed: %ld\n", PTR_ERR(link
)))
72 skel1
->links
.xdp_handler
= link
;
74 /* validate prog ID */
75 err
= bpf_get_link_xdp_id(IFINDEX_LO
, &id0
, 0);
76 if (CHECK(err
|| id0
!= id1
, "id1_check",
77 "loaded prog id %u != id1 %u, err %d", id0
, id1
, err
))
80 /* BPF prog attach is not allowed to replace BPF link */
81 opts
.old_fd
= prog_fd1
;
82 err
= bpf_set_link_xdp_fd_opts(IFINDEX_LO
, prog_fd2
, XDP_FLAGS_REPLACE
, &opts
);
83 if (CHECK(!err
, "prog_attach_fail", "unexpected success\n"))
86 /* Can't force-update when BPF link is active */
87 err
= bpf_set_link_xdp_fd(IFINDEX_LO
, prog_fd2
, 0);
88 if (CHECK(!err
, "prog_update_fail", "unexpected success\n"))
91 /* Can't force-detach when BPF link is active */
92 err
= bpf_set_link_xdp_fd(IFINDEX_LO
, -1, 0);
93 if (CHECK(!err
, "prog_detach_fail", "unexpected success\n"))
96 /* BPF link is not allowed to replace another BPF link */
97 link
= bpf_program__attach_xdp(skel2
->progs
.xdp_handler
, IFINDEX_LO
);
98 if (CHECK(!IS_ERR(link
), "link_attach_fail", "unexpected success\n")) {
99 bpf_link__destroy(link
);
103 bpf_link__destroy(skel1
->links
.xdp_handler
);
104 skel1
->links
.xdp_handler
= NULL
;
106 /* new link attach should succeed */
107 link
= bpf_program__attach_xdp(skel2
->progs
.xdp_handler
, IFINDEX_LO
);
108 if (CHECK(IS_ERR(link
), "link_attach", "failed: %ld\n", PTR_ERR(link
)))
110 skel2
->links
.xdp_handler
= link
;
112 err
= bpf_get_link_xdp_id(IFINDEX_LO
, &id0
, 0);
113 if (CHECK(err
|| id0
!= id2
, "id2_check",
114 "loaded prog id %u != id2 %u, err %d", id0
, id1
, err
))
117 /* updating program under active BPF link works as expected */
118 err
= bpf_link__update_program(link
, skel1
->progs
.xdp_handler
);
119 if (CHECK(err
, "link_upd", "failed: %d\n", err
))
122 memset(&link_info
, 0, sizeof(link_info
));
123 err
= bpf_obj_get_info_by_fd(bpf_link__fd(link
), &link_info
, &link_info_len
);
124 if (CHECK(err
, "link_info", "failed: %d\n", err
))
127 CHECK(link_info
.type
!= BPF_LINK_TYPE_XDP
, "link_type",
128 "got %u != exp %u\n", link_info
.type
, BPF_LINK_TYPE_XDP
);
129 CHECK(link_info
.prog_id
!= id1
, "link_prog_id",
130 "got %u != exp %u\n", link_info
.prog_id
, id1
);
131 CHECK(link_info
.xdp
.ifindex
!= IFINDEX_LO
, "link_ifindex",
132 "got %u != exp %u\n", link_info
.xdp
.ifindex
, IFINDEX_LO
);
134 err
= bpf_link__detach(link
);
135 if (CHECK(err
, "link_detach", "failed %d\n", err
))
138 memset(&link_info
, 0, sizeof(link_info
));
139 err
= bpf_obj_get_info_by_fd(bpf_link__fd(link
), &link_info
, &link_info_len
);
140 if (CHECK(err
, "link_info", "failed: %d\n", err
))
142 CHECK(link_info
.prog_id
!= id1
, "link_prog_id",
143 "got %u != exp %u\n", link_info
.prog_id
, id1
);
144 /* ifindex should be zeroed out */
145 CHECK(link_info
.xdp
.ifindex
!= 0, "link_ifindex",
146 "got %u != exp %u\n", link_info
.xdp
.ifindex
, 0);
149 test_xdp_link__destroy(skel1
);
150 test_xdp_link__destroy(skel2
);