From e4bb5bc7c153ec1b26abae00461aaf19f5541419 Mon Sep 17 00:00:00 2001 From: Jakub Grajciar Date: Thu, 2 Nov 2017 14:33:27 +0100 Subject: [PATCH] libmemif: example app can generate ICMP, dev perf tests (using icmpr-epoll) Change-Id: Ib72ede51559754f606c0a1d57f4fb624d032caa6 Signed-off-by: Jakub Grajciar --- extras/libmemif/docs/devperftest_doc.md | 94 ++++ extras/libmemif/examples/example_setup_doc.md | 2 +- .../libmemif/examples/icmp_responder-epoll/main.c | 615 +++++++++++++++++++-- .../libmemif/examples/icmp_responder/icmp_proto.c | 105 +++- .../libmemif/examples/icmp_responder/icmp_proto.h | 3 + extras/libmemif/libmemif_doc.md | 1 + 6 files changed, 774 insertions(+), 46 deletions(-) create mode 100644 extras/libmemif/docs/devperftest_doc.md diff --git a/extras/libmemif/docs/devperftest_doc.md b/extras/libmemif/docs/devperftest_doc.md new file mode 100644 index 00000000000..45741457b6c --- /dev/null +++ b/extras/libmemif/docs/devperftest_doc.md @@ -0,0 +1,94 @@ +## Development performance test {#libmemif_devperftest_doc} + +Simle test cases using ICMP. icmpr-epoll example app generates and transmits packets over memif interface. + +#### TC1: LIB-VPP + +Start icmpr-epoll example app and VPP. + +VPP-side config: +``` +DBGvpp# create memif id 0 master +DBGvpp# set int state memif0/0 up +DBGvpp# set int ip address memif0/0 192.168.1.1/24 +``` +icmpr-epoll: +``` +conn 0 0 1 +``` +> Last argument specifies interrupt function to use. This function only respondes to ARP requests. This is important because, packet generation and transmitting is handled by a separate thread. Calling memif_tx_burst from multiple threads writing on same queue could transmit uninitialized buffers. +Once connection is established, you can send ping from VPP to icmpr-epoll app to learn its mac address. +``` +DBGvpp# ping 192.168.1.2 +``` +> There should be no ICMP response. Only ARP response. +Now send ICMP requests from icmpr-epoll: +``` +send +send 0 5 192.168.1.1 02:fe:ff:ff:ff:ff +``` +this command will create new thread which will generate icmp packets and transmit them over memif connection with specified index. Once the sequence is finished status will be printed. + +###### Example results (owerview of test data) + +(This test was run with modofication in VPP-memif plugin. The modification disallows memif tx node to allocate last ring buffer) +lib-tx: 200M (if ring full don't drop packets) +vpp-rx: 200M +vpp-tx: 200M - 50K (if ring full drop packets) +lib-rx: =vpp-tx +drop: ~0.025% (full ring) +pps: ~650K +multiple interfaces: +pps: divided +drop: constant + +#### TC2: LIB-LIB + +This test case will not drop packets if memif ring is full. Instead it will loop until all required packets have been sent. + +Start two instances of icmpr-epoll example app. +instance 1: +``` +conn 0 1 0 +``` +instance 2: +``` +conn 0 0 1 +send 0 5 192.168.1.1 aa:aa:aa:aa:aa:aa +``` +> icmpr-epoll example app doesn't check ip or mac address so as long as the format is correct you can type anything as ip_daddr and hw_daddr arguments. + +###### Example results (owerview of test data) + +lib1-tx: 200M (if ring full don't drop packets) +lib2-rx: 200M +lib2-tx: 200M (if ring full don't drop packets) +lib1-rx: 200M +drop: obsolete +pps: 4.5M +multiple interfaces: +not tested (excpected same as TC1) + +#### TC3: LIB-LIB + +Start two instances of icmpr-epoll example app. +instance 1: +``` +conn 0 1 +``` +instance 2: +``` +conn 0 0 1 +send 0 5 192.168.1.1 aa:aa:aa:aa:aa:aa +``` + +###### Example results (owerview of test data) + +lib1-tx: 200M (if ring full don't drop packets) +lib2-rx: 200M +lib2-tx: 169626182 (if ring full drop packets) +lib1-rx: =lib2-tx +drop: ~15% +pps: ~6M +multiple interfaces: +not tested (excpected same as TC1) diff --git a/extras/libmemif/examples/example_setup_doc.md b/extras/libmemif/examples/example_setup_doc.md index 89a0b10e2f8..7fc5443b5fd 100644 --- a/extras/libmemif/examples/example_setup_doc.md +++ b/extras/libmemif/examples/example_setup_doc.md @@ -187,7 +187,7 @@ Statistics: 5 sent, 4 received, 20% packet loss #### icmp_responder master icmp_responder slave -> Example apps can only repond to ping. This setup creates connection between two applications using libmemif. Traffic functionality is the same as when connection to VPP. App can receive ARP/ICMP request and transmit response, but can not send ARP/ICMP request. +> This setup creates connection between two applications using libmemif. Traffic functionality is the same as when connection to VPP. App can receive ARP/ICMP request and transmit response. Run two instances of icmpr-epoll example. > If not running in container, make sure folder /run/vpp/ exists before creating memif master. diff --git a/extras/libmemif/examples/icmp_responder-epoll/main.c b/extras/libmemif/examples/icmp_responder-epoll/main.c index cff944f94c7..80a7f7e79fc 100644 --- a/extras/libmemif/examples/icmp_responder-epoll/main.c +++ b/extras/libmemif/examples/icmp_responder-epoll/main.c @@ -43,6 +43,9 @@ #include #include #include +#include + +#include #include #include @@ -57,8 +60,16 @@ printf (__VA_ARGS__); \ printf ("\n"); \ } while (0) +#define LOG(...) do { \ + if (enable_log) { \ + dprintf (out_fd, __VA_ARGS__); \ + dprintf (out_fd, "\n"); \ + } \ + } while (0) +#define LOG_FILE "/tmp/memif_time_test.txt" #else #define DBG(...) +#define LOG(...) #endif #define INFO(...) do { \ @@ -66,11 +77,14 @@ printf ("\n"); \ } while (0) + /* maximum tx/rx memif buffers */ #define MAX_MEMIF_BUFS 256 #define MAX_CONNS 50 int epfd; +int out_fd; +uint8_t enable_log; typedef struct { @@ -89,9 +103,22 @@ typedef struct uint16_t rx_buf_num; /* interface ip address */ uint8_t ip_addr[4]; + uint16_t seq; + uint64_t tx_counter, rx_counter, tx_err_counter; + uint64_t t_sec, t_nsec; } memif_connection_t; +typedef struct +{ + uint16_t index; + uint64_t packet_num; + uint8_t ip_daddr[4]; + uint8_t hw_daddr[6]; +} icmpr_thread_data_t; + memif_connection_t memif_connection[MAX_CONNS]; +icmpr_thread_data_t icmpr_thread_data[MAX_CONNS]; +pthread_t thread[MAX_CONNS]; long ctx[MAX_CONNS]; /* print details for all memif connections */ @@ -243,6 +270,7 @@ int on_connect (memif_conn_handle_t conn, void *private_ctx) { INFO ("memif connected!"); + enable_log = 1; return 0; } @@ -277,21 +305,20 @@ control_fd_update (int fd, uint8_t events) } int -icmpr_buffer_alloc (long index, long n, uint16_t qid) +icmpr_buffer_alloc (long index, long n, uint16_t * r, uint16_t i, + uint16_t qid) { memif_connection_t *c = &memif_connection[index]; int err; - uint16_t r; /* set data pointer to shared memory and set buffer_len to shared mmeory buffer len */ - err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, n, &r, 0); - if (err != MEMIF_ERR_SUCCESS) + err = memif_buffer_alloc (c->conn, qid, c->tx_bufs + i, n, r, 0); + if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING)) { INFO ("memif_buffer_alloc: %s", memif_strerror (err)); - c->tx_buf_num += r; return -1; } - c->tx_buf_num += r; - DBG ("allocated %d/%ld buffers, %u free buffers", r, n, + c->tx_buf_num += *r; + DBG ("allocated %d/%ld buffers, %u free buffers", *r, n, MAX_MEMIF_BUFS - c->tx_buf_num); return 0; } @@ -307,8 +334,8 @@ icmpr_tx_burst (long index, uint16_t qid) err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &r); if (err != MEMIF_ERR_SUCCESS) INFO ("memif_tx_burst: %s", memif_strerror (err)); - DBG ("tx: %d/%u", r, c->tx_buf_num); c->tx_buf_num -= r; + c->tx_counter += r; return 0; } @@ -324,46 +351,267 @@ on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid) INFO ("invalid context: %ld/%u", index, c->index); return 0; } - int err; - uint16_t rx; + + int err = MEMIF_ERR_SUCCESS, ret_val; + uint16_t rx, tx; uint16_t fb; - /* receive data from shared memory buffers */ - err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); - if (err != MEMIF_ERR_SUCCESS) + int i; /* rx buffer iterator */ + int j; /* tx bufferiterator */ + + /* loop while there are packets in shm */ + do { - INFO ("memif_rx_burst: %s", memif_strerror (err)); - c->rx_buf_num += rx; - goto error; + /* receive data from shared memory buffers */ + err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); + ret_val = err; + c->rx_counter += rx; + if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF)) + { + INFO ("memif_rx_burst: %s", memif_strerror (err)); + goto error; + } + + i = 0; + + /* try to alloc required number of buffers buffers */ + err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, rx, &tx, 0); + if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING)) + { + INFO ("memif_buffer_alloc: %s", memif_strerror (err)); + goto error; + } + j = 0; + c->tx_err_counter = rx - tx; + + /* process bufers */ + while (tx) + { + while (tx > 2) + { + resolve_packet ((void *) (c->rx_bufs + i)->data, + (c->rx_bufs + i)->data_len, + (void *) (c->tx_bufs + j)->data, + &(c->tx_bufs + j)->data_len, c->ip_addr); + resolve_packet ((void *) (c->rx_bufs + i + 1)->data, + (c->rx_bufs + i + 1)->data_len, + (void *) (c->tx_bufs + j + 1)->data, + &(c->tx_bufs + j + 1)->data_len, c->ip_addr); + + i += 2; + j += 2; + tx -= 2; + } + resolve_packet ((void *) (c->rx_bufs + i)->data, + (c->rx_bufs + i)->data_len, + (void *) (c->tx_bufs + j)->data, + &(c->tx_bufs + j)->data_len, c->ip_addr); + i++; + j++; + tx--; + } + /* mark memif buffers and shared memory buffers as free */ + /* free processed buffers */ + err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb); + if (err != MEMIF_ERR_SUCCESS) + INFO ("memif_buffer_free: %s", memif_strerror (err)); + rx -= fb; + + DBG ("freed %d buffers. %u/%u alloc/free buffers", + fb, rx, MAX_MEMIF_BUFS - rx); + + /* transmit allocated buffers */ + err = memif_tx_burst (c->conn, qid, c->tx_bufs, j, &tx); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_tx_burst: %s", memif_strerror (err)); + goto error; + } + c->tx_counter += tx; + } - c->rx_buf_num += rx; + while (ret_val == MEMIF_ERR_NOBUF); + + return 0; - DBG ("received %d buffers. %u/%u alloc/free buffers", - rx, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num); +error: + err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb); + if (err != MEMIF_ERR_SUCCESS) + INFO ("memif_buffer_free: %s", memif_strerror (err)); + c->rx_buf_num -= fb; + DBG ("freed %d buffers. %u/%u alloc/free buffers", + fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num); + return 0; +} - if (icmpr_buffer_alloc (index, rx, qid) < 0) +/* called when event is polled on interrupt file descriptor. + there are packets in shared memory ready to be received */ +/* dev test modification: loop until TX == RX (don't drop buffers) */ +int +on_interrupt0 (memif_conn_handle_t conn, void *private_ctx, uint16_t qid) +{ + long index = *((long *) private_ctx); + memif_connection_t *c = &memif_connection[index]; + if (c->index != index) { - INFO ("buffer_alloc error"); - goto error; + INFO ("invalid context: %ld/%u", index, c->index); + return 0; } - int i; - for (i = 0; i < rx; i++) + + int err = MEMIF_ERR_SUCCESS, ret_val; + uint16_t rx, tx; + uint16_t fb; + int i; /* rx buffer iterator */ + int j; /* tx bufferiterator */ + int prev_i; /* first allocated rx buffer */ + + /* loop while there are packets in shm */ + do { - resolve_packet ((void *) (c->rx_bufs + i)->data, - (c->rx_bufs + i)->data_len, - (void *) (c->tx_bufs + i)->data, - &(c->tx_bufs + i)->data_len, c->ip_addr); + /* receive data from shared memory buffers */ + err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); + ret_val = err; + c->rx_counter += rx; + if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF)) + { + INFO ("memif_rx_burst: %s", memif_strerror (err)); + goto error; + } + + prev_i = i = 0; + + /* loop while there are RX buffers to be processed */ + while (rx) + { + + /* try to alloc required number of buffers buffers */ + err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, rx, &tx, 0); + if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING)) + { + INFO ("memif_buffer_alloc: %s", memif_strerror (err)); + goto error; + } + j = 0; + + /* process bufers */ + while (tx) + { + while (tx > 2) + { + resolve_packet ((void *) (c->rx_bufs + i)->data, + (c->rx_bufs + i)->data_len, + (void *) (c->tx_bufs + j)->data, + &(c->tx_bufs + j)->data_len, c->ip_addr); + resolve_packet ((void *) (c->rx_bufs + i + 1)->data, + (c->rx_bufs + i + 1)->data_len, + (void *) (c->tx_bufs + j + 1)->data, + &(c->tx_bufs + j + 1)->data_len, + c->ip_addr); + + i += 2; + j += 2; + tx -= 2; + } + resolve_packet ((void *) (c->rx_bufs + i)->data, + (c->rx_bufs + i)->data_len, + (void *) (c->tx_bufs + j)->data, + &(c->tx_bufs + j)->data_len, c->ip_addr); + i++; + j++; + tx--; + } + /* mark memif buffers and shared memory buffers as free */ + /* free processed buffers */ + err = memif_buffer_free (c->conn, qid, c->rx_bufs + prev_i, j, &fb); + if (err != MEMIF_ERR_SUCCESS) + INFO ("memif_buffer_free: %s", memif_strerror (err)); + rx -= fb; + prev_i = i; + + DBG ("freed %d buffers. %u/%u alloc/free buffers", + fb, rx, MAX_MEMIF_BUFS - rx); + + /* transmit allocated buffers */ + err = memif_tx_burst (c->conn, qid, c->tx_bufs, j, &tx); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_tx_burst: %s", memif_strerror (err)); + goto error; + } + c->tx_counter += tx; + + } + } + while (ret_val == MEMIF_ERR_NOBUF); + + return 0; - /* mark memif buffers and shared memory buffers as free */ +error: err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb); if (err != MEMIF_ERR_SUCCESS) INFO ("memif_buffer_free: %s", memif_strerror (err)); c->rx_buf_num -= fb; - DBG ("freed %d buffers. %u/%u alloc/free buffers", fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num); + return 0; +} + +/* called when event is polled on interrupt file descriptor. + there are packets in shared memory ready to be received */ +/* dev test modification: handle only ARP requests */ +int +on_interrupt1 (memif_conn_handle_t conn, void *private_ctx, uint16_t qid) +{ + long index = *((long *) private_ctx); + memif_connection_t *c = &memif_connection[index]; + if (c->index != index) + { + INFO ("invalid context: %ld/%u", index, c->index); + return 0; + } + + int err = MEMIF_ERR_SUCCESS, ret_val; + int i; + uint16_t rx, tx; + uint16_t fb; + uint16_t pck_seq; + + do + { + /* receive data from shared memory buffers */ + err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); + ret_val = err; + if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF)) + { + INFO ("memif_rx_burst: %s", memif_strerror (err)); + goto error; + } + c->rx_buf_num += rx; + c->rx_counter += rx; + + for (i = 0; i < rx; i++) + { + if (((struct ether_header *) (c->rx_bufs + i)->data)->ether_type == + 0x0608) + { + if (icmpr_buffer_alloc (c->index, 1, &tx, i, qid) < 0) + break; + resolve_packet ((void *) (c->rx_bufs + i)->data, + (c->rx_bufs + i)->data_len, + (void *) (c->tx_bufs + i)->data, + &(c->tx_bufs + i)->data_len, c->ip_addr); + icmpr_tx_burst (c->index, qid); + } + } - icmpr_tx_burst (index, qid); + err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb); + if (err != MEMIF_ERR_SUCCESS) + INFO ("memif_buffer_free: %s", memif_strerror (err)); + c->rx_buf_num -= fb; + + + } + while (ret_val == MEMIF_ERR_NOBUF); return 0; @@ -378,7 +626,7 @@ error: } int -icmpr_memif_create (long index, long mode) +icmpr_memif_create (long index, long mode, char *s) { if (index >= MAX_CONNS) { @@ -397,7 +645,7 @@ icmpr_memif_create (long index, long mode) int fd = -1; memset (&args, 0, sizeof (args)); args.is_master = mode; - args.log2_ring_size = 10; + args.log2_ring_size = 11; args.buffer_size = 2048; args.num_s2m_rings = 2; args.num_m2s_rings = 2; @@ -411,13 +659,48 @@ icmpr_memif_create (long index, long mode) args.interface_id = index; /* last argument for memif_create (void * private_ctx) is used by user to identify connection. this context is returned with callbacks */ - int err = memif_create (&c->conn, + int err; + /* default interrupt */ + if (s == NULL) + { + err = memif_create (&c->conn, &args, on_connect, on_disconnect, on_interrupt, &ctx[index]); - if (err != MEMIF_ERR_SUCCESS) + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_create: %s", memif_strerror (err)); + return 0; + } + } + else { - INFO ("memif_create: %s", memif_strerror (err)); - return 0; + if (strncmp (s, "0", 1) == 0) + { + err = memif_create (&c->conn, + &args, on_connect, on_disconnect, on_interrupt0, + &ctx[index]); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_create: %s", memif_strerror (err)); + return 0; + } + } + else if (strncmp (s, "1", 1) == 0) + { + err = memif_create (&c->conn, + &args, on_connect, on_disconnect, on_interrupt1, + &ctx[index]); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_create: %s", memif_strerror (err)); + return 0; + } + } + else + { + INFO ("Unknown interrupt descriptor"); + goto done; + } } c->index = index; @@ -433,6 +716,10 @@ icmpr_memif_create (long index, long mode) c->ip_addr[1] = 168; c->ip_addr[2] = c->index + 1; c->ip_addr[3] = 2; + + c->seq = c->tx_err_counter = c->tx_counter = c->rx_counter = 0; + +done: return 0; } @@ -489,12 +776,15 @@ print_help () printf ("\thelp - prints this help\n"); printf ("\texit - exit app\n"); printf - ("\tconn - create memif. index is also used as interface id, mode 0 = slave 1 = master\n"); + ("\tconn [] - create memif. index is also used as interface id, mode 0 = slave 1 = master, interrupt-desc none = default 0 = if ring is full wait 1 = handle only ARP requests\n"); printf ("\tdel - delete memif\n"); printf ("\tshow - show connection details\n"); printf ("\tip-set - set interface ip address\n"); printf ("\trx-mode - set queue rx mode\n"); + printf ("\tsh-count - print counters\n"); + printf ("\tcl-count - clear counters\n"); + printf ("\tsend - send icmp\n"); } int @@ -503,6 +793,9 @@ icmpr_free () /* application cleanup */ int err; long i; + if (out_fd > 0) + close (out_fd); + out_fd = -1; for (i = 0; i < MAX_CONNS; i++) { memif_connection_t *c = &memif_connection[i]; @@ -610,6 +903,209 @@ icmpr_set_rx_mode (long index, long qid, char *mode) return 0; } +void +icmpr_print_counters () +{ + int i; + for (i = 0; i < MAX_CONNS; i++) + { + memif_connection_t *c = &memif_connection[i]; + if (c->conn == NULL) + continue; + printf ("===============================\n"); + printf ("interface index: %d\n", c->index); + printf ("\trx: %lu\n", c->rx_counter); + printf ("\ttx: %lu\n", c->tx_counter); + printf ("\ttx_err: %lu\n", c->tx_err_counter); + printf ("\tts: %lus %luns\n", c->t_sec, c->t_nsec); + } +} + +void +icmpr_reset_counters () +{ + int i; + for (i = 0; i < MAX_CONNS; i++) + { + memif_connection_t *c = &memif_connection[i]; + if (c->conn == NULL) + continue; + c->t_sec = c->t_nsec = c->tx_err_counter = c->tx_counter = + c->rx_counter = 0; + } +} + +void * +icmpr_send_proc (void *data) +{ + icmpr_thread_data_t *d = (icmpr_thread_data_t *) data; + int index = d->index; + uint64_t count = d->packet_num; + memif_connection_t *c = &memif_connection[index]; + if (c->conn == NULL) + { + INFO ("No connection at index %d. Thread exiting...\n", index); + pthread_exit (NULL); + } + uint16_t tx, i; + int err = MEMIF_ERR_SUCCESS; + uint32_t seq = 0; + struct timespec start, end; + memset (&start, 0, sizeof (start)); + memset (&end, 0, sizeof (end)); + + timespec_get (&start, TIME_UTC); + while (count) + { + i = 0; + err = memif_buffer_alloc (c->conn, 0, c->tx_bufs, + MAX_MEMIF_BUFS > + count ? count : MAX_MEMIF_BUFS, &tx, 0); + if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING)) + { + INFO ("memif_buffer_alloc: %s Thread exiting...\n", + memif_strerror (err)); + pthread_exit (NULL); + } + c->tx_buf_num += tx; + + while (tx) + { + while (tx > 2) + { + generate_packet ((void *) c->tx_bufs[i].data, + &c->tx_bufs[i].data_len, c->ip_addr, + d->ip_daddr, d->hw_daddr, seq++); + generate_packet ((void *) c->tx_bufs[i + 1].data, + &c->tx_bufs[i + 1].data_len, c->ip_addr, + d->ip_daddr, d->hw_daddr, seq++); + i += 2; + tx -= 2; + } + generate_packet ((void *) c->tx_bufs[i].data, + &c->tx_bufs[i].data_len, c->ip_addr, + d->ip_daddr, d->hw_daddr, seq++); + i++; + tx--; + } + err = memif_tx_burst (c->conn, 0, c->tx_bufs, c->tx_buf_num, &tx); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_tx_burst: %s Thread exiting...\n", + memif_strerror (err)); + pthread_exit (NULL); + } + c->tx_buf_num -= tx; + c->tx_counter += tx; + count -= tx; + } + timespec_get (&end, TIME_UTC); + INFO ("Pakcet sequence finished!"); + INFO ("Seq len: %u", seq); + uint64_t t1 = end.tv_sec - start.tv_sec; + uint64_t t2; + if (end.tv_nsec > start.tv_nsec) + { + t2 = end.tv_nsec - start.tv_nsec; + } + else + { + t2 = start.tv_nsec - end.tv_nsec; + t1--; + } + c->t_sec = t1; + c->t_nsec = t2; + INFO ("Seq time: %lus %luns", t1, t2); + double tmp = t1; + tmp += t2 / 1e+9; + tmp = seq / tmp; + INFO ("Average pps: %f", tmp); + INFO ("Thread exiting..."); + pthread_exit (NULL); +} + +int +icmpr_send (long index, long packet_num, char *hw, char *ip) +{ + memif_connection_t *c = &memif_connection[index]; + char *end; + char *ui; + uint8_t tmp[6]; + if (c->conn == NULL) + return -1; + c->seq = 0; + icmpr_thread_data_t *data = &icmpr_thread_data[index]; + data->index = index; + data->packet_num = packet_num; + INFO ("PN: %lu", data->packet_num); + printf ("%s\n", ip); + printf ("%s\n", hw); + + ui = strtok (ip, "."); + if (ui == NULL) + goto error; + tmp[0] = strtol (ui, &end, 10); + + ui = strtok (NULL, "."); + if (ui == NULL) + goto error; + tmp[1] = strtol (ui, &end, 10); + + ui = strtok (NULL, "."); + if (ui == NULL) + goto error; + tmp[2] = strtol (ui, &end, 10); + + ui = strtok (NULL, "."); + if (ui == NULL) + goto error; + tmp[3] = strtol (ui, &end, 10); + + data->ip_daddr[0] = tmp[0]; + data->ip_daddr[1] = tmp[1]; + data->ip_daddr[2] = tmp[2]; + data->ip_daddr[3] = tmp[3]; + + ui = strtok (hw, ":"); + if (ui == NULL) + goto error; + tmp[0] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + goto error; + tmp[1] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + goto error; + tmp[2] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + goto error; + tmp[3] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + goto error; + tmp[4] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + goto error; + tmp[5] = strtol (ui, &end, 16); + + data->hw_daddr[0] = tmp[0]; + data->hw_daddr[1] = tmp[1]; + data->hw_daddr[2] = tmp[2]; + data->hw_daddr[3] = tmp[3]; + data->hw_daddr[4] = tmp[4]; + data->hw_daddr[5] = tmp[5]; + + pthread_create (&thread[index], NULL, icmpr_send_proc, (void *) data); + return 0; + +error: + INFO ("Invalid input\n"); + return 0; +} + int user_input_handler () { @@ -644,7 +1140,7 @@ user_input_handler () } ui = strtok (NULL, " "); if (ui != NULL) - icmpr_memif_create (a, strtol (ui, &end, 10)); + icmpr_memif_create (a, strtol (ui, &end, 10), strtok (NULL, " ")); else INFO ("expected mode <0|1>"); goto done; @@ -689,6 +1185,32 @@ user_input_handler () INFO ("expected qid"); goto done; } + else if (strncmp (ui, "sh-count", 8) == 0) + { + icmpr_print_counters (); + } + else if (strncmp (ui, "cl-count", 8) == 0) + { + icmpr_reset_counters (); + } + else if (strncmp (ui, "send", 4) == 0) + { + ui = strtok (NULL, " "); + if (ui != NULL) + a = strtol (ui, &end, 10); + else + { + INFO ("expected id"); + goto done; + } + ui = strtok (NULL, " "); + if (ui != NULL) + icmpr_send (a, strtol (ui, &end, 10), strtok (NULL, " "), + strtok (NULL, " ")); + else + INFO ("expected count"); + goto done; + } else { DBG ("unknown command: %s", ui); @@ -708,11 +1230,14 @@ poll_event (int timeout) int app_err = 0, memif_err = 0, en = 0; int tmp, nfd; uint32_t events = 0; + struct timespec start, end; memset (&evt, 0, sizeof (evt)); evt.events = EPOLLIN | EPOLLOUT; sigset_t sigset; sigemptyset (&sigset); en = epoll_pwait (epfd, &evt, 1, timeout, &sigset); + /* id event polled */ + timespec_get (&start, TIME_UTC); if (en < 0) { DBG ("epoll_pwait: %s", strerror (errno)); @@ -745,6 +1270,9 @@ poll_event (int timeout) } } + timespec_get (&end, TIME_UTC); + LOG ("interrupt: %ld", end.tv_nsec - start.tv_nsec); + if ((app_err < 0) || (memif_err < 0)) { if (app_err < 0) @@ -763,6 +1291,15 @@ main () epfd = epoll_create (1); add_epoll_fd (0, EPOLLIN); +#ifdef LOG_FILE + remove (LOG_FILE); + enable_log = 0; + + out_fd = open (LOG_FILE, O_WRONLY | O_CREAT, S_IRWXO); + if (out_fd < 0) + INFO ("Error opening log file: %s", strerror (errno)); +#endif /* LOG_FILE */ + /* initialize memory interface */ int err, i; /* if valid callback is passed as argument, fd event polling will be done by user diff --git a/extras/libmemif/examples/icmp_responder/icmp_proto.c b/extras/libmemif/examples/icmp_responder/icmp_proto.c index a923f209126..b27abb6a231 100644 --- a/extras/libmemif/examples/icmp_responder/icmp_proto.c +++ b/extras/libmemif/examples/icmp_responder/icmp_proto.c @@ -137,8 +137,9 @@ resolve_eth_arp (struct ether_arp *eth_arp, void *eth_arp_resp, memcpy (resp->arp_sha, (((struct ether_header *) (eth_arp_resp - - sizeof (struct ether_header)))-> - ether_shost), 6); + sizeof (struct + ether_header)))->ether_shost), + 6); memcpy (resp->arp_spa, ip_addr, 4); @@ -172,7 +173,7 @@ resolve_ip (struct iphdr *ip, void *ip_resp, uint8_t ip_addr[4]) resp->version = 4; resp->tos = 0; /*len updated later */ - resp->tot_len = 0x5400; + resp->tot_len = 0x0000; resp->id = 0; resp->frag_off = 0; resp->ttl = 0x40; @@ -183,7 +184,7 @@ resolve_ip (struct iphdr *ip, void *ip_resp, uint8_t ip_addr[4]) ((uint8_t *) & resp->saddr)[3] = ip_addr[3]; resp->daddr = ip->saddr; - resp->check = cksum (resp, sizeof (struct iphdr)); + /* resp->check = cksum (resp, sizeof (struct iphdr)); */ return sizeof (struct iphdr); } @@ -192,7 +193,7 @@ static ssize_t resolve_icmp (struct icmphdr *icmp, void *icmp_resp) { struct icmphdr *resp = (struct icmphdr *) icmp_resp; - resp->type = ICMP_ECHOREPLY; + resp->type = 0x00; resp->code = 0; resp->un.echo.id = icmp->un.echo.id; resp->un.echo.sequence = icmp->un.echo.sequence; @@ -208,10 +209,13 @@ resolve_packet (void *in_pck, ssize_t in_size, { struct ether_header *eh; struct ether_arp *eah; - struct iphdr *ip; + struct iphdr *ip, *ip_out; struct icmphdr *icmp; *out_size = 0; + if ((in_pck == NULL) || (out_pck == NULL)) + return -1; + eh = (struct ether_header *) in_pck; *out_size = resolve_eth (eh, out_pck); @@ -227,6 +231,7 @@ resolve_packet (void *in_pck, ssize_t in_size, print_packet (in_pck + *out_size); #endif ip = (struct iphdr *) (in_pck + *out_size); + ip_out = (struct iphdr *) (out_pck + *out_size); *out_size += resolve_ip (ip, out_pck + *out_size, ip_addr); if (ip->protocol == 1) { @@ -240,7 +245,95 @@ resolve_packet (void *in_pck, ssize_t in_size, memcpy (out_pck + *out_size, in_pck + *out_size, in_size - *out_size); *out_size = in_size; + ip_out->tot_len = + __bswap_16 (*out_size - sizeof (struct ether_header)); + ip_out->check = cksum (ip_out, sizeof (struct iphdr)); } } return 0; } + +static ssize_t +generate_eth (struct ether_header *eh, uint8_t hw_daddr[6]) +{ + uint8_t hw_addr[6]; + int i; + for (i = 0; i < 6; i++) + { + hw_addr[i] = 'a'; + } + memcpy (eh->ether_shost, hw_addr, 6); + memcpy (eh->ether_dhost, hw_daddr, 6); + + eh->ether_type = 0x0008; + + return sizeof (struct ether_header); +} + +static ssize_t +generate_ip (struct iphdr *ip, uint8_t saddr[4], uint8_t daddr[4]) +{ + ip->ihl = 5; + ip->version = 4; + ip->tos = 0; + /*len updated later */ + ip->tot_len = 0x5400; + ip->id = 0; + ip->frag_off = 0; + ip->ttl = 0x40; + ip->protocol = 1; + /* saddr */ + ((uint8_t *) & ip->saddr)[0] = saddr[0]; + ((uint8_t *) & ip->saddr)[1] = saddr[1]; + ((uint8_t *) & ip->saddr)[2] = saddr[2]; + ((uint8_t *) & ip->saddr)[3] = saddr[3]; + /* daddr */ + ((uint8_t *) & ip->daddr)[0] = daddr[0]; + ((uint8_t *) & ip->daddr)[1] = daddr[1]; + ((uint8_t *) & ip->daddr)[2] = daddr[2]; + ((uint8_t *) & ip->daddr)[3] = daddr[3]; + + ip->check = cksum (ip, sizeof (struct iphdr)); + + return sizeof (struct iphdr); +} + +static ssize_t +generate_icmp (struct icmphdr *icmp, uint32_t seq) +{ + icmp->type = ICMP_ECHO; + icmp->code = 0; + icmp->un.echo.id = 0; + icmp->un.echo.sequence = seq; + + return sizeof (struct icmphdr); +} + +int +generate_packet (void *pck, uint32_t * size, uint8_t saddr[4], + uint8_t daddr[4], uint8_t hw_daddr[6], uint32_t seq) +{ + struct ether_header *eh; + struct iphdr *ip; + struct icmphdr *icmp; + + *size = 0; + + eh = (struct ether_header *) pck; + *size += generate_eth (eh, hw_daddr); + + ip = (struct iphdr *) (pck + *size); + *size += generate_ip (ip, saddr, daddr); + + icmp = (struct icmphdr *) (pck + *size); + *size += generate_icmp (icmp, seq); + + ((struct icmphdr *) (pck + *size - sizeof (struct icmphdr)))->checksum = + cksum (pck + *size - sizeof (struct icmphdr), sizeof (struct icmphdr)); + + ip->tot_len = __bswap_16 (*size - sizeof (struct ether_header)); + ip->check = 0; + ip->check = cksum (ip, sizeof (struct iphdr)); + + return 0; +} diff --git a/extras/libmemif/examples/icmp_responder/icmp_proto.h b/extras/libmemif/examples/icmp_responder/icmp_proto.h index f2f22ac4629..ca72b2fe026 100644 --- a/extras/libmemif/examples/icmp_responder/icmp_proto.h +++ b/extras/libmemif/examples/icmp_responder/icmp_proto.h @@ -21,6 +21,9 @@ int resolve_packet (void *in_pck, ssize_t in_size, void *out_pck, uint32_t * out_size, uint8_t ip_addr[4]); +int generate_packet (void *pck, uint32_t * size, uint8_t saddr[4], + uint8_t daddr[4], uint8_t hw_daddr[6], uint32_t seq); + int print_packet (void *pck); #endif /* _ICMP_PROTO_H_ */ diff --git a/extras/libmemif/libmemif_doc.md b/extras/libmemif/libmemif_doc.md index fb4a18aff1b..0ecaea0378e 100644 --- a/extras/libmemif/libmemif_doc.md +++ b/extras/libmemif/libmemif_doc.md @@ -72,3 +72,4 @@ Continue with @ref libmemif_example_setup which contains instructions on how to - @subpage libmemif_examples_doc - @subpage libmemif_example_setup_doc - @subpage libmemif_gettingstarted_doc +- @subpage libmemif_devperftest_doc -- 2.16.6