Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | // SPDX-License-Identifier: GPL-2.0 #include <test_progs.h> #include "cgroup_helpers.h" #include "network_helpers.h" #include "sockopt_inherit.skel.h" #define SOL_CUSTOM 0xdeadbeef #define CUSTOM_INHERIT1 0 #define CUSTOM_INHERIT2 1 #define CUSTOM_LISTENER 2 static int verify_sockopt(int fd, int optname, const char *msg, char expected) { socklen_t optlen = 1; char buf = 0; int err; err = getsockopt(fd, SOL_CUSTOM, optname, &buf, &optlen); if (err) { log_err("%s: failed to call getsockopt", msg); return 1; } printf("%s %d: got=0x%x ? expected=0x%x\n", msg, optname, buf, expected); if (buf != expected) { log_err("%s: unexpected getsockopt value %d != %d", msg, buf, expected); return 1; } return 0; } static pthread_mutex_t server_started_mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t server_started = PTHREAD_COND_INITIALIZER; static void *server_thread(void *arg) { struct sockaddr_storage addr; socklen_t len = sizeof(addr); int fd = *(int *)arg; int client_fd; int err = 0; err = listen(fd, 1); pthread_mutex_lock(&server_started_mtx); pthread_cond_signal(&server_started); pthread_mutex_unlock(&server_started_mtx); if (!ASSERT_GE(err, 0, "listed on socket")) return NULL; err += verify_sockopt(fd, CUSTOM_INHERIT1, "listen", 1); err += verify_sockopt(fd, CUSTOM_INHERIT2, "listen", 1); err += verify_sockopt(fd, CUSTOM_LISTENER, "listen", 1); client_fd = accept(fd, (struct sockaddr *)&addr, &len); if (!ASSERT_GE(client_fd, 0, "accept client")) return NULL; err += verify_sockopt(client_fd, CUSTOM_INHERIT1, "accept", 1); err += verify_sockopt(client_fd, CUSTOM_INHERIT2, "accept", 1); err += verify_sockopt(client_fd, CUSTOM_LISTENER, "accept", 0); close(client_fd); return (void *)(long)err; } static int custom_cb(int fd, const struct post_socket_opts *opts) { char buf; int err; int i; for (i = CUSTOM_INHERIT1; i <= CUSTOM_LISTENER; i++) { buf = 0x01; err = setsockopt(fd, SOL_CUSTOM, i, &buf, 1); if (err) { log_err("Failed to call setsockopt(%d)", i); return -1; } } return 0; } static void run_test(int cgroup_fd) { struct bpf_link *link_getsockopt = NULL; struct bpf_link *link_setsockopt = NULL; struct network_helper_opts opts = { .post_socket_cb = custom_cb, }; int server_fd = -1, client_fd; struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), }; struct sockopt_inherit *obj; void *server_err; pthread_t tid; int err; obj = sockopt_inherit__open_and_load(); if (!ASSERT_OK_PTR(obj, "skel-load")) return; obj->bss->page_size = sysconf(_SC_PAGESIZE); link_getsockopt = bpf_program__attach_cgroup(obj->progs._getsockopt, cgroup_fd); if (!ASSERT_OK_PTR(link_getsockopt, "cg-attach-getsockopt")) goto close_bpf_object; link_setsockopt = bpf_program__attach_cgroup(obj->progs._setsockopt, cgroup_fd); if (!ASSERT_OK_PTR(link_setsockopt, "cg-attach-setsockopt")) goto close_bpf_object; server_fd = start_server_addr(SOCK_STREAM, (struct sockaddr_storage *)&addr, sizeof(addr), &opts); if (!ASSERT_GE(server_fd, 0, "start_server")) goto close_bpf_object; pthread_mutex_lock(&server_started_mtx); if (!ASSERT_OK(pthread_create(&tid, NULL, server_thread, (void *)&server_fd), "pthread_create")) { pthread_mutex_unlock(&server_started_mtx); goto close_server_fd; } pthread_cond_wait(&server_started, &server_started_mtx); pthread_mutex_unlock(&server_started_mtx); client_fd = connect_to_fd(server_fd, 0); if (!ASSERT_GE(client_fd, 0, "connect_to_server")) goto close_server_fd; ASSERT_OK(verify_sockopt(client_fd, CUSTOM_INHERIT1, "connect", 0), "verify_sockopt1"); ASSERT_OK(verify_sockopt(client_fd, CUSTOM_INHERIT2, "connect", 0), "verify_sockopt2"); ASSERT_OK(verify_sockopt(client_fd, CUSTOM_LISTENER, "connect", 0), "verify_sockopt ener"); pthread_join(tid, &server_err); err = (int)(long)server_err; ASSERT_OK(err, "pthread_join retval"); close(client_fd); close_server_fd: close(server_fd); close_bpf_object: bpf_link__destroy(link_getsockopt); bpf_link__destroy(link_setsockopt); sockopt_inherit__destroy(obj); } void test_sockopt_inherit(void) { int cgroup_fd; cgroup_fd = test__join_cgroup("/sockopt_inherit"); if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup")) return; run_test(cgroup_fd); close(cgroup_fd); } |