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