MTU: Software interface / Per-protocol MTU support
[vpp.git] / src / vnet / devices / virtio / vhost-user.c
index c782040..9244776 100644 (file)
  */
 #define VHOST_USER_TX_COPY_THRESHOLD (VHOST_USER_COPY_ARRAY_N - 40)
 
-#define UNIX_GET_FD(unixfd_idx) \
-    (unixfd_idx != ~0) ? \
+#define UNIX_GET_FD(unixfd_idx) ({ \
+    typeof(unixfd_idx) __unixfd_idx = (unixfd_idx); \
+    (__unixfd_idx != ~0) ? \
        pool_elt_at_index (file_main.file_pool, \
-                          unixfd_idx)->file_descriptor : -1;
+                          __unixfd_idx)->file_descriptor : -1; })
 
 #define foreach_virtio_trace_flags \
   _ (SIMPLE_CHAINED, 0, "Simple descriptor chaining") \
@@ -247,8 +248,8 @@ map_guest_mem (vhost_user_intf_t * vui, uword addr, u32 * hint)
   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x88);
 
   r = _mm_shuffle_epi8 (r, _mm_set_epi64x (0, 0x0e060c040a020800));
-  i = __builtin_ctzll (_mm_movemask_epi8 (r) |
-                      (1 << VHOST_MEMORY_MAX_NREGIONS));
+  i = count_trailing_zeros (_mm_movemask_epi8 (r) |
+                           (1 << VHOST_MEMORY_MAX_NREGIONS));
 
   if (i < vui->nregions)
     {
@@ -256,7 +257,76 @@ map_guest_mem (vhost_user_intf_t * vui, uword addr, u32 * hint)
       return (void *) (vui->region_mmap_addr[i] + addr -
                       vui->regions[i].guest_phys_addr);
     }
+#elif __aarch64__ && __ARM_NEON
+  uint64x2_t al, ah, rl, rh, r;
+  uint32_t u32 = 0;
 
