laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/upf-benchmark/+/38329?usp=email )

Change subject: Introduce osmo-udp-simpleflood
......................................................................

Introduce osmo-udp-simpleflood

Related: SYS#7096
Change-Id: I389c75054f769b7ca93a56f7085b1694e999aa04
---
M configure.ac
M src/Makefile.am
A src/osmo-udp-simpleflood/Makefile.am
A src/osmo-udp-simpleflood/README.md
A src/osmo-udp-simpleflood/osmo_udp_simpleflood_rx.c
A src/osmo-udp-simpleflood/osmo_udp_simpleflood_tx.c
6 files changed, 381 insertions(+), 0 deletions(-)

Approvals:
  laforge: Looks good to me, approved; Verified




diff --git a/configure.ac b/configure.ac
index ec92355..61a8d35 100644
--- a/configure.ac
+++ b/configure.ac
@@ -165,6 +165,7 @@
     src/Makefile
     src/osmo-pfcp-tool/Makefile
     src/osmo-udp-responder/Makefile
+    src/osmo-udp-simpleflood/Makefile
     doc/Makefile
     doc/manuals/Makefile
     Makefile)
diff --git a/src/Makefile.am b/src/Makefile.am
index 731fc5e..0005c41 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,5 @@
 SUBDIRS = \
        osmo-pfcp-tool \
        osmo-udp-responder \
+       osmo-udp-simpleflood \
        $(NULL)
