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