https://jira.fd.io/browse/GOVPP-21
[govpp.git] / extras / libmemif / adapter.go
index 8ade6bc..ac8a827 100644 (file)
@@ -34,7 +34,7 @@ import (
 #include <stdint.h>
 #include <string.h>
 #include <sys/eventfd.h>
-#include <libmemif.h>
+#include <libmemif.h>  // <-- VPP must be installed!
 
 // Feature tests.
 #ifndef MEMIF_HAVE_CANCEL_POLL_EVENT
@@ -50,7 +50,7 @@ memif_cancel_poll_event ()
 // are much easier to work with in cgo.
 typedef struct
 {
-       char *socket_filename;
+       memif_socket_handle_t socket;
        char *secret;
        uint8_t num_s2m_rings;
        uint8_t num_m2s_rings;
@@ -75,6 +75,8 @@ typedef struct
        uint8_t role;
        uint8_t mode;
        char *socket_filename;
+       uint8_t regions_num;
+       memif_region_details_t *regions;
        uint8_t rx_queues_num;
        uint8_t tx_queues_num;
        memif_queue_details_t *rx_queues;
@@ -106,7 +108,7 @@ govpp_memif_create (memif_conn_handle_t *conn, govpp_memif_conn_args_t *go_args,
 {
        memif_conn_args_t args;
        memset (&args, 0, sizeof (args));
-       args.socket_filename = (char *)go_args->socket_filename;
+       args.socket = (char *)go_args->socket;
        if (go_args->secret != NULL)
        {
                strncpy ((char *)args.secret, go_args->secret,
@@ -130,6 +132,12 @@ govpp_memif_create (memif_conn_handle_t *conn, govpp_memif_conn_args_t *go_args,
                                                private_ctx);
 }
 
+static int
+govpp_memif_create_socket (memif_socket_handle_t *sock, char *filename)
+{
+       return memif_create_socket(sock, filename, NULL);
+}
+
 // govpp_memif_get_details keeps reallocating buffer until it is large enough.
 // The buffer is returned to be deallocated when it is no longer needed.
 static int
@@ -167,6 +175,8 @@ govpp_memif_get_details (memif_conn_handle_t conn, govpp_memif_details_t *govpp_
                govpp_md->role = md.role;
                govpp_md->mode = md.mode;
                govpp_md->socket_filename = (char *)md.socket_filename;
+               govpp_md->regions_num = md.regions_num;
+               govpp_md->regions = md.regions;
                govpp_md->rx_queues_num = md.rx_queues_num;
                govpp_md->tx_queues_num = md.tx_queues_num;
                govpp_md->rx_queues = md.rx_queues;
@@ -361,14 +371,16 @@ type Memif struct {
        MemifMeta
 
        // Per-library references
-       ifIndex int                   // index used in the Go-libmemif context (Context.memifs)
-       cHandle C.memif_conn_handle_t // handle used in C-libmemif
+       ifIndex int                     // index used in the Go-libmemif context (Context.memifs)
+       cHandle C.memif_conn_handle_t   // connection handle used in C-libmemif
+       sHandle C.memif_socket_handle_t // socket handle used in C-libmemif
 
        // Callbacks
        callbacks *MemifCallbacks
 
        // Interrupt
        intCh      chan uint8      // memif-global interrupt channel (value = queue ID)
+       intErrCh   chan error      // triggered when interrupt error occurs
        queueIntCh []chan struct{} // per RX queue interrupt channel
 
        // Rx/Tx queues
@@ -415,8 +427,8 @@ type MemifQueueDetails struct {
 
 // CPacketBuffers stores an array of memif buffers for use with TxBurst or RxBurst.
 type CPacketBuffers struct {
-       buffers *C.memif_buffer_t
-       count   int
+       buffers    *C.memif_buffer_t
+       count      int
        rxChainBuf []RawPacketData
 }
 
@@ -574,6 +586,7 @@ func CreateInterface(config *MemifConfig, callbacks *MemifCallbacks) (memif *Mem
 
        // Initialize memif-global interrupt channel.
        memif.intCh = make(chan uint8, 1<<6)
+       memif.intErrCh = make(chan error, 1<<6)
 
        // Initialize event file descriptor for stopping Rx/Tx queue polling.
        memif.stopQPollFd = int(C.eventfd(0, C.EFD_NONBLOCK))
@@ -585,9 +598,13 @@ func CreateInterface(config *MemifConfig, callbacks *MemifCallbacks) (memif *Mem
        args := &C.govpp_memif_conn_args_t{}
        // - socket file name
        if config.SocketFilename != "" {
-               args.socket_filename = C.CString(config.SocketFilename)
-               defer C.free(unsafe.Pointer(args.socket_filename))
+               log.WithField("name", config.SocketFilename).Debug("A new memif socket was created")
+               errCode := C.govpp_memif_create_socket(&memif.sHandle, C.CString(config.SocketFilename))
+               if getMemifError(int(errCode)) != nil {
+                       return nil, err
+               }
        }
+       args.socket = memif.sHandle
        // - interface ID
        args.interface_id = C.uint32_t(config.ConnID)
        // - interface name
@@ -628,8 +645,7 @@ func CreateInterface(config *MemifConfig, callbacks *MemifCallbacks) (memif *Mem
 
        // Create memif in C-libmemif.
        errCode := C.govpp_memif_create(&memif.cHandle, args, unsafe.Pointer(uintptr(memif.ifIndex)))
-       err = getMemifError(int(errCode))
-       if err != nil {
+       if getMemifError(int(errCode)) != nil {
                return nil, err
        }
 
@@ -653,6 +669,12 @@ func (memif *Memif) GetInterruptChan() (ch <-chan uint8 /* queue ID */) {
        return memif.intCh
 }
 
+// GetInterruptErrorChan returns an Error channel
+// which fires if there are errors occurred while read data.
+func (memif *Memif) GetInterruptErrorChan() (ch <-chan error /* The error */) {
+       return memif.intErrCh
+}
+
 // GetQueueInterruptChan returns an empty-data channel which fires every time
 // there are data to read on a given queue.
 // It is only valid to call this function if memif is in the connected state.
@@ -767,7 +789,7 @@ func (memif *Memif) TxBurst(queueID uint8, packets []RawPacketData) (count uint1
        }
 
        var bufCount int
-       var buffers []*txPacketBuffer
+       buffers := make([]*txPacketBuffer, 0)
        cQueueID := C.uint16_t(queueID)
 
        for _, packet := range packets {
@@ -912,6 +934,7 @@ func (memif *Memif) TxBurst(queueID uint8, packets []RawPacketData) (count uint1
 // Rx queue.
 func (memif *Memif) RxBurst(queueID uint8, count uint16) (packets []RawPacketData, err error) {
        var recvCount C.uint16_t
+       packets = make([]RawPacketData, 0)
 
        if count == 0 {
                return packets, nil
@@ -1007,6 +1030,7 @@ func (memif *Memif) Close() error {
        if err != nil {
                // Close memif-global interrupt channel.
                close(memif.intCh)
+               close(memif.intErrCh)
                // Close file descriptor stopQPollFd.
                C.close(C.int(memif.stopQPollFd))
        }
@@ -1142,7 +1166,13 @@ func pollRxQueue(memif *Memif, queueID uint8) {
        for {
                _, err := syscall.EpollWait(epFd, event[:], -1)
                if err != nil {
+                       errno, _ := err.(syscall.Errno)
+                       //EINTR and EAGAIN should not be considered as a fatal error, try again
+                       if errno == syscall.EINTR || errno == syscall.EAGAIN {
+                               continue
+                       }
                        log.WithField("err", err).Error("epoll_wait() failed")
+                       memif.intErrCh <- err
                        return
                }