dpdk: fix rte_delay_us callback issue
[vpp.git] / vpp / vnet / main.c
index f6d21a6..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;
+
+  /* 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
-vpe_main_init (vlib_main_t * vm)
+rte_delay_us_override_cb (unsigned us)
 {
-    if (CLIB_DEBUG > 0)
-        vlib_unix_cli_set_prompt ("DBGvpp# ");
-    else
-        vlib_unix_cli_set_prompt ("vpp# ");
+  if (rte_delay_us_override (us) == 0)
+    rte_delay_us_block (us);
+}
+#endif
 
-    /* Turn off network stack components which we don't want */
-    vlib_mark_init_function_complete (vm, srp_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;
-    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);
+  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__
-    __builtin_cpu_init ();
-    const char * msg = "ERROR: This binary requires CPU with %s extensions.\n";
-#define _(a,b) \
-    if (!__builtin_cpu_supports(a))    \
-      {                                        \
-       fprintf(stderr, msg, b);        \
-       exit(1);                        \
+  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")
+  _(avx2, "AVX2")
 #endif
 #if __AVX__
-      _("avx", "AVX")
+    _(avx, "AVX")
 #endif
 #if __SSE4_2__
-      _("sse4.2", "SSE4.2")
+    _(sse42, "SSE4.2")
 #endif
 #if __SSE4_1__
-      _("sse4.1", "SSE4.1")
+    _(sse41, "SSE4.1")
 #endif
 #if __SSSE3__
-      _("ssse3", "SSSE3")
+    _(ssse3, "SSSE3")
 #endif
 #if __SSE3__
-      _("sse3", "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_;
-      }
-
-    /* 
-     * Look for and parse the "heapsize" config parameter.
-     * Manual since none of the clib infra has been bootstrapped yet.
-     *
-     * Format: heapsize <nn>[mM][gG] 
-     */
+    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)) {
-        vm->init_functions_called = hash_create (0, /* value bytes */ 0);
-        vpe_main_init(vm);
-#if ! DPDK
-        unix_physmem_init(vm, 0 /* fail_if_physical_memory_not_present */);
+  /* 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 {
+      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");
@@ -233,68 +301,78 @@ 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'
@@ -305,10 +383,9 @@ u32 vlib_app_num_thread_stacks_needed (void)
 
 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;
 
@@ -316,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:
+ */