Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: add selftest for UDP SO_PEEK_OFF support

Add the SO_PEEK_OFF selftest for UDP. In this patch, I mainly do
three things:
1. rename tcp_so_peek_off.c
2. adjust for UDP protocol
3. add selftests into it

Suggested-by: Jon Maloy <jmaloy@redhat.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Jason Xing <kernelxing@tencent.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jason Xing and committed by
David S. Miller
5c26516f ff09bc36

+57 -37
+1
tools/testing/selftests/net/.gitignore
··· 34 34 scm_rights 35 35 sk_bind_sendto_listen 36 36 sk_connect_zero_addr 37 + sk_so_peek_off 37 38 socket 38 39 so_incoming_cpu 39 40 so_netns_cookie
+1 -1
tools/testing/selftests/net/Makefile
··· 80 80 TEST_GEN_FILES += bind_bhash 81 81 TEST_GEN_PROGS += sk_bind_sendto_listen 82 82 TEST_GEN_PROGS += sk_connect_zero_addr 83 - TEST_GEN_PROGS += tcp_so_peek_off 83 + TEST_GEN_PROGS += sk_so_peek_off 84 84 TEST_PROGS += test_ingress_egress_chaining.sh 85 85 TEST_GEN_PROGS += so_incoming_cpu 86 86 TEST_PROGS += sctp_vrf.sh
+55 -36
tools/testing/selftests/net/tcp_so_peek_off.c tools/testing/selftests/net/sk_so_peek_off.c
··· 10 10 #include <arpa/inet.h> 11 11 #include "../kselftest.h" 12 12 13 - static char *afstr(int af) 13 + static char *afstr(int af, int proto) 14 14 { 15 - return af == AF_INET ? "TCP/IPv4" : "TCP/IPv6"; 15 + if (proto == IPPROTO_TCP) 16 + return af == AF_INET ? "TCP/IPv4" : "TCP/IPv6"; 17 + else 18 + return af == AF_INET ? "UDP/IPv4" : "UDP/IPv6"; 16 19 } 17 20 18 - int tcp_peek_offset_probe(sa_family_t af) 21 + int sk_peek_offset_probe(sa_family_t af, int proto) 19 22 { 23 + int type = (proto == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM); 20 24 int optv = 0; 21 25 int ret = 0; 22 26 int s; 23 27 24 - s = socket(af, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP); 28 + s = socket(af, type, proto); 25 29 if (s < 0) { 26 30 ksft_perror("Temporary TCP socket creation failed"); 27 31 } else { 28 32 if (!setsockopt(s, SOL_SOCKET, SO_PEEK_OFF, &optv, sizeof(int))) 29 33 ret = 1; 30 34 else 31 - printf("%s does not support SO_PEEK_OFF\n", afstr(af)); 35 + printf("%s does not support SO_PEEK_OFF\n", afstr(af, proto)); 32 36 close(s); 33 37 } 34 38 return ret; 35 39 } 36 40 37 - static void tcp_peek_offset_set(int s, int offset) 41 + static void sk_peek_offset_set(int s, int offset) 38 42 { 39 43 if (setsockopt(s, SOL_SOCKET, SO_PEEK_OFF, &offset, sizeof(offset))) 40 44 ksft_perror("Failed to set SO_PEEK_OFF value\n"); 41 45 } 42 46 43 - static int tcp_peek_offset_get(int s) 47 + static int sk_peek_offset_get(int s) 44 48 { 45 49 int offset; 46 50 socklen_t len = sizeof(offset); ··· 54 50 return offset; 55 51 } 56 52 57 - static int tcp_peek_offset_test(sa_family_t af) 53 + static int sk_peek_offset_test(sa_family_t af, int proto) 58 54 { 55 + int type = (proto == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM); 59 56 union { 60 57 struct sockaddr sa; 61 58 struct sockaddr_in a4; ··· 67 62 int recv_sock = 0; 68 63 int offset = 0; 69 64 ssize_t len; 70 - char buf; 65 + char buf[2]; 71 66 72 67 memset(&a, 0, sizeof(a)); 73 68 a.sa.sa_family = af; 74 69 75 - s[0] = socket(af, SOCK_STREAM, IPPROTO_TCP); 76 - s[1] = socket(af, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP); 70 + s[0] = recv_sock = socket(af, type, proto); 71 + s[1] = socket(af, type, proto); 77 72 78 73 if (s[0] < 0 || s[1] < 0) { 79 74 ksft_perror("Temporary socket creation failed\n"); ··· 87 82 ksft_perror("Temporary socket getsockname() failed\n"); 88 83 goto out; 89 84 } 90 - if (listen(s[0], 0) < 0) { 85 + if (proto == IPPROTO_TCP && listen(s[0], 0) < 0) { 91 86 ksft_perror("Temporary socket listen() failed\n"); 92 87 goto out; 93 88 } 94 - if (connect(s[1], &a.sa, sizeof(a)) >= 0 || errno != EINPROGRESS) { 89 + if (connect(s[1], &a.sa, sizeof(a)) < 0) { 95 90 ksft_perror("Temporary socket connect() failed\n"); 96 91 goto out; 97 92 } 98 - recv_sock = accept(s[0], NULL, NULL); 99 - if (recv_sock <= 0) { 100 - ksft_perror("Temporary socket accept() failed\n"); 101 - goto out; 93 + if (proto == IPPROTO_TCP) { 94 + recv_sock = accept(s[0], NULL, NULL); 95 + if (recv_sock <= 0) { 96 + ksft_perror("Temporary socket accept() failed\n"); 97 + goto out; 98 + } 102 99 } 103 100 104 101 /* Some basic tests of getting/setting offset */ 105 - offset = tcp_peek_offset_get(recv_sock); 102 + offset = sk_peek_offset_get(recv_sock); 106 103 if (offset != -1) { 107 104 ksft_perror("Initial value of socket offset not -1\n"); 108 105 goto out; 109 106 } 110 - tcp_peek_offset_set(recv_sock, 0); 111 - offset = tcp_peek_offset_get(recv_sock); 107 + sk_peek_offset_set(recv_sock, 0); 108 + offset = sk_peek_offset_get(recv_sock); 112 109 if (offset != 0) { 113 110 ksft_perror("Failed to set socket offset to 0\n"); 114 111 goto out; 115 112 } 116 113 117 114 /* Transfer a message */ 118 - if (send(s[1], (char *)("ab"), 2, 0) <= 0 || errno != EINPROGRESS) { 115 + if (send(s[1], (char *)("ab"), 2, 0) != 2) { 119 116 ksft_perror("Temporary probe socket send() failed\n"); 120 117 goto out; 121 118 } 122 119 /* Read first byte */ 123 - len = recv(recv_sock, &buf, 1, MSG_PEEK); 124 - if (len != 1 || buf != 'a') { 120 + len = recv(recv_sock, buf, 1, MSG_PEEK); 121 + if (len != 1 || buf[0] != 'a') { 125 122 ksft_perror("Failed to read first byte of message\n"); 126 123 goto out; 127 124 } 128 - offset = tcp_peek_offset_get(recv_sock); 125 + offset = sk_peek_offset_get(recv_sock); 129 126 if (offset != 1) { 130 127 ksft_perror("Offset not forwarded correctly at first byte\n"); 131 128 goto out; 132 129 } 133 130 /* Try to read beyond last byte */ 134 - len = recv(recv_sock, &buf, 2, MSG_PEEK); 135 - if (len != 1 || buf != 'b') { 131 + len = recv(recv_sock, buf, 2, MSG_PEEK); 132 + if (len != 1 || buf[0] != 'b') { 136 133 ksft_perror("Failed to read last byte of message\n"); 137 134 goto out; 138 135 } 139 - offset = tcp_peek_offset_get(recv_sock); 136 + offset = sk_peek_offset_get(recv_sock); 140 137 if (offset != 2) { 141 138 ksft_perror("Offset not forwarded correctly at last byte\n"); 142 139 goto out; 143 140 } 144 141 /* Flush message */ 145 - len = recv(recv_sock, NULL, 2, MSG_TRUNC); 142 + len = recv(recv_sock, buf, 2, MSG_TRUNC); 146 143 if (len != 2) { 147 144 ksft_perror("Failed to flush message\n"); 148 145 goto out; 149 146 } 150 - offset = tcp_peek_offset_get(recv_sock); 147 + offset = sk_peek_offset_get(recv_sock); 151 148 if (offset != 0) { 152 149 ksft_perror("Offset not reverted correctly after flush\n"); 153 150 goto out; 154 151 } 155 152 156 - printf("%s with MSG_PEEK_OFF works correctly\n", afstr(af)); 153 + printf("%s with MSG_PEEK_OFF works correctly\n", afstr(af, proto)); 157 154 res = 1; 158 155 out: 159 - if (recv_sock >= 0) 156 + if (proto == IPPROTO_TCP && recv_sock >= 0) 160 157 close(recv_sock); 161 158 if (s[1] >= 0) 162 159 close(s[1]); ··· 167 160 return res; 168 161 } 169 162 170 - int main(void) 163 + static int do_test(int proto) 171 164 { 172 165 int res4, res6; 173 166 174 - res4 = tcp_peek_offset_probe(AF_INET); 175 - res6 = tcp_peek_offset_probe(AF_INET6); 167 + res4 = sk_peek_offset_probe(AF_INET, proto); 168 + res6 = sk_peek_offset_probe(AF_INET6, proto); 176 169 177 170 if (!res4 && !res6) 178 171 return KSFT_SKIP; 179 172 180 173 if (res4) 181 - res4 = tcp_peek_offset_test(AF_INET); 174 + res4 = sk_peek_offset_test(AF_INET, proto); 182 175 183 176 if (res6) 184 - res6 = tcp_peek_offset_test(AF_INET6); 177 + res6 = sk_peek_offset_test(AF_INET6, proto); 185 178 186 179 if (!res4 || !res6) 180 + return KSFT_FAIL; 181 + 182 + return KSFT_PASS; 183 + } 184 + 185 + int main(void) 186 + { 187 + int restcp, resudp; 188 + 189 + restcp = do_test(IPPROTO_TCP); 190 + resudp = do_test(IPPROTO_UDP); 191 + if (restcp == KSFT_FAIL || resudp == KSFT_FAIL) 187 192 return KSFT_FAIL; 188 193 189 194 return KSFT_PASS;