2 *------------------------------------------------------------------
3 * Copyright (c) 2019 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 *------------------------------------------------------------------
28 #include <sys/epoll.h>
29 #include <sys/eventfd.h>
32 #include <icmp_proto.h>
35 #define APP_NAME "ICMP_Responder_mt_v3.1"
36 #define IF_NAME "memif_connection"
39 #define DBG(...) do { \
40 printf (APP_NAME":%s:%d: ", __func__, __LINE__); \
41 printf (__VA_ARGS__); \
48 #define ICMPR_BUFFER_LENGTH 32
49 #define ICMPR_SOCKET_FILENAME_LEN 256
50 #define ICMPR_MEMIF_BUFFER_NUM 256
52 static struct option options[] = {
53 {"threads", required_argument, 0, 't'},
54 {"if_num", required_argument, 0, 'i'}
57 struct memif_connection
59 uint16_t id; /* unique interface id */
60 bool connected; /* is connected */
61 struct per_thread_data *ptd; /* per thread data */
62 memif_conn_handle_t handle; /* memif connection handle */
63 uint8_t ip_addr[4]; /* ip4 address */
66 struct per_thread_data
68 bool running; /* is thread main loop running */
69 uint8_t index; /* thread index */
70 int epfd; /* epoll file descriptor */
71 int pcfd; /* poll cancel file descriptor */
72 uint16_t if_num; /* number of interfaces on this thread */
73 struct memif_connection *conns; /* memif connections pool */
74 memif_per_thread_main_handle_t pt_main; /* memif per thread main handle */
75 memif_socket_handle_t socket_handle; /* memif socket handle */
80 uint8_t threads; /* number of threads */
81 uint16_t per_thread_if_num; /* number of interfaces per thread */
82 struct per_thread_data *ptd; /* per thread data pool */
83 pthread_t *pthread; /* thread pool */
86 struct icmpr_main icmpr_main;
89 add_epoll_fd (int epfd, int fd, uint32_t events)
93 DBG ("invalid fd %d", fd);
96 struct epoll_event evt;
97 memset (&evt, 0, sizeof (evt));
100 if (epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &evt) < 0)
102 DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
105 DBG ("fd %d added to epoll", fd);
110 mod_epoll_fd (int epfd, int fd, uint32_t events)
114 DBG ("invalid fd %d", fd);
117 struct epoll_event evt;
118 memset (&evt, 0, sizeof (evt));
121 if (epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &evt) < 0)
123 DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
126 DBG ("fd %d moddified on epoll", fd);
131 del_epoll_fd (int epfd, int fd)
135 DBG ("invalid fd %d", fd);
138 struct epoll_event evt;
139 memset (&evt, 0, sizeof (evt));
140 if (epoll_ctl (epfd, EPOLL_CTL_DEL, fd, &evt) < 0)
142 DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
145 DBG ("fd %d removed from epoll", fd);
149 /* Called when libmemif requests an update on any of its file descriptors */
151 control_fd_update (int fd, uint8_t events, void *private_ctx)
153 struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
159 /* convert memif event definitions to epoll events */
160 if (events & MEMIF_FD_EVENT_DEL)
161 return del_epoll_fd (ptd->epfd, fd);
163 if (events & MEMIF_FD_EVENT_READ)
165 if (events & MEMIF_FD_EVENT_WRITE)
168 if (events & MEMIF_FD_EVENT_MOD)
169 return mod_epoll_fd (ptd->epfd, fd, evt);
171 return add_epoll_fd (ptd->epfd, fd, evt);
175 on_connect (memif_conn_handle_t conn, void *private_ctx)
177 struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
178 struct memif_connection *c;
181 while (i < ptd->if_num && ptd->conns[i].handle != conn)
186 DBG ("Connected: %u", c->id);
188 memif_refill_queue (conn, 0, -1, 0);
194 on_disconnect (memif_conn_handle_t conn, void *private_ctx)
196 struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
197 struct memif_connection *c;
200 while (i < ptd->if_num && ptd->conns[i].handle != conn)
204 c->connected = false;
205 DBG ("Disconnected: %u", c->id);
211 on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
213 struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
214 struct memif_connection *c;
215 memif_buffer_t mbufs[ICMPR_MEMIF_BUFFER_NUM];
222 memset (mbufs, 0, sizeof (memif_buffer_t) * ICMPR_MEMIF_BUFFER_NUM);
224 while (i < ptd->if_num && ptd->conns[i].handle != conn)
228 /* receive data from shared memory buffers */
229 err = memif_rx_burst (conn, qid, mbufs, ICMPR_MEMIF_BUFFER_NUM, &rx);
230 if (err != MEMIF_ERR_SUCCESS)
232 printf ("memif_rx_burst: %s\n", memif_strerror (err));
236 /* resolve packet in place (zer-copy slave) */
237 for (i = 0; i < rx; i++)
238 resolve_packet2 (mbufs[i].data, &mbufs[i].len, c->ip_addr);
240 /* enqueue received buffers */
241 err = memif_buffer_enq_tx (conn, qid, mbufs, i, &tx);
242 if (err != MEMIF_ERR_SUCCESS)
244 printf ("memif_rx_burst: %s\n", memif_strerror (err));
248 /* mark shared memory buffers as free */
249 err = memif_refill_queue (conn, qid, rx, 0);
250 if (err != MEMIF_ERR_SUCCESS)
252 printf ("memif_rx_burst: %s\n", memif_strerror (err));
256 err = memif_tx_burst (conn, qid, mbufs, tx, &ret);
257 if (err != MEMIF_ERR_SUCCESS)
259 printf ("memif_rx_burst: %s\n", memif_strerror (err));
266 memif_refill_queue (conn, qid, -1, 0);
271 poll_event (memif_per_thread_main_handle_t pt_main, int pcfd, int epfd,
274 struct epoll_event evt;
277 memset (&evt, 0, sizeof (evt));
278 evt.events = EPOLLIN | EPOLLOUT;
280 en = epoll_pwait (epfd, &evt, 1, timeout, NULL);
283 printf ("epoll_pwait: %s\n", strerror (errno));
289 /* Cancel event polling */
290 if (evt.data.fd == pcfd)
293 if (evt.events & EPOLLIN)
294 events |= MEMIF_FD_EVENT_READ;
295 if (evt.events & EPOLLOUT)
296 events |= MEMIF_FD_EVENT_WRITE;
297 if (evt.events & EPOLLERR)
298 events |= MEMIF_FD_EVENT_ERROR;
300 /* No need to use locks, as the database is separated */
301 memif_per_thread_control_fd_handler (pt_main, evt.data.fd, events);
308 icmpr_thread_fn (void *data)
310 struct per_thread_data *ptd = (struct per_thread_data *) data;
313 char socket_filename[ICMPR_SOCKET_FILENAME_LEN] = "/run/vpp/memif";
314 memif_conn_args_t args;
316 ptd->epfd = epoll_create (1);
318 ptd->conns = malloc (sizeof (struct memif_connection) * ptd->if_num);
319 if (ptd->conns == NULL)
321 printf ("%s\n", strerror (errno));
325 memset (ptd->conns, 0, sizeof (struct memif_connection) * ptd->if_num);
327 /* Initialize memif database (per thread). */
329 memif_per_thread_init (&ptd->pt_main, ptd, control_fd_update, APP_NAME,
331 if (rv != MEMIF_ERR_SUCCESS)
333 printf ("memif_per_thread_init: %s\n", memif_strerror (rv));
337 /* Create unique socket. Each thread requires uniqueue socket. Interfaces created
338 * on the same thread can share one socket.
340 socket_filename[strlen (socket_filename)] = '0' + ptd->index;
341 strncpy (socket_filename + strlen (socket_filename), ".sock", 5);
342 DBG ("socket_filename: %s", socket_filename);
344 rv = memif_per_thread_create_socket (ptd->pt_main, &ptd->socket_handle,
345 socket_filename, ptd);
346 if (rv != MEMIF_ERR_SUCCESS)
348 printf ("memif_per_thread_create_socket: %s\n", memif_strerror (rv));
352 /* Create interfaces on this thread */
353 for (i = 0; i < ptd->if_num; i++)
355 ptd->conns[i].ip_addr[0] = 192;
356 ptd->conns[i].ip_addr[1] = 168;
357 ptd->conns[i].ip_addr[2] = ptd->index + 1;
358 ptd->conns[i].ip_addr[3] = i * 2 + 2;
360 memset (&args, 0, sizeof (args));
362 args.socket = ptd->socket_handle;
363 ptd->conns[i].id = i;
364 args.interface_id = i;
366 rv = memif_create (&ptd->conns[i].handle, &args, on_connect,
367 on_disconnect, on_interrupt, ptd);
370 printf ("%s\n", memif_strerror (rv));
375 /* Poll cancel file descriptor. When an event is received on this fd, exit thread
376 * loop in respective thread.
378 ptd->pcfd = eventfd (0, EFD_NONBLOCK);
381 printf ("eventfd: %s\n", strerror (errno));
384 if (add_epoll_fd (ptd->epfd, ptd->pcfd, EPOLLIN) < 0)
386 printf ("Failed to add poll cancel fd to epfd.");
394 rv = poll_event (ptd->pt_main, ptd->pcfd, ptd->epfd, -1);
396 ptd->running = false;
400 for (i = 0; i < ptd->if_num; i++)
401 memif_delete (&ptd->conns[i].handle);
403 memif_delete_socket (&ptd->socket_handle);
405 memif_per_thread_cleanup (&ptd->pt_main);
417 ("exit - Exits the application.\nhelp - Print this help.\nshow - Show memif interfaces\n");
423 struct icmpr_main *im = &icmpr_main;
425 memif_socket_handle_t sh;
427 printf ("%u Threads %u Memifs (per thread)\n", im->threads,
428 im->per_thread_if_num);
429 printf ("=================================\n");
431 for (i = 0; i < im->threads; i++)
433 sh = im->ptd[i].socket_handle;
434 printf ("Thread %u %s\n", i, memif_get_socket_filename (sh));
435 for (j = 0; j < im->per_thread_if_num; j++)
437 printf ("\tMemif id %u\n\t%s\n", im->ptd[i].conns[j].id,
438 im->ptd[i].conns[j].connected ? "Link up" : "Link down");
444 main (int argc, char **argv)
446 struct icmpr_main *im = &icmpr_main;
448 int option_index = 0;
450 char buffer[ICMPR_BUFFER_LENGTH];
453 memset (im, 0, sizeof (struct icmpr_main));
457 im->per_thread_if_num = 1;
461 getopt_long (argc, argv, "t:i:", options, &option_index)) != (-1))
466 im->threads = strtoul (optarg, NULL, 10);
469 im->per_thread_if_num = strtoul (optarg, NULL, 10);
479 printf ("threads < 1\n");
483 if (im->per_thread_if_num < 1)
485 printf ("if_num < 1\n");
489 /* Allocate memory */
490 im->ptd = malloc (sizeof (struct per_thread_data) * im->threads);
493 printf ("%s\n", strerror (errno));
496 im->pthread = malloc (sizeof (pthread_t) * im->threads);
497 if (im->pthread == NULL)
499 printf ("%s\n", strerror (errno));
503 /* Initialize and create threads */
504 for (i = 0; i < im->threads; i++)
506 im->ptd[i].index = i;
507 im->ptd[i].if_num = im->per_thread_if_num;
508 pthread_create (&im->pthread[i], NULL, icmpr_thread_fn, &im->ptd[i]);
518 memset (buffer, 0, ICMPR_BUFFER_LENGTH);
519 if (fgets (buffer, ICMPR_BUFFER_LENGTH, stdin) != buffer)
521 printf ("%s\n", strerror (errno));
525 if (strncmp (buffer, "exit", 4) == 0)
527 else if (strncmp (buffer, "help", 4) == 0)
529 else if (strncmp (buffer, "show", 4) == 0)
530 icmpr_show_memifs ();
533 for (i = 0; i < im->threads; i++)
536 rv = write (im->ptd[i].pcfd, &b, sizeof (b));
539 printf ("Failed to cancel polling. %s\n", strerror (errno));
542 pthread_join (im->pthread[i], NULL);