For detailed information on api calls and structures please refer to @ref libmemif.h.
int control_fd_update (int fd, uint8_t events) { ... }
err = memif_init (control_fd_update, APP_NAME, NULL, NULL);
If event occurres on any file descriptor returned by this callback, call memif_control_fd_handler function. Since version 2.0, last two optional arguments are used to specify custom memory allocation.
memif_err = memif_control_fd_handler (evt.data.fd, events);
If callback function parameter for memif_init function is set to NULL, libmemif will handle file descriptor event polling. Api call memif_poll_event will call epoll_pwait with user defined timeout to poll event on file descriptors opened by libmemif.
/* main loop */ while (1) { if (memif_poll_event (-1) < 0) { DBG ("poll_event error!"); } }
Memif initialization function will initialize internal structures and create timer file descriptor, which will be used for sending periodic connection requests. Timer is disarmed if no memif interface is created.
memif_conn_handle_t c;
example app uses struct that contains connection handle, rx/tx buffers and other connection specific information.
memif_conn_args_t args; memset (&args, 0, sizeof (args)); args.is_master = is_master; args.log2_ring_size = 10; args.buffer_size = 2048; args.num_s2m_rings = 2; args.num_m2s_rings = 2; strncpy ((char *) args.interface_name, IF_NAME, strlen (IF_NAME)); args.mode = 0; args.interface_id = 0;
int on_connect (memif_conn_handle_t conn, void *private_ctx) { ... } int on_disconnect (memif_conn_handle_t conn, void *private_ctx) { INFO ("memif connected!"); return 0; }
err = memif_create (&c->conn, &args, on_connect, on_disconnect, on_interrupt, &ctx[index]);
If connection is in slave mode, arms timer file descriptor. If on interrupt callback is set to NULL, user will not be notified about interrupt. Use memif_get_queue_efd call to get interrupt file descriptor for specific queue.
int fd = -1; err = memif_get_queue_efd (c->conn, data->qid, &fd);
Connection establishment
Interrupt packet receive
int on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid) { ... }
typedef struct { uint16_t desc_index; uint32_t len; uint8_t flags; void *data; } memif_buffer_t;
err = memif_rx_burst (c->conn, qid, c->bufs, MAX_MEMIF_BUFS, &rx);
- User application can then process packets. - Api call memif\_refill\_queue will enqueue rx buffers.
err = memif_refill_queue (c->conn, qid, rx);
err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, n, &r);
- User application can populate shared memory buffers with packets. - Api call memif\_tx\_burst will enqueue tx buffers
err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &r);
uint16_t memif_ver = memif_get_version ();
- Memif details - Api call memif\_get\_details will return details about connection.
err = memif_get_details (c->conn, &md, buf, buflen);
- Memif error messages - Every api call returns error code (integer value) mapped to error string. - Call memif\_strerror will return error message assigned to specific error code.
if (err != MEMIF_ERR_SUCCESS) INFO ("memif_get_details: %s", memif_strerror (err));
- Not all syscall errors are translated to memif error codes. If error code 1 (MEMIF\_ERR\_SYSCALL) is returned then libmemif needs to be compiled with -DMEMIF_DBG flag to print error message. Use _make -B_ to rebuild libmemif in debug mode.
Optional argument: transmit queue id.
icmpr 1
Set transmit queue id to 1. Default is 0. Application will create memif interface in slave mode and try to connect to VPP. Exit using Ctrl+C. Application will handle SIGINT signal, free allocated memory and exit with EXIT_SUCCESS.
ICMP Responder custom fd event polling.
ICMP Responder multi-thread.
Simple example of libmemif multi-thread usage. Connection establishment is handled by main thread. There are two rx/tx queues in this example. One in polling mode and second in interrupt mode.
VPP config:
# create memif id 0 master # set int state memif0 up # set int ip address memif0 192.168.1.1/24 # ping 192.168.1.2
For multiple rings (queues) support run VPP with worker threads: example startup.conf:
unix { interactive nodaemon full-coredump } cpu { workers 2 }
VPP config:
# create memif id 0 master # set int state memif0 up # set int ip address memif0 192.168.1.1/24 # ping 192.168.1.2
Master mode queue number is limited by worker threads. Slave mode interface needs to specify number of queues.
# create memif id 0 slave rx-queues 2 tx-queues 2
Example applications use VPP default socket file for memif: /run/vpp/memif.sock For master mode, socket directory must exist prior to memif_create call.
Unit tests use Check framework. This framework must be installed in order to build unit_test binary. Ubuntu/Debian:
sudo apt-get install check