dpdk: fix rte_delay_us callback issue
[vpp.git] / vpp / vnet / main.c
index 09adfea..6dac33c 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <vppinfra/cpu.h>
 #include <vlib/vlib.h>
 #include <vlib/unix/unix.h>
 #include <vnet/plugin/plugin.h>
 #include <vnet/ethernet/ethernet.h>
 
-#include <api/vpe_msg_enum.h>
+#include <vpp-api/vpe_msg_enum.h>
 
-/** \mainpage Virtual Packet Edge Documentation
- * \section intro_sec Introduction
- * 
- * VPE is a specific vector packet processing application,
- * designed to steer packets to/from tenant virtual machines.
- *
+#if DPDK
+#include <vnet/devices/dpdk/dpdk.h>
+
+/*
+ * Called by the dpdk driver's rte_delay_us() function.
+ * Return 0 to have the dpdk do a regular delay loop.
+ * Return 1 if to skip the delay loop because we are suspending
+ * the calling vlib process instead.
  */
+int
+rte_delay_us_override (unsigned us)
+{
+  vlib_main_t *vm;
 
-static clib_error_t *
-vpe_main_init (vlib_main_t * vm)
+  /* Don't bother intercepting for short delays */
+  if (us < 10)
+    return 0;
+
+  /*
+   * Only intercept if we are in a vlib process.
+   * If we are called from a vlib worker thread or the vlib main
+   * thread then do not intercept. (Must not be called from an
+   * independent pthread).
+   */
+  if (os_get_cpu_number () == 0)
+    {
+      /*
+       * We're in the vlib main thread or a vlib process. Make sure
+       * the process is running and we're not still initializing.
+       */
+      vm = vlib_get_main ();
+      if (vlib_in_process_context (vm))
+       {
+         /* Only suspend for the admin_down_process */
+         vlib_process_t *proc = vlib_get_current_process (vm);
+         if (!(proc->flags & VLIB_PROCESS_IS_RUNNING) ||
+             (proc->node_runtime.function != admin_up_down_process))
+           return 0;
+
+         f64 delay = 1e-6 * us;
+         vlib_process_suspend (vm, delay);
+         return 1;
+       }
+    }
+  return 0;                    // no override
+}
+
+static void
+rte_delay_us_override_cb (unsigned us)
 {
-    clib_error_t * error = 0;
-    void vnet_library_plugin_reference(void);
-
-    if (CLIB_DEBUG > 0)
-        vlib_unix_cli_set_prompt ("DBGvpp# ");
-    else
-        vlib_unix_cli_set_prompt ("vpp# ");
-
-    vnet_library_plugin_reference();
-
-    if ((error = vlib_call_init_function (vm, pg_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, ip_main_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, osi_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, l2_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, ethernet_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, ethernet_arp_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, sr_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, map_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, sixrd_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, nsh_gre_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, nsh_vxlan_gpe_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
-       return error;
-
-#if DPDK == 1
-    if ((error = vlib_call_init_function (vm, dpdk_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, dpdk_thread_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, vhost_user_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, ipsec_init)))
-        return error;
-#endif    
-    if ((error = vlib_call_init_function (vm, vlibmemory_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, l2tp_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, gre_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, gre_interface_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, mpls_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, mpls_interface_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, dhcp_proxy_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, dhcpv6_proxy_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, tapcli_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, tuntap_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, gdb_func_init)))
-        return error;
-    if ((error = unix_physmem_init
-        (vm, 0 /* fail_if_physical_memory_not_present */)))
-        return error;
-    if ((error = vlib_call_init_function (vm, tuntap_init)))
-       return error;
-    if ((error = vlib_call_init_function (vm, sr_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, l2_classify_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, policer_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, vxlan_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, vcgn_init)))
-        return error;
-    if ((error = vlib_call_init_function (vm, li_init)))
-        return error;
-
-    return error;
+  if (rte_delay_us_override (us) == 0)
+    rte_delay_us_block (us);
 }
+#endif
 
-VLIB_INIT_FUNCTION (vpe_main_init);
+static void
+vpe_main_init (vlib_main_t * vm)
+{
+  if (CLIB_DEBUG > 0)
+    vlib_unix_cli_set_prompt ("DBGvpp# ");
+  else
+    vlib_unix_cli_set_prompt ("vpp# ");
+
+  /* Turn off network stack components which we don't want */
+  vlib_mark_init_function_complete (vm, srp_init);
+
+#if DPDK
+#if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0)
+  /* register custom delay function */
+  rte_delay_us_callback_register (rte_delay_us_override_cb);
+#endif
+#endif
+}
 
-/* 
+/*
  * Load plugins from /usr/lib/vpp_plugins by default
  */
 char *vlib_plugin_path = "/usr/lib/vpp_plugins";
-                                                
-void *vnet_get_handoff_structure (void)
+
+void *
+vnet_get_handoff_structure (void)
 {
-    static vnet_plugin_handoff_t _rv, *rv = &_rv;
+  static vnet_plugin_handoff_t _rv, *rv = &_rv;
 
-    rv->vnet_main = vnet_get_main();
-    rv->ethernet_main = &ethernet_main;
-    return (void *)rv;
+  rv->vnet_main = vnet_get_main ();
+  rv->ethernet_main = &ethernet_main;
+  return (void *) rv;
 }
 
-int main (int argc, char * argv[])
+int
+main (int argc, char *argv[])
 {
-    int i;
-    void vl_msg_api_set_first_available_msg_id (u16);
-    uword main_heap_size = (1ULL << 30);
-    u8 * sizep;
-    u32 size;
-    void vlib_set_get_handoff_structure_cb (void *cb);
-
-    /* 
-     * Look for and parse the "heapsize" config parameter.
-     * Manual since none of the clib infra has been bootstrapped yet.
-     *
-     * Format: heapsize <nn>[mM][gG] 
+  int i;
+  vlib_main_t *vm = &vlib_global_main;
+  void vl_msg_api_set_first_available_msg_id (u16);
+  uword main_heap_size = (1ULL << 30);
+  u8 *sizep;
+  u32 size;
+  void vlib_set_get_handoff_structure_cb (void *cb);
+
+#if __x86_64__
+  const char *msg = "ERROR: This binary requires CPU with %s extensions.\n";
+#define _(a,b)                                  \
+    if (!clib_cpu_supports_ ## a ())            \
+      {                                         \
+       fprintf(stderr, msg, b);                \
+       exit(1);                                \
+      }
+
+#if __AVX2__
+  _(avx2, "AVX2")
+#endif
+#if __AVX__
+    _(avx, "AVX")
+#endif
+#if __SSE4_2__
+    _(sse42, "SSE4.2")
+#endif
+#if __SSE4_1__
+    _(sse41, "SSE4.1")
+#endif
+#if __SSSE3__
+    _(ssse3, "SSSE3")
+#endif
+#if __SSE3__
+    _(sse3, "SSE3")
+#endif
+#undef _
+#endif
+    /*
+     * Load startup config from file.
+     * usage: vpp -c /etc/vpp/startup.conf
      */
+    if ((argc == 3) && !strncmp (argv[1], "-c", 2))
+    {
+      FILE *fp;
+      char inbuf[4096];
+      int argc_ = 1;
+      char **argv_ = NULL;
+      char *arg = NULL;
+      char *p;
+
+      fp = fopen (argv[2], "r");
+      if (fp == NULL)
+       {
+         fprintf (stderr, "open configuration file '%s' failed\n", argv[2]);
+         return 1;
+       }
+      argv_ = calloc (1, sizeof (char *));
+      if (argv_ == NULL)
+       return 1;
+      arg = strndup (argv[0], 1024);
+      if (arg == NULL)
+       return 1;
+      argv_[0] = arg;
+
+      while (1)
+       {
+         if (fgets (inbuf, 4096, fp) == 0)
+           break;
+         p = strtok (inbuf, " \t\n");
+         while (p != NULL)
+           {
+             if (*p == '#')
+               break;
+             argc_++;
+             char **tmp = realloc (argv_, argc_ * sizeof (char *));
+             if (tmp == NULL)
+               return 1;
+             argv_ = tmp;
+             arg = strndup (p, 1024);
+             if (arg == NULL)
+               return 1;
+             argv_[argc_ - 1] = arg;
+             p = strtok (NULL, " \t\n");
+           }
+       }
+
+      fclose (fp);
+
+      char **tmp = realloc (argv_, (argc_ + 1) * sizeof (char *));
+      if (tmp == NULL)
+       return 1;
+      argv_ = tmp;
+      argv_[argc_] = NULL;
+
+      argc = argc_;
+      argv = argv_;
+    }
 
-    for (i = 1; i < (argc-1); i++) {
-        if (!strncmp (argv[i], "plugin_path", 11)) {
-            if (i < (argc-1))
-                vlib_plugin_path = argv[++i];
-        } else if (!strncmp (argv[i], "heapsize", 8)) {
-            sizep = (u8 *) argv[i+1];
-            size = 0;
-            while (*sizep >= '0' && *sizep <= '9') {
-                size *= 10;
-                size += *sizep++ - '0';
-            }
-            if (size == 0) {
-                fprintf
-                    (stderr, 
-                     "warning: heapsize parse error '%s', use default %lld\n",
-                     argv[i], (long long int) main_heap_size);
-                goto defaulted;
-            }
-
-            main_heap_size = size;
-            
-            if (*sizep == 'g' || *sizep == 'G')
-                main_heap_size <<= 30;
-            else if (*sizep == 'm' || *sizep == 'M')
-                main_heap_size <<= 20;
-        }
+  /*
+   * Look for and parse the "heapsize" config parameter.
+   * Manual since none of the clib infra has been bootstrapped yet.
+   *
+   * Format: heapsize <nn>[mM][gG]
+   */
+
+  for (i = 1; i < (argc - 1); i++)
+    {
+      if (!strncmp (argv[i], "plugin_path", 11))
+       {
+         if (i < (argc - 1))
+           vlib_plugin_path = argv[++i];
+       }
+      else if (!strncmp (argv[i], "heapsize", 8))
+       {
+         sizep = (u8 *) argv[i + 1];
+         size = 0;
+         while (*sizep >= '0' && *sizep <= '9')
+           {
+             size *= 10;
+             size += *sizep++ - '0';
+           }
+         if (size == 0)
+           {
+             fprintf
+               (stderr,
+                "warning: heapsize parse error '%s', use default %lld\n",
+                argv[i], (long long int) main_heap_size);
+             goto defaulted;
+           }
+
+         main_heap_size = size;
+
+         if (*sizep == 'g' || *sizep == 'G')
+           main_heap_size <<= 30;
+         else if (*sizep == 'm' || *sizep == 'M')
+           main_heap_size <<= 20;
+       }
     }
-            
+
 defaulted:
 
-    /* Set up the plugin message ID allocator right now... */
-    vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
+  /* Set up the plugin message ID allocator right now... */
+  vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
 
-    /* Allocate main heap */
-    if (clib_mem_init (0, main_heap_size)) {
-        vlib_set_get_handoff_structure_cb (&vnet_get_handoff_structure);
-        return vlib_unix_main (argc, argv);
-    } else {
+  /* Allocate main heap */
+  if (clib_mem_init (0, main_heap_size))
+    {
+      vm->init_functions_called = hash_create (0, /* value bytes */ 0);
+      vpe_main_init (vm);
+#if DPDK == 0
+      unix_physmem_init (vm, 0 /* fail_if_physical_memory_not_present */ );
+#endif
+      vlib_set_get_handoff_structure_cb (&vnet_get_handoff_structure);
+      return vlib_unix_main (argc, argv);
+    }
+  else
+    {
       {
-       int rv __attribute__((unused)) =
+       int rv __attribute__ ((unused)) =
          write (2, "Main heap allocation failure!\r\n", 31);
       }
-        return 1;
+      return 1;
     }
 }
 
 static clib_error_t *
 heapsize_config (vlib_main_t * vm, unformat_input_t * input)
 {
-    u32 junk;
-
-    while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
-        if (unformat (input, "%dm", &junk)
-            || unformat (input, "%dM", &junk)
-            || unformat (input, "%dg", &junk)
-            || unformat (input, "%dG", &junk))
-            return 0;
-        else
-            return clib_error_return (0, "unknown input '%U'",
-                                      format_unformat_error, input);
+  u32 junk;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "%dm", &junk)
+         || unformat (input, "%dM", &junk)
+         || unformat (input, "%dg", &junk) || unformat (input, "%dG", &junk))
+       return 0;
+      else
+       return clib_error_return (0, "unknown input '%U'",
+                                 format_unformat_error, input);
     }
-    return 0;
+  return 0;
 }
 
 VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize");
@@ -219,75 +301,91 @@ VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize");
 static clib_error_t *
 plugin_path_config (vlib_main_t * vm, unformat_input_t * input)
 {
-    u8 * junk;
-
-    while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
-        if (unformat (input, "%s", &junk)) {
-            vec_free(junk);
-            return 0;
-        }
-        else
-            return clib_error_return (0, "unknown input '%U'",
-                                      format_unformat_error, input);
-        }
-    return 0;
+  u8 *junk;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "%s", &junk))
+       {
+         vec_free (junk);
+         return 0;
+       }
+      else
+       return clib_error_return (0, "unknown input '%U'",
+                                 format_unformat_error, input);
+    }
+  return 0;
 }
 
 VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path");
 
