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