Shared memory packet interface (memif) library

Change-Id: I5097462ae85acd705f19e92517c01094dba7565f
Signed-off-by: Jakub Grajciar <grajciar.jakub@gmail.com>
diff --git a/extras/libmemif/src/libmemif.h b/extras/libmemif/src/libmemif.h
new file mode 100644
index 0000000..3732be6
--- /dev/null
+++ b/extras/libmemif/src/libmemif.h
@@ -0,0 +1,442 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+/** @file */
+
+#ifndef _LIBMEMIF_H_
+#define _LIBMEMIF_H_
+
+/** Libmemif version. */
+#define LIBMEMIF_VERSION "1.0"
+/** Default name of application using libmemif. */
+#define MEMIF_DEFAULT_APP_NAME "libmemif-app"
+
+#include <inttypes.h>
+
+#include <memif.h>
+
+/*! Error codes */
+typedef enum
+{
+  MEMIF_ERR_SUCCESS = 0,	/*!< success */
+/* SYSCALL ERRORS */
+  MEMIF_ERR_SYSCALL,		/*!< other syscall error */
+  MEMIF_ERR_ACCES,		/*!< permission denied */
+  MEMIF_ERR_NO_FILE,		/*!< file does not exist */
+  MEMIF_ERR_FILE_LIMIT,		/*!< system open file limit */
+  MEMIF_ERR_PROC_FILE_LIMIT,	/*!< process open file limit */
+  MEMIF_ERR_ALREADY,		/*!< connection already requested */
+  MEMIF_ERR_AGAIN,		/*!< fd is not socket, or operation would block */
+  MEMIF_ERR_BAD_FD,		/*!< invalid fd */
+  MEMIF_ERR_NOMEM,		/*!< out of memory */
+/* LIBMEMIF ERRORS */
+  MEMIF_ERR_INVAL_ARG,		/*!< invalid argument */
+  MEMIF_ERR_NOCONN,		/*!< handle points to no connection */
+  MEMIF_ERR_CONN,		/*!< handle points to existing connection */
+  MEMIF_ERR_CB_FDUPDATE,	/*!< user defined callback memif_control_fd_update_t error */
+  MEMIF_ERR_FILE_NOT_SOCK,	/*!< file specified by socket filename 
+				   exists, but it's not socket */
+  MEMIF_ERR_NO_SHMFD,		/*!< missing shm fd */
+  MEMIF_ERR_COOKIE,		/*!< wrong cookie on ring */
+  MEMIF_ERR_NOBUF_RING,		/*!< ring buffer full */
+  MEMIF_ERR_NOBUF,		/*!< not enough memif buffers */
+  MEMIF_ERR_NOBUF_DET,		/*!< memif details needs larger buffer */
+  MEMIF_ERR_INT_WRITE,		/*!< send interrupt error */
+  MEMIF_ERR_MFMSG,		/*!< malformed msg received */
+  MEMIF_ERR_QID,		/*!< invalid queue id */
+/* MEMIF PROTO ERRORS */
+  MEMIF_ERR_PROTO,		/*!< incompatible protocol version */
+  MEMIF_ERR_ID,			/*!< unmatched interface id */
+  MEMIF_ERR_ACCSLAVE,		/*!< slave cannot accept connection requests */
+  MEMIF_ERR_ALRCONN,		/*!< memif is already connected */
+  MEMIF_ERR_MODE,		/*!< mode mismatch */
+  MEMIF_ERR_SECRET,		/*!< secret mismatch */
+  MEMIF_ERR_NOSECRET,		/*!< secret required */
+  MEMIF_ERR_MAXREG,		/*!< max region limit reached */
+  MEMIF_ERR_MAXRING,		/*!< max ring limit reached */
+  MEMIF_ERR_NO_INTFD,		/*!< missing interrupt fd */
+  MEMIF_ERR_DISCONNECT,		/*!< disconenct received */
+  MEMIF_ERR_DISCONNECTED,	/*!< peer interface disconnected */
+  MEMIF_ERR_UNKNOWN_MSG,	/*!< unknown message type */
+} memif_err_t;
+
+/**
+ * @defgroup MEMIF_FD_EVENT Types of events that need to be watched for specific fd.
+ *
+ * @{
+ */
+
+/** user needs to set events that occured on fd and pass them to memif_control_fd_handler */
+#define MEMIF_FD_EVENT_READ  (1 << 0)
+#define MEMIF_FD_EVENT_WRITE (1 << 1)
+/** inform libmemif that error occured on fd */
+#define MEMIF_FD_EVENT_ERROR (1 << 2)
+/** if set, informs that fd is going to be closed (user may want to stop watching for events on this fd) */
+#define MEMIF_FD_EVENT_DEL   (1 << 3)
+/** update events */
+#define MEMIF_FD_EVENT_MOD   (1 << 4)
+/** @} */
+
+/** *brief Memif connection handle
+    pointer of type void, pointing to internal structure
+*/
+typedef void *memif_conn_handle_t;
+/**
+ * @defgroup CALLBACKS Callback functions definitions
+ *
+ * @{
+ */
+
+/** \brief Memif control file descriptor update (callback function)
+    @param fd - new file descriptor to watch
+    @param events - event type(s) to watch for
+
+    This callback is called when there is new fd to watch for events on
+    or if fd is about to be closed (user mey want to stop watching for events on this fd).
+*/
+typedef int (memif_control_fd_update_t) (int fd, uint8_t events);
+
+/** \brief Memif connection status update (callback function)
+    @param conn - memif connection handle
+    @param private_ctx - private context
+
+    Informs user about connection status connected/disconnected.
+    On connected -> start watching for events on interrupt fd (optional).
+*/
+typedef int (memif_connection_update_t) (memif_conn_handle_t conn,
+					 void *private_ctx);
+
+/** \brief Memif interrupt occured (callback function)
+    @param conn - memif connection handle
+    @param private_ctx - private context
+    @param qid - queue id on which interrupt occured
+
+    Called when event is received on interrupt fd.
+*/
+typedef int (memif_interrupt_t) (memif_conn_handle_t conn, void *private_ctx,
+				 uint16_t qid);
+/** @} */
+
+/**
+ * @defgroup ARGS_N_BUFS Connection arguments and buffers
+ *
+ * @{
+ */
+
+/** \brief Memif connection arguments
+    @param socket_filename - socket filename
+    @param secret - otional parameter used as interface autenthication
+    @param num_s2m_rings - number of slave to master rings
+    @param num_m2s_rings - number of master to slave rings
+    @param buffer_size - size of buffer in shared memory
+    @param log2_ring_size - logarithm base 2 of ring size
+    @param is_master - 0 == master, 1 == slave
+    @param interface_id - id used to identify peer connection
+    @param interface_name - interface name
+    @param instance_name - application name
+    @param mode - 0 == ethernet, 1 == ip , 2 == punt/inject
+*/
+typedef struct
+{
+  uint8_t *socket_filename;	/*!< default = /run/vpp/memif.sock */
+  uint8_t secret[24];		/*!< optional (interface authentication) */
+
+  uint8_t num_s2m_rings;	/*!< default = 1 */
+  uint8_t num_m2s_rings;	/*!< default = 1 */
+  uint16_t buffer_size;		/*!< default = 2048 */
+  memif_log2_ring_size_t log2_ring_size;	/*!< default = 10 (1024) */
+  uint8_t is_master;
+
+  memif_interface_id_t interface_id;
+  uint8_t interface_name[32];
+  uint8_t instance_name[32];
+  memif_interface_mode_t mode:8;
+} memif_conn_args_t;
+
+/*! memif receive mode */
+typedef enum
+{
+  MEMIF_RX_MODE_INTERRUPT = 0,	/*!< interrupt mode */
+  MEMIF_RX_MODE_POLLING		/*!< polling mode */
+} memif_rx_mode_t;
+
+/** \brief Memif buffer
+    @param desc_index - ring descriptor index
+    @param buffer_len - shared meory buffer length
+    @param data_len - data length
+    @param data - pointer to shared memory data
+*/
+typedef struct
+{
+  uint16_t desc_index;
+  uint32_t buffer_len;
+  uint32_t data_len;
+  void *data;
+} memif_buffer_t;
+/** @} */
+
+/**
+ * @defgroup MEMIF_DETAILS Memif details structs
+ *
+ * @{
+ */
+
+/** \brief Memif queue details
+    @param qid - queue id
+    @param ring_size - size of ring buffer in sharem memory
+    @param buffer_size - buffer size on sharem memory
+*/
+typedef struct
+{
+  uint8_t qid;
+  uint32_t ring_size;
+  uint16_t buffer_size;
+  /* add ring information */
+} memif_queue_details_t;
+
+/** \brief Memif details
+    @param if_name - interface name
+    @param inst_name - application name
+    @param remote_if_name - peer interface name
+    @param remote_inst_name - peer application name
+    @param id - connection id
+    @param secret - secret
+    @param role - 0 = master, 1 = slave
+    @param mode - 0 = ethernet, 1 = ip , 2 = punt/inject
+    @param socket_filename = socket filename
+    @param rx_queues_num - number of receive queues
+    @param tx_queues_num - number of transmit queues
+    @param rx_queues - struct containing receive queue details
+    @param tx_queues - struct containing transmit queue details
+    @param link_up_down - 1 = up (connected), 2 = down (disconnected)
+*/
+typedef struct
+{
+  uint8_t *if_name;
+  uint8_t *inst_name;
+  uint8_t *remote_if_name;
+  uint8_t *remote_inst_name;
+
+  uint32_t id;
+  uint8_t *secret;		/* optional */
+  uint8_t role;			/* 0 = master, 1 = slave */
+  uint8_t mode;			/* 0 = ethernet, 1 = ip, 2 = punt/inject */
+  uint8_t *socket_filename;
+  uint8_t rx_queues_num;
+  uint8_t tx_queues_num;
+  memif_queue_details_t *rx_queues;
+  memif_queue_details_t *tx_queues;
+
+  uint8_t link_up_down;		/* 1 = up, 0 = down */
+} memif_details_t;
+/** @} */
+
+/**
+ * @defgroup API_CALLS Api calls
+ *
+ * @{
+ */
+
+/** \biref Memif get queue event file descriptor
+    @param conn - memif connection handle
+    @param qid - queue id
+    @param[out] fd - returns event file descriptor
+
+    \return memif_err_t
+*/
+
+int memif_get_queue_efd (memif_conn_handle_t conn, uint16_t qid, int *fd);
+
+/** \brief Memif set rx mode
+    @param conn - memif connection handle
+    @param rx_mode - receive mode
+    @param qid - queue id
+
+    \return memif_err_t
+*/
+int memif_set_rx_mode (memif_conn_handle_t conn, memif_rx_mode_t rx_mode,
+		       uint16_t qid);
+
+/** \brief Memif strerror
+    @param err_code - error code
+
+    Converts error code to error message.
+    
+    \return Error string
+*/
+char *memif_strerror (int err_code);
+
+/** \brief Memif get details
+    @param conn - memif conenction handle
+    @param md - pointer to memif details struct
+    @param buf - buffer containing details strings
+    @param buflen - length of buffer
+
+    \return memif_err_t
+*/
+int memif_get_details (memif_conn_handle_t conn, memif_details_t * md,
+		       char *buf, ssize_t buflen);
+
+/** \brief Memif initialization
+    @param on_control_fd_update - if control fd updates inform user to watch new fd
+    @param app_name - application name
+
+    if param on_control_fd_update is set to NULL,
+    libmemif will handle file descriptor event polling
+    if a valid callback is set, file descriptor event polling needs to be done by
+    user application, all file descriptors and event types will be passed in
+    this callback to user application
+
+    Initialize internal libmemif structures. Create timerfd (used to periodically request connection by
+    disconnected memifs in slave mode, with no additional API call). This fd is passed to user with memif_control_fd_update_t
+    timer is inactive at this state. It activates with if there is at least one memif in slave mode.
+
+    \return memif_err_t
+*/
+int memif_init (memif_control_fd_update_t * on_control_fd_update,
+		char *app_name);
+
+/** \brief Memif cleanup
+
+    Free libmemif internal allocations.
+
+    \return 0
+*/
+int memif_cleanup ();
+
+/** \brief Memory interface create function
+    @param conn - connection handle for user app
+    @param args - memory interface connection arguments
+    @param on_connect - inform user about connected status
+    @param on_disconnect - inform user about disconnected status
+    @param on_interrupt - informs user about interrupt, if set to null user will not be notified about interrupt, user can use memif_get_queue_efd call to get interrupt fd to poll for events
+    @param private_ctx - private contex passed back to user with callback
+
+    Creates memory interface.
+     
+    SLAVE-MODE - 
+        Start timer that will send events to timerfd. If this fd is passed to memif_control_fd_handler
+        every disconnected memif in slave mode will send connection request.
+        On success new fd is passed to user with memif_control_fd_update_t.
+
+    MASTER-MODE - 
+        Create listener socket and pass fd to user with memif_cntrol_fd_update_t.
+        If this fd is passed to memif_control_fd_handler accept will be called and
+        new fd will be passed to user with memif_control_fd_update_t.
+
+
+    \return memif_err_t
+*/
+int memif_create (memif_conn_handle_t * conn, 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);
+
+/** \brief Memif control file descriptor handler
+    @param fd - file descriptor on which the event occured
+    @param events - event type(s) that occured
+
+    If event occures on any control fd, call memif_control_fd_handler.
+    Internal - lib will "identify" fd (timerfd, lsitener, control) and handle event accordingly.
+ 
+    FD-TYPE - 
+        TIMERFD - 
+            Every disconnected memif in slave mode will request connection.
+        LISTENER or CONTROL - 
+            Handle socket messaging (internal connection establishment).
+        INTERRUPT - 
+            Call on_interrupt callback (if set).
+        
+    \return memif_err_t
+
+*/
+int memif_control_fd_handler (int fd, uint8_t events);
+
+/** \brief Memif delete
+    @param conn - pointer to memif connection handle
+
+
+    disconnect session (free queues and regions, close file descriptors, unmap shared memory)
+    set connection handle to NULL, to avoid possible double free
+
+    \return memif_err_t
+*/
+int memif_delete (memif_conn_handle_t * conn);
+
+/** \brief Memif buffer alloc
+    @param conn - memif conenction handle
+    @param qid - number indentifying queue
+    @param bufs - memif buffers
+    @param count - number of memif buffers to allocate
+    @param count_out - returns number of allocated buffers
+
+    \return memif_err_t
+*/
+int memif_buffer_alloc (memif_conn_handle_t conn, uint16_t qid,
+			memif_buffer_t * bufs, uint16_t count,
+			uint16_t * count_out);
+
+/** \brief Memif buffer free
+    @param conn - memif conenction handle
+    @param qid - number indentifying queue
+    @param bufs - memif buffers
+    @param count - number of memif buffers to free
+    @param count_out - returns number of freed buffers
+
+    \return memif_err_t
+*/
+int memif_buffer_free (memif_conn_handle_t conn, uint16_t qid,
+		       memif_buffer_t * bufs, uint16_t count,
+		       uint16_t * count_out);
+
+/** \brief Memif transmit buffer burst
+    @param conn - memif conenction handle
+    @param qid - number indentifying queue
+    @param bufs - memif buffers
+    @param count - number of memif buffers to transmit
+    @param tx - returns number of transmitted buffers
+
+    \return memif_err_t
+*/
+int memif_tx_burst (memif_conn_handle_t conn, uint16_t qid,
+		    memif_buffer_t * bufs, uint16_t count, uint16_t * tx);
+
+/** \brief Memif receive buffer burst
+    @param conn - memif conenction handle
+    @param qid - number indentifying queue
+    @param bufs - memif buffers
+    @param count - number of memif buffers to receive
+    @param rx - returns number of received buffers
+
+    \return memif_err_t
+*/
+int memif_rx_burst (memif_conn_handle_t conn, uint16_t qid,
+		    memif_buffer_t * bufs, uint16_t count, uint16_t * rx);
+
+/** \brief Memif poll event
+    @param timeout - timeout in seconds
+
+    Passive event polling - 
+    timeout = 0 - dont wait for event, check event queue if there is an event and return.
+    timeout = -1 - wait until event
+
+    \return memif_err_t
+*/
+int memif_poll_event (int timeout);
+/** @} */
+
+#endif /* _LIBMEMIF_H_ */