+  al = vdupq_n_u64 (addr + 1);
+  ah = vdupq_n_u64 (addr);
+
+  /*First Iteration */
+  rl = vld1q_u64 (&vui->region_guest_addr_lo[0]);
+  rl = vcgtq_u64 (al, rl);
+  rh = vld1q_u64 (&vui->region_guest_addr_hi[0]);
+  rh = vcgtq_u64 (rh, ah);
+  r = vandq_u64 (rl, rh);
+  u32 |= (vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1);
+  u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 1);
+
+  if (u32)
+    {
+      i = count_trailing_zeros (u32);
+      goto vhost_map_guest_mem_done;
+    }
+
+  /*Second Iteration */
+  rl = vld1q_u64 (&vui->region_guest_addr_lo[2]);
+  rl = vcgtq_u64 (al, rl);
+  rh = vld1q_u64 (&vui->region_guest_addr_hi[2]);
+  rh = vcgtq_u64 (rh, ah);
+  r = vandq_u64 (rl, rh);
+  u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1) << 2);
+  u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 3);
+
+  if (u32)
+    {
+      i = count_trailing_zeros (u32);
+      goto vhost_map_guest_mem_done;
+    }
+
+  /*Third Iteration */
+  rl = vld1q_u64 (&vui->region_guest_addr_lo[4]);
+  rl = vcgtq_u64 (al, rl);
+  rh = vld1q_u64 (&vui->region_guest_addr_hi[4]);
+  rh = vcgtq_u64 (rh, ah);
+  r = vandq_u64 (rl, rh);
+  u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1) << 4);
+  u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 5);
+
+  if (u32)
+    {
+      i = count_trailing_zeros (u32);
+      goto vhost_map_guest_mem_done;
+    }
+
+  /*Fourth Iteration */
+  rl = vld1q_u64 (&vui->region_guest_addr_lo[6]);
+  rl = vcgtq_u64 (al, rl);
+  rh = vld1q_u64 (&vui->region_guest_addr_hi[6]);
+  rh = vcgtq_u64 (rh, ah);
+  r = vandq_u64 (rl, rh);
+  u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1) << 6);
+  u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 7);
+
+  i = count_trailing_zeros (u32 | (1 << VHOST_MEMORY_MAX_NREGIONS));
+
+vhost_map_guest_mem_done:
+  if (i < vui->nregions)
+    {
+      *hint = i;
+      return (void *) (vui->region_mmap_addr[i] + addr -
+                      vui->regions[i].guest_phys_addr);
+    }
 #else
   for (i = 0; i < vui->nregions; i++)
     {
@@ -306,7 +376,7 @@ unmap_all_mem_regions (vhost_user_intf_t * vui)
   int i, r;
   for (i = 0; i < vui->nregions; i++)
     {
-      if (vui->region_mmap_addr[i] != (void *) -1)
+      if (vui->region_mmap_addr[i] != MAP_FAILED)
        {
 
          long page_sz = get_huge_page_size (vui->region_mmap_fd[i]);
@@ -323,7 +393,7 @@ unmap_all_mem_regions (vhost_user_intf_t * vui)
            ("unmap memory region %d addr 0x%lx len 0x%lx page_sz 0x%x", i,
             vui->region_mmap_addr[i], map_sz, page_sz);
 
-         vui->region_mmap_addr[i] = (void *) -1;
+         vui->region_mmap_addr[i] = MAP_FAILED;
 
          if (r == -1)
            {
@@ -829,7 +899,7 @@ vhost_user_socket_read (clib_file_t * uf)
 
          long page_sz = get_huge_page_size (fds[i]);
 
-         /* align size to 2M page */
+         /* align size to page */
          ssize_t map_sz = (vui->regions[i].memory_size +
                            vui->regions[i].mmap_offset +
                            page_sz - 1) & ~(page_sz - 1);
@@ -1076,7 +1146,7 @@ vhost_user_socket_read (clib_file_t * uf)
          }
 
        fd = fds[0];
-       /* align size to 2M page */
+       /* align size to page */
        long page_sz = get_huge_page_size (fd);
        ssize_t map_sz =
          (msg.log.size + msg.log.offset + page_sz - 1) & ~(page_sz - 1);
@@ -1213,7 +1283,15 @@ vhost_user_socksvr_accept_ready (clib_file_t * uf)
   if (client_fd < 0)
     return clib_error_return_unix (0, "accept");
 
-  DBG_SOCK ("New client socket for vhost interface %d", vui->sw_if_index);
+  if (vui->clib_file_index != ~0)
+    {
+      DBG_SOCK ("Close client socket for vhost interface %d, fd %d",
+               vui->sw_if_index, UNIX_GET_FD (vui->clib_file_index));
+      clib_file_del (&file_main, file_main.file_pool + vui->clib_file_index);
+    }
+
+  DBG_SOCK ("New client socket for vhost interface %d, fd %d",
+           vui->sw_if_index, client_fd);
   template.read_function = vhost_user_socket_read;
   template.error_function = vhost_user_socket_error;
   template.file_descriptor = client_fd;
@@ -2470,16 +2548,14 @@ vhost_user_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
                                    u32 flags)
 {
   vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
-  uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
   vhost_user_main_t *vum = &vhost_user_main;
   vhost_user_intf_t *vui =
     pool_elt_at_index (vum->vhost_user_interfaces, hif->dev_instance);
+  u32 hw_flags = 0;
+  vui->admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
+  hw_flags = vui->admin_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
 
-  vui->admin_up = is_up;
-
-  if (is_up && vui->is_up)
-    vnet_hw_interface_set_flags (vnm, vui->hw_if_index,
-                                VNET_HW_INTERFACE_FLAG_LINK_UP);
+  vnet_hw_interface_set_flags (vnm, vui->hw_if_index, hw_flags);
 
   return /* no error */ 0;
 }
@@ -2791,8 +2867,7 @@ vhost_user_create_ethernet (vnet_main_t * vnm, vlib_main_t * vm,
   if (error)
     clib_error_report (error);
 
-  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, vui->hw_if_index);
-  hi->max_l3_packet_bytes[VLIB_RX] = hi->max_l3_packet_bytes[VLIB_TX] = 9000;
+  vnet_sw_interface_set_mtu (vnm, vui->sw_if_index, 9000);
 }
 
 /*
@@ -3175,6 +3250,13 @@ show_vhost_user_command_fn (vlib_main_t * vm,
       if (unformat
          (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
        {
+         hi = vnet_get_hw_interface (vnm, hw_if_index);
+         if (vhost_user_dev_class.index != hi->dev_class_index)
+           {
+             error = clib_error_return (0, "unknown input `%U'",
+                                        format_unformat_error, input);
+             goto done;
+           }
          vec_add1 (hw_if_indices, hw_if_index);
        }
       else if (unformat (input, "descriptors") || unformat (input, "desc"))
@@ -3355,16 +3437,23 @@ done:
  *
  * There are several parameters associated with a vHost interface:
  *
- * - <b>socket <socket-filename></b> - Name of the linux socket used by QEMU/VM and
- * VPP to manage the vHost interface. If socket does not already exist, VPP will
- * create the socket.
+ * - <b>socket <socket-filename></b> - Name of the linux socket used by hypervisor
+ * and VPP to manage the vHost interface. If in '<em>server</em>' mode, VPP will
+ * create the socket if it does not already exist. If in '<em>client</em>' mode,
+ * hypervisor will create the socket if it does not already exist. The VPP code
+ * is indifferent to the file location. However, if SELinux is enabled, then the
+ * socket needs to be created in '<em>/var/run/vpp/</em>'.
  *
- * - <b>server</b> - Optional flag to indicate that VPP should be the server for the
- * linux socket. If not provided, VPP will be the client.
+ * - <b>server</b> - Optional flag to indicate that VPP should be the server for
+ * the linux socket. If not provided, VPP will be the client. In '<em>server</em>'
+ *  mode, the VM can be reset without tearing down the vHost Interface. In
+ * '<em>client</em>' mode, VPP can be reset without bringing down the VM and
+ * tearing down the vHost Interface.
  *
  * - <b>feature-mask <hex></b> - Optional virtio/vhost feature set negotiated at
- * startup. By default, all supported features will be advertised. Otherwise,
- * provide the set of features desired.
+ * startup. <b>This is intended for degugging only.</b> It is recommended that this
+ * parameter not be used except by experienced users. By default, all supported
+ * features will be advertised. Otherwise, provide the set of features desired.
  *   - 0x000008000 (15) - VIRTIO_NET_F_MRG_RXBUF
  *   - 0x000020000 (17) - VIRTIO_NET_F_CTRL_VQ
  *   - 0x000200000 (21) - VIRTIO_NET_F_GUEST_ANNOUNCE
@@ -3382,17 +3471,14 @@ done:
  * in the name to be specified. If instance already exists, name will be used
  * anyway and multiple instances will have the same name. Use with caution.
  *
- * - <b>mode [interrupt | polling]</b> - Optional parameter specifying
- * the input thread polling policy.
- *
  * @cliexpar
  * Example of how to create a vhost interface with VPP as the client and all features enabled:
- * @cliexstart{create vhost-user socket /tmp/vhost1.sock}
+ * @cliexstart{create vhost-user socket /var/run/vpp/vhost1.sock}
  * VirtualEthernet0/0/0
  * @cliexend
  * Example of how to create a vhost interface with VPP as the server and with just
  * multiple queues enabled:
- * @cliexstart{create vhost-user socket /tmp/vhost2.sock server feature-mask 0x40400000}
+ * @cliexstart{create vhost-user socket /var/run/vpp/vhost2.sock server feature-mask 0x40400000}
  * VirtualEthernet0/0/1
  * @cliexend
  * Once the vHost interface is created, enable the interface using:
@@ -3451,7 +3537,7 @@ VLIB_CLI_COMMAND (vhost_user_delete_command, static) = {
  *    VHOST_USER_PROTOCOL_F_MQ (0)
  *    VHOST_USER_PROTOCOL_F_LOG_SHMFD (1)
  *
- *  socket filename /tmp/vhost1.sock type client errno "Success"
+ *  socket filename /var/run/vpp/vhost1.sock type client errno "Success"
  *
  * rx placement:
  *    thread 1 on vring 1