Basic VPP pingpong example

Test results:
- VPP 39us RTT
- sockperf kernel 42us RTT
master
Vitaliy Filippov 2021-10-23 23:29:26 +03:00
commit 22e71c2c12
2 changed files with 321 additions and 0 deletions

2
Makefile Normal file
View File

@ -0,0 +1,2 @@
all: pingpong.c
gcc -g -O3 -o vpp-pingpong pingpong.c -lvppcom

319
pingpong.c Normal file
View File

@ -0,0 +1,319 @@
#include <stdio.h>
#include <time.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <assert.h>
#include <signal.h>
#include <vcl/vppcom.h>
#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;
}