libmemif: version 2
[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, 128);
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 = 0, tx = 0;
365   uint16_t fb = 0;
366   int i = 0;                    /* rx buffer iterator */
367   int j = 0;                    /* 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       err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, rx, &tx, 128);
384       if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING))
385         {
386           INFO ("memif_buffer_alloc: %s", memif_strerror (err));
387           goto error;
388         }
389       j = 0;
390       c->tx_err_counter += rx - tx;
391
392       while (tx)
393         {
394           resolve_packet ((void *) (c->rx_bufs + i)->data,
395                           (c->rx_bufs + i)->len,
396                           (void *) (c->tx_bufs + j)->data,
397                           &(c->tx_bufs + j)->len, c->ip_addr);
398           i++;
399           j++;
400           tx--;
401         }
402
403       err = memif_refill_queue (c->conn, qid, rx);
404       if (err != MEMIF_ERR_SUCCESS)
405         INFO ("memif_buffer_free: %s", memif_strerror (err));
406       rx -= rx;
407
408       DBG ("freed %d buffers. %u/%u alloc/free buffers",
409            rx, rx, MAX_MEMIF_BUFS - rx);
410
411       err = memif_tx_burst (c->conn, qid, c->tx_bufs, j, &tx);
412       if (err != MEMIF_ERR_SUCCESS)
413         {
414           INFO ("memif_tx_burst: %s", memif_strerror (err));
415           goto error;
416         }
417       c->tx_counter += tx;
418
419     }
420   while (ret_val == MEMIF_ERR_NOBUF);
421
422   return 0;
423
424 error:
425   err = memif_refill_queue (c->conn, qid, rx);
426   if (err != MEMIF_ERR_SUCCESS)
427     INFO ("memif_buffer_free: %s", memif_strerror (err));
428   c->rx_buf_num -= rx;
429   DBG ("freed %d buffers. %u/%u alloc/free buffers",
430        fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
431   return 0;
432 }
433
434 /* called when event is polled on interrupt file descriptor.
435     there are packets in shared memory ready to be received */
436 /* dev test modification: loop until TX == RX (don't drop buffers) */
437 int
438 on_interrupt0 (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
439 {
440   long index = *((long *) private_ctx);
441   memif_connection_t *c = &memif_connection[index];
442   if (c->index != index)
443     {
444       INFO ("invalid context: %ld/%u", index, c->index);
445       return 0;
446     }
447
448   int err = MEMIF_ERR_SUCCESS, ret_val;
449   uint16_t rx = 0, tx = 0;
450   uint16_t fb;
451   int i;                        /* rx buffer iterator */
452   int j;                        /* tx bufferiterator */
453   int prev_i;                   /* first allocated rx buffer */
454
455   /* loop while there are packets in shm */
456   do
457     {
458       /* receive data from shared memory buffers */
459       err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx);
460       ret_val = err;
461       c->rx_counter += rx;
462       if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF))
463         {
464           INFO ("memif_rx_burst: %s", memif_strerror (err));
465           goto error;
466         }
467
468       prev_i = i = 0;
469
470       /* loop while there are RX buffers to be processed */
471       while (rx)
472         {
473
474           /* try to alloc required number of buffers buffers */
475           err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, rx, &tx, 128);
476           if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING))
477             {
478               INFO ("memif_buffer_alloc: %s", memif_strerror (err));
479               goto error;
480             }
481           j = 0;
482
483           /* process bufers */
484           while (tx)
485             {
486               while (tx > 2)
487                 {
488                   resolve_packet ((void *) (c->rx_bufs + i)->data,
489                                   (c->rx_bufs + i)->len,
490                                   (void *) (c->tx_bufs + j)->data,
491                                   &(c->tx_bufs + j)->len, c->ip_addr);
492                   resolve_packet ((void *) (c->rx_bufs + i + 1)->data,
493                                   (c->rx_bufs + i + 1)->len,
494                                   (void *) (c->tx_bufs + j + 1)->data,
495                                   &(c->tx_bufs + j + 1)->len, c->ip_addr);
496
497                   i += 2;
498                   j += 2;
499                   tx -= 2;
500                 }
501               resolve_packet ((void *) (c->rx_bufs + i)->data,
502                               (c->rx_bufs + i)->len,
503                               (void *) (c->tx_bufs + j)->data,
504                               &(c->tx_bufs + j)->len, c->ip_addr);
505               i++;
506               j++;
507               tx--;
508             }
509           /* mark memif buffers and shared memory buffers as free */
510           /* free processed buffers */
511           err = memif_refill_queue (c->conn, qid, j);
512           if (err != MEMIF_ERR_SUCCESS)
513             INFO ("memif_buffer_free: %s", memif_strerror (err));
514           rx -= j;
515           prev_i = i;
516
517           DBG ("freed %d buffers. %u/%u alloc/free buffers",
518                fb, rx, MAX_MEMIF_BUFS - rx);
519
520           /* transmit allocated buffers */
521           err = memif_tx_burst (c->conn, qid, c->tx_bufs, j, &tx);
522           if (err != MEMIF_ERR_SUCCESS)
523             {
524               INFO ("memif_tx_burst: %s", memif_strerror (err));
525               goto error;
526             }
527           c->tx_counter += tx;
528
529         }
530
531     }
532   while (ret_val == MEMIF_ERR_NOBUF);
533
534   return 0;
535
536 error:
537   err = memif_refill_queue (c->conn, qid, rx);
538   if (err != MEMIF_ERR_SUCCESS)
539     INFO ("memif_buffer_free: %s", memif_strerror (err));
540   c->rx_buf_num -= rx;
541   DBG ("freed %d buffers. %u/%u alloc/free buffers",
542        fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
543   return 0;
544 }
545
546 /* called when event is polled on interrupt file descriptor.
547     there are packets in shared memory ready to be received */
548 /* dev test modification: handle only ARP requests */
549 int
550 on_interrupt1 (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
551 {
552   long index = *((long *) private_ctx);
553   memif_connection_t *c = &memif_connection[index];
554   if (c->index != index)
555     {
556       INFO ("invalid context: %ld/%u", index, c->index);
557       return 0;
558     }
559
560   int err = MEMIF_ERR_SUCCESS, ret_val;
561   int i;
562   uint16_t rx, tx;
563   uint16_t fb;
564   uint16_t pck_seq;
565
566   do
567     {
568       /* receive data from shared memory buffers */
569       err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx);
570       ret_val = err;
571       if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF))
572         {
573           INFO ("memif_rx_burst: %s", memif_strerror (err));
574           goto error;
575         }
576       c->rx_buf_num += rx;
577       c->rx_counter += rx;
578
579       for (i = 0; i < rx; i++)
580         {
581           if (((struct ether_header *) (c->rx_bufs + i)->data)->ether_type ==
582               0x0608)
583             {
584               if (icmpr_buffer_alloc (c->index, 1, &tx, i, qid) < 0)
585                 break;
586               resolve_packet ((void *) (c->rx_bufs + i)->data,
587                               (c->rx_bufs + i)->len,
588                               (void *) (c->tx_bufs + i)->data,
589                               &(c->tx_bufs + i)->len, c->ip_addr);
590               icmpr_tx_burst (c->index, qid);
591             }
592         }
593
594       err = memif_refill_queue (c->conn, qid, rx);
595       if (err != MEMIF_ERR_SUCCESS)
596         INFO ("memif_buffer_free: %s", memif_strerror (err));
597       c->rx_buf_num -= rx;
598
599
600     }
601   while (ret_val == MEMIF_ERR_NOBUF);
602
603   return 0;
604
605 error:
606   err = memif_refill_queue (c->conn, qid, rx);
607   if (err != MEMIF_ERR_SUCCESS)
608     INFO ("memif_buffer_free: %s", memif_strerror (err));
609   c->rx_buf_num -= rx;
610   DBG ("freed %d buffers. %u/%u alloc/free buffers",
611        fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
612   return 0;
613 }
614
615 int
616 icmpr_memif_create (long index, long mode, char *s)
617 {
618   if (index >= MAX_CONNS)
619     {
620       INFO ("connection array overflow");
621       return 0;
622     }
623   if (index < 0)
624     {
625       INFO ("don't even try...");
626       return 0;
627     }
628   memif_connection_t *c = &memif_connection[index];
629
630   /* setting memif connection arguments */
631   memif_conn_args_t args;
632   int fd = -1;
633   memset (&args, 0, sizeof (args));
634   args.is_master = mode;
635   args.log2_ring_size = 11;
636   args.buffer_size = 2048;
637   args.num_s2m_rings = 1;
638   args.num_m2s_rings = 1;
639   strncpy ((char *) args.interface_name, IF_NAME, strlen (IF_NAME));
640   args.mode = 0;
641   /* socket filename is not specified, because this app is supposed to
642      connect to VPP over memif. so default socket filename will be used */
643   /* default socketfile = /run/vpp/memif.sock */
644
645   args.interface_id = index;
646   /* last argument for memif_create (void * private_ctx) is used by user
647      to identify connection. this context is returned with callbacks */
648   int err;
649   /* default interrupt */
650   if (s == NULL)
651     {
652       err = memif_create (&c->conn,
653                           &args, on_connect, on_disconnect, on_interrupt,
654                           &ctx[index]);
655       if (err != MEMIF_ERR_SUCCESS)
656         {
657           INFO ("memif_create: %s", memif_strerror (err));
658           return 0;
659         }
660     }
661   else
662     {
663       if (strncmp (s, "0", 1) == 0)
664         {
665           err = memif_create (&c->conn,
666                               &args, on_connect, on_disconnect, on_interrupt0,
667                               &ctx[index]);
668           if (err != MEMIF_ERR_SUCCESS)
669             {
670               INFO ("memif_create: %s", memif_strerror (err));
671               return 0;
672             }
673         }
674       else if (strncmp (s, "1", 1) == 0)
675         {
676           err = memif_create (&c->conn,
677                               &args, on_connect, on_disconnect, on_interrupt1,
678                               &ctx[index]);
679           if (err != MEMIF_ERR_SUCCESS)
680             {
681               INFO ("memif_create: %s", memif_strerror (err));
682               return 0;
683             }
684         }
685       else
686         {
687           INFO ("Unknown interrupt descriptor");
688           goto done;
689         }
690     }
691
692   c->index = index;
693   /* alloc memif buffers */
694   c->rx_buf_num = 0;
695   c->rx_bufs =
696     (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
697   c->tx_buf_num = 0;
698   c->tx_bufs =
699     (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
700
701   c->ip_addr[0] = 192;
702   c->ip_addr[1] = 168;
703   c->ip_addr[2] = c->index + 1;
704   c->ip_addr[3] = 2;
705
706   c->seq = c->tx_err_counter = c->tx_counter = c->rx_counter = 0;
707
708 done:
709   return 0;
710 }
711
712 int
713 icmpr_memif_delete (long index)
714 {
715   if (index >= MAX_CONNS)
716     {
717       INFO ("connection array overflow");
718       return 0;
719     }
720   if (index < 0)
721     {
722       INFO ("don't even try...");
723       return 0;
724     }
725   memif_connection_t *c = &memif_connection[index];
726
727   if (c->rx_bufs)
728     free (c->rx_bufs);
729   c->rx_bufs = NULL;
730   c->rx_buf_num = 0;
731   if (c->tx_bufs)
732     free (c->tx_bufs);
733   c->tx_bufs = NULL;
734   c->tx_buf_num = 0;
735
736   int err;
737   /* disconenct then delete memif connection */
738   err = memif_delete (&c->conn);
739   if (err != MEMIF_ERR_SUCCESS)
740     INFO ("memif_delete: %s", memif_strerror (err));
741   if (c->conn != NULL)
742     INFO ("memif delete fail");
743   return 0;
744 }
745
746 void
747 print_help ()
748 {
749   printf ("LIBMEMIF EXAMPLE APP: %s", APP_NAME);
750 #ifdef ICMP_DBG
751   printf (" (debug)");
752 #endif
753   printf ("\n");
754   printf ("==============================\n");
755   printf ("libmemif version: %s", LIBMEMIF_VERSION);
756 #ifdef MEMIF_DBG
757   printf (" (debug)");
758 #endif
759   printf ("\n");
760   printf ("memif version: %d\n", memif_get_version ());
761   printf ("commands:\n");
762   printf ("\thelp - prints this help\n");
763   printf ("\texit - exit app\n");
764   printf
765     ("\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");
766   printf ("\tdel  <index> - delete memif\n");
767   printf ("\tshow - show connection details\n");
768   printf ("\tip-set <index> <ip-addr> - set interface ip address\n");
769   printf
770     ("\trx-mode <index> <qid> <polling|interrupt> - set queue rx mode\n");
771   printf ("\tsh-count - print counters\n");
772   printf ("\tcl-count - clear counters\n");
773   printf ("\tsend <index> <tx> <ip> <mac> - send icmp\n");
774 }
775
776 int
777 icmpr_free ()
778 {
779   /* application cleanup */
780   int err;
781   long i;
782   if (out_fd > 0)
783     close (out_fd);
784   out_fd = -1;
785   for (i = 0; i < MAX_CONNS; i++)
786     {
787       memif_connection_t *c = &memif_connection[i];
788       if (c->conn)
789         icmpr_memif_delete (i);
790     }
791
792   err = memif_cleanup ();
793   if (err != MEMIF_ERR_SUCCESS)
794     INFO ("memif_delete: %s", memif_strerror (err));
795
796   return 0;
797 }
798
799 int
800 icmpr_set_ip (long index, char *ip)
801 {
802   if (index >= MAX_CONNS)
803     {
804       INFO ("connection array overflow");
805       return 0;
806     }
807   if (index < 0)
808     {
809       INFO ("don't even try...");
810       return 0;
811     }
812   memif_connection_t *c = &memif_connection[index];
813   if (c->conn == NULL)
814     {
815       INFO ("no connection at index %ld", index);
816       return 0;
817     }
818
819   char *end;
820   char *ui;
821   uint8_t tmp[4];
822   ui = strtok (ip, ".");
823   if (ui == NULL)
824     goto error;
825   tmp[0] = strtol (ui, &end, 10);
826
827   ui = strtok (NULL, ".");
828   if (ui == NULL)
829     goto error;
830   tmp[1] = strtol (ui, &end, 10);
831
832   ui = strtok (NULL, ".");
833   if (ui == NULL)
834     goto error;
835   tmp[2] = strtol (ui, &end, 10);
836
837   ui = strtok (NULL, ".");
838   if (ui == NULL)
839     goto error;
840   tmp[3] = strtol (ui, &end, 10);
841
842   c->ip_addr[0] = tmp[0];
843   c->ip_addr[1] = tmp[1];
844   c->ip_addr[2] = tmp[2];
845   c->ip_addr[3] = tmp[3];
846
847   INFO ("memif %ld ip address set to %u.%u.%u.%u",
848         index, c->ip_addr[0], c->ip_addr[1], c->ip_addr[2], c->ip_addr[3]);
849
850   return 0;
851
852 error:
853   INFO ("invalid ip address");
854   return 0;
855 }
856
857 int
858 icmpr_set_rx_mode (long index, long qid, char *mode)
859 {
860   if (index >= MAX_CONNS)
861     {
862       INFO ("connection array overflow");
863       return 0;
864     }
865   if (index < 0)
866     {
867       INFO ("don't even try...");
868       return 0;
869     }
870   memif_connection_t *c = &memif_connection[index];
871
872   if (c->conn == NULL)
873     {
874       INFO ("no connection at index %ld", index);
875       return 0;
876     }
877
878   if (strncmp (mode, "interrupt", 9) == 0)
879     {
880       memif_set_rx_mode (c->conn, MEMIF_RX_MODE_INTERRUPT, qid);
881     }
882
883   else if (strncmp (mode, "polling", 7) == 0)
884     {
885       memif_set_rx_mode (c->conn, MEMIF_RX_MODE_POLLING, qid);
886     }
887   else
888     INFO ("expected rx mode <interrupt|polling>");
889   return 0;
890 }
891
892 void
893 icmpr_print_counters ()
894 {
895   int i;
896   for (i = 0; i < MAX_CONNS; i++)
897     {
898       memif_connection_t *c = &memif_connection[i];
899       if (c->conn == NULL)
900         continue;
901       printf ("===============================\n");
902       printf ("interface index: %d\n", c->index);
903       printf ("\trx: %lu\n", c->rx_counter);
904       printf ("\ttx: %lu\n", c->tx_counter);
905       printf ("\ttx_err: %lu\n", c->tx_err_counter);
906       printf ("\tts: %lus %luns\n", c->t_sec, c->t_nsec);
907     }
908 }
909
910 void
911 icmpr_reset_counters ()
912 {
913   int i;
914   for (i = 0; i < MAX_CONNS; i++)
915     {
916       memif_connection_t *c = &memif_connection[i];
917       if (c->conn == NULL)
918         continue;
919       c->t_sec = c->t_nsec = c->tx_err_counter = c->tx_counter =
920         c->rx_counter = 0;
921     }
922 }
923
924 void *
925 icmpr_send_proc (void *data)
926 {
927   icmpr_thread_data_t *d = (icmpr_thread_data_t *) data;
928   int index = d->index;
929   uint64_t count = d->packet_num;
930   memif_connection_t *c = &memif_connection[index];
931   if (c->conn == NULL)
932     {
933       INFO ("No connection at index %d. Thread exiting...\n", index);
934       pthread_exit (NULL);
935     }
936   uint16_t tx, i;
937   int err = MEMIF_ERR_SUCCESS;
938   uint32_t seq = 0;
939   struct timespec start, end;
940   memset (&start, 0, sizeof (start));
941   memset (&end, 0, sizeof (end));
942
943   timespec_get (&start, TIME_UTC);
944   while (count)
945     {
946       i = 0;
947       err = memif_buffer_alloc (c->conn, 0, c->tx_bufs,
948                                 MAX_MEMIF_BUFS >
949                                 count ? count : MAX_MEMIF_BUFS, &tx, 128);
950       if ((err != MEMIF_ERR_SUCCESS) && (err != MEMIF_ERR_NOBUF_RING))
951         {
952           INFO ("memif_buffer_alloc: %s Thread exiting...\n",
953                 memif_strerror (err));
954           pthread_exit (NULL);
955         }
956       c->tx_buf_num += tx;
957
958       while (tx)
959         {
960           while (tx > 2)
961             {
962               generate_packet ((void *) c->tx_bufs[i].data,
963                                &c->tx_bufs[i].len, c->ip_addr,
964                                d->ip_daddr, d->hw_daddr, seq++);
965               generate_packet ((void *) c->tx_bufs[i + 1].data,
966                                &c->tx_bufs[i + 1].len, c->ip_addr,
967                                d->ip_daddr, d->hw_daddr, seq++);
968               i += 2;
969               tx -= 2;
970             }
971           generate_packet ((void *) c->tx_bufs[i].data,
972                            &c->tx_bufs[i].len, c->ip_addr,
973                            d->ip_daddr, d->hw_daddr, seq++);
974           i++;
975           tx--;
976         }
977       err = memif_tx_burst (c->conn, 0, c->tx_bufs, c->tx_buf_num, &tx);
978       if (err != MEMIF_ERR_SUCCESS)
979         {
980           INFO ("memif_tx_burst: %s Thread exiting...\n",
981                 memif_strerror (err));
982           pthread_exit (NULL);
983         }
984       c->tx_buf_num -= tx;
985       c->tx_counter += tx;
986       count -= tx;
987     }
988   timespec_get (&end, TIME_UTC);
989   INFO ("Pakcet sequence finished!");
990   INFO ("Seq len: %u", seq);
991   uint64_t t1 = end.tv_sec - start.tv_sec;
992   uint64_t t2;
993   if (end.tv_nsec > start.tv_nsec)
994     {
995       t2 = end.tv_nsec - start.tv_nsec;
996     }
997   else
998     {
999       t2 = start.tv_nsec - end.tv_nsec;
1000       t1--;
1001     }
1002   c->t_sec = t1;
1003   c->t_nsec = t2;
1004   INFO ("Seq time: %lus %luns", t1, t2);
1005   double tmp = t1;
1006   tmp += t2 / 1e+9;
1007   tmp = seq / tmp;
1008   INFO ("Average pps: %f", tmp);
1009   INFO ("Thread exiting...");
1010   pthread_exit (NULL);
1011 }
1012
1013 int
1014 icmpr_send (long index, long packet_num, char *hw, char *ip)
1015 {
1016   memif_connection_t *c = &memif_connection[index];
1017   char *end;
1018   char *ui;
1019   uint8_t tmp[6];
1020   if (c->conn == NULL)
1021     return -1;
1022   c->seq = 0;
1023   icmpr_thread_data_t *data = &icmpr_thread_data[index];
1024   data->index = index;
1025   data->packet_num = packet_num;
1026   INFO ("PN: %lu", data->packet_num);
1027   printf ("%s\n", ip);
1028   printf ("%s\n", hw);
1029
1030   ui = strtok (ip, ".");
1031   if (ui == NULL)
1032     goto error;
1033   tmp[0] = strtol (ui, &end, 10);
1034
1035   ui = strtok (NULL, ".");
1036   if (ui == NULL)
1037     goto error;
1038   tmp[1] = strtol (ui, &end, 10);
1039
1040   ui = strtok (NULL, ".");
1041   if (ui == NULL)
1042     goto error;
1043   tmp[2] = strtol (ui, &end, 10);
1044
1045   ui = strtok (NULL, ".");
1046   if (ui == NULL)
1047     goto error;
1048   tmp[3] = strtol (ui, &end, 10);
1049
1050   data->ip_daddr[0] = tmp[0];
1051   data->ip_daddr[1] = tmp[1];
1052   data->ip_daddr[2] = tmp[2];
1053   data->ip_daddr[3] = tmp[3];
1054
1055   ui = strtok (hw, ":");
1056   if (ui == NULL)
1057     goto error;
1058   tmp[0] = strtol (ui, &end, 16);
1059   ui = strtok (NULL, ":");
1060   if (ui == NULL)
1061     goto error;
1062   tmp[1] = strtol (ui, &end, 16);
1063   ui = strtok (NULL, ":");
1064   if (ui == NULL)
1065     goto error;
1066   tmp[2] = strtol (ui, &end, 16);
1067   ui = strtok (NULL, ":");
1068   if (ui == NULL)
1069     goto error;
1070   tmp[3] = strtol (ui, &end, 16);
1071   ui = strtok (NULL, ":");
1072   if (ui == NULL)
1073     goto error;
1074   tmp[4] = strtol (ui, &end, 16);
1075   ui = strtok (NULL, ":");
1076   if (ui == NULL)
1077     goto error;
1078   tmp[5] = strtol (ui, &end, 16);
1079
1080   data->hw_daddr[0] = tmp[0];
1081   data->hw_daddr[1] = tmp[1];
1082   data->hw_daddr[2] = tmp[2];
1083   data->hw_daddr[3] = tmp[3];
1084   data->hw_daddr[4] = tmp[4];
1085   data->hw_daddr[5] = tmp[5];
1086
1087   pthread_create (&thread[index], NULL, icmpr_send_proc, (void *) data);
1088   return 0;
1089
1090 error:
1091   INFO ("Invalid input\n");
1092   return 0;
1093 }
1094
1095 int
1096 user_input_handler ()
1097 {
1098   int i;
1099   char *in = (char *) malloc (256);
1100   char *ui = fgets (in, 256, stdin);
1101   char *end;
1102   long a;
1103   if (in[0] == '\n')
1104     goto done;
1105   ui = strtok (in, " ");
1106   if (strncmp (ui, "exit", 4) == 0)
1107     {
1108       free (in);
1109       icmpr_free ();
1110       exit (EXIT_SUCCESS);
1111     }
1112   else if (strncmp (ui, "help", 4) == 0)
1113     {
1114       print_help ();
1115       goto done;
1116     }
1117   else if (strncmp (ui, "conn", 4) == 0)
1118     {
1119       ui = strtok (NULL, " ");
1120       if (ui != NULL)
1121         a = strtol (ui, &end, 10);
1122       else
1123         {
1124           INFO ("expected id");
1125           goto done;
1126         }
1127       ui = strtok (NULL, " ");
1128       if (ui != NULL)
1129         icmpr_memif_create (a, strtol (ui, &end, 10), strtok (NULL, " "));
1130       else
1131         INFO ("expected mode <0|1>");
1132       goto done;
1133     }
1134   else if (strncmp (ui, "del", 3) == 0)
1135     {
1136       ui = strtok (NULL, " ");
1137       if (ui != NULL)
1138         icmpr_memif_delete (strtol (ui, &end, 10));
1139       else
1140         INFO ("expected id");
1141       goto done;
1142     }
1143   else if (strncmp (ui, "show", 4) == 0)
1144     {
1145       print_memif_details ();
1146       goto done;
1147     }
1148   else if (strncmp (ui, "ip-set", 6) == 0)
1149     {
1150       ui = strtok (NULL, " ");
1151       if (ui != NULL)
1152         icmpr_set_ip (strtol (ui, &end, 10), strtok (NULL, " "));
1153       else
1154         INFO ("expected id");
1155       goto done;
1156     }
1157   else if (strncmp (ui, "rx-mode", 7) == 0)
1158     {
1159       ui = strtok (NULL, " ");
1160       if (ui != NULL)
1161         a = strtol (ui, &end, 10);
1162       else
1163         {
1164           INFO ("expected id");
1165           goto done;
1166         }
1167       ui = strtok (NULL, " ");
1168       if (ui != NULL)
1169         icmpr_set_rx_mode (a, strtol (ui, &end, 10), strtok (NULL, " "));
1170       else
1171         INFO ("expected qid");
1172       goto done;
1173     }
1174   else if (strncmp (ui, "sh-count", 8) == 0)
1175     {
1176       icmpr_print_counters ();
1177     }
1178   else if (strncmp (ui, "cl-count", 8) == 0)
1179     {
1180       icmpr_reset_counters ();
1181     }
1182   else if (strncmp (ui, "send", 4) == 0)
1183     {
1184       ui = strtok (NULL, " ");
1185       if (ui != NULL)
1186         a = strtol (ui, &end, 10);
1187       else
1188         {
1189           INFO ("expected id");
1190           goto done;
1191         }
1192       ui = strtok (NULL, " ");
1193       if (ui != NULL)
1194         icmpr_send (a, strtol (ui, &end, 10), strtok (NULL, " "),
1195                     strtok (NULL, " "));
1196       else
1197         INFO ("expected count");
1198       goto done;
1199     }
1200   else
1201     {
1202       INFO ("unknown command: %s", ui);
1203       goto done;
1204     }
1205
1206   return 0;
1207 done:
1208   free (in);
1209   return 0;
1210 }
1211
1212 int
1213 poll_event (int timeout)
1214 {
1215   struct epoll_event evt, *e;
1216   int app_err = 0, memif_err = 0, en = 0;
1217   int tmp, nfd;
1218   uint32_t events = 0;
1219   struct timespec start, end;
1220   memset (&evt, 0, sizeof (evt));
1221   evt.events = EPOLLIN | EPOLLOUT;
1222   sigset_t sigset;
1223   sigemptyset (&sigset);
1224   en = epoll_pwait (epfd, &evt, 1, timeout, &sigset);
1225   /* id event polled */
1226   timespec_get (&start, TIME_UTC);
1227   if (en < 0)
1228     {
1229       DBG ("epoll_pwait: %s", strerror (errno));
1230       return -1;
1231     }
1232   if (en > 0)
1233     {
1234       /* this app does not use any other file descriptors than stds and memif control fds */
1235       if (evt.data.fd > 2)
1236         {
1237           /* event of memif control fd */
1238           /* convert epolle events to memif events */
1239           if (evt.events & EPOLLIN)
1240             events |= MEMIF_FD_EVENT_READ;
1241           if (evt.events & EPOLLOUT)
1242             events |= MEMIF_FD_EVENT_WRITE;
1243           if (evt.events & EPOLLERR)
1244             events |= MEMIF_FD_EVENT_ERROR;
1245           memif_err = memif_control_fd_handler (evt.data.fd, events);
1246           if (memif_err != MEMIF_ERR_SUCCESS)
1247             INFO ("memif_control_fd_handler: %s", memif_strerror (memif_err));
1248         }
1249       else if (evt.data.fd == 0)
1250         {
1251           app_err = user_input_handler ();
1252         }
1253       else
1254         {
1255           DBG ("unexpected event at memif_epfd. fd %d", evt.data.fd);
1256         }
1257     }
1258
1259   timespec_get (&end, TIME_UTC);
1260   LOG ("interrupt: %ld", end.tv_nsec - start.tv_nsec);
1261
1262   if ((app_err < 0) || (memif_err < 0))
1263     {
1264       if (app_err < 0)
1265         DBG ("user input handler error");
1266       if (memif_err < 0)
1267         DBG ("memif control fd handler error");
1268       return -1;
1269     }
1270
1271   return 0;
1272 }
1273
1274 int
1275 main ()
1276 {
1277   epfd = epoll_create (1);
1278   add_epoll_fd (0, EPOLLIN);
1279
1280 #ifdef LOG_FILE
1281   remove (LOG_FILE);
1282   enable_log = 0;
1283
1284   out_fd = open (LOG_FILE, O_WRONLY | O_CREAT, S_IRWXO);
1285   if (out_fd < 0)
1286     INFO ("Error opening log file: %s", strerror (errno));
1287 #endif /* LOG_FILE */
1288
1289   /* initialize memory interface */
1290   int err, i;
1291   /* if valid callback is passed as argument, fd event polling will be done by user
1292      all file descriptors and events will be passed to user in this callback */
1293   /* if callback is set to NULL libmemif will handle fd event polling */
1294   err = memif_init (control_fd_update, APP_NAME, NULL, NULL);
1295   if (err != MEMIF_ERR_SUCCESS)
1296     {
1297       INFO ("memif_init: %s", memif_strerror (err));
1298       icmpr_free ();
1299       exit (-1);
1300     }
1301
1302   for (i = 0; i < MAX_CONNS; i++)
1303     {
1304       memset (&memif_connection[i], 0, sizeof (memif_connection_t));
1305       ctx[i] = i;
1306     }
1307
1308   print_help ();
1309
1310   /* main loop */
1311   while (1)
1312     {
1313       if (poll_event (-1) < 0)
1314         {
1315           DBG ("poll_event error!");
1316         }
1317     }
1318 }