117f2a7bbSJakub Grajciar/*
217f2a7bbSJakub Grajciar *------------------------------------------------------------------
317f2a7bbSJakub Grajciar * Copyright (c) 2019 Cisco and/or its affiliates.
417f2a7bbSJakub Grajciar * Licensed under the Apache License, Version 2.0 (the "License");
517f2a7bbSJakub Grajciar * you may not use this file except in compliance with the License.
617f2a7bbSJakub Grajciar * You may obtain a copy of the License at:
717f2a7bbSJakub Grajciar *
817f2a7bbSJakub Grajciar *     http://www.apache.org/licenses/LICENSE-2.0
917f2a7bbSJakub Grajciar *
1017f2a7bbSJakub Grajciar * Unless required by applicable law or agreed to in writing, software
1117f2a7bbSJakub Grajciar * distributed under the License is distributed on an "AS IS" BASIS,
1217f2a7bbSJakub Grajciar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1317f2a7bbSJakub Grajciar * See the License for the specific language governing permissions and
1417f2a7bbSJakub Grajciar * limitations under the License.
1517f2a7bbSJakub Grajciar *------------------------------------------------------------------
1617f2a7bbSJakub Grajciar */
1717f2a7bbSJakub Grajciar
1817f2a7bbSJakub Grajciar#include <stdlib.h>
1917f2a7bbSJakub Grajciar#include <stdio.h>
2017f2a7bbSJakub Grajciar#include <string.h>
2117f2a7bbSJakub Grajciar#include <getopt.h>
2217f2a7bbSJakub Grajciar#include <errno.h>
2317f2a7bbSJakub Grajciar#include <inttypes.h>
2417f2a7bbSJakub Grajciar#include <pthread.h>
2517f2a7bbSJakub Grajciar#include <stdbool.h>
2617f2a7bbSJakub Grajciar#include <unistd.h>
2717f2a7bbSJakub Grajciar
2817f2a7bbSJakub Grajciar#include <sys/epoll.h>
2917f2a7bbSJakub Grajciar#include <sys/eventfd.h>
3017f2a7bbSJakub Grajciar
3117f2a7bbSJakub Grajciar#include <libmemif.h>
3217f2a7bbSJakub Grajciar#include <icmp_proto.h>
3317f2a7bbSJakub Grajciar
3417f2a7bbSJakub Grajciar
3517f2a7bbSJakub Grajciar#define APP_NAME "ICMP_Responder_mt_v3.1"
3617f2a7bbSJakub Grajciar#define IF_NAME  "memif_connection"
3717f2a7bbSJakub Grajciar
3817f2a7bbSJakub Grajciar#ifdef ICMP_DBG
3917f2a7bbSJakub Grajciar#define DBG(...) do {                                               \
4017f2a7bbSJakub Grajciar                    printf (APP_NAME":%s:%d: ", __func__, __LINE__);         \
4117f2a7bbSJakub Grajciar                    printf (__VA_ARGS__);                           \
4217f2a7bbSJakub Grajciar                    printf ("\n");                                  \
4317f2a7bbSJakub Grajciar                } while (0)
4417f2a7bbSJakub Grajciar#else
4517f2a7bbSJakub Grajciar#define DBG(...)
4617f2a7bbSJakub Grajciar#endif
4717f2a7bbSJakub Grajciar
4817f2a7bbSJakub Grajciar#define ICMPR_BUFFER_LENGTH		32
4917f2a7bbSJakub Grajciar#define ICMPR_SOCKET_FILENAME_LEN	256
5017f2a7bbSJakub Grajciar#define ICMPR_MEMIF_BUFFER_NUM		256
5117f2a7bbSJakub Grajciar
5217f2a7bbSJakub Grajciarstatic struct option options[] = {
5317f2a7bbSJakub Grajciar  {"threads", required_argument, 0, 't'},
5417f2a7bbSJakub Grajciar  {"if_num", required_argument, 0, 'i'}
5517f2a7bbSJakub Grajciar};
5617f2a7bbSJakub Grajciar
5717f2a7bbSJakub Grajciarstruct memif_connection
5817f2a7bbSJakub Grajciar{
5917f2a7bbSJakub Grajciar  uint16_t id;			/* unique interface id */
6017f2a7bbSJakub Grajciar  bool connected;		/* is connected */
6117f2a7bbSJakub Grajciar  struct per_thread_data *ptd;	/* per thread data */
6217f2a7bbSJakub Grajciar  memif_conn_handle_t handle;	/* memif connection handle */
6317f2a7bbSJakub Grajciar  uint8_t ip_addr[4];		/* ip4 address */
6417f2a7bbSJakub Grajciar};
6517f2a7bbSJakub Grajciar
6617f2a7bbSJakub Grajciarstruct per_thread_data
6717f2a7bbSJakub Grajciar{
6817f2a7bbSJakub Grajciar  bool running;			/* is thread main loop running */
6917f2a7bbSJakub Grajciar  uint8_t index;		/* thread index */
7017f2a7bbSJakub Grajciar  int epfd;			/* epoll file descriptor */
7117f2a7bbSJakub Grajciar  int pcfd;			/* poll cancel file descriptor */
7217f2a7bbSJakub Grajciar  uint16_t if_num;		/* number of interfaces on this thread */
7317f2a7bbSJakub Grajciar  struct memif_connection *conns;	/* memif connections pool */
7417f2a7bbSJakub Grajciar  memif_per_thread_main_handle_t pt_main;	/* memif per thread main handle */
7517f2a7bbSJakub Grajciar  memif_socket_handle_t socket_handle;		/* memif socket handle */
7617f2a7bbSJakub Grajciar};
7717f2a7bbSJakub Grajciar
7817f2a7bbSJakub Grajciarstruct icmpr_main
7917f2a7bbSJakub Grajciar{
8017f2a7bbSJakub Grajciar  uint8_t threads;		/* number of threads */
8117f2a7bbSJakub Grajciar  uint16_t per_thread_if_num;	/* number of interfaces per thread */
8217f2a7bbSJakub Grajciar  struct per_thread_data *ptd;	/* per thread data pool */
8317f2a7bbSJakub Grajciar  pthread_t *pthread;		/* thread pool */
8417f2a7bbSJakub Grajciar};
8517f2a7bbSJakub Grajciar
8617f2a7bbSJakub Grajciarstruct icmpr_main icmpr_main;
8717f2a7bbSJakub Grajciar
8817f2a7bbSJakub Grajciarint
8917f2a7bbSJakub Grajciaradd_epoll_fd (int epfd, int fd, uint32_t events)
9017f2a7bbSJakub Grajciar{
9117f2a7bbSJakub Grajciar  if (fd < 0)
9217f2a7bbSJakub Grajciar    {
9317f2a7bbSJakub Grajciar      DBG ("invalid fd %d", fd);
9417f2a7bbSJakub Grajciar      return -1;
9517f2a7bbSJakub Grajciar    }
9617f2a7bbSJakub Grajciar  struct epoll_event evt;
9717f2a7bbSJakub Grajciar  memset (&evt, 0, sizeof (evt));
9817f2a7bbSJakub Grajciar  evt.events = events;
9917f2a7bbSJakub Grajciar  evt.data.fd = fd;
10017f2a7bbSJakub Grajciar  if (epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &evt) < 0)
10117f2a7bbSJakub Grajciar    {
10217f2a7bbSJakub Grajciar      DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
10317f2a7bbSJakub Grajciar      return -1;
10417f2a7bbSJakub Grajciar    }
10517f2a7bbSJakub Grajciar  DBG ("fd %d added to epoll", fd);
10617f2a7bbSJakub Grajciar  return 0;
10717f2a7bbSJakub Grajciar}
10817f2a7bbSJakub Grajciar
10917f2a7bbSJakub Grajciarint
11017f2a7bbSJakub Grajciarmod_epoll_fd (int epfd, int fd, uint32_t events)
11117f2a7bbSJakub Grajciar{
11217f2a7bbSJakub Grajciar  if (fd < 0)
11317f2a7bbSJakub Grajciar    {
11417f2a7bbSJakub Grajciar      DBG ("invalid fd %d", fd);
11517f2a7bbSJakub Grajciar      return -1;
11617f2a7bbSJakub Grajciar    }
11717f2a7bbSJakub Grajciar  struct epoll_event evt;
11817f2a7bbSJakub Grajciar  memset (&evt, 0, sizeof (evt));
11917f2a7bbSJakub Grajciar  evt.events = events;
12017f2a7bbSJakub Grajciar  evt.data.fd = fd;
12117f2a7bbSJakub Grajciar  if (epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &evt) < 0)
12217f2a7bbSJakub Grajciar    {
12317f2a7bbSJakub Grajciar      DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
12417f2a7bbSJakub Grajciar      return -1;
12517f2a7bbSJakub Grajciar    }
12617f2a7bbSJakub Grajciar  DBG ("fd %d moddified on epoll", fd);
12717f2a7bbSJakub Grajciar  return 0;
12817f2a7bbSJakub Grajciar}
12917f2a7bbSJakub Grajciar
13017f2a7bbSJakub Grajciarint
13117f2a7bbSJakub Grajciardel_epoll_fd (int epfd, int fd)
13217f2a7bbSJakub Grajciar{
13317f2a7bbSJakub Grajciar  if (fd < 0)
13417f2a7bbSJakub Grajciar    {
13517f2a7bbSJakub Grajciar      DBG ("invalid fd %d", fd);
13617f2a7bbSJakub Grajciar      return -1;
13717f2a7bbSJakub Grajciar    }
13817f2a7bbSJakub Grajciar  struct epoll_event evt;
13917f2a7bbSJakub Grajciar  memset (&evt, 0, sizeof (evt));
14017f2a7bbSJakub Grajciar  if (epoll_ctl (epfd, EPOLL_CTL_DEL, fd, &evt) < 0)
14117f2a7bbSJakub Grajciar    {
14217f2a7bbSJakub Grajciar      DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
14317f2a7bbSJakub Grajciar      return -1;
14417f2a7bbSJakub Grajciar    }
14517f2a7bbSJakub Grajciar  DBG ("fd %d removed from epoll", fd);
14617f2a7bbSJakub Grajciar  return 0;
14717f2a7bbSJakub Grajciar}
14817f2a7bbSJakub Grajciar
14917f2a7bbSJakub Grajciar/* Called when libmemif requests an update on any of its file descriptors */
15017f2a7bbSJakub Grajciarstatic int
15117f2a7bbSJakub Grajciarcontrol_fd_update (int fd, uint8_t events, void *private_ctx)
15217f2a7bbSJakub Grajciar{
15317f2a7bbSJakub Grajciar  struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
15417f2a7bbSJakub Grajciar  uint32_t evt = 0;
15517f2a7bbSJakub Grajciar
15617f2a7bbSJakub Grajciar  if (ptd == NULL)
15717f2a7bbSJakub Grajciar    return -1;
15817f2a7bbSJakub Grajciar
15917f2a7bbSJakub Grajciar  /* convert memif event definitions to epoll events */
16017f2a7bbSJakub Grajciar  if (events & MEMIF_FD_EVENT_DEL)
16117f2a7bbSJakub Grajciar    return del_epoll_fd (ptd->epfd, fd);
16217f2a7bbSJakub Grajciar
16317f2a7bbSJakub Grajciar  if (events & MEMIF_FD_EVENT_READ)
16417f2a7bbSJakub Grajciar    evt |= EPOLLIN;
16517f2a7bbSJakub Grajciar  if (events & MEMIF_FD_EVENT_WRITE)
16617f2a7bbSJakub Grajciar    evt |= EPOLLOUT;
16717f2a7bbSJakub Grajciar
16817f2a7bbSJakub Grajciar  if (events & MEMIF_FD_EVENT_MOD)
16917f2a7bbSJakub Grajciar    return mod_epoll_fd (ptd->epfd, fd, evt);
17017f2a7bbSJakub Grajciar
17117f2a7bbSJakub Grajciar  return add_epoll_fd (ptd->epfd, fd, evt);
17217f2a7bbSJakub Grajciar}
17317f2a7bbSJakub Grajciar
17417f2a7bbSJakub Grajciarstatic int
17517f2a7bbSJakub Grajciaron_connect (memif_conn_handle_t conn, void *private_ctx)
17617f2a7bbSJakub Grajciar{
17717f2a7bbSJakub Grajciar  struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
17817f2a7bbSJakub Grajciar  struct memif_connection *c;
17917f2a7bbSJakub Grajciar  int i = 0;
18017f2a7bbSJakub Grajciar
18117f2a7bbSJakub Grajciar  while (i < ptd->if_num && ptd->conns[i].handle != conn)
18217f2a7bbSJakub Grajciar    i++;
18317f2a7bbSJakub Grajciar  c = &ptd->conns[i];
18417f2a7bbSJakub Grajciar
18517f2a7bbSJakub Grajciar  c->connected = true;
18617f2a7bbSJakub Grajciar  DBG ("Connected: %u", c->id);
18717f2a7bbSJakub Grajciar
18817f2a7bbSJakub Grajciar  memif_refill_queue (conn, 0, -1, 0);
18917f2a7bbSJakub Grajciar
19017f2a7bbSJakub Grajciar  return 0;
19117f2a7bbSJakub Grajciar}
19217f2a7bbSJakub Grajciar
19317f2a7bbSJakub Grajciarstatic int
19417f2a7bbSJakub Grajciaron_disconnect (memif_conn_handle_t conn, void *private_ctx)
19517f2a7bbSJakub Grajciar{
19617f2a7bbSJakub Grajciar  struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
19717f2a7bbSJakub Grajciar  struct memif_connection *c;
19817f2a7bbSJakub Grajciar  int i = 0;
19917f2a7bbSJakub Grajciar
20017f2a7bbSJakub Grajciar  while (i < ptd->if_num && ptd->conns[i].handle != conn)
20117f2a7bbSJakub Grajciar    i++;
20217f2a7bbSJakub Grajciar  c = &ptd->conns[i];
20317f2a7bbSJakub Grajciar
20417f2a7bbSJakub Grajciar  c->connected = false;
20517f2a7bbSJakub Grajciar  DBG ("Disconnected: %u", c->id);
20617f2a7bbSJakub Grajciar
20717f2a7bbSJakub Grajciar  return 0;
20817f2a7bbSJakub Grajciar}
20917f2a7bbSJakub Grajciar
21017f2a7bbSJakub Grajciarstatic int
21117f2a7bbSJakub Grajciaron_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
21217f2a7bbSJakub Grajciar{
21317f2a7bbSJakub Grajciar  struct per_thread_data *ptd = (struct per_thread_data *) private_ctx;
21417f2a7bbSJakub Grajciar  struct memif_connection *c;
21517f2a7bbSJakub Grajciar  memif_buffer_t mbufs[ICMPR_MEMIF_BUFFER_NUM];
21617f2a7bbSJakub Grajciar  uint16_t rx = 0;
21717f2a7bbSJakub Grajciar  uint16_t tx = 0;
21817f2a7bbSJakub Grajciar  uint16_t ret;
21917f2a7bbSJakub Grajciar  memif_err_t err;
22017f2a7bbSJakub Grajciar  int i = 0;
22117f2a7bbSJakub Grajciar
22217f2a7bbSJakub Grajciar  memset (mbufs, 0, sizeof (memif_buffer_t) * ICMPR_MEMIF_BUFFER_NUM);
22317f2a7bbSJakub Grajciar
22417f2a7bbSJakub Grajciar  while (i < ptd->if_num && ptd->conns[i].handle != conn)
22517f2a7bbSJakub Grajciar    i++;
22617f2a7bbSJakub Grajciar  c = &ptd->conns[i];
22717f2a7bbSJakub Grajciar
22817f2a7bbSJakub Grajciar  /* receive data from shared memory buffers */
22917f2a7bbSJakub Grajciar  err = memif_rx_burst (conn, qid, mbufs, ICMPR_MEMIF_BUFFER_NUM, &rx);
23017f2a7bbSJakub Grajciar  if (err != MEMIF_ERR_SUCCESS)
23117f2a7bbSJakub Grajciar  {
23217f2a7bbSJakub Grajciar    printf ("memif_rx_burst: %s\n", memif_strerror (err));
23317f2a7bbSJakub Grajciar    goto error;
23417f2a7bbSJakub Grajciar  }
23517f2a7bbSJakub Grajciar
23617f2a7bbSJakub Grajciar  /* resolve packet in place (zer-copy slave) */
23717f2a7bbSJakub Grajciar  for (i = 0; i < rx; i++)
23817f2a7bbSJakub Grajciar    resolve_packet2 (mbufs[i].data, &mbufs[i].len, c->ip_addr);
23917f2a7bbSJakub Grajciar
24017f2a7bbSJakub Grajciar  /* enqueue received buffers */
24117f2a7bbSJakub Grajciar  err = memif_buffer_enq_tx (conn, qid, mbufs, i, &tx);
24217f2a7bbSJakub Grajciar  if (err != MEMIF_ERR_SUCCESS)
24317f2a7bbSJakub Grajciar  {
24417f2a7bbSJakub Grajciar    printf ("memif_rx_burst: %s\n", memif_strerror (err));
24517f2a7bbSJakub Grajciar    goto error;
24617f2a7bbSJakub Grajciar  }
24717f2a7bbSJakub Grajciar
24817f2a7bbSJakub Grajciar  /* mark shared memory buffers as free */
24917f2a7bbSJakub Grajciar  err = memif_refill_queue (conn, qid, rx, 0);
25017f2a7bbSJakub Grajciar  if (err != MEMIF_ERR_SUCCESS)
25117f2a7bbSJakub Grajciar  {
25217f2a7bbSJakub Grajciar    printf ("memif_rx_burst: %s\n", memif_strerror (err));
25317f2a7bbSJakub Grajciar    goto error;
25417f2a7bbSJakub Grajciar  }
25517f2a7bbSJakub Grajciar
25617f2a7bbSJakub Grajciar  err = memif_tx_burst (conn, qid, mbufs, tx, &ret);
25717f2a7bbSJakub Grajciar  if (err != MEMIF_ERR_SUCCESS)
25817f2a7bbSJakub Grajciar  {
25917f2a7bbSJakub Grajciar    printf ("memif_rx_burst: %s\n", memif_strerror (err));
26017f2a7bbSJakub Grajciar    goto error;
26117f2a7bbSJakub Grajciar  }
26217f2a7bbSJakub Grajciar
26317f2a7bbSJakub Grajciar  return 0;
26417f2a7bbSJakub Grajciar
26517f2a7bbSJakub Grajciarerror:
26617f2a7bbSJakub Grajciar  memif_refill_queue (conn, qid, -1, 0);
26717f2a7bbSJakub Grajciar  return -1;
26817f2a7bbSJakub Grajciar}
26917f2a7bbSJakub Grajciar
27017f2a7bbSJakub Grajciarint
27117f2a7bbSJakub Grajciarpoll_event (memif_per_thread_main_handle_t pt_main, int pcfd, int epfd,
27217f2a7bbSJakub Grajciar	    int timeout)
27317f2a7bbSJakub Grajciar{
27417f2a7bbSJakub Grajciar  struct epoll_event evt;
27517f2a7bbSJakub Grajciar  int en = 0;
27617f2a7bbSJakub Grajciar  uint8_t events = 0;
27717f2a7bbSJakub Grajciar  memset (&evt, 0, sizeof (evt));
27817f2a7bbSJakub Grajciar  evt.events = EPOLLIN | EPOLLOUT;
27917f2a7bbSJakub Grajciar
28017f2a7bbSJakub Grajciar  en = epoll_pwait (epfd, &evt, 1, timeout, NULL);
28117f2a7bbSJakub Grajciar  if (en < 0)
28217f2a7bbSJakub Grajciar    {
28317f2a7bbSJakub Grajciar      printf ("epoll_pwait: %s\n", strerror (errno));
28417f2a7bbSJakub Grajciar      return -1;
28517f2a7bbSJakub Grajciar    }
28617f2a7bbSJakub Grajciar
28717f2a7bbSJakub Grajciar  if (en > 0)
28817f2a7bbSJakub Grajciar    {
28917f2a7bbSJakub Grajciar      /* Cancel event polling */
29017f2a7bbSJakub Grajciar      if (evt.data.fd == pcfd)
29117f2a7bbSJakub Grajciar	return 1;
29217f2a7bbSJakub Grajciar
29317f2a7bbSJakub Grajciar      if (evt.events & EPOLLIN)
29417f2a7bbSJakub Grajciar	events |= MEMIF_FD_EVENT_READ;
29517f2a7bbSJakub Grajciar      if (evt.events & EPOLLOUT)
29617f2a7bbSJakub Grajciar	events |= MEMIF_FD_EVENT_WRITE;
29717f2a7bbSJakub Grajciar      if (evt.events & EPOLLERR)
29817f2a7bbSJakub Grajciar	events |= MEMIF_FD_EVENT_ERROR;
29917f2a7bbSJakub Grajciar
30017f2a7bbSJakub Grajciar      /* No need to use locks, as the database is separated */
30117f2a7bbSJakub Grajciar      memif_per_thread_control_fd_handler (pt_main, evt.data.fd, events);
30217f2a7bbSJakub Grajciar    }
30317f2a7bbSJakub Grajciar
30417f2a7bbSJakub Grajciar  return 0;
30517f2a7bbSJakub Grajciar}
30617f2a7bbSJakub Grajciar
30717f2a7bbSJakub Grajciarstatic void *
30817f2a7bbSJakub Grajciaricmpr_thread_fn (void *data)
30917f2a7bbSJakub Grajciar{
31017f2a7bbSJakub Grajciar  struct per_thread_data *ptd = (struct per_thread_data *) data;
31117f2a7bbSJakub Grajciar  int rv;
31217f2a7bbSJakub Grajciar  uint16_t i;
31317f2a7bbSJakub Grajciar  char socket_filename[ICMPR_SOCKET_FILENAME_LEN] = "/run/vpp/memif";
31417f2a7bbSJakub Grajciar  memif_conn_args_t args;
31517f2a7bbSJakub Grajciar
31617f2a7bbSJakub Grajciar  ptd->epfd = epoll_create (1);
31717f2a7bbSJakub Grajciar
31817f2a7bbSJakub Grajciar  ptd->conns = malloc (sizeof (struct memif_connection) * ptd->if_num);
31917f2a7bbSJakub Grajciar  if (ptd->conns == NULL)
32017f2a7bbSJakub Grajciar    {
32117f2a7bbSJakub Grajciar      printf ("%s\n", strerror (errno));
32217f2a7bbSJakub Grajciar      return NULL;
32317f2a7bbSJakub Grajciar    }
32417f2a7bbSJakub Grajciar
32517f2a7bbSJakub Grajciar  memset (ptd->conns, 0, sizeof (struct memif_connection) * ptd->if_num);
32617f2a7bbSJakub Grajciar
32717f2a7bbSJakub Grajciar  /* Initialize memif database (per thread). */
32817f2a7bbSJakub Grajciar  rv =
32917f2a7bbSJakub Grajciar    memif_per_thread_init (&ptd->pt_main, ptd, control_fd_update, APP_NAME,
33017f2a7bbSJakub Grajciar			   NULL, NULL, NULL);
33117f2a7bbSJakub Grajciar  if (rv != MEMIF_ERR_SUCCESS)
33217f2a7bbSJakub Grajciar    {
33317f2a7bbSJakub Grajciar      printf ("memif_per_thread_init: %s\n", memif_strerror (rv));
33417f2a7bbSJakub Grajciar      return NULL;
33517f2a7bbSJakub Grajciar    }
33617f2a7bbSJakub Grajciar
33717f2a7bbSJakub Grajciar  /*  Create unique socket. Each thread requires uniqueue socket. Interfaces created
33817f2a7bbSJakub Grajciar   *  on the same thread can share one socket.
33917f2a7bbSJakub Grajciar   */
34017f2a7bbSJakub Grajciar  socket_filename[strlen (socket_filename)] = '0' + ptd->index;
34117f2a7bbSJakub Grajciar  strncpy (socket_filename + strlen (socket_filename), ".sock", 5);
34217f2a7bbSJakub Grajciar  DBG ("socket_filename: %s", socket_filename);
34317f2a7bbSJakub Grajciar
34417f2a7bbSJakub Grajciar  rv = memif_per_thread_create_socket (ptd->pt_main, &ptd->socket_handle,
34517f2a7bbSJakub Grajciar				       socket_filename, ptd);
34617f2a7bbSJakub Grajciar  if (rv != MEMIF_ERR_SUCCESS)
34717f2a7bbSJakub Grajciar    {
34817f2a7bbSJakub Grajciar      printf ("memif_per_thread_create_socket: %s\n", memif_strerror (rv));
34917f2a7bbSJakub Grajciar      return NULL;
35017f2a7bbSJakub Grajciar    }
35117f2a7bbSJakub Grajciar
35217f2a7bbSJakub Grajciar  /* Create interfaces on this thread */
35317f2a7bbSJakub Grajciar  for (i = 0; i < ptd->if_num; i++)
35417f2a7bbSJakub Grajciar    {
35517f2a7bbSJakub Grajciar      ptd->conns[i].ip_addr[0] = 192;
35617f2a7bbSJakub Grajciar      ptd->conns[i].ip_addr[1] = 168;
35717f2a7bbSJakub Grajciar      ptd->conns[i].ip_addr[2] = ptd->index + 1;
35817f2a7bbSJakub Grajciar      ptd->conns[i].ip_addr[3] = i * 2 + 2;
35917f2a7bbSJakub Grajciar
36017f2a7bbSJakub Grajciar      memset (&args, 0, sizeof (args));
36117f2a7bbSJakub Grajciar
36217f2a7bbSJakub Grajciar      args.socket = ptd->socket_handle;
36317f2a7bbSJakub Grajciar      ptd->conns[i].id = i;
36417f2a7bbSJakub Grajciar      args.interface_id = i;
36517f2a7bbSJakub Grajciar
36617f2a7bbSJakub Grajciar      rv = memif_create (&ptd->conns[i].handle, &args, on_connect,
36717f2a7bbSJakub Grajciar			 on_disconnect, on_interrupt, ptd);
36817f2a7bbSJakub Grajciar      if (rv < 0)
36917f2a7bbSJakub Grajciar	{
37017f2a7bbSJakub Grajciar	  printf ("%s\n", memif_strerror (rv));
37117f2a7bbSJakub Grajciar	  return NULL;
37217f2a7bbSJakub Grajciar	}
37317f2a7bbSJakub Grajciar    }
37417f2a7bbSJakub Grajciar
37517f2a7bbSJakub Grajciar  /* Poll cancel file descriptor. When an event is received on this fd, exit thread
37617f2a7bbSJakub Grajciar   * loop in respective thread.
37717f2a7bbSJakub Grajciar   */
37817f2a7bbSJakub Grajciar  ptd->pcfd = eventfd (0, EFD_NONBLOCK);
37917f2a7bbSJakub Grajciar  if (ptd->pcfd < 0)
38017f2a7bbSJakub Grajciar    {
38117f2a7bbSJakub Grajciar      printf ("eventfd: %s\n", strerror (errno));
38217f2a7bbSJakub Grajciar      return NULL;
38317f2a7bbSJakub Grajciar    }
38417f2a7bbSJakub Grajciar  if (add_epoll_fd (ptd->epfd, ptd->pcfd, EPOLLIN) < 0)
38517f2a7bbSJakub Grajciar    {
38617f2a7bbSJakub Grajciar      printf ("Failed to add poll cancel fd to epfd.");
38717f2a7bbSJakub Grajciar      return NULL;
38817f2a7bbSJakub Grajciar    }
38917f2a7bbSJakub Grajciar
39017f2a7bbSJakub Grajciar  /* Thread loop */
39117f2a7bbSJakub Grajciar  ptd->running = true;
39217f2a7bbSJakub Grajciar  while (ptd->running)
39317f2a7bbSJakub Grajciar    {
39417f2a7bbSJakub Grajciar      rv = poll_event (ptd->pt_main, ptd->pcfd, ptd->epfd, -1);
39517f2a7bbSJakub Grajciar      if (rv != 0)
39617f2a7bbSJakub Grajciar	ptd->running = false;
39717f2a7bbSJakub Grajciar    }
39817f2a7bbSJakub Grajciar
39917f2a7bbSJakub Grajciar  /* Clean up */
40017f2a7bbSJakub Grajciar  for (i = 0; i < ptd->if_num; i++)
40117f2a7bbSJakub Grajciar    memif_delete (&ptd->conns[i].handle);
40217f2a7bbSJakub Grajciar
40317f2a7bbSJakub Grajciar  memif_delete_socket (&ptd->socket_handle);
40417f2a7bbSJakub Grajciar
40517f2a7bbSJakub Grajciar  memif_per_thread_cleanup (&ptd->pt_main);
40617f2a7bbSJakub Grajciar
40717f2a7bbSJakub Grajciar  free (ptd->conns);
40817f2a7bbSJakub Grajciar  close (ptd->pcfd);
40917f2a7bbSJakub Grajciar
41017f2a7bbSJakub Grajciar  return NULL;
41117f2a7bbSJakub Grajciar}
41217f2a7bbSJakub Grajciar
41317f2a7bbSJakub Grajciarstatic void
41417f2a7bbSJakub Grajciaricmpr_print_help ()
41517f2a7bbSJakub Grajciar{
41617f2a7bbSJakub Grajciar  printf
41717f2a7bbSJakub Grajciar    ("exit - Exits the application.\nhelp - Print this help.\nshow - Show memif interfaces\n");
41817f2a7bbSJakub Grajciar}
41917f2a7bbSJakub Grajciar
42017f2a7bbSJakub Grajciarstatic void
42117f2a7bbSJakub Grajciaricmpr_show_memifs ()
42217f2a7bbSJakub Grajciar{
42317f2a7bbSJakub Grajciar  struct icmpr_main *im = &icmpr_main;
42417f2a7bbSJakub Grajciar  int i, j;
42517f2a7bbSJakub Grajciar  memif_socket_handle_t sh;
42617f2a7bbSJakub Grajciar
42717f2a7bbSJakub Grajciar  printf ("%u Threads %u Memifs (per thread)\n", im->threads,
42817f2a7bbSJakub Grajciar	  im->per_thread_if_num);
42917f2a7bbSJakub Grajciar  printf ("=================================\n");
43017f2a7bbSJakub Grajciar
43117f2a7bbSJakub Grajciar  for (i = 0; i < im->threads; i++)
43217f2a7bbSJakub Grajciar    {
43317f2a7bbSJakub Grajciar      sh = im->ptd[i].socket_handle;
43417f2a7bbSJakub Grajciar      printf ("Thread %u %s\n", i, memif_get_socket_filename (sh));
43517f2a7bbSJakub Grajciar      for (j = 0; j < im->per_thread_if_num; j++)
43617f2a7bbSJakub Grajciar	{
43717f2a7bbSJakub Grajciar	  printf ("\tMemif id %u\n\t%s\n", im->ptd[i].conns[j].id,
43817f2a7bbSJakub Grajciar		  im->ptd[i].conns[j].connected ? "Link up" : "Link down");
43917f2a7bbSJakub Grajciar	}
44017f2a7bbSJakub Grajciar    }
44117f2a7bbSJakub Grajciar}
44217f2a7bbSJakub Grajciar
44317f2a7bbSJakub Grajciarint
44417f2a7bbSJakub Grajciarmain (int argc, char **argv)
44517f2a7bbSJakub Grajciar{
44617f2a7bbSJakub Grajciar  struct icmpr_main *im = &icmpr_main;
44717f2a7bbSJakub Grajciar  int rv, i;
44817f2a7bbSJakub Grajciar  int option_index = 0;
44917f2a7bbSJakub Grajciar  bool running;
45017f2a7bbSJakub Grajciar  char buffer[ICMPR_BUFFER_LENGTH];
45117f2a7bbSJakub Grajciar  uint64_t b = 1;
45217f2a7bbSJakub Grajciar
453