mirror of
https://git.proxmox.com/git/mirror_kronosnet
synced 2026-01-10 06:26:09 +00:00
Logic is to try to configure a link with port X and if it fails, try the next port. This avoids port collisions between services and knet test suite. Please note that the implementation in test-common.c is NOT super clean. There is still some redundant code in there that is left on purpose. There is another branch, not yet merged, that implements functional testing framework that does heavy use of those functions. We will clean test-common.c as we port the functional testing branch and make it ready for merging. For now, this is good enough to have a more stable test suite. Signed-off-by: Fabio M. Di Nitto <fdinitto@redhat.com>
437 lines
12 KiB
C
437 lines
12 KiB
C
/*
|
|
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
|
|
*
|
|
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
|
|
*
|
|
* This software licensed under GPL-2.0+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "libknet.h"
|
|
|
|
#include "internals.h"
|
|
#include "netutils.h"
|
|
#include "test-common.h"
|
|
|
|
static int private_data;
|
|
|
|
static void sock_notify(void *pvt_data,
|
|
int datafd,
|
|
int8_t channel,
|
|
uint8_t tx_rx,
|
|
int error,
|
|
int errorno)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static int dhost_filter(void *pvt_data,
|
|
const unsigned char *outdata,
|
|
ssize_t outdata_len,
|
|
uint8_t tx_rx,
|
|
knet_node_id_t this_host_id,
|
|
knet_node_id_t src_host_id,
|
|
int8_t *dst_channel,
|
|
knet_node_id_t *dst_host_ids,
|
|
size_t *dst_host_ids_entries)
|
|
{
|
|
dst_host_ids[0] = 1;
|
|
*dst_host_ids_entries = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void test(void)
|
|
{
|
|
knet_handle_t knet_h;
|
|
int logfds[2];
|
|
int datafd = 0;
|
|
int8_t channel = 0;
|
|
struct knet_link_status link_status;
|
|
char send_buff[KNET_MAX_PACKET_SIZE];
|
|
char recv_buff[KNET_MAX_PACKET_SIZE];
|
|
ssize_t send_len = 0;
|
|
int recv_len = 0;
|
|
int savederrno;
|
|
struct sockaddr_storage lo;
|
|
|
|
memset(send_buff, 0, sizeof(send_buff));
|
|
|
|
setup_logpipes(logfds);
|
|
|
|
knet_h = knet_handle_start(logfds, KNET_LOG_DEBUG);
|
|
|
|
flush_logs(logfds[0], stdout);
|
|
|
|
printf("Test configuring multiple links with loopback\n");
|
|
|
|
if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) {
|
|
printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno));
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
datafd = 0;
|
|
channel = -1;
|
|
|
|
if (knet_handle_add_datafd(knet_h, &datafd, &channel) < 0) {
|
|
printf("knet_handle_add_datafd failed: %s\n", strerror(errno));
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (knet_host_add(knet_h, 1) < 0) {
|
|
printf("knet_host_add failed: %s\n", strerror(errno));
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (_knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_LOOPBACK, 0, AF_INET, 0, &lo) < 0) {
|
|
printf("Unable to configure link: %s\n", strerror(errno));
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (_knet_link_set_config(knet_h, 1, 1, KNET_TRANSPORT_LOOPBACK, 0, AF_INET, 0, &lo) == 0) {
|
|
printf("Managed to configure two LOOPBACK links - this is wrong\n");
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
flush_logs(logfds[0], stdout);
|
|
printf("Test configuring UDP link after loopback\n");
|
|
|
|
if (_knet_link_set_config(knet_h, 1, 1, KNET_TRANSPORT_UDP, 0, AF_INET, 0, &lo) == 0) {
|
|
printf("Managed to configure UDP and LOOPBACK links together: %s\n", strerror(errno));
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
flush_logs(logfds[0], stdout);
|
|
printf("Test configuring UDP link before loopback\n");
|
|
|
|
if (knet_link_clear_config(knet_h, 1, 0) < 0) {
|
|
printf("Failed to clear existing LOOPBACK link: %s\n", strerror(errno));
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (_knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_UDP, 0, AF_INET, 0, &lo) < 0) {
|
|
printf("Failed to configure UDP link for testing: %s\n", strerror(errno));
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (_knet_link_set_config(knet_h, 1, 1, KNET_TRANSPORT_LOOPBACK, 0, AF_INET, 0, &lo) == 0) {
|
|
printf("Managed to configure LOOPBACK link after UDP: %s\n", strerror(errno));
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
flush_logs(logfds[0], stdout);
|
|
printf("Test knet_send with valid data\n");
|
|
|
|
if (knet_handle_enable_access_lists(knet_h, 1) < 0) {
|
|
printf("knet_handle_enable_access_lists failed: %s\n", strerror(errno));
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (knet_link_clear_config(knet_h, 1, 0) < 0) {
|
|
printf("Failed to clear existing UDP link: %s\n", strerror(errno));
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (_knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_LOOPBACK, 0, AF_INET, 0, &lo) < 0) {
|
|
printf("Failed configure LOOPBACK link for sending: %s\n", strerror(errno));
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (knet_link_set_enable(knet_h, 1, 0, 1) < 0) {
|
|
printf("knet_link_set_enable failed: %s\n", strerror(errno));
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (knet_handle_setfwd(knet_h, 1) < 0) {
|
|
printf("knet_handle_setfwd failed: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (wait_for_host(knet_h, 1, 10, logfds[0], stdout) < 0) {
|
|
printf("timeout waiting for host to be reachable");
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
send_len = knet_send(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel);
|
|
if (send_len <= 0) {
|
|
printf("knet_send failed: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (send_len != sizeof(send_buff)) {
|
|
printf("knet_send sent only %zd bytes: %s\n", send_len, strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
flush_logs(logfds[0], stdout);
|
|
|
|
if (knet_handle_setfwd(knet_h, 0) < 0) {
|
|
printf("knet_handle_setfwd failed: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (wait_for_packet(knet_h, 10, datafd, logfds[0], stdout)) {
|
|
printf("Error waiting for packet: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
recv_len = knet_recv(knet_h, recv_buff, KNET_MAX_PACKET_SIZE, channel);
|
|
savederrno = errno;
|
|
if (recv_len != send_len) {
|
|
printf("knet_recv received only %d bytes: %s (errno: %d)\n", recv_len, strerror(errno), errno);
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
if ((is_helgrind()) && (recv_len == -1) && (savederrno == EAGAIN)) {
|
|
printf("helgrind exception. this is normal due to possible timeouts\n");
|
|
exit(PASS);
|
|
}
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (memcmp(recv_buff, send_buff, KNET_MAX_PACKET_SIZE)) {
|
|
printf("recv and send buffers are different!\n");
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
/* A sanity check on the stats */
|
|
if (knet_link_get_status(knet_h, 1, 0, &link_status, sizeof(link_status)) < 0) {
|
|
printf("knet_link_get_status failed: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (link_status.stats.tx_data_packets != 1 ||
|
|
link_status.stats.rx_data_packets != 0 ||
|
|
link_status.stats.tx_data_bytes != KNET_MAX_PACKET_SIZE) {
|
|
printf("stats look wrong: tx_packets: %" PRIu64 " (%" PRIu64 " bytes), rx_packets: %" PRIu64 " (%" PRIu64 " bytes)\n",
|
|
link_status.stats.tx_data_packets,
|
|
link_status.stats.tx_data_bytes,
|
|
link_status.stats.rx_data_packets,
|
|
link_status.stats.rx_data_bytes);
|
|
}
|
|
|
|
flush_logs(logfds[0], stdout);
|
|
|
|
|
|
printf("Test knet_send with only localhost\n");
|
|
|
|
if (knet_handle_setfwd(knet_h, 1) < 0) {
|
|
printf("knet_handle_setfwd failed: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (knet_handle_enable_filter(knet_h, NULL, dhost_filter) < 0) {
|
|
printf("knet_handle_enable_filter failed: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
send_len = knet_send(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel);
|
|
if (send_len <= 0) {
|
|
printf("knet_send failed: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (send_len != sizeof(send_buff)) {
|
|
printf("knet_send sent only %zd bytes: %s\n", send_len, strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
flush_logs(logfds[0], stdout);
|
|
|
|
if (knet_handle_setfwd(knet_h, 0) < 0) {
|
|
printf("knet_handle_setfwd failed: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (wait_for_packet(knet_h, 10, datafd, logfds[0], stdout)) {
|
|
printf("Error waiting for packet: %s\n", strerror(errno));
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
recv_len = knet_recv(knet_h, recv_buff, KNET_MAX_PACKET_SIZE, channel);
|
|
savederrno = errno;
|
|
if (recv_len != send_len) {
|
|
printf("knet_recv received only %d bytes: %s (errno: %d)\n", recv_len, strerror(errno), errno);
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
if ((is_helgrind()) && (recv_len == -1) && (savederrno == EAGAIN)) {
|
|
printf("helgrind exception. this is normal due to possible timeouts\n");
|
|
exit(PASS);
|
|
}
|
|
exit(FAIL);
|
|
}
|
|
|
|
if (memcmp(recv_buff, send_buff, KNET_MAX_PACKET_SIZE)) {
|
|
printf("recv and send buffers are different!\n");
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
exit(FAIL);
|
|
}
|
|
|
|
knet_link_set_enable(knet_h, 1, 0, 0);
|
|
knet_link_clear_config(knet_h, 1, 0);
|
|
knet_host_remove(knet_h, 1);
|
|
knet_handle_free(knet_h);
|
|
flush_logs(logfds[0], stdout);
|
|
close_logpipes(logfds);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
test();
|
|
|
|
return PASS;
|
|
}
|