LCOV - code coverage report
Current view: top level - plugins/memif - memif.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 467 649 72.0 %
Date: 2023-10-26 01:39:38 Functions: 19 24 79.2 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2017 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             : 
      19             : #define _GNU_SOURCE
      20             : #include <stdint.h>
      21             : #include <net/if.h>
      22             : #include <sys/types.h>
      23             : #include <fcntl.h>
      24             : #include <sys/ioctl.h>
      25             : #include <sys/socket.h>
      26             : #include <sys/un.h>
      27             : #include <sys/uio.h>
      28             : #include <sys/mman.h>
      29             : #include <sys/prctl.h>
      30             : #include <sys/eventfd.h>
      31             : #include <inttypes.h>
      32             : #include <limits.h>
      33             : 
      34             : #include <vlib/vlib.h>
      35             : #include <vlib/unix/unix.h>
      36             : #include <vnet/plugin/plugin.h>
      37             : #include <vnet/ethernet/ethernet.h>
      38             : #include <vnet/interface/rx_queue_funcs.h>
      39             : #include <vnet/interface/tx_queue_funcs.h>
      40             : #include <vpp/app/version.h>
      41             : #include <memif/memif.h>
      42             : #include <memif/private.h>
      43             : 
      44             : memif_main_t memif_main;
      45             : 
      46             : static u32
      47           6 : memif_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi, u32 flags)
      48             : {
      49             :   /* nothing for now */
      50           6 :   return 0;
      51             : }
      52             : 
      53             : static clib_error_t *
      54           0 : memif_eth_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi,
      55             :                               u32 flags)
      56             : {
      57             :   /* nothing for now */
      58           0 :   return 0;
      59             : }
      60             : 
      61             : static void
      62          16 : memif_queue_intfd_close (memif_queue_t * mq)
      63             : {
      64          16 :   if (mq->int_clib_file_index != ~0)
      65             :     {
      66           8 :       memif_file_del_by_index (mq->int_clib_file_index);
      67           8 :       mq->int_clib_file_index = ~0;
      68           8 :       mq->int_fd = -1;
      69             :     }
      70           8 :   else if (mq->int_fd > -1)
      71             :     {
      72           8 :       close (mq->int_fd);
      73           8 :       mq->int_fd = -1;
      74             :     }
      75          16 : }
      76             : 
      77             : static void
      78           8 : memif_disconnect_free_zc_queue_buffer (memif_queue_t * mq, u8 is_rx)
      79             : {
      80           8 :   vlib_main_t *vm = vlib_get_main ();
      81             :   u16 ring_size, n_slots, mask, start;
      82             : 
      83           8 :   ring_size = 1 << mq->log2_ring_size;
      84           8 :   mask = ring_size - 1;
      85           8 :   n_slots = mq->ring->head - mq->last_tail;
      86           8 :   start = mq->last_tail & mask;
      87           8 :   if (is_rx)
      88           4 :     vlib_buffer_free_from_ring (vm, mq->buffers, start, ring_size, n_slots);
      89             :   else
      90           4 :     vlib_buffer_free_from_ring_no_next (vm, mq->buffers, start, ring_size,
      91             :                                         n_slots);
      92           8 :   vec_free (mq->buffers);
      93           8 : }
      94             : 
      95             : void
      96          20 : memif_disconnect (memif_if_t * mif, clib_error_t * err)
      97             : {
      98          20 :   memif_main_t *mm = &memif_main;
      99          20 :   vnet_main_t *vnm = vnet_get_main ();
     100             :   memif_region_t *mr;
     101             :   memif_queue_t *mq;
     102             :   int i;
     103          20 :   vlib_main_t *vm = vlib_get_main ();
     104          20 :   int with_barrier = 0;
     105             : 
     106          20 :   if (mif == 0)
     107           0 :     return;
     108             : 
     109          20 :   memif_log_debug (mif, "disconnect %u (%v)", mif->dev_instance,
     110             :                    err ? err->what : 0);
     111             : 
     112          20 :   if (err)
     113             :     {
     114          20 :       clib_error_t *e = 0;
     115          20 :       mif->local_disc_string = vec_dup (err->what);
     116          20 :       if (mif->sock && clib_socket_is_connected (mif->sock))
     117           8 :         e = memif_msg_send_disconnect (mif, err);
     118          20 :       clib_error_free (e);
     119             :     }
     120             : 
     121             :   /* set interface down */
     122          20 :   mif->flags &= ~(MEMIF_IF_FLAG_CONNECTED | MEMIF_IF_FLAG_CONNECTING);
     123          20 :   if (mif->hw_if_index != ~0)
     124          20 :     vnet_hw_interface_set_flags (vnm, mif->hw_if_index, 0);
     125             : 
     126             :   /* close connection socket */
     127          20 :   if (mif->sock && mif->sock->fd)
     128           8 :     {
     129           8 :       memif_socket_file_t *msf = vec_elt_at_index (mm->socket_files,
     130             :                                                    mif->socket_file_index);
     131           8 :       hash_unset (msf->dev_instance_by_fd, mif->sock->fd);
     132           8 :       memif_socket_close (&mif->sock);
     133             :     }
     134          12 :   else if (mif->sock)
     135             :     {
     136             :       clib_error_t *err;
     137           0 :       err = clib_socket_close (mif->sock);
     138           0 :       if (err)
     139             :         {
     140           0 :           memif_log_err (mif, "%U", format_clib_error, err);
     141           0 :           clib_error_free (err);
     142             :         }
     143           0 :       clib_mem_free (mif->sock);
     144             :     }
     145             : 
     146          20 :   if (vlib_worker_thread_barrier_held () == 0)
     147             :     {
     148           0 :       with_barrier = 1;
     149           0 :       vlib_worker_thread_barrier_sync (vm);
     150             :     }
     151             : 
     152             :   /* *INDENT-OFF* */
     153          28 :   vec_foreach_index (i, mif->rx_queues)
     154             :     {
     155           8 :       mq = vec_elt_at_index (mif->rx_queues, i);
     156           8 :       if (mq->ring)
     157             :         {
     158           8 :           if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
     159             :           {
     160           4 :             memif_disconnect_free_zc_queue_buffer(mq, 1);
     161             :           }
     162           8 :           mq->ring = 0;
     163             :         }
     164             :     }
     165          20 :   vnet_hw_if_unregister_all_rx_queues (vnm, mif->hw_if_index);
     166             : 
     167             :   /* *INDENT-OFF* */
     168          28 :   vec_foreach_index (i, mif->tx_queues)
     169             :   {
     170           8 :     mq = vec_elt_at_index (mif->tx_queues, i);
     171           8 :     if (mq->ring)
     172             :     {
     173           8 :       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
     174             :       {
     175           4 :         memif_disconnect_free_zc_queue_buffer(mq, 0);
     176             :       }
     177           8 :       clib_spinlock_free (&mq->lockp);
     178             :     }
     179           8 :     mq->ring = 0;
     180             :   }
     181          20 :   vnet_hw_if_unregister_all_tx_queues (vnm, mif->hw_if_index);
     182          20 :   vnet_hw_if_update_runtime_data (vnm, mif->hw_if_index);
     183             : 
     184             :   /* free tx and rx queues */
     185          28 :   vec_foreach (mq, mif->rx_queues)
     186           8 :     memif_queue_intfd_close (mq);
     187          20 :   vec_free (mif->rx_queues);
     188             : 
     189          28 :   vec_foreach (mq, mif->tx_queues)
     190           8 :     memif_queue_intfd_close (mq);
     191          20 :   vec_free (mif->tx_queues);
     192             : 
     193             :   /* free memory regions */
     194          36 :   vec_foreach (mr, mif->regions)
     195             :     {
     196             :       int rv;
     197          16 :       if (mr->is_external)
     198           4 :         continue;
     199          12 :       if ((rv = munmap (mr->shm, mr->region_size)))
     200           0 :         memif_log_err (mif, "munmap failed, rv = %d", rv);
     201          12 :       if (mr->fd > -1)
     202          12 :         close (mr->fd);
     203             :     }
     204             :   /* *INDENT-ON* */
     205          20 :   vec_free (mif->regions);
     206          20 :   vec_free (mif->remote_name);
     207          20 :   vec_free (mif->remote_if_name);
     208          20 :   clib_fifo_free (mif->msg_queue);
     209             : 
     210          20 :   if (with_barrier)
     211           0 :     vlib_worker_thread_barrier_release (vm);
     212             : }
     213             : 
     214             : static clib_error_t *
     215           0 : memif_int_fd_write_ready (clib_file_t * uf)
     216             : {
     217           0 :   memif_main_t *mm = &memif_main;
     218           0 :   u16 qid = uf->private_data & 0xFFFF;
     219           0 :   memif_if_t *mif = vec_elt_at_index (mm->interfaces, uf->private_data >> 16);
     220             : 
     221           0 :   memif_log_warn (mif, "unexpected EPOLLOUT on RX for queue %u", qid);
     222           0 :   return 0;
     223             : }
     224             : 
     225             : static clib_error_t *
     226           0 : memif_int_fd_read_ready (clib_file_t * uf)
     227             : {
     228           0 :   memif_main_t *mm = &memif_main;
     229           0 :   vnet_main_t *vnm = vnet_get_main ();
     230           0 :   u16 qid = uf->private_data & 0xFFFF;
     231           0 :   memif_if_t *mif = vec_elt_at_index (mm->interfaces, uf->private_data >> 16);
     232           0 :   memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, qid);
     233             :   u64 b;
     234             :   ssize_t size;
     235             : 
     236           0 :   size = read (uf->file_descriptor, &b, sizeof (b));
     237           0 :   if (size < 0)
     238             :     {
     239           0 :       memif_log_debug (mif, "Failed to read from socket");
     240           0 :       return 0;
     241             :     }
     242             : 
     243           0 :   vnet_hw_if_rx_queue_set_int_pending (vnm, mq->queue_index);
     244           0 :   mq->int_count++;
     245             : 
     246           0 :   return 0;
     247             : }
     248             : 
     249             : 
     250             : clib_error_t *
     251          14 : memif_connect (memif_if_t * mif)
     252             : {
     253          14 :   memif_main_t *mm = &memif_main;
     254          14 :   vlib_main_t *vm = vlib_get_main ();
     255          14 :   vnet_main_t *vnm = vnet_get_main ();
     256          14 :   clib_file_t template = { 0 };
     257             :   memif_region_t *mr;
     258             :   int i, j;
     259          14 :   u32 n_txqs = 0, n_threads = vlib_get_n_threads ();
     260          14 :   clib_error_t *err = NULL;
     261          14 :   u8 max_log2_ring_sz = 0;
     262          14 :   int with_barrier = 0;
     263             : 
     264          14 :   memif_log_debug (mif, "connect %u", mif->dev_instance);
     265             : 
     266          14 :   vec_free (mif->local_disc_string);
     267          14 :   vec_free (mif->remote_disc_string);
     268             : 
     269             :   /* *INDENT-OFF* */
     270          42 :   vec_foreach (mr, mif->regions)
     271             :     {
     272          28 :       if (mr->shm)
     273          14 :         continue;
     274             : 
     275          14 :       if (mr->fd < 0)
     276             :         {
     277           0 :           err = clib_error_return (0, "no memory region fd");
     278           0 :           goto error;
     279             :         }
     280             : 
     281          14 :       if ((mr->shm = mmap (NULL, mr->region_size, PROT_READ | PROT_WRITE,
     282             :                            MAP_SHARED, mr->fd, 0)) == MAP_FAILED)
     283             :         {
     284           0 :           err = clib_error_return_unix (0, "mmap");
     285           0 :           goto error;
     286             :         }
     287             :     }
     288             :   /* *INDENT-ON* */
     289             : 
     290          14 :   template.read_function = memif_int_fd_read_ready;
     291          14 :   template.write_function = memif_int_fd_write_ready;
     292             : 
     293          14 :   with_barrier = 1;
     294          14 :   if (vlib_worker_thread_barrier_held ())
     295          14 :     with_barrier = 0;
     296             : 
     297          14 :   if (with_barrier)
     298           0 :     vlib_worker_thread_barrier_sync (vm);
     299             : 
     300             :   /* *INDENT-OFF* */
     301          28 :   vec_foreach_index (i, mif->tx_queues)
     302             :     {
     303          14 :       memif_queue_t *mq = vec_elt_at_index (mif->tx_queues, i);
     304          14 :       max_log2_ring_sz = clib_max (max_log2_ring_sz, mq->log2_ring_size);
     305             : 
     306          14 :       mq->ring = mif->regions[mq->region].shm + mq->offset;
     307          14 :       if (mq->ring->cookie != MEMIF_COOKIE)
     308             :         {
     309           0 :           err = clib_error_return (0, "wrong cookie on tx ring %u", i);
     310           0 :           goto error;
     311             :         }
     312          14 :       mq->queue_index =
     313          14 :         vnet_hw_if_register_tx_queue (vnm, mif->hw_if_index, i);
     314          14 :       clib_spinlock_init (&mq->lockp);
     315             : 
     316          14 :       if (mif->flags & MEMIF_IF_FLAG_USE_DMA)
     317             :         {
     318             :           memif_dma_info_t *dma_info;
     319           0 :           mq->dma_head = 0;
     320           0 :           mq->dma_tail = 0;
     321           0 :           mq->dma_info_head = 0;
     322           0 :           mq->dma_info_tail = 0;
     323           0 :           mq->dma_info_size = MEMIF_DMA_INFO_SIZE;
     324           0 :           vec_validate_aligned (mq->dma_info, MEMIF_DMA_INFO_SIZE,
     325             :                                 CLIB_CACHE_LINE_BYTES);
     326             : 
     327           0 :           vec_foreach (dma_info, mq->dma_info)
     328             :             {
     329           0 :               vec_validate_aligned (dma_info->data.desc_data,
     330             :                                     pow2_mask (max_log2_ring_sz),
     331             :                                     CLIB_CACHE_LINE_BYTES);
     332           0 :               vec_validate_aligned (dma_info->data.desc_len,
     333             :                                     pow2_mask (max_log2_ring_sz),
     334             :                                     CLIB_CACHE_LINE_BYTES);
     335           0 :               vec_validate_aligned (dma_info->data.desc_status,
     336             :                                     pow2_mask (max_log2_ring_sz),
     337             :                                     CLIB_CACHE_LINE_BYTES);
     338           0 :               vec_validate_aligned (dma_info->data.copy_ops, 0,
     339             :                                     CLIB_CACHE_LINE_BYTES);
     340           0 :               vec_reset_length (dma_info->data.copy_ops);
     341           0 :               vec_validate_aligned (dma_info->data.buffers, 0,
     342             :                                     CLIB_CACHE_LINE_BYTES);
     343           0 :               vec_reset_length (dma_info->data.buffers);
     344             :             }
     345             :         }
     346             :     }
     347             : 
     348          14 :   if (vec_len (mif->tx_queues) > 0)
     349             :     {
     350          14 :       n_txqs = vec_len (mif->tx_queues);
     351          28 :       for (j = 0; j < n_threads; j++)
     352             :         {
     353          14 :           u32 qi = mif->tx_queues[j % n_txqs].queue_index;
     354          14 :           vnet_hw_if_tx_queue_assign_thread (vnm, qi, j);
     355             :         }
     356             :     }
     357             : 
     358          28 :   vec_foreach_index (i, mif->rx_queues)
     359             :     {
     360          14 :       memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, i);
     361             :       u32 ti;
     362             :       u32 qi;
     363             :       int rv;
     364             : 
     365          14 :       max_log2_ring_sz = clib_max (max_log2_ring_sz, mq->log2_ring_size);
     366             : 
     367          14 :       mq->ring = mif->regions[mq->region].shm + mq->offset;
     368          14 :       if (mq->ring->cookie != MEMIF_COOKIE)
     369             :         {
     370           0 :           err = clib_error_return (0, "wrong cookie on tx ring %u", i);
     371           0 :           goto error;
     372             :         }
     373          14 :       qi = vnet_hw_if_register_rx_queue (vnm, mif->hw_if_index, i,
     374             :                                          VNET_HW_IF_RXQ_THREAD_ANY);
     375          14 :       mq->queue_index = qi;
     376             : 
     377          14 :       if (mif->flags & MEMIF_IF_FLAG_USE_DMA)
     378             :         {
     379             :           memif_dma_info_t *dma_info;
     380           0 :           mq->dma_head = 0;
     381           0 :           mq->dma_tail = 0;
     382           0 :           mq->dma_info_head = 0;
     383           0 :           mq->dma_info_tail = 0;
     384           0 :           mq->dma_info_size = MEMIF_DMA_INFO_SIZE;
     385           0 :           vec_validate_aligned (mq->dma_info, MEMIF_DMA_INFO_SIZE,
     386             :                                 CLIB_CACHE_LINE_BYTES);
     387           0 :           vec_foreach (dma_info, mq->dma_info)
     388             :             {
     389           0 :               vec_validate_aligned (dma_info->data.desc_data,
     390             :                                     pow2_mask (max_log2_ring_sz),
     391             :                                     CLIB_CACHE_LINE_BYTES);
     392           0 :               vec_validate_aligned (dma_info->data.desc_len,
     393             :                                     pow2_mask (max_log2_ring_sz),
     394             :                                     CLIB_CACHE_LINE_BYTES);
     395           0 :               vec_validate_aligned (dma_info->data.desc_status,
     396             :                                     pow2_mask (max_log2_ring_sz),
     397             :                                     CLIB_CACHE_LINE_BYTES);
     398           0 :               vec_validate_aligned (dma_info->data.copy_ops, 0,
     399             :                                     CLIB_CACHE_LINE_BYTES);
     400           0 :               vec_reset_length (dma_info->data.copy_ops);
     401           0 :               vec_validate_aligned (dma_info->data.buffers, 0,
     402             :                                     CLIB_CACHE_LINE_BYTES);
     403           0 :               vec_reset_length (dma_info->data.buffers);
     404             :             }
     405             :         }
     406             : 
     407          14 :       if (mq->int_fd > -1)
     408             :         {
     409          14 :           template.file_descriptor = mq->int_fd;
     410          14 :           template.private_data = (mif->dev_instance << 16) | (i & 0xFFFF);
     411          14 :           template.description = format (0, "%U rx %u int",
     412             :                                          format_memif_device_name,
     413             :                                          mif->dev_instance, i);
     414          14 :           memif_file_add (&mq->int_clib_file_index, &template);
     415          14 :           vnet_hw_if_set_rx_queue_file_index (vnm, qi,
     416          14 :                                               mq->int_clib_file_index);
     417             :         }
     418          14 :       ti = vnet_hw_if_get_rx_queue_thread_index (vnm, qi);
     419          14 :       mq->buffer_pool_index = vlib_buffer_pool_get_default_for_numa (
     420          14 :         vm, vlib_get_main_by_index (ti)->numa_node);
     421          14 :       rv = vnet_hw_if_set_rx_queue_mode (vnm, qi, VNET_HW_IF_RX_MODE_DEFAULT);
     422          14 :       vnet_hw_if_update_runtime_data (vnm, mif->hw_if_index);
     423             : 
     424          14 :       if (rv)
     425           0 :         memif_log_err
     426             :           (mif, "Warning: unable to set rx mode for interface %d queue %d: "
     427             :            "rc=%d", mif->hw_if_index, i, rv);
     428             :       else
     429             :         {
     430          14 :           vnet_hw_if_rx_mode rxmode = vnet_hw_if_get_rx_queue_mode (vnm, qi);
     431             : 
     432          14 :           if (rxmode == VNET_HW_IF_RX_MODE_POLLING)
     433          14 :             mq->ring->flags |= MEMIF_RING_FLAG_MASK_INT;
     434             :           else
     435           0 :             vnet_hw_if_rx_queue_set_int_pending (vnm, qi);
     436             :         }
     437             :     }
     438             :   /* *INDENT-ON* */
     439             : 
     440          14 :   if (1 << max_log2_ring_sz > vec_len (mm->per_thread_data[0].desc_data))
     441             :     {
     442             :       memif_per_thread_data_t *ptd;
     443             : 
     444           8 :       vec_foreach (ptd, mm->per_thread_data)
     445             :         {
     446           4 :           vec_validate_aligned (ptd->desc_data, pow2_mask (max_log2_ring_sz),
     447             :                                 CLIB_CACHE_LINE_BYTES);
     448           4 :           vec_validate_aligned (ptd->desc_len, pow2_mask (max_log2_ring_sz),
     449             :                                 CLIB_CACHE_LINE_BYTES);
     450           4 :           vec_validate_aligned (ptd->desc_status, pow2_mask (max_log2_ring_sz),
     451             :                                 CLIB_CACHE_LINE_BYTES);
     452             :         }
     453             :     }
     454          14 :   if (with_barrier)
     455           0 :     vlib_worker_thread_barrier_release (vm);
     456             : 
     457          14 :   mif->flags &= ~MEMIF_IF_FLAG_CONNECTING;
     458          14 :   mif->flags |= MEMIF_IF_FLAG_CONNECTED;
     459             : 
     460          14 :   vnet_hw_interface_set_flags (vnm, mif->hw_if_index,
     461             :                                VNET_HW_INTERFACE_FLAG_LINK_UP);
     462          14 :   return 0;
     463             : 
     464           0 : error:
     465           0 :   if (with_barrier)
     466           0 :     vlib_worker_thread_barrier_release (vm);
     467           0 :   memif_log_err (mif, "%U", format_clib_error, err);
     468           0 :   return err;
     469             : }
     470             : 
     471             : static_always_inline memif_ring_t *
     472          28 : memif_get_ring (memif_if_t * mif, memif_ring_type_t type, u16 ring_num)
     473             : {
     474          28 :   if (vec_len (mif->regions) == 0)
     475           0 :     return NULL;
     476          28 :   void *p = mif->regions[0].shm;
     477          28 :   int ring_size =
     478          28 :     sizeof (memif_ring_t) +
     479          28 :     sizeof (memif_desc_t) * (1 << mif->run.log2_ring_size);
     480          28 :   p += (ring_num + type * mif->run.num_s2m_rings) * ring_size;
     481             : 
     482          28 :   return (memif_ring_t *) p;
     483             : }
     484             : 
     485             : clib_error_t *
     486           7 : memif_init_regions_and_queues (memif_if_t * mif)
     487             : {
     488           7 :   vlib_main_t *vm = vlib_get_main ();
     489             :   memif_socket_file_t *msf;
     490           7 :   memif_ring_t *ring = NULL;
     491             :   int fd, i, j;
     492             :   u64 buffer_offset;
     493             :   memif_region_t *r;
     494             :   clib_error_t *err;
     495             : 
     496           7 :   ASSERT (vec_len (mif->regions) == 0);
     497           7 :   vec_add2_aligned (mif->regions, r, 1, CLIB_CACHE_LINE_BYTES);
     498             : 
     499           7 :   buffer_offset = (mif->run.num_s2m_rings + mif->run.num_m2s_rings) *
     500           7 :     (sizeof (memif_ring_t) +
     501           7 :      sizeof (memif_desc_t) * (1 << mif->run.log2_ring_size));
     502             : 
     503           7 :   r->region_size = buffer_offset;
     504             : 
     505           7 :   if ((mif->flags & MEMIF_IF_FLAG_ZERO_COPY) == 0)
     506           0 :     r->region_size += mif->run.buffer_size * (1 << mif->run.log2_ring_size) *
     507           0 :       (mif->run.num_s2m_rings + mif->run.num_m2s_rings);
     508             : 
     509           7 :   if ((fd = clib_mem_vm_create_fd (CLIB_MEM_PAGE_SZ_DEFAULT, "%U region 0",
     510             :                                    format_memif_device_name,
     511             :                                    mif->dev_instance)) == -1)
     512             :     {
     513           0 :       err = clib_mem_get_last_error ();
     514           0 :       goto error;
     515             :     }
     516             : 
     517           7 :   if ((ftruncate (fd, r->region_size)) == -1)
     518             :     {
     519           0 :       err = clib_error_return_unix (0, "ftruncate");
     520           0 :       goto error;
     521             :     }
     522             : 
     523           7 :   msf = pool_elt_at_index (memif_main.socket_files, mif->socket_file_index);
     524           7 :   r->shm = clib_mem_vm_map_shared (0, r->region_size, fd, 0, "memif%lu/%lu:0",
     525             :                                    msf->socket_id, mif->id);
     526             : 
     527           7 :   if (r->shm == CLIB_MEM_VM_MAP_FAILED)
     528             :     {
     529           0 :       err = clib_error_return_unix (0, "memif shared region map failed");
     530           0 :       goto error;
     531             :     }
     532             : 
     533           7 :   r->fd = fd;
     534             : 
     535           7 :   if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
     536             :     {
     537             :       vlib_buffer_pool_t *bp;
     538             :       /* *INDENT-OFF* */
     539          14 :       vec_foreach (bp, vm->buffer_main->buffer_pools)
     540             :         {
     541             :           vlib_physmem_map_t *pm;
     542           7 :           pm = vlib_physmem_get_map (vm, bp->physmem_map_index);
     543           7 :           vec_add2_aligned (mif->regions, r, 1, CLIB_CACHE_LINE_BYTES);
     544           7 :           r->fd = pm->fd;
     545           7 :           r->region_size = pm->n_pages << pm->log2_page_size;
     546           7 :           r->shm = pm->base;
     547           7 :           r->is_external = 1;
     548             :         }
     549             :       /* *INDENT-ON* */
     550             :     }
     551             : 
     552          14 :   for (i = 0; i < mif->run.num_s2m_rings; i++)
     553             :     {
     554           7 :       ring = memif_get_ring (mif, MEMIF_RING_S2M, i);
     555           7 :       ring->head = ring->tail = 0;
     556           7 :       ring->cookie = MEMIF_COOKIE;
     557             : 
     558           7 :       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
     559           7 :         continue;
     560             : 
     561           0 :       for (j = 0; j < (1 << mif->run.log2_ring_size); j++)
     562             :         {
     563           0 :           u16 slot = i * (1 << mif->run.log2_ring_size) + j;
     564           0 :           ring->desc[j].region = 0;
     565           0 :           ring->desc[j].offset =
     566           0 :             buffer_offset + (u32) (slot * mif->run.buffer_size);
     567           0 :           ring->desc[j].length = mif->run.buffer_size;
     568             :         }
     569             :     }
     570          14 :   for (i = 0; i < mif->run.num_m2s_rings; i++)
     571             :     {
     572           7 :       ring = memif_get_ring (mif, MEMIF_RING_M2S, i);
     573           7 :       ring->head = ring->tail = 0;
     574           7 :       ring->cookie = MEMIF_COOKIE;
     575             : 
     576           7 :       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
     577           7 :         continue;
     578             : 
     579           0 :       for (j = 0; j < (1 << mif->run.log2_ring_size); j++)
     580             :         {
     581           0 :           u16 slot =
     582           0 :             (i + mif->run.num_s2m_rings) * (1 << mif->run.log2_ring_size) + j;
     583           0 :           ring->desc[j].region = 0;
     584           0 :           ring->desc[j].offset =
     585           0 :             buffer_offset + (u32) (slot * mif->run.buffer_size);
     586           0 :           ring->desc[j].length = mif->run.buffer_size;
     587             :         }
     588             :     }
     589             : 
     590           7 :   ASSERT (mif->tx_queues == 0);
     591           7 :   vec_validate_aligned (mif->tx_queues, mif->run.num_s2m_rings - 1,
     592             :                         CLIB_CACHE_LINE_BYTES);
     593             : 
     594             :   /* *INDENT-OFF* */
     595          14 :   vec_foreach_index (i, mif->tx_queues)
     596             :     {
     597           7 :       memif_queue_t *mq = vec_elt_at_index (mif->tx_queues, i);
     598           7 :       if ((mq->int_fd = eventfd (0, EFD_NONBLOCK)) < 0)
     599             :         {
     600           0 :           err = clib_error_return_unix (0, "eventfd[tx queue %u]", i);
     601           0 :           goto error;
     602             :         }
     603             : 
     604           7 :       mq->int_clib_file_index = ~0;
     605           7 :       mq->ring = memif_get_ring (mif, MEMIF_RING_S2M, i);
     606           7 :       mq->log2_ring_size = mif->cfg.log2_ring_size;
     607           7 :       mq->region = 0;
     608           7 :       mq->offset = (void *) mq->ring - (void *) mif->regions[mq->region].shm;
     609           7 :       mq->last_head = 0;
     610           7 :       mq->type = MEMIF_RING_S2M;
     611           7 :       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
     612           7 :         vec_validate_aligned (mq->buffers, 1 << mq->log2_ring_size,
     613             :                               CLIB_CACHE_LINE_BYTES);
     614             :     }
     615             :   /* *INDENT-ON* */
     616             : 
     617           7 :   ASSERT (mif->rx_queues == 0);
     618           7 :   vec_validate_aligned (mif->rx_queues, mif->run.num_m2s_rings - 1,
     619             :                         CLIB_CACHE_LINE_BYTES);
     620             : 
     621             :   /* *INDENT-OFF* */
     622          14 :   vec_foreach_index (i, mif->rx_queues)
     623             :     {
     624           7 :       memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, i);
     625           7 :       if ((mq->int_fd = eventfd (0, EFD_NONBLOCK)) < 0)
     626             :         {
     627           0 :           err = clib_error_return_unix (0, "eventfd[rx queue %u]", i);
     628           0 :           goto error;
     629             :         }
     630           7 :       mq->int_clib_file_index = ~0;
     631           7 :       mq->ring = memif_get_ring (mif, MEMIF_RING_M2S, i);
     632           7 :       mq->log2_ring_size = mif->cfg.log2_ring_size;
     633           7 :       mq->region = 0;
     634           7 :       mq->offset = (void *) mq->ring - (void *) mif->regions[mq->region].shm;
     635           7 :       mq->last_head = 0;
     636           7 :       mq->type = MEMIF_RING_M2S;
     637           7 :       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
     638           7 :         vec_validate_aligned (mq->buffers, 1 << mq->log2_ring_size,
     639             :                               CLIB_CACHE_LINE_BYTES);
     640             :     }
     641             :   /* *INDENT-ON* */
     642             : 
     643           7 :   return 0;
     644             : 
     645           0 : error:
     646           0 :   memif_log_err (mif, "%U", format_clib_error, err);
     647           0 :   return err;
     648             : }
     649             : 
     650             : static uword
     651         575 : memif_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
     652             : {
     653         575 :   memif_main_t *mm = &memif_main;
     654             :   memif_if_t *mif;
     655             :   clib_socket_t *sock;
     656         575 :   uword *event_data = 0, event_type;
     657         575 :   u8 enabled = 0;
     658         575 :   f64 start_time, last_run_duration = 0, now;
     659             :   clib_error_t *err;
     660             : 
     661         575 :   sock = clib_mem_alloc (sizeof (clib_socket_t));
     662         575 :   clib_memset (sock, 0, sizeof (clib_socket_t));
     663             : 
     664             :   while (1)
     665             :     {
     666         638 :       if (enabled)
     667          47 :         vlib_process_wait_for_event_or_clock (vm, (f64) 3 -
     668             :                                               last_run_duration);
     669             :       else
     670         591 :         vlib_process_wait_for_event (vm);
     671             : 
     672          63 :       event_type = vlib_process_get_events (vm, &event_data);
     673          63 :       vec_reset_length (event_data);
     674             : 
     675          63 :       switch (event_type)
     676             :         {
     677           3 :         case ~0:
     678           3 :           break;
     679          18 :         case MEMIF_PROCESS_EVENT_START:
     680          18 :           enabled = 1;
     681          18 :           break;
     682          16 :         case MEMIF_PROCESS_EVENT_STOP:
     683          16 :           enabled = 0;
     684          16 :           continue;
     685          26 :         case MEMIF_PROCESS_EVENT_ADMIN_UP_DOWN:
     686          26 :           break;
     687           0 :         default:
     688           0 :           ASSERT (0);
     689             :         }
     690             : 
     691          47 :       last_run_duration = start_time = vlib_time_now (vm);
     692             :       /* *INDENT-OFF* */
     693          96 :       pool_foreach (mif, mm->interfaces)
     694             :          {
     695          49 :           memif_socket_file_t * msf = vec_elt_at_index (mm->socket_files, mif->socket_file_index);
     696             :           /* Allow no more than 10us without a pause */
     697          49 :           now = vlib_time_now (vm);
     698          49 :           if (now > start_time + 10e-6)
     699             :             {
     700           0 :               vlib_process_suspend (vm, 100e-6);        /* suspend for 100 us */
     701           0 :               start_time = vlib_time_now (vm);
     702             :             }
     703             : 
     704          49 :           if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) == 0)
     705          20 :             continue;
     706             : 
     707          29 :           if (mif->flags & MEMIF_IF_FLAG_CONNECTING)
     708           0 :             continue;
     709             : 
     710          29 :           if (mif->flags & MEMIF_IF_FLAG_CONNECTED)
     711          13 :             continue;
     712             : 
     713          16 :           if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
     714             :             {
     715           8 :               clib_memset (sock, 0, sizeof(clib_socket_t));
     716           8 :               sock->config = (char *) msf->filename;
     717           8 :               sock->is_seqpacket = 1;
     718           8 :               sock->is_blocking = 1;
     719             : 
     720           8 :               if ((err = clib_socket_init (sock)))
     721             :                 {
     722           1 :                   clib_error_free (err);
     723             :                 }
     724             :               else
     725             :                 {
     726           7 :                   clib_file_t t = { 0 };
     727             : 
     728           7 :                   t.read_function = memif_slave_conn_fd_read_ready;
     729           7 :                   t.write_function = memif_slave_conn_fd_write_ready;
     730           7 :                   t.error_function = memif_slave_conn_fd_error;
     731           7 :                   t.file_descriptor = sock->fd;
     732           7 :                   t.private_data = mif->dev_instance;
     733           7 :                   memif_file_add (&sock->private_data, &t);
     734           7 :                   t.description = format (0, "%U ctl",
     735             :                                           format_memif_device_name,
     736             :                                           mif->dev_instance);
     737           7 :                   hash_set (msf->dev_instance_by_fd, sock->fd, mif->dev_instance);
     738             : 
     739           7 :                   mif->flags |= MEMIF_IF_FLAG_CONNECTING;
     740           7 :                   mif->sock = sock;
     741           7 :                   sock = clib_mem_alloc (sizeof(clib_socket_t));
     742             :                 }
     743             :             }
     744             :         }
     745             :       /* *INDENT-ON* */
     746          47 :       last_run_duration = vlib_time_now (vm) - last_run_duration;
     747             :     }
     748             :   return 0;
     749             : }
     750             : 
     751       85850 : VLIB_REGISTER_NODE (memif_process_node,static) = {
     752             :   .function = memif_process,
     753             :   .type = VLIB_NODE_TYPE_PROCESS,
     754             :   .name = "memif-process",
     755             : };
     756             : 
     757             : /*
     758             :  * Returns an unused socket id, and ~0 if it can't find one.
     759             :  */
     760             : u32
     761           0 : memif_get_unused_socket_id ()
     762             : {
     763           0 :   memif_main_t *mm = &memif_main;
     764             :   uword *p;
     765             :   int i, j;
     766             : 
     767             :   static u32 seed = 0;
     768             :   /* limit to 1M tries */
     769           0 :   for (j = 0; j < 1 << 10; j++)
     770             :     {
     771           0 :       seed = random_u32 (&seed);
     772           0 :       for (i = 0; i < 1 << 10; i++)
     773             :         {
     774             :           /* look around randomly generated id */
     775           0 :           seed += (2 * (i % 2) - 1) * i;
     776           0 :           if (seed == (u32) ~0)
     777           0 :             continue;
     778           0 :           p = hash_get (mm->socket_file_index_by_sock_id, seed);
     779           0 :           if (!p)
     780           0 :             return seed;
     781             :         }
     782             :     }
     783             : 
     784           0 :   return ~0;
     785             : }
     786             : 
     787             : clib_error_t *
     788         599 : memif_socket_filename_add_del (u8 is_add, u32 sock_id, char *sock_filename)
     789             : {
     790         599 :   memif_main_t *mm = &memif_main;
     791             :   uword *p;
     792             :   memif_socket_file_t *msf;
     793         599 :   clib_error_t *err = 0;
     794         599 :   char *dir = 0, *tmp;
     795         599 :   u32 idx = 0;
     796         599 :   u8 *name = 0;
     797             : 
     798             :   /* allow adding socket id 0 */
     799         599 :   if (sock_id == 0 && is_add == 0)
     800           0 :     return vnet_error (VNET_ERR_INVALID_ARGUMENT, "cannot delete socket id 0");
     801             : 
     802         599 :   if (sock_id == ~0)
     803           0 :     return vnet_error (VNET_ERR_INVALID_ARGUMENT,
     804             :                        "socked id is not specified");
     805             : 
     806         599 :   if (is_add == 0)
     807             :     {
     808           9 :       p = hash_get (mm->socket_file_index_by_sock_id, sock_id);
     809           9 :       if (!p)
     810             :         /* Don't delete non-existent entries. */
     811           0 :         return vnet_error (VNET_ERR_INVALID_ARGUMENT,
     812             :                            "socket file with id %u does not exist", sock_id);
     813             : 
     814           9 :       msf = pool_elt_at_index (mm->socket_files, *p);
     815           9 :       if (msf->ref_cnt > 0)
     816           0 :         return vnet_error (VNET_ERR_UNEXPECTED_INTF_STATE,
     817           0 :                            "socket file '%s' is in use", msf->filename);
     818             : 
     819           9 :       vec_free (msf->filename);
     820           9 :       pool_put (mm->socket_files, msf);
     821             : 
     822           9 :       hash_unset (mm->socket_file_index_by_sock_id, sock_id);
     823             : 
     824           9 :       return 0;
     825             :     }
     826             : 
     827         590 :   if (sock_filename == 0 || sock_filename[0] == 0)
     828           0 :     return vnet_error (VNET_ERR_INVALID_ARGUMENT,
     829             :                        "socket filename not specified");
     830             : 
     831         590 :   if (clib_socket_prefix_is_valid (sock_filename))
     832             :     {
     833           0 :       name = format (0, "%s%c", sock_filename, 0);
     834             :     }
     835         590 :   else if (sock_filename[0] == '/')
     836             :     {
     837          11 :       name = format (0, "%s%c", sock_filename, 0);
     838             :     }
     839             :   else
     840             :     {
     841             :       /* copy runtime dir path */
     842         579 :       vec_add (dir, vlib_unix_get_runtime_dir (),
     843             :                strlen (vlib_unix_get_runtime_dir ()));
     844         579 :       vec_add1 (dir, '/');
     845             : 
     846             :       /* if sock_filename contains dirs, add them to path */
     847         579 :       tmp = strrchr (sock_filename, '/');
     848         579 :       if (tmp)
     849             :         {
     850           2 :           idx = tmp - sock_filename;
     851           2 :           vec_add (dir, sock_filename, idx);
     852             :         }
     853             : 
     854         579 :       vec_add1 (dir, '\0');
     855             :       /* create socket dir */
     856         579 :       if ((err = vlib_unix_recursive_mkdir (dir)))
     857             :         {
     858           0 :           clib_error_free (err);
     859           0 :           err = vnet_error (VNET_ERR_SYSCALL_ERROR_1,
     860             :                             "unable to create socket dir");
     861           0 :           goto done;
     862             :         }
     863             : 
     864         579 :       name =
     865         579 :         format (0, "%s/%s%c", vlib_unix_get_runtime_dir (), sock_filename, 0);
     866             :     }
     867             : 
     868         590 :   p = hash_get (mm->socket_file_index_by_sock_id, sock_id);
     869         590 :   if (p)
     870             :     {
     871           0 :       msf = pool_elt_at_index (mm->socket_files, *p);
     872           0 :       if (strcmp ((char *) msf->filename, (char *) name) == 0)
     873             :         {
     874             :           /* Silently accept identical "add". */
     875           0 :           goto done;
     876             :         }
     877             : 
     878             :       /* But don't allow a direct add of a different filename. */
     879           0 :       err = vnet_error (VNET_ERR_ENTRY_ALREADY_EXISTS, "entry already exists");
     880           0 :       goto done;
     881             :     }
     882             : 
     883         590 :   pool_get (mm->socket_files, msf);
     884         590 :   clib_memset (msf, 0, sizeof (memif_socket_file_t));
     885             : 
     886         590 :   msf->filename = name;
     887         590 :   msf->socket_id = sock_id;
     888         590 :   name = 0;
     889             : 
     890         590 :   hash_set (mm->socket_file_index_by_sock_id, sock_id, msf - mm->socket_files);
     891             : 
     892         590 : done:
     893         590 :   vec_free (name);
     894         590 :   vec_free (dir);
     895         590 :   return err;
     896             : }
     897             : 
     898             : clib_error_t *
     899          16 : memif_delete_if (vlib_main_t *vm, memif_if_t *mif)
     900             : {
     901          16 :   vnet_main_t *vnm = vnet_get_main ();
     902          16 :   memif_main_t *mm = &memif_main;
     903          16 :   memif_socket_file_t *msf =
     904          16 :     vec_elt_at_index (mm->socket_files, mif->socket_file_index);
     905             :   clib_error_t *err;
     906             : 
     907          16 :   mif->flags |= MEMIF_IF_FLAG_DELETING;
     908          16 :   vec_free (mif->local_disc_string);
     909          16 :   vec_free (mif->remote_disc_string);
     910             : 
     911             :   /* bring down the interface */
     912          16 :   vnet_hw_interface_set_flags (vnm, mif->hw_if_index, 0);
     913          16 :   vnet_sw_interface_set_flags (vnm, mif->sw_if_index, 0);
     914             : 
     915          16 :   err = clib_error_return (0, "interface deleted");
     916          16 :   memif_disconnect (mif, err);
     917          16 :   clib_error_free (err);
     918             : 
     919          16 :   if (mif->hw_if_index != ~0)
     920             :     {
     921             :       /* remove the interface */
     922          16 :       if (mif->mode == MEMIF_INTERFACE_MODE_IP)
     923           0 :         vnet_delete_hw_interface (vnm, mif->hw_if_index);
     924             :       else
     925          16 :         ethernet_delete_interface (vnm, mif->hw_if_index);
     926          16 :       mif->hw_if_index = ~0;
     927             :     }
     928             : 
     929             :   /* free interface data structures */
     930          16 :   mhash_unset (&msf->dev_instance_by_id, &mif->id, 0);
     931             : 
     932             :   /* remove socket file */
     933          16 :   if (--(msf->ref_cnt) == 0)
     934             :     {
     935          16 :       if (msf->is_listener)
     936             :         {
     937             :           int i;
     938             :           /* *INDENT-OFF* */
     939           8 :           vec_foreach_index (i, msf->pending_clients)
     940           0 :             memif_socket_close (msf->pending_clients + i);
     941             :           /* *INDENT-ON* */
     942           8 :           memif_socket_close (&msf->sock);
     943           8 :           vec_free (msf->pending_clients);
     944             :         }
     945          16 :       mhash_free (&msf->dev_instance_by_id);
     946          16 :       hash_free (msf->dev_instance_by_fd);
     947          16 :       if (msf->sock)
     948             :         {
     949           0 :           err = clib_socket_close (msf->sock);
     950           0 :           if (err)
     951             :             {
     952           0 :               memif_log_err (mif, "%U", format_clib_error, err);
     953           0 :               clib_error_free (err);
     954             :             }
     955           0 :           clib_mem_free (msf->sock);
     956             :         }
     957             :     }
     958             : 
     959          16 :   vec_free (mif->local_disc_string);
     960          16 :   clib_memset (mif, 0, sizeof (*mif));
     961          16 :   pool_put (mm->interfaces, mif);
     962             : 
     963          16 :   if (pool_elts (mm->interfaces) == 0)
     964          16 :     vlib_process_signal_event (vm, memif_process_node.index,
     965             :                                MEMIF_PROCESS_EVENT_STOP, 0);
     966             : 
     967          16 :   return 0;
     968             : }
     969             : 
     970             : /* *INDENT-OFF* */
     971        3455 : VNET_HW_INTERFACE_CLASS (memif_ip_hw_if_class, static) = {
     972             :   .name = "memif-ip",
     973             :   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
     974             :   .tx_hash_fn_type = VNET_HASH_FN_TYPE_IP,
     975             : };
     976             : /* *INDENT-ON* */
     977             : 
     978             : static void
     979           0 : memif_prepare_dma_args (vlib_dma_config_t *args)
     980             : {
     981           0 :   args->max_batches = 256;
     982           0 :   args->max_transfer_size = VLIB_BUFFER_DEFAULT_DATA_SIZE;
     983           0 :   args->barrier_before_last = 1;
     984           0 :   args->sw_fallback = 1;
     985           0 :   args->callback_fn = NULL;
     986           0 : }
     987             : 
     988             : clib_error_t *
     989          22 : memif_create_if (vlib_main_t *vm, memif_create_if_args_t *args)
     990             : {
     991          22 :   memif_main_t *mm = &memif_main;
     992          22 :   vlib_thread_main_t *tm = vlib_get_thread_main ();
     993          22 :   vnet_main_t *vnm = vnet_get_main ();
     994          22 :   vnet_eth_interface_registration_t eir = {};
     995          22 :   memif_if_t *mif = 0;
     996             :   vnet_sw_interface_t *sw;
     997             :   uword *p;
     998          22 :   memif_socket_file_t *msf = 0;
     999          22 :   clib_error_t *err = 0;
    1000             : 
    1001          22 :   p = hash_get (mm->socket_file_index_by_sock_id, args->socket_id);
    1002          22 :   if (p == 0)
    1003             :     {
    1004           0 :       err = vnet_error (VNET_ERR_INVALID_ARGUMENT, "unknown socket id");
    1005           0 :       goto done;
    1006             :     }
    1007             : 
    1008          22 :   msf = vec_elt_at_index (mm->socket_files, p[0]);
    1009             : 
    1010             :   /* existing socket file can be either master or slave but cannot be both */
    1011          22 :   if (msf->ref_cnt > 0)
    1012             :     {
    1013           0 :       if ((!msf->is_listener != !args->is_master))
    1014             :         {
    1015             :           err =
    1016           0 :             vnet_error (VNET_ERR_SUBIF_ALREADY_EXISTS,
    1017             :                         "socket file cannot be used by both master and slave");
    1018           0 :           goto done;
    1019             :         }
    1020             : 
    1021           0 :       p = mhash_get (&msf->dev_instance_by_id, &args->id);
    1022           0 :       if (p)
    1023             :         {
    1024           0 :           err = vnet_error (VNET_ERR_SUBIF_ALREADY_EXISTS,
    1025             :                             "interface already exists");
    1026           0 :           goto done;
    1027             :         }
    1028             :     }
    1029             : 
    1030             :   /* Create new socket file */
    1031          22 :   if (msf->ref_cnt == 0)
    1032             :     {
    1033          22 :       mhash_init (&msf->dev_instance_by_id, sizeof (uword),
    1034             :                   sizeof (memif_interface_id_t));
    1035          22 :       msf->dev_instance_by_fd = hash_create (0, sizeof (uword));
    1036          22 :       msf->is_listener = (args->is_master != 0);
    1037             : 
    1038          22 :       memif_log_debug (0, "initializing socket file %s", msf->filename);
    1039             :     }
    1040             : 
    1041          22 :   if (mm->per_thread_data == 0)
    1042             :     {
    1043             :       int i;
    1044             : 
    1045           4 :       vec_validate_aligned (mm->per_thread_data, tm->n_vlib_mains - 1,
    1046             :                             CLIB_CACHE_LINE_BYTES);
    1047             : 
    1048           8 :       for (i = 0; i < tm->n_vlib_mains; i++)
    1049             :         {
    1050           4 :           memif_per_thread_data_t *ptd =
    1051           4 :             vec_elt_at_index (mm->per_thread_data, i);
    1052           4 :           vlib_buffer_t *bt = &ptd->buffer_template;
    1053           4 :           clib_memset (bt, 0, sizeof (vlib_buffer_t));
    1054           4 :           bt->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
    1055           4 :           bt->total_length_not_including_first_buffer = 0;
    1056           4 :           vnet_buffer (bt)->sw_if_index[VLIB_TX] = (u32) ~ 0;
    1057             : 
    1058           4 :           vec_validate_aligned (ptd->copy_ops, 0, CLIB_CACHE_LINE_BYTES);
    1059           4 :           vec_reset_length (ptd->copy_ops);
    1060           4 :           vec_validate_aligned (ptd->buffers, 0, CLIB_CACHE_LINE_BYTES);
    1061           4 :           vec_reset_length (ptd->buffers);
    1062             :         }
    1063             :     }
    1064             : 
    1065          22 :   pool_get (mm->interfaces, mif);
    1066          22 :   clib_memset (mif, 0, sizeof (*mif));
    1067          22 :   mif->dev_instance = mif - mm->interfaces;
    1068          22 :   mif->socket_file_index = msf - mm->socket_files;
    1069          22 :   mif->id = args->id;
    1070          22 :   mif->sw_if_index = mif->hw_if_index = mif->per_interface_next_index = ~0;
    1071          22 :   mif->mode = args->mode;
    1072          22 :   if (args->secret)
    1073           6 :     mif->secret = vec_dup (args->secret);
    1074             : 
    1075             :   /* register dma config if enabled */
    1076          22 :   if (args->use_dma)
    1077             :     {
    1078             :       vlib_dma_config_t dma_args;
    1079           0 :       bzero (&dma_args, sizeof (dma_args));
    1080           0 :       memif_prepare_dma_args (&dma_args);
    1081             : 
    1082           0 :       dma_args.max_transfers = 1 << args->log2_ring_size;
    1083           0 :       dma_args.callback_fn = memif_dma_completion_cb;
    1084           0 :       mif->dma_input_config = vlib_dma_config_add (vm, &dma_args);
    1085           0 :       dma_args.callback_fn = memif_tx_dma_completion_cb;
    1086           0 :       mif->dma_tx_config = vlib_dma_config_add (vm, &dma_args);
    1087             :     }
    1088             : 
    1089          22 :   if (mif->mode == MEMIF_INTERFACE_MODE_ETHERNET)
    1090             :     {
    1091             : 
    1092          22 :       if (!args->hw_addr_set)
    1093             :         {
    1094          22 :           f64 now = vlib_time_now (vm);
    1095             :           u32 rnd;
    1096          22 :           rnd = (u32) (now * 1e6);
    1097          22 :           rnd = random_u32 (&rnd);
    1098             : 
    1099          22 :           memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
    1100          22 :           args->hw_addr[0] = 2;
    1101          22 :           args->hw_addr[1] = 0xfe;
    1102             :         }
    1103             : 
    1104          22 :       eir.dev_class_index = memif_device_class.index;
    1105          22 :       eir.dev_instance = mif->dev_instance;
    1106          22 :       eir.address = args->hw_addr;
    1107          22 :       eir.cb.flag_change = memif_eth_flag_change;
    1108          22 :       eir.cb.set_max_frame_size = memif_eth_set_max_frame_size;
    1109          22 :       mif->hw_if_index = vnet_eth_register_interface (vnm, &eir);
    1110             :     }
    1111           0 :   else if (mif->mode == MEMIF_INTERFACE_MODE_IP)
    1112             :     {
    1113           0 :       mif->hw_if_index =
    1114           0 :         vnet_register_interface (vnm, memif_device_class.index,
    1115           0 :                                  mif->dev_instance,
    1116             :                                  memif_ip_hw_if_class.index,
    1117           0 :                                  mif->dev_instance);
    1118             :     }
    1119             :   else
    1120             :     {
    1121             :       err =
    1122           0 :         vnet_error (VNET_ERR_SYSCALL_ERROR_2, "unsupported interface mode");
    1123           0 :       goto error;
    1124             :     }
    1125             : 
    1126          22 :   sw = vnet_get_hw_sw_interface (vnm, mif->hw_if_index);
    1127          22 :   mif->sw_if_index = sw->sw_if_index;
    1128             : 
    1129          22 :   mif->cfg.log2_ring_size = args->log2_ring_size;
    1130          22 :   mif->cfg.buffer_size = args->buffer_size;
    1131          22 :   mif->cfg.num_s2m_rings =
    1132          22 :     args->is_master ? args->rx_queues : args->tx_queues;
    1133          22 :   mif->cfg.num_m2s_rings =
    1134          22 :     args->is_master ? args->tx_queues : args->rx_queues;
    1135             : 
    1136          22 :   args->sw_if_index = mif->sw_if_index;
    1137             : 
    1138             :   /* If this is new one, start listening */
    1139          22 :   if (msf->is_listener && msf->ref_cnt == 0)
    1140             :     {
    1141          11 :       clib_socket_t *s = clib_mem_alloc (sizeof (clib_socket_t));
    1142             : 
    1143          11 :       ASSERT (msf->sock == 0);
    1144          11 :       msf->sock = s;
    1145             : 
    1146          11 :       clib_memset (s, 0, sizeof (clib_socket_t));
    1147          11 :       s->config = (char *) msf->filename;
    1148          11 :       s->local_only = 1;
    1149          11 :       s->is_server = 1;
    1150          11 :       s->allow_group_write = 1;
    1151          11 :       s->is_seqpacket = 1;
    1152          11 :       s->passcred = 1;
    1153             : 
    1154          11 :       if ((err = clib_socket_init (s)))
    1155             :         {
    1156           0 :           err->code = VNET_ERR_SYSCALL_ERROR_4;
    1157           0 :           goto error;
    1158             :         }
    1159             : 
    1160          11 :       clib_file_t template = { 0 };
    1161          11 :       template.read_function = memif_conn_fd_accept_ready;
    1162          11 :       template.file_descriptor = msf->sock->fd;
    1163          11 :       template.private_data = mif->socket_file_index;
    1164          11 :       template.description = format (0, "memif listener %s", msf->filename);
    1165          11 :       memif_file_add (&msf->sock->private_data, &template);
    1166             :     }
    1167             : 
    1168          22 :   msf->ref_cnt++;
    1169             : 
    1170          22 :   if (args->is_master == 0)
    1171             :     {
    1172          11 :       mif->flags |= MEMIF_IF_FLAG_IS_SLAVE;
    1173          11 :       if (args->is_zero_copy)
    1174          11 :         mif->flags |= MEMIF_IF_FLAG_ZERO_COPY;
    1175             :     }
    1176             : 
    1177          22 :   if (args->use_dma)
    1178           0 :     mif->flags |= MEMIF_IF_FLAG_USE_DMA;
    1179             : 
    1180          22 :   vnet_hw_if_set_caps (vnm, mif->hw_if_index, VNET_HW_IF_CAP_INT_MODE);
    1181          22 :   vnet_hw_if_set_input_node (vnm, mif->hw_if_index, memif_input_node.index);
    1182          22 :   mhash_set (&msf->dev_instance_by_id, &mif->id, mif->dev_instance, 0);
    1183             : 
    1184          22 :   if (pool_elts (mm->interfaces) == 1)
    1185             :     {
    1186          18 :       vlib_process_signal_event (vm, memif_process_node.index,
    1187             :                                  MEMIF_PROCESS_EVENT_START, 0);
    1188             :     }
    1189          22 :   goto done;
    1190             : 
    1191           0 : error:
    1192           0 :   memif_delete_if (vm, mif);
    1193           0 :   if (err)
    1194           0 :     memif_log_err (mif, "%U", format_clib_error, err);
    1195           0 :   return err;
    1196             : 
    1197          22 : done:
    1198          22 :   return err;
    1199             : }
    1200             : 
    1201             : clib_error_t *
    1202          26 : memif_interface_admin_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
    1203             : {
    1204          26 :   memif_main_t *mm = &memif_main;
    1205          26 :   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
    1206          26 :   memif_if_t *mif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
    1207             :   static clib_error_t *error = 0;
    1208             : 
    1209          26 :   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
    1210             :     {
    1211          16 :       if (mif->flags & MEMIF_IF_FLAG_CONNECTED)
    1212             :         {
    1213           4 :           vnet_hw_interface_set_flags (vnm, mif->hw_if_index,
    1214             :                                        VNET_HW_INTERFACE_FLAG_LINK_UP);
    1215             :         }
    1216          16 :       mif->flags |= MEMIF_IF_FLAG_ADMIN_UP;
    1217             :     }
    1218             :   else
    1219          10 :     mif->flags &= ~MEMIF_IF_FLAG_ADMIN_UP;
    1220             : 
    1221          26 :   vlib_process_signal_event (vnm->vlib_main, memif_process_node.index,
    1222             :                              MEMIF_PROCESS_EVENT_ADMIN_UP_DOWN, 0);
    1223          26 :   return error;
    1224             : }
    1225             : 
    1226             : static clib_error_t *
    1227         575 : memif_init (vlib_main_t * vm)
    1228             : {
    1229         575 :   memif_main_t *mm = &memif_main;
    1230             : 
    1231         575 :   clib_memset (mm, 0, sizeof (memif_main_t));
    1232             : 
    1233         575 :   mm->log_class = vlib_log_register_class ("memif_plugin", 0);
    1234         575 :   memif_log_debug (0, "initialized");
    1235             : 
    1236             :   /* initialize binary API */
    1237         575 :   memif_plugin_api_hookup (vm);
    1238             : 
    1239             :   /*
    1240             :    * Pre-stuff socket filename pool with a non-modifieable mapping
    1241             :    * for socket-id 0 to MEMIF_DEFAULT_SOCKET_FILENAME in the
    1242             :    * default run-time directory.
    1243             :    */
    1244         575 :   return memif_socket_filename_add_del (1, 0, MEMIF_DEFAULT_SOCKET_FILENAME);
    1245             : }
    1246             : 
    1247        1151 : VLIB_INIT_FUNCTION (memif_init);
    1248             : 
    1249             : /* *INDENT-OFF* */
    1250             : VLIB_PLUGIN_REGISTER () = {
    1251             :     .version = VPP_BUILD_VER,
    1252             :     .description = "Packet Memory Interface (memif) -- Experimental",
    1253             : };
    1254             : /* *INDENT-ON* */
    1255             : 
    1256             : /*
    1257             :  * fd.io coding-style-patch-verification: ON
    1258             :  *
    1259             :  * Local Variables:
    1260             :  * eval: (c-set-style "gnu")
    1261             :  * End:
    1262             :  */

Generated by: LCOV version 1.14