]> git.proxmox.com Git - mirror_kronosnet.git/blob - libknet/tests/test-common.c
58216083a3b9a6979da5df1daf19e019ac1da435
[mirror_kronosnet.git] / libknet / tests / test-common.c
1 /*
2 * Copyright (C) 2016-2019 Red Hat, Inc. All rights reserved.
3 *
4 * Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
5 *
6 * This software licensed under GPL-2.0+
7 */
8
9 #include "config.h"
10
11 #include <errno.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include <sys/wait.h>
18 #include <fcntl.h>
19 #include <pthread.h>
20 #include <sys/select.h>
21
22 #include "libknet.h"
23 #include "test-common.h"
24
25 static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
26 static int log_init = 0;
27 static pthread_mutex_t log_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
28 static pthread_t log_thread;
29 static int log_thread_init = 0;
30 static int log_fds[2];
31 struct log_thread_data {
32 int logfd;
33 FILE *std;
34 };
35 static struct log_thread_data data;
36 static pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER;
37 static int stop_in_progress = 0;
38
39 static int _read_pipe(int fd, char **file, size_t *length)
40 {
41 char buf[4096];
42 int n;
43 int done = 0;
44
45 *file = NULL;
46 *length = 0;
47
48 memset(buf, 0, sizeof(buf));
49
50 while (!done) {
51
52 n = read(fd, buf, sizeof(buf));
53
54 if (n < 0) {
55 if (errno == EINTR)
56 continue;
57
58 if (*file)
59 free(*file);
60
61 return n;
62 }
63
64 if (n == 0 && (!*length))
65 return 0;
66
67 if (n == 0)
68 done = 1;
69
70 if (*file)
71 *file = realloc(*file, (*length) + n + done);
72 else
73 *file = malloc(n + done);
74
75 if (!*file)
76 return -1;
77
78 memmove((*file) + (*length), buf, n);
79 *length += (done + n);
80 }
81
82 /* Null terminator */
83 (*file)[(*length) - 1] = 0;
84
85 return 0;
86 }
87
88 int execute_shell(const char *command, char **error_string)
89 {
90 pid_t pid;
91 int status, err = 0;
92 int fd[2];
93 size_t size = 0;
94
95 if ((command == NULL) || (!error_string)) {
96 errno = EINVAL;
97 return FAIL;
98 }
99
100 *error_string = NULL;
101
102 err = pipe(fd);
103 if (err)
104 goto out_clean;
105
106 pid = fork();
107 if (pid < 0) {
108 err = pid;
109 goto out_clean;
110 }
111
112 if (pid) { /* parent */
113
114 close(fd[1]);
115 err = _read_pipe(fd[0], error_string, &size);
116 if (err)
117 goto out_clean0;
118
119 waitpid(pid, &status, 0);
120 if (!WIFEXITED(status)) {
121 err = -1;
122 goto out_clean0;
123 }
124 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
125 err = WEXITSTATUS(status);
126 goto out_clean0;
127 }
128 goto out_clean0;
129 } else { /* child */
130 close(0);
131 close(1);
132 close(2);
133
134 close(fd[0]);
135 dup2(fd[1], 1);
136 dup2(fd[1], 2);
137 close(fd[1]);
138
139 execlp("/bin/sh", "/bin/sh", "-c", command, NULL);
140 exit(FAIL);
141 }
142
143 out_clean:
144 close(fd[1]);
145 out_clean0:
146 close(fd[0]);
147
148 return err;
149 }
150
151 int is_memcheck(void)
152 {
153 char *val;
154
155 val = getenv("KNETMEMCHECK");
156
157 if (val) {
158 if (!strncmp(val, "yes", 3)) {
159 return 1;
160 }
161 }
162
163 return 0;
164 }
165
166 int is_helgrind(void)
167 {
168 char *val;
169
170 val = getenv("KNETHELGRIND");
171
172 if (val) {
173 if (!strncmp(val, "yes", 3)) {
174 return 1;
175 }
176 }
177
178 return 0;
179 }
180
181 void set_scheduler(int policy)
182 {
183 struct sched_param sched_param;
184 int err;
185
186 err = sched_get_priority_max(policy);
187 if (err < 0) {
188 printf("Could not get maximum scheduler priority\n");
189 exit(FAIL);
190 }
191 sched_param.sched_priority = err;
192 err = sched_setscheduler(0, policy, &sched_param);
193 if (err < 0) {
194 printf("Could not set priority\n");
195 exit(FAIL);
196 }
197 return;
198 }
199
200 int setup_logpipes(int *logfds)
201 {
202 if (pipe2(logfds, O_CLOEXEC | O_NONBLOCK) < 0) {
203 printf("Unable to setup logging pipe\n");
204 exit(FAIL);
205 }
206
207 return PASS;
208 }
209
210 void close_logpipes(int *logfds)
211 {
212 close(logfds[0]);
213 logfds[0] = 0;
214 close(logfds[1]);
215 logfds[1] = 0;
216 }
217
218 void flush_logs(int logfd, FILE *std)
219 {
220 struct knet_log_msg msg;
221 int len;
222
223 while (1) {
224 len = read(logfd, &msg, sizeof(msg));
225 if (len != sizeof(msg)) {
226 /*
227 * clear errno to avoid incorrect propagation
228 */
229 errno = 0;
230 return;
231 }
232
233 if (!msg.knet_h) {
234 /*
235 * this is harsh but this function is void
236 * and it is used also inside log_thread.
237 * this is the easiest to get out with an error
238 */
239 fprintf(std, "NO HANDLE INFO IN LOG MSG!!\n");
240 abort();
241 }
242
243 msg.msg[sizeof(msg.msg) - 1] = 0;
244
245 fprintf(std, "[knet]: [%s] %s: %.*s\n",
246 knet_log_get_loglevel_name(msg.msglevel),
247 knet_log_get_subsystem_name(msg.subsystem),
248 KNET_MAX_LOG_MSG_SIZE, msg.msg);
249 }
250 }
251
252 static void *_logthread(void *args)
253 {
254 while (1) {
255 int num;
256 struct timeval tv = { 60, 0 };
257 fd_set rfds;
258
259 FD_ZERO(&rfds);
260 FD_SET(data.logfd, &rfds);
261
262 num = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
263 if (num < 0) {
264 fprintf(data.std, "Unable select over logfd!\nHALTING LOGTHREAD!\n");
265 return NULL;
266 }
267 if (num == 0) {
268 fprintf(data.std, "[knet]: No logs in the last 60 seconds\n");
269 continue;
270 }
271 if (FD_ISSET(data.logfd, &rfds)) {
272 flush_logs(data.logfd, data.std);
273 }
274 }
275 }
276
277 int start_logthread(int logfd, FILE *std)
278 {
279 int savederrno = 0;
280
281 savederrno = pthread_mutex_lock(&log_thread_mutex);
282 if (savederrno) {
283 printf("Unable to get log_thread mutex lock\n");
284 return -1;
285 }
286
287 if (!log_thread_init) {
288 data.logfd = logfd;
289 data.std = std;
290
291 savederrno = pthread_create(&log_thread, 0, _logthread, NULL);
292 if (savederrno) {
293 printf("Unable to start logging thread: %s\n", strerror(savederrno));
294 pthread_mutex_unlock(&log_thread_mutex);
295 return -1;
296 }
297 log_thread_init = 1;
298 }
299
300 pthread_mutex_unlock(&log_thread_mutex);
301 return 0;
302 }
303
304 int stop_logthread(void)
305 {
306 int savederrno = 0;
307 void *retval;
308
309 savederrno = pthread_mutex_lock(&log_thread_mutex);
310 if (savederrno) {
311 printf("Unable to get log_thread mutex lock\n");
312 return -1;
313 }
314
315 if (log_thread_init) {
316 pthread_cancel(log_thread);
317 pthread_join(log_thread, &retval);
318 log_thread_init = 0;
319 }
320
321 pthread_mutex_unlock(&log_thread_mutex);
322 return 0;
323 }
324
325 static void stop_logging(void)
326 {
327 stop_logthread();
328 flush_logs(log_fds[0], stdout);
329 close_logpipes(log_fds);
330 }
331
332 int start_logging(FILE *std)
333 {
334 int savederrno = 0;
335
336 savederrno = pthread_mutex_lock(&log_mutex);
337 if (savederrno) {
338 printf("Unable to get log_mutex lock\n");
339 return -1;
340 }
341
342 if (!log_init) {
343 setup_logpipes(log_fds);
344
345 if (atexit(&stop_logging) != 0) {
346 printf("Unable to register atexit handler to stop logging: %s\n",
347 strerror(errno));
348 exit(FAIL);
349 }
350
351 if (start_logthread(log_fds[0], std) < 0) {
352 exit(FAIL);
353 }
354
355 log_init = 1;
356 }
357
358 pthread_mutex_unlock(&log_mutex);
359
360 return log_fds[1];
361 }
362
363 knet_handle_t knet_handle_start(int logfds[2], uint8_t log_level)
364 {
365 knet_handle_t knet_h = knet_handle_new(1, logfds[1], log_level, 0);
366
367 if (knet_h) {
368 return knet_h;
369 } else {
370 printf("knet_handle_new failed: %s\n", strerror(errno));
371 flush_logs(logfds[0], stdout);
372 close_logpipes(logfds);
373 exit(FAIL);
374 }
375 }
376
377 int knet_handle_stop(knet_handle_t knet_h)
378 {
379 int savederrno;
380 size_t i, j;
381 knet_node_id_t host_ids[KNET_MAX_HOST];
382 uint8_t link_ids[KNET_MAX_LINK];
383 size_t host_ids_entries = 0, link_ids_entries = 0;
384 struct knet_link_status status;
385
386 savederrno = pthread_mutex_lock(&shutdown_mutex);
387 if (savederrno) {
388 printf("Unable to get shutdown mutex lock\n");
389 return -1;
390 }
391
392 if (stop_in_progress) {
393 pthread_mutex_unlock(&shutdown_mutex);
394 errno = EINVAL;
395 return -1;
396 }
397
398 stop_in_progress = 1;
399
400 pthread_mutex_unlock(&shutdown_mutex);
401
402 if (!knet_h) {
403 errno = EINVAL;
404 return -1;
405 }
406
407 if (knet_handle_setfwd(knet_h, 0) < 0) {
408 printf("knet_handle_setfwd failed: %s\n", strerror(errno));
409 return -1;
410 }
411
412 if (knet_host_get_host_list(knet_h, host_ids, &host_ids_entries) < 0) {
413 printf("knet_host_get_host_list failed: %s\n", strerror(errno));
414 return -1;
415 }
416
417 for (i = 0; i < host_ids_entries; i++) {
418 if (knet_link_get_link_list(knet_h, host_ids[i], link_ids, &link_ids_entries)) {
419 printf("knet_link_get_link_list failed: %s\n", strerror(errno));
420 return -1;
421 }
422 for (j = 0; j < link_ids_entries; j++) {
423 if (knet_link_get_status(knet_h, host_ids[i], link_ids[j], &status, sizeof(struct knet_link_status))) {
424 printf("knet_link_get_status failed: %s\n", strerror(errno));
425 return -1;
426 }
427 if (status.enabled) {
428 if (knet_link_set_enable(knet_h, host_ids[i], j, 0)) {
429 printf("knet_link_set_enable failed: %s\n", strerror(errno));
430 return -1;
431 }
432 }
433 knet_link_clear_config(knet_h, host_ids[i], j);
434 }
435 if (knet_host_remove(knet_h, host_ids[i]) < 0) {
436 printf("knet_host_remove failed: %s\n", strerror(errno));
437 return -1;
438 }
439 }
440
441 if (knet_handle_free(knet_h)) {
442 printf("knet_handle_free failed: %s\n", strerror(errno));
443 return -1;
444 }
445 return 0;
446 }
447
448 static int _make_local_sockaddr(struct sockaddr_storage *lo, uint16_t offset, int family)
449 {
450 uint32_t port;
451 char portstr[32];
452
453 /* Use the pid if we can. but makes sure its in a sensible range */
454 port = (uint32_t)getpid() + offset;
455 if (port < 1024) {
456 port += 1024;
457 }
458 if (port > 65536) {
459 port = port & 0xFFFF;
460 }
461 sprintf(portstr, "%u", port);
462 memset(lo, 0, sizeof(struct sockaddr_storage));
463 printf("Using port %u\n", port);
464
465 if (family == AF_INET6) {
466 return knet_strtoaddr("::1", portstr, lo, sizeof(struct sockaddr_storage));
467 }
468 return knet_strtoaddr("127.0.0.1", portstr, lo, sizeof(struct sockaddr_storage));
469 }
470
471 int make_local_sockaddr(struct sockaddr_storage *lo, uint16_t offset)
472 {
473 return _make_local_sockaddr(lo, offset, AF_INET);
474 }
475
476 int make_local_sockaddr6(struct sockaddr_storage *lo, uint16_t offset)
477 {
478 return _make_local_sockaddr(lo, offset, AF_INET6);
479 }
480
481 int wait_for_host(knet_handle_t knet_h, uint16_t host_id, int seconds, int logfd, FILE *std)
482 {
483 int i = 0;
484
485 if (is_memcheck() || is_helgrind()) {
486 printf("Test suite is running under valgrind, adjusting wait_for_host timeout\n");
487 seconds = seconds * 16;
488 }
489
490 while (i < seconds) {
491 flush_logs(logfd, std);
492 if (knet_h->host_index[host_id]->status.reachable == 1) {
493 return 0;
494 }
495 printf("waiting host %u to be reachable for %d more seconds\n", host_id, seconds - i);
496 sleep(1);
497 i++;
498 }
499 return -1;
500 }
501
502 int wait_for_packet(knet_handle_t knet_h, int seconds, int datafd, int logfd, FILE *std)
503 {
504 fd_set rfds;
505 struct timeval tv;
506 int err = 0, i = 0;
507
508 if (is_memcheck() || is_helgrind()) {
509 printf("Test suite is running under valgrind, adjusting wait_for_packet timeout\n");
510 seconds = seconds * 16;
511 }
512
513 try_again:
514 FD_ZERO(&rfds);
515 FD_SET(datafd, &rfds);
516
517 tv.tv_sec = 1;
518 tv.tv_usec = 0;
519
520 err = select(datafd+1, &rfds, NULL, NULL, &tv);
521 /*
522 * on slow arches the first call to select can return 0.
523 * pick an arbitrary 10 times loop (multiplied by waiting seconds)
524 * before failing.
525 */
526 if ((!err) && (i < seconds)) {
527 flush_logs(logfd, std);
528 i++;
529 goto try_again;
530 }
531 if ((err > 0) && (FD_ISSET(datafd, &rfds))) {
532 return 0;
533 }
534
535 return -1;
536 }