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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
21 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
28 #include <sys/prctl.h>
34 #include <linux/icmp.h>
35 #include <arpa/inet.h>
37 #include <netinet/if_ether.h>
38 #include <net/if_arp.h>
39 #include <asm/byteorder.h>
42 #include <sys/epoll.h>
48 #include <icmp_proto.h>
50 #define APP_NAME "ICMP_Responder"
51 #define IF_NAME "memif_connection"
55 #define DBG(...) do { \
56 printf (APP_NAME":%s:%d: ", __func__, __LINE__); \
57 printf (__VA_ARGS__); \
64 #define INFO(...) do { \
65 printf ("INFO: "__VA_ARGS__); \
69 /* maximum tx/rx memif buffers */
70 #define MAX_MEMIF_BUFS 256
78 /* memif conenction handle */
79 memif_conn_handle_t conn;
81 memif_buffer_t *tx_bufs;
82 /* allocated tx buffers counter */
83 /* number of tx buffers pointing to shared memory */
86 memif_buffer_t *rx_bufs;
87 /* allcoated rx buffers counter */
88 /* number of rx buffers pointing to shared memory */
90 /* interface ip address */
94 memif_connection_t memif_connection[MAX_CONNS];
97 /* print details for all memif connections */
99 print_memif_details ()
106 buf = malloc (buflen);
107 printf ("MEMIF DETAILS\n");
108 printf ("==============================\n");
109 for (i = 0; i < MAX_CONNS; i++)
111 memif_connection_t *c = &memif_connection[i];
113 memset (&md, 0, sizeof (md));
114 memset (buf, 0, buflen);
116 err = memif_get_details (c->conn, &md, buf, buflen);
117 if (err != MEMIF_ERR_SUCCESS)
119 if (err != MEMIF_ERR_NOCONN)
120 INFO ("%s", memif_strerror (err));
124 printf ("interface index: %d\n", i);
126 printf ("\tinterface ip: %u.%u.%u.%u\n",
127 c->ip_addr[0], c->ip_addr[1], c->ip_addr[2], c->ip_addr[3]);
128 printf ("\tinterface name: %s\n", (char *) md.if_name);
129 printf ("\tapp name: %s\n", (char *) md.inst_name);
130 printf ("\tremote interface name: %s\n", (char *) md.remote_if_name);
131 printf ("\tremote app name: %s\n", (char *) md.remote_inst_name);
132 printf ("\tid: %u\n", md.id);
133 printf ("\tsecret: %s\n", (char *) md.secret);
143 printf ("ethernet\n");
149 printf ("punt/inject\n");
152 printf ("unknown\n");
155 printf ("\tsocket filename: %s\n", (char *) md.socket_filename);
156 printf ("\trx queues:\n");
157 for (e = 0; e < md.rx_queues_num; e++)
159 printf ("\t\tqueue id: %u\n", md.rx_queues[e].qid);
160 printf ("\t\tring size: %u\n", md.rx_queues[e].ring_size);
161 printf ("\t\tbuffer size: %u\n", md.rx_queues[e].buffer_size);
163 printf ("\ttx queues:\n");
164 for (e = 0; e < md.tx_queues_num; e++)
166 printf ("\t\tqueue id: %u\n", md.tx_queues[e].qid);
167 printf ("\t\tring size: %u\n", md.tx_queues[e].ring_size);
168 printf ("\t\tbuffer size: %u\n", md.tx_queues[e].buffer_size);
180 add_epoll_fd (int fd, uint32_t events)
184 DBG ("invalid fd %d", fd);
187 struct epoll_event evt;
188 memset (&evt, 0, sizeof (evt));
191 if (epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &evt) < 0)
193 DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
196 DBG ("fd %d added to epoll", fd);
201 mod_epoll_fd (int fd, uint32_t events)
205 DBG ("invalid fd %d", fd);
208 struct epoll_event evt;
209 memset (&evt, 0, sizeof (evt));
212 if (epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &evt) < 0)
214 DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
217 DBG ("fd %d moddified on epoll", fd);
222 del_epoll_fd (int fd)
226 DBG ("invalid fd %d", fd);
229 struct epoll_event evt;
230 memset (&evt, 0, sizeof (evt));
231 if (epoll_ctl (epfd, EPOLL_CTL_DEL, fd, &evt) < 0)
233 DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
236 DBG ("fd %d removed from epoll", fd);
240 /* informs user about connected status. private_ctx is used by user to identify connection
241 (multiple connections WIP) */
243 on_connect (memif_conn_handle_t conn, void *private_ctx)
245 INFO ("memif connected!");
249 /* informs user about disconnected status. private_ctx is used by user to identify connection
250 (multiple connections WIP) */
252 on_disconnect (memif_conn_handle_t conn, void *private_ctx)
254 INFO ("memif disconnected!");
258 /* user needs to watch new fd or stop watching fd that is about to be closed.
259 control fd will be modified during connection establishment to minimize CPU usage */
261 control_fd_update (int fd, uint8_t events)
263 /* convert memif event definitions to epoll events */
264 if (events & MEMIF_FD_EVENT_DEL)
265 return del_epoll_fd (fd);
268 if (events & MEMIF_FD_EVENT_READ)
270 if (events & MEMIF_FD_EVENT_WRITE)
273 if (events & MEMIF_FD_EVENT_MOD)
274 return mod_epoll_fd (fd, evt);
276 return add_epoll_fd (fd, evt);
280 icmpr_buffer_alloc (long index, long n, uint16_t qid)
282 memif_connection_t *c = &memif_connection[index];
285 /* set data pointer to shared memory and set buffer_len to shared mmeory buffer len */
286 err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, n, &r);
287 if (err != MEMIF_ERR_SUCCESS)
289 INFO ("memif_buffer_alloc: %s", memif_strerror (err));
294 DBG ("allocated %d/%ld buffers, %u free buffers", r, n,
295 MAX_MEMIF_BUFS - c->tx_buf_num);
300 icmpr_tx_burst (long index, uint16_t qid)
302 memif_connection_t *c = &memif_connection[index];
305 /* inform peer memif interface about data in shared memory buffers */
306 /* mark memif buffers as free */
307 err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &r);
308 if (err != MEMIF_ERR_SUCCESS)
309 INFO ("memif_tx_burst: %s", memif_strerror (err));
310 DBG ("tx: %d/%u", r, c->tx_buf_num);
315 /* called when event is polled on interrupt file descriptor.
316 there are packets in shared memory ready to be received */
318 on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
320 long index = *((long *) private_ctx);
321 memif_connection_t *c = &memif_connection[index];
322 if (c->index != index)
324 INFO ("invalid context: %ld/%u", index, c->index);
330 /* receive data from shared memory buffers */
331 err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx);
332 if (err != MEMIF_ERR_SUCCESS)
334 INFO ("memif_rx_burst: %s", memif_strerror (err));
340 DBG ("received %d buffers. %u/%u alloc/free buffers",
341 rx, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
343 if (icmpr_buffer_alloc (index, rx, qid) < 0)
345 INFO ("buffer_alloc error");
349 for (i = 0; i < rx; i++)
351 resolve_packet ((void *) (c->rx_bufs + i)->data,
352 (c->rx_bufs + i)->data_len,
353 (void *) (c->tx_bufs + i)->data,
354 &(c->tx_bufs + i)->data_len, c->ip_addr);
357 /* mark memif buffers and shared memory buffers as free */
358 err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb);
359 if (err != MEMIF_ERR_SUCCESS)
360 INFO ("memif_buffer_free: %s", memif_strerror (err));
363 DBG ("freed %d buffers. %u/%u alloc/free buffers",
364 fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
366 icmpr_tx_burst (index, qid);
371 err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb);
372 if (err != MEMIF_ERR_SUCCESS)
373 INFO ("memif_buffer_free: %s", memif_strerror (err));
375 DBG ("freed %d buffers. %u/%u alloc/free buffers",
376 fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
381 icmpr_memif_create (long index, long mode)
383 if (index >= MAX_CONNS)
385 INFO ("connection array overflow");
390 INFO ("don't even try...");
393 memif_connection_t *c = &memif_connection[index];
395 /* setting memif connection arguments */
396 memif_conn_args_t args;
398 memset (&args, 0, sizeof (args));
399 args.is_master = mode;
400 args.log2_ring_size = 10;
401 args.buffer_size = 2048;
402 args.num_s2m_rings = 2;
403 args.num_m2s_rings = 2;
404 strncpy ((char *) args.interface_name, IF_NAME, strlen (IF_NAME));
405 strncpy ((char *) args.instance_name, APP_NAME, strlen (APP_NAME));
407 /* socket filename is not specified, because this app is supposed to
408 connect to VPP over memif. so default socket filename will be used */
409 /* default socketfile = /run/vpp/memif.sock */
411 args.interface_id = index;
412 /* last argument for memif_create (void * private_ctx) is used by user
413 to identify connection. this context is returned with callbacks */
414 int err = memif_create (&c->conn,
415 &args, on_connect, on_disconnect, on_interrupt,
417 if (err != MEMIF_ERR_SUCCESS)
419 INFO ("memif_create: %s", memif_strerror (err));
424 /* alloc memif buffers */
427 (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
430 (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
434 c->ip_addr[2] = c->index + 1;
440 icmpr_memif_delete (long index)
442 if (index >= MAX_CONNS)
444 INFO ("connection array overflow");
449 INFO ("don't even try...");
452 memif_connection_t *c = &memif_connection[index];
464 /* disconenct then delete memif connection */
465 err = memif_delete (&c->conn);
466 if (err != MEMIF_ERR_SUCCESS)
467 INFO ("memif_delete: %s", memif_strerror (err));
469 INFO ("memif delete fail");
476 printf ("LIBMEMIF EXAMPLE APP: %s", APP_NAME);
481 printf ("==============================\n");
482 printf ("libmemif version: %s", LIBMEMIF_VERSION);
487 printf ("memif version: %d\n", MEMIF_VERSION);
488 printf ("commands:\n");
489 printf ("\thelp - prints this help\n");
490 printf ("\texit - exit app\n");
492 ("\tconn <index> <mode> - create memif. index is also used as interface id, mode 0 = slave 1 = master\n");
493 printf ("\tdel <index> - delete memif\n");
494 printf ("\tshow - show connection details\n");
495 printf ("\tip-set <index> <ip-addr> - set interface ip address\n");
497 ("\trx-mode <index> <qid> <polling|interrupt> - set queue rx mode\n");
503 /* application cleanup */
506 for (i = 0; i < MAX_CONNS; i++)
508 memif_connection_t *c = &memif_connection[i];
510 icmpr_memif_delete (i);
513 err = memif_cleanup ();
514 if (err != MEMIF_ERR_SUCCESS)
515 INFO ("memif_delete: %s", memif_strerror (err));
521 icmpr_set_ip (long index, char *ip)
523 if (index >= MAX_CONNS)
525 INFO ("connection array overflow");
530 INFO ("don't even try...");
533 memif_connection_t *c = &memif_connection[index];
536 INFO ("no connection at index %ld", index);
543 ui = strtok (ip, ".");
546 tmp[0] = strtol (ui, &end, 10);
548 ui = strtok (NULL, ".");
551 tmp[1] = strtol (ui, &end, 10);
553 ui = strtok (NULL, ".");
556 tmp[2] = strtol (ui, &end, 10);
558 ui = strtok (NULL, ".");
561 tmp[3] = strtol (ui, &end, 10);
563 c->ip_addr[0] = tmp[0];
564 c->ip_addr[1] = tmp[1];
565 c->ip_addr[2] = tmp[2];
566 c->ip_addr[3] = tmp[3];
568 INFO ("memif %ld ip address set to %u.%u.%u.%u",
569 index, c->ip_addr[0], c->ip_addr[1], c->ip_addr[2], c->ip_addr[3]);
574 INFO ("invalid ip address");
579 icmpr_set_rx_mode (long index, long qid, char *mode)
581 if (index >= MAX_CONNS)
583 INFO ("connection array overflow");
588 INFO ("don't even try...");
591 memif_connection_t *c = &memif_connection[index];
595 INFO ("no connection at index %ld", index);
599 if (strncmp (mode, "interrupt", 9) == 0)
601 memif_set_rx_mode (c->conn, MEMIF_RX_MODE_INTERRUPT, qid);
604 else if (strncmp (mode, "polling", 7) == 0)
606 memif_set_rx_mode (c->conn, MEMIF_RX_MODE_POLLING, qid);
609 INFO ("expected rx mode <interrupt|polling>");
614 user_input_handler ()
617 char *in = (char *) malloc (256);
618 char *ui = fgets (in, 256, stdin);
623 ui = strtok (in, " ");
624 if (strncmp (ui, "exit", 4) == 0)
630 else if (strncmp (ui, "help", 4) == 0)
635 else if (strncmp (ui, "conn", 4) == 0)
637 ui = strtok (NULL, " ");
639 a = strtol (ui, &end, 10);
642 INFO ("expected id");
645 ui = strtok (NULL, " ");
647 icmpr_memif_create (a, strtol (ui, &end, 10));
649 INFO ("expected mode <0|1>");
652 else if (strncmp (ui, "del", 3) == 0)
654 ui = strtok (NULL, " ");
656 icmpr_memif_delete (strtol (ui, &end, 10));
658 INFO ("expected id");
661 else if (strncmp (ui, "show", 4) == 0)
663 print_memif_details ();
666 else if (strncmp (ui, "ip-set", 6) == 0)
668 ui = strtok (NULL, " ");
670 icmpr_set_ip (strtol (ui, &end, 10), strtok (NULL, " "));
672 INFO ("expected id");
675 else if (strncmp (ui, "rx-mode", 7) == 0)
677 ui = strtok (NULL, " ");
679 a = strtol (ui, &end, 10);
682 INFO ("expected id");
685 ui = strtok (NULL, " ");
687 icmpr_set_rx_mode (a, strtol (ui, &end, 10), strtok (NULL, " "));
689 INFO ("expected qid");
694 DBG ("unknown command: %s", ui);
705 poll_event (int timeout)
707 struct epoll_event evt, *e;
708 int app_err = 0, memif_err = 0, en = 0;
711 memset (&evt, 0, sizeof (evt));
712 evt.events = EPOLLIN | EPOLLOUT;
714 sigemptyset (&sigset);
715 en = epoll_pwait (epfd, &evt, 1, timeout, &sigset);
718 DBG ("epoll_pwait: %s", strerror (errno));
723 /* this app does not use any other file descriptors than stds and memif control fds */
726 /* event of memif control fd */
727 /* convert epolle events to memif events */
728 if (evt.events & EPOLLIN)
729 events |= MEMIF_FD_EVENT_READ;
730 if (evt.events & EPOLLOUT)
731 events |= MEMIF_FD_EVENT_WRITE;
732 if (evt.events & EPOLLERR)
733 events |= MEMIF_FD_EVENT_ERROR;
734 memif_err = memif_control_fd_handler (evt.data.fd, events);
735 if (memif_err != MEMIF_ERR_SUCCESS)
736 INFO ("memif_control_fd_handler: %s", memif_strerror (memif_err));
738 else if (evt.data.fd == 0)
740 app_err = user_input_handler ();
744 DBG ("unexpected event at memif_epfd. fd %d", evt.data.fd);
748 if ((app_err < 0) || (memif_err < 0))
751 DBG ("user input handler error");
753 DBG ("memif control fd handler error");
763 epfd = epoll_create (1);
764 add_epoll_fd (0, EPOLLIN);
766 /* initialize memory interface */
768 /* if valid callback is passed as argument, fd event polling will be done by user
769 all file descriptors and events will be passed to user in this callback */
770 /* if callback is set to NULL libmemif will handle fd event polling */
771 err = memif_init (control_fd_update, APP_NAME);
772 if (err != MEMIF_ERR_SUCCESS)
773 INFO ("memif_init: %s", memif_strerror (err));
775 for (i = 0; i < MAX_CONNS; i++)
777 memif_connection[i].conn = NULL;
786 if (poll_event (-1) < 0)
788 DBG ("poll_event error!");