FD.io VPP  v19.08.3-2-gbabecb413
Vector Packet Processing
memif.c
Go to the documentation of this file.
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 <vppinfra/linux/syscall.h>
37 #include <vnet/plugin/plugin.h>
38 #include <vnet/ethernet/ethernet.h>
39 #include <vpp/app/version.h>
40 #include <memif/memif.h>
41 #include <memif/private.h>
42 
44 
45 static u32
47 {
48  /* nothing for now */
49  return 0;
50 }
51 
52 static void
54 {
55  if (mq->int_clib_file_index != ~0)
56  {
58  mq->int_clib_file_index = ~0;
59  mq->int_fd = -1;
60  }
61  else if (mq->int_fd > -1)
62  {
63  close (mq->int_fd);
64  mq->int_fd = -1;
65  }
66 }
67 
68 static void
70 {
72  u16 ring_size, n_slots, mask, start;
73 
74  ring_size = 1 << mq->log2_ring_size;
75  mask = ring_size - 1;
76  n_slots = mq->ring->head - mq->last_tail;
77  start = mq->last_tail & mask;
78  if (is_rx)
79  vlib_buffer_free_from_ring (vm, mq->buffers, start, ring_size, n_slots);
80  else
81  vlib_buffer_free_from_ring_no_next (vm, mq->buffers, start, ring_size,
82  n_slots);
83  vec_free (mq->buffers);
84 }
85 
86 void
88 {
89  memif_main_t *mm = &memif_main;
90  vnet_main_t *vnm = vnet_get_main ();
91  memif_region_t *mr;
92  memif_queue_t *mq;
93  int i;
94 
95  if (mif == 0)
96  return;
97 
98  memif_log_debug (mif, "disconnect %u (%v)", mif->dev_instance,
99  err ? err->what : 0);
100 
101  if (err)
102  {
103  clib_error_t *e = 0;
104  mif->local_disc_string = vec_dup (err->what);
105  if (mif->sock && clib_socket_is_connected (mif->sock))
106  e = memif_msg_send_disconnect (mif, err);
107  clib_error_free (e);
108  }
109 
110  /* set interface down */
111  mif->flags &= ~(MEMIF_IF_FLAG_CONNECTED | MEMIF_IF_FLAG_CONNECTING);
112  if (mif->hw_if_index != ~0)
114 
115  /* close connection socket */
116  if (mif->sock && mif->sock->fd)
117  {
119  mif->socket_file_index);
120  hash_unset (msf->dev_instance_by_fd, mif->sock->fd);
121  memif_socket_close (&mif->sock);
122  }
123  else if (mif->sock)
124  {
125  clib_error_t *err;
126  err = clib_socket_close (mif->sock);
127  if (err)
128  {
129  memif_log_err (mif, "%U", format_clib_error, err);
130  clib_error_free (err);
131  }
132  clib_mem_free (mif->sock);
133  }
134 
135  /* *INDENT-OFF* */
136  vec_foreach_index (i, mif->rx_queues)
137  {
138  mq = vec_elt_at_index (mif->rx_queues, i);
139  if (mq->ring)
140  {
141  int rv;
143  if (rv)
144  memif_log_warn (mif,
145  "Unable to unassign interface %d, queue %d: rc=%d",
146  mif->hw_if_index, i, rv);
147  if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
148  {
150  }
151  mq->ring = 0;
152  }
153  }
154 
155  /* *INDENT-OFF* */
156  vec_foreach_index (i, mif->tx_queues)
157  {
158  mq = vec_elt_at_index (mif->tx_queues, i);
159  if (mq->ring)
160  {
161  if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
162  {
164  }
165  }
166  mq->ring = 0;
167  }
168 
169  /* free tx and rx queues */
170  vec_foreach (mq, mif->rx_queues)
172  vec_free (mif->rx_queues);
173 
174  vec_foreach (mq, mif->tx_queues)
176  vec_free (mif->tx_queues);
177 
178  /* free memory regions */
179  vec_foreach (mr, mif->regions)
180  {
181  int rv;
182  if (mr->is_external)
183  continue;
184  if ((rv = munmap (mr->shm, mr->region_size)))
185  memif_log_err (mif, "munmap failed, rv = %d", rv);
186  if (mr->fd > -1)
187  close (mr->fd);
188  }
189  /* *INDENT-ON* */
190  vec_free (mif->regions);
191  vec_free (mif->remote_name);
192  vec_free (mif->remote_if_name);
193  clib_fifo_free (mif->msg_queue);
194 }
195 
196 static clib_error_t *
198 {
199  memif_main_t *mm = &memif_main;
200  vnet_main_t *vnm = vnet_get_main ();
201  u16 qid = uf->private_data & 0xFFFF;
202  memif_if_t *mif = vec_elt_at_index (mm->interfaces, uf->private_data >> 16);
203  memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, qid);
204  u64 b;
205  ssize_t size;
206 
207  size = read (uf->file_descriptor, &b, sizeof (b));
208  if (size < 0)
209  {
210  memif_log_debug (mif, "Failed to read form socket");
211  return 0;
212  }
213 
215  mq->int_count++;
216 
217  return 0;
218 }
219 
220 
221 clib_error_t *
223 {
225  vnet_main_t *vnm = vnet_get_main ();
226  clib_file_t template = { 0 };
227  memif_region_t *mr;
228  int i;
229  clib_error_t *err = NULL;
230 
231  memif_log_debug (mif, "connect %u", mif->dev_instance);
232 
235 
236  /* *INDENT-OFF* */
237  vec_foreach (mr, mif->regions)
238  {
239  if (mr->shm)
240  continue;
241 
242  if (mr->fd < 0)
243  {
244  err = clib_error_return (0, "no memory region fd");
245  goto error;
246  }
247 
248  if ((mr->shm = mmap (NULL, mr->region_size, PROT_READ | PROT_WRITE,
249  MAP_SHARED, mr->fd, 0)) == MAP_FAILED)
250  {
251  err = clib_error_return_unix (0, "mmap");
252  goto error;
253  }
254  }
255  /* *INDENT-ON* */
256 
257  template.read_function = memif_int_fd_read_ready;
258 
259  /* *INDENT-OFF* */
260  vec_foreach_index (i, mif->tx_queues)
261  {
262  memif_queue_t *mq = vec_elt_at_index (mif->tx_queues, i);
263 
264  mq->ring = mif->regions[mq->region].shm + mq->offset;
265  if (mq->ring->cookie != MEMIF_COOKIE)
266  {
267  err = clib_error_return (0, "wrong cookie on tx ring %u", i);
268  goto error;
269  }
270  }
271 
272  vec_foreach_index (i, mif->rx_queues)
273  {
274  memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, i);
275  u32 ti;
276  int rv;
277 
278  mq->ring = mif->regions[mq->region].shm + mq->offset;
279  if (mq->ring->cookie != MEMIF_COOKIE)
280  {
281  err = clib_error_return (0, "wrong cookie on tx ring %u", i);
282  goto error;
283  }
284 
285  if (mq->int_fd > -1)
286  {
287  template.file_descriptor = mq->int_fd;
288  template.private_data = (mif->dev_instance << 16) | (i & 0xFFFF);
289  template.description = format (0, "%U rx %u int",
291  mif->dev_instance, i);
292  memif_file_add (&mq->int_clib_file_index, &template);
293  }
296  mq->buffer_pool_index =
298  rv = vnet_hw_interface_set_rx_mode (vnm, mif->hw_if_index, i,
300  if (rv)
302  (mif, "Warning: unable to set rx mode for interface %d queue %d: "
303  "rc=%d", mif->hw_if_index, i, rv);
304  else
305  {
307  vnet_hw_interface_get_rx_mode (vnm, mif->hw_if_index, i, &rxmode);
308 
309  if (rxmode == VNET_HW_INTERFACE_RX_MODE_POLLING)
311  else
313  }
314  }
315  /* *INDENT-ON* */
316 
317  mif->flags &= ~MEMIF_IF_FLAG_CONNECTING;
318  mif->flags |= MEMIF_IF_FLAG_CONNECTED;
319 
322  return 0;
323 
324 error:
325  memif_log_err (mif, "%U", format_clib_error, err);
326  return err;
327 }
328 
331 {
332  if (vec_len (mif->regions) == 0)
333  return NULL;
334  void *p = mif->regions[0].shm;
335  int ring_size =
336  sizeof (memif_ring_t) +
337  sizeof (memif_desc_t) * (1 << mif->run.log2_ring_size);
338  p += (ring_num + type * mif->run.num_s2m_rings) * ring_size;
339 
340  return (memif_ring_t *) p;
341 }
342 
343 clib_error_t *
345 {
347  memif_ring_t *ring = NULL;
348  int i, j;
349  u64 buffer_offset;
350  memif_region_t *r;
351  clib_mem_vm_alloc_t alloc = { 0 };
352  clib_error_t *err;
353 
354  ASSERT (vec_len (mif->regions) == 0);
356 
357  buffer_offset = (mif->run.num_s2m_rings + mif->run.num_m2s_rings) *
358  (sizeof (memif_ring_t) +
359  sizeof (memif_desc_t) * (1 << mif->run.log2_ring_size));
360 
361  r->region_size = buffer_offset;
362 
363  if ((mif->flags & MEMIF_IF_FLAG_ZERO_COPY) == 0)
364  r->region_size += mif->run.buffer_size * (1 << mif->run.log2_ring_size) *
365  (mif->run.num_s2m_rings + mif->run.num_m2s_rings);
366 
367  alloc.name = "memif region";
368  alloc.size = r->region_size;
369  alloc.flags = CLIB_MEM_VM_F_SHARED;
370 
371  err = clib_mem_vm_ext_alloc (&alloc);
372  if (err)
373  goto error;
374 
375  r->fd = alloc.fd;
376  r->shm = alloc.addr;
377 
378  if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
379  {
380  vlib_buffer_pool_t *bp;
381  /* *INDENT-OFF* */
383  {
384  vlib_physmem_map_t *pm;
387  r->fd = pm->fd;
388  r->region_size = pm->n_pages << pm->log2_page_size;
389  r->shm = pm->base;
390  r->is_external = 1;
391  }
392  /* *INDENT-ON* */
393  }
394 
395  for (i = 0; i < mif->run.num_s2m_rings; i++)
396  {
397  ring = memif_get_ring (mif, MEMIF_RING_S2M, i);
398  ring->head = ring->tail = 0;
399  ring->cookie = MEMIF_COOKIE;
400 
401  if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
402  continue;
403 
404  for (j = 0; j < (1 << mif->run.log2_ring_size); j++)
405  {
406  u16 slot = i * (1 << mif->run.log2_ring_size) + j;
407  ring->desc[j].region = 0;
408  ring->desc[j].offset =
409  buffer_offset + (u32) (slot * mif->run.buffer_size);
410  ring->desc[j].length = mif->run.buffer_size;
411  }
412  }
413  for (i = 0; i < mif->run.num_m2s_rings; i++)
414  {
415  ring = memif_get_ring (mif, MEMIF_RING_M2S, i);
416  ring->head = ring->tail = 0;
417  ring->cookie = MEMIF_COOKIE;
418 
419  if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
420  continue;
421 
422  for (j = 0; j < (1 << mif->run.log2_ring_size); j++)
423  {
424  u16 slot =
425  (i + mif->run.num_s2m_rings) * (1 << mif->run.log2_ring_size) + j;
426  ring->desc[j].region = 0;
427  ring->desc[j].offset =
428  buffer_offset + (u32) (slot * mif->run.buffer_size);
429  ring->desc[j].length = mif->run.buffer_size;
430  }
431  }
432 
433  ASSERT (mif->tx_queues == 0);
436 
437  /* *INDENT-OFF* */
438  vec_foreach_index (i, mif->tx_queues)
439  {
440  memif_queue_t *mq = vec_elt_at_index (mif->tx_queues, i);
441  if ((mq->int_fd = eventfd (0, EFD_NONBLOCK)) < 0)
442  {
443  err = clib_error_return_unix (0, "eventfd[tx queue %u]", i);
444  goto error;
445  }
446  mq->int_clib_file_index = ~0;
447  mq->ring = memif_get_ring (mif, MEMIF_RING_S2M, i);
448  mq->log2_ring_size = mif->cfg.log2_ring_size;
449  mq->region = 0;
450  mq->offset = (void *) mq->ring - (void *) mif->regions[mq->region].shm;
451  mq->last_head = 0;
452  mq->type = MEMIF_RING_S2M;
453  if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
456  }
457  /* *INDENT-ON* */
458 
459  ASSERT (mif->rx_queues == 0);
462 
463  /* *INDENT-OFF* */
464  vec_foreach_index (i, mif->rx_queues)
465  {
466  memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, i);
467  if ((mq->int_fd = eventfd (0, EFD_NONBLOCK)) < 0)
468  {
469  err = clib_error_return_unix (0, "eventfd[rx queue %u]", i);
470  goto error;
471  }
472  mq->int_clib_file_index = ~0;
473  mq->ring = memif_get_ring (mif, MEMIF_RING_M2S, i);
474  mq->log2_ring_size = mif->cfg.log2_ring_size;
475  mq->region = 0;
476  mq->offset = (void *) mq->ring - (void *) mif->regions[mq->region].shm;
477  mq->last_head = 0;
478  mq->type = MEMIF_RING_M2S;
479  if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
482  }
483  /* *INDENT-ON* */
484 
485  return 0;
486 
487 error:
488  memif_log_err (mif, "%U", format_clib_error, err);
489  return err;
490 }
491 
492 static uword
494 {
495  memif_main_t *mm = &memif_main;
496  memif_if_t *mif;
497  clib_socket_t *sock;
498  uword *event_data = 0, event_type;
499  u8 enabled = 0;
500  f64 start_time, last_run_duration = 0, now;
501  clib_error_t *err;
502 
503  sock = clib_mem_alloc (sizeof (clib_socket_t));
504  clib_memset (sock, 0, sizeof (clib_socket_t));
505 
506  while (1)
507  {
508  if (enabled)
510  last_run_duration);
511  else
513 
514  event_type = vlib_process_get_events (vm, &event_data);
515  vec_reset_length (event_data);
516 
517  switch (event_type)
518  {
519  case ~0:
520  break;
522  enabled = 1;
523  break;
525  enabled = 0;
526  continue;
527  default:
528  ASSERT (0);
529  }
530 
531  last_run_duration = start_time = vlib_time_now (vm);
532  /* *INDENT-OFF* */
533  pool_foreach (mif, mm->interfaces,
534  ({
535  memif_socket_file_t * msf = vec_elt_at_index (mm->socket_files, mif->socket_file_index);
536  /* Allow no more than 10us without a pause */
537  now = vlib_time_now (vm);
538  if (now > start_time + 10e-6)
539  {
540  vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */
541  start_time = vlib_time_now (vm);
542  }
543 
544  if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) == 0)
545  continue;
546 
547  if (mif->flags & MEMIF_IF_FLAG_CONNECTING)
548  continue;
549 
550  if (mif->flags & MEMIF_IF_FLAG_CONNECTED)
551  continue;
552 
553  if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
554  {
555  clib_memset (sock, 0, sizeof(clib_socket_t));
556  sock->config = (char *) msf->filename;
557  sock->flags = CLIB_SOCKET_F_IS_CLIENT| CLIB_SOCKET_F_SEQPACKET;
558 
559  if ((err = clib_socket_init (sock)))
560  {
561  clib_error_free (err);
562  }
563  else
564  {
565  clib_file_t t = { 0 };
566 
567  t.read_function = memif_slave_conn_fd_read_ready;
568  t.write_function = memif_slave_conn_fd_write_ready;
569  t.error_function = memif_slave_conn_fd_error;
570  t.file_descriptor = sock->fd;
571  t.private_data = mif->dev_instance;
572  memif_file_add (&sock->private_data, &t);
573  t.description = format (0, "%U ctl",
575  mif->dev_instance);
576  hash_set (msf->dev_instance_by_fd, sock->fd, mif->dev_instance);
577 
578  mif->flags |= MEMIF_IF_FLAG_CONNECTING;
579  mif->sock = sock;
580  sock = clib_mem_alloc (sizeof(clib_socket_t));
581  }
582  }
583  }));
584  /* *INDENT-ON* */
585  last_run_duration = vlib_time_now (vm) - last_run_duration;
586  }
587  return 0;
588 }
589 
590 /* *INDENT-OFF* */
592  .function = memif_process,
593  .type = VLIB_NODE_TYPE_PROCESS,
594  .name = "memif-process",
595 };
596 /* *INDENT-ON* */
597 
598 static int
599 memif_add_socket_file (u32 sock_id, u8 * socket_filename)
600 {
601  memif_main_t *mm = &memif_main;
602  uword *p;
603  memif_socket_file_t *msf;
604 
605  p = hash_get (mm->socket_file_index_by_sock_id, sock_id);
606  if (p)
607  {
608  msf = pool_elt_at_index (mm->socket_files, *p);
609  if (strcmp ((char *) msf->filename, (char *) socket_filename) == 0)
610  {
611  /* Silently accept identical "add". */
612  return 0;
613  }
614 
615  /* But don't allow a direct add of a different filename. */
616  return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
617  }
618 
619  pool_get (mm->socket_files, msf);
620  clib_memset (msf, 0, sizeof (memif_socket_file_t));
621 
622  msf->filename = socket_filename;
623  msf->socket_id = sock_id;
624 
626  msf - mm->socket_files);
627 
628  return 0;
629 }
630 
631 static int
633 {
634  memif_main_t *mm = &memif_main;
635  uword *p;
636  memif_socket_file_t *msf;
637 
638  p = hash_get (mm->socket_file_index_by_sock_id, sock_id);
639  if (!p)
640  {
641  /* Don't delete non-existent entries. */
642  return VNET_API_ERROR_INVALID_ARGUMENT;
643  }
644 
645  msf = pool_elt_at_index (mm->socket_files, *p);
646  if (msf->ref_cnt > 0)
647  {
648  return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
649  }
650 
651  vec_free (msf->filename);
652  pool_put (mm->socket_files, msf);
653 
655 
656  return 0;
657 }
658 
659 int
660 memif_socket_filename_add_del (u8 is_add, u32 sock_id, u8 * sock_filename)
661 {
662  char *dir = 0, *tmp;
663  u32 idx = 0;
664 
665  /* allow adding socket id 0 */
666  if ((sock_id == 0 && is_add == 0) || sock_id == ~0)
667  {
668  return VNET_API_ERROR_INVALID_ARGUMENT;
669  }
670 
671  if (is_add == 0)
672  {
673  return memif_delete_socket_file (sock_id);
674  }
675 
676  if (sock_filename == 0 || sock_filename[0] == 0)
677  {
678  return VNET_API_ERROR_INVALID_ARGUMENT;
679  }
680 
681  if (sock_filename[0] != '/')
682  {
683  clib_error_t *error;
684 
685  /* copy runtime dir path */
687  strlen (vlib_unix_get_runtime_dir ()));
688  vec_add1 (dir, '/');
689 
690  /* if sock_filename contains dirs, add them to path */
691  tmp = strrchr ((char *) sock_filename, '/');
692  if (tmp)
693  {
694  idx = tmp - (char *) sock_filename;
695  vec_add (dir, sock_filename, idx);
696  }
697 
698  vec_add1 (dir, '\0');
699  /* create socket dir */
700  error = vlib_unix_recursive_mkdir (dir);
701  if (error)
702  {
703  clib_error_free (error);
704  return VNET_API_ERROR_SYSCALL_ERROR_1;
705  }
706 
707  sock_filename = format (0, "%s/%s%c", vlib_unix_get_runtime_dir (),
708  sock_filename, 0);
709  }
710  else
711  {
712  sock_filename = vec_dup (sock_filename);
713 
714  /* check if directory exists */
715  tmp = strrchr ((char *) sock_filename, '/');
716  if (tmp)
717  {
718  idx = tmp - (char *) sock_filename;
719  vec_add (dir, sock_filename, idx);
720  vec_add1 (dir, '\0');
721  }
722 
723  /* check dir existance and access rights for effective user/group IDs */
724  if ((dir == NULL)
725  ||
726  (faccessat ( /* ignored */ -1, dir, F_OK | R_OK | W_OK, AT_EACCESS)
727  < 0))
728  {
729  vec_free (dir);
730  return VNET_API_ERROR_INVALID_ARGUMENT;
731  }
732  }
733  vec_free (dir);
734 
735  return memif_add_socket_file (sock_id, sock_filename);
736 }
737 
738 int
740 {
741  vnet_main_t *vnm = vnet_get_main ();
742  memif_main_t *mm = &memif_main;
743  memif_socket_file_t *msf =
745  clib_error_t *err;
746 
747  mif->flags |= MEMIF_IF_FLAG_DELETING;
750 
751  /* bring down the interface */
754 
755  err = clib_error_return (0, "interface deleted");
756  memif_disconnect (mif, err);
757  clib_error_free (err);
758 
759  if (mif->hw_if_index != ~0)
760  {
761  /* remove the interface */
762  if (mif->mode == MEMIF_INTERFACE_MODE_IP)
764  else
766  mif->hw_if_index = ~0;
767  }
768 
769  /* free interface data structures */
770  clib_spinlock_free (&mif->lockp);
771  mhash_unset (&msf->dev_instance_by_id, &mif->id, 0);
772 
773  /* remove socket file */
774  if (--(msf->ref_cnt) == 0)
775  {
776  if (msf->is_listener)
777  {
778  int i;
779  /* *INDENT-OFF* */
782  /* *INDENT-ON* */
783  memif_socket_close (&msf->sock);
784  vec_free (msf->pending_clients);
785  }
788  if (msf->sock)
789  {
790  err = clib_socket_close (msf->sock);
791  if (err)
792  {
793  memif_log_err (mif, "%U", format_clib_error, err);
794  clib_error_free (err);
795  }
796  clib_mem_free (msf->sock);
797  }
798  }
799 
800  clib_memset (mif, 0, sizeof (*mif));
801  pool_put (mm->interfaces, mif);
802 
803  if (pool_elts (mm->interfaces) == 0)
806 
807  return 0;
808 }
809 
810 /* *INDENT-OFF* */
811 VNET_HW_INTERFACE_CLASS (memif_ip_hw_if_class, static) =
812 {
813  .name = "memif-ip",
815 };
816 /* *INDENT-ON* */
817 
818 int
820 {
821  memif_main_t *mm = &memif_main;
823  vnet_main_t *vnm = vnet_get_main ();
824  memif_if_t *mif = 0;
826  clib_error_t *error = 0;
827  int ret = 0;
828  uword *p;
830  memif_socket_file_t *msf = 0;
831  int rv = 0;
832 
834  if (p == 0)
835  {
836  rv = VNET_API_ERROR_INVALID_ARGUMENT;
837  goto done;
838  }
839 
840  msf = vec_elt_at_index (mm->socket_files, p[0]);
841 
842  /* existing socket file can be either master or slave but cannot be both */
843  if (msf->ref_cnt > 0)
844  {
845  if ((!msf->is_listener != !args->is_master))
846  {
847  rv = VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
848  goto done;
849  }
850 
851  p = mhash_get (&msf->dev_instance_by_id, &args->id);
852  if (p)
853  {
854  rv = VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
855  goto done;
856  }
857  }
858 
859  /* Create new socket file */
860  if (msf->ref_cnt == 0)
861  {
862  struct stat file_stat;
863 
864  /* If we are creating listener make sure file doesn't exist or if it
865  * exists thn delete it if it is old socket file */
866  if (args->is_master && (stat ((char *) msf->filename, &file_stat) == 0))
867  {
868  if (S_ISSOCK (file_stat.st_mode))
869  {
870  unlink ((char *) msf->filename);
871  }
872  else
873  {
874  error = clib_error_return (0, "File exists for %s",
875  msf->filename);
876  rv = VNET_API_ERROR_VALUE_EXIST;
877  goto done;
878  }
879  }
880 
881  mhash_init (&msf->dev_instance_by_id, sizeof (uword),
882  sizeof (memif_interface_id_t));
883  msf->dev_instance_by_fd = hash_create (0, sizeof (uword));
884  msf->is_listener = (args->is_master != 0);
885 
886  memif_log_debug (0, "initializing socket file %s", msf->filename);
887  }
888 
889  if (mm->per_thread_data == 0)
890  {
891  int i;
892 
895 
896  for (i = 0; i < tm->n_vlib_mains; i++)
897  {
900  vlib_buffer_t *bt = &ptd->buffer_template;
901  clib_memset (bt, 0, sizeof (vlib_buffer_t));
902  bt->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
904  vnet_buffer (bt)->sw_if_index[VLIB_TX] = (u32) ~ 0;
905 
906  /* initially prealloc copy_ops so we can use
907  _vec_len instead of vec_elen */
909  vec_reset_length (ptd->copy_ops);
911  vec_reset_length (ptd->buffers);
912  }
913  }
914 
915  pool_get (mm->interfaces, mif);
916  clib_memset (mif, 0, sizeof (*mif));
917  mif->dev_instance = mif - mm->interfaces;
918  mif->socket_file_index = msf - mm->socket_files;
919  mif->id = args->id;
920  mif->sw_if_index = mif->hw_if_index = mif->per_interface_next_index = ~0;
921  mif->mode = args->mode;
922  if (args->secret)
923  mif->secret = vec_dup (args->secret);
924 
925  if (tm->n_vlib_mains > 1)
926  clib_spinlock_init (&mif->lockp);
927 
929  {
930 
931  if (!args->hw_addr_set)
932  {
933  f64 now = vlib_time_now (vm);
934  u32 rnd;
935  rnd = (u32) (now * 1e6);
936  rnd = random_u32 (&rnd);
937 
938  memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
939  args->hw_addr[0] = 2;
940  args->hw_addr[1] = 0xfe;
941  }
943  mif->dev_instance, args->hw_addr,
944  &mif->hw_if_index,
946  }
947  else if (mif->mode == MEMIF_INTERFACE_MODE_IP)
948  {
949  mif->hw_if_index =
951  mif->dev_instance,
952  memif_ip_hw_if_class.index,
953  mif->dev_instance);
954  }
955  else
956  error = clib_error_return (0, "unsupported interface mode");
957 
958  if (error)
959  {
960  ret = VNET_API_ERROR_SYSCALL_ERROR_2;
961  goto error;
962  }
963 
964  sw = vnet_get_hw_sw_interface (vnm, mif->hw_if_index);
965  mif->sw_if_index = sw->sw_if_index;
966 
967  mif->cfg.log2_ring_size = args->log2_ring_size;
968  mif->cfg.buffer_size = args->buffer_size;
969  mif->cfg.num_s2m_rings =
970  args->is_master ? args->rx_queues : args->tx_queues;
971  mif->cfg.num_m2s_rings =
972  args->is_master ? args->tx_queues : args->rx_queues;
973 
974  args->sw_if_index = mif->sw_if_index;
975 
976  /* If this is new one, start listening */
977  if (msf->is_listener && msf->ref_cnt == 0)
978  {
979  struct stat file_stat;
981 
982  ASSERT (msf->sock == 0);
983  msf->sock = s;
984 
985  clib_memset (s, 0, sizeof (clib_socket_t));
986  s->config = (char *) msf->filename;
987  s->flags = CLIB_SOCKET_F_IS_SERVER |
990 
991  if ((error = clib_socket_init (s)))
992  {
993  ret = VNET_API_ERROR_SYSCALL_ERROR_4;
994  goto error;
995  }
996 
997  if (stat ((char *) msf->filename, &file_stat) == -1)
998  {
999  ret = VNET_API_ERROR_SYSCALL_ERROR_8;
1000  goto error;
1001  }
1002 
1003  clib_file_t template = { 0 };
1005  template.file_descriptor = msf->sock->fd;
1006  template.private_data = mif->socket_file_index;
1007  template.description = format (0, "memif listener %s", msf->filename);
1008  memif_file_add (&msf->sock->private_data, &template);
1009  }
1010 
1011  msf->ref_cnt++;
1012 
1013  if (args->is_master == 0)
1014  {
1015  mif->flags |= MEMIF_IF_FLAG_IS_SLAVE;
1016  if (args->is_zero_copy)
1017  mif->flags |= MEMIF_IF_FLAG_ZERO_COPY;
1018  }
1019 
1020  hw = vnet_get_hw_interface (vnm, mif->hw_if_index);
1023  memif_input_node.index);
1024 
1025  mhash_set (&msf->dev_instance_by_id, &mif->id, mif->dev_instance, 0);
1026 
1027  if (pool_elts (mm->interfaces) == 1)
1028  {
1031  }
1032  goto done;
1033 
1034 error:
1035  if (mif->hw_if_index != ~0)
1036  {
1037  if (mif->mode == MEMIF_INTERFACE_MODE_IP)
1039  else
1041  mif->hw_if_index = ~0;
1042  }
1043  memif_delete_if (vm, mif);
1044  if (error)
1045  {
1046  memif_log_err (mif, "%U", format_clib_error, error);
1047  clib_error_free (error);
1048  }
1049  return ret;
1050 
1051 done:
1052  return rv;
1053 }
1054 
1055 static clib_error_t *
1057 {
1058  memif_main_t *mm = &memif_main;
1059 
1060  clib_memset (mm, 0, sizeof (memif_main_t));
1061 
1062  mm->log_class = vlib_log_register_class ("memif_plugin", 0);
1063  memif_log_debug (0, "initialized");
1064 
1065  /* initialize binary API */
1067 
1068  /*
1069  * Pre-stuff socket filename pool with a non-modifieable mapping
1070  * for socket-id 0 to MEMIF_DEFAULT_SOCKET_FILENAME in the
1071  * default run-time directory.
1072  */
1074 
1075  return 0;
1076 }
1077 
1079 
1080 /* *INDENT-OFF* */
1081 VLIB_PLUGIN_REGISTER () = {
1082  .version = VPP_BUILD_VER,
1083  .description = "Packet Memory Interface (memif) -- Experimental",
1084 };
1085 /* *INDENT-ON* */
1086 
1087 /*
1088  * fd.io coding-style-patch-verification: ON
1089  *
1090  * Local Variables:
1091  * eval: (c-set-style "gnu")
1092  * End:
1093  */
memif_if_t * interfaces
Definition: private.h:241
#define memif_log_err(dev, f,...)
Definition: private.h:55
vlib_log_class_t vlib_log_register_class(char *class, char *subclass)
Definition: log.c:176
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
vlib_log_class_t log_class
Definition: private.h:250
vmrglw vmrglh hi
#define vec_foreach_index(var, v)
Iterate over vector indices.
u8 * format_clib_error(u8 *s, va_list *va)
Definition: error.c:191
#define hash_set(h, key, value)
Definition: hash.h:255
u32 flags
Definition: vhost_user.h:141
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:673
#define hash_unset(h, key)
Definition: hash.h:261
u8 * secret
Definition: private.h:170
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:593
void ethernet_delete_interface(vnet_main_t *vnm, u32 hw_if_index)
Definition: interface.c:324
clib_socket_t ** pending_clients
Definition: private.h:87
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static uword clib_socket_is_connected(clib_socket_t *sock)
Definition: socket.h:112
struct memif_if_t::@543 cfg
unsigned long u64
Definition: types.h:89
memif_socket_file_t * socket_files
Definition: private.h:244
memif_log2_ring_size_t log2_ring_size
Definition: private.h:183
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:346
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
void * addr
Pointer to allocated memory, set on successful allocation.
Definition: mem.h:413
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:279
#define vec_add2_aligned(V, P, N, A)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:572
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
u32 physmem_map_index
Definition: buffer.h:428
u32 file_descriptor
Definition: file.h:54
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
static clib_error_t * memif_init(vlib_main_t *vm)
Definition: memif.c:1056
int i
vlib_buffer_main_t * buffer_main
Definition: main.h:152
clib_error_t * clib_socket_init(clib_socket_t *s)
Definition: socket.c:384
clib_error_t * memif_msg_send_disconnect(memif_if_t *mif, clib_error_t *err)
Definition: socket.c:198
memif_interface_mode_t mode
Definition: private.h:271
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
vlib_physmem_map_t * vlib_physmem_get_map(vlib_main_t *vm, u32 index)
Definition: physmem.c:87
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:450
u32 * buffers
Definition: private.h:125
u8 num_m2s_rings
Definition: private.h:185
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:236
vlib_main_t ** vlib_mains
Definition: buffer.c:332
unsigned char u8
Definition: types.h:56
#define memif_file_del_by_index(a)
Definition: private.h:77
uint32_t length
Definition: memif.h:152
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
clib_file_function_t * read_function
Definition: file.h:67
double f64
Definition: types.h:142
static void clib_spinlock_free(clib_spinlock_t *p)
Definition: lock.h:70
static vnet_sw_interface_t * vnet_get_hw_sw_interface(vnet_main_t *vnm, u32 hw_if_index)
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:598
#define CLIB_SOCKET_F_IS_SERVER
Definition: socket.h:58
vnet_hw_interface_rx_mode
Definition: interface.h:53
#define static_always_inline
Definition: clib.h:100
clib_error_t * clib_mem_vm_ext_alloc(clib_mem_vm_alloc_t *a)
Definition: mem.c:193
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:493
u8 * remote_name
Definition: private.h:178
static int memif_add_socket_file(u32 sock_id, u8 *socket_filename)
Definition: memif.c:599
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:516
clib_error_t * memif_plugin_api_hookup(vlib_main_t *vm)
Definition: memif_api.c:377
uword socket_file_index
Definition: private.h:168
static char * vlib_unix_get_runtime_dir(void)
Definition: unix.h:139
uint32_t cookie
Definition: memif.h:166
char * name
Name for memory allocation, set by caller.
Definition: mem.h:410
u8 buffer_pool_index
Definition: private.h:126
clib_error_t * memif_init_regions_and_queues(memif_if_t *mif)
Definition: memif.c:344
static_always_inline void vnet_device_input_set_interrupt_pending(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id)
Definition: devices.h:136
u16 buffer_size
Definition: private.h:186
memif_log2_ring_size_t log2_ring_size
Definition: private.h:272
vnet_hw_interface_flags_t flags
Definition: interface.h:506
static void memif_disconnect_free_zc_queue_buffer(memif_queue_t *mq, u8 is_rx)
Definition: memif.c:69
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
vnet_device_class_t memif_device_class
u32 per_interface_next_index
Definition: private.h:164
static int memif_delete_socket_file(u32 sock_id)
Definition: memif.c:632
#define clib_error_return(e, args...)
Definition: error.h:99
memif_region_offset_t offset
Definition: private.h:121
uword size
Allocation size, set by caller.
Definition: mem.h:411
#define memif_file_add(a, b)
Definition: private.h:66
unsigned int u32
Definition: types.h:88
struct memif_if_t::@544 run
void * shm
Definition: private.h:102
u32 vnet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u32 hw_class_index, u32 hw_instance)
Definition: interface.c:762
static u32 memif_eth_flag_change(vnet_main_t *vnm, vnet_hw_interface_t *hi, u32 flags)
Definition: memif.c:46
mhash_t dev_instance_by_id
Definition: private.h:92
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:63
static void vlib_buffer_free_from_ring(vlib_main_t *vm, u32 *ring, u32 start, u32 ring_size, u32 n_buffers)
Free buffers from ring.
Definition: buffer_funcs.h:912
vl_api_fib_path_type_t type
Definition: fib_types.api:123
#define CLIB_MEM_VM_F_SHARED
Definition: mem.h:393
memif_region_index_t region
Definition: memif.h:151
u16 last_head
Definition: private.h:123
#define hash_get(h, key)
Definition: hash.h:249
memif_copy_op_t * copy_ops
Definition: private.h:225
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
uword size
vlib_node_registration_t memif_input_node
(constructor) VLIB_REGISTER_NODE (memif_input_node)
Definition: node.c:926
static_always_inline uword vnet_get_device_input_thread_index(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id)
Definition: devices.h:127
memif_desc_t desc[0]
Definition: memif.h:173
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:934
int memif_delete_if(vlib_main_t *vm, memif_if_t *mif)
Definition: memif.c:739
int fd
File descriptor, set on successful allocation if CLIB_MEM_VM_F_SHARED is set.
Definition: mem.h:414
uword dev_instance
Definition: private.h:161
static clib_error_t * clib_socket_close(clib_socket_t *sock)
Definition: socket.h:175
clib_spinlock_t lockp
Definition: private.h:156
unsigned short u16
Definition: types.h:57
#define clib_error_return_unix(e, args...)
Definition: error.h:102
int vnet_hw_interface_get_rx_mode(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id, vnet_hw_interface_rx_mode *mode)
Definition: devices.c:313
#define hash_free(h)
Definition: hash.h:310
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:375
vlib_buffer_pool_t * buffer_pools
Definition: buffer.h:451
memif_interface_id_t id
Definition: private.h:266
int memif_create_if(vlib_main_t *vm, memif_create_if_args_t *args)
Definition: memif.c:819
uword int_clib_file_index
Definition: private.h:130
VNET_HW_INTERFACE_CLASS(memif_ip_hw_if_class, static)
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
memif_queue_t * tx_queues
Definition: private.h:175
clib_error_t * memif_connect(memif_if_t *mif)
Definition: memif.c:222
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
vlib_main_t * vm
Definition: buffer.c:323
u8 * local_disc_string
Definition: private.h:198
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
int memif_socket_filename_add_del(u8 is_add, u32 sock_id, u8 *sock_filename)
Definition: memif.c:660
uint32_t memif_interface_id_t
Definition: memif.h:64
u16 last_tail
Definition: private.h:124
void memif_disconnect(memif_if_t *mif, clib_error_t *err)
Definition: memif.c:87
u32 flags
vm allocation flags: CLIB_MEM_VM_F_SHARED: request shared memory, file descriptor will be provided ...
Definition: mem.h:399
memif_ring_type_t type
Definition: private.h:134
memif_region_t * regions
Definition: private.h:172
#define hash_create(elts, value_bytes)
Definition: hash.h:696
#define ASSERT(truth)
void vnet_hw_interface_assign_rx_thread(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id, uword thread_index)
Definition: devices.c:139
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
static void memif_queue_intfd_close(memif_queue_t *mq)
Definition: memif.c:53
static void mhash_free(mhash_t *h)
Definition: mhash.h:149
static clib_error_t * memif_int_fd_read_ready(clib_file_t *uf)
Definition: memif.c:197
u32 flags
Definition: private.h:157
memif_ring_t * ring
Definition: private.h:118
static void clib_mem_free(void *p)
Definition: mem.h:226
vlib_buffer_t buffer_template
Definition: private.h:229
u32 hw_if_index
Definition: private.h:159
struct _socket_t clib_socket_t
clib_error_t * memif_slave_conn_fd_write_ready(clib_file_t *uf)
Definition: socket.c:596
#define clib_fifo_free(f)
Definition: fifo.h:257
#define MEMIF_RING_FLAG_MASK_INT
Definition: memif.h:168
static void * clib_mem_alloc(uword size)
Definition: mem.h:153
clib_error_t * memif_slave_conn_fd_error(clib_file_t *uf)
Definition: socket.c:604
#define CLIB_SOCKET_F_SEQPACKET
Definition: socket.h:63
clib_error_t * memif_slave_conn_fd_read_ready(clib_file_t *uf)
Definition: socket.c:553
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u64 int_count
Definition: private.h:131
void vnet_delete_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
Definition: interface.c:974
memif_region_offset_t offset
Definition: memif.h:153
uword * dev_instance_by_fd
Definition: private.h:95
u8 num_s2m_rings
Definition: private.h:184
VLIB_PLUGIN_REGISTER()
Definition: defs.h:47
clib_error_t * vlib_unix_recursive_mkdir(char *path)
Definition: util.c:103
static_always_inline memif_ring_t * memif_get_ring(memif_if_t *mif, memif_ring_type_t type, u16 ring_num)
Definition: memif.c:330
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define MEMIF_DEFAULT_SOCKET_FILENAME
Definition: private.h:21
clib_error_t * ethernet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, const u8 *address, u32 *hw_if_index_return, ethernet_flag_change_function_t flag_change)
Definition: interface.c:278
#define CLIB_SOCKET_F_PASSCRED
Definition: socket.h:64
clib_error_t * vnet_hw_interface_set_flags(vnet_main_t *vnm, u32 hw_if_index, vnet_hw_interface_flags_t flags)
Definition: interface.c:492
#define memif_log_warn(dev, f,...)
Definition: private.h:44
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
a point 2 point interface
Definition: interface.h:368
void memif_socket_close(clib_socket_t **sock)
Definition: socket.c:43
#define clib_error_free(e)
Definition: error.h:86
u8 * remote_if_name
Definition: private.h:179
memif_interface_id_t id
Definition: private.h:158
memif_log2_ring_size_t log2_ring_size
Definition: private.h:119
int vnet_hw_interface_unassign_rx_thread(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id)
Definition: devices.c:188
#define vnet_buffer(b)
Definition: buffer.h:365
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
uint16_t flags
Definition: memif.h:167
clib_error_t * vnet_sw_interface_set_flags(vnet_main_t *vnm, u32 sw_if_index, vnet_sw_interface_flags_t flags)
Definition: interface.c:501
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
memif_per_thread_data_t * per_thread_data
Definition: private.h:248
static vlib_node_registration_t memif_process_node
(constructor) VLIB_REGISTER_NODE (memif_process_node)
Definition: memif.c:591
#define memif_log_debug(dev, f,...)
Definition: private.h:33
u8 * remote_disc_string
Definition: private.h:199
memif_ring_type_t
Definition: memif.h:47
#define vec_foreach(var, vec)
Vector iterator.
volatile uint16_t head
Definition: memif.h:169
uword private_data
Definition: file.h:64
Definition: file.h:51
clib_socket_t * sock
Definition: private.h:167
memif_queue_t * rx_queues
Definition: private.h:174
int vnet_hw_interface_set_rx_mode(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id, vnet_hw_interface_rx_mode mode)
Definition: devices.c:253
clib_error_t * memif_conn_fd_accept_ready(clib_file_t *uf)
Definition: socket.c:657
uword * socket_file_index_by_sock_id
Definition: private.h:245
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:167
#define CLIB_SOCKET_F_ALLOW_GROUP_WRITE
Definition: socket.h:62
memif_msg_fifo_elt_t * msg_queue
Definition: private.h:169
memif_main_t memif_main
Definition: memif.c:43
static u8 vlib_buffer_pool_get_default_for_numa(vlib_main_t *vm, u32 numa_node)
Definition: buffer_funcs.h:163
static void vlib_buffer_free_from_ring_no_next(vlib_main_t *vm, u32 *ring, u32 start, u32 ring_size, u32 n_buffers)
Free buffers from ring without freeing tail buffers.
Definition: buffer_funcs.h:937
memif_region_index_t region
Definition: private.h:120
clib_socket_t * sock
Definition: private.h:86
#define MEMIF_COOKIE
Definition: memif.h:25
u32 sw_if_index
Definition: private.h:160
static void vnet_hw_interface_set_input_node(vnet_main_t *vnm, u32 hw_if_index, u32 node_index)
Definition: devices.h:79
volatile uint16_t tail
Definition: memif.h:171
memif_interface_mode_t mode
Definition: private.h:162
static uword memif_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: memif.c:493
u8 * format_memif_device_name(u8 *s, va_list *args)
Definition: device.c:51
memif_region_size_t region_size
Definition: private.h:103
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128