From 22e71c2c1237edae438709aa5ab48c0b23788968 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Sat, 23 Oct 2021 23:29:26 +0300 Subject: [PATCH] Basic VPP pingpong example Test results: - VPP 39us RTT - sockperf kernel 42us RTT --- Makefile | 2 + pingpong.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 321 insertions(+) create mode 100644 Makefile create mode 100644 pingpong.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..64a63f0 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +all: pingpong.c + gcc -g -O3 -o vpp-pingpong pingpong.c -lvppcom diff --git a/pingpong.c b/pingpong.c new file mode 100644 index 0000000..7be1eff --- /dev/null +++ b/pingpong.c @@ -0,0 +1,319 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAX_EVENTS 512 + +struct epoll_event ev; +struct epoll_event events[MAX_EVENTS]; + +static int message_size = 4096; +static char *buf = NULL; + +static int epfd = -1; +static int sockfd = -1; +static int is_client = 0; + +/* Echo server */ +int loop(void *arg) +{ + /* Wait for events to happen */ + int nevents = vppcom_epoll_wait(epfd, events, MAX_EVENTS, 0); + if (nevents < 0) + { + return 0; + } + + int i; + + for (i = 0; i < nevents; ++i) + { + /* Handle new connection */ + if (events[i].data.fd == sockfd) + { + while (1) + { + int nclientfd = vppcom_session_accept(sockfd, NULL, 0); + if (nclientfd < 0) + { + break; + } + /* Add to event list */ + ev.data.fd = nclientfd; + ev.events = EPOLLIN; + int rv = vppcom_epoll_ctl(epfd, EPOLL_CTL_ADD, nclientfd, &ev); + if (rv) + { + printf("vppcom_epoll_ctl failed: %d\n", rv); + break; + } + } + } + else + { + if (events[i].events & (EPOLLERR|EPOLLHUP)) + { + /* Simply close socket */ + vppcom_epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL); + vppcom_session_close(events[i].data.fd); + } + else if (events[i].events & EPOLLIN) + { + size_t readlen = vppcom_session_read(events[i].data.fd, buf, message_size); + if (readlen > 0) + vppcom_session_write(events[i].data.fd, buf, readlen); + else + { + vppcom_epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL); + vppcom_session_close(events[i].data.fd); + } + } + else + { + printf("unknown event: %8.8X\n", events[i].events); + } + } + } + + return 0; +} + +static uint64_t sum_us = 0, count_us = 0; +static int to_write = 0; +static int to_read = 0; +static int connected = 0; +static struct timespec connect_time; +static struct timespec start, end; + +void sigint_handler(int signum) +{ + if (sockfd >= 0) + { + vppcom_session_close(sockfd); + sockfd = 0; + } + if (is_client) + { + struct timespec stop_time; + clock_gettime(CLOCK_REALTIME, &stop_time); + double duration_sec = ((stop_time.tv_nsec - connect_time.tv_nsec)/1000000000.0 + 1.0*(stop_time.tv_sec - connect_time.tv_sec)); + uint64_t mps = count_us/duration_sec; + printf( + "%lu messages in %.2f seconds (%lu messages per second), %lu us avg ping-pong\n", count_us, + duration_sec, mps, sum_us/(count_us == 0 ? 1 : count_us) + ); + } + exit(0); +} + +int loop_client(void *arg) +{ + ssize_t len = 0; + int nevents = vppcom_epoll_wait(epfd, events, MAX_EVENTS, 0); + int i; + for (i = 0; i < nevents; ++i) + { + if (events[i].events & (EPOLLHUP|EPOLLERR)) + { + /* Simply close socket */ + vppcom_epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL); + vppcom_session_close(events[i].data.fd); + sigint_handler(SIGINT); + exit(0); + } + else if (events[i].events & EPOLLIN) + { + /* Read everything back */ + if (to_read > 0) + { + len = vppcom_session_read(events[i].data.fd, buf, message_size); + if (len > 0) + to_read = to_read > len ? to_read-len : 0; + if (to_read == 0) + { + /* Calculate latency */ + clock_gettime(CLOCK_REALTIME, &end); + sum_us += (end.tv_nsec - start.tv_nsec)/1000 + (end.tv_sec - start.tv_sec)*1000000; + count_us++; + /* Send next request */ + start = end; + memset(buf, 0xab, message_size); + to_write = message_size; + len = vppcom_session_write(events[i].data.fd, buf, to_write); + if (len > 0) + to_write -= len; + if (to_write == 0) + to_read = message_size; + } + } + } + else if (events[i].events & EPOLLOUT) + { + /* Connected or buffer available */ + if (!connected) + { + connected = 1; + printf("Connected, starting ping-pong, press Ctrl-C to interrupt\n"); + clock_gettime(CLOCK_REALTIME, &connect_time); + start = connect_time; + memset(buf, 0xab, message_size); + to_write = message_size; + } + if (to_write > 0) + { + len = vppcom_session_write(events[i].data.fd, buf, to_write); + if (len > 0) + to_write -= len; + if (to_write == 0) + to_read = message_size; + } + } + else + { + printf("unknown event: %8.8X\n", events[i].events); + } + } + return 0; +} + +int main(int argc, char *argv[]) +{ + char *server = NULL; + char **f_argv = malloc(sizeof(char*) * (argc+1)); + int f_argidx = 1; + int rv; + f_argv[0] = argv[0]; + for (int i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "--size")) + { + if (i < argc-1) + message_size = atoi(argv[++i]); + if (message_size < 4) + { + printf("invalid argument for --size\n"); + exit(1); + } + } + else if (argv[i][0] == '-') + { + f_argv[f_argidx++] = argv[i++]; + f_argv[f_argidx++] = argv[i]; + } + else + { + server = argv[i]; + break; + } + } + f_argv[f_argidx] = NULL; + + buf = malloc(message_size); + if (!buf) + { + printf("failed to allocate buffer\n"); + exit(1); + } + + rv = vppcom_app_create("pingpong"); + if (rv) + { + printf("vppcom_app_create() failed: %d\n", rv); + exit(1); + } + + sockfd = vppcom_session_create(VPPCOM_PROTO_TCP, 1/* is_nonblocking */); + if (sockfd < 0) + { + printf("vppcom_session_create failed: %d\n", sockfd); + exit(1); + } + + if (server) + { + printf("Client mode, message size %d, connecting to %s port 7777\n", message_size, server); + is_client = 1; + + struct sockaddr_in my_addr; + bzero(&my_addr, sizeof(my_addr)); + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons(7777); + my_addr.sin_addr.s_addr = inet_addr(server); + + vppcom_endpt_t endpt; + endpt.is_ip4 = 1; + endpt.ip = (uint8_t *)&my_addr.sin_addr; + endpt.port = (uint16_t)my_addr.sin_port; + + rv = vppcom_session_connect(sockfd, &endpt); + if (rv < 0 && rv != VPPCOM_EINPROGRESS) + { + printf("vppcom_session_connect failed: %d\n", rv); + exit(1); + } + } + else + { + printf("Server mode, listening on port 7777 and echoing everything back\n"); + + struct sockaddr_in my_addr; + bzero(&my_addr, sizeof(my_addr)); + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons(7777); + my_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + vppcom_endpt_t endpt; + endpt.is_ip4 = 1; + endpt.ip = (uint8_t *)&my_addr.sin_addr; + endpt.port = (uint16_t)my_addr.sin_port; + + rv = vppcom_session_bind(sockfd, &endpt); + if (rv < 0) + { + printf("vppcom_session_bind() failed: %d", rv); + exit(1); + } + + rv = vppcom_session_listen(sockfd, MAX_EVENTS); + if (rv < 0) + { + printf("vppcom_session_listen() failed: %d", rv); + exit(1); + } + } + + assert((epfd = vppcom_epoll_create()) > 0); + ev.data.fd = sockfd; + ev.events = (server ? EPOLLOUT : 0) | EPOLLIN|EPOLLHUP; + rv = vppcom_epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); + if (rv < 0) + { + printf("vppcom_epoll_ctl() failed: %d", rv); + exit(1); + } + signal(SIGINT, sigint_handler); + + if (server) + while (1) + loop_client(NULL); + else + while (1) + loop(NULL); + + vppcom_app_destroy(); + + return 0; +}