Fix coverity issues in vhost-user code, fixes VPP-189
[vpp.git] / vnet / vnet / devices / virtio / vhost-user.c
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
40 #include <vnet/devices/virtio/vhost-user.h>
41
42 #define VHOST_USER_DEBUG_SOCKET 0
43 #define VHOST_USER_DEBUG_VQ 0
44
45 /* Set to get virtio_net_hdr in buffer pre-data
46    details will be shown in  packet trace */
47 #define VHOST_USER_COPY_TX_HDR 0
48
49 #if VHOST_USER_DEBUG_SOCKET == 1
50 #define DBG_SOCK(args...) clib_warning(args);
51 #else
52 #define DBG_SOCK(args...)
53 #endif
54
55 #if VHOST_USER_DEBUG_VQ == 1
56 #define DBG_VQ(args...) clib_warning(args);
57 #else
58 #define DBG_VQ(args...)
59 #endif
60
61 vlib_node_registration_t vhost_user_input_node;
62
63 #define foreach_vhost_user_tx_func_error      \
64   _(NONE, "no error")  \
65   _(NOT_READY, "vhost user state error")  \
66   _(PKT_DROP_NOBUF, "tx packet drops (no available descriptors)")  \
67   _(MMAP_FAIL, "mmap failure")
68
69 typedef enum {
70 #define _(f,s) VHOST_USER_TX_FUNC_ERROR_##f,
71   foreach_vhost_user_tx_func_error
72 #undef _
73   VHOST_USER_TX_FUNC_N_ERROR,
74 } vhost_user_tx_func_error_t;
75
76 static char * vhost_user_tx_func_error_strings[] = {
77 #define _(n,s) s,
78     foreach_vhost_user_tx_func_error
79 #undef _
80 };
81
82 #define foreach_vhost_user_input_func_error      \
83   _(NO_ERROR, "no error")  \
84   _(NO_BUFFER, "no available buffer")  \
85   _(MMAP_FAIL, "mmap failure")  \
86   _(UNDERSIZED_FRAME, "undersized ethernet frame received (< 14 bytes)")
87
88 typedef enum {
89 #define _(f,s) VHOST_USER_INPUT_FUNC_ERROR_##f,
90   foreach_vhost_user_input_func_error
91 #undef _
92   VHOST_USER_INPUT_FUNC_N_ERROR,
93 } vhost_user_input_func_error_t;
94
95 static char * vhost_user_input_func_error_strings[] = {
96 #define _(n,s) s,
97     foreach_vhost_user_input_func_error
98 #undef _
99 };
100
101 static vhost_user_main_t vhost_user_main = {
102   .mtu_bytes = 1518,
103 };
104
105 VNET_HW_INTERFACE_CLASS (vhost_interface_class, static) = {
106   .name = "vhost-user",
107 };
108
109 static u8 * format_vhost_user_interface_name (u8 * s, va_list * args)
110 {
111   u32 i = va_arg (*args, u32);
112   u32 show_dev_instance = ~0;
113   vhost_user_main_t * vum = &vhost_user_main;
114
115   if (i < vec_len (vum->show_dev_instance_by_real_dev_instance))
116     show_dev_instance = vum->show_dev_instance_by_real_dev_instance[i];
117
118   if (show_dev_instance != ~0)
119     i = show_dev_instance;
120
121   s = format (s, "VirtualEthernet0/0/%d", i);
122   return s;
123 }
124
125 static int vhost_user_name_renumber (vnet_hw_interface_t * hi,
126                                      u32 new_dev_instance)
127 {
128   vhost_user_main_t * vum = &vhost_user_main;
129
130   vec_validate_init_empty (vum->show_dev_instance_by_real_dev_instance,
131                            hi->dev_instance, ~0);
132
133   vum->show_dev_instance_by_real_dev_instance [hi->dev_instance] =
134     new_dev_instance;
135
136   DBG_SOCK("renumbered vhost-user interface dev_instance %d to %d",
137            hi->dev_instance, new_dev_instance);
138
139   return 0;
140 }
141
142
143 static inline void * map_guest_mem(vhost_user_intf_t * vui, uword addr)
144 {
145   int i;
146   for (i=0; i<vui->nregions; i++) {
147     if ((vui->regions[i].guest_phys_addr <= addr) &&
148        ((vui->regions[i].guest_phys_addr + vui->regions[i].memory_size) > addr)) {
149          return (void *) (vui->region_mmap_addr[i] + addr - vui->regions[i].guest_phys_addr);
150        }
151   }
152   DBG_VQ("failed to map guest mem addr %llx", addr);
153   return 0;
154 }
155
156 static inline void * map_user_mem(vhost_user_intf_t * vui, uword addr)
157 {
158   int i;
159   for (i=0; i<vui->nregions; i++) {
160     if ((vui->regions[i].userspace_addr <= addr) &&
161        ((vui->regions[i].userspace_addr + vui->regions[i].memory_size) > addr)) {
162          return (void *) (vui->region_mmap_addr[i] + addr - vui->regions[i].userspace_addr);
163        }
164   }
165   return 0;
166 }
167
168 static long get_huge_page_size(int fd)
169 {
170   struct statfs s;
171   fstatfs(fd, &s);
172   return s.f_bsize;
173 }
174
175 static void unmap_all_mem_regions(vhost_user_intf_t * vui)
176 {
177   int i,r;
178   for (i=0; i<vui->nregions; i++) {
179     if (vui->region_mmap_addr[i] != (void *) -1) {
180
181       long page_sz = get_huge_page_size(vui->region_mmap_fd[i]);
182
183       ssize_t map_sz = (vui->regions[i].memory_size +
184         vui->regions[i].mmap_offset + page_sz) & ~(page_sz - 1);
185
186       r = munmap(vui->region_mmap_addr[i] - vui->regions[i].mmap_offset, map_sz);
187
188       DBG_SOCK("unmap memory region %d addr 0x%lx len 0x%lx page_sz 0x%x", i,
189         vui->region_mmap_addr[i], map_sz, page_sz);
190
191       vui->region_mmap_addr[i]= (void *) -1;
192
193       if (r == -1) {
194         clib_warning("failed to unmap memory region (errno %d)", errno);
195       }
196       close(vui->region_mmap_fd[i]);
197     }
198   }
199   vui->nregions = 0;
200 }
201
202
203 static clib_error_t * vhost_user_callfd_read_ready (unix_file_t * uf)
204 {
205   __attribute__((unused)) int n;
206   u8 buff[8];
207   n = read(uf->file_descriptor, ((char*)&buff), 8);
208   return 0;
209 }
210
211 static inline void vhost_user_if_disconnect(vhost_user_intf_t * vui)
212 {
213   vhost_user_main_t * vum = &vhost_user_main;
214   vnet_main_t * vnm = vnet_get_main();
215   int q;
216
217   vnet_hw_interface_set_flags (vnm, vui->hw_if_index,  0);
218
219   if (vui->unix_file_index != ~0) {
220       unix_file_del (&unix_main, unix_main.file_pool + vui->unix_file_index);
221       vui->unix_file_index = ~0;
222   }
223
224   hash_unset(vum->vhost_user_interface_index_by_sock_fd, vui->unix_fd);
225   hash_unset(vum->vhost_user_interface_index_by_listener_fd, vui->unix_fd);
226   close(vui->unix_fd);
227   vui->unix_fd = -1;
228   vui->is_up = 0;
229   for (q = 0; q < vui->num_vrings; q++) {
230     vui->vrings[q].desc = NULL;
231     vui->vrings[q].avail = NULL;
232     vui->vrings[q].used = NULL;
233     vui->vrings[q].log_guest_addr = 0;
234     vui->vrings[q].log_used = 0;
235   }
236
237   unmap_all_mem_regions(vui);
238   DBG_SOCK("interface ifindex %d disconnected", vui->sw_if_index);
239 }
240
241 #define VHOST_LOG_PAGE 0x1000
242 always_inline void vhost_user_log_dirty_pages(vhost_user_intf_t * vui,
243                                                 u64 addr, u64 len)
244 {
245   if (PREDICT_TRUE(vui->log_base_addr == 0
246                    || !(vui->features & (1 << FEAT_VHOST_F_LOG_ALL)))) {
247     return;
248   }
249   if (PREDICT_FALSE((addr + len - 1) / VHOST_LOG_PAGE / 8 >= vui->log_size)) {
250     DBG_SOCK("vhost_user_log_dirty_pages(): out of range\n");
251     return;
252   }
253
254   CLIB_MEMORY_BARRIER();
255   u64 page = addr / VHOST_LOG_PAGE;
256   while (page * VHOST_LOG_PAGE < addr + len) {
257     ((u8*)vui->log_base_addr)[page / 8] |= 1 << page % 8;
258     page++;
259   }
260 }
261
262 #define vhost_user_log_dirty_ring(vui, vq, member) \
263   if (PREDICT_FALSE(vq->log_used)) { \
264     vhost_user_log_dirty_pages(vui, vq->log_guest_addr + offsetof(vring_used_t, member), \
265                              sizeof(vq->used->member)); \
266   }
267
268 static clib_error_t * vhost_user_socket_read (unix_file_t * uf)
269 {
270   int n, i;
271   int fd, number_of_fds = 0;
272   int fds[VHOST_MEMORY_MAX_NREGIONS];
273   vhost_user_msg_t msg;
274   struct msghdr mh;
275   struct iovec iov[1];
276   vhost_user_main_t * vum = &vhost_user_main;
277   vhost_user_intf_t * vui;
278   struct cmsghdr *cmsg;
279   uword * p;
280   u8 q;
281   unix_file_t template = {0};
282   vnet_main_t * vnm = vnet_get_main();
283
284   p = hash_get (vum->vhost_user_interface_index_by_sock_fd,
285                 uf->file_descriptor);
286   if (p == 0) {
287       DBG_SOCK ("FD %d doesn't belong to any interface",
288                     uf->file_descriptor);
289       return 0;
290     }
291   else
292     vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
293
294   char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))];
295
296   memset(&mh, 0, sizeof(mh));
297   memset(control, 0, sizeof(control));
298
299   for (i=0; i < VHOST_MEMORY_MAX_NREGIONS; i++)
300     fds[i] = -1;
301
302   /* set the payload */
303   iov[0].iov_base = (void *) &msg;
304   iov[0].iov_len = VHOST_USER_MSG_HDR_SZ;
305
306   mh.msg_iov = iov;
307   mh.msg_iovlen = 1;
308   mh.msg_control = control;
309   mh.msg_controllen = sizeof(control);
310
311   n = recvmsg(uf->file_descriptor, &mh, 0);
312
313   if (n != VHOST_USER_MSG_HDR_SZ)
314     goto close_socket;
315
316   if (mh.msg_flags & MSG_CTRUNC) {
317     goto close_socket;
318   }
319
320   cmsg = CMSG_FIRSTHDR(&mh);
321
322   if (cmsg && (cmsg->cmsg_len > 0) && (cmsg->cmsg_level == SOL_SOCKET) &&
323       (cmsg->cmsg_type == SCM_RIGHTS) &&
324       (cmsg->cmsg_len - CMSG_LEN(0) <= VHOST_MEMORY_MAX_NREGIONS * sizeof(int))) {
325         number_of_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
326         clib_memcpy(fds, CMSG_DATA(cmsg), number_of_fds * sizeof(int));
327   }
328
329   /* version 1, no reply bit set*/
330   if ((msg.flags & 7) != 1) {
331     DBG_SOCK("malformed message received. closing socket");
332     goto close_socket;
333   }
334
335   {
336       int rv __attribute__((unused));
337       /* $$$$ pay attention to rv */
338       rv = read(uf->file_descriptor, ((char*)&msg) + n, msg.size);
339   }
340
341   switch (msg.request) {
342     case VHOST_USER_GET_FEATURES:
343       DBG_SOCK("if %d msg VHOST_USER_GET_FEATURES",
344         vui->hw_if_index);
345
346       msg.flags |= 4;
347       msg.u64 = (1 << FEAT_VIRTIO_NET_F_MRG_RXBUF) |
348                 (1 << FEAT_VIRTIO_F_ANY_LAYOUT) |
349                 (1 << FEAT_VHOST_F_LOG_ALL) |
350                 (1 << FEAT_VIRTIO_NET_F_GUEST_ANNOUNCE) |
351                 (1 << FEAT_VHOST_USER_F_PROTOCOL_FEATURES);
352       msg.u64 &= vui->feature_mask;
353
354       msg.size = sizeof(msg.u64);
355       break;
356
357     case VHOST_USER_SET_FEATURES:
358       DBG_SOCK("if %d msg VHOST_USER_SET_FEATURES features 0x%016llx",
359         vui->hw_if_index, msg.u64);
360
361       vui->features = msg.u64;
362
363       if (vui->features & (1 << FEAT_VIRTIO_NET_F_MRG_RXBUF))
364         vui->virtio_net_hdr_sz = 12;
365       else
366         vui->virtio_net_hdr_sz = 10;
367
368       vui->is_any_layout = (vui->features & (1 << FEAT_VIRTIO_F_ANY_LAYOUT)) ? 1 : 0;
369
370       ASSERT (vui->virtio_net_hdr_sz < VLIB_BUFFER_PRE_DATA_SIZE);
371       vnet_hw_interface_set_flags (vnm, vui->hw_if_index,  0);
372       vui->is_up = 0;
373
374       for (q = 0; q < 2; q++) {
375         vui->vrings[q].desc = 0;
376         vui->vrings[q].avail = 0;
377         vui->vrings[q].used = 0;
378         vui->vrings[q].log_guest_addr = 0;
379         vui->vrings[q].log_used = 0;
380       }
381
382       DBG_SOCK("interface %d disconnected", vui->sw_if_index);
383
384       break;
385
386     case VHOST_USER_SET_MEM_TABLE:
387       DBG_SOCK("if %d msg VHOST_USER_SET_MEM_TABLE nregions %d",
388         vui->hw_if_index, msg.memory.nregions);
389
390       if ((msg.memory.nregions < 1) ||
391           (msg.memory.nregions > VHOST_MEMORY_MAX_NREGIONS)) {
392
393         DBG_SOCK("number of mem regions must be between 1 and %i",
394           VHOST_MEMORY_MAX_NREGIONS);
395
396         goto close_socket;
397       }
398
399       if (msg.memory.nregions != number_of_fds) {
400         DBG_SOCK("each memory region must have FD");
401         goto close_socket;
402       }
403       unmap_all_mem_regions(vui);
404       for(i=0; i < msg.memory.nregions; i++) {
405         clib_memcpy(&(vui->regions[i]), &msg.memory.regions[i],
406           sizeof(vhost_user_memory_region_t));
407
408         long page_sz = get_huge_page_size(fds[i]);
409
410         /* align size to 2M page */
411         ssize_t map_sz = (vui->regions[i].memory_size +
412           vui->regions[i].mmap_offset + page_sz) & ~(page_sz - 1);
413
414         vui->region_mmap_addr[i] = mmap(0, map_sz, PROT_READ | PROT_WRITE,
415                                         MAP_SHARED, fds[i], 0);
416
417         DBG_SOCK("map memory region %d addr 0 len 0x%lx fd %d mapped 0x%lx "
418           "page_sz 0x%x", i, map_sz, fds[i], vui->region_mmap_addr[i], page_sz);
419
420         if (vui->region_mmap_addr[i]  == MAP_FAILED) {
421           clib_warning("failed to map memory. errno is %d", errno);
422           goto close_socket;
423         }
424         vui->region_mmap_addr[i] += vui->regions[i].mmap_offset;
425         vui->region_mmap_fd[i] = fds[i];
426       }
427       vui->nregions = msg.memory.nregions;
428       break;
429
430     case VHOST_USER_SET_VRING_NUM:
431       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_NUM idx %d num %d",
432         vui->hw_if_index, msg.state.index, msg.state.num);
433
434       if ((msg.state.num > 32768) || /* maximum ring size is 32768 */
435           (msg.state.num == 0) ||    /* it cannot be zero */
436           (msg.state.num % 2))       /* must be power of 2 */
437         goto close_socket;
438       vui->vrings[msg.state.index].qsz = msg.state.num;
439       break;
440
441     case VHOST_USER_SET_VRING_ADDR:
442       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_ADDR idx %d",
443         vui->hw_if_index, msg.state.index);
444
445       vui->vrings[msg.state.index].desc = (vring_desc_t *) 
446           map_user_mem(vui, msg.addr.desc_user_addr);
447       vui->vrings[msg.state.index].used = (vring_used_t *)
448           map_user_mem(vui, msg.addr.used_user_addr);
449       vui->vrings[msg.state.index].avail = (vring_avail_t *)
450           map_user_mem(vui, msg.addr.avail_user_addr);
451
452       if ((vui->vrings[msg.state.index].desc == NULL) ||
453           (vui->vrings[msg.state.index].used == NULL) ||
454           (vui->vrings[msg.state.index].avail == NULL)) {
455         DBG_SOCK("failed to map user memory for hw_if_index %d",
456           vui->hw_if_index);
457         goto close_socket;
458       }
459
460       vui->vrings[msg.state.index].log_guest_addr = msg.addr.log_guest_addr;
461       vui->vrings[msg.state.index].log_used =
462           (msg.addr.flags & (1 << VHOST_VRING_F_LOG)) ? 1 : 0;
463
464       /* Spec says: If VHOST_USER_F_PROTOCOL_FEATURES has not been negotiated,
465        the ring is initialized in an enabled state. */
466
467       if (!(vui->features & (1 << FEAT_VHOST_USER_F_PROTOCOL_FEATURES))) {
468         vui->vrings[msg.state.index].enabled = 1;
469       }
470
471       vui->vrings[msg.state.index].last_used_idx =
472           vui->vrings[msg.state.index].used->idx;
473
474       /* tell driver that we don't want interrupts */
475       vui->vrings[msg.state.index].used->flags |= 1;
476       break;
477
478     case VHOST_USER_SET_OWNER:
479       DBG_SOCK("if %d msg VHOST_USER_SET_OWNER",
480         vui->hw_if_index);
481       break;
482
483     case VHOST_USER_RESET_OWNER:
484       DBG_SOCK("if %d msg VHOST_USER_RESET_OWNER",
485         vui->hw_if_index);
486       break;
487
488     case VHOST_USER_SET_VRING_CALL:
489       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_CALL u64 %d",
490         vui->hw_if_index, msg.u64);
491
492       q = (u8) (msg.u64 & 0xFF);
493
494       if (!(msg.u64 & 0x100))
495       {
496         if (number_of_fds != 1)
497           goto close_socket;
498
499         /* if there is old fd, delete it */
500         if (vui->vrings[q].callfd) {
501           unix_file_t * uf = pool_elt_at_index (unix_main.file_pool,
502             vui->vrings[q].callfd_idx);
503           unix_file_del (&unix_main, uf);
504         }
505         vui->vrings[q].callfd = fds[0];
506         template.read_function = vhost_user_callfd_read_ready;
507         template.file_descriptor = fds[0];
508         vui->vrings[q].callfd_idx = unix_file_add (&unix_main, &template);
509       }
510       else
511         vui->vrings[q].callfd = -1;
512       break;
513
514     case VHOST_USER_SET_VRING_KICK:
515       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_KICK u64 %d",
516         vui->hw_if_index, msg.u64);
517
518       q = (u8) (msg.u64 & 0xFF);
519
520       if (!(msg.u64 & 0x100))
521       {
522         if (number_of_fds != 1)
523           goto close_socket;
524
525         vui->vrings[q].kickfd = fds[0];
526       }
527       else
528         vui->vrings[q].kickfd = -1;
529       break;
530
531     case VHOST_USER_SET_VRING_ERR:
532       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_ERR u64 %d",
533         vui->hw_if_index, msg.u64);
534
535       q = (u8) (msg.u64 & 0xFF);
536
537       if (!(msg.u64 & 0x100))
538       {
539         if (number_of_fds != 1)
540           goto close_socket;
541
542         fd = fds[0];
543       }
544       else
545         fd = -1;
546
547       vui->vrings[q].errfd = fd;
548       break;
549
550     case VHOST_USER_SET_VRING_BASE:
551       DBG_SOCK("if %d msg VHOST_USER_SET_VRING_BASE idx %d num %d",
552         vui->hw_if_index, msg.state.index, msg.state.num);
553
554       vui->vrings[msg.state.index].last_avail_idx = msg.state.num;
555       break;
556
557     case VHOST_USER_GET_VRING_BASE:
558       DBG_SOCK("if %d msg VHOST_USER_GET_VRING_BASE idx %d num %d",
559         vui->hw_if_index, msg.state.index, msg.state.num);
560
561       /* Spec says: Client must [...] stop ring upon receiving VHOST_USER_GET_VRING_BASE. */
562       vui->vrings[msg.state.index].enabled = 0;
563
564       msg.state.num = vui->vrings[msg.state.index].last_avail_idx;
565       msg.flags |= 4;
566       msg.size = sizeof(msg.state);
567       break;
568
569     case VHOST_USER_NONE:
570       DBG_SOCK("if %d msg VHOST_USER_NONE",
571         vui->hw_if_index);
572
573       break;
574
575     case VHOST_USER_SET_LOG_BASE:
576     {
577       DBG_SOCK("if %d msg VHOST_USER_SET_LOG_BASE",
578         vui->hw_if_index);
579
580       if (msg.size != sizeof(msg.log)) {
581         DBG_SOCK("invalid msg size for VHOST_USER_SET_LOG_BASE: %d instead of %d",
582                  msg.size, sizeof(msg.log));
583         goto close_socket;
584       }
585
586       if (!(vui->protocol_features & (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD))) {
587         DBG_SOCK("VHOST_USER_PROTOCOL_F_LOG_SHMFD not set but VHOST_USER_SET_LOG_BASE received");
588         goto close_socket;
589       }
590
591       fd = fds[0];
592       /* align size to 2M page */
593       long page_sz = get_huge_page_size(fd);
594       ssize_t map_sz = (msg.log.size + msg.log.offset + page_sz) & ~(page_sz - 1);
595
596       vui->log_base_addr = mmap(0, map_sz, PROT_READ | PROT_WRITE,
597                                 MAP_SHARED, fd, 0);
598
599       DBG_SOCK("map log region addr 0 len 0x%lx off 0x%lx fd %d mapped 0x%lx",
600                map_sz, msg.log.offset, fd, vui->log_base_addr);
601
602       if (vui->log_base_addr == MAP_FAILED) {
603         clib_warning("failed to map memory. errno is %d", errno);
604         goto close_socket;
605       }
606
607       vui->log_base_addr += msg.log.offset;
608       vui->log_size = msg.log.size;
609
610       msg.flags |= 4;
611       msg.size = sizeof(msg.u64);
612
613       break;
614     }
615
616     case VHOST_USER_SET_LOG_FD:
617       DBG_SOCK("if %d msg VHOST_USER_SET_LOG_FD",
618         vui->hw_if_index);
619
620       break;
621
622     case VHOST_USER_GET_PROTOCOL_FEATURES:
623       DBG_SOCK("if %d msg VHOST_USER_GET_PROTOCOL_FEATURES", vui->hw_if_index);
624
625       msg.flags |= 4;
626       msg.u64 = (1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD);
627       msg.size = sizeof(msg.u64);
628       break;
629
630     case VHOST_USER_SET_PROTOCOL_FEATURES:
631       DBG_SOCK("if %d msg VHOST_USER_SET_PROTOCOL_FEATURES features 0x%lx",
632                vui->hw_if_index, msg.u64);
633
634       vui->protocol_features = msg.u64;
635
636       break;
637
638     case VHOST_USER_SET_VRING_ENABLE:
639       DBG_SOCK("if %d VHOST_USER_SET_VRING_ENABLE, enable: %d",
640                vui->hw_if_index, msg.state.num);
641       vui->vrings[msg.state.index].enabled = msg.state.num;
642       break;
643
644     default:
645       DBG_SOCK("unknown vhost-user message %d received. closing socket",
646         msg.request);
647       goto close_socket;
648   }
649
650   /* if we have pointers to descriptor table, go up*/
651   if (!vui->is_up &&
652     vui->vrings[VHOST_NET_VRING_IDX_TX].desc &&
653     vui->vrings[VHOST_NET_VRING_IDX_RX].desc) {
654
655       DBG_SOCK("interface %d connected", vui->sw_if_index);
656
657       vnet_hw_interface_set_flags (vnm, vui->hw_if_index,  VNET_HW_INTERFACE_FLAG_LINK_UP);
658       vui->is_up = 1;
659
660   }
661
662   /* if we need to reply */
663   if (msg.flags & 4)
664   {
665       n = send(uf->file_descriptor, &msg, VHOST_USER_MSG_HDR_SZ + msg.size, 0);
666       if (n != (msg.size + VHOST_USER_MSG_HDR_SZ))
667         goto close_socket;
668   }
669
670   return 0;
671
672 close_socket:
673   vhost_user_if_disconnect(vui);
674   return 0;
675 }
676
677 static clib_error_t * vhost_user_socket_error (unix_file_t * uf)
678 {
679   vhost_user_main_t * vum = &vhost_user_main;
680   vhost_user_intf_t * vui;
681   uword * p;
682
683   p = hash_get (vum->vhost_user_interface_index_by_sock_fd,
684                 uf->file_descriptor);
685   if (p == 0) {
686       DBG_SOCK ("fd %d doesn't belong to any interface",
687                     uf->file_descriptor);
688       return 0;
689     }
690   else
691     vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
692
693   vhost_user_if_disconnect(vui);
694   return 0;
695 }
696
697 static clib_error_t * vhost_user_socksvr_accept_ready (unix_file_t * uf)
698 {
699   int client_fd, client_len;
700   struct sockaddr_un client;
701   unix_file_t template = {0};
702   vhost_user_main_t * vum = &vhost_user_main;
703   vhost_user_intf_t * vui;
704   uword * p;
705
706   p = hash_get (vum->vhost_user_interface_index_by_listener_fd,
707                 uf->file_descriptor);
708   if (p == 0) {
709       DBG_SOCK ("fd %d doesn't belong to any interface",
710                     uf->file_descriptor);
711       return 0;
712     }
713   else
714     vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
715
716   client_len = sizeof(client);
717   client_fd = accept (uf->file_descriptor,
718                       (struct sockaddr *)&client,
719                       (socklen_t *)&client_len);
720
721   if (client_fd < 0)
722       return clib_error_return_unix (0, "accept");
723
724   template.read_function = vhost_user_socket_read;
725   template.error_function = vhost_user_socket_error;
726   template.file_descriptor = client_fd;
727   vui->unix_file_index = unix_file_add (&unix_main, &template);
728
729   vui->client_fd = client_fd;
730   hash_set (vum->vhost_user_interface_index_by_sock_fd, vui->client_fd,
731             vui - vum->vhost_user_interfaces);
732
733   return 0;
734 }
735
736 static clib_error_t *
737 vhost_user_init (vlib_main_t * vm)
738 {
739   clib_error_t * error;
740   vhost_user_main_t * vum = &vhost_user_main;
741   vlib_thread_main_t * tm = vlib_get_thread_main();
742
743   error = vlib_call_init_function (vm, ip4_init);
744   if (error)
745     return error;
746
747   vum->vhost_user_interface_index_by_listener_fd = hash_create (0, sizeof (uword));
748   vum->vhost_user_interface_index_by_sock_fd = hash_create (0, sizeof (uword));
749   vum->vhost_user_interface_index_by_sw_if_index = hash_create (0, sizeof (uword));
750   vum->coalesce_frames = 32;
751   vum->coalesce_time = 1e-3;
752
753   vec_validate_aligned (vum->rx_buffers, tm->n_vlib_mains - 1,
754                         CLIB_CACHE_LINE_BYTES);
755
756   return 0;
757 }
758
759 VLIB_INIT_FUNCTION (vhost_user_init);
760
761 static clib_error_t *
762 vhost_user_exit (vlib_main_t * vm)
763 {
764   /* TODO cleanup */
765   return 0;
766 }
767
768 VLIB_MAIN_LOOP_EXIT_FUNCTION (vhost_user_exit);
769
770 enum {
771   VHOST_USER_RX_NEXT_ETHERNET_INPUT,
772   VHOST_USER_RX_NEXT_DROP,
773   VHOST_USER_RX_N_NEXT,
774 };
775
776
777 typedef struct {
778   u16 virtqueue;
779   u16 device_index;
780 #if VHOST_USER_COPY_TX_HDR == 1
781   virtio_net_hdr_t hdr;
782 #endif
783 } vhost_user_input_trace_t;
784
785 static u8 * format_vhost_user_input_trace (u8 * s, va_list * va)
786 {
787   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
788   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
789   CLIB_UNUSED (vnet_main_t * vnm) = vnet_get_main();
790   vhost_user_main_t * vum = &vhost_user_main;
791   vhost_user_input_trace_t * t = va_arg (*va, vhost_user_input_trace_t *);
792   vhost_user_intf_t * vui = vec_elt_at_index (vum->vhost_user_interfaces,
793                                               t->device_index);
794
795   vnet_sw_interface_t * sw = vnet_get_sw_interface (vnm, vui->sw_if_index);
796
797 #if VHOST_USER_COPY_TX_HDR == 1
798   uword indent = format_get_indent (s);
799 #endif
800
801   s = format (s, "%U virtqueue %d",
802               format_vnet_sw_interface_name, vnm, sw,
803               t->virtqueue);
804
805 #if VHOST_USER_COPY_TX_HDR == 1
806   s = format (s, "\n%Uvirtio_net_hdr flags 0x%02x gso_type %u hdr_len %u",
807               format_white_space, indent,
808               t->hdr.flags,
809               t->hdr.gso_type,
810               t->hdr.hdr_len);
811 #endif
812
813   return s;
814 }
815
816 void vhost_user_rx_trace (vlib_main_t * vm,
817                     vlib_node_runtime_t * node,
818                     vhost_user_intf_t *vui,
819                     i16 virtqueue)
820 {
821   u32 * b, n_left;
822   vhost_user_main_t * vum = &vhost_user_main;
823
824   u32 next_index = VHOST_USER_RX_NEXT_ETHERNET_INPUT;
825
826   n_left = vec_len(vui->d_trace_buffers);
827   b = vui->d_trace_buffers;
828
829   while (n_left >= 1)
830   {
831     u32 bi0;
832     vlib_buffer_t * b0;
833     vhost_user_input_trace_t * t0;
834
835     bi0 = b[0];
836     n_left -= 1;
837
838     b0 = vlib_get_buffer (vm, bi0);
839     vlib_trace_buffer (vm, node, next_index, b0, /* follow_chain */ 0);
840     t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
841     t0->virtqueue = virtqueue;
842     t0->device_index = vui - vum->vhost_user_interfaces;
843 #if VHOST_USER_COPY_TX_HDR == 1
844     clib_memcpy(&t0->hdr, b0->pre_data, sizeof(virtio_net_hdr_t));
845 #endif
846
847     b+=1;
848   }
849 }
850
851 static inline void vhost_user_send_call(vlib_main_t * vm, vhost_user_vring_t * vq)
852 {
853     vhost_user_main_t * vum = &vhost_user_main;
854     u64 x = 1;
855     int rv __attribute__((unused));
856     /* $$$$ pay attention to rv */
857     rv = write(vq->callfd, &x, sizeof(x));
858     vq->n_since_last_int = 0;
859     vq->int_deadline = vlib_time_now(vm) + vum->coalesce_time;
860 }
861
862
863 static u32 vhost_user_if_input ( vlib_main_t * vm,
864                                vhost_user_main_t * vum, 
865                                vhost_user_intf_t * vui,
866                                vlib_node_runtime_t * node)
867 {
868   vhost_user_vring_t * txvq = &vui->vrings[VHOST_NET_VRING_IDX_TX];
869   vhost_user_vring_t * rxvq = &vui->vrings[VHOST_NET_VRING_IDX_RX];
870   uword n_rx_packets = 0, n_rx_bytes = 0;
871   uword n_left;
872   u32 n_left_to_next, * to_next;
873   u32 next_index = 0;
874   u32 next0;
875   uword n_trace = vlib_get_trace_count (vm, node);
876   u16 qsz_mask;
877   u32 cpu_index, rx_len, drops, flush;
878   f64 now = vlib_time_now (vm);
879
880   vec_reset_length (vui->d_trace_buffers);
881
882   /* no descriptor ptr - bail out */
883   if (PREDICT_FALSE(!txvq->desc || !txvq->avail || !txvq->enabled))
884     return 0;
885
886   /* do we have pending intterupts ? */
887   if ((txvq->n_since_last_int) && (txvq->int_deadline < now))
888     vhost_user_send_call(vm, txvq);
889
890   if ((rxvq->n_since_last_int) && (rxvq->int_deadline < now))
891     vhost_user_send_call(vm, rxvq);
892
893   /* only bit 0 of avail.flags is used so we don't want to deal with this
894      interface if any other bit is set */
895   if (PREDICT_FALSE(txvq->avail->flags & 0xFFFE))
896     return 0;
897
898   /* nothing to do */
899   if (txvq->avail->idx == txvq->last_avail_idx)
900     return 0;
901
902   if (PREDICT_TRUE(txvq->avail->idx > txvq->last_avail_idx))
903     n_left = txvq->avail->idx - txvq->last_avail_idx;
904   else /* wrapped */
905     n_left = (u16) -1 - txvq->last_avail_idx + txvq->avail->idx;
906
907   if (PREDICT_FALSE(!vui->admin_up)) {
908     /* if intf is admin down, just drop all packets waiting in the ring */
909     txvq->last_avail_idx = txvq->last_used_idx = txvq->avail->idx;
910     CLIB_MEMORY_BARRIER();
911     txvq->used->idx = txvq->last_used_idx;
912     vhost_user_log_dirty_ring(vui, txvq, idx);
913     vhost_user_send_call(vm, txvq);
914     return 0;
915   }
916
917   if (PREDICT_FALSE(n_left > txvq->qsz))
918     return 0;
919
920   qsz_mask = txvq->qsz - 1;
921   cpu_index = os_get_cpu_number();
922   drops = 0;
923   flush = 0;
924
925   if (n_left > VLIB_FRAME_SIZE)
926     n_left = VLIB_FRAME_SIZE;
927
928   /* Allocate some buffers.
929    * Note that buffers that are chained for jumbo
930    * frames are allocated separately using a slower path.
931    * The idea is to be certain to have enough buffers at least
932    * to cycle through the descriptors without having to check for errors.
933    * For jumbo frames, the bottleneck is memory copy anyway.
934    */
935   if (PREDICT_FALSE(!vum->rx_buffers[cpu_index])) {
936     vec_alloc (vum->rx_buffers[cpu_index], VLIB_FRAME_SIZE);
937
938     if (PREDICT_FALSE(!vum->rx_buffers[cpu_index]))
939       flush = n_left; //Drop all input
940   }
941
942   if (PREDICT_FALSE(_vec_len(vum->rx_buffers[cpu_index]) < n_left)) {
943     _vec_len(vum->rx_buffers[cpu_index]) +=
944         vlib_buffer_alloc_from_free_list(vm, vum->rx_buffers[cpu_index] + _vec_len(vum->rx_buffers[cpu_index]),
945                                          VLIB_FRAME_SIZE - _vec_len(vum->rx_buffers[cpu_index]),
946                                          VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
947
948     if (PREDICT_FALSE(n_left > _vec_len(vum->rx_buffers[cpu_index])))
949       flush = n_left - _vec_len(vum->rx_buffers[cpu_index]);
950   }
951
952   if (PREDICT_FALSE(flush)) {
953     //Remove some input buffers
954     drops += flush;
955     n_left -= flush;
956     vlib_error_count(vm, vhost_user_input_node.index,
957                      VHOST_USER_INPUT_FUNC_ERROR_NO_BUFFER, flush);
958     while (flush) {
959       u16 desc_chain_head = txvq->avail->ring[txvq->last_avail_idx & qsz_mask];
960       txvq->last_avail_idx++;
961       txvq->used->ring[txvq->last_used_idx & qsz_mask].id = desc_chain_head;
962       txvq->used->ring[txvq->last_used_idx & qsz_mask].len = 0;
963       vhost_user_log_dirty_ring(vui, txvq, ring[txvq->last_used_idx & qsz_mask]);
964       txvq->last_used_idx++;
965       flush--;
966     }
967   }
968
969   rx_len = vec_len(vum->rx_buffers[cpu_index]); //vector might be null
970   while (n_left > 0) {
971     vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
972
973     while (n_left > 0 && n_left_to_next > 0) {
974       vlib_buffer_t *b_head, *b_current;
975       u32 bi_head, bi_current;
976       u16 desc_chain_head, desc_current;
977       u8 error = VHOST_USER_INPUT_FUNC_ERROR_NO_ERROR;
978
979       desc_chain_head = desc_current = txvq->avail->ring[txvq->last_avail_idx & qsz_mask];
980       bi_head = bi_current = vum->rx_buffers[cpu_index][--rx_len];
981       b_head = b_current = vlib_get_buffer (vm, bi_head);
982       vlib_buffer_chain_init(b_head);
983
984       uword offset;
985       if (PREDICT_TRUE(vui->is_any_layout) ||
986           !(txvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT)) {
987         /* ANYLAYOUT or single buffer */
988         offset = vui->virtio_net_hdr_sz;
989       } else {
990         /* CSR case without ANYLAYOUT, skip 1st buffer */
991         offset = txvq->desc[desc_current].len;
992       }
993
994       while(1) {
995         void * buffer_addr = map_guest_mem(vui, txvq->desc[desc_current].addr);
996         if (PREDICT_FALSE(buffer_addr == 0)) {
997           error = VHOST_USER_INPUT_FUNC_ERROR_MMAP_FAIL;
998           break;
999         }
1000
1001 #if VHOST_USER_COPY_TX_HDR == 1
1002         if (PREDICT_TRUE(offset))
1003           clib_memcpy(b->pre_data, buffer_addr, sizeof(virtio_net_hdr_t)); /* 12 byte hdr is not used on tx */
1004 #endif
1005
1006         if (txvq->desc[desc_current].len > offset) {
1007           u16 len = txvq->desc[desc_current].len - offset;
1008           u16 copied = vlib_buffer_chain_append_data_with_alloc(vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX,
1009                                                    b_head, &b_current, buffer_addr + offset, len);
1010
1011           if (copied != len) {
1012             error = VHOST_USER_INPUT_FUNC_ERROR_NO_BUFFER;
1013             break;
1014           }
1015         }
1016         offset = 0;
1017
1018         /* if next flag is set, take next desc in the chain */
1019         if (txvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT )
1020           desc_current = txvq->desc[desc_current].next;
1021         else
1022           break;
1023       }
1024
1025       /* consume the descriptor and return it as used */
1026       txvq->last_avail_idx++;
1027       txvq->used->ring[txvq->last_used_idx & qsz_mask].id = desc_chain_head;
1028       txvq->used->ring[txvq->last_used_idx & qsz_mask].len = 0;
1029       vhost_user_log_dirty_ring(vui, txvq, ring[txvq->last_used_idx & qsz_mask]);
1030       txvq->last_used_idx++;
1031
1032       if(PREDICT_FALSE(b_head->current_length < 14 &&
1033                        error == VHOST_USER_INPUT_FUNC_ERROR_NO_ERROR)) {
1034         error = VHOST_USER_INPUT_FUNC_ERROR_UNDERSIZED_FRAME;
1035       }
1036
1037       VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b_head);
1038
1039       vnet_buffer (b_head)->sw_if_index[VLIB_RX] = vui->sw_if_index;
1040       vnet_buffer (b_head)->sw_if_index[VLIB_TX] = (u32)~0;
1041       b_head->error = node->errors[error];
1042
1043       if (PREDICT_FALSE (n_trace > n_rx_packets))
1044         vec_add1 (vui->d_trace_buffers, bi_head);
1045
1046       if (PREDICT_FALSE(error)) {
1047         drops++;
1048         next0 = VHOST_USER_RX_NEXT_DROP;
1049       } else {
1050         n_rx_bytes += b_head->current_length + b_head->total_length_not_including_first_buffer;
1051         n_rx_packets++;
1052         next0 = VHOST_USER_RX_NEXT_ETHERNET_INPUT;
1053       }
1054
1055       to_next[0] = bi_head;
1056       to_next++;
1057       n_left_to_next--;
1058       vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1059                                        to_next, n_left_to_next,
1060                                        bi_head, next0);
1061       n_left--;
1062     }
1063
1064     vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1065   }
1066
1067   if (PREDICT_TRUE(vum->rx_buffers[cpu_index] != 0))
1068     _vec_len(vum->rx_buffers[cpu_index]) = rx_len;
1069
1070   /* give buffers back to driver */
1071   CLIB_MEMORY_BARRIER();
1072   txvq->used->idx = txvq->last_used_idx;
1073   vhost_user_log_dirty_ring(vui, txvq, idx);
1074
1075   if (PREDICT_FALSE (vec_len (vui->d_trace_buffers) > 0))
1076   {
1077     vhost_user_rx_trace (vm, node, vui, VHOST_NET_VRING_IDX_TX);
1078     vlib_set_trace_count (vm, node, n_trace - vec_len (vui->d_trace_buffers));
1079   }
1080
1081   /* interrupt (call) handling */
1082   if((txvq->callfd > 0) && !(txvq->avail->flags & 1)) {
1083     txvq->n_since_last_int += n_rx_packets;
1084
1085     if(txvq->n_since_last_int > vum->coalesce_frames)
1086       vhost_user_send_call(vm, txvq);
1087   }
1088
1089   if (PREDICT_FALSE(drops)) {
1090     vlib_increment_simple_counter
1091     (vnet_main.interface_main.sw_if_counters
1092      + VNET_INTERFACE_COUNTER_DROP, os_get_cpu_number(),
1093      vui->sw_if_index, drops);
1094   }
1095
1096   /* increase rx counters */
1097   vlib_increment_combined_counter
1098   (vnet_main.interface_main.combined_sw_if_counters
1099    + VNET_INTERFACE_COUNTER_RX,
1100    os_get_cpu_number(),
1101    vui->sw_if_index,
1102    n_rx_packets, n_rx_bytes);
1103
1104   return n_rx_packets;
1105 }
1106
1107 static uword
1108 vhost_user_input (vlib_main_t * vm,
1109             vlib_node_runtime_t * node,
1110             vlib_frame_t * f)
1111 {
1112   vhost_user_main_t * vum = &vhost_user_main;
1113   dpdk_main_t * dm = &dpdk_main;
1114   vhost_user_intf_t * vui;
1115   uword n_rx_packets = 0;
1116   u32 cpu_index = os_get_cpu_number();
1117   int i;
1118
1119   for(i = 0; i < vec_len(vum->vhost_user_interfaces); i++ )
1120     {
1121       vui = vec_elt_at_index(vum->vhost_user_interfaces, i);
1122       if (vui->is_up &&
1123           (i % dm->input_cpu_count) == (cpu_index - dm->input_cpu_first_index))
1124         n_rx_packets += vhost_user_if_input (vm, vum, vui, node);
1125     }
1126   return n_rx_packets;
1127 }
1128
1129 VLIB_REGISTER_NODE (vhost_user_input_node) = {
1130   .function = vhost_user_input,
1131   .type = VLIB_NODE_TYPE_INPUT,
1132   .name = "vhost-user-input",
1133
1134   /* Will be enabled if/when hardware is detected. */
1135   .state = VLIB_NODE_STATE_DISABLED,
1136
1137   .format_buffer = format_ethernet_header_with_length,
1138   .format_trace = format_vhost_user_input_trace,
1139
1140   .n_errors = VHOST_USER_INPUT_FUNC_N_ERROR,
1141   .error_strings = vhost_user_input_func_error_strings,
1142
1143   .n_next_nodes = VHOST_USER_RX_N_NEXT,
1144   .next_nodes = {
1145     [VHOST_USER_RX_NEXT_DROP] = "error-drop",
1146     [VHOST_USER_RX_NEXT_ETHERNET_INPUT] = "ethernet-input",
1147   },
1148 };
1149
1150 VLIB_NODE_FUNCTION_MULTIARCH (vhost_user_input_node, vhost_user_input)
1151
1152 static uword
1153 vhost_user_intfc_tx (vlib_main_t * vm,
1154                  vlib_node_runtime_t * node,
1155                  vlib_frame_t * frame)
1156 {
1157   u32 * buffers = vlib_frame_args (frame);
1158   u32 n_left = 0;
1159   u16 used_index;
1160   vhost_user_main_t * vum = &vhost_user_main;
1161   uword n_packets = 0;
1162   vnet_interface_output_runtime_t * rd = (void *) node->runtime_data;
1163   vhost_user_intf_t * vui = vec_elt_at_index (vum->vhost_user_interfaces, rd->dev_instance);
1164   vhost_user_vring_t * rxvq = &vui->vrings[VHOST_NET_VRING_IDX_RX];
1165   u16 qsz_mask;
1166   u8 error = VHOST_USER_TX_FUNC_ERROR_NONE;
1167
1168   if (PREDICT_FALSE(!vui->is_up))
1169      goto done2;
1170
1171   if (PREDICT_FALSE(!rxvq->desc || !rxvq->avail || vui->sock_errno != 0 || !rxvq->enabled)) {
1172      error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
1173      goto done2;
1174   }
1175
1176   if (PREDICT_FALSE(vui->lockp != 0))
1177     {
1178       while (__sync_lock_test_and_set (vui->lockp, 1))
1179         ;
1180     }
1181
1182   /* only bit 0 of avail.flags is used so we don't want to deal with this
1183      interface if any other bit is set */
1184   if (PREDICT_FALSE(rxvq->avail->flags & 0xFFFE)) {
1185     error = VHOST_USER_TX_FUNC_ERROR_NOT_READY;
1186     goto done2;
1187   }
1188
1189   if (PREDICT_FALSE((rxvq->avail->idx == rxvq->last_avail_idx))) {
1190      error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1191      goto done2;
1192    }
1193
1194   n_left = n_packets = frame->n_vectors;
1195   used_index = rxvq->used->idx;
1196   qsz_mask = rxvq->qsz - 1; /* qsz is always power of 2 */
1197
1198   while (n_left > 0)
1199   {
1200       vlib_buffer_t *b0, *current_b0;
1201       u16 desc_chain_head, desc_current, desc_len;
1202       void *buffer_addr;
1203       uword offset;
1204
1205       if (n_left >= 2)
1206         vlib_prefetch_buffer_with_index (vm, buffers[1], LOAD);
1207
1208       b0 = vlib_get_buffer (vm, buffers[0]);
1209       buffers++;
1210       n_left--;
1211
1212       if (PREDICT_FALSE(rxvq->last_avail_idx == rxvq->avail->idx)) {
1213         error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1214         goto done;
1215       }
1216
1217       desc_current = desc_chain_head = rxvq->avail->ring[rxvq->last_avail_idx & qsz_mask];
1218       offset = vui->virtio_net_hdr_sz;
1219       desc_len = offset;
1220       if (PREDICT_FALSE(!(buffer_addr = map_guest_mem(vui, rxvq->desc[desc_current].addr)))) {
1221         error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1222         goto done;
1223       }
1224       CLIB_PREFETCH(buffer_addr, clib_min(rxvq->desc[desc_current].len,
1225         4*CLIB_CACHE_LINE_BYTES), STORE);
1226
1227       virtio_net_hdr_mrg_rxbuf_t * hdr = (virtio_net_hdr_mrg_rxbuf_t *) buffer_addr;
1228       hdr->hdr.flags = 0;
1229       hdr->hdr.gso_type = 0;
1230
1231       vhost_user_log_dirty_pages(vui, rxvq->desc[desc_current].addr, vui->virtio_net_hdr_sz);
1232
1233       if (vui->virtio_net_hdr_sz == 12)
1234         hdr->num_buffers = 1;
1235
1236       u16 bytes_left = b0->current_length;
1237       buffer_addr += offset;
1238       current_b0 = b0;
1239
1240       //FIXME: This was in the code but I don't think it is valid
1241       /*if (PREDICT_FALSE(!vui->is_any_layout && (rxvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT))) {
1242         rxvq->desc[desc_current].len = vui->virtio_net_hdr_sz;
1243       }*/
1244
1245       while(1) {
1246         if (!bytes_left) { //Get new input
1247           if (current_b0->flags & VLIB_BUFFER_NEXT_PRESENT) {
1248             current_b0 = vlib_get_buffer(vm, current_b0->next_buffer);
1249             bytes_left = current_b0->current_length;
1250           } else {
1251             //End of packet
1252             break;
1253           }
1254         }
1255
1256         if (rxvq->desc[desc_current].len <= offset) { //Get new output
1257           if (rxvq->desc[desc_current].flags & VIRTQ_DESC_F_NEXT) {
1258             offset = 0;
1259             desc_current = rxvq->desc[desc_current].next;
1260             if (PREDICT_FALSE(!(buffer_addr = map_guest_mem(vui, rxvq->desc[desc_current].addr)))) {
1261               used_index -= hdr->num_buffers - 1;
1262               rxvq->last_avail_idx -= hdr->num_buffers - 1;
1263               error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1264               goto done;
1265             }
1266           } else if (vui->virtio_net_hdr_sz == 12) { //MRG is available
1267
1268             //Move from available to used buffer
1269             rxvq->used->ring[used_index & qsz_mask].id = desc_chain_head;
1270             rxvq->used->ring[used_index & qsz_mask].len = desc_len;
1271             vhost_user_log_dirty_ring(vui, rxvq, ring[used_index & qsz_mask]);
1272             rxvq->last_avail_idx++;
1273             used_index++;
1274             hdr->num_buffers++;
1275
1276             if (PREDICT_FALSE(rxvq->last_avail_idx == rxvq->avail->idx)) {
1277               //Dequeue queued descriptors for this packet
1278               used_index -= hdr->num_buffers - 1;
1279               rxvq->last_avail_idx -= hdr->num_buffers - 1;
1280               error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1281               goto done;
1282             }
1283
1284             //Look at next one
1285             desc_chain_head = rxvq->avail->ring[rxvq->last_avail_idx & qsz_mask];
1286             desc_current = desc_chain_head;
1287             desc_len = 0;
1288             offset = 0;
1289             if (PREDICT_FALSE(!(buffer_addr = map_guest_mem(vui, rxvq->desc[desc_current].addr)))) {
1290               //Dequeue queued descriptors for this packet
1291               used_index -= hdr->num_buffers - 1;
1292               rxvq->last_avail_idx -= hdr->num_buffers - 1;
1293               error = VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL;
1294               goto done;
1295             }
1296           } else {
1297             error = VHOST_USER_TX_FUNC_ERROR_PKT_DROP_NOBUF;
1298             goto done;
1299           }
1300         }
1301
1302         u16 bytes_to_copy = bytes_left > (rxvq->desc[desc_current].len - offset) ? (rxvq->desc[desc_current].len - offset) : bytes_left;
1303         clib_memcpy(buffer_addr, vlib_buffer_get_current (current_b0) + current_b0->current_length - bytes_left, bytes_to_copy);
1304
1305         vhost_user_log_dirty_pages(vui, rxvq->desc[desc_current].addr + offset, bytes_to_copy);
1306         bytes_left -= bytes_to_copy;
1307         offset += bytes_to_copy;
1308         buffer_addr += bytes_to_copy;
1309         desc_len += bytes_to_copy;
1310       }
1311
1312       //Move from available to used ring
1313       rxvq->used->ring[used_index & qsz_mask].id = desc_chain_head;
1314       rxvq->used->ring[used_index & qsz_mask].len = desc_len;
1315       vhost_user_log_dirty_ring(vui, rxvq, ring[used_index & qsz_mask]);
1316
1317       rxvq->last_avail_idx++;
1318       used_index++;
1319   }
1320
1321 done:
1322   CLIB_MEMORY_BARRIER();
1323   rxvq->used->idx = used_index;
1324   vhost_user_log_dirty_ring(vui, rxvq, idx);
1325
1326   /* interrupt (call) handling */
1327   if((rxvq->callfd > 0) && !(rxvq->avail->flags & 1)) {
1328     rxvq->n_since_last_int += n_packets - n_left;
1329
1330     if(rxvq->n_since_last_int > vum->coalesce_frames)
1331       vhost_user_send_call(vm, rxvq);
1332   }
1333
1334 done2:
1335
1336   if (PREDICT_FALSE(vui->lockp != 0))
1337       *vui->lockp = 0;
1338
1339   if (PREDICT_FALSE(n_left && error != VHOST_USER_TX_FUNC_ERROR_NONE)) {
1340     vlib_error_count(vm, node->node_index, error, n_left);
1341     vlib_increment_simple_counter
1342     (vnet_main.interface_main.sw_if_counters
1343      + VNET_INTERFACE_COUNTER_DROP,
1344      os_get_cpu_number(),
1345      vui->sw_if_index,
1346      n_left);
1347   }
1348
1349   vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors);
1350   return frame->n_vectors;
1351 }
1352
1353 static clib_error_t *
1354 vhost_user_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
1355 {
1356   vnet_hw_interface_t * hif = vnet_get_hw_interface (vnm, hw_if_index);
1357   uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
1358   vhost_user_main_t * vum = &vhost_user_main;
1359   vhost_user_intf_t * vui = vec_elt_at_index (vum->vhost_user_interfaces, hif->dev_instance);
1360
1361   vui->admin_up = is_up;
1362
1363   if (is_up)
1364     vnet_hw_interface_set_flags (vnm, vui->hw_if_index,
1365                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
1366
1367   return /* no error */ 0;
1368 }
1369
1370 VNET_DEVICE_CLASS (vhost_user_dev_class,static) = {
1371   .name = "vhost-user",
1372   .tx_function = vhost_user_intfc_tx,
1373   .tx_function_n_errors = VHOST_USER_TX_FUNC_N_ERROR,
1374   .tx_function_error_strings = vhost_user_tx_func_error_strings,
1375   .format_device_name = format_vhost_user_interface_name,
1376   .name_renumber = vhost_user_name_renumber,
1377   .admin_up_down_function = vhost_user_interface_admin_up_down,
1378   .no_flatten_output_chains = 1,
1379 };
1380
1381 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (vhost_user_dev_class,
1382                                    vhost_user_intfc_tx)
1383
1384 static uword
1385 vhost_user_process (vlib_main_t * vm,
1386               vlib_node_runtime_t * rt,
1387               vlib_frame_t * f)
1388 {
1389     vhost_user_main_t * vum = &vhost_user_main;
1390     vhost_user_intf_t * vui;
1391     struct sockaddr_un sun;
1392     int sockfd;
1393     unix_file_t template = {0};
1394     f64 timeout = 3153600000.0 /* 100 years */;
1395     uword *event_data = 0;
1396
1397     sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1398     sun.sun_family = AF_UNIX;
1399     template.read_function = vhost_user_socket_read;
1400     template.error_function = vhost_user_socket_error;
1401
1402
1403     if (sockfd < 0)
1404       return 0;
1405
1406     while (1) {
1407         vlib_process_wait_for_event_or_clock (vm, timeout);
1408         vlib_process_get_events (vm, &event_data);
1409         vec_reset_length (event_data);
1410
1411         timeout = 3.0;
1412
1413         vec_foreach (vui, vum->vhost_user_interfaces) {
1414
1415           if (vui->sock_is_server || !vui->active)
1416             continue;
1417
1418           if  (vui->unix_fd == -1) {
1419             /* try to connect */
1420
1421             strncpy(sun.sun_path,  (char *) vui->sock_filename, sizeof(sun.sun_path) - 1);
1422
1423             if (connect(sockfd, (struct sockaddr *) &sun, sizeof(struct sockaddr_un)) == 0) {
1424                 vui->sock_errno = 0;
1425                 vui->unix_fd = sockfd;
1426                 template.file_descriptor = sockfd;
1427                 vui->unix_file_index = unix_file_add (&unix_main, &template);
1428                 hash_set (vum->vhost_user_interface_index_by_sock_fd, sockfd, vui - vum->vhost_user_interfaces);
1429
1430                 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1431                 if (sockfd < 0)
1432                   return 0;
1433             }
1434             else {
1435               vui->sock_errno = errno;
1436             }
1437           } else {
1438             /* check if socket is alive */
1439             int error = 0;
1440             socklen_t len = sizeof (error);
1441             int retval = getsockopt(vui->unix_fd, SOL_SOCKET, SO_ERROR, &error, &len);
1442
1443             if (retval)
1444               vhost_user_if_disconnect(vui);
1445           }
1446         }
1447     }
1448     return 0;
1449 }
1450
1451 VLIB_REGISTER_NODE (vhost_user_process_node,static) = {
1452     .function = vhost_user_process,
1453     .type = VLIB_NODE_TYPE_PROCESS,
1454     .name = "vhost-user-process",
1455 };
1456
1457 int vhost_user_delete_if(vnet_main_t * vnm, vlib_main_t * vm,
1458                          u32 sw_if_index)
1459 {
1460   vhost_user_main_t * vum = &vhost_user_main;
1461   vhost_user_intf_t * vui;
1462   uword *p = NULL;
1463   int rv = 0;
1464
1465   p = hash_get (vum->vhost_user_interface_index_by_sw_if_index,
1466                 sw_if_index);
1467   if (p == 0) {
1468     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1469   } else {
1470     vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
1471   }
1472
1473   // interface is inactive
1474   vui->active = 0;
1475   // disconnect interface sockets
1476   vhost_user_if_disconnect(vui);
1477   // add to inactive interface list
1478   vec_add1 (vum->vhost_user_inactive_interfaces_index, p[0]);
1479
1480   // reset renumbered iface
1481   if (p[0] < vec_len (vum->show_dev_instance_by_real_dev_instance))
1482     vum->show_dev_instance_by_real_dev_instance[p[0]] = ~0;
1483
1484   ethernet_delete_interface (vnm, vui->hw_if_index);
1485   DBG_SOCK ("deleted (deactivated) vhost-user interface instance %d", p[0]);
1486
1487   return rv;
1488 }
1489
1490 // init server socket on specified sock_filename
1491 static int vhost_user_init_server_sock(const char * sock_filename, int *sockfd)
1492 {
1493   int rv = 0;
1494   struct sockaddr_un un = {};
1495   int fd;
1496   /* create listening socket */
1497   fd = socket(AF_UNIX, SOCK_STREAM, 0);
1498
1499   if (fd < 0) {
1500     return VNET_API_ERROR_SYSCALL_ERROR_1;
1501   }
1502
1503   un.sun_family = AF_UNIX;
1504   strncpy((char *) un.sun_path, (char *) sock_filename, sizeof(un.sun_path) - 1);
1505
1506   /* remove if exists */
1507   unlink( (char *) sock_filename);
1508
1509   if (bind(fd, (struct sockaddr *) &un, sizeof(un)) == -1) {
1510     rv = VNET_API_ERROR_SYSCALL_ERROR_2;
1511     goto error;
1512   }
1513
1514   if (listen(fd, 1) == -1) {
1515     rv = VNET_API_ERROR_SYSCALL_ERROR_3;
1516     goto error;
1517   }
1518
1519   unix_file_t template = {0};
1520   template.read_function = vhost_user_socksvr_accept_ready;
1521   template.file_descriptor = fd;
1522   unix_file_add (&unix_main, &template);
1523   *sockfd = fd;
1524   return rv;
1525
1526 error:
1527   close(fd);
1528   return rv;
1529 }
1530
1531 // get new vhost_user_intf_t from inactive interfaces or create new one
1532 static vhost_user_intf_t *vhost_user_vui_new()
1533 {
1534   vhost_user_main_t * vum = &vhost_user_main;
1535   vhost_user_intf_t * vui = NULL;
1536   int inactive_cnt = vec_len(vum->vhost_user_inactive_interfaces_index);
1537   // if there are any inactive ifaces
1538   if (inactive_cnt > 0) {
1539     // take last
1540     u32 vui_idx = vum->vhost_user_inactive_interfaces_index[inactive_cnt - 1];
1541     if (vec_len(vum->vhost_user_interfaces) > vui_idx) {
1542       vui = vec_elt_at_index (vum->vhost_user_interfaces, vui_idx);
1543       DBG_SOCK("reusing inactive vhost-user interface index %d", vui_idx);
1544     }
1545     // "remove" from inactive list
1546     _vec_len(vum->vhost_user_inactive_interfaces_index) -= 1;
1547   }
1548
1549   // vui was not retrieved from inactive ifaces - create new
1550   if (!vui)
1551     vec_add2 (vum->vhost_user_interfaces, vui, 1);
1552   return vui;
1553 }
1554
1555 // create ethernet interface for vhost user intf
1556 static void vhost_user_create_ethernet(vnet_main_t * vnm, vlib_main_t * vm,
1557                                        vhost_user_intf_t *vui, u8 *hwaddress)
1558 {
1559   vhost_user_main_t * vum = &vhost_user_main;
1560   u8 hwaddr[6];
1561   clib_error_t * error;
1562
1563   /* create hw and sw interface */
1564   if (hwaddress) {
1565     clib_memcpy(hwaddr, hwaddress, 6);
1566   } else {
1567     f64 now = vlib_time_now(vm);
1568     u32 rnd;
1569     rnd = (u32) (now * 1e6);
1570     rnd = random_u32 (&rnd);
1571
1572     clib_memcpy (hwaddr+2, &rnd, sizeof(rnd));
1573     hwaddr[0] = 2;
1574     hwaddr[1] = 0xfe;
1575   }
1576
1577   error = ethernet_register_interface
1578     (vnm,
1579      vhost_user_dev_class.index,
1580      vui - vum->vhost_user_interfaces /* device instance */,
1581      hwaddr /* ethernet address */,
1582      &vui->hw_if_index,
1583      0 /* flag change */);
1584   if (error)
1585     clib_error_report (error);
1586
1587   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, vui->hw_if_index);
1588   hi->max_l3_packet_bytes[VLIB_RX] = hi->max_l3_packet_bytes[VLIB_TX] = 9000;
1589 }
1590
1591 // initialize vui with specified attributes
1592 static void vhost_user_vui_init(vnet_main_t * vnm,
1593                                 vhost_user_intf_t *vui, int sockfd,
1594                                 const char * sock_filename,
1595                                 u8 is_server, u64 feature_mask,
1596                                 u32 * sw_if_index)
1597 {
1598   vnet_sw_interface_t * sw;
1599   sw = vnet_get_hw_sw_interface (vnm, vui->hw_if_index);
1600   vlib_thread_main_t * tm = vlib_get_thread_main();
1601   int q;
1602
1603   vui->unix_fd = sockfd;
1604   vui->sw_if_index = sw->sw_if_index;
1605   vui->num_vrings = 2;
1606   vui->sock_is_server = is_server;
1607   strncpy(vui->sock_filename, sock_filename, ARRAY_LEN(vui->sock_filename)-1);
1608   vui->sock_errno = 0;
1609   vui->is_up = 0;
1610   vui->feature_mask = feature_mask;
1611   vui->active = 1;
1612   vui->unix_file_index = ~0;
1613   vui->log_base_addr = 0;
1614
1615   for (q = 0; q < 2; q++) {
1616     vui->vrings[q].enabled = 0;
1617   }
1618
1619   vnet_hw_interface_set_flags (vnm, vui->hw_if_index,  0);
1620
1621   if (sw_if_index)
1622       *sw_if_index = vui->sw_if_index;
1623
1624   if (tm->n_vlib_mains > 1)
1625   {
1626     vui->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
1627                                          CLIB_CACHE_LINE_BYTES);
1628     memset ((void *) vui->lockp, 0, CLIB_CACHE_LINE_BYTES);
1629   }
1630 }
1631
1632 // register vui and start polling on it
1633 static void vhost_user_vui_register(vlib_main_t * vm, vhost_user_intf_t *vui)
1634 {
1635   vhost_user_main_t * vum = &vhost_user_main;
1636   dpdk_main_t * dm = &dpdk_main;
1637   int cpu_index;
1638   vlib_thread_main_t * tm = vlib_get_thread_main();
1639
1640   hash_set (vum->vhost_user_interface_index_by_listener_fd, vui->unix_fd,
1641             vui - vum->vhost_user_interfaces);
1642   hash_set (vum->vhost_user_interface_index_by_sw_if_index, vui->sw_if_index,
1643             vui - vum->vhost_user_interfaces);
1644
1645   /* start polling */
1646   cpu_index = dm->input_cpu_first_index +
1647               (vui - vum->vhost_user_interfaces) % dm->input_cpu_count;
1648
1649   if (tm->n_vlib_mains == 1)
1650     vlib_node_set_state (vm, vhost_user_input_node.index,
1651                          VLIB_NODE_STATE_POLLING);
1652   else
1653     vlib_node_set_state (vlib_mains[cpu_index], vhost_user_input_node.index,
1654                          VLIB_NODE_STATE_POLLING);
1655
1656   /* tell process to start polling for sockets */
1657   vlib_process_signal_event(vm, vhost_user_process_node.index, 0, 0);
1658 }
1659
1660 int vhost_user_create_if(vnet_main_t * vnm, vlib_main_t * vm,
1661                          const char * sock_filename,
1662                          u8 is_server,
1663                          u32 * sw_if_index,
1664                          u64 feature_mask,
1665                          u8 renumber, u32 custom_dev_instance,
1666                          u8 *hwaddr)
1667 {
1668   vhost_user_intf_t * vui = NULL;
1669   u32 sw_if_idx = ~0;
1670   int sockfd = -1;
1671   int rv = 0;
1672
1673   if (is_server) {
1674       if ((rv = vhost_user_init_server_sock (sock_filename, &sockfd)) != 0) {
1675           return rv;
1676       }
1677   }
1678
1679   vui = vhost_user_vui_new ();
1680   ASSERT(vui != NULL);
1681
1682   vhost_user_create_ethernet (vnm, vm, vui, hwaddr);
1683   vhost_user_vui_init (vnm, vui, sockfd, sock_filename, is_server,
1684                        feature_mask, &sw_if_idx);
1685
1686   if (renumber) {
1687     vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
1688   }
1689
1690   vhost_user_vui_register (vm, vui);
1691
1692   if (sw_if_index)
1693       *sw_if_index = sw_if_idx;
1694
1695   return rv;
1696 }
1697
1698 int vhost_user_modify_if(vnet_main_t * vnm, vlib_main_t * vm,
1699                          const char * sock_filename,
1700                          u8 is_server,
1701                          u32 sw_if_index,
1702                          u64 feature_mask,
1703                          u8 renumber, u32 custom_dev_instance)
1704 {
1705   vhost_user_main_t * vum = &vhost_user_main;
1706   vhost_user_intf_t * vui = NULL;
1707   u32 sw_if_idx = ~0;
1708   int sockfd = -1;
1709   int rv = 0;
1710   uword *p = NULL;
1711
1712   p = hash_get (vum->vhost_user_interface_index_by_sw_if_index,
1713                 sw_if_index);
1714   if (p == 0) {
1715     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1716   } else {
1717     vui = vec_elt_at_index (vum->vhost_user_interfaces, p[0]);
1718   }
1719
1720   // interface is inactive
1721   vui->active = 0;
1722   // disconnect interface sockets
1723   vhost_user_if_disconnect(vui);
1724
1725   if (is_server) {
1726       if ((rv = vhost_user_init_server_sock (sock_filename, &sockfd)) != 0) {
1727           return rv;
1728       }
1729   }
1730
1731   vhost_user_vui_init (vnm, vui, sockfd, sock_filename, is_server,
1732                        feature_mask, &sw_if_idx);
1733
1734   if (renumber) {
1735     vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
1736   }
1737
1738   vhost_user_vui_register (vm, vui);
1739
1740   return rv;
1741 }
1742
1743 clib_error_t *
1744 vhost_user_connect_command_fn (vlib_main_t * vm,
1745                  unformat_input_t * input,
1746                  vlib_cli_command_t * cmd)
1747 {
1748   unformat_input_t _line_input, * line_input = &_line_input;
1749   u8 * sock_filename = NULL;
1750   u32 sw_if_index;
1751   u8 is_server = 0;
1752   u64 feature_mask = (u64)~0;
1753   u8 renumber = 0;
1754   u32 custom_dev_instance = ~0;
1755   u8 hwaddr[6];
1756   u8 *hw = NULL;
1757
1758   /* Get a line of input. */
1759   if (! unformat_user (input, unformat_line_input, line_input))
1760     return 0;
1761
1762   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
1763     if (unformat (line_input, "socket %s", &sock_filename))
1764       ;
1765     else if (unformat (line_input, "server"))
1766       is_server = 1;
1767     else if (unformat (line_input, "feature-mask 0x%llx", &feature_mask))
1768       ;
1769     else if (unformat (line_input, "hwaddr %U", unformat_ethernet_address, hwaddr))
1770           hw = hwaddr;
1771     else if (unformat (line_input, "renumber %d", &custom_dev_instance)) {
1772         renumber = 1;
1773     }
1774     else
1775       return clib_error_return (0, "unknown input `%U'",
1776                                 format_unformat_error, input);
1777   }
1778   unformat_free (line_input);
1779
1780   vnet_main_t *vnm = vnet_get_main();
1781
1782   int rv;
1783   if ((rv = vhost_user_create_if(vnm, vm, (char *)sock_filename,
1784                        is_server, &sw_if_index, feature_mask,
1785                        renumber, custom_dev_instance, hw))) {
1786       vec_free(sock_filename);
1787       return clib_error_return (0, "vhost_user_create_if returned %d", rv);
1788   }
1789
1790   vec_free(sock_filename);
1791   vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
1792   return 0;
1793 }
1794
1795 clib_error_t *
1796 vhost_user_delete_command_fn (vlib_main_t * vm,
1797                  unformat_input_t * input,
1798                  vlib_cli_command_t * cmd)
1799 {
1800   unformat_input_t _line_input, * line_input = &_line_input;
1801   u32 sw_if_index = ~0;
1802
1803   /* Get a line of input. */
1804   if (! unformat_user (input, unformat_line_input, line_input))
1805     return 0;
1806
1807   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
1808     if (unformat (line_input, "sw_if_index %d", &sw_if_index))
1809       ;
1810     else
1811       return clib_error_return (0, "unknown input `%U'",
1812                                 format_unformat_error, input);
1813   }
1814   unformat_free (line_input);
1815
1816   vnet_main_t *vnm = vnet_get_main();
1817
1818   vhost_user_delete_if(vnm, vm, sw_if_index);
1819
1820   return 0;
1821 }
1822
1823 int vhost_user_dump_ifs(vnet_main_t * vnm, vlib_main_t * vm, vhost_user_intf_details_t **out_vuids)
1824 {
1825   int rv = 0;
1826   vhost_user_main_t * vum = &vhost_user_main;
1827   vhost_user_intf_t * vui;
1828   vhost_user_intf_details_t * r_vuids = NULL;
1829   vhost_user_intf_details_t * vuid = NULL;
1830   u32 * hw_if_indices = 0;
1831   vnet_hw_interface_t * hi;
1832   u8 *s = NULL;
1833   int i;
1834
1835   if (!out_vuids)
1836       return -1;
1837
1838   vec_foreach (vui, vum->vhost_user_interfaces) {
1839     if (vui->active)
1840       vec_add1(hw_if_indices, vui->hw_if_index);
1841   }
1842
1843   for (i = 0; i < vec_len (hw_if_indices); i++) {
1844     hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
1845     vui = vec_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
1846
1847     vec_add2(r_vuids, vuid, 1);
1848     vuid->sw_if_index = vui->sw_if_index;
1849     vuid->virtio_net_hdr_sz = vui->virtio_net_hdr_sz;
1850     vuid->features = vui->features;
1851     vuid->is_server = vui->sock_is_server;
1852     vuid->num_regions = vui->nregions;
1853     vuid->sock_errno = vui->sock_errno;
1854     strncpy((char *)vuid->sock_filename, (char *)vui->sock_filename,
1855             ARRAY_LEN(vuid->sock_filename)-1);
1856
1857     s = format (s, "%v%c", hi->name, 0);
1858
1859     strncpy((char *)vuid->if_name, (char *)s,
1860             ARRAY_LEN(vuid->if_name)-1);
1861     _vec_len(s) = 0;
1862   }
1863
1864   vec_free (s);
1865   vec_free (hw_if_indices);
1866
1867   *out_vuids = r_vuids;
1868
1869   return rv;
1870 }
1871
1872 clib_error_t *
1873 show_vhost_user_command_fn (vlib_main_t * vm,
1874                  unformat_input_t * input,
1875                  vlib_cli_command_t * cmd)
1876 {
1877   clib_error_t * error = 0;
1878   vnet_main_t * vnm = vnet_get_main();
1879   vhost_user_main_t * vum = &vhost_user_main;
1880   vhost_user_intf_t * vui;
1881   u32 hw_if_index, * hw_if_indices = 0;
1882   vnet_hw_interface_t * hi;
1883   int i, j, q;
1884   int show_descr = 0;
1885   struct feat_struct { u8 bit; char *str;};
1886   struct feat_struct *feat_entry;
1887
1888   static struct feat_struct feat_array[] = {
1889 #define _(s,b) { .str = #s, .bit = b, },
1890   foreach_virtio_net_feature
1891 #undef _
1892   { .str = NULL }
1893   };
1894
1895   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1896     if (unformat (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) {
1897       vec_add1 (hw_if_indices, hw_if_index);
1898       vlib_cli_output(vm, "add %d", hw_if_index);
1899     }
1900     else if (unformat (input, "descriptors") || unformat (input, "desc") )
1901       show_descr = 1;
1902     else {
1903       error = clib_error_return (0, "unknown input `%U'",
1904                                      format_unformat_error, input);
1905       goto done;
1906     }
1907   }
1908   if (vec_len (hw_if_indices) == 0) {
1909     vec_foreach (vui, vum->vhost_user_interfaces) {
1910       if (vui->active)
1911         vec_add1(hw_if_indices, vui->hw_if_index);
1912     }
1913   }
1914   vlib_cli_output (vm, "Virtio vhost-user interfaces");
1915   vlib_cli_output (vm, "Global:\n  coalesce frames %d time %e\n\n",
1916                    vum->coalesce_frames, vum->coalesce_time);
1917
1918   for (i = 0; i < vec_len (hw_if_indices); i++) {
1919     hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
1920     vui = vec_elt_at_index (vum->vhost_user_interfaces, hi->dev_instance);
1921     vlib_cli_output (vm, "Interface: %s (ifindex %d)",
1922                          hi->name, hw_if_indices[i]);
1923
1924     vlib_cli_output (vm, "virtio_net_hdr_sz %d\n features (0x%llx): \n",
1925                          vui->virtio_net_hdr_sz, vui->features);
1926
1927     feat_entry = (struct feat_struct *) &feat_array;
1928     while(feat_entry->str) {
1929       if (vui->features & (1 << feat_entry->bit))
1930         vlib_cli_output (vm, "   %s (%d)", feat_entry->str, feat_entry->bit);
1931       feat_entry++;
1932     }
1933
1934     vlib_cli_output (vm, "\n");
1935
1936
1937     vlib_cli_output (vm, " socket filename %s type %s errno \"%s\"\n\n",
1938                          vui->sock_filename, vui->sock_is_server ? "server" : "client",
1939                          strerror(vui->sock_errno));
1940
1941     vlib_cli_output (vm, " Memory regions (total %d)\n", vui->nregions);
1942
1943     if (vui->nregions){
1944       vlib_cli_output(vm, " region fd    guest_phys_addr    memory_size        userspace_addr     mmap_offset        mmap_addr\n");
1945       vlib_cli_output(vm, " ====== ===== ================== ================== ================== ================== ==================\n");
1946     }
1947     for (j = 0; j < vui->nregions; j++) {
1948       vlib_cli_output(vm, "  %d     %-5d 0x%016lx 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n", j,
1949         vui->region_mmap_fd[j],
1950         vui->regions[j].guest_phys_addr,
1951         vui->regions[j].memory_size,
1952         vui->regions[j].userspace_addr,
1953         vui->regions[j].mmap_offset,
1954         pointer_to_uword( vui->region_mmap_addr[j]) );
1955     }
1956     for (q = 0; q < vui->num_vrings; q++) {
1957       vlib_cli_output(vm, "\n Virtqueue %d\n", q);
1958
1959       vlib_cli_output(vm, "  qsz %d last_avail_idx %d last_used_idx %d\n",
1960         vui->vrings[q].qsz,
1961         vui->vrings[q].last_avail_idx,
1962         vui->vrings[q].last_used_idx);
1963
1964       if (vui->vrings[q].avail && vui->vrings[q].used)
1965         vlib_cli_output(vm, "  avail.flags %x avail.idx %d used.flags %x used.idx %d\n",
1966           vui->vrings[q].avail->flags,
1967           vui->vrings[q].avail->idx,
1968           vui->vrings[q].used->flags,
1969           vui->vrings[q].used->idx);
1970
1971       vlib_cli_output(vm, "  kickfd %d callfd %d errfd %d\n",
1972         vui->vrings[q].kickfd,
1973         vui->vrings[q].callfd,
1974         vui->vrings[q].errfd);
1975
1976       if (show_descr) {
1977         vlib_cli_output(vm, "\n  descriptor table:\n");
1978         vlib_cli_output(vm, "   id          addr         len  flags  next      user_addr\n");
1979         vlib_cli_output(vm, "  ===== ================== ===== ====== ===== ==================\n");
1980         for(j = 0; j < vui->vrings[q].qsz; j++) {
1981           vlib_cli_output(vm, "  %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
1982             j,
1983             vui->vrings[q].desc[j].addr,
1984             vui->vrings[q].desc[j].len,
1985             vui->vrings[q].desc[j].flags,
1986             vui->vrings[q].desc[j].next,
1987             pointer_to_uword(map_guest_mem(vui, vui->vrings[q].desc[j].addr)));}
1988       }
1989     }
1990     vlib_cli_output (vm, "\n");
1991   }
1992 done:
1993   vec_free (hw_if_indices);
1994   return error;
1995 }
1996
1997 static clib_error_t *
1998 vhost_user_config (vlib_main_t * vm, unformat_input_t * input)
1999 {
2000   vhost_user_main_t * vum = &vhost_user_main;
2001
2002   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2003     {
2004       if (unformat (input, "coalesce-frames %d", &vum->coalesce_frames))
2005         ;
2006       else if (unformat (input, "coalesce-time %f", &vum->coalesce_time))
2007         ;
2008       else if (unformat (input, "dont-dump-memory"))
2009         vum->dont_dump_vhost_user_memory = 1;
2010       else
2011         return clib_error_return (0, "unknown input `%U'",
2012                                   format_unformat_error, input);
2013     }
2014
2015   return 0;
2016 }
2017
2018 /* vhost-user { ... } configuration. */
2019 VLIB_CONFIG_FUNCTION (vhost_user_config, "vhost-user");
2020
2021 void
2022 vhost_user_unmap_all (void)
2023 {
2024   vhost_user_main_t * vum = &vhost_user_main;
2025   vhost_user_intf_t * vui;
2026
2027   if (vum->dont_dump_vhost_user_memory)
2028     {
2029       vec_foreach (vui, vum->vhost_user_interfaces)
2030         {
2031           unmap_all_mem_regions(vui);
2032         }
2033     }
2034 }