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 serial_test_xdp_link(void) 10 { 11 struct test_xdp_link *skel1 = NULL, *skel2 = NULL; 12 __u32 id1, id2, id0 = 0, prog_fd1, prog_fd2; 13 LIBBPF_OPTS(bpf_xdp_attach_opts, opts); 14 struct bpf_link_info link_info; 15 struct bpf_prog_info prog_info; 16 struct bpf_link *link; 17 int err; 18 __u32 link_info_len = sizeof(link_info); 19 __u32 prog_info_len = sizeof(prog_info); 20 21 skel1 = test_xdp_link__open_and_load(); 22 if (!ASSERT_OK_PTR(skel1, "skel_load")) 23 goto cleanup; 24 prog_fd1 = bpf_program__fd(skel1->progs.xdp_handler); 25 26 skel2 = test_xdp_link__open_and_load(); 27 if (!ASSERT_OK_PTR(skel2, "skel_load")) 28 goto cleanup; 29 prog_fd2 = bpf_program__fd(skel2->progs.xdp_handler); 30 31 memset(&prog_info, 0, sizeof(prog_info)); 32 err = bpf_prog_get_info_by_fd(prog_fd1, &prog_info, &prog_info_len); 33 if (!ASSERT_OK(err, "fd_info1")) 34 goto cleanup; 35 id1 = prog_info.id; 36 37 memset(&prog_info, 0, sizeof(prog_info)); 38 err = bpf_prog_get_info_by_fd(prog_fd2, &prog_info, &prog_info_len); 39 if (!ASSERT_OK(err, "fd_info2")) 40 goto cleanup; 41 id2 = prog_info.id; 42 43 /* set initial prog attachment */ 44 err = bpf_xdp_attach(IFINDEX_LO, prog_fd1, XDP_FLAGS_REPLACE, &opts); 45 if (!ASSERT_OK(err, "fd_attach")) 46 goto cleanup; 47 48 /* validate prog ID */ 49 err = bpf_xdp_query_id(IFINDEX_LO, 0, &id0); 50 if (!ASSERT_OK(err, "id1_check_err") || !ASSERT_EQ(id0, id1, "id1_check_val")) 51 goto cleanup; 52 53 /* BPF link is not allowed to replace prog attachment */ 54 link = bpf_program__attach_xdp(skel1->progs.xdp_handler, IFINDEX_LO); 55 if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 56 bpf_link__destroy(link); 57 /* best-effort detach prog */ 58 opts.old_prog_fd = prog_fd1; 59 bpf_xdp_detach(IFINDEX_LO, XDP_FLAGS_REPLACE, &opts); 60 goto cleanup; 61 } 62 63 /* detach BPF program */ 64 opts.old_prog_fd = prog_fd1; 65 err = bpf_xdp_detach(IFINDEX_LO, XDP_FLAGS_REPLACE, &opts); 66 if (!ASSERT_OK(err, "prog_detach")) 67 goto cleanup; 68 69 /* now BPF link should attach successfully */ 70 link = bpf_program__attach_xdp(skel1->progs.xdp_handler, IFINDEX_LO); 71 if (!ASSERT_OK_PTR(link, "link_attach")) 72 goto cleanup; 73 skel1->links.xdp_handler = link; 74 75 /* validate prog ID */ 76 err = bpf_xdp_query_id(IFINDEX_LO, 0, &id0); 77 if (!ASSERT_OK(err, "id1_check_err") || !ASSERT_EQ(id0, id1, "id1_check_val")) 78 goto cleanup; 79 80 /* BPF prog attach is not allowed to replace BPF link */ 81 opts.old_prog_fd = prog_fd1; 82 err = bpf_xdp_attach(IFINDEX_LO, prog_fd2, XDP_FLAGS_REPLACE, &opts); 83 if (!ASSERT_ERR(err, "prog_attach_fail")) 84 goto cleanup; 85 86 /* Can't force-update when BPF link is active */ 87 err = bpf_xdp_attach(IFINDEX_LO, prog_fd2, 0, NULL); 88 if (!ASSERT_ERR(err, "prog_update_fail")) 89 goto cleanup; 90 91 /* Can't force-detach when BPF link is active */ 92 err = bpf_xdp_detach(IFINDEX_LO, 0, NULL); 93 if (!ASSERT_ERR(err, "prog_detach_fail")) 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 (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) { 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 (!ASSERT_OK_PTR(link, "link_attach")) 109 goto cleanup; 110 skel2->links.xdp_handler = link; 111 112 err = bpf_xdp_query_id(IFINDEX_LO, 0, &id0); 113 if (!ASSERT_OK(err, "id2_check_err") || !ASSERT_EQ(id0, id2, "id2_check_val")) 114 goto cleanup; 115 116 /* updating program under active BPF link works as expected */ 117 err = bpf_link__update_program(link, skel1->progs.xdp_handler); 118 if (!ASSERT_OK(err, "link_upd")) 119 goto cleanup; 120 121 memset(&link_info, 0, sizeof(link_info)); 122 err = bpf_link_get_info_by_fd(bpf_link__fd(link), 123 &link_info, &link_info_len); 124 if (!ASSERT_OK(err, "link_info")) 125 goto cleanup; 126 127 ASSERT_EQ(link_info.type, BPF_LINK_TYPE_XDP, "link_type"); 128 ASSERT_EQ(link_info.prog_id, id1, "link_prog_id"); 129 ASSERT_EQ(link_info.xdp.ifindex, IFINDEX_LO, "link_ifindex"); 130 131 /* updating program under active BPF link with different type fails */ 132 err = bpf_link__update_program(link, skel1->progs.tc_handler); 133 if (!ASSERT_ERR(err, "link_upd_invalid")) 134 goto cleanup; 135 136 err = bpf_link__detach(link); 137 if (!ASSERT_OK(err, "link_detach")) 138 goto cleanup; 139 140 memset(&link_info, 0, sizeof(link_info)); 141 err = bpf_link_get_info_by_fd(bpf_link__fd(link), 142 &link_info, &link_info_len); 143 144 ASSERT_OK(err, "link_info"); 145 ASSERT_EQ(link_info.prog_id, id1, "link_prog_id"); 146 /* ifindex should be zeroed out */ 147 ASSERT_EQ(link_info.xdp.ifindex, 0, "link_ifindex"); 148 149 cleanup: 150 test_xdp_link__destroy(skel1); 151 test_xdp_link__destroy(skel2); 152 } 153