diff --git a/src/osmo-udp-simpleflood/Makefile.am 
b/src/osmo-udp-simpleflood/Makefile.am
new file mode 100644
index 0000000..540b047
--- /dev/null
+++ b/src/osmo-udp-simpleflood/Makefile.am
@@ -0,0 +1,30 @@
+AM_CPPFLAGS = \
+       $(all_includes) \
+       -I$(top_srcdir)/include \
+       -I$(top_builddir)/include \
+       -I$(top_builddir) \
+       $(NULL)
+
+AM_CFLAGS = \
+       -Wall \
+       $(LIBOSMOCORE_CFLAGS) \
+       $(LIBURING_CFLAGS) \
+       $(NULL)
+
+AM_LDFLAGS = \
+       $(LIBOSMOCORE_LIBS) \
+       $(LIBURING_LIBS) \
+       $(NULL)
+
+bin_PROGRAMS = \
+       osmo-udp-simpleflood-rx \
+       osmo-udp-simpleflood-tx \
+       $(NULL)
+
+osmo_udp_simpleflood_rx_SOURCES = \
+       osmo_udp_simpleflood_rx.c \
+       $(NULL)
+
+osmo_udp_simpleflood_tx_SOURCES = \
+       osmo_udp_simpleflood_tx.c \
+       $(NULL)
diff --git a/src/osmo-udp-simpleflood/README.md 
b/src/osmo-udp-simpleflood/README.md
new file mode 100644
index 0000000..81c60aa
--- /dev/null
+++ b/src/osmo-udp-simpleflood/README.md
@@ -0,0 +1,5 @@
+Simple pair of programs to transmit and receive UDP packets over a single UDP
+stream using a single CPU.
+
+These programs are kept simple on purpose, to be able to test simplest scenario
+and to be used as a skeleton for new tools.
\ No newline at end of file
diff --git a/src/osmo-udp-simpleflood/osmo_udp_simpleflood_rx.c 
b/src/osmo-udp-simpleflood/osmo_udp_simpleflood_rx.c
new file mode 100644
index 0000000..6f7be44
--- /dev/null
+++ b/src/osmo-udp-simpleflood/osmo_udp_simpleflood_rx.c
@@ -0,0 +1,184 @@
+#include <liburing.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/sockaddr_str.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/timer_compat.h>
+
+#define RECV_SLOTS 32000
+#define BUF_SIZE 1460
+
+static struct io_uring ring = {};
+static unsigned long long num_packets_received;
+static unsigned long long last_num_packets_received;
+static unsigned long long num_bytes_received;
+static bool started;
+static struct timespec ts_start;
+
+static int rx_fd;
+
+struct recv_slot {
+       struct iovec iov;
+       uint8_t buf[BUF_SIZE];
+       struct msghdr msgh;
+};
+
+static struct recv_slot recv_slots[RECV_SLOTS];
+
+static void prepare_rx(struct recv_slot *s)
+{
+       s->iov.iov_base = s->buf;
+       s->iov.iov_len = sizeof(s->buf);
+
+       s->msgh = (struct msghdr){
+               .msg_iov = &s->iov,
+               .msg_iovlen = 1,
+       };
+}
+
+static void submit_rx(struct recv_slot *s)
+{
+       struct io_uring_sqe *sqe;
+
+       sqe = io_uring_get_sqe(&ring);
+       OSMO_ASSERT(sqe);
+       io_uring_prep_recvmsg(sqe, rx_fd, &s->msgh, 0);
+       io_uring_sqe_set_data(sqe, s);
+}
+
+void handle_completion(struct io_uring_cqe *cqe)
+{
+       struct recv_slot *s;
+       s = io_uring_cqe_get_data(cqe);
+
+       if (OSMO_UNLIKELY(!started)) {
+               started = true;
+               OSMO_ASSERT(clock_gettime(CLOCK_MONOTONIC, &ts_start) == 0);
+       }
+
+       if (cqe->res <= 0) {
+               printf("rc = %d\n", cqe->res);
+               return;
+       }
+
+       num_bytes_received += cqe->res;
+       num_packets_received++;
+       io_uring_cqe_seen(&ring, cqe);
+
+       /* submit more */
+       submit_rx(s);
+}
+
+static void log_rx_force(struct timespec *ts_now)
+{
+       struct timespec ts_elapsed;
+       timespecsub(ts_now, &ts_start, &ts_elapsed);
+       unsigned long long elapsed_usec = (ts_elapsed.tv_sec * 1000 * 1000) + 
(ts_elapsed.tv_nsec / 1000);
+       if (elapsed_usec == 0)
+               elapsed_usec = 1;
+       unsigned long long kpkts_per_sec = num_packets_received * 1000 / 
elapsed_usec;
+       unsigned long long mbps = num_bytes_received * 8 / elapsed_usec;
+       printf("%16llu RX: %8llu packets %16llu bytes %16llu kPPS %16llu 
Mbps\n",
+               elapsed_usec, num_packets_received, num_bytes_received, 
kpkts_per_sec, mbps);
+       fflush(stdout);
+}
+
+static void log_rx(void)
+{
+       static struct timespec last_info_log = {.tv_sec = 0, .tv_nsec = 0};
+       struct timespec ts_now;
+       clock_gettime(CLOCK_MONOTONIC, &ts_now);
+       if (OSMO_UNLIKELY(ts_now.tv_sec != last_info_log.tv_sec)) {
+               last_info_log = ts_now;
+               log_rx_force(&ts_now);
+       }
+}
+
+int main(int argc, const char **argv)
+{
+       int i;
+       int rc;
+       const char *local_addr_str = "0.0.0.0";
+       uint16_t local_port = 23000;
+
+       struct osmo_sockaddr_str local_addr = {};
+       struct osmo_sockaddr local_osa = {};
+
+       struct __kernel_timespec ts_zero = {};
+       struct __kernel_timespec ts_1s = { .tv_sec = 1 };
+
+       if (argc >= 2)
+               local_addr_str = argv[1];
+       if (argc >= 3)
+               local_port = atoi(argv[2]);
+
+       if (osmo_sockaddr_str_from_str(&local_addr, local_addr_str, local_port)
+           || osmo_sockaddr_str_to_osa(&local_addr, &local_osa)) {
+               printf("ERROR: invalid address or port number: %s:%d\n", 
local_addr_str, local_port);
+               return -1;
+       }
+
+       /* create and bind socket */
+       rc = osmo_sock_init_osa(SOCK_DGRAM, IPPROTO_UDP, &local_osa, NULL, 
OSMO_SOCK_F_BIND);
+       if (rc < 0)
+               return -1;
+       rx_fd = rc;
+       printf("bound UDP %s fd=%d\n", osmo_sock_get_name2(rx_fd), rx_fd);
+
+       rc = io_uring_queue_init(ARRAY_SIZE(recv_slots), &ring, 0);
+
+       /* Prepare */
+       for (i = 0; i < ARRAY_SIZE(recv_slots); i++)
+               prepare_rx(&recv_slots[i]);
+
+       /* fill up tx queue */
+       for (i = 0; i < ARRAY_SIZE(recv_slots); i++)
+               submit_rx(&recv_slots[i]);
+
+
+       while (1) {
+               uint32_t new_submissions;
+               uint32_t new_completions = 0;
+               struct io_uring_cqe *cqe;
+
+               /* submit any requests from previous loop */
+               new_submissions = io_uring_submit(&ring);
+
+               /* process all pending completions */
+               while (io_uring_wait_cqe_timeout(&ring, &cqe, &ts_zero) == 0) {
+                       handle_completion(cqe);
+                       new_completions++;
+               }
+
+               /* Nothing happened in this loop iteration, so wait a bit 
longer */
+               if (!new_submissions && !new_completions) {
+                       if (io_uring_wait_cqe_timeout(&ring, &cqe, &ts_1s) == 
0) {
+                               handle_completion(cqe);
+                               new_completions++;
+                       }
+               }
+
+
+               if (OSMO_UNLIKELY(!started))
+                       continue;
+
+               if (OSMO_UNLIKELY(last_num_packets_received == 
num_packets_received)) {
+#if 0
+                       printf("FINISHED!\n");
+                       struct timespec ts_now;
+                       clock_gettime(CLOCK_MONOTONIC, &ts_now);
+                       log_rx_force(&ts_now);
+                       started = false;
+                       last_num_packets_received = 0;
+#endif
+                       continue;
+               }
+
+               last_num_packets_received = num_packets_received;
+               log_rx();
+       }
+
+       printf("done\n");
+       return 0;
+}
diff --git a/src/osmo-udp-simpleflood/osmo_udp_simpleflood_tx.c 
b/src/osmo-udp-simpleflood/osmo_udp_simpleflood_tx.c
new file mode 100644
index 0000000..be1c9f6
--- /dev/null
+++ b/src/osmo-udp-simpleflood/osmo_udp_simpleflood_tx.c
@@ -0,0 +1,160 @@
+#include <stdio.h>
+#include <limits.h>
+#include <liburing.h>
+#include <netinet/in.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/sockaddr_str.h>
+
+#define SEND_SLOTS 32000
+#define BUF_SIZE 1452
+
+static struct io_uring ring = {};
+static unsigned long long num_packets = ULLONG_MAX;
+static unsigned long long num_packets_completed = 0;
+
+static int src_fd;
+static struct osmo_sockaddr remote_osa;
+
+struct send_slot {
+       struct iovec iov;
+       uint8_t buf[BUF_SIZE];
+       struct msghdr msgh;
+};
+
+struct send_slot send_slots[SEND_SLOTS];
+
+static void prepare_tx(struct send_slot *s)
+{
+       s->iov.iov_base = s->buf;
+       s->iov.iov_len = sizeof(s->buf);
+
+       s->msgh = (struct msghdr){
+               .msg_name = &remote_osa,
+               .msg_namelen = sizeof(remote_osa),
+               .msg_iov = &s->iov,
+               .msg_iovlen = 1,
+       };
+}
+
+static void submit_tx(struct send_slot *s)
+{
+       struct io_uring_sqe *sqe;
+
+       sqe = io_uring_get_sqe(&ring);
+       OSMO_ASSERT(sqe);
+       io_uring_prep_sendmsg(sqe, src_fd, &s->msgh, 0);
+       io_uring_sqe_set_data(sqe, s);
+}
+
+static void handle_completion(struct io_uring_cqe *cqe)
+{
+       struct send_slot *s;
+       s = io_uring_cqe_get_data(cqe);
+
+       if (cqe->res < 0) {
+               printf("rc = %d\n", cqe->res);
+               return;
+       }
+
+       io_uring_cqe_seen(&ring, cqe);
+       num_packets_completed++;
+
+       /* submit more */
+       submit_tx(s);
+}
+
+int main(int argc, const char **argv)
+{
+       int i;
+       int rc;
+       const char *local_addr_str = "0.0.0.0";
+       uint16_t local_port = 42000;
+       const char *remote_addr_str = "127.0.0.2";
+       uint16_t remote_port = 23000;
+
+       struct osmo_sockaddr_str local_addr = {};
+       struct osmo_sockaddr local_osa = {};
+
+       struct osmo_sockaddr_str remote_addr = {};
+
+       struct __kernel_timespec ts_zero = {};
+       struct __kernel_timespec ts_1s = { .tv_sec = 1 };
+
+       if (argc >= 2)
+               remote_addr_str = argv[1];
+       if (argc >= 3)
+               remote_port = atoi(argv[2]);
+       if (argc >= 4)
+               local_port = atoi(argv[3]);
+       if (argc >= 5)
+               num_packets = atoi(argv[4]);
+
+       if (osmo_sockaddr_str_from_str(&local_addr, local_addr_str, local_port)
+           || osmo_sockaddr_str_to_osa(&local_addr, &local_osa)) {
+               printf("ERROR: invalid address or port number: %s:%d\n", 
local_addr_str, local_port);
+               return -1;
+       }
+
+       if (osmo_sockaddr_str_from_str(&remote_addr, remote_addr_str, 
remote_port)
+           || osmo_sockaddr_str_to_osa(&remote_addr, &remote_osa)) {
+               printf("ERROR: invalid address or port number: %s:%d\n", 
remote_addr_str, remote_port);
+               return -1;
+       }
+
+       /* create and bind socket */
+       rc = osmo_sock_init_osa(SOCK_DGRAM, IPPROTO_UDP, &local_osa, NULL, 
OSMO_SOCK_F_BIND);
+       if (rc < 0)
+               return -1;
+       src_fd = rc;
+       printf("bound UDP %s fd=%d\n", osmo_sock_get_name2(src_fd), src_fd);
+
+       /* Set Don't Fragment (DF) bit on IP packets transmitted by socket: */
+       int val = IP_PMTUDISC_DO;
+       rc = setsockopt(src_fd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val));
+       if (rc == -1) {
+               fprintf(stderr, "ERROR: setsockopt(IPPROTO_IP, IP_DONTFRAG) 
failed errno=%d\n", errno);
+               return -1;
+       }
+
+       printf("sending %llu UDP packets to %s\n", num_packets, 
osmo_sockaddr_to_str(&remote_osa));
+
+       rc = io_uring_queue_init(ARRAY_SIZE(send_slots), &ring, 0);
+       if (rc < 0) {
+               fprintf(stderr, "ERROR: io_uring_queue_init errno=%d\n", -rc);
+               return -1;
+       }
+
+       /* Prepare */
+       for (i = 0; i < ARRAY_SIZE(send_slots); i++)
+               prepare_tx(&send_slots[i]);
+       /* fill up tx queue */
+       for (i = 0; i < ARRAY_SIZE(send_slots); i++)
+               submit_tx(&send_slots[i]);
+
+       while (num_packets_completed < num_packets) {
+               uint32_t new_submissions;
+               uint32_t new_completions = 0;
+               struct io_uring_cqe *cqe;
+
+               /* submit any requests from previous loop */
+               new_submissions = io_uring_submit(&ring);
+
+               /* process all pending completions */
+               while (io_uring_wait_cqe_timeout(&ring, &cqe, &ts_zero) == 0) {
+                       handle_completion(cqe);
+                       new_completions++;
+
+               }
+
+               /* Nothing happened in this loop iteration, so wait a bit 
longer */
+               if (!new_submissions && !new_completions) {
+                       if (io_uring_wait_cqe_timeout(&ring, &cqe, &ts_1s) == 0)
+                               handle_completion(cqe);
+               }
+       }
+
+       printf("done\n");
+       return 0;
+}

--
To view, visit https://gerrit.osmocom.org/c/upf-benchmark/+/38329?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: upf-benchmark
Gerrit-Branch: master
Gerrit-Change-Id: I389c75054f769b7ca93a56f7085b1694e999aa04
Gerrit-Change-Number: 38329
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: neels <[email protected]>

Reply via email to