FD.io VPP  v21.06
Vector Packet Processing
main.c
Go to the documentation of this file.
1 /*
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:
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 <stdio.h>
20 #include <string.h>
21 #include <getopt.h>
22 #include <errno.h>
23 #include <inttypes.h>
24 #include <pthread.h>
25 #include <stdbool.h>
26 #include <unistd.h>
27 
28 #include <sys/epoll.h>
29 #include <sys/eventfd.h>
30 
31 #include <libmemif.h>
32 #include <icmp_proto.h>
33 
34 
35 #define APP_NAME "ICMP_Responder_mt_v3.1"
36 #define IF_NAME "memif_connection"
37 
38 #ifdef ICMP_DBG
39 #define DBG(...) do { \
40  printf (APP_NAME":%s:%d: ", __func__, __LINE__); \
41  printf (__VA_ARGS__); \
42  printf ("\n"); \
43  } while (0)
44 #else
45 #define DBG(...)
46 #endif
47 
48 #define ICMPR_BUFFER_LENGTH 32
49 #define ICMPR_SOCKET_FILENAME_LEN 256
50 #define ICMPR_MEMIF_BUFFER_NUM 256
51 
52 static struct option options[] = {
53  {"threads", required_argument, 0, 't'},
54  {"if_num", required_argument, 0, 'i'}
55 };
56 
58 {
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 */
64 };
65 
67 {
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 */
76 };
77 
78 struct icmpr_main
79 {
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 */
84 };
85 
87 
88 int
89 add_epoll_fd (int epfd, int fd, uint32_t events)
90 {
91  if (fd < 0)
92  {
93  DBG ("invalid fd %d", fd);
94  return -1;
95  }
96  struct epoll_event evt;
97  memset (&evt, 0, sizeof (evt));
98  evt.events = events;
99  evt.data.fd = fd;
100  if (epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &evt) < 0)
101  {
102  DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
103  return -1;
104  }
105  DBG ("fd %d added to epoll", fd);
106  return 0;
107 }
108 
109 int
110 mod_epoll_fd (int epfd, int fd, uint32_t events)
111 {
112  if (fd < 0)
113  {
114  DBG ("invalid fd %d", fd);
115  return -1;
116  }
117  struct epoll_event evt;
118  memset (&evt, 0, sizeof (evt));
119  evt.events = events;
120  evt.data.fd = fd;
121  if (epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &evt) < 0)
122  {
123  DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
124  return -1;
125  }
126  DBG ("fd %d modified on epoll", fd);
127  return 0;
128 }
129 
130 int
131 del_epoll_fd (int epfd, int fd)
132 {
133  if (fd < 0)
134  {
135  DBG ("invalid fd %d", fd);
136  return -1;
137  }
138  struct epoll_event evt;
139  memset (&evt, 0, sizeof (evt));
140  if (epoll_ctl (epfd, EPOLL_CTL_DEL, fd, &evt) < 0)
141  {
142  DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
143  return -1;
144  }
145  DBG ("fd %d removed from epoll", fd);
146  return 0;
147 }
148 
149 /* Called when libmemif requests an update on any of its file descriptors */
150 static int
151 control_fd_update (int fd, uint8_t events, void *private_ctx)
152 {
153  struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
154  uint32_t evt = 0;
155 
156  if (ptd == NULL)
157  return -1;
158 
159  /* convert memif event definitions to epoll events */
160  if (events & MEMIF_FD_EVENT_DEL)
161  return del_epoll_fd (ptd->epfd, fd);
162 
163  if (events & MEMIF_FD_EVENT_READ)
164  evt |= EPOLLIN;
165  if (events & MEMIF_FD_EVENT_WRITE)
166  evt |= EPOLLOUT;
167 
168  if (events & MEMIF_FD_EVENT_MOD)
169  return mod_epoll_fd (ptd->epfd, fd, evt);
170 
171  return add_epoll_fd (ptd->epfd, fd, evt);
172 }
173 
174 static int
176 {
177  struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
178  struct memif_connection *c;
179  int i = 0;
180 
181  while (i < ptd->if_num && ptd->conns[i].handle != conn)
182  i++;
183  c = &ptd->conns[i];
184 
185  c->connected = true;
186  DBG ("Connected: %u", c->id);
187 
188  memif_refill_queue (conn, 0, -1, 0);
189 
190  return 0;
191 }
192 
193 static int
195 {
196  struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
197  struct memif_connection *c;
198  int i = 0;
199 
200  while (i < ptd->if_num && ptd->conns[i].handle != conn)
201  i++;
202  c = &ptd->conns[i];
203 
204  c->connected = false;
205  DBG ("Disconnected: %u", c->id);
206 
207  return 0;
208 }
209 
210 static int
211 on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
212 {
213  struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
214  struct memif_connection *c;
216  uint16_t rx = 0;
217  uint16_t tx = 0;
218  uint16_t ret;
219  memif_err_t err;
220  int i = 0;
221 
222  memset (mbufs, 0, sizeof (memif_buffer_t) * ICMPR_MEMIF_BUFFER_NUM);
223 
224  while (i < ptd->if_num && ptd->conns[i].handle != conn)
225  i++;
226  c = &ptd->conns[i];
227 
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)
231  {
232  printf ("memif_rx_burst: %s\n", memif_strerror (err));
233  goto error;
234  }
235 
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);
239 
240  /* enqueue received buffers */
241  err = memif_buffer_enq_tx (conn, qid, mbufs, i, &tx);
242  if (err != MEMIF_ERR_SUCCESS)
243  {
244  printf ("memif_rx_burst: %s\n", memif_strerror (err));
245  goto error;
246  }
247 
248  /* mark shared memory buffers as free */
249  err = memif_refill_queue (conn, qid, rx, 0);
250  if (err != MEMIF_ERR_SUCCESS)
251  {
252  printf ("memif_rx_burst: %s\n", memif_strerror (err));
253  goto error;
254  }
255 
256  err = memif_tx_burst (conn, qid, mbufs, tx, &ret);
257  if (err != MEMIF_ERR_SUCCESS)
258  {
259  printf ("memif_rx_burst: %s\n", memif_strerror (err));
260  goto error;
261  }
262 
263  return 0;
264 
265 error:
266  memif_refill_queue (conn, qid, -1, 0);
267  return -1;
268 }
269 
270 int
272  int timeout)
273 {
274  struct epoll_event evt;
275  int en = 0;
276  uint8_t events = 0;
277  memset (&evt, 0, sizeof (evt));
278  evt.events = EPOLLIN | EPOLLOUT;
279 
280  en = epoll_pwait (epfd, &evt, 1, timeout, NULL);
281  if (en < 0)
282  {
283  printf ("epoll_pwait: %s\n", strerror (errno));
284  return -1;
285  }
286 
287  if (en > 0)
288  {
289  /* Cancel event polling */
290  if (evt.data.fd == pcfd)
291  return 1;
292 
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;
299 
300  /* No need to use locks, as the database is separated */
301  memif_per_thread_control_fd_handler (pt_main, evt.data.fd, events);
302  }
303 
304  return 0;
305 }
306 
307 static void *
309 {
310  struct per_thread_data *ptd = (struct per_thread_data *) data;
311  int rv;
312  uint16_t i;
313  char socket_filename[ICMPR_SOCKET_FILENAME_LEN] = "/run/vpp/memif";
315 
316  ptd->epfd = epoll_create (1);
317 
318  ptd->conns = malloc (sizeof (struct memif_connection) * ptd->if_num);
319  if (ptd->conns == NULL)
320  {
321  printf ("%s\n", strerror (errno));
322  return NULL;
323  }
324 
325  memset (ptd->conns, 0, sizeof (struct memif_connection) * ptd->if_num);
326 
327  /* Initialize memif database (per thread). */
328  rv =
330  NULL, NULL, NULL);
331  if (rv != MEMIF_ERR_SUCCESS)
332  {
333  printf ("memif_per_thread_init: %s\n", memif_strerror (rv));
334  return NULL;
335  }
336 
337  /* Create unique socket. Each thread requires a unique socket. Interfaces created
338  * on the same thread can share one socket.
339  */
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);
343 
345  socket_filename, ptd);
346  if (rv != MEMIF_ERR_SUCCESS)
347  {
348  printf ("memif_per_thread_create_socket: %s\n", memif_strerror (rv));
349  return NULL;
350  }
351 
352  /* Create interfaces on this thread */
353  for (i = 0; i < ptd->if_num; i++)
354  {
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;
359 
360  memset (&args, 0, sizeof (args));
361 
362  args.socket = ptd->socket_handle;
363  ptd->conns[i].id = i;
364  args.interface_id = i;
365 
366  rv = memif_create (&ptd->conns[i].handle, &args, on_connect,
368  if (rv < 0)
369  {
370  printf ("%s\n", memif_strerror (rv));
371  return NULL;
372  }
373  }
374 
375  /* Poll cancel file descriptor. When an event is received on this fd, exit thread
376  * loop in respective thread.
377  */
378  ptd->pcfd = eventfd (0, EFD_NONBLOCK);
379  if (ptd->pcfd < 0)
380  {
381  printf ("eventfd: %s\n", strerror (errno));
382  return NULL;
383  }
384  if (add_epoll_fd (ptd->epfd, ptd->pcfd, EPOLLIN) < 0)
385  {
386  printf ("Failed to add poll cancel fd to epfd.");
387  return NULL;
388  }
389 
390  /* Thread loop */
391  ptd->running = true;
392  while (ptd->running)
393  {
394  rv = poll_event (ptd->pt_main, ptd->pcfd, ptd->epfd, -1);
395  if (rv != 0)
396  ptd->running = false;
397  }
398 
399  /* Clean up */
400  for (i = 0; i < ptd->if_num; i++)
401  memif_delete (&ptd->conns[i].handle);
402 
404 
406 
407  free (ptd->conns);
408  close (ptd->pcfd);
409 
410  return NULL;
411 }
412 
413 static void
415 {
416  printf
417  ("exit - Exits the application.\nhelp - Print this help.\nshow - Show memif interfaces\n");
418 }
419 
420 static void
422 {
423  struct icmpr_main *im = &icmpr_main;
424  int i, j;
426 
427  printf ("%u Threads %u Memifs (per thread)\n", im->threads,
428  im->per_thread_if_num);
429  printf ("=================================\n");
430 
431  for (i = 0; i < im->threads; i++)
432  {
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++)
436  {
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");
439  }
440  }
441 }
442 
443 int
444 main (int argc, char **argv)
445 {
446  struct icmpr_main *im = &icmpr_main;
447  int rv, i;
448  int option_index = 0;
449  bool running;
451  uint64_t b = 1;
452 
453  memset (im, 0, sizeof (struct icmpr_main));
454 
455  /* Default args */
456  im->threads = 4;
457  im->per_thread_if_num = 1;
458 
459  /* Parse args */
460  while ((rv =
461  getopt_long (argc, argv, "t:i:", options, &option_index)) != (-1))
462  {
463  switch (rv)
464  {
465  case 't':
466  im->threads = strtoul (optarg, NULL, 10);
467  break;
468  case 'i':
469  im->per_thread_if_num = strtoul (optarg, NULL, 10);
470  break;
471  default:
472  break;
473  }
474  }
475 
476  /* Check args */
477  if (im->threads < 1)
478  {
479  printf ("threads < 1\n");
480  exit (EXIT_FAILURE);
481  }
482 
483  if (im->per_thread_if_num < 1)
484  {
485  printf ("if_num < 1\n");
486  exit (EXIT_FAILURE);
487  }
488 
489  /* Allocate memory */
490  im->ptd = malloc (sizeof (struct per_thread_data) * im->threads);
491  if (im->ptd == NULL)
492  {
493  printf ("%s\n", strerror (errno));
494  return -1;
495  }
496  im->pthread = malloc (sizeof (pthread_t) * im->threads);
497  if (im->pthread == NULL)
498  {
499  printf ("%s\n", strerror (errno));
500  return -1;
501  }
502 
503  /* Initialize and create threads */
504  for (i = 0; i < im->threads; i++)
505  {
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]);
509  }
510 
511  icmpr_print_help ();
512 
513  /* Main loop */
514  running = true;
515  while (running)
516  {
517  printf ("cmd: ");
518  memset (buffer, 0, ICMPR_BUFFER_LENGTH);
519  if (fgets (buffer, ICMPR_BUFFER_LENGTH, stdin) != buffer)
520  {
521  printf ("%s\n", strerror (errno));
522  running = false;
523  }
524 
525  if (strncmp (buffer, "exit", 4) == 0)
526  running = false;
527  else if (strncmp (buffer, "help", 4) == 0)
528  icmpr_print_help ();
529  else if (strncmp (buffer, "show", 4) == 0)
531  }
532 
533  for (i = 0; i < im->threads; i++)
534  {
535  /* Stop polling */
536  rv = write (im->ptd[i].pcfd, &b, sizeof (b));
537  if (rv < 0)
538  {
539  printf ("Failed to cancel polling. %s\n", strerror (errno));
540  exit (EXIT_FAILURE);
541  }
542  pthread_join (im->pthread[i], NULL);
543  }
544 
545  free (im->pthread);
546  free (im->ptd);
547 
548  return 0;
549 }
struct memif_connection * conns
Definition: main.c:73
uint8_t threads
Definition: main.c:80
#define ICMPR_SOCKET_FILENAME_LEN
Definition: main.c:49
bool running
Definition: main.c:68
int add_epoll_fd(int fd, uint32_t events)
Definition: main.c:302
struct per_thread_data * ptd
Definition: main.c:82
memif_socket_handle_t socket_handle
Definition: main.c:75
#define MEMIF_FD_EVENT_READ
user needs to set events that occurred on fd and pass them to memif_control_fd_handler ...
Definition: libmemif.h:91
int del_epoll_fd(int fd)
Definition: main.c:344
Optimized string handling code, including c11-compliant "safe C library" variants.
struct per_thread_data * ptd
Definition: main.c:61
int pcfd
Definition: main.c:71
uint32_t interface_id
Definition: libmemif.h:306
uint8_t ip_addr[4]
Definition: main.c:63
uint16_t if_num
Definition: main.c:72
int resolve_packet2(void *pck, uint32_t *size, uint8_t ip_addr[4])
Definition: icmp_proto.c:381
memif_conn_args_t args
memif_socket_handle_t socket
Definition: libmemif.h:297
memif_per_thread_main_handle_t pt_main
Definition: main.c:74
vlib_buffer_t ** b
uint16_t per_thread_if_num
Definition: main.c:81
u8 data[128]
Definition: ipsec_types.api:92
int poll_event(int timeout)
Definition: main.c:975
int memif_refill_queue(memif_conn_handle_t conn, uint16_t qid, uint16_t count, uint16_t headroom)
Memif refill queue.
Definition: main.c:2389
memif_connection_update_t * on_disconnect
const char * memif_get_socket_filename(memif_socket_handle_t sock)
Get socket filename.
Definition: main.c:1753
int control_fd_update(int fd, uint8_t events, void *ctx)
Definition: main.c:378
int memif_per_thread_init(memif_per_thread_main_handle_t *pt_main, void *private_ctx, memif_control_fd_update_t *on_control_fd_update, char *app_name, memif_alloc_t *memif_alloc, memif_realloc_t *memif_realloc, memif_free_t *memif_free)
Memif per thread initialization.
Definition: main.c:650
char * memif_strerror(int err_code)
Memif strerror.
Definition: main.c:157
#define ICMPR_BUFFER_LENGTH
Definition: main.c:48
static perfmon_event_t events[]
Definition: core.c:21
int __clib_unused rv
Definition: application.c:491
Definition: cJSON.c:88
memif_conn_handle_t handle
Definition: main.c:62
#define MEMIF_FD_EVENT_DEL
if set, informs that fd is going to be closed (user may want to stop watching for events on this fd) ...
Definition: libmemif.h:96
static void icmpr_print_help()
Definition: main.c:414
void * memif_socket_handle_t
Memif socket handle pointer of type void, pointing to internal structure.
Definition: libmemif.h:115
int memif_buffer_enq_tx(memif_conn_handle_t conn, uint16_t qid, memif_buffer_t *bufs, uint16_t count, uint16_t *count_out)
Memif buffer enq tx.
Definition: main.c:2204
void * malloc(size_t size)
Definition: mem.c:33
#define ICMPR_MEMIF_BUFFER_NUM
Definition: main.c:50
struct icmpr_main icmpr_main
Definition: main.c:86
u8 len
Definition: ip_types.api:103
#define APP_NAME
Definition: main.c:35
svmdb_client_t * c
int memif_per_thread_create_socket(memif_per_thread_main_handle_t pt_main, memif_socket_handle_t *sock, const char *filename, void *private_ctx)
Create memif socket.
Definition: main.c:992
int memif_tx_burst(memif_conn_handle_t conn, uint16_t qid, memif_buffer_t *bufs, uint16_t count, uint16_t *tx)
Memif transmit buffer burst.
Definition: main.c:2444
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
char * buffer
Definition: cJSON.h:163
vnet_interface_main_t * im
int memif_per_thread_control_fd_handler(memif_per_thread_main_handle_t pt_main, int fd, uint8_t events)
Memif per thread control file descriptor handler.
Definition: main.c:1389
uint8_t index
Definition: main.c:69
void free(void *p)
Definition: mem.c:42
bool connected
Definition: main.c:60
memif_connection_update_t * on_connect
int memif_create(memif_conn_handle_t *c, memif_conn_args_t *args, memif_connection_update_t *on_connect, memif_connection_update_t *on_disconnect, memif_interrupt_t *on_interrupt, void *private_ctx)
Memory interface create function.
Definition: main.c:1065
int epfd
Definition: main.c:70
void * memif_per_thread_main_handle_t
Memif per thread main handle Pointer of type void, pointing to internal structure.
Definition: libmemif.h:105
memif_err_t
Definition: libmemif.h:36
void * memif_conn_handle_t
Memif connection handle pointer of type void, pointing to internal structure.
Definition: libmemif.h:110
memif_interrupt_t * on_interrupt
int mod_epoll_fd(int fd, uint32_t events)
Definition: main.c:323
int epfd
Definition: main.c:94
int memif_rx_burst(memif_conn_handle_t conn, uint16_t qid, memif_buffer_t *bufs, uint16_t count, uint16_t *rx)
Memif receive buffer burst.
Definition: main.c:2545
int memif_delete(memif_conn_handle_t *conn)
Memif delete.
Definition: main.c:1784
int memif_per_thread_cleanup(memif_per_thread_main_handle_t *pt_main)
Memif per thread cleanup.
Definition: main.c:2849
static struct option options[]
Definition: main.c:52
static void icmpr_show_memifs()
Definition: main.c:421
#define MEMIF_FD_EVENT_ERROR
inform libmemif that error occurred on fd
Definition: libmemif.h:94
#define MEMIF_FD_EVENT_MOD
update events
Definition: libmemif.h:98
uint16_t id
Definition: main.c:59
int main(int argc, char *argv[])
Definition: main.c:106
int memif_delete_socket(memif_socket_handle_t *sock)
Delete memif socket.
Definition: main.c:1764
pthread_t * pthread
Definition: main.c:83
Memif buffer.
Definition: libmemif.h:325
#define MEMIF_FD_EVENT_WRITE
Definition: libmemif.h:92
Memif connection arguments.
Definition: libmemif.h:295
#define DBG(...)
Definition: main.c:45
static void * icmpr_thread_fn(void *data)
Definition: main.c:308