-void vl_msg_api_post_mortem_dump(void);
+void vl_msg_api_post_mortem_dump (void);
 
-void os_panic (void) 
-{ 
-    vl_msg_api_post_mortem_dump();
-    abort (); 
+void
+os_panic (void)
+{
+  vl_msg_api_post_mortem_dump ();
+  abort ();
 }
 
-void vhost_user_unmap_all (void) __attribute__((weak));
-void vhost_user_unmap_all (void) { }
+void vhost_user_unmap_all (void) __attribute__ ((weak));
+void
+vhost_user_unmap_all (void)
+{
+}
 
-void os_exit (int code)
-{ 
-    static int recursion_block;
+void
+os_exit (int code)
+{
+  static int recursion_block;
 
-    if (code)
-      {
-        if (recursion_block)
-            abort();
+  if (code)
+    {
+      if (recursion_block)
+       abort ();
 
-        recursion_block = 1;
+      recursion_block = 1;
 
-        vl_msg_api_post_mortem_dump();
-        vhost_user_unmap_all();
-        abort();
-      }
-    exit (code);
+      vl_msg_api_post_mortem_dump ();
+      vhost_user_unmap_all ();
+      abort ();
+    }
+  exit (code);
 }
 
-void vl_msg_api_barrier_sync(void) 
-{ 
-  vlib_worker_thread_barrier_sync (vlib_get_main());
+void
+vl_msg_api_barrier_sync (void)
+{
+  vlib_worker_thread_barrier_sync (vlib_get_main ());
 }
 
-void vl_msg_api_barrier_release(void) 
-{ 
-  vlib_worker_thread_barrier_release (vlib_get_main());
+void
+vl_msg_api_barrier_release (void)
+{
+  vlib_worker_thread_barrier_release (vlib_get_main ());
 }
 
 /* This application needs 1 thread stack for the stats pthread */
-u32 vlib_app_num_thread_stacks_needed (void) 
+u32
+vlib_app_num_thread_stacks_needed (void)
 {
   return 1;
 }
 
+/*
+ * Depending on the configuration selected above,
+ * it may be necessary to generate stub graph nodes.
+ * It is never OK to ignore "node 'x' refers to unknown node 'y'
+ * messages!
+ */
+
 #if CLIB_DEBUG > 0
 
 static clib_error_t *
 test_crash_command_fn (vlib_main_t * vm,
-                       unformat_input_t * input,
-                       vlib_cli_command_t * cmd)
+                      unformat_input_t * input, vlib_cli_command_t * cmd)
 {
-  u64 * p = (u64 *)0xdefec8ed;
+  u64 *p = (u64 *) 0xdefec8ed;
 
   *p = 0xdeadbeef;
 
@@ -295,11 +393,20 @@ test_crash_command_fn (vlib_main_t * vm,
   return 0;
 }
 
+/* *INDENT-OFF* */
 VLIB_CLI_COMMAND (test_crash_command, static) = {
-    .path = "test crash",
-    .short_help = "crash the bus!",
-    .function = test_crash_command_fn,
+  .path = "test crash",
+  .short_help = "crash the bus!",
+  .function = test_crash_command_fn,
 };
+/* *INDENT-ON* */
 
 #endif
 
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */