Merge tag 'xfs-5.13-fixes-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-2.6-microblaze.git] / tools / testing / selftests / bpf / prog_tests / xdp_link.c
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"
6
7 #define IFINDEX_LO 1
8
9 void test_xdp_link(void)
10 {
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);
19
20         skel1 = test_xdp_link__open_and_load();
21         if (CHECK(!skel1, "skel_load", "skeleton open and load failed\n"))
22                 goto cleanup;
23         prog_fd1 = bpf_program__fd(skel1->progs.xdp_handler);
24
25         skel2 = test_xdp_link__open_and_load();
26         if (CHECK(!skel2, "skel_load", "skeleton open and load failed\n"))
27                 goto cleanup;
28         prog_fd2 = bpf_program__fd(skel2->progs.xdp_handler);
29
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))
33                 goto cleanup;
34         id1 = prog_info.id;
35
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))
39                 goto cleanup;
40         id2 = prog_info.id;
41
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))
45                 goto cleanup;
46
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);
51
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);
59                 goto cleanup;
60         }
61
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))
66                 goto cleanup;
67
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)))
71                 goto cleanup;
72         skel1->links.xdp_handler = link;
73
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))
78                 goto cleanup;
79
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"))
84                 goto cleanup;
85
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"))
89                 goto cleanup;
90
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"))
94                 goto cleanup;
95
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);
100                 goto cleanup;
101         }
102
103         bpf_link__destroy(skel1->links.xdp_handler);
104         skel1->links.xdp_handler = NULL;
105
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)))
109                 goto cleanup;
110         skel2->links.xdp_handler = link;
111
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))
115                 goto cleanup;
116
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))
120                 goto cleanup;
121
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))
125                 goto cleanup;
126
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);
133
134         err = bpf_link__detach(link);
135         if (CHECK(err, "link_detach", "failed %d\n", err))
136                 goto cleanup;
137
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))
141                 goto cleanup;
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);
147
148 cleanup:
149         test_xdp_link__destroy(skel1);
150         test_xdp_link__destroy(skel2);
151 }