FD.io VPP  v16.12-rc0-308-g931be3a
Vector Packet Processing
vhost-user.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * vhost.c - vhost-user
4  *
5  * Copyright (c) 2014 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19 
20 #include <fcntl.h> /* for open */
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/uio.h> /* for iovec */
27 #include <netinet/in.h>
28 #include <sys/vfs.h>
29 
30 #include <linux/if_arp.h>
31 #include <linux/if_tun.h>
32 
33 #include <vlib/vlib.h>
34 #include <vlib/unix/unix.h>
35 
36 #include <vnet/ip/ip.h>
37 
38 #include <vnet/ethernet/ethernet.h>
39 #include <vnet/devices/devices.h>
40 #include <vnet/feature/feature.h>
41 
43 
44 #define VHOST_USER_DEBUG_SOCKET 0
45 #define VHOST_USER_DEBUG_VQ 0
46 
47 /* Set to get virtio_net_hdr in buffer pre-data
48  details will be shown in packet trace */
49 #define VHOST_USER_COPY_TX_HDR 0
50 
51 #if VHOST_USER_DEBUG_SOCKET == 1
52 #define DBG_SOCK(args...) clib_warning(args);
53 #else
54 #define DBG_SOCK(args...)
55 #endif
56 
57 #if VHOST_USER_DEBUG_VQ == 1
58 #define DBG_VQ(args...) clib_warning(args);
59 #else
60 #define DBG_VQ(args...)
61 #endif
62 
64 
65 #define foreach_vhost_user_tx_func_error \
66  _(NONE, "no error") \
67  _(NOT_READY, "vhost user state error") \
68  _(PKT_DROP_NOBUF, "tx packet drops (no available descriptors)") \
69  _(PKT_DROP_NOMRG, "tx packet drops (cannot merge descriptors)") \
70  _(MMAP_FAIL, "mmap failure") \
71  _(INDIRECT_OVERFLOW, "indirect descriptor table overflow")
72 
73 typedef enum
74 {
75 #define _(f,s) VHOST_USER_TX_FUNC_ERROR_##f,
77 #undef _
80 
82 #define _(n,s) s,
84 #undef _
85 };
86 
87 #define foreach_vhost_user_input_func_error \
88  _(NO_ERROR, "no error") \
89  _(NO_BUFFER, "no available buffer") \
90  _(MMAP_FAIL, "mmap failure") \
91  _(INDIRECT_OVERFLOW, "indirect descriptor overflows table") \
92  _(UNDERSIZED_FRAME, "undersized ethernet frame received (< 14 bytes)") \
93  _(FULL_RX_QUEUE, "full rx queue (possible driver tx drop)")
94 
95 typedef enum
96 {
97 #define _(f,s) VHOST_USER_INPUT_FUNC_ERROR_##f,
99 #undef _
102 
104 #define _(n,s) s,
106 #undef _
107 };
108 
109 /* *INDENT-OFF* */
110 static vhost_user_main_t vhost_user_main = {
111  .mtu_bytes = 1518,
112 };
113 
114 VNET_HW_INTERFACE_CLASS (vhost_interface_class, static) = {
115  .name = "vhost-user",
116 };
117 /* *INDENT-ON* */
118 
119 static u8 *
121 {
122  u32 i = va_arg (*args, u32);
123  u32 show_dev_instance = ~0;
125 
127  show_dev_instance = vum->show_dev_instance_by_real_dev_instance[i];
128 
129  if (show_dev_instance != ~0)
130  i = show_dev_instance;
131 
132  s = format (s, "VirtualEthernet0/0/%d", i);
133  return s;
134 }
135 
136 static int
138 {
140 
142  hi->dev_instance, ~0);
143 
145  new_dev_instance;
146 
147  DBG_SOCK ("renumbered vhost-user interface dev_instance %d to %d",
148  hi->dev_instance, new_dev_instance);
149 
150  return 0;
151 }
152 
155 {
156  int i = *hint;
157  if (PREDICT_TRUE ((vui->regions[i].guest_phys_addr <= addr) &&
158  ((vui->regions[i].guest_phys_addr +
159  vui->regions[i].memory_size) > addr)))
160  {
161  return (void *) (vui->region_mmap_addr[i] + addr -
162  vui->regions[i].guest_phys_addr);
163  }
164 #if __SSE4_2__
165  __m128i rl, rh, al, ah, r;
166  al = _mm_set1_epi64x (addr + 1);
167  ah = _mm_set1_epi64x (addr);
168 
169  rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[0]);
170  rl = _mm_cmpgt_epi64 (al, rl);
171  rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[0]);
172  rh = _mm_cmpgt_epi64 (rh, ah);
173  r = _mm_and_si128 (rl, rh);
174 
175  rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[2]);
176  rl = _mm_cmpgt_epi64 (al, rl);
177  rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[2]);
178  rh = _mm_cmpgt_epi64 (rh, ah);
179  r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x22);
180 
181  rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[4]);
182  rl = _mm_cmpgt_epi64 (al, rl);
183  rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[4]);
184  rh = _mm_cmpgt_epi64 (rh, ah);
185  r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x44);
186 
187  rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[6]);
188  rl = _mm_cmpgt_epi64 (al, rl);
189  rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[6]);
190  rh = _mm_cmpgt_epi64 (rh, ah);
191  r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x88);
192 
193  r = _mm_shuffle_epi8 (r, _mm_set_epi64x (0, 0x0e060c040a020800));
194  i = __builtin_ctzll (_mm_movemask_epi8 (r));
195 
196  if (i < vui->nregions)
197  {
198  *hint = i;
199  return (void *) (vui->region_mmap_addr[i] + addr -
200  vui->regions[i].guest_phys_addr);
201  }
202 
203 #else
204  for (i = 0; i < vui->nregions; i++)
205  {
206  if ((vui->regions[i].guest_phys_addr <= addr) &&
207  ((vui->regions[i].guest_phys_addr + vui->regions[i].memory_size) >
208  addr))
209  {
210  *hint = i;
211  return (void *) (vui->region_mmap_addr[i] + addr -
212  vui->regions[i].guest_phys_addr);
213  }
214  }
215 #endif
216  DBG_VQ ("failed to map guest mem addr %llx", addr);
217  *hint = 0;
218  return 0;
219 }
220 
221 static inline void *
223 {
224  int i;
225  for (i = 0; i < vui->nregions; i++)
226  {
227  if ((vui->regions[i].userspace_addr <= addr) &&
228  ((vui->regions[i].userspace_addr + vui->regions[i].memory_size) >
229  addr))
230  {
231  return (void *) (vui->region_mmap_addr[i] + addr -
232  vui->regions[i].userspace_addr);
233  }
234  }
235  return 0;
236 }
237 
238 static long
240 {
241  struct statfs s;
242  fstatfs (fd, &s);
243  return s.f_bsize;
244 }
245 
246 static void
248 {
249  int i, r;
250  for (i = 0; i < vui->nregions; i++)
251  {
252  if (vui->region_mmap_addr[i] != (void *) -1)
253  {
254 
255  long page_sz = get_huge_page_size (vui->region_mmap_fd[i]);
256 
257  ssize_t map_sz = (vui->regions[i].memory_size +
258  vui->regions[i].mmap_offset +
259  page_sz) & ~(page_sz - 1);
260 
261  r =
262  munmap (vui->region_mmap_addr[i] - vui->regions[i].mmap_offset,
263  map_sz);
264 
265  DBG_SOCK
266  ("unmap memory region %d addr 0x%lx len 0x%lx page_sz 0x%x", i,
267  vui->region_mmap_addr[i], map_sz, page_sz);
268 
269  vui->region_mmap_addr[i] = (void *) -1;
270 
271  if (r == -1)
272  {
273  clib_warning ("failed to unmap memory region (errno %d)",
274  errno);
275  }
276  close (vui->region_mmap_fd[i]);
277  }
278  }
279  vui->nregions = 0;
280 }
281 
282 
283 static clib_error_t *
285 {
286  __attribute__ ((unused)) int n;
287  u8 buff[8];
288  n = read (uf->file_descriptor, ((char *) &buff), 8);
289  return 0;
290 }
291 
292 static inline void
294 {
296  vnet_main_t *vnm = vnet_get_main ();
297  int q;
298 
300 
301  if (vui->unix_file_index != ~0)
302  {
304  vui->unix_file_index = ~0;
305  }
306  else
307  close (vui->unix_fd);
308 
311  vui->unix_fd = -1;
312  vui->is_up = 0;
313  for (q = 0; q < vui->num_vrings; q++)
314  {
315  if (vui->vrings[q].callfd > -1)
316  {
318  vui->vrings[q].callfd_idx);
319  unix_file_del (&unix_main, uf);
320  }
321 
322  if (vui->vrings[q].kickfd > -1)
323  close (vui->vrings[q].kickfd);
324 
325  vui->vrings[q].callfd = -1;
326  vui->vrings[q].kickfd = -1;
327  vui->vrings[q].desc = NULL;
328  vui->vrings[q].avail = NULL;
329  vui->vrings[q].used = NULL;
330  vui->vrings[q].log_guest_addr = 0;
331  vui->vrings[q].log_used = 0;
332  }
333 
334  unmap_all_mem_regions (vui);
335  DBG_SOCK ("interface ifindex %d disconnected", vui->sw_if_index);
336 }
337 
338 #define VHOST_LOG_PAGE 0x1000
339 always_inline void
341 {
342  if (PREDICT_TRUE (vui->log_base_addr == 0
343  || !(vui->features & (1 << FEAT_VHOST_F_LOG_ALL))))
344  {
345  return;
346  }
347  if (PREDICT_FALSE ((addr + len - 1) / VHOST_LOG_PAGE / 8 >= vui->log_size))
348  {
349  DBG_SOCK ("vhost_user_log_dirty_pages(): out of range\n");
350  return;
351  }
352 
354  u64 page = addr / VHOST_LOG_PAGE;
355  while (page * VHOST_LOG_PAGE < addr + len)
356  {
357  ((u8 *) vui->log_base_addr)[page / 8] |= 1 << page % 8;
358  page++;
359  }
360 }
361 
362 #define vhost_user_log_dirty_ring(vui, vq, member) \
363  if (PREDICT_FALSE(vq->log_used)) { \
364  vhost_user_log_dirty_pages(vui, vq->log_guest_addr + STRUCT_OFFSET_OF(vring_used_t, member), \
365  sizeof(vq->used->member)); \
366  }
367 
368 static clib_error_t *
370 {
371  int n, i;
372  int fd, number_of_fds = 0;
373  int fds[VHOST_MEMORY_MAX_NREGIONS];
374  vhost_user_msg_t msg;
375  struct msghdr mh;
376  struct iovec iov[1];
378  vhost_user_intf_t *vui;
379  struct cmsghdr *cmsg;
380  uword *p;
381  u8 q;
382  unix_file_t template = { 0 };
383  vnet_main_t *vnm = vnet_get_main ();
384 
385  p = hash_get (vum->vhost_user_interface_index_by_sock_fd,
386  uf->file_descriptor);
387  if (p == 0)
388  {
389  DBG_SOCK ("FD %d doesn't belong to any interface", uf->file_descriptor);
390  return 0;
391  }
392  else
393  vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
394 
395  char control[CMSG_SPACE (VHOST_MEMORY_MAX_NREGIONS * sizeof (int))];
396 
397  memset (&mh, 0, sizeof (mh));
398  memset (control, 0, sizeof (control));
399 
400  for (i = 0; i < VHOST_MEMORY_MAX_NREGIONS; i++)
401  fds[i] = -1;
402 
403  /* set the payload */
404  iov[0].iov_base = (void *) &msg;
405  iov[0].iov_len = VHOST_USER_MSG_HDR_SZ;
406 
407  mh.msg_iov = iov;
408  mh.msg_iovlen = 1;
409  mh.msg_control = control;
410  mh.msg_controllen = sizeof (control);
411 
412  n = recvmsg (uf->file_descriptor, &mh, 0);
413 
414  if (n != VHOST_USER_MSG_HDR_SZ)
415  goto close_socket;
416 
417  if (mh.msg_flags & MSG_CTRUNC)
418  {
419  goto close_socket;
420  }
421 
422  cmsg = CMSG_FIRSTHDR (&mh);
423 
424  if (cmsg && (cmsg->cmsg_len > 0) && (cmsg->cmsg_level == SOL_SOCKET) &&
425  (cmsg->cmsg_type == SCM_RIGHTS) &&
426  (cmsg->cmsg_len - CMSG_LEN (0) <=
427  VHOST_MEMORY_MAX_NREGIONS * sizeof (int)))
428  {
429  number_of_fds = (cmsg->cmsg_len - CMSG_LEN (0)) / sizeof (int);
430  clib_memcpy (fds, CMSG_DATA (cmsg), number_of_fds * sizeof (int));
431  }
432 
433  /* version 1, no reply bit set */
434  if ((msg.flags & 7) != 1)
435  {
436  DBG_SOCK ("malformed message received. closing socket");
437  goto close_socket;
438  }
439 
440  {
441  int rv __attribute__ ((unused));
442  /* $$$$ pay attention to rv */
443  rv = read (uf->file_descriptor, ((char *) &msg) + n, msg.size);
444  }
445 
446  switch (msg.request)
447  {
449  DBG_SOCK ("if %d msg VHOST_USER_GET_FEATURES", vui->hw_if_index);
450 
451  msg.flags |= 4;
452  msg.u64 = (1 << FEAT_VIRTIO_NET_F_MRG_RXBUF) |
453  (1 << FEAT_VIRTIO_F_ANY_LAYOUT) |
454  (1 << FEAT_VIRTIO_F_INDIRECT_DESC) |
455  (1 << FEAT_VHOST_F_LOG_ALL) |
456  (1 << FEAT_VIRTIO_NET_F_GUEST_ANNOUNCE) |
457  (1 << FEAT_VHOST_USER_F_PROTOCOL_FEATURES) |
458  (1UL << FEAT_VIRTIO_F_VERSION_1);
459  msg.u64 &= vui->feature_mask;
460 
461  msg.size = sizeof (msg.u64);
462  break;
463 
465  DBG_SOCK ("if %d msg VHOST_USER_SET_FEATURES features 0x%016llx",
466  vui->hw_if_index, msg.u64);
467 
468  vui->features = msg.u64;
469 
470  if (vui->features & (1 << FEAT_VIRTIO_NET_F_MRG_RXBUF))
471  vui->virtio_net_hdr_sz = 12;
472  else
473  vui->virtio_net_hdr_sz = 10;
474 
475  vui->is_any_layout =
476  (vui->features & (1 << FEAT_VIRTIO_F_ANY_LAYOUT)) ? 1 : 0;
477 
480  vui->is_up = 0;
481 
482  for (q = 0; q < 2; q++)
483  {
484  vui->vrings[q].desc = 0;
485  vui->vrings[q].avail = 0;
486  vui->vrings[q].used = 0;
487  vui->vrings[q].log_guest_addr = 0;
488  vui->vrings[q].log_used = 0;
489  }
490 
491  DBG_SOCK ("interface %d disconnected", vui->sw_if_index);
492 
493  break;
494 
496  DBG_SOCK ("if %d msg VHOST_USER_SET_MEM_TABLE nregions %d",
497  vui->hw_if_index, msg.memory.nregions);
498 
499  if ((msg.memory.nregions < 1) ||
500  (msg.memory.nregions > VHOST_MEMORY_MAX_NREGIONS))
501  {
502 
503  DBG_SOCK ("number of mem regions must be between 1 and %i",
504  VHOST_MEMORY_MAX_NREGIONS);
505 
506  goto close_socket;
507  }
508 
509  if (msg.memory.nregions != number_of_fds)
510  {
511  DBG_SOCK ("each memory region must have FD");
512  goto close_socket;
513  }
514  unmap_all_mem_regions (vui);
515  for (i = 0; i < msg.memory.nregions; i++)
516  {
517  clib_memcpy (&(vui->regions[i]), &msg.memory.regions[i],
518  sizeof (vhost_user_memory_region_t));
519 
520  long page_sz = get_huge_page_size (fds[i]);
521 
522  /* align size to 2M page */
523  ssize_t map_sz = (vui->regions[i].memory_size +
524  vui->regions[i].mmap_offset +
525  page_sz) & ~(page_sz - 1);
526 
527  vui->region_mmap_addr[i] = mmap (0, map_sz, PROT_READ | PROT_WRITE,
528  MAP_SHARED, fds[i], 0);
531  vui->regions[i].memory_size;
532 
533  DBG_SOCK
534  ("map memory region %d addr 0 len 0x%lx fd %d mapped 0x%lx "
535  "page_sz 0x%x", i, map_sz, fds[i], vui->region_mmap_addr[i],
536  page_sz);
537 
538  if (vui->region_mmap_addr[i] == MAP_FAILED)
539  {
540  clib_warning ("failed to map memory. errno is %d", errno);
541  goto close_socket;
542  }
543  vui->region_mmap_addr[i] += vui->regions[i].mmap_offset;
544  vui->region_mmap_fd[i] = fds[i];
545  }
546  vui->nregions = msg.memory.nregions;
547  break;
548 
550  DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_NUM idx %d num %d",
551  vui->hw_if_index, msg.state.index, msg.state.num);
552 
553  if ((msg.state.num > 32768) || /* maximum ring size is 32768 */
554  (msg.state.num == 0) || /* it cannot be zero */
555  (msg.state.num % 2)) /* must be power of 2 */
556  goto close_socket;
557  vui->vrings[msg.state.index].qsz = msg.state.num;
558  break;
559 
561  DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_ADDR idx %d",
562  vui->hw_if_index, msg.state.index);
563 
564  vui->vrings[msg.state.index].desc = (vring_desc_t *)
565  map_user_mem (vui, msg.addr.desc_user_addr);
566  vui->vrings[msg.state.index].used = (vring_used_t *)
567  map_user_mem (vui, msg.addr.used_user_addr);
568  vui->vrings[msg.state.index].avail = (vring_avail_t *)
569  map_user_mem (vui, msg.addr.avail_user_addr);
570 
571  if ((vui->vrings[msg.state.index].desc == NULL) ||
572  (vui->vrings[msg.state.index].used == NULL) ||
573  (vui->vrings[msg.state.index].avail == NULL))
574  {
575  DBG_SOCK ("failed to map user memory for hw_if_index %d",
576  vui->hw_if_index);
577  goto close_socket;
578  }
579 
580  vui->vrings[msg.state.index].log_guest_addr = msg.addr.log_guest_addr;
581  vui->vrings[msg.state.index].log_used =
582  (msg.addr.flags & (1 << VHOST_VRING_F_LOG)) ? 1 : 0;
583 
584  /* Spec says: If VHOST_USER_F_PROTOCOL_FEATURES has not been negotiated,
585  the ring is initialized in an enabled state. */
586 
587  if (!(vui->features & (1 << FEAT_VHOST_USER_F_PROTOCOL_FEATURES)))
588  {
589  vui->vrings[msg.state.index].enabled = 1;
590  }
591 
592  vui->vrings[msg.state.index].last_used_idx =
593  vui->vrings[msg.state.index].last_avail_idx =
594  vui->vrings[msg.state.index].used->idx;
595 
596  /* tell driver that we don't want interrupts */
597  vui->vrings[msg.state.index].used->flags |= 1;
598  break;
599 
601  DBG_SOCK ("if %d msg VHOST_USER_SET_OWNER", vui->hw_if_index);
602  break;
603 
605  DBG_SOCK ("if %d msg VHOST_USER_RESET_OWNER", vui->hw_if_index);
606  break;
607 
609  DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_CALL u64 %d",
610  vui->hw_if_index, msg.u64);
611 
612  q = (u8) (msg.u64 & 0xFF);
613 
614  if (!(msg.u64 & 0x100))
615  {
616  if (number_of_fds != 1)
617  goto close_socket;
618 
619  /* if there is old fd, delete it */
620  if (vui->vrings[q].callfd > -1)
621  {
623  vui->vrings[q].callfd_idx);
624  unix_file_del (&unix_main, uf);
625  }
626  vui->vrings[q].callfd = fds[0];
627  template.read_function = vhost_user_callfd_read_ready;
628  template.file_descriptor = fds[0];
629  vui->vrings[q].callfd_idx = unix_file_add (&unix_main, &template);
630  }
631  else
632  vui->vrings[q].callfd = -1;
633  break;
634 
636  DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_KICK u64 %d",
637  vui->hw_if_index, msg.u64);
638 
639  q = (u8) (msg.u64 & 0xFF);
640 
641  if (!(msg.u64 & 0x100))
642  {
643  if (number_of_fds != 1)
644  goto close_socket;
645 
646  if (vui->vrings[q].kickfd > -1)
647  close (vui->vrings[q].kickfd);
648 
649  vui->vrings[q].kickfd = fds[0];
650  }
651  else
652  vui->vrings[q].kickfd = -1;
653  break;
654 
656  DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_ERR u64 %d",
657  vui->hw_if_index, msg.u64);
658 
659  q = (u8) (msg.u64 & 0xFF);
660 
661  if (!(msg.u64 & 0x100))
662  {
663  if (number_of_fds != 1)
664  goto close_socket;
665 
666  fd = fds[0];
667  }
668  else
669  fd = -1;
670 
671  vui->vrings[q].errfd = fd;
672  break;
673 
675  DBG_SOCK ("if %d msg VHOST_USER_SET_VRING_BASE idx %d num %d",
676  vui->hw_if_index, msg.state.index, msg.state.num);
677 
678  vui->vrings[msg.state.index].last_avail_idx = msg.state.num;
679  break;
680 
682  DBG_SOCK ("if %d msg VHOST_USER_GET_VRING_BASE idx %d num %d",
683  vui->hw_if_index, msg.state.index, msg.state.num);
684 
685  /* Spec says: Client must [...] stop ring upon receiving VHOST_USER_GET_VRING_BASE. */
686  vui->vrings[msg.state.index].enabled = 0;
687 
688  msg.state.num = vui->vrings[msg.state.index].last_avail_idx;
689  msg.flags |= 4;
690  msg.size = sizeof (msg.state);
691  break;
692 
693  case VHOST_USER_NONE:
694  DBG_SOCK ("if %d msg VHOST_USER_NONE", vui->hw_if_index);
695 
696  break;
697 
699  {
700  DBG_SOCK ("if %d msg VHOST_USER_SET_LOG_BASE", vui->hw_if_index);
701 
702  if (msg.size != sizeof (msg.log))
703  {
704  DBG_SOCK
705  ("invalid msg size for VHOST_USER_SET_LOG_BASE: %d instead of %d",
706  msg.size, sizeof (msg.log));
707  goto close_socket;
708  }
709 
710  if (!
712  {
713  DBG_SOCK
714  ("VHOST_USER_PROTOCOL_F_LOG_SHMFD not set but VHOST_USER_SET_LOG_BASE received");
715  goto close_socket;
716  }
717 
718  fd = fds[0];
719  /* align size to 2M page */
720  long page_sz = get_huge_page_size (fd);
721  ssize_t map_sz =
722  (msg.log.size + msg.log.offset + page_sz) & ~(page_sz - 1);
723 
724  vui->log_base_addr = mmap (0, map_sz, PROT_READ | PROT_WRITE,
725  MAP_SHARED, fd, 0);
726 
727  DBG_SOCK
728  ("map log region addr 0 len 0x%lx off 0x%lx fd %d mapped 0x%lx",
729  map_sz, msg.log.offset, fd, vui->log_base_addr);
730 
731  if (vui->log_base_addr == MAP_FAILED)
732  {
733  clib_warning ("failed to map memory. errno is %d", errno);
734  goto close_socket;
735  }
736 
737  vui->log_base_addr += msg.log.offset;
738  vui->log_size = msg.log.size;
739 
740  msg.flags |= 4;
741  msg.size = sizeof (msg.u64);
742 
743  break;
744  }
745 
747  DBG_SOCK ("if %d msg VHOST_USER_SET_LOG_FD", vui->hw_if_index);
748 
749  break;
750 
752  DBG_SOCK ("if %d msg VHOST_USER_GET_PROTOCOL_FEATURES",
753  vui->hw_if_index);
754 
755  msg.flags |= 4;
756  msg.u64 = (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD);
757  msg.size = sizeof (msg.u64);
758  break;
759 
761  DBG_SOCK ("if %d msg VHOST_USER_SET_PROTOCOL_FEATURES features 0x%lx",
762  vui->hw_if_index, msg.u64);
763 
764  vui->protocol_features = msg.u64;
765 
766  break;
767 
769  DBG_SOCK ("if %d VHOST_USER_SET_VRING_ENABLE, enable: %d",
770  vui->hw_if_index, msg.state.num);
771  vui->vrings[msg.state.index].enabled = msg.state.num;
772  break;
773 
774  default:
775  DBG_SOCK ("unknown vhost-user message %d received. closing socket",
776  msg.request);
777  goto close_socket;
778  }
779 
780  /* if we have pointers to descriptor table, go up */
781  if (!vui->is_up &&
784  {
785 
786  DBG_SOCK ("interface %d connected", vui->sw_if_index);
787 
790  vui->is_up = 1;
791 
792  }
793 
794  /* if we need to reply */
795  if (msg.flags & 4)
796  {
797  n =
798  send (uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
799  if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
800  goto close_socket;
801  }
802 
803  return 0;
804 
805 close_socket:
807  return 0;
808 }
809 
810 static clib_error_t *
812 {
814  vhost_user_intf_t *vui;
815  uword *p;
816 
818  uf->file_descriptor);
819  if (p == 0)
820  {
821  DBG_SOCK ("fd %d doesn't belong to any interface", uf->file_descriptor);
822  return 0;
823  }
824  else
825  vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
826 
828  return 0;
829 }
830 
831 static clib_error_t *
833 {
834  int client_fd, client_len;
835  struct sockaddr_un client;
836  unix_file_t template = { 0 };
838  vhost_user_intf_t *vui;
839  uword *p;
840 
842  uf->file_descriptor);
843  if (p == 0)
844  {
845  DBG_SOCK ("fd %d doesn't belong to any interface", uf->file_descriptor);
846  return 0;
847  }
848  else
849  vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
850 
851  client_len = sizeof (client);
852  client_fd = accept (uf->file_descriptor,
853  (struct sockaddr *) &client,
854  (socklen_t *) & client_len);
855 
856  if (client_fd < 0)
857  return clib_error_return_unix (0, "accept");
858 
859  template.read_function = vhost_user_socket_read;
860  template.error_function = vhost_user_socket_error;
861  template.file_descriptor = client_fd;
862  vui->unix_file_index = unix_file_add (&unix_main, &template);
863 
864  vui->client_fd = client_fd;
866  vui - vum->vhost_user_interfaces);
867 
868  return 0;
869 }
870 
871 static clib_error_t *
873 {
874  clib_error_t *error;
878  uword *p;
879 
880  error = vlib_call_init_function (vm, ip4_init);
881  if (error)
882  return error;
883 
885  hash_create (0, sizeof (uword));
887  hash_create (0, sizeof (uword));
889  hash_create (0, sizeof (uword));
890  vum->coalesce_frames = 32;
891  vum->coalesce_time = 1e-3;
892 
895 
896  /* find out which cpus will be used for input */
897  vum->input_cpu_first_index = 0;
898  vum->input_cpu_count = 1;
899  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
900  tr = p ? (vlib_thread_registration_t *) p[0] : 0;
901 
902  if (tr && tr->count > 0)
903  {
905  vum->input_cpu_count = tr->count;
906  }
907 
908  return 0;
909 }
910 
912 
913 static clib_error_t *
915 {
916  /* TODO cleanup */
917  return 0;
918 }
919 
921 
922 typedef struct
923 {
926 #if VHOST_USER_COPY_TX_HDR == 1
927  virtio_net_hdr_t hdr;
928 #endif
930 
931 static u8 *
933 {
934  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
935  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
940  t->device_index);
941 
943 
944 #if VHOST_USER_COPY_TX_HDR == 1
945  uword indent = format_get_indent (s);
946 #endif
947 
948  s = format (s, "%U virtqueue %d",
950 
951 #if VHOST_USER_COPY_TX_HDR == 1
952  s = format (s, "\n%Uvirtio_net_hdr flags 0x%02x gso_type %u hdr_len %u",
953  format_white_space, indent,
954  t->hdr.flags, t->hdr.gso_type, t->hdr.hdr_len);
955 #endif
956 
957  return s;
958 }
959 
960 void
962  vlib_node_runtime_t * node,
963  vhost_user_intf_t * vui, i16 virtqueue)
964 {
965  u32 *b, n_left;
967 
969 
970  n_left = vec_len (vui->d_trace_buffers);
971  b = vui->d_trace_buffers;
972 
973  while (n_left >= 1)
974  {
975  u32 bi0;
976  vlib_buffer_t *b0;
978 
979  bi0 = b[0];
980  n_left -= 1;
981 
982  b0 = vlib_get_buffer (vm, bi0);
983  vlib_trace_buffer (vm, node, next_index, b0, /* follow_chain */ 0);
984  t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
985  t0->virtqueue = virtqueue;
986  t0->device_index = vui - vum->vhost_user_interfaces;
987 #if VHOST_USER_COPY_TX_HDR == 1
988  clib_memcpy (&t0->hdr, b0->pre_data, sizeof (virtio_net_hdr_t));
989 #endif
990 
991  b += 1;
992  }
993 }
994 
995 static inline void
997 {
999  u64 x = 1;
1000  int rv __attribute__ ((unused));
1001  /* $$$$ pay attention to rv */
1002  rv = write (vq->callfd, &x, sizeof (x));
1003  vq->n_since_last_int = 0;
1004  vq->int_deadline = vlib_time_now (vm) + vum->coalesce_time;
1005 }
1006 
1007 
1008 static u32
1010  vhost_user_main_t * vum,
1011  vhost_user_intf_t * vui, vlib_node_runtime_t * node)
1012 {
1015  uword n_rx_packets = 0, n_rx_bytes = 0;
1016  uword n_left;
1017  u32 n_left_to_next, *to_next;
1018  u32 next_index = 0;
1019  u32 next0;
1020  uword n_trace = vlib_get_trace_count (vm, node);
1021  u16 qsz_mask;
1022  u32 cpu_index, rx_len, drops, flush;
1023  f64 now = vlib_time_now (vm);
1024  u32 map_guest_hint_desc = 0;
1025  u32 map_guest_hint_indirect = 0;
1026  u32 *map_guest_hint_p = &map_guest_hint_desc;
1027 
1029 
1030  /* no descriptor ptr - bail out */
1031  if (PREDICT_FALSE (!txvq->desc || !txvq->avail || !txvq->enabled))
1032  return 0;
1033 
1034  /* do we have pending intterupts ? */
1035  if ((txvq->n_since_last_int) && (txvq->int_deadline < now))
1036  vhost_user_send_call (vm, txvq);
1037 
1038  if ((rxvq->n_since_last_int) && (rxvq->int_deadline < now))
1039  vhost_user_send_call (vm, rxvq);
1040 
1041  /* only bit 0 of avail.flags is used so we don't want to deal with this
1042  interface if any other bit is set */
1043  if (PREDICT_FALSE (txvq->avail->flags & 0xFFFE))
1044  return 0;
1045 
1046  n_left = (u16) (txvq->avail->idx - txvq->last_avail_idx);
1047 
1048  /* nothing to do */
1049  if (PREDICT_FALSE (n_left == 0))
1050  return 0;
1051 
1052  if (PREDICT_FALSE (n_left == txvq->qsz))
1053  {
1054  //Informational error logging when VPP is not receiving packets fast enough
1055  vlib_error_count (vm, node->node_index,
1056  VHOST_USER_INPUT_FUNC_ERROR_FULL_RX_QUEUE, 1);
1057  }
1058 
1059  if (PREDICT_FALSE (!vui->admin_up))
1060  {
1061  /* if intf is admin down, just drop all packets waiting in the ring */
1062  txvq->last_avail_idx = txvq->last_used_idx = txvq->avail->idx;
1064  txvq->used->idx = txvq->last_used_idx;
1065  vhost_user_log_dirty_ring (vui, txvq, idx);
1066  vhost_user_send_call (vm, txvq);
1067  return 0;
1068  }
1069 
1070  qsz_mask = txvq->qsz - 1;
1071  cpu_index = os_get_cpu_number ();
1072  drops = 0;
1073  flush = 0;
1074 
1075  if (n_left > VLIB_FRAME_SIZE)
1076  n_left = VLIB_FRAME_SIZE;
1077 
1078  /* Allocate some buffers.
1079  * Note that buffers that are chained for jumbo
1080  * frames are allocated separately using a slower path.
1081  * The idea is to be certain to have enough buffers at least
1082  * to cycle through the descriptors without having to check for errors.
1083  * For jumbo frames, the bottleneck is memory copy anyway.
1084  */
1085  if (PREDICT_FALSE (!vum->rx_buffers[cpu_index]))
1086  {
1087  vec_alloc (vum->rx_buffers[cpu_index], 2 * VLIB_FRAME_SIZE);
1088 
1089  if (PREDICT_FALSE (!vum->rx_buffers[cpu_index]))
1090  flush = n_left; //Drop all input
1091  }
1092 
1093  if (PREDICT_FALSE (_vec_len (vum->rx_buffers[cpu_index]) < n_left))
1094  {
1095  u32 curr_len = _vec_len (vum->rx_buffers[cpu_index]);
1096  _vec_len (vum->rx_buffers[cpu_index]) +=
1098  vum->rx_buffers[cpu_index] +
1099  curr_len,
1100  2 * VLIB_FRAME_SIZE - curr_len,
1102 
1103  if (PREDICT_FALSE (n_left > _vec_len (vum->rx_buffers[cpu_index])))
1104  flush = n_left - _vec_len (vum->rx_buffers[cpu_index]);
1105  }
1106 
1107  if (PREDICT_FALSE (flush))
1108  {
1109  //Remove some input buffers
1110  drops += flush;
1111  n_left -= flush;
1113  VHOST_USER_INPUT_FUNC_ERROR_NO_BUFFER, flush);
1114  while (flush)
1115  {
1116  u16 desc_chain_head =
1117  txvq->avail->ring[txvq->last_avail_idx & qsz_mask];
1118  txvq->last_avail_idx++;
1119  txvq->used->ring[txvq->last_used_idx & qsz_mask].id =
1120  desc_chain_head;
1121  txvq->used->ring[txvq->last_used_idx & qsz_mask].len = 0;
1122  vhost_user_log_dirty_ring (vui, txvq,
1123  ring[txvq->last_used_idx & qsz_mask]);
1124  txvq->last_used_idx++;
1125  flush--;
1126  }
1127  }
1128 
1129  rx_len = vec_len (vum->rx_buffers[cpu_index]); //vector might be null
1130  while (n_left > 0)
1131  {
1132  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1133 
1134  while (n_left > 0 && n_left_to_next > 0)
1135  {
1136  vlib_buffer_t *b_head, *b_current;
1137  u32 bi_head, bi_current;
1138  u16 desc_chain_head, desc_current;
1139  u8 error = VHOST_USER_INPUT_FUNC_ERROR_NO_ERROR;
1140 
1141  if (PREDICT_TRUE (n_left > 1))
1142  {
1143  u32 next_desc =
1144  txvq->avail->ring[(txvq->last_avail_idx + 1) & qsz_mask];
1145  void *buffer_addr =
1146  map_guest_mem (vui, txvq->desc[next_desc].addr,
1147  &map_guest_hint_desc);
1148  if (PREDICT_TRUE (buffer_addr != 0))
1149  CLIB_PREFETCH (buffer_addr, 64, STORE);
1150 
1151  u32 bi = vum->rx_buffers[cpu_index][rx_len - 2];
1152  vlib_prefetch_buffer_with_index (vm, bi, STORE);
1153  CLIB_PREFETCH (vlib_get_buffer (vm, bi)->data, 128, STORE);
1154  }
1155 
1156  desc_chain_head = desc_current =
1157  txvq->avail->ring[txvq->last_avail_idx & qsz_mask];
1158  bi_head = bi_current = vum->rx_buffers[cpu_index][--rx_len];
1159  b_head = b_current = vlib_get_buffer (vm, bi_head);
1160  vlib_buffer_chain_init (b_head);
1161 
1162  uword offset;
1163  if (PREDICT_TRUE (vui->is_any_layout) ||
1164  (!(txvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT) &&
1165  !(txvq->desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT)))
1166  {
1167  /* ANYLAYOUT or single buffer */
1168  offset = vui->virtio_net_hdr_sz;
1169  }
1170  else
1171  {
1172  /* CSR case without ANYLAYOUT, skip 1st buffer */
1173  offset = txvq->desc[desc_current].len;
1174  }
1175 
1176  vring_desc_t *desc_table = txvq->desc;
1177  u32 desc_index = desc_current;
1178  map_guest_hint_p = &map_guest_hint_desc;
1179 
1180  if (txvq->desc[desc_current].flags & VIRTQ_DESC_F_INDIRECT)
1181  {
1182  desc_table = map_guest_mem (vui, txvq->desc[desc_current].addr,
1183  &map_guest_hint_desc);
1184  desc_index = 0;
1185  map_guest_hint_p = &map_guest_hint_indirect;
1186  if (PREDICT_FALSE (desc_table == 0))
1187  {
1188  error = VHOST_USER_INPUT_FUNC_ERROR_MMAP_FAIL;
1189  goto out;
1190  }
1191  }
1192 
1193  while (1)
1194  {
1195  void *buffer_addr =
1196  map_guest_mem (vui, desc_table[desc_index].addr,
1197  map_guest_hint_p);
1198  if (PREDICT_FALSE (buffer_addr == 0))
1199  {
1200  error = VHOST_USER_INPUT_FUNC_ERROR_MMAP_FAIL;
1201  goto out;
1202  }
1203 
1204  if (PREDICT_TRUE
1205  (desc_table[desc_index].flags & VIRTQ_DESC_F_NEXT))
1206  {
1207  CLIB_PREFETCH (&desc_table[desc_table[desc_index].next],
1208  sizeof (vring_desc_t), STORE);
1209  }
1210 
1211 #if VHOST_USER_COPY_TX_HDR == 1
1212  if (PREDICT_TRUE (offset))
1213  clib_memcpy (b->pre_data, buffer_addr, sizeof (virtio_net_hdr_t)); /* 12 byte hdr is not used on tx */
1214 #endif
1215 
1216  if (desc_table[desc_index].len > offset)
1217  {
1218  u16 len = desc_table[desc_index].len - offset;
1221  b_head,
1222  &b_current,
1223  buffer_addr
1224  +
1225  offset,
1226  len);
1227  if (copied != len)
1228  {
1229  error = VHOST_USER_INPUT_FUNC_ERROR_NO_BUFFER;
1230  break;
1231  }
1232  }
1233  offset = 0;
1234 
1235  /* if next flag is set, take next desc in the chain */
1236  if ((desc_table[desc_index].flags & VIRTQ_DESC_F_NEXT))
1237  desc_index = desc_table[desc_index].next;
1238  else
1239  goto out;
1240  }
1241  out:
1242 
1243  /* consume the descriptor and return it as used */
1244  txvq->last_avail_idx++;
1245  txvq->used->ring[txvq->last_used_idx & qsz_mask].id =
1246  desc_chain_head;
1247  txvq->used->ring[txvq->last_used_idx & qsz_mask].len = 0;
1248  vhost_user_log_dirty_ring (vui, txvq,
1249  ring[txvq->last_used_idx & qsz_mask]);
1250  txvq->last_used_idx++;
1251 
1252  //It is important to free RX as fast as possible such that the TX
1253  //process does not drop packets
1254  if ((txvq->last_used_idx & 0x3f) == 0) // Every 64 packets
1255  txvq->used->idx = txvq->last_used_idx;
1256 
1257  if (PREDICT_FALSE (b_head->current_length < 14 &&
1258  error == VHOST_USER_INPUT_FUNC_ERROR_NO_ERROR))
1259  error = VHOST_USER_INPUT_FUNC_ERROR_UNDERSIZED_FRAME;
1260 
1262 
1263  vnet_buffer (b_head)->sw_if_index[VLIB_RX] = vui->sw_if_index;
1264  vnet_buffer (b_head)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1265  b_head->error = node->errors[error];
1266 
1267  if (PREDICT_FALSE (n_trace > n_rx_packets))
1268  vec_add1 (vui->d_trace_buffers, bi_head);
1269 
1270  if (PREDICT_FALSE (error))
1271  {
1272  drops++;
1274  }
1275  else
1276  {
1277  n_rx_bytes +=
1278  b_head->current_length +
1280  n_rx_packets++;
1282  }
1283 
1284  to_next[0] = bi_head;
1285  to_next++;
1286  n_left_to_next--;
1287 
1288  /* redirect if feature path enabled */
1290  &next0, b_head, 0);
1291 
1292  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1293  to_next, n_left_to_next,
1294  bi_head, next0);
1295  n_left--;
1296  }
1297 
1298  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1299 
1300  }
1301 
1302  if (PREDICT_TRUE (vum->rx_buffers[cpu_index] != 0))
1303  _vec_len (vum->rx_buffers[cpu_index]) = rx_len;
1304 
1305  /* give buffers back to driver */
1307  txvq->used->idx = txvq->last_used_idx;
1308  vhost_user_log_dirty_ring (vui, txvq, idx);
1309 
1310  if (PREDICT_FALSE (vec_len (vui->d_trace_buffers) > 0))
1311  {
1313  vlib_set_trace_count (vm, node,
1314  n_trace - vec_len (vui->d_trace_buffers));
1315  }
1316 
1317  /* interrupt (call) handling */
1318  if ((txvq->callfd > -1) && !(txvq->avail->flags & 1))
1319  {
1320  txvq->n_since_last_int += n_rx_packets;
1321 
1322  if (txvq->n_since_last_int > vum->coalesce_frames)
1323  vhost_user_send_call (vm, txvq);
1324  }
1325 
1326  if (PREDICT_FALSE (drops))
1327  {
1331  vui->sw_if_index, drops);
1332  }
1333 
1334  /* increase rx counters */
1338  os_get_cpu_number (), vui->sw_if_index, n_rx_packets, n_rx_bytes);
1339 
1340  return n_rx_packets;
1341 }
1342 
1343 static uword
1345  vlib_node_runtime_t * node, vlib_frame_t * f)
1346 {
1348  u32 cpu_index = os_get_cpu_number ();
1349  vhost_user_intf_t *vui;
1350  uword n_rx_packets = 0;
1351  int i;
1352 
1353  for (i = 0; i < vec_len (vum->vhost_user_interfaces); i++)
1354  {
1355  vui = vec_elt_at_index (vum->vhost_user_interfaces, i);
1356  if (vui->is_up)
1357  {
1358  if ((i % vum->input_cpu_count) ==
1359  (cpu_index - vum->input_cpu_first_index))
1360  n_rx_packets += vhost_user_if_input (vm, vum, vui, node);
1361  }
1362  }
1363  return n_rx_packets;
1364 }
1365 
1366 /* *INDENT-OFF* */
1368  .function = vhost_user_input,
1369  .type = VLIB_NODE_TYPE_INPUT,
1370  .name = "vhost-user-input",
1371 
1372  /* Will be enabled if/when hardware is detected. */
1373  .state = VLIB_NODE_STATE_DISABLED,
1374 
1375  .format_buffer = format_ethernet_header_with_length,
1376  .format_trace = format_vhost_user_input_trace,
1377 
1378  .n_errors = VHOST_USER_INPUT_FUNC_N_ERROR,
1379  .error_strings = vhost_user_input_func_error_strings,
1380 
1381  .n_next_nodes = VNET_DEVICE_INPUT_N_NEXT_NODES,
1382  .next_nodes = VNET_DEVICE_INPUT_NEXT_NODES,
1383 };
1384 
1386 /* *INDENT-ON* */
1387 
1388 static uword
1390  vlib_node_runtime_t * node, vlib_frame_t * frame)
1391 {
1392  u32 *buffers = vlib_frame_args (frame);
1393  u32 n_left = 0;
1395  uword n_packets = 0;
1396  vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
1397  vhost_user_intf_t *vui =
1399  vhost_user_vring_t *rxvq = &vui->vrings[VHOST_NET_VRING_IDX_RX];
1400  u16 qsz_mask;
1401  u8 error = VHOST_USER_TX_FUNC_ERROR_NONE;
1402 
1403  n_left = n_packets = frame->n_vectors;
1404  u32 map_guest_hint_desc = 0;
1405  u32 map_guest_hint_indirect = 0;
1406  u32 *map_guest_hint_p = &map_guest_hint_desc;
1407 
1408  if (PREDICT_FALSE (!vui->is_up))
1409  goto done2;
1410 
1411  if (PREDICT_FALSE
1412  (!rxvq->desc || !rxvq->avail || vui->sock_errno != 0 || !rxvq->enabled))
1413  {
1414  error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
1415  goto done2;
1416  }
1417 
1418  if (PREDICT_FALSE (vui->lockp != 0))
1419  {
1420  while (__sync_lock_test_and_set (vui->lockp, 1))
1421  ;
1422  }
1423 
1424  /* only bit 0 of avail.flags is used so we don't want to deal with this
1425  interface if any other bit is set */
1426  if (PREDICT_FALSE (rxvq->avail->flags & 0xFFFE))
1427  {
1428  error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
1429  goto done2;
1430  }
1431 
1432  if (PREDICT_FALSE ((rxvq->avail->idx == rxvq->last_avail_idx)))
1433  {
1434  error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1435  goto done2;
1436  }
1437 
1438  qsz_mask = rxvq->qsz - 1; /* qsz is always power of 2 */
1439 
1440  while (n_left > 0)
1441  {
1442  vlib_buffer_t *b0, *current_b0;
1443  u16 desc_head, desc_index, desc_len;
1444  vring_desc_t *desc_table;
1445  void *buffer_addr;
1446  u32 buffer_len;
1447 
1448  b0 = vlib_get_buffer (vm, buffers[0]);
1449  buffers++;
1450 
1451  if (PREDICT_FALSE (rxvq->last_avail_idx == rxvq->avail->idx))
1452  {
1453  error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1454  goto done;
1455  }
1456 
1457  desc_table = rxvq->desc;
1458  map_guest_hint_p = &map_guest_hint_desc;
1459  desc_head = desc_index =
1460  rxvq->avail->ring[rxvq->last_avail_idx & qsz_mask];
1461  if (rxvq->desc[desc_head].flags & VIRTQ_DESC_F_INDIRECT)
1462  {
1463  if (PREDICT_FALSE
1464  (rxvq->desc[desc_head].len < sizeof (vring_desc_t)))
1465  {
1466  error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
1467  goto done;
1468  }
1469  if (PREDICT_FALSE
1470  (!(desc_table =
1471  map_guest_mem (vui, rxvq->desc[desc_index].addr,
1472  &map_guest_hint_desc))))
1473  {
1474  error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1475  goto done;
1476  }
1477  desc_index = 0;
1478  map_guest_hint_p = &map_guest_hint_indirect;
1479  }
1480 
1481  desc_len = vui->virtio_net_hdr_sz;
1482 
1483  if (PREDICT_FALSE
1484  (!(buffer_addr =
1485  map_guest_mem (vui, desc_table[desc_index].addr,
1486  map_guest_hint_p))))
1487  {
1488  error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1489  goto done;
1490  }
1491  buffer_len = desc_table[desc_index].len;
1492 
1493  CLIB_PREFETCH (buffer_addr, CLIB_CACHE_LINE_BYTES, STORE);
1494 
1495  virtio_net_hdr_mrg_rxbuf_t *hdr =
1496  (virtio_net_hdr_mrg_rxbuf_t *) buffer_addr;
1497  hdr->hdr.flags = 0;
1498  hdr->hdr.gso_type = 0;
1499  if (vui->virtio_net_hdr_sz == 12)
1500  hdr->num_buffers = 1;
1501 
1502  vhost_user_log_dirty_pages (vui, desc_table[desc_index].addr,
1503  vui->virtio_net_hdr_sz);
1504 
1505  u16 bytes_left = b0->current_length;
1506  buffer_addr += vui->virtio_net_hdr_sz;
1507  buffer_len -= vui->virtio_net_hdr_sz;
1508  current_b0 = b0;
1509  while (1)
1510  {
1511  if (!bytes_left)
1512  { //Get new input
1513  if (current_b0->flags & VLIB_BUFFER_NEXT_PRESENT)
1514  {
1515  current_b0 = vlib_get_buffer (vm, current_b0->next_buffer);
1516  bytes_left = current_b0->current_length;
1517  }
1518  else
1519  {
1520  //End of packet
1521  break;
1522  }
1523  }
1524 
1525  if (buffer_len == 0)
1526  { //Get new output
1527  if (desc_table[desc_index].flags & VIRTQ_DESC_F_NEXT)
1528  {
1529  //Next one is chained
1530  desc_index = desc_table[desc_index].next;
1531  if (PREDICT_FALSE
1532  (!(buffer_addr =
1533  map_guest_mem (vui, desc_table[desc_index].addr,
1534  map_guest_hint_p))))
1535  {
1536  rxvq->last_used_idx -= hdr->num_buffers - 1;
1537  rxvq->last_avail_idx -= hdr->num_buffers - 1;
1538  error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1539  goto done;
1540  }
1541  buffer_len = desc_table[desc_index].len;
1542  }
1543  else if (vui->virtio_net_hdr_sz == 12) //MRG is available
1544  {
1545  //Move from available to used buffer
1546  rxvq->used->ring[rxvq->last_used_idx & qsz_mask].id =
1547  desc_head;
1548  rxvq->used->ring[rxvq->last_used_idx & qsz_mask].len =
1549  desc_len;
1550  vhost_user_log_dirty_ring (vui, rxvq,
1551  ring[rxvq->last_used_idx &
1552  qsz_mask]);
1553  rxvq->last_avail_idx++;
1554  rxvq->last_used_idx++;
1555  hdr->num_buffers++;
1556 
1557  if (PREDICT_FALSE
1558  (rxvq->last_avail_idx == rxvq->avail->idx))
1559  {
1560  //Dequeue queued descriptors for this packet
1561  rxvq->last_used_idx -= hdr->num_buffers - 1;
1562  rxvq->last_avail_idx -= hdr->num_buffers - 1;
1563  error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1564  goto done;
1565  }
1566 
1567  desc_table = rxvq->desc;
1568  map_guest_hint_p = &map_guest_hint_desc;
1569  desc_head = desc_index =
1570  rxvq->avail->ring[rxvq->last_avail_idx & qsz_mask];
1571  if (PREDICT_FALSE
1572  (rxvq->desc[desc_head].flags & VIRTQ_DESC_F_INDIRECT))
1573  {
1574  //It is seriously unlikely that a driver will put indirect descriptor
1575  //after non-indirect descriptor.
1576  if (PREDICT_FALSE
1577  (rxvq->desc[desc_head].len < sizeof (vring_desc_t)))
1578  {
1579  error = VHOST_USER_TX_FUNC_ERROR_INDIRECT_OVERFLOW;
1580  goto done;
1581  }
1582  if (PREDICT_FALSE
1583  (!(desc_table =
1584  map_guest_mem (vui,
1585  rxvq->desc[desc_index].addr,
1586  &map_guest_hint_desc))))
1587  {
1588  error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1589  goto done;
1590  }
1591  desc_index = 0;
1592  map_guest_hint_p = &map_guest_hint_indirect;
1593  }
1594 
1595  if (PREDICT_FALSE
1596  (!(buffer_addr =
1597  map_guest_mem (vui, desc_table[desc_index].addr,
1598  map_guest_hint_p))))
1599  {
1600  error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1601  goto done;
1602  }
1603  buffer_len = desc_table[desc_index].len;
1604  CLIB_PREFETCH (buffer_addr, CLIB_CACHE_LINE_BYTES, STORE);
1605  }
1606  else
1607  {
1608  error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOMRG;
1609  goto done;
1610  }
1611  }
1612 
1613  u16 bytes_to_copy = bytes_left;
1614  bytes_to_copy =
1615  (bytes_to_copy > buffer_len) ? buffer_len : bytes_to_copy;
1616  clib_memcpy (buffer_addr,
1617  vlib_buffer_get_current (current_b0) +
1618  current_b0->current_length - bytes_left,
1619  bytes_to_copy);
1620 
1622  desc_table[desc_index].addr +
1623  desc_table[desc_index].len -
1624  bytes_left - bytes_to_copy,
1625  bytes_to_copy);
1626 
1627  bytes_left -= bytes_to_copy;
1628  buffer_len -= bytes_to_copy;
1629  buffer_addr += bytes_to_copy;
1630  desc_len += bytes_to_copy;
1631  }
1632 
1633  //Move from available to used ring
1634  rxvq->used->ring[rxvq->last_used_idx & qsz_mask].id = desc_head;
1635  rxvq->used->ring[rxvq->last_used_idx & qsz_mask].len = desc_len;
1636  vhost_user_log_dirty_ring (vui, rxvq,
1637  ring[rxvq->last_used_idx & qsz_mask]);
1638 
1639  rxvq->last_avail_idx++;
1640  rxvq->last_used_idx++;
1641 
1642  n_left--; //At the end for error counting when 'goto done' is invoked
1643  }
1644 
1645 done:
1647  rxvq->used->idx = rxvq->last_used_idx;
1648  vhost_user_log_dirty_ring (vui, rxvq, idx);
1649 
1650  /* interrupt (call) handling */
1651  if ((rxvq->callfd > -1) && !(rxvq->avail->flags & 1))
1652  {
1653  rxvq->n_since_last_int += n_packets - n_left;
1654 
1655  if (rxvq->n_since_last_int > vum->coalesce_frames)
1656  vhost_user_send_call (vm, rxvq);
1657  }
1658 
1659 done2:
1660 
1661  if (PREDICT_FALSE (vui->lockp != 0))
1662  *vui->lockp = 0;
1663 
1664  if (PREDICT_FALSE (n_left && error != VHOST_USER_TX_FUNC_ERROR_NONE))
1665  {
1666  vlib_error_count (vm, node->node_index, error, n_left);
1670  os_get_cpu_number (), vui->sw_if_index, n_left);
1671  }
1672 
1673  vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors);
1674  return frame->n_vectors;
1675 }
1676 
1677 static clib_error_t *
1679  u32 flags)
1680 {
1681  vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
1682  uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
1684  vhost_user_intf_t *vui =
1686 
1687  vui->admin_up = is_up;
1688 
1689  if (is_up)
1692 
1693  return /* no error */ 0;
1694 }
1695 
1696 /* *INDENT-OFF* */
1697 VNET_DEVICE_CLASS (vhost_user_dev_class,static) = {
1698  .name = "vhost-user",
1699  .tx_function = vhost_user_intfc_tx,
1700  .tx_function_n_errors = VHOST_USER_TX_FUNC_N_ERROR,
1701  .tx_function_error_strings = vhost_user_tx_func_error_strings,
1702  .format_device_name = format_vhost_user_interface_name,
1703  .name_renumber = vhost_user_name_renumber,
1704  .admin_up_down_function = vhost_user_interface_admin_up_down,
1705  .no_flatten_output_chains = 1,
1706 };
1707 
1710 /* *INDENT-ON* */
1711 
1712 static uword
1713 vhost_user_process (vlib_main_t * vm,
1715 {
1717  vhost_user_intf_t *vui;
1718  struct sockaddr_un sun;
1719  int sockfd;
1720  unix_file_t template = { 0 };
1721  f64 timeout = 3153600000.0 /* 100 years */ ;
1722  uword *event_data = 0;
1723 
1724  sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
1725  sun.sun_family = AF_UNIX;
1726  template.read_function = vhost_user_socket_read;
1727  template.error_function = vhost_user_socket_error;
1728 
1729 
1730  if (sockfd < 0)
1731  return 0;
1732 
1733  while (1)
1734  {
1736  vlib_process_get_events (vm, &event_data);
1737  vec_reset_length (event_data);
1738 
1739  timeout = 3.0;
1740 
1742  {
1743 
1744  if (vui->sock_is_server || !vui->active)
1745  continue;
1746 
1747  if (vui->unix_fd == -1)
1748  {
1749  /* try to connect */
1750 
1751  strncpy (sun.sun_path, (char *) vui->sock_filename,
1752  sizeof (sun.sun_path) - 1);
1753 
1754  if (connect
1755  (sockfd, (struct sockaddr *) &sun,
1756  sizeof (struct sockaddr_un)) == 0)
1757  {
1758  vui->sock_errno = 0;
1759  vui->unix_fd = sockfd;
1760  template.file_descriptor = sockfd;
1761  vui->unix_file_index = unix_file_add (&unix_main, &template);
1763  vui - vum->vhost_user_interfaces);
1764 
1765  sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
1766  if (sockfd < 0)
1767  return 0;
1768  }
1769  else
1770  {
1771  vui->sock_errno = errno;
1772  }
1773  }
1774  else
1775  {
1776  /* check if socket is alive */
1777  int error = 0;
1778  socklen_t len = sizeof (error);
1779  int retval =
1780  getsockopt (vui->unix_fd, SOL_SOCKET, SO_ERROR, &error, &len);
1781 
1782  if (retval)
1784  }
1785  }
1786  }
1787  return 0;
1788 }
1789 
1790 /* *INDENT-OFF* */
1792  .function = vhost_user_process,
1793  .type = VLIB_NODE_TYPE_PROCESS,
1794  .name = "vhost-user-process",
1795 };
1796 /* *INDENT-ON* */
1797 
1798 int
1800 {
1802  vhost_user_intf_t *vui;
1803  uword *p = NULL;
1804  int rv = 0;
1805 
1806  p = hash_get (vum->vhost_user_interface_index_by_sw_if_index, sw_if_index);
1807  if (p == 0)
1808  {
1809  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1810  }
1811  else
1812  {
1813  vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
1814  }
1815 
1816  // interface is inactive
1817  vui->active = 0;
1818  // disconnect interface sockets
1820  // add to inactive interface list
1822 
1823  // reset renumbered iface
1826 
1828  DBG_SOCK ("deleted (deactivated) vhost-user interface instance %d", p[0]);
1829 
1830  return rv;
1831 }
1832 
1833 // init server socket on specified sock_filename
1834 static int
1835 vhost_user_init_server_sock (const char *sock_filename, int *sockfd)
1836 {
1837  int rv = 0;
1838  struct sockaddr_un un = { };
1839  int fd;
1840  /* create listening socket */
1841  fd = socket (AF_UNIX, SOCK_STREAM, 0);
1842 
1843  if (fd < 0)
1844  {
1845  return VNET_API_ERROR_SYSCALL_ERROR_1;
1846  }
1847 
1848  un.sun_family = AF_UNIX;
1849  strncpy ((char *) un.sun_path, (char *) sock_filename,
1850  sizeof (un.sun_path) - 1);
1851 
1852  /* remove if exists */
1853  unlink ((char *) sock_filename);
1854 
1855  if (bind (fd, (struct sockaddr *) &un, sizeof (un)) == -1)
1856  {
1857  rv = VNET_API_ERROR_SYSCALL_ERROR_2;
1858  goto error;
1859  }
1860 
1861  if (listen (fd, 1) == -1)
1862  {
1863  rv = VNET_API_ERROR_SYSCALL_ERROR_3;
1864  goto error;
1865  }
1866 
1867  unix_file_t template = { 0 };
1869  template.file_descriptor = fd;
1870  unix_file_add (&unix_main, &template);
1871  *sockfd = fd;
1872  return rv;
1873 
1874 error:
1875  close (fd);
1876  return rv;
1877 }
1878 
1879 // get new vhost_user_intf_t from inactive interfaces or create new one
1880 static vhost_user_intf_t *
1882 {
1884  vhost_user_intf_t *vui = NULL;
1885  int inactive_cnt = vec_len (vum->vhost_user_inactive_interfaces_index);
1886  // if there are any inactive ifaces
1887  if (inactive_cnt > 0)
1888  {
1889  // take last
1890  u32 vui_idx =
1891  vum->vhost_user_inactive_interfaces_index[inactive_cnt - 1];
1892  if (vec_len (vum->vhost_user_interfaces) > vui_idx)
1893  {
1894  vui = vec_elt_at_index (vum->vhost_user_interfaces, vui_idx);
1895  DBG_SOCK ("reusing inactive vhost-user interface index %d",
1896  vui_idx);
1897  }
1898  // "remove" from inactive list
1899  _vec_len (vum->vhost_user_inactive_interfaces_index) -= 1;
1900  }
1901 
1902  // vui was not retrieved from inactive ifaces - create new
1903  if (!vui)
1904  vec_add2 (vum->vhost_user_interfaces, vui, 1);
1905  return vui;
1906 }
1907 
1908 // create ethernet interface for vhost user intf
1909 static void
1911  vhost_user_intf_t * vui, u8 * hwaddress)
1912 {
1914  u8 hwaddr[6];
1915  clib_error_t *error;
1916 
1917  /* create hw and sw interface */
1918  if (hwaddress)
1919  {
1920  clib_memcpy (hwaddr, hwaddress, 6);
1921  }
1922  else
1923  {
1924  f64 now = vlib_time_now (vm);
1925  u32 rnd;
1926  rnd = (u32) (now * 1e6);
1927  rnd = random_u32 (&rnd);
1928 
1929  clib_memcpy (hwaddr + 2, &rnd, sizeof (rnd));
1930  hwaddr[0] = 2;
1931  hwaddr[1] = 0xfe;
1932  }
1933 
1935  (vnm,
1936  vhost_user_dev_class.index,
1937  vui - vum->vhost_user_interfaces /* device instance */ ,
1938  hwaddr /* ethernet address */ ,
1939  &vui->hw_if_index, 0 /* flag change */ );
1940  if (error)
1941  clib_error_report (error);
1942 
1945 }
1946 
1947 // initialize vui with specified attributes
1948 static void
1950  vhost_user_intf_t * vui, int sockfd,
1951  const char *sock_filename,
1952  u8 is_server, u64 feature_mask, u32 * sw_if_index)
1953 {
1954  vnet_sw_interface_t *sw;
1955  sw = vnet_get_hw_sw_interface (vnm, vui->hw_if_index);
1957  int q;
1958 
1959  vui->unix_fd = sockfd;
1960  vui->sw_if_index = sw->sw_if_index;
1961  vui->num_vrings = 2;
1962  vui->sock_is_server = is_server;
1963  strncpy (vui->sock_filename, sock_filename,
1964  ARRAY_LEN (vui->sock_filename) - 1);
1965  vui->sock_errno = 0;
1966  vui->is_up = 0;
1967  vui->feature_mask = feature_mask;
1968  vui->active = 1;
1969  vui->unix_file_index = ~0;
1970  vui->log_base_addr = 0;
1971 
1972  for (q = 0; q < 2; q++)
1973  {
1974  vui->vrings[q].enabled = 0;
1975  vui->vrings[q].callfd = -1;
1976  vui->vrings[q].kickfd = -1;
1977  }
1978 
1980 
1981  if (sw_if_index)
1982  *sw_if_index = vui->sw_if_index;
1983 
1984  if (tm->n_vlib_mains > 1)
1985  {
1988  memset ((void *) vui->lockp, 0, CLIB_CACHE_LINE_BYTES);
1989  }
1990 }
1991 
1992 // register vui and start polling on it
1993 static void
1995 {
1997  int cpu_index;
1999 
2001  vui - vum->vhost_user_interfaces);
2003  vui - vum->vhost_user_interfaces);
2004 
2005  /* start polling */
2006  cpu_index = vum->input_cpu_first_index +
2007  (vui - vum->vhost_user_interfaces) % vum->input_cpu_count;
2008 
2009  if (tm->n_vlib_mains == 1)
2011  VLIB_NODE_STATE_POLLING);
2012  else
2014  VLIB_NODE_STATE_POLLING);
2015 
2016  /* tell process to start polling for sockets */
2018 }
2019 
2020 int
2022  const char *sock_filename,
2023  u8 is_server,
2024  u32 * sw_if_index,
2025  u64 feature_mask,
2026  u8 renumber, u32 custom_dev_instance, u8 * hwaddr)
2027 {
2028  vhost_user_intf_t *vui = NULL;
2029  u32 sw_if_idx = ~0;
2030  int sockfd = -1;
2031  int rv = 0;
2032 
2033  if (is_server)
2034  {
2035  if ((rv = vhost_user_init_server_sock (sock_filename, &sockfd)) != 0)
2036  {
2037  return rv;
2038  }
2039  }
2040 
2041  vui = vhost_user_vui_new ();
2042  ASSERT (vui != NULL);
2043 
2044  vhost_user_create_ethernet (vnm, vm, vui, hwaddr);
2045  vhost_user_vui_init (vnm, vui, sockfd, sock_filename, is_server,
2046  feature_mask, &sw_if_idx);
2047 
2048  if (renumber)
2049  {
2050  vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
2051  }
2052 
2053  vhost_user_vui_register (vm, vui);
2054 
2055  if (sw_if_index)
2056  *sw_if_index = sw_if_idx;
2057 
2058  return rv;
2059 }
2060 
2061 int
2063  const char *sock_filename,
2064  u8 is_server,
2065  u32 sw_if_index,
2066  u64 feature_mask, u8 renumber, u32 custom_dev_instance)
2067 {
2069  vhost_user_intf_t *vui = NULL;
2070  u32 sw_if_idx = ~0;
2071  int sockfd = -1;
2072  int rv = 0;
2073  uword *p = NULL;
2074 
2075  p = hash_get (vum->vhost_user_interface_index_by_sw_if_index, sw_if_index);
2076  if (p == 0)
2077  {
2078  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
2079  }
2080  else
2081  {
2082  vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
2083  }
2084 
2085  // interface is inactive
2086  vui->active = 0;
2087  // disconnect interface sockets
2089 
2090  if (is_server)
2091  {
2092  if ((rv = vhost_user_init_server_sock (sock_filename, &sockfd)) != 0)
2093  {
2094  return rv;
2095  }
2096  }
2097 
2098  vhost_user_vui_init (vnm, vui, sockfd, sock_filename, is_server,
2099  feature_mask, &sw_if_idx);
2100 
2101  if (renumber)
2102  {
2103  vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
2104  }
2105 
2106  vhost_user_vui_register (vm, vui);
2107 
2108  return rv;
2109 }
2110 
2111 clib_error_t *
2113  unformat_input_t * input,
2114  vlib_cli_command_t * cmd)
2115 {
2116  unformat_input_t _line_input, *line_input = &_line_input;
2117  u8 *sock_filename = NULL;
2118  u32 sw_if_index;
2119  u8 is_server = 0;
2120  u64 feature_mask = (u64) ~ 0;
2121  u8 renumber = 0;
2122  u32 custom_dev_instance = ~0;
2123  u8 hwaddr[6];
2124  u8 *hw = NULL;
2125 
2126  /* Get a line of input. */
2127  if (!unformat_user (input, unformat_line_input, line_input))
2128  return 0;
2129 
2130  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2131  {
2132  if (unformat (line_input, "socket %s", &sock_filename))
2133  ;
2134  else if (unformat (line_input, "server"))
2135  is_server = 1;
2136  else if (unformat (line_input, "feature-mask 0x%llx", &feature_mask))
2137  ;
2138  else
2139  if (unformat
2140  (line_input, "hwaddr %U", unformat_ethernet_address, hwaddr))
2141  hw = hwaddr;
2142  else if (unformat (line_input, "renumber %d", &custom_dev_instance))
2143  {
2144  renumber = 1;
2145  }
2146  else
2147  return clib_error_return (0, "unknown input `%U'",
2148  format_unformat_error, input);
2149  }
2150  unformat_free (line_input);
2151 
2152  vnet_main_t *vnm = vnet_get_main ();
2153 
2154  int rv;
2155  if ((rv = vhost_user_create_if (vnm, vm, (char *) sock_filename,
2156  is_server, &sw_if_index, feature_mask,
2157  renumber, custom_dev_instance, hw)))
2158  {
2159  vec_free (sock_filename);
2160  return clib_error_return (0, "vhost_user_create_if returned %d", rv);
2161  }
2162 
2163  vec_free (sock_filename);
2165  sw_if_index);
2166  return 0;
2167 }
2168 
2169 clib_error_t *
2171  unformat_input_t * input,
2172  vlib_cli_command_t * cmd)
2173 {
2174  unformat_input_t _line_input, *line_input = &_line_input;
2175  u32 sw_if_index = ~0;
2176 
2177  /* Get a line of input. */
2178  if (!unformat_user (input, unformat_line_input, line_input))
2179  return 0;
2180 
2181  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2182  {
2183  if (unformat (line_input, "sw_if_index %d", &sw_if_index))
2184  ;
2185  else
2186  return clib_error_return (0, "unknown input `%U'",
2187  format_unformat_error, input);
2188  }
2189  unformat_free (line_input);
2190 
2191  vnet_main_t *vnm = vnet_get_main ();
2192 
2193  vhost_user_delete_if (vnm, vm, sw_if_index);
2194 
2195  return 0;
2196 }
2197 
2198 int
2200  vhost_user_intf_details_t ** out_vuids)
2201 {
2202  int rv = 0;
2204  vhost_user_intf_t *vui;
2205  vhost_user_intf_details_t *r_vuids = NULL;
2207  u32 *hw_if_indices = 0;
2209  u8 *s = NULL;
2210  int i;
2211 
2212  if (!out_vuids)
2213  return -1;
2214 
2216  {
2217  if (vui->active)
2218  vec_add1 (hw_if_indices, vui->hw_if_index);
2219  }
2220 
2221  for (i = 0; i < vec_len (hw_if_indices); i++)
2222  {
2223  hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
2225 
2226  vec_add2 (r_vuids, vuid, 1);
2227  vuid->sw_if_index = vui->sw_if_index;
2228  vuid->virtio_net_hdr_sz = vui->virtio_net_hdr_sz;
2229  vuid->features = vui->features;
2230  vuid->is_server = vui->sock_is_server;
2231  vuid->num_regions = vui->nregions;
2232  vuid->sock_errno = vui->sock_errno;
2233  strncpy ((char *) vuid->sock_filename, (char *) vui->sock_filename,
2234  ARRAY_LEN (vuid->sock_filename) - 1);
2235 
2236  s = format (s, "%v%c", hi->name, 0);
2237 
2238  strncpy ((char *) vuid->if_name, (char *) s,
2239  ARRAY_LEN (vuid->if_name) - 1);
2240  _vec_len (s) = 0;
2241  }
2242 
2243  vec_free (s);
2244  vec_free (hw_if_indices);
2245 
2246  *out_vuids = r_vuids;
2247 
2248  return rv;
2249 }
2250 
2251 clib_error_t *
2253  unformat_input_t * input,
2254  vlib_cli_command_t * cmd)
2255 {
2256  clib_error_t *error = 0;
2257  vnet_main_t *vnm = vnet_get_main ();
2259  vhost_user_intf_t *vui;
2260  u32 hw_if_index, *hw_if_indices = 0;
2262  int i, j, q;
2263  int show_descr = 0;
2264  struct feat_struct
2265  {
2266  u8 bit;
2267  char *str;
2268  };
2269  struct feat_struct *feat_entry;
2270 
2271  static struct feat_struct feat_array[] = {
2272 #define _(s,b) { .str = #s, .bit = b, },
2274 #undef _
2275  {.str = NULL}
2276  };
2277 
2278  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2279  {
2280  if (unformat
2281  (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
2282  {
2283  vec_add1 (hw_if_indices, hw_if_index);
2284  vlib_cli_output (vm, "add %d", hw_if_index);
2285  }
2286  else if (unformat (input, "descriptors") || unformat (input, "desc"))
2287  show_descr = 1;
2288  else
2289  {
2290  error = clib_error_return (0, "unknown input `%U'",
2291  format_unformat_error, input);
2292  goto done;
2293  }
2294  }
2295  if (vec_len (hw_if_indices) == 0)
2296  {
2298  {
2299  if (vui->active)
2300  vec_add1 (hw_if_indices, vui->hw_if_index);
2301  }
2302  }
2303  vlib_cli_output (vm, "Virtio vhost-user interfaces");
2304  vlib_cli_output (vm, "Global:\n coalesce frames %d time %e\n\n",
2305  vum->coalesce_frames, vum->coalesce_time);
2306 
2307  for (i = 0; i < vec_len (hw_if_indices); i++)
2308  {
2309  hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
2311  vlib_cli_output (vm, "Interface: %s (ifindex %d)",
2312  hi->name, hw_if_indices[i]);
2313 
2314  vlib_cli_output (vm, "virtio_net_hdr_sz %d\n features (0x%llx): \n",
2315  vui->virtio_net_hdr_sz, vui->features);
2316 
2317  feat_entry = (struct feat_struct *) &feat_array;
2318  while (feat_entry->str)
2319  {
2320  if (vui->features & (1 << feat_entry->bit))
2321  vlib_cli_output (vm, " %s (%d)", feat_entry->str,
2322  feat_entry->bit);
2323  feat_entry++;
2324  }
2325 
2326  vlib_cli_output (vm, "\n");
2327 
2328 
2329  vlib_cli_output (vm, " socket filename %s type %s errno \"%s\"\n\n",
2330  vui->sock_filename,
2331  vui->sock_is_server ? "server" : "client",
2332  strerror (vui->sock_errno));
2333 
2334  vlib_cli_output (vm, " Memory regions (total %d)\n", vui->nregions);
2335 
2336  if (vui->nregions)
2337  {
2338  vlib_cli_output (vm,
2339  " region fd guest_phys_addr memory_size userspace_addr mmap_offset mmap_addr\n");
2340  vlib_cli_output (vm,
2341  " ====== ===== ================== ================== ================== ================== ==================\n");
2342  }
2343  for (j = 0; j < vui->nregions; j++)
2344  {
2345  vlib_cli_output (vm,
2346  " %d %-5d 0x%016lx 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
2347  j, vui->region_mmap_fd[j],
2348  vui->regions[j].guest_phys_addr,
2349  vui->regions[j].memory_size,
2350  vui->regions[j].userspace_addr,
2351  vui->regions[j].mmap_offset,
2353  }
2354  for (q = 0; q < vui->num_vrings; q++)
2355  {
2356  vlib_cli_output (vm, "\n Virtqueue %d\n", q);
2357 
2358  vlib_cli_output (vm,
2359  " qsz %d last_avail_idx %d last_used_idx %d\n",
2360  vui->vrings[q].qsz, vui->vrings[q].last_avail_idx,
2361  vui->vrings[q].last_used_idx);
2362 
2363  if (vui->vrings[q].avail && vui->vrings[q].used)
2364  vlib_cli_output (vm,
2365  " avail.flags %x avail.idx %d used.flags %x used.idx %d\n",
2366  vui->vrings[q].avail->flags,
2367  vui->vrings[q].avail->idx,
2368  vui->vrings[q].used->flags,
2369  vui->vrings[q].used->idx);
2370 
2371  vlib_cli_output (vm, " kickfd %d callfd %d errfd %d\n",
2372  vui->vrings[q].kickfd,
2373  vui->vrings[q].callfd, vui->vrings[q].errfd);
2374 
2375  if (show_descr)
2376  {
2377  vlib_cli_output (vm, "\n descriptor table:\n");
2378  vlib_cli_output (vm,
2379  " id addr len flags next user_addr\n");
2380  vlib_cli_output (vm,
2381  " ===== ================== ===== ====== ===== ==================\n");
2382  for (j = 0; j < vui->vrings[q].qsz; j++)
2383  {
2384  u32 mem_hint = 0;
2385  vlib_cli_output (vm,
2386  " %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
2387  j, vui->vrings[q].desc[j].addr,
2388  vui->vrings[q].desc[j].len,
2389  vui->vrings[q].desc[j].flags,
2390  vui->vrings[q].desc[j].next,
2392  (vui,
2393  vui->vrings[q].desc[j].
2394  addr, &mem_hint)));
2395  }
2396  }
2397  }
2398  vlib_cli_output (vm, "\n");
2399  }
2400 done:
2401  vec_free (hw_if_indices);
2402  return error;
2403 }
2404 
2405 /*
2406  * CLI functions
2407  */
2408 
2409 /* *INDENT-OFF* */
2410 VLIB_CLI_COMMAND (vhost_user_connect_command, static) = {
2411  .path = "create vhost-user",
2412  .short_help = "create vhost-user socket <socket-filename> [server] [feature-mask <hex>] [renumber <dev_instance>]",
2413  .function = vhost_user_connect_command_fn,
2414 };
2415 
2416 VLIB_CLI_COMMAND (vhost_user_delete_command, static) = {
2417  .path = "delete vhost-user",
2418  .short_help = "delete vhost-user sw_if_index <nn>",
2419  .function = vhost_user_delete_command_fn,
2420 };
2421 
2422 VLIB_CLI_COMMAND (show_vhost_user_command, static) = {
2423  .path = "show vhost-user",
2424  .short_help = "show vhost-user interface",
2425  .function = show_vhost_user_command_fn,
2426 };
2427 /* *INDENT-ON* */
2428 
2429 static clib_error_t *
2431 {
2433 
2434  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2435  {
2436  if (unformat (input, "coalesce-frames %d", &vum->coalesce_frames))
2437  ;
2438  else if (unformat (input, "coalesce-time %f", &vum->coalesce_time))
2439  ;
2440  else if (unformat (input, "dont-dump-memory"))
2441  vum->dont_dump_vhost_user_memory = 1;
2442  else
2443  return clib_error_return (0, "unknown input `%U'",
2444  format_unformat_error, input);
2445  }
2446 
2447  return 0;
2448 }
2449 
2450 /* vhost-user { ... } configuration. */
2451 VLIB_CONFIG_FUNCTION (vhost_user_config, "vhost-user");
2452 
2453 void
2455 {
2457  vhost_user_intf_t *vui;
2458 
2459  if (vum->dont_dump_vhost_user_memory)
2460  {
2462  {
2463  unmap_all_mem_regions (vui);
2464  }
2465  }
2466 }
2467 
2468 /*
2469  * fd.io coding-style-patch-verification: ON
2470  *
2471  * Local Variables:
2472  * eval: (c-set-style "gnu")
2473  * End:
2474  */
unformat_function_t unformat_vnet_hw_interface
static clib_error_t * vhost_user_init(vlib_main_t *vm)
Definition: vhost-user.c:872
unix_file_t * file_pool
Definition: unix.h:89
static void vhost_user_vui_init(vnet_main_t *vnm, vhost_user_intf_t *vui, int sockfd, const char *sock_filename, u8 is_server, u64 feature_mask, u32 *sw_if_index)
Definition: vhost-user.c:1949
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:457
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 cpu_index, u32 index, u32 increment)
Increment a simple counter.
Definition: counter.h:78
vmrglw vmrglh hi
static void vhost_user_if_disconnect(vhost_user_intf_t *vui)
Definition: vhost-user.c:293
#define hash_set(h, key, value)
Definition: hash.h:254
static uword vhost_user_intfc_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: vhost-user.c:1389
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
vring_desc_t * desc
Definition: vhost-user.h:195
#define CLIB_UNUSED(x)
Definition: clib.h:79
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
clib_error_t * vnet_hw_interface_set_flags(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: interface.c:522
static u32 vlib_get_trace_count(vlib_main_t *vm, vlib_node_runtime_t *rt)
Definition: trace_funcs.h:143
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:684
unix_file_function_t * read_function
Definition: unix.h:62
#define hash_unset(h, key)
Definition: hash.h:260
static void vhost_user_create_ethernet(vnet_main_t *vnm, vlib_main_t *vm, vhost_user_intf_t *vui, u8 *hwaddress)
Definition: vhost-user.c:1910
u8 runtime_data[0]
Definition: node.h:472
void ethernet_delete_interface(vnet_main_t *vnm, u32 hw_if_index)
Definition: interface.c:254
static clib_error_t * vhost_user_socket_error(unix_file_t *uf)
Definition: vhost-user.c:811
u64 region_guest_addr_hi[VHOST_MEMORY_MAX_NREGIONS]
Definition: vhost-user.h:232
uword * vhost_user_interface_index_by_sock_fd
Definition: vhost-user.h:250
vnet_interface_main_t interface_main
Definition: vnet.h:72
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
Definition: buffer.h:402
static vhost_user_intf_t * vhost_user_vui_new()
Definition: vhost-user.c:1881
#define PREDICT_TRUE(x)
Definition: clib.h:98
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:55
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
#define NULL
Definition: clib.h:55
u32 vlib_buffer_alloc_from_free_list(vlib_main_t *vm, u32 *buffers, u32 n_buffers, u32 free_list_index)
Allocate buffers from specific freelist into supplied array.
Definition: dpdk_buffer.c:655
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
vring_avail_t * avail
Definition: vhost-user.h:196
static uword vhost_user_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *f)
Definition: vhost-user.c:1344
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
int vnet_interface_name_renumber(u32 sw_if_index, u32 new_show_dev_instance)
Definition: interface.c:1177
static u32 vhost_user_if_input(vlib_main_t *vm, vhost_user_main_t *vum, vhost_user_intf_t *vui, vlib_node_runtime_t *node)
Definition: vhost-user.c:1009
static u8 * format_vhost_user_input_trace(u8 *s, va_list *va)
Definition: vhost-user.c:932
struct _vlib_node_registration vlib_node_registration_t
#define VHOST_USER_MSG_HDR_SZ
Definition: vhost-user.h:20
static clib_error_t * vhost_user_interface_admin_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: vhost-user.c:1678
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:521
static void vhost_user_vui_register(vlib_main_t *vm, vhost_user_intf_t *vui)
Definition: vhost-user.c:1994
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
clib_error_t * show_vhost_user_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vhost-user.c:2252
#define clib_error_report(e)
Definition: error.h:125
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:348
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:407
vlib_error_t * errors
Definition: node.h:419
static char * vhost_user_input_func_error_strings[]
Definition: vhost-user.c:103
static char * vhost_user_tx_func_error_strings[]
Definition: vhost-user.c:81
vring_used_t * used
Definition: vhost-user.h:197
#define vec_alloc(V, N)
Allocate space for N more elements (no header, unspecified alignment)
Definition: vec.h:239
format_function_t format_vnet_sw_if_index_name
static uword unix_file_add(unix_main_t *um, unix_file_t *template)
Definition: unix.h:136
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static int vhost_user_name_renumber(vnet_hw_interface_t *hi, u32 new_dev_instance)
Definition: vhost-user.c:137
static vnet_sw_interface_t * vnet_get_hw_sw_interface(vnet_main_t *vnm, u32 hw_if_index)
static void vlib_trace_buffer(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, vlib_buffer_t *b, int follow_chain)
Definition: trace_funcs.h:104
#define VHOST_VRING_F_LOG
Definition: vhost-user.h:32
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
vhost_user_vring_t vrings[2]
Definition: vhost-user.h:234
VNET_DEVICE_CLASS(vhost_user_dev_class, static)
static u8 * format_vhost_user_interface_name(u8 *s, va_list *args)
Definition: vhost-user.c:120
#define static_always_inline
Definition: clib.h:85
#define vlib_prefetch_buffer_with_index(vm, bi, type)
Prefetch buffer metadata by buffer index The first 64 bytes of buffer contains most header informatio...
Definition: buffer_funcs.h:182
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
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:527
static clib_error_t * ip4_init(vlib_main_t *vm)
Definition: ip4_input.c:431
#define always_inline
Definition: clib.h:84
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:190
vlib_combined_counter_main_t * combined_sw_if_counters
Definition: interface.h:577
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:113
void * log_base_addr
Definition: vhost-user.h:239
static_always_inline void vnet_feature_device_input_redirect_x1(vlib_node_runtime_t *node, u32 sw_if_index, u32 *next0, vlib_buffer_t *b0, u16 buffer_advanced0)
Definition: feature.h:158
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
void vhost_user_rx_trace(vlib_main_t *vm, vlib_node_runtime_t *node, vhost_user_intf_t *vui, i16 virtqueue)
Definition: vhost-user.c:961
u8 pre_data[VLIB_BUFFER_PRE_DATA_SIZE]
Space for inserting data before buffer start.
Definition: buffer.h:146
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
vhost_user_tx_func_error_t
Definition: vhost-user.c:73
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
static void unmap_all_mem_regions(vhost_user_intf_t *vui)
Definition: vhost-user.c:247
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
VLIB_DEVICE_TX_FUNCTION_MULTIARCH(vhost_user_dev_class, vhost_user_intfc_tx)
Definition: vhost-user.c:1708
vhost_user_input_func_error_t
Definition: vhost-user.c:95
#define vlib_call_init_function(vm, x)
Definition: init.h:161
static clib_error_t * vhost_user_socket_read(unix_file_t *uf)
Definition: vhost-user.c:369
static uword pointer_to_uword(const void *p)
Definition: types.h:131
#define VLIB_BUFFER_NEXT_PRESENT
Definition: buffer.h:97
vlib_main_t ** vlib_mains
Definition: dpdk_buffer.c:157
#define VLIB_BUFFER_PRE_DATA_SIZE
Definition: buffer.h:52
static void unix_file_del(unix_main_t *um, unix_file_t *f)
Definition: unix.h:146
#define hash_get(h, key)
Definition: hash.h:248
format_function_t format_vnet_sw_interface_name
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
static uword format_get_indent(u8 *s)
Definition: format.h:72
u32 file_descriptor
Definition: unix.h:52
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:931
int vhost_user_delete_if(vnet_main_t *vnm, vlib_main_t *vm, u32 sw_if_index)
Definition: vhost-user.c:1799
static void * map_user_mem(vhost_user_intf_t *vui, uword addr)
Definition: vhost-user.c:222
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
#define VIRTQ_DESC_F_INDIRECT
Definition: vhost-user.h:27
#define clib_error_return_unix(e, args...)
Definition: error.h:114
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:118
#define vhost_user_log_dirty_ring(vui, vq, member)
Definition: vhost-user.c:362
static vlib_node_registration_t vhost_user_process_node
(constructor) VLIB_REGISTER_NODE (vhost_user_process_node)
Definition: vhost-user.c:1791
void vhost_user_unmap_all(void)
Definition: vhost-user.c:2454
char sock_filename[256]
Definition: vhost-user.h:218
vnet_main_t vnet_main
Definition: misc.c:43
#define VNET_DEVICE_INPUT_NEXT_NODES
Definition: devices.h:32
#define VLIB_FRAME_SIZE
Definition: node.h:328
vlib_simple_counter_main_t * sw_if_counters
Definition: interface.h:576
u32 region_mmap_fd[VHOST_MEMORY_MAX_NREGIONS]
Definition: vhost-user.h:233
static void vhost_user_send_call(vlib_main_t *vm, vhost_user_vring_t *vq)
Definition: vhost-user.c:996
vhost_user_memory_region_t regions[VHOST_MEMORY_MAX_NREGIONS]
Definition: vhost-user.h:229
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:216
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:350
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
int vhost_user_dump_ifs(vnet_main_t *vnm, vlib_main_t *vm, vhost_user_intf_details_t **out_vuids)
Definition: vhost-user.c:2199
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:121
static void vhost_user_log_dirty_pages(vhost_user_intf_t *vui, u64 addr, u64 len)
Definition: vhost-user.c:340
static void vlib_buffer_chain_init(vlib_buffer_t *first)
Definition: buffer_funcs.h:432
static clib_error_t * vhost_user_exit(vlib_main_t *vm)
Definition: vhost-user.c:914
u8 * format_ethernet_header_with_length(u8 *s, va_list *args)
Definition: format.c:115
u32 * show_dev_instance_by_real_dev_instance
Definition: vhost-user.h:252
int vhost_user_create_if(vnet_main_t *vnm, vlib_main_t *vm, const char *sock_filename, u8 is_server, u32 *sw_if_index, u64 feature_mask, u8 renumber, u32 custom_dev_instance, u8 *hwaddr)
Definition: vhost-user.c:2021
vhost_user_intf_t * vhost_user_interfaces
Definition: vhost-user.h:247
u16 n_vectors
Definition: node.h:344
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
#define VLIB_MAIN_LOOP_EXIT_FUNCTION(x)
Definition: init.h:115
int vhost_user_modify_if(vnet_main_t *vnm, vlib_main_t *vm, const char *sock_filename, u8 is_server, u32 sw_if_index, u64 feature_mask, u8 renumber, u32 custom_dev_instance)
Definition: vhost-user.c:2062
#define clib_memcpy(a, b, c)
Definition: string.h:64
#define VHOST_MEMORY_MAX_NREGIONS
Definition: vhost-user.h:19
static_always_inline void * map_guest_mem(vhost_user_intf_t *vui, uword addr, u32 *hint)
Definition: vhost-user.c:154
#define ARRAY_LEN(x)
Definition: clib.h:59
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD
Definition: vhost-user.h:31
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:306
u32 * vhost_user_inactive_interfaces_index
Definition: vhost-user.h:248
#define hash_create(elts, value_bytes)
Definition: hash.h:658
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:490
u32 max_l3_packet_bytes[VLIB_N_RX_TX]
Definition: interface.h:420
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:245
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 cpu_index, u32 index, u32 packet_increment, u32 byte_increment)
Increment a combined counter.
Definition: counter.h:241
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define vnet_buffer(b)
Definition: buffer.h:333
void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: dpdk_buffer.c:766
static long get_huge_page_size(int fd)
Definition: vhost-user.c:239
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:117
clib_error_t * vhost_user_delete_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vhost-user.c:2170
u16 vlib_buffer_chain_append_data_with_alloc(vlib_main_t *vm, u32 free_list_index, vlib_buffer_t *first, vlib_buffer_t **last, void *data, u16 data_len)
Definition: dpdk_buffer.c:908
#define VIRTQ_DESC_F_NEXT
Definition: vhost-user.h:26
clib_error_t * ethernet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u8 *address, u32 *hw_if_index_return, ethernet_flag_change_function_t flag_change)
Definition: interface.c:205
static void * vlib_frame_args(vlib_frame_t *f)
Get pointer to frame scalar data.
Definition: node_funcs.h:270
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
Definition: node_funcs.h:146
uword * thread_registrations_by_name
Definition: threads.h:285
unix_main_t unix_main
Definition: main.c:57
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
volatile u32 * lockp
Definition: vhost-user.h:212
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:112
#define foreach_vhost_user_tx_func_error
Definition: vhost-user.c:65
void * region_mmap_addr[VHOST_MEMORY_MAX_NREGIONS]
Definition: vhost-user.h:230
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
static clib_error_t * vhost_user_socksvr_accept_ready(unix_file_t *uf)
Definition: vhost-user.c:832
static clib_error_t * vhost_user_config(vlib_main_t *vm, unformat_input_t *input)
Definition: vhost-user.c:2430
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
static int vhost_user_init_server_sock(const char *sock_filename, int *sockfd)
Definition: vhost-user.c:1835
#define VHOST_NET_VRING_IDX_RX
Definition: vhost-user.h:22
uword * vhost_user_interface_index_by_listener_fd
Definition: vhost-user.h:249
Definition: unix.h:49
vlib_node_registration_t vhost_user_input_node
(constructor) VLIB_REGISTER_NODE (vhost_user_input_node)
Definition: vhost-user.c:63
#define DBG_SOCK(args...)
Definition: vhost-user.c:54
#define hash_get_mem(h, key)
Definition: hash.h:268
struct clib_bihash_value offset
template key/value backing page structure
static vhost_user_main_t vhost_user_main
Definition: vhost-user.c:110
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:117
short i16
Definition: types.h:46
#define DBG_VQ(args...)
Definition: vhost-user.c:60
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
#define VHOST_NET_VRING_IDX_TX
Definition: vhost-user.h:23
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
u64 region_guest_addr_lo[VHOST_MEMORY_MAX_NREGIONS]
Definition: vhost-user.h:231
static clib_error_t * vhost_user_callfd_read_ready(unix_file_t *uf)
Definition: vhost-user.c:284
#define vec_foreach(var, vec)
Vector iterator.
#define foreach_vhost_user_input_func_error
Definition: vhost-user.c:87
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:101
vhost_vring_addr_t addr
Definition: vhost-user.h:81
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
static void vlib_set_trace_count(vlib_main_t *vm, vlib_node_runtime_t *rt, u32 count)
Definition: trace_funcs.h:159
u32 flags
Definition: vhost-user.h:75
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:445
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
uword * vhost_user_interface_index_by_sw_if_index
Definition: vhost-user.h:251
unformat_function_t unformat_line_input
Definition: format.h:281
#define VHOST_LOG_PAGE
Definition: vhost-user.c:338
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
clib_error_t * vhost_user_connect_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vhost-user.c:2112
VNET_HW_INTERFACE_CLASS(vhost_interface_class, static)
Definition: defs.h:46
int dont_dump_vhost_user_memory
Definition: vhost-user.h:255