Build libmemif as part of verify job
[vpp.git] / extras / libmemif / examples / icmp_responder-epoll / main.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <net/if.h>
21 #include <sys/types.h>
22 #include <fcntl.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <sys/uio.h>
27 #include <sys/mman.h>
28 #include <sys/prctl.h>
29 #include <inttypes.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <netdb.h>
33 #include <linux/ip.h>
34 #include <linux/icmp.h>
35 #include <arpa/inet.h>
36 #include <stdlib.h>
37 #include <netinet/if_ether.h>
38 #include <net/if_arp.h>
39 #include <asm/byteorder.h>
40 #include <byteswap.h>
41 #include <string.h>
42 #include <sys/epoll.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <signal.h>
46 #include <pthread.h>
47
48 #include <time.h>
49
50 #ifndef TIME_UTC
51 #define TIME_UTC 1
52 #endif
53
54 #include <libmemif.h>
55 #include <icmp_proto.h>
56
57 #define APP_NAME "ICMP_Responder"
58 #define IF_NAME  "memif_connection"
59
60
61 #ifdef ICMP_DBG
62 #define DBG(...) do {                                               \
63                     printf (APP_NAME":%s:%d: ", __func__, __LINE__);         \
64                     printf (__VA_ARGS__);                           \
65                     printf ("\n");                                  \
66                 } while (0)
67 #define LOG(...) do {                                               \
68                     if (enable_log) {                               \
69                         dprintf (out_fd, __VA_ARGS__);              \
70                         dprintf (out_fd, "\n");                     \
71                     }                                               \
72                 } while (0)
73 #define LOG_FILE "/tmp/memif_time_test.txt"
74 #else
75 #define DBG(...)
76 #define LOG(...)
77 #endif
78
79 #define INFO(...) do {                                              \
80                     printf ("INFO: "__VA_ARGS__);                   \
81                     printf ("\n");                                  \
82                 } while (0)
83
84
85 /* maximum tx/rx memif buffers */
86 #define MAX_MEMIF_BUFS  256
87 #define MAX_CONNS       50
88
89 int epfd;
90 int out_fd;
91 uint8_t enable_log;
92
93 typedef struct
94 {
95   uint16_t index;
96   /* memif conenction handle */
97   memif_conn_handle_t conn;
98   /* tx buffers */
99   memif_buffer_t *tx_bufs;
100   /* allocated tx buffers counter */
101   /* number of tx buffers pointing to shared memory */
102   uint16_t tx_buf_num;
103   /* rx buffers */
104   memif_buffer_t *rx_bufs;
105   /* allcoated rx buffers counter */
106   /* number of rx buffers pointing to shared memory */
107   uint16_t rx_buf_num;
108   /* interface ip address */
109   uint8_t ip_addr[4];
110   uint16_t seq;
111   uint64_t tx_counter, rx_counter, tx_err_counter;
112   uint64_t t_sec, t_nsec;
113 } memif_connection_t;
114
115 typedef struct
116 {
117   uint16_t index;
118   uint64_t packet_num;
119   uint8_t ip_daddr[4];
120   uint8_t hw_daddr[6];
121 } icmpr_thread_data_t;
122
123 memif_connection_t memif_connection[MAX_CONNS];
124 icmpr_thread_data_t icmpr_thread_data[MAX_CONNS];
125 pthread_t thread[MAX_CONNS];
126 long ctx[MAX_CONNS];
127
128 /* print details for all memif connections */
129 static void
130 print_memif_details ()
131 {
132   memif_details_t md;
133   ssize_t buflen;
134   char *buf;
135   int err, i, e;
136   buflen = 2048;
137   buf = malloc (buflen);
138   printf ("MEMIF DETAILS\n");
139   printf ("==============================\n");
140   for (i = 0; i < MAX_CONNS; i++)
141     {
142       memif_connection_t *c = &memif_connection[i];
143
144       memset (&md, 0, sizeof (md));
145       memset (buf, 0, buflen);
146
147       err = memif_get_details (c->conn, &md, buf, buflen);
148       if (err != MEMIF_ERR_SUCCESS)
149         {
150           if (err != MEMIF_ERR_NOCONN)
151             INFO ("%s", memif_strerror (err));
152           continue;
153         }
154
155       printf ("interface index: %d\n", i);
156
157       printf ("\tinterface ip: %u.%u.%u.%u\n",
158               c->ip_addr[0], c->ip_addr[1], c->ip_addr[2], c->ip_addr[3]);
159       printf ("\tinterface name: %s\n", (char *) md.if_name);
160       printf ("\tapp name: %s\n", (char *) md.inst_name);
161       printf ("\tremote interface name: %s\n", (char *) md.remote_if_name);
162       printf ("\tremote app name: %s\n", (char *) md.remote_inst_name);
163       printf ("\tid: %u\n", md.id);
164       printf ("\tsecret: %s\n", (char *) md.secret);
165       printf ("\trole: ");
166       if (md.role)
167         printf ("slave\n");
168       else
169         printf ("master\n");
170       printf ("\tmode: ");
171       switch (md.mode)
172         {
173         case 0:
174           printf ("ethernet\n");
175           break;
176         case 1:
177           printf ("ip\n");
178           break;
179         case 2:
180           printf ("punt/inject\n");
181           break;
182         default:
183           printf ("unknown\n");
184           break;
185         }
186       printf ("\tsocket filename: %s\n", (char *) md.socket_filename);
187       printf ("\trx queues:\n");
188       for (e = 0; e < md.rx_queues_num; e++)
189         {
190           printf ("\t\tqueue id: %u\n", md.rx_queues[e].qid);
191           printf ("\t\tring size: %u\n", md.rx_queues[e].ring_size);
192           printf ("\t\tring rx mode: %s\n",
193                   md.rx_queues[e].flags ? "polling" : "interrupt");
194           printf ("\t\tring head: %u\n", md.rx_queues[e].head);
195           printf ("\t\tring tail: %u\n", md.rx_queues[e].tail);
196           printf ("\t\tbuffer size: %u\n", md.rx_queues[e].buffer_size);
197         }
198       printf ("\ttx queues:\n");
199       for (e = 0; e < md.tx_queues_num; e++)
200         {
201           printf ("\t\tqueue id: %u\n", md.tx_queues[e].qid);
202           printf ("\t\tring size: %u\n", md.tx_queues[e].ring_size);
203           printf ("\t\tring rx mode: %s\n",
204                   md.tx_queues[e].flags ? "polling" : "interrupt");
205           printf ("\t\tring head: %u\n", md.tx_queues[e].head);
206           printf ("\t\tring tail: %u\n", md.tx_queues[e].tail);
207           printf ("\t\tbuffer size: %u\n", md.tx_queues[e].buffer_size);
208         }
209       printf ("\tlink: ");
210       if (md.link_up_down)
211         printf ("up\n");
212       else
213         printf ("down\n");
214     }
215   free (buf);
216 }
217
218 int
219 add_epoll_fd (int fd, uint32_t events)
220 {
221   if (fd < 0)
222     {
223       DBG ("invalid fd %d", fd);
224       return -1;
225     }
226   struct epoll_event evt;
227   memset (&evt, 0, sizeof (evt));
228   evt.events = events;
229   evt.data.fd = fd;
230   if (epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &evt) < 0)
231     {
232       DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
233       return -1;
234     }
235   DBG ("fd %d added to epoll", fd);
236   return 0;
237 }
238
239 int
240 mod_epoll_fd (int fd, uint32_t events)
241 {
242   if (fd < 0)
243     {
244       DBG ("invalid fd %d", fd);
245       return -1;
246     }
247   struct epoll_event evt;
248   memset (&evt, 0, sizeof (evt));
249   evt.events = events;
250   evt.data.fd = fd;
251   if (epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &evt) < 0)
252     {
253       DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
254       return -1;
255     }
256   DBG ("fd %d moddified on epoll", fd);
257   return 0;
258 }
259
260 int
261 del_epoll_fd (int fd)
262 {
263   if (fd < 0)
264     {
265       DBG ("invalid fd %d", fd);
266       return -1;
267     }
268   struct epoll_event evt;
269   memset (&evt, 0, sizeof (evt));
270   if (epoll_ctl (epfd, EPOLL_CTL_DEL, fd, &evt) < 0)
271     {
272       DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
273       return -1;
274     }
275   DBG ("fd %d removed from epoll", fd);
276   return 0;
277 }
278
279 /* informs user about connected status. private_ctx is used by user to identify connection
280     (multiple connections WIP) */
281 int
282 on_connect (memif_conn_handle_t conn, void *private_ctx)
283 {
284   INFO ("memif connected!");
285   enable_log = 1;
286   return 0;
287 }
288
289 /* informs user about disconnected status. private_ctx is used by user to identify connection
290     (multiple connections WIP) */
291 int
292 on_disconnect (memif_conn_handle_t conn, void *private_ctx)
293 {
294   INFO ("memif disconnected!");
295   return 0;
296 }
297
298 /* user needs to watch new fd or stop watching fd that is about to be closed.
299     control fd will be modified during connection establishment to minimize CPU usage */
300 int
301 control_fd_update (int fd, uint8_t events)
302 {
303   /* convert memif event definitions to epoll events */
304   if (events & MEMIF_FD_EVENT_DEL)
305     return del_epoll_fd (fd);
306
307   uint32_t evt = 0;
308   if (events & MEMIF_FD_EVENT_READ)
309     evt |= EPOLLIN;
310   if (events & MEMIF_FD_EVENT_WRITE)
311     evt |= EPOLLOUT;
312
313   if (events & MEMIF_FD_EVENT_MOD)
314     return mod_epoll_fd (fd, evt);
315
316   return add_epoll_fd (fd, evt);
317 }
318
319 int
320 icmpr_buffer_alloc (long index, long n, uint16_t * r, uint16_t i,
321                     uint16_t qid)
322 {
323   memif_connection_t *c = &memif_connection[index];
324   int err;
325   /* set data pointer to shared memory and set buffer_len to shared mmeory buffer len */
326   err = memif_buffer_alloc (c->conn, qid, c->tx_bufs + i, n, r, 128);
327   if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING))
328     {
329       INFO ("memif_buffer_alloc: %s", memif_strerror (err));
330       return -1;
331     }
332   c->tx_buf_num += *r;
333   DBG ("allocated %d/%ld buffers, %u free buffers", *r, n,
334        MAX_MEMIF_BUFS - c->tx_buf_num);
335   return 0;
336 }
337
338 int
339 icmpr_tx_burst (long index, uint16_t qid)
340 {
341   memif_connection_t *c = &memif_connection[index];
342   int err;
343   uint16_t r;
344   /* inform peer memif interface about data in shared memory buffers */
345   /* mark memif buffers as free */
346   err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &r);
347   if (err != MEMIF_ERR_SUCCESS)
348     INFO ("memif_tx_burst: %s", memif_strerror (err));
349   c->tx_buf_num -= r;
350   c->tx_counter += r;
351   return 0;
352 }
353
354 /* called when event is polled on interrupt file descriptor.
355     there are packets in shared memory ready to be received */
356 int
357 on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
358 {
359   long index = *((long *) private_ctx);
360   memif_connection_t *c = &memif_connection[index];
361   if (c->index != index)
362     {
363       INFO ("invalid context: %ld/%u", index, c->index);
364       return 0;
365     }
366
367   int err = MEMIF_ERR_SUCCESS, ret_val;
368   uint16_t rx = 0, tx = 0;
369   uint16_t fb = 0;
370   int i = 0;                    /* rx buffer iterator */
371   int j = 0;                    /* tx bufferiterator */
372
373   /* loop while there are packets in shm */
374   do
375     {
376       /* receive data from shared memory buffers */
377       err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx);
378       ret_val = err;
379       c->rx_counter += rx;
380       if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF))
381         {
382           INFO ("memif_rx_burst: %s", memif_strerror (err));
383           goto error;
384         }
385
386       i = 0;
387       err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, rx, &tx, 128);
388       if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING))
389         {
390           INFO ("memif_buffer_alloc: %s", memif_strerror (err));
391           goto error;
392         }
393       j = 0;
394       c->tx_err_counter += rx - tx;
395
396       while (tx)
397         {
398           resolve_packet ((void *) (c->rx_bufs + i)->data,
399                           (c->rx_bufs + i)->len,
400                           (void *) (c->tx_bufs + j)->data,
401                           &(c->tx_bufs + j)->len, c->ip_addr);
402           i++;
403           j++;
404           tx--;
405         }
406
407       err = memif_refill_queue (c->conn, qid, rx);
408       if (err != MEMIF_ERR_SUCCESS)
409         INFO ("memif_buffer_free: %s", memif_strerror (err));
410       rx -= rx;
411
412       DBG ("freed %d buffers. %u/%u alloc/free buffers",
413            rx, rx, MAX_MEMIF_BUFS - rx);
414
415       err = memif_tx_burst (c->conn, qid, c->tx_bufs, j, &tx);
416       if (err != MEMIF_ERR_SUCCESS)
417         {
418           INFO ("memif_tx_burst: %s", memif_strerror (err));
419           goto error;
420         }
421       c->tx_counter += tx;
422
423     }
424   while (ret_val == MEMIF_ERR_NOBUF);
425
426   return 0;
427
428 error:
429   err = memif_refill_queue (c->conn, qid, rx);
430   if (err != MEMIF_ERR_SUCCESS)
431     INFO ("memif_buffer_free: %s", memif_strerror (err));
432   c->rx_buf_num -= rx;
433   DBG ("freed %d buffers. %u/%u alloc/free buffers",
434        fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
435   return 0;
436 }
437
438 /* called when event is polled on interrupt file descriptor.
439     there are packets in shared memory ready to be received */
440 /* dev test modification: loop until TX == RX (don't drop buffers) */
441 int
442 on_interrupt0 (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
443 {
444   long index = *((long *) private_ctx);
445   memif_connection_t *c = &memif_connection[index];
446   if (c->index != index)
447     {
448       INFO ("invalid context: %ld/%u", index, c->index);
449       return 0;
450     }
451
452   int err = MEMIF_ERR_SUCCESS, ret_val;
453   uint16_t rx = 0, tx = 0;
454   uint16_t fb;
455   int i;                        /* rx buffer iterator */
456   int j;                        /* tx bufferiterator */
457   int prev_i;                   /* first allocated rx buffer */
458
459   /* loop while there are packets in shm */
460   do
461     {
462       /* receive data from shared memory buffers */
463       err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx);
464       ret_val = err;
465       c->rx_counter += rx;
466       if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF))
467         {
468           INFO ("memif_rx_burst: %s", memif_strerror (err));
469           goto error;
470         }
471
472       prev_i = i = 0;
473
474       /* loop while there are RX buffers to be processed */
475       while (rx)
476         {
477
478           /* try to alloc required number of buffers buffers */
479           err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, rx, &tx, 128);
480           if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING))
481             {
482               INFO ("memif_buffer_alloc: %s", memif_strerror (err));
483               goto error;
484             }
485           j = 0;
486
487           /* process bufers */
488           while (tx)
489             {
490               while (tx > 2)
491                 {
492                   resolve_packet ((void *) (c->rx_bufs + i)->data,
493                                   (c->rx_bufs + i)->len,
494                                   (void *) (c->tx_bufs + j)->data,
495                                   &(c->tx_bufs + j)->len, c->ip_addr);
496                   resolve_packet ((void *) (c->rx_bufs + i + 1)->data,
497                                   (c->rx_bufs + i + 1)->len,
498                                   (void *) (c->tx_bufs + j + 1)->data,
499                                   &(c->tx_bufs + j + 1)->len, c->ip_addr);
500
501                   i += 2;
502                   j += 2;
503                   tx -= 2;
504                 }
505               resolve_packet ((void *) (c->rx_bufs + i)->data,
506                               (c->rx_bufs + i)->len,
507                               (void *) (c->tx_bufs + j)->data,
508                               &(c->tx_bufs + j)->len, c->ip_addr);
509               i++;
510               j++;
511               tx--;
512             }
513           /* mark memif buffers and shared memory buffers as free */
514           /* free processed buffers */
515           err = memif_refill_queue (c->conn, qid, j);
516           if (err != MEMIF_ERR_SUCCESS)
517             INFO ("memif_buffer_free: %s", memif_strerror (err));
518           rx -= j;
519           prev_i = i;
520
521           DBG ("freed %d buffers. %u/%u alloc/free buffers",
522                fb, rx, MAX_MEMIF_BUFS - rx);
523
524           /* transmit allocated buffers */
525           err = memif_tx_burst (c->conn, qid, c->tx_bufs, j, &tx);
526           if (err != MEMIF_ERR_SUCCESS)
527             {
528               INFO ("memif_tx_burst: %s", memif_strerror (err));
529               goto error;
530             }
531           c->tx_counter += tx;
532
533         }
534
535     }
536   while (ret_val == MEMIF_ERR_NOBUF);
537
538   return 0;
539
540 error:
541   err = memif_refill_queue (c->conn, qid, rx);
542   if (err != MEMIF_ERR_SUCCESS)
543     INFO ("memif_buffer_free: %s", memif_strerror (err));
544   c->rx_buf_num -= rx;
545   DBG ("freed %d buffers. %u/%u alloc/free buffers",
546        fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
547   return 0;
548 }
549
550 /* called when event is polled on interrupt file descriptor.
551     there are packets in shared memory ready to be received */
552 /* dev test modification: handle only ARP requests */
553 int
554 on_interrupt1 (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
555 {
556   long index = *((long *) private_ctx);
557   memif_connection_t *c = &memif_connection[index];
558   if (c->index != index)
559     {
560       INFO ("invalid context: %ld/%u", index, c->index);
561       return 0;
562     }
563
564   int err = MEMIF_ERR_SUCCESS, ret_val;
565   int i;
566   uint16_t rx, tx;
567   uint16_t fb;
568   uint16_t pck_seq;
569
570   do
571     {
572       /* receive data from shared memory buffers */
573       err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx);
574       ret_val = err;
575       if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF))
576         {
577           INFO ("memif_rx_burst: %s", memif_strerror (err));
578           goto error;
579         }
580       c->rx_buf_num += rx;
581       c->rx_counter += rx;
582
583       for (i = 0; i < rx; i++)
584         {
585           if (((struct ether_header *) (c->rx_bufs + i)->data)->ether_type ==
586               0x0608)
587             {
588               if (icmpr_buffer_alloc (c->index, 1, &tx, i, qid) < 0)
589                 break;
590               resolve_packet ((void *) (c->rx_bufs + i)->data,
591                               (c->rx_bufs + i)->len,
592                               (void *) (c->tx_bufs + i)->data,
593                               &(c->tx_bufs + i)->len, c->ip_addr);
594               icmpr_tx_burst (c->index, qid);
595             }
596         }
597
598       err = memif_refill_queue (c->conn, qid, rx);
599       if (err != MEMIF_ERR_SUCCESS)
600         INFO ("memif_buffer_free: %s", memif_strerror (err));
601       c->rx_buf_num -= rx;
602
603
604     }
605   while (ret_val == MEMIF_ERR_NOBUF);
606
607   return 0;
608
609 error:
610   err = memif_refill_queue (c->conn, qid, rx);
611   if (err != MEMIF_ERR_SUCCESS)
612     INFO ("memif_buffer_free: %s", memif_strerror (err));
613   c->rx_buf_num -= rx;
614   DBG ("freed %d buffers. %u/%u alloc/free buffers",
615        fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
616   return 0;
617 }
618
619 int
620 icmpr_memif_create (long index, long mode, char *s)
621 {
622   if (index >= MAX_CONNS)
623     {
624       INFO ("connection array overflow");
625       return 0;
626     }
627   if (index < 0)
628     {
629       INFO ("don't even try...");
630       return 0;
631     }
632   memif_connection_t *c = &memif_connection[index];
633
634   /* setting memif connection arguments */
635   memif_conn_args_t args;
636   int fd = -1;
637   memset (&args, 0, sizeof (args));
638   args.is_master = mode;
639   args.log2_ring_size = 11;
640   args.buffer_size = 2048;
641   args.num_s2m_rings = 1;
642   args.num_m2s_rings = 1;
643   strncpy ((char *) args.interface_name, IF_NAME, strlen (IF_NAME));
644   args.mode = 0;
645   /* socket filename is not specified, because this app is supposed to
646      connect to VPP over memif. so default socket filename will be used */
647   /* default socketfile = /run/vpp/memif.sock */
648
649   args.interface_id = index;
650   /* last argument for memif_create (void * private_ctx) is used by user
651      to identify connection. this context is returned with callbacks */
652   int err;
653   /* default interrupt */
654   if (s == NULL)
655     {
656       err = memif_create (&c->conn,
657                           &args, on_connect, on_disconnect, on_interrupt,
658                           &ctx[index]);
659       if (err != MEMIF_ERR_SUCCESS)
660         {
661           INFO ("memif_create: %s", memif_strerror (err));
662           return 0;
663         }
664     }
665   else
666     {
667       if (strncmp (s, "0", 1) == 0)
668         {
669           err = memif_create (&c->conn,
670                               &args, on_connect, on_disconnect, on_interrupt0,
671                               &ctx[index]);
672           if (err != MEMIF_ERR_SUCCESS)
673             {
674               INFO ("memif_create: %s", memif_strerror (err));
675               return 0;
676             }
677         }
678       else if (strncmp (s, "1", 1) == 0)
679         {
680           err = memif_create (&c->conn,
681                               &args, on_connect, on_disconnect, on_interrupt1,
682                               &ctx[index]);
683           if (err != MEMIF_ERR_SUCCESS)
684             {
685               INFO ("memif_create: %s", memif_strerror (err));
686               return 0;
687             }
688         }
689       else
690         {
691           INFO ("Unknown interrupt descriptor");
692           goto done;
693         }
694     }
695
696   c->index = index;
697   /* alloc memif buffers */
698   c->rx_buf_num = 0;
699   c->rx_bufs =
700     (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
701   c->tx_buf_num = 0;
702   c->tx_bufs =
703     (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
704
705   c->ip_addr[0] = 192;
706   c->ip_addr[1] = 168;
707   c->ip_addr[2] = c->index + 1;
708   c->ip_addr[3] = 2;
709
710   c->seq = c->tx_err_counter = c->tx_counter = c->rx_counter = 0;
711
712 done:
713   return 0;
714 }
715
716 int
717 icmpr_memif_delete (long index)
718 {
719   if (index >= MAX_CONNS)
720     {
721       INFO ("connection array overflow");
722       return 0;
723     }
724   if (index < 0)
725     {
726       INFO ("don't even try...");
727       return 0;
728     }
729   memif_connection_t *c = &memif_connection[index];
730
731   if (c->rx_bufs)
732     free (c->rx_bufs);
733   c->rx_bufs = NULL;
734   c->rx_buf_num = 0;
735   if (c->tx_bufs)
736     free (c->tx_bufs);
737   c->tx_bufs = NULL;
738   c->tx_buf_num = 0;
739
740   int err;
741   /* disconenct then delete memif connection */
742   err = memif_delete (&c->conn);
743   if (err != MEMIF_ERR_SUCCESS)
744     INFO ("memif_delete: %s", memif_strerror (err));
745   if (c->conn != NULL)
746     INFO ("memif delete fail");
747   return 0;
748 }
749
750 void
751 print_help ()
752 {
753   printf ("LIBMEMIF EXAMPLE APP: %s", APP_NAME);
754 #ifdef ICMP_DBG
755   printf (" (debug)");
756 #endif
757   printf ("\n");
758   printf ("==============================\n");
759   printf ("libmemif version: %s", LIBMEMIF_VERSION);
760 #ifdef MEMIF_DBG
761   printf (" (debug)");
762 #endif
763   printf ("\n");
764   printf ("memif version: %d\n", memif_get_version ());
765   printf ("commands:\n");
766   printf ("\thelp - prints this help\n");
767   printf ("\texit - exit app\n");
768   printf
769     ("\tconn <index> <mode> [<interrupt-desc>] - 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");
770   printf ("\tdel  <index> - delete memif\n");
771   printf ("\tshow - show connection details\n");
772   printf ("\tip-set <index> <ip-addr> - set interface ip address\n");
773   printf
774     ("\trx-mode <index> <qid> <polling|interrupt> - set queue rx mode\n");
775   printf ("\tsh-count - print counters\n");
776   printf ("\tcl-count - clear counters\n");
777   printf ("\tsend <index> <tx> <ip> <mac> - send icmp\n");
778 }
779
780 int
781 icmpr_free ()
782 {
783   /* application cleanup */
784   int err;
785   long i;
786   if (out_fd > 0)
787     close (out_fd);
788   out_fd = -1;
789   for (i = 0; i < MAX_CONNS; i++)
790     {
791       memif_connection_t *c = &memif_connection[i];
792       if (c->conn)
793         icmpr_memif_delete (i);
794     }
795
796   err = memif_cleanup ();
797   if (err != MEMIF_ERR_SUCCESS)
798     INFO ("memif_delete: %s", memif_strerror (err));
799
800   return 0;
801 }
802
803 int
804 icmpr_set_ip (long index, char *ip)
805 {
806   if (index >= MAX_CONNS)
807     {
808       INFO ("connection array overflow");
809       return 0;
810     }
811   if (index < 0)
812     {
813       INFO ("don't even try...");
814       return 0;
815     }
816   memif_connection_t *c = &memif_connection[index];
817   if (c->conn == NULL)
818     {
819       INFO ("no connection at index %ld", index);
820       return 0;
821     }
822
823   char *end;
824   char *ui;
825   uint8_t tmp[4];
826   ui = strtok (ip, ".");
827   if (ui == NULL)
828     goto error;
829   tmp[0] = strtol (ui, &end, 10);
830
831   ui = strtok (NULL, ".");
832   if (ui == NULL)
833     goto error;
834   tmp[1] = strtol (ui, &end, 10);
835
836   ui = strtok (NULL, ".");
837   if (ui == NULL)
838     goto error;
839   tmp[2] = strtol (ui, &end, 10);
840
841   ui = strtok (NULL, ".");
842   if (ui == NULL)
843     goto error;
844   tmp[3] = strtol (ui, &end, 10);
845
846   c->ip_addr[0] = tmp[0];
847   c->ip_addr[1] = tmp[1];
848   c->ip_addr[2] = tmp[2];
849   c->ip_addr[3] = tmp[3];
850
851   INFO ("memif %ld ip address set to %u.%u.%u.%u",
852         index, c->ip_addr[0], c->ip_addr[1], c->ip_addr[2], c->ip_addr[3]);
853
854   return 0;
855
856 error:
857   INFO ("invalid ip address");
858   return 0;
859 }
860
861 int
862 icmpr_set_rx_mode (long index, long qid, char *mode)
863 {
864   if (index >= MAX_CONNS)
865     {
866       INFO ("connection array overflow");
867       return 0;
868     }
869   if (index < 0)
870     {
871       INFO ("don't even try...");
872       return 0;
873     }
874   memif_connection_t *c = &memif_connection[index];
875
876   if (c->conn == NULL)
877     {
878       INFO ("no connection at index %ld", index);
879       return 0;
880     }
881
882   if (strncmp (mode, "interrupt", 9) == 0)
883     {
884       memif_set_rx_mode (c->conn, MEMIF_RX_MODE_INTERRUPT, qid);
885     }
886
887   else if (strncmp (mode, "polling", 7) == 0)
888     {
889       memif_set_rx_mode (c->conn, MEMIF_RX_MODE_POLLING, qid);
890     }
891   else
892     INFO ("expected rx mode <interrupt|polling>");
893   return 0;
894 }
895
896 void
897 icmpr_print_counters ()
898 {
899   int i;
900   for (i = 0; i < MAX_CONNS; i++)
901     {
902       memif_connection_t *c = &memif_connection[i];
903       if (c->conn == NULL)
904         continue;
905       printf ("===============================\n");
906       printf ("interface index: %d\n", c->index);
907       printf ("\trx: %lu\n", c->rx_counter);
908       printf ("\ttx: %lu\n", c->tx_counter);
909       printf ("\ttx_err: %lu\n", c->tx_err_counter);
910       printf ("\tts: %lus %luns\n", c->t_sec, c->t_nsec);
911     }
912 }
913
914 void
915 icmpr_reset_counters ()
916 {
917   int i;
918   for (i = 0; i < MAX_CONNS; i++)
919     {
920       memif_connection_t *c = &memif_connection[i];
921       if (c->conn == NULL)
922         continue;
923       c->t_sec = c->t_nsec = c->tx_err_counter = c->tx_counter =
924         c->rx_counter = 0;
925     }
926 }
927
928 void *
929 icmpr_send_proc (void *data)
930 {
931   icmpr_thread_data_t *d = (icmpr_thread_data_t *) data;
932   int index = d->index;
933   uint64_t count = d->packet_num;
934   memif_connection_t *c = &memif_connection[index];
935   if (c->conn == NULL)
936     {
937       INFO ("No connection at index %d. Thread exiting...\n", index);
938       pthread_exit (NULL);
939     }
940   uint16_t tx, i;
941   int err = MEMIF_ERR_SUCCESS;
942   uint32_t seq = 0;
943   struct timespec start, end;
944   memset (&start, 0, sizeof (start));
945   memset (&end, 0, sizeof (end));
946
947   timespec_get (&start, TIME_UTC);
948   while (count)
949     {
950       i = 0;
951       err = memif_buffer_alloc (c->conn, 0, c->tx_bufs,
952                                 MAX_MEMIF_BUFS >
953                                 count ? count : MAX_MEMIF_BUFS, &tx, 128);
954       if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING))
955         {
956           INFO ("memif_buffer_alloc: %s Thread exiting...\n",
957                 memif_strerror (err));
958           pthread_exit (NULL);
959         }
960       c->tx_buf_num += tx;
961
962       while (tx)
963         {
964           while (tx > 2)
965             {
966               generate_packet ((void *) c->tx_bufs[i].data,
967                                &c->tx_bufs[i].len, c->ip_addr,
968                                d->ip_daddr, d->hw_daddr, seq++);
969               generate_packet ((void *) c->tx_bufs[i + 1].data,
970                                &c->tx_bufs[i + 1].len, c->ip_addr,
971                                d->ip_daddr, d->hw_daddr, seq++);
972               i += 2;
973               tx -= 2;
974             }
975           generate_packet ((void *) c->tx_bufs[i].data,
976                            &c->tx_bufs[i].len, c->ip_addr,
977                            d->ip_daddr, d->hw_daddr, seq++);
978           i++;
979           tx--;
980         }
981       err = memif_tx_burst (c->conn, 0, c->tx_bufs, c->tx_buf_num, &tx);
982       if (err != MEMIF_ERR_SUCCESS)
983         {
984           INFO ("memif_tx_burst: %s Thread exiting...\n",
985                 memif_strerror (err));
986           pthread_exit (NULL);
987         }
988       c->tx_buf_num -= tx;
989       c->tx_counter += tx;
990       count -= tx;
991     }
992   timespec_get (&end, TIME_UTC);
993   INFO ("Pakcet sequence finished!");
994   INFO ("Seq len: %u", seq);
995   uint64_t t1 = end.tv_sec - start.tv_sec;
996   uint64_t t2;
997   if (end.tv_nsec > start.tv_nsec)
998     {
999       t2 = end.tv_nsec - start.tv_nsec;
1000     }
1001   else
1002     {
1003       t2 = start.tv_nsec - end.tv_nsec;
1004       t1--;
1005     }
1006   c->t_sec = t1;
1007   c->t_nsec = t2;
1008   INFO ("Seq time: %lus %luns", t1, t2);
1009   double tmp = t1;
1010   tmp += t2 / 1e+9;
1011   tmp = seq / tmp;
1012   INFO ("Average pps: %f", tmp);
1013   INFO ("Thread exiting...");
1014   pthread_exit (NULL);
1015 }
1016
1017 int
1018 icmpr_send (long index, long packet_num, char *hw, char *ip)
1019 {
1020   memif_connection_t *c = &memif_connection[index];
1021   char *end;
1022   char *ui;
1023   uint8_t tmp[6];
1024   if (c->conn == NULL)
1025     return -1;
1026   c->seq = 0;
1027   icmpr_thread_data_t *data = &icmpr_thread_data[index];
1028   data->index = index;
1029   data->packet_num = packet_num;
1030   INFO ("PN: %lu", data->packet_num);
1031   printf ("%s\n", ip);
1032   printf ("%s\n", hw);
1033
1034   ui = strtok (ip, ".");
1035   if (ui == NULL)
1036     goto error;
1037   tmp[0] = strtol (ui, &end, 10);
1038
1039   ui = strtok (NULL, ".");
1040   if (ui == NULL)
1041     goto error;
1042   tmp[1] = strtol (ui, &end, 10);
1043
1044   ui = strtok (NULL, ".");
1045   if (ui == NULL)
1046     goto error;
1047   tmp[2] = strtol (ui, &end, 10);
1048
1049   ui = strtok (NULL, ".");
1050   if (ui == NULL)
1051     goto error;
1052   tmp[3] = strtol (ui, &end, 10);
1053
1054   data->ip_daddr[0] = tmp[0];
1055   data->ip_daddr[1] = tmp[1];
1056   data->ip_daddr[2] = tmp[2];
1057   data->ip_daddr[3] = tmp[3];
1058
1059   ui = strtok (hw, ":");
1060   if (ui == NULL)
1061     goto error;
1062   tmp[0] = strtol (ui, &end, 16);
1063   ui = strtok (NULL, ":");
1064   if (ui == NULL)
1065     goto error;
1066   tmp[1] = strtol (ui, &end, 16);
1067   ui = strtok (NULL, ":");
1068   if (ui == NULL)
1069     goto error;
1070   tmp[2] = strtol (ui, &end, 16);
1071   ui = strtok (NULL, ":");
1072   if (ui == NULL)
1073     goto error;
1074   tmp[3] = strtol (ui, &end, 16);
1075   ui = strtok (NULL, ":");
1076   if (ui == NULL)
1077     goto error;
1078   tmp[4] = strtol (ui, &end, 16);
1079   ui = strtok (NULL, ":");
1080   if (ui == NULL)
1081     goto error;
1082   tmp[5] = strtol (ui, &end, 16);
1083
1084   data->hw_daddr[0] = tmp[0];
1085   data->hw_daddr[1] = tmp[1];
1086   data->hw_daddr[2] = tmp[2];
1087   data->hw_daddr[3] = tmp[3];
1088   data->hw_daddr[4] = tmp[4];
1089   data->hw_daddr[5] = tmp[5];
1090
1091   pthread_create (&thread[index], NULL, icmpr_send_proc, (void *) data);
1092   return 0;
1093
1094 error:
1095   INFO ("Invalid input\n");
1096   return 0;
1097 }
1098
1099 int
1100 user_input_handler ()
1101 {
1102   int i;
1103   char *in = (char *) malloc (256);
1104   char *ui = fgets (in, 256, stdin);
1105   char *end;
1106   long a;
1107   if (in[0] == '\n')
1108     goto done;
1109   ui = strtok (in, " ");
1110   if (strncmp (ui, "exit", 4) == 0)
1111     {
1112       free (in);
1113       icmpr_free ();
1114       exit (EXIT_SUCCESS);
1115     }
1116   else if (strncmp (ui, "help", 4) == 0)
1117     {
1118       print_help ();
1119       goto done;
1120     }
1121   else if (strncmp (ui, "conn", 4) == 0)
1122     {
1123       ui = strtok (NULL, " ");
1124       if (ui != NULL)
1125         a = strtol (ui, &end, 10);
1126       else
1127         {
1128           INFO ("expected id");
1129           goto done;
1130         }
1131       ui = strtok (NULL, " ");
1132       if (ui != NULL)
1133         icmpr_memif_create (a, strtol (ui, &end, 10), strtok (NULL, " "));
1134       else
1135         INFO ("expected mode <0|1>");
1136       goto done;
1137     }
1138   else if (strncmp (ui, "del", 3) == 0)
1139     {
1140       ui = strtok (NULL, " ");
1141       if (ui != NULL)
1142         icmpr_memif_delete (strtol (ui, &end, 10));
1143       else
1144         INFO ("expected id");
1145       goto done;
1146     }
1147   else if (strncmp (ui, "show", 4) == 0)
1148     {
1149       print_memif_details ();
1150       goto done;
1151     }
1152   else if (strncmp (ui, "ip-set", 6) == 0)
1153     {
1154       ui = strtok (NULL, " ");
1155       if (ui != NULL)
1156         icmpr_set_ip (strtol (ui, &end, 10), strtok (NULL, " "));
1157       else
1158         INFO ("expected id");
1159       goto done;
1160     }
1161   else if (strncmp (ui, "rx-mode", 7) == 0)
1162     {
1163       ui = strtok (NULL, " ");
1164       if (ui != NULL)
1165         a = strtol (ui, &end, 10);
1166       else
1167         {
1168           INFO ("expected id");
1169           goto done;
1170         }
1171       ui = strtok (NULL, " ");
1172       if (ui != NULL)
1173         icmpr_set_rx_mode (a, strtol (ui, &end, 10), strtok (NULL, " "));
1174       else
1175         INFO ("expected qid");
1176       goto done;
1177     }
1178   else if (strncmp (ui, "sh-count", 8) == 0)
1179     {
1180       icmpr_print_counters ();
1181     }
1182   else if (strncmp (ui, "cl-count", 8) == 0)
1183     {
1184       icmpr_reset_counters ();
1185     }
1186   else if (strncmp (ui, "send", 4) == 0)
1187     {
1188       ui = strtok (NULL, " ");
1189       if (ui != NULL)
1190         a = strtol (ui, &end, 10);
1191       else
1192         {
1193           INFO ("expected id");
1194           goto done;
1195         }
1196       ui = strtok (NULL, " ");
1197       if (ui != NULL)
1198         icmpr_send (a, strtol (ui, &end, 10), strtok (NULL, " "),
1199                     strtok (NULL, " "));
1200       else
1201         INFO ("expected count");
1202       goto done;
1203     }
1204   else
1205     {
1206       INFO ("unknown command: %s", ui);
1207       goto done;
1208     }
1209
1210   return 0;
1211 done:
1212   free (in);
1213   return 0;
1214 }
1215
1216 int
1217 poll_event (int timeout)
1218 {
1219   struct epoll_event evt, *e;
1220   int app_err = 0, memif_err = 0, en = 0;
1221   int tmp, nfd;
1222   uint32_t events = 0;
1223   struct timespec start, end;
1224   memset (&evt, 0, sizeof (evt));
1225   evt.events = EPOLLIN | EPOLLOUT;
1226   sigset_t sigset;
1227   sigemptyset (&sigset);
1228   en = epoll_pwait (epfd, &evt, 1, timeout, &sigset);
1229   /* id event polled */
1230   timespec_get (&start, TIME_UTC);
1231   if (en < 0)
1232     {
1233       DBG ("epoll_pwait: %s", strerror (errno));
1234       return -1;
1235     }
1236   if (en > 0)
1237     {
1238       /* this app does not use any other file descriptors than stds and memif control fds */
1239       if (evt.data.fd > 2)
1240         {
1241           /* event of memif control fd */
1242           /* convert epolle events to memif events */
1243           if (evt.events & EPOLLIN)
1244             events |= MEMIF_FD_EVENT_READ;
1245           if (evt.events & EPOLLOUT)
1246             events |= MEMIF_FD_EVENT_WRITE;
1247           if (evt.events & EPOLLERR)
1248             events |= MEMIF_FD_EVENT_ERROR;
1249           memif_err = memif_control_fd_handler (evt.data.fd, events);
1250           if (memif_err != MEMIF_ERR_SUCCESS)
1251             INFO ("memif_control_fd_handler: %s", memif_strerror (memif_err));
1252         }
1253       else if (evt.data.fd == 0)
1254         {
1255           app_err = user_input_handler ();
1256         }
1257       else
1258         {
1259           DBG ("unexpected event at memif_epfd. fd %d", evt.data.fd);
1260         }
1261     }
1262
1263   timespec_get (&end, TIME_UTC);
1264   LOG ("interrupt: %ld", end.tv_nsec - start.tv_nsec);
1265
1266   if ((app_err < 0) || (memif_err < 0))
1267     {
1268       if (app_err < 0)
1269         DBG ("user input handler error");
1270       if (memif_err < 0)
1271         DBG ("memif control fd handler error");
1272       return -1;
1273     }
1274
1275   return 0;
1276 }
1277
1278 int
1279 main ()
1280 {
1281   epfd = epoll_create (1);
1282   add_epoll_fd (0, EPOLLIN);
1283
1284 #ifdef LOG_FILE
1285   remove (LOG_FILE);
1286   enable_log = 0;
1287
1288   out_fd = open (LOG_FILE, O_WRONLY | O_CREAT, S_IRWXO);
1289   if (out_fd < 0)
1290     INFO ("Error opening log file: %s", strerror (errno));
1291 #endif /* LOG_FILE */
1292
1293   /* initialize memory interface */
1294   int err, i;
1295   /* if valid callback is passed as argument, fd event polling will be done by user
1296      all file descriptors and events will be passed to user in this callback */
1297   /* if callback is set to NULL libmemif will handle fd event polling */
1298   err = memif_init (control_fd_update, APP_NAME, NULL, NULL);
1299   if (err != MEMIF_ERR_SUCCESS)
1300     {
1301       INFO ("memif_init: %s", memif_strerror (err));
1302       icmpr_free ();
1303       exit (-1);
1304     }
1305
1306   for (i = 0; i < MAX_CONNS; i++)
1307     {
1308       memset (&memif_connection[i], 0, sizeof (memif_connection_t));
1309       ctx[i] = i;
1310     }
1311
1312   print_help ();
1313
1314   /* main loop */
1315   while (1)
1316     {
1317       if (poll_event (-1) < 0)
1318         {
1319           DBG ("poll_event error!");
1320         }
1321     }
1322 }