Add support for multiple microarchitectures in single binary 75/1075/6
authorDamjan Marion <damarion@cisco.com>
Wed, 11 May 2016 21:07:18 +0000 (23:07 +0200)
committerDamjan Marion <damarion@cisco.com>
Thu, 19 May 2016 16:14:38 +0000 (18:14 +0200)
 * compiler -march= parameter is changed from native to corei7
   so code is always genereted with instructions which are available
   on the Nehalem microarchitecture (up to SSE4.2)

 * compiler -mtune= parameter is added so code is optimized for
   corei7-avx which equals to Sandy Bridge microarchitecture

 * set of macros is added which allows run-time detection of available
   cpu instructions (e.g. clib_cpu_supports_avx())

 * set of macros is added which allows us to clone graph node funcitons
   where cloned function is optmized for different microarchitecture
   Those macros are using following attributes:
     __attribute__((flatten))
     __attribute__((target("arch=core-avx2)))

   I.e. If applied to foo_node_fn() macro will generate cloned
   functions foo_node_fn_avx2() and foo_node_fn_avx512() (future)
   It will also generate function void * foo_node_fn_multiarch_select()
   which detects available instruction set and returns pointer to the
   best matching function clone.

Change-Id: I2dce0ac92a5ede95fcb56f47f3d1f3c4c040bac0
Signed-off-by: Damjan Marion <damarion@cisco.com>
72 files changed:
build-data/packages/dpdk.mk
build-data/platforms/vpp.mk
build-data/platforms/vpp_lite.mk
build-root/Makefile
dpdk/Makefile
vlib/vlib/node.h
vnet/vnet/classify/ip_classify.c
vnet/vnet/cop/ip4_whitelist.c
vnet/vnet/cop/ip6_whitelist.c
vnet/vnet/cop/node1.c
vnet/vnet/devices/af_packet/device.c
vnet/vnet/devices/af_packet/node.c
vnet/vnet/devices/dpdk/cli.c
vnet/vnet/devices/dpdk/device.c
vnet/vnet/devices/dpdk/dpdk.h
vnet/vnet/devices/dpdk/init.c
vnet/vnet/devices/dpdk/node.c
vnet/vnet/devices/netmap/device.c
vnet/vnet/devices/netmap/node.c
vnet/vnet/devices/ssvm/node.c
vnet/vnet/devices/ssvm/ssvm_eth.c
vnet/vnet/devices/virtio/vhost-user.c
vnet/vnet/ethernet/node.c
vnet/vnet/gre/gre.c
vnet/vnet/gre/node.c
vnet/vnet/interface.h
vnet/vnet/interface_output.c
vnet/vnet/ip/ip4_forward.c
vnet/vnet/ip/ip4_hop_by_hop.c
vnet/vnet/ip/ip4_input.c
vnet/vnet/ip/ip4_source_check.c
vnet/vnet/ip/ip6_forward.c
vnet/vnet/ip/ip6_hop_by_hop.c
vnet/vnet/ip/ip6_input.c
vnet/vnet/ip/ip_input_acl.c
vnet/vnet/ip/udp_local.c
vnet/vnet/ipsec/esp_decrypt.c
vnet/vnet/ipsec/esp_encrypt.c
vnet/vnet/ipsec/ipsec_if_in.c
vnet/vnet/ipsec/ipsec_if_out.c
vnet/vnet/ipsec/ipsec_input.c
vnet/vnet/ipsec/ipsec_output.c
vnet/vnet/l2/l2_classify.c
vnet/vnet/l2/l2_efp_filter.c
vnet/vnet/l2/l2_flood.c
vnet/vnet/l2/l2_fwd.c
vnet/vnet/l2/l2_input.c
vnet/vnet/l2/l2_input_acl.c
vnet/vnet/l2/l2_input_vtr.c
vnet/vnet/l2/l2_learn.c
vnet/vnet/l2/l2_output.c
vnet/vnet/l2/l2_output_acl.c
vnet/vnet/l2/l2_patch.c
vnet/vnet/l2/l2_rw.c
vnet/vnet/l2/l2_xcrw.c
vnet/vnet/l2tp/decap.c
vnet/vnet/l2tp/encap.c
vnet/vnet/lawful-intercept/node.c
vnet/vnet/mpls-gre/interface.c
vnet/vnet/mpls-gre/node.c
vnet/vnet/mpls-gre/policy_encap.c
vnet/vnet/policer/node_funcs.c
vnet/vnet/sr/sr.c
vnet/vnet/sr/sr_replicate.c
vnet/vnet/vxlan/decap.c
vnet/vnet/vxlan/encap.c
vpp/app/l2t_ip6.c
vpp/app/l2t_l2.c
vpp/app/version.c
vpp/vnet/main.c
vppinfra/vppinfra/cpu.c
vppinfra/vppinfra/cpu.h

index 2bfc4b4..0a4c161 100644 (file)
@@ -4,6 +4,11 @@ ifeq ($(DPDK_MARCH),)
        DPDK_MARCH="native"
 endif
 
+DPDK_TUNE = $(strip $($(PLATFORM)_mtune))
+ifeq ($(DPDK_TUNE),)
+       DPDK_MARCH="generic"
+endif
+
 ifneq (,$(findstring debug,$(TAG)))
        DPDK_DEBUG=y
 else
@@ -14,6 +19,7 @@ DPDK_MAKE_ARGS = -C $(call find_source_fn,$(PACKAGE_SOURCE)) \
        DPDK_BUILD_DIR=$(PACKAGE_BUILD_DIR) \
        DPDK_INSTALL_DIR=$(PACKAGE_INSTALL_DIR) \
        DPDK_MARCH=$(DPDK_MARCH) \
+       DPDK_TUNE=$(DPDK_TUNE) \
        DPDK_DEBUG=$(DPDK_DEBUG)
 
 
index c381be1..ec0d874 100644 (file)
@@ -13,6 +13,9 @@
 
 # vector packet processor
 vpp_arch = native
+vpp_march = corei7                     # Nehalem Instruction set
+vpp_mtune = corei7-avx                 # Optimize for Sandy Bridge
+vpp_dpdk_arch = corei7
 vpp_native_tools = vppapigen
 
 vpp_uses_dpdk = yes
@@ -40,9 +43,9 @@ vpp_debug_TAG_CFLAGS = -g -O0 -DCLIB_DEBUG -DFORTIFY_SOURCE=2 -march=$(MARCH) \
 vpp_debug_TAG_LDFLAGS = -g -O0 -DCLIB_DEBUG -DFORTIFY_SOURCE=2 -march=$(MARCH) \
        -fstack-protector-all -fPIC -Werror
 
-vpp_TAG_CFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) \
+vpp_TAG_CFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) -mtune=$(MTUNE) \
        -fstack-protector -fPIC -Werror
-vpp_TAG_LDFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) \
+vpp_TAG_LDFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) -mtune=$(MTUNE) \
        -fstack-protector -fPIC -Werror
 
 vpp_gcov_TAG_CFLAGS = -g -O0 -DCLIB_DEBUG -march=$(MARCH) \
index 4183700..d35d234 100644 (file)
@@ -13,6 +13,8 @@
 
 # vector packet processor
 vpp_lite_arch = native
+vpp_lite_march = corei7                                # Nehalem Instruction set
+vpp_lite_mtune = corei7-avx                    # Optimize for Sandy Bridge
 vpp_lite_native_tools = vppapigen
 
 vpp_lite_uses_dpdk = no
@@ -30,7 +32,7 @@ vpp_lite_debug_TAG_CFLAGS = -g -O0 -DCLIB_DEBUG -DFORTIFY_SOURCE=2 -march=$(MARC
 vpp_lite_debug_TAG_LDFLAGS = -g -O0 -DCLIB_DEBUG -DFORTIFY_SOURCE=2 -march=$(MARCH) \
        -fstack-protector-all -fPIC -Werror
 
-vpp_lite_TAG_CFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) \
+vpp_lite_TAG_CFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) -mtune=$(MTUNE) \
        -fstack-protector -fPIC -Werror
-vpp_lite_TAG_LDFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) \
+vpp_lite_TAG_LDFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) -mtune=$(MTUNE) \
        -fstack-protector -fPIC -Werror
index a60cbf0..97fb43d 100644 (file)
@@ -220,6 +220,11 @@ else
 endif
 export MARCH
 
+MTUNE = $(strip $($(PLATFORM)_mtune))
+ifeq ($(MTUNE),)
+  MTUNE = generic
+endif
+
 ######################################################################
 # Generic build stuff
 ######################################################################
index 165058d..b7e1e09 100644 (file)
@@ -19,6 +19,7 @@ DPDK_INSTALL_DIR      ?= $(CURDIR)/_install
 DPDK_PKTMBUF_HEADROOM ?= 128
 DPDK_DOWNLOAD_DIR     ?= $(HOME)/Downloads
 DPDK_MARCH            ?= native
+DPDK_TUNE             ?= generic
 DPDK_DEBUG            ?= n
 
 B := $(DPDK_BUILD_DIR)
@@ -51,7 +52,7 @@ DPDK_CPU_LDFLAGS :=
 DPDK_EXTRA_LDFLAGS := -g
 
 ifeq ($(DPDK_DEBUG),n)
-DPDK_EXTRA_CFLAGS := -g
+DPDK_EXTRA_CFLAGS := -g -mtune=$(DPDK_TUNE)
 else
 DPDK_EXTRA_CFLAGS := -g -O0
 endif
index 2caede6..9b33a0a 100644 (file)
@@ -40,6 +40,7 @@
 #ifndef included_vlib_node_h
 #define included_vlib_node_h
 
+#include <vppinfra/cpu.h>
 #include <vppinfra/longjmp.h>
 #include <vppinfra/timing_wheel.h>
 #include <vlib/trace.h>                /* for vlib_trace_filter_t */
@@ -149,6 +150,32 @@ static void __vlib_add_node_registration_##x (void)                     \
 }                                                                       \
 __VA_ARGS__ vlib_node_registration_t x 
 
+#if CLIB_DEBUG > 0
+#define VLIB_NODE_FUNCTION_CLONE_TEMPLATE(arch, fn)
+#define VLIB_NODE_FUNCTION_MULTIARCH_CLONE(fn)
+#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
+#else
+#define VLIB_NODE_FUNCTION_CLONE_TEMPLATE(arch, fn, tgt)               \
+  uword                                                                        \
+  __attribute__ ((flatten))                                            \
+  __attribute__ ((target (tgt)))                                       \
+  CLIB_CPU_OPTIMIZED                                                   \
+  fn ## _ ## arch ( struct vlib_main_t * vm,                           \
+                   struct vlib_node_runtime_t * node,                  \
+                   struct vlib_frame_t * frame)                                \
+  { return fn (vm, node, frame); }
+
+#define VLIB_NODE_FUNCTION_MULTIARCH_CLONE(fn)                         \
+  foreach_march_variant(VLIB_NODE_FUNCTION_CLONE_TEMPLATE, fn)
+
+#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)                         \
+  VLIB_NODE_FUNCTION_MULTIARCH_CLONE(fn)                               \
+  CLIB_MULTIARCH_SELECT_FN(fn, static inline)                          \
+  static void __attribute__((__constructor__))                         \
+  __vlib_node_function_multiarch_select_##node (void)                  \
+  { node.function = fn ## _multiarch_select(); }
+#endif
+
 always_inline vlib_node_registration_t *
 vlib_node_next_registered (vlib_node_registration_t * c)
 {
index 8152f6c..75e80ad 100644 (file)
@@ -329,6 +329,8 @@ VLIB_REGISTER_NODE (ip4_classify_node) = {
   .next_nodes = IP4_LOOKUP_NEXT_NODES,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_classify_node, ip4_classify)
+
 static uword
 ip6_classify (vlib_main_t * vm,
               vlib_node_runtime_t * node,
@@ -350,6 +352,8 @@ VLIB_REGISTER_NODE (ip6_classify_node) = {
   .next_nodes = IP6_LOOKUP_NEXT_NODES,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_classify_node, ip6_classify)
+
 static clib_error_t *
 ip_classify_init (vlib_main_t * vm)
 {
index 6178e89..5578558 100644 (file)
@@ -348,6 +348,8 @@ VLIB_REGISTER_NODE (ip4_cop_whitelist_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_cop_whitelist_node, ip4_cop_whitelist_node_fn)
+
 static clib_error_t *
 ip4_whitelist_init (vlib_main_t * vm)
 {
index dc6a1ee..4a8f33f 100644 (file)
@@ -286,6 +286,8 @@ VLIB_REGISTER_NODE (ip6_cop_whitelist_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_cop_whitelist_node, ip6_cop_whitelist_node_fn)
+
 static clib_error_t *
 ip6_whitelist_init (vlib_main_t * vm)
 {
index 3ee7006..b448b53 100644 (file)
@@ -282,6 +282,8 @@ VLIB_REGISTER_NODE (cop_input_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (cop_input_node, cop_input_node_fn)
+
 #define foreach_cop_stub                        \
 _(default-cop-whitelist, default_cop_whitelist)
 
index f0e9148..0671d9e 100644 (file)
@@ -204,3 +204,6 @@ VNET_DEVICE_CLASS (af_packet_device_class) = {
   .subif_add_del_function = af_packet_subif_add_del_function,
   .no_flatten_output_chains = 1,
 };
+
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH (af_packet_device_class,
+                                  af_packet_interface_tx)
index b622a22..0c608ea 100644 (file)
@@ -267,7 +267,6 @@ af_packet_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
   return n_rx_packets;
 }
 
-
 VLIB_REGISTER_NODE (af_packet_input_node) = {
   .function = af_packet_input_fn,
   .name = "af-packet-input",
@@ -283,3 +282,6 @@ VLIB_REGISTER_NODE (af_packet_input_node) = {
     [AF_PACKET_INPUT_NEXT_ETHERNET_INPUT] = "ethernet-input",
   },
 };
+
+VLIB_NODE_FUNCTION_MULTIARCH (af_packet_input_node, af_packet_input_fn)
+
index 9ec1986..9063cad 100644 (file)
@@ -759,6 +759,7 @@ set_efd (vlib_main_t *vm, unformat_input_t *input,
     dpdk_main_t * dm = &dpdk_main;
     vlib_thread_main_t * tm = vlib_get_thread_main();
     clib_error_t * error = NULL;
+    vlib_node_runtime_t * rt = vlib_node_get_runtime (vm, dpdk_input_node.index);
 
     if (unformat(input, "enable")) {
         if (unformat(input, "dpdk")) {
@@ -844,6 +845,13 @@ set_efd (vlib_main_t *vm, unformat_input_t *input,
                                   format_unformat_error, input);
     }
 
+    if (dm->efd.enabled)
+       rt->function = dpdk_input_efd_multiarch_select();
+    else if (dm->use_rss)
+       rt->function = dpdk_input_rss_multiarch_select();
+    else
+       rt->function = dpdk_input_multiarch_select();
+
     return error;
 }
 
index ab85dfb..a38c8d1 100644 (file)
@@ -1184,6 +1184,9 @@ VNET_DEVICE_CLASS (dpdk_device_class) = {
   .name_renumber = dpdk_device_renumber,
 };
 
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH (dpdk_device_class,
+                                  dpdk_interface_tx)
+
 void dpdk_set_flowcontrol_callback (vlib_main_t *vm, 
                                     dpdk_flowcontrol_callback_t callback)
 {
index 019d83f..525cd8d 100644 (file)
@@ -584,8 +584,9 @@ dpdk_pmd_t dpdk_get_pmd_type (vnet_hw_interface_t *hi);
 
 i8 dpdk_get_cpu_socket (vnet_hw_interface_t *hi);
 
-uword
-dpdk_input_rss (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * f);
+void * dpdk_input_multiarch_select();
+void * dpdk_input_rss_multiarch_select();
+void * dpdk_input_efd_multiarch_select();
 
 clib_error_t*
 dpdk_get_hw_interface_stats (u32 hw_if_index, struct rte_eth_stats* dest);
index 63fa4c0..8ee59ff 100644 (file)
@@ -804,6 +804,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
   clib_error_t * error = 0;
   dpdk_main_t * dm = &dpdk_main;
   vlib_thread_main_t * tm = vlib_get_thread_main();
+  vlib_node_runtime_t * rt = vlib_node_get_runtime (vm, dpdk_input_node.index);
   u8 * s, * tmp = 0;
   u8 * pci_dev_id = 0;
   u8 * rte_cmd = 0, * ethname = 0;
@@ -1251,10 +1252,9 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
     }
 
   if (dm->use_rss)
-    {
-      vlib_node_runtime_t * rt = vlib_node_get_runtime (vm, dpdk_input_node.index);
-      rt->function = dpdk_input_rss;
-    }
+    rt->function = dpdk_input_rss_multiarch_select();
+  else
+    rt->function = dpdk_input_multiarch_select();
  done:
   return error;
 }
index a7590a5..ca94511 100644 (file)
@@ -251,6 +251,8 @@ VLIB_REGISTER_NODE (handoff_dispatch_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (handoff_dispatch_node, handoff_dispatch_node_fn)
+
 clib_error_t *handoff_dispatch_init (vlib_main_t *vm)
 {
   handoff_dispatch_main_t * mp = &handoff_dispatch_main;
@@ -488,7 +490,8 @@ static inline u32 dpdk_device_input ( dpdk_main_t * dm,
                                       dpdk_device_t * xd,
                                       vlib_node_runtime_t * node,
                                       u32 cpu_index,
-                                      u16 queue_id)
+                                      u16 queue_id,
+                                      int use_efd)
 {
   u32 n_buffers;
   u32 next_index = DPDK_RX_NEXT_ETHERNET_INPUT;
@@ -510,7 +513,7 @@ static inline u32 dpdk_device_input ( dpdk_main_t * dm,
   if (n_buffers == 0)
     {
       /* check if EFD (dpdk) is enabled */
-      if (PREDICT_FALSE(dm->efd.enabled))
+      if (PREDICT_FALSE(use_efd && dm->efd.enabled))
         {
           /* reset a few stats */
           xd->efd_agent.last_poll_time = 0;
@@ -546,7 +549,7 @@ static inline u32 dpdk_device_input ( dpdk_main_t * dm,
   /* Check for congestion if EFD (Early-Fast-Discard) is enabled
    * in any mode (e.g. dpdk, monitor, or drop_all)
    */
-  if (PREDICT_FALSE(dm->efd.enabled))
+  if (PREDICT_FALSE(use_efd && dm->efd.enabled))
     {
       /* update EFD counters */
       dpdk_efd_update_counters(xd, n_buffers, dm->efd.enabled);
@@ -793,7 +796,7 @@ dpdk_input (vlib_main_t * vm,
     {
       xd = vec_elt_at_index(dm->devices, dq->device);
       ASSERT(dq->queue_id == 0);
-      n_rx_packets += dpdk_device_input (dm, xd, node, cpu_index, 0);
+      n_rx_packets += dpdk_device_input (dm, xd, node, cpu_index, 0, 0);
     }
 
   VIRL_SPEED_LIMIT()
@@ -818,7 +821,7 @@ dpdk_input_rss (vlib_main_t * vm,
   vec_foreach (dq, dm->devices_by_cpu[cpu_index])
     {
       xd = vec_elt_at_index(dm->devices, dq->device);
-      n_rx_packets += dpdk_device_input (dm, xd, node, cpu_index, dq->queue_id);
+      n_rx_packets += dpdk_device_input (dm, xd, node, cpu_index, dq->queue_id, 0);
     }
 
   VIRL_SPEED_LIMIT()
@@ -826,6 +829,32 @@ dpdk_input_rss (vlib_main_t * vm,
   return n_rx_packets;
 }
 
+uword
+dpdk_input_efd (vlib_main_t * vm,
+      vlib_node_runtime_t * node,
+      vlib_frame_t * f)
+{
+  dpdk_main_t * dm = &dpdk_main;
+  dpdk_device_t * xd;
+  uword n_rx_packets = 0;
+  dpdk_device_and_queue_t * dq;
+  u32 cpu_index = os_get_cpu_number();
+
+  /*
+   * Poll all devices on this cpu for input/interrupts.
+   */
+  vec_foreach (dq, dm->devices_by_cpu[cpu_index])
+    {
+      xd = vec_elt_at_index(dm->devices, dq->device);
+      n_rx_packets += dpdk_device_input (dm, xd, node, cpu_index, dq->queue_id, 1);
+    }
+
+  VIRL_SPEED_LIMIT()
+
+  return n_rx_packets;
+}
+
+
 VLIB_REGISTER_NODE (dpdk_input_node) = {
   .function = dpdk_input,
   .type = VLIB_NODE_TYPE_INPUT,
@@ -850,6 +879,17 @@ VLIB_REGISTER_NODE (dpdk_input_node) = {
   },
 };
 
+
+/* handle dpdk_input_rss alternative function */
+VLIB_NODE_FUNCTION_MULTIARCH_CLONE(dpdk_input)
+VLIB_NODE_FUNCTION_MULTIARCH_CLONE(dpdk_input_rss)
+VLIB_NODE_FUNCTION_MULTIARCH_CLONE(dpdk_input_efd)
+
+/* this macro defines dpdk_input_rss_multiarch_select() */
+CLIB_MULTIARCH_SELECT_FN(dpdk_input);
+CLIB_MULTIARCH_SELECT_FN(dpdk_input_rss);
+CLIB_MULTIARCH_SELECT_FN(dpdk_input_efd);
+
 /*
  * Override the next nodes for the dpdk input nodes.
  * Must be invoked prior to VLIB_INIT_FUNCTION calls.
index f04e067..a966ffe 100644 (file)
@@ -232,3 +232,6 @@ VNET_DEVICE_CLASS (netmap_device_class) = {
   .subif_add_del_function = netmap_subif_add_del_function,
   .no_flatten_output_chains = 1,
 };
+
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH(netmap_device_class,
+                                 netmap_interface_tx)
index 3986c7e..f4c39e6 100644 (file)
@@ -270,7 +270,6 @@ netmap_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
   return n_rx_packets;
 }
 
-
 VLIB_REGISTER_NODE (netmap_input_node) = {
   .function = netmap_input_fn,
   .name = "netmap-input",
@@ -287,3 +286,5 @@ VLIB_REGISTER_NODE (netmap_input_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (netmap_input_node, netmap_input_fn)
+
index 8462569..57b5fd2 100644 (file)
@@ -334,3 +334,5 @@ VLIB_REGISTER_NODE (ssvm_eth_input_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ssvm_eth_input_node, ssvm_eth_input_node_fn)
+
index 49f2d5f..7c65e21 100644 (file)
@@ -474,3 +474,6 @@ VNET_DEVICE_CLASS (ssvm_eth_device_class) = {
   .rx_redirect_to_node = ssvm_eth_set_interface_next_node,
   .no_flatten_output_chains = 1,
 };
+
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH (ssvm_eth_device_class,
+                                  ssvm_eth_interface_tx)
index 5902c42..ef4993f 100644 (file)
@@ -1144,6 +1144,8 @@ VLIB_REGISTER_NODE (vhost_user_input_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (vhost_user_input_node, vhost_user_input)
+
 static uword
 vhost_user_intfc_tx (vlib_main_t * vm,
                  vlib_node_runtime_t * node,
@@ -1373,6 +1375,9 @@ VNET_DEVICE_CLASS (vhost_user_dev_class,static) = {
   .no_flatten_output_chains = 1,
 };
 
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH (vhost_user_dev_class,
+                                  vhost_user_intfc_tx)
+
 static uword
 vhost_user_process (vlib_main_t * vm,
               vlib_node_runtime_t * rt,
index e8902fd..226a66e 100644 (file)
@@ -945,6 +945,8 @@ VLIB_REGISTER_NODE (ethernet_input_node) = {
   .unformat_buffer = unformat_ethernet_header,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ethernet_input_node, ethernet_input)
+
 VLIB_REGISTER_NODE (ethernet_input_type_node,static) = {
   .function = ethernet_input_type,
   .name = "ethernet-input-type",
@@ -959,6 +961,8 @@ VLIB_REGISTER_NODE (ethernet_input_type_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ethernet_input_type_node, ethernet_input_type)
+
 VLIB_REGISTER_NODE (ethernet_input_not_l2_node,static) = {
   .function = ethernet_input_not_l2,
   .name = "ethernet-input-not-l2",
@@ -973,6 +977,8 @@ VLIB_REGISTER_NODE (ethernet_input_not_l2_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ethernet_input_not_l2_node, ethernet_input_not_l2)
+
 void ethernet_set_rx_redirect (vnet_main_t * vnm, 
                                vnet_hw_interface_t * hi, 
                                u32 enable)
index 075bd6f..6d37515 100644 (file)
@@ -454,6 +454,9 @@ VNET_DEVICE_CLASS (gre_device_class) = {
 #endif
 };
 
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH (gre_device_class,
+                                  gre_interface_tx)
+
 
 VNET_HW_INTERFACE_CLASS (gre_hw_interface_class) = {
   .name = "GRE",
index a91f7e9..e33b2b0 100644 (file)
@@ -434,6 +434,8 @@ VLIB_REGISTER_NODE (gre_input_node) = {
   .unformat_buffer = unformat_gre_header,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (gre_input_node, gre_input)
+
 void
 gre_register_input_protocol (vlib_main_t * vm,
                             gre_protocol_t protocol,
index 2829a0c..30dcf27 100644 (file)
@@ -163,6 +163,32 @@ static void __vnet_add_device_class_registration_##x (void)             \
 }                                                                       \
 __VA_ARGS__ vnet_device_class_t x                                       
 
+#define VLIB_DEVICE_TX_FUNCTION_CLONE_TEMPLATE(arch, fn, tgt)          \
+  uword                                                                        \
+  __attribute__ ((flatten))                                            \
+  __attribute__ ((target (tgt)))                                       \
+  CLIB_CPU_OPTIMIZED                                                   \
+  fn ## _ ## arch ( vlib_main_t * vm,                                  \
+                   vlib_node_runtime_t * node,                         \
+                   vlib_frame_t * frame)                               \
+  { return fn (vm, node, frame); }
+
+#define VLIB_DEVICE_TX_FUNCTION_MULTIARCH_CLONE(fn)                    \
+  foreach_march_variant(VLIB_DEVICE_TX_FUNCTION_CLONE_TEMPLATE, fn)
+
+#if CLIB_DEBUG > 0
+#define VLIB_MULTIARCH_CLONE_AND_SELECT_FN(fn,...)
+#define VLIB_DEVICE_TX_FUNCTION_MULTIARCH(dev, fn)
+#else
+#define VLIB_DEVICE_TX_FUNCTION_MULTIARCH(dev, fn)                     \
+  VLIB_DEVICE_TX_FUNCTION_MULTIARCH_CLONE(fn)                          \
+  CLIB_MULTIARCH_SELECT_FN(fn, static inline)                          \
+  static void __attribute__((__constructor__))                         \
+  __vlib_device_tx_function_multiarch_select_##dev (void)              \
+  { dev.tx_function = fn ## _multiarch_select(); }
+#endif
+
+
 /* Layer-2 (e.g. Ethernet) interface class. */
 typedef struct _vnet_hw_interface_class {
   /* Index into main vector. */
index 04c1b7f..9f9fb70 100644 (file)
@@ -1140,6 +1140,8 @@ VLIB_REGISTER_NODE (drop_buffers,static) = {
   .validate_frame = validate_error_frame,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (drop_buffers, process_drop)
+
 VLIB_REGISTER_NODE (punt_buffers,static) = {
   .function = process_punt,
   .flags = (VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH
@@ -1150,12 +1152,16 @@ VLIB_REGISTER_NODE (punt_buffers,static) = {
   .validate_frame = validate_error_frame,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (punt_buffers, process_punt)
+
 VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node,static) = {
   .function = vnet_per_buffer_interface_output,
   .name = "interface-output",
   .vector_size = sizeof (u32),
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (vnet_per_buffer_interface_output_node, vnet_per_buffer_interface_output)
+
 clib_error_t *
 vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
                                                       u32 hw_if_index,
index a84b83b..ae2f9ee 100644 (file)
@@ -1354,6 +1354,8 @@ VLIB_REGISTER_NODE (ip4_lookup_node) = {
   .next_nodes = IP4_LOOKUP_NEXT_NODES,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup)
+
 static uword
 ip4_indirect (vlib_main_t * vm,
                vlib_node_runtime_t * node,
@@ -1373,6 +1375,8 @@ VLIB_REGISTER_NODE (ip4_indirect_node) = {
   .next_nodes = IP4_LOOKUP_NEXT_NODES,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_indirect_node, ip4_indirect)
+
 
 /* Global IP4 main. */
 ip4_main_t ip4_main;
@@ -1612,6 +1616,8 @@ VLIB_REGISTER_NODE (ip4_drop_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop)
+
 VLIB_REGISTER_NODE (ip4_punt_node,static) = {
   .function = ip4_punt,
   .name = "ip4-punt",
@@ -1625,6 +1631,8 @@ VLIB_REGISTER_NODE (ip4_punt_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt)
+
 VLIB_REGISTER_NODE (ip4_miss_node,static) = {
   .function = ip4_miss,
   .name = "ip4-miss",
@@ -1638,6 +1646,8 @@ VLIB_REGISTER_NODE (ip4_miss_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_miss_node, ip4_miss)
+
 /* Compute TCP/UDP/ICMP4 checksum in software. */
 u16
 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
@@ -2076,6 +2086,8 @@ VLIB_REGISTER_NODE (ip4_local_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local)
+
 void ip4_register_protocol (u32 protocol, u32 node_index)
 {
   vlib_main_t * vm = vlib_get_main();
@@ -2743,6 +2755,8 @@ VLIB_REGISTER_NODE (ip4_rewrite_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite_transit)
+
 VLIB_REGISTER_NODE (ip4_rewrite_local_node,static) = {
   .function = ip4_rewrite_local,
   .name = "ip4-rewrite-local",
@@ -2759,6 +2773,8 @@ VLIB_REGISTER_NODE (ip4_rewrite_local_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_local_node, ip4_rewrite_local)
+
 static clib_error_t *
 add_del_interface_table (vlib_main_t * vm,
                         unformat_input_t * input,
@@ -3032,6 +3048,8 @@ VLIB_REGISTER_NODE (ip4_lookup_multicast_node,static) = {
   .next_nodes = IP4_LOOKUP_NEXT_NODES,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, ip4_lookup_multicast)
+
 VLIB_REGISTER_NODE (ip4_multicast_node,static) = {
   .function = ip4_drop,
   .name = "ip4-multicast",
index ae46040..177feb7 100644 (file)
@@ -233,6 +233,8 @@ VLIB_REGISTER_NODE (ip4_hop_by_hop_node) = {
   .next_nodes = IP4_LOOKUP_NEXT_NODES,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_hop_by_hop_node, ip4_hop_by_hop_node_fn)
+
 VLIB_REGISTER_NODE (ip4_add_hop_by_hop_node) = {
   .function = ip4_hop_by_hop_node_fn,
   .name = "ip4-add-hop-by-hop",
index f31df0f..6063425 100644 (file)
@@ -371,6 +371,8 @@ VLIB_REGISTER_NODE (ip4_input_node) = {
   .format_trace = format_ip4_input_trace,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_input_node, ip4_input)
+
 VLIB_REGISTER_NODE (ip4_input_no_checksum_node,static) = {
   .function = ip4_input_no_checksum,
   .name = "ip4-input-no-checksum",
@@ -389,6 +391,8 @@ VLIB_REGISTER_NODE (ip4_input_no_checksum_node,static) = {
   .format_trace = format_ip4_input_trace,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_input_no_checksum_node, ip4_input_no_checksum)
+
 static clib_error_t * ip4_init (vlib_main_t * vm)
 {
   clib_error_t * error;
index 47e22f2..11e6678 100644 (file)
@@ -297,6 +297,9 @@ VLIB_REGISTER_NODE (ip4_check_source_reachable_via_any) = {
   .format_trace = format_ip4_source_check_trace,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_check_source_reachable_via_any,
+                             ip4_source_check_reachable_via_any)
+
 VLIB_REGISTER_NODE (ip4_check_source_reachable_via_rx) = {
   .function = ip4_source_check_reachable_via_rx,
   .name = "ip4-source-check-via-rx",
@@ -311,6 +314,9 @@ VLIB_REGISTER_NODE (ip4_check_source_reachable_via_rx) = {
   .format_trace = format_ip4_source_check_trace,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_check_source_reachable_via_rx,
+                             ip4_source_check_reachable_via_rx)
+
 static clib_error_t *
 set_ip_source_check (vlib_main_t * vm,
                     unformat_input_t * input,
index a136da3..7093c57 100644 (file)
@@ -1260,6 +1260,8 @@ VLIB_REGISTER_NODE (ip6_lookup_node) = {
   .next_nodes = IP6_LOOKUP_NEXT_NODES,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup)
+
 static uword
 ip6_indirect (vlib_main_t * vm,
              vlib_node_runtime_t * node,
@@ -1278,6 +1280,8 @@ VLIB_REGISTER_NODE (ip6_indirect_node) = {
   .next_nodes = IP6_LOOKUP_NEXT_NODES,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_indirect_node, ip6_indirect)
+
 typedef struct {
   /* Adjacency taken. */
   u32 adj_index;
@@ -1454,6 +1458,8 @@ VLIB_REGISTER_NODE (ip6_drop_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop)
+
 VLIB_REGISTER_NODE (ip6_punt_node,static) = {
   .function = ip6_punt,
   .name = "ip6-punt",
@@ -1467,6 +1473,8 @@ VLIB_REGISTER_NODE (ip6_punt_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt)
+
 VLIB_REGISTER_NODE (ip6_miss_node,static) = {
   .function = ip6_miss,
   .name = "ip6-miss",
@@ -1480,6 +1488,8 @@ VLIB_REGISTER_NODE (ip6_miss_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_miss_node, ip6_miss)
+
 VLIB_REGISTER_NODE (ip6_multicast_node,static) = {
   .function = ip6_drop,
   .name = "ip6-multicast",
@@ -1858,6 +1868,8 @@ VLIB_REGISTER_NODE (ip6_local_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local)
+
 void ip6_register_protocol (u32 protocol, u32 node_index)
 {
   vlib_main_t * vm = vlib_get_main();
@@ -2424,6 +2436,8 @@ VLIB_REGISTER_NODE (ip6_rewrite_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite_transit)
+
 VLIB_REGISTER_NODE (ip6_rewrite_local_node,static) = {
   .function = ip6_rewrite_local,
   .name = "ip6-rewrite-local",
@@ -2439,6 +2453,8 @@ VLIB_REGISTER_NODE (ip6_rewrite_local_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_local_node, ip6_rewrite_local)
+
 /* Global IP6 main. */
 ip6_main_t ip6_main;
 
index 16650dd..045dbc7 100644 (file)
@@ -628,6 +628,8 @@ VLIB_REGISTER_NODE (ip6_hop_by_hop_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop_node_fn)
+
 /* The main h-b-h tracer will be invoked, no need to do much here */
 typedef struct {
   u32 next_index;
@@ -849,6 +851,7 @@ VLIB_REGISTER_NODE (ip6_add_hop_by_hop_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_add_hop_by_hop_node, ip6_add_hop_by_hop_node_fn)
 
 /* The main h-b-h tracer was already invoked, no need to do much here */
 typedef struct {
@@ -1162,6 +1165,8 @@ VLIB_REGISTER_NODE (ip6_pop_hop_by_hop_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_pop_hop_by_hop_node,
+                             ip6_pop_hop_by_hop_node_fn)
 
 static clib_error_t *
 ip6_hop_by_hop_init (vlib_main_t * vm)
index f96a1cf..2042cbd 100644 (file)
@@ -305,6 +305,8 @@ VLIB_REGISTER_NODE (ip6_input_node) = {
   .format_trace = format_ip6_input_trace,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_input_node, ip6_input)
+
 static clib_error_t * ip6_init (vlib_main_t * vm)
 {
   ethernet_register_input_type (vm, ETHERNET_TYPE_IP6,
index e905ed1..fcf8eea 100644 (file)
@@ -369,6 +369,8 @@ VLIB_REGISTER_NODE (ip4_inacl_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_inacl_node, ip4_inacl)
+
 static uword
 ip6_inacl (vlib_main_t * vm,
               vlib_node_runtime_t * node,
@@ -392,6 +394,8 @@ VLIB_REGISTER_NODE (ip6_inacl_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_inacl_node, ip6_inacl)
+
 static clib_error_t *
 ip_inacl_init (vlib_main_t * vm)
 {
index 253ad0f..354dd4e 100644 (file)
@@ -327,6 +327,8 @@ VLIB_REGISTER_NODE (udp4_input_node) = {
   .unformat_buffer = unformat_udp_header,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (udp4_input_node, udp4_input)
+
 VLIB_REGISTER_NODE (udp6_input_node) = {
   .function = udp6_input,
   .name = "ip6-udp-lookup",
@@ -350,6 +352,8 @@ VLIB_REGISTER_NODE (udp6_input_node) = {
   .unformat_buffer = unformat_udp_header,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (udp6_input_node, udp6_input)
+
 static void add_dst_port (udp_main_t * um,
                           udp_dst_port_t dst_port,
                          char * dst_port_name, u8 is_ip4)
index 958a4d6..7af88b2 100644 (file)
@@ -425,3 +425,5 @@ VLIB_REGISTER_NODE (esp_decrypt_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (esp_decrypt_node, esp_decrypt_node_fn)
+
index 39bbf2e..d1dbcf9 100644 (file)
@@ -387,3 +387,5 @@ VLIB_REGISTER_NODE (esp_encrypt_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (esp_encrypt_node, esp_encrypt_node_fn)
+
index 517f8bf..5a8a685 100644 (file)
@@ -148,4 +148,7 @@ VLIB_REGISTER_NODE (ipsec_if_input_node) = {
         [IPSEC_IF_INPUT_NEXT_ESP_DECRYPT] = "esp-decrypt",
         [IPSEC_IF_INPUT_NEXT_DROP] = "error-drop",
   },
-};
\ No newline at end of file
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ipsec_if_input_node, ipsec_if_input_node_fn)
+
index 1e1dd52..9573c4f 100644 (file)
@@ -138,3 +138,5 @@ VLIB_REGISTER_NODE (ipsec_if_output_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ipsec_if_output_node, ipsec_if_output_node_fn)
+
index 3cd60ba..09acd10 100644 (file)
@@ -288,6 +288,9 @@ VLIB_REGISTER_NODE (ipsec_input_ip4_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ipsec_input_ip4_node,
+                             ipsec_input_ip4_node_fn)
+
 
 static vlib_node_registration_t ipsec_input_ip6_node;
 
@@ -406,3 +409,7 @@ VLIB_REGISTER_NODE (ipsec_input_ip6_node,static) = {
 #undef _
   },
 };
+
+VLIB_NODE_FUNCTION_MULTIARCH (ipsec_input_ip6_node,
+                             ipsec_input_ip6_node_fn)
+
index 509b1e2..9355468 100644 (file)
@@ -405,6 +405,8 @@ VLIB_REGISTER_NODE (ipsec_output_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (ipsec_output_node, ipsec_output_node_fn)
+
 #else /* IPSEC > 1 */
 
 /* Dummy ipsec output node, in case when IPSec is disabled */
index 449dea7..765bc68 100644 (file)
@@ -399,6 +399,8 @@ VLIB_REGISTER_NODE (l2_classify_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2_classify_node, l2_classify_node_fn)
+
 clib_error_t *l2_classify_init (vlib_main_t *vm)
 {
   l2_classify_main_t * cm = &l2_classify_main;
index b865c37..17b7eb3 100644 (file)
@@ -498,6 +498,8 @@ VLIB_REGISTER_NODE (l2_efp_filter_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2_efp_filter_node, l2_efp_filter_node_fn)
+
 clib_error_t *l2_efp_filter_init (vlib_main_t *vm)
 {
   l2_efp_filter_main_t * mp = &l2_efp_filter_main;
index ca8c171..9f71677 100644 (file)
@@ -442,6 +442,8 @@ VLIB_REGISTER_NODE (l2flood_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2flood_node, l2flood_node_fn)
+
 clib_error_t *l2flood_init (vlib_main_t *vm)
 {
   l2flood_main_t * mp = &l2flood_main;
index 88a6b69..5af83a7 100644 (file)
@@ -367,6 +367,8 @@ VLIB_REGISTER_NODE (l2fwd_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2fwd_node, l2fwd_node_fn)
+
 clib_error_t *l2fwd_init (vlib_main_t *vm)
 {
   l2fwd_main_t * mp = &l2fwd_main;
index 870aff6..dd3a8b7 100644 (file)
@@ -433,6 +433,8 @@ VLIB_REGISTER_NODE (l2input_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2input_node, l2input_node_fn)
+
 clib_error_t *l2input_init (vlib_main_t *vm)
 {
   l2input_main_t * mp = &l2input_main;
index 49df0f6..68c005f 100644 (file)
@@ -371,6 +371,8 @@ VLIB_REGISTER_NODE (l2_inacl_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2_inacl_node, l2_inacl_node_fn)
+
 clib_error_t *l2_inacl_init (vlib_main_t *vm)
 {
   l2_inacl_main_t * mp = &l2_inacl_main;
index bbef33a..d0f2181 100644 (file)
@@ -293,6 +293,8 @@ VLIB_REGISTER_NODE (l2_invtr_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2_invtr_node, l2_invtr_node_fn)
+
 clib_error_t *l2_invtr_init (vlib_main_t *vm)
 {
   l2_invtr_main_t * mp = &l2_invtr_main;
index a891cb3..0d94e43 100644 (file)
@@ -415,6 +415,7 @@ VLIB_REGISTER_NODE (l2learn_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2learn_node, l2learn_node_fn)
 
 clib_error_t *l2learn_init (vlib_main_t *vm)
 {
index a550d07..f5b2211 100644 (file)
@@ -414,6 +414,8 @@ VLIB_REGISTER_NODE (l2output_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2output_node, l2output_node_fn)
+
 clib_error_t *l2output_init (vlib_main_t *vm)
 {
   l2output_main_t * mp = &l2output_main;
index f75345f..b222255 100644 (file)
@@ -274,6 +274,8 @@ VLIB_REGISTER_NODE (l2_outacl_node,static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2_outacl_node, l2_outacl_node_fn)
+
 clib_error_t *l2_outacl_init (vlib_main_t *vm)
 {
   l2_outacl_main_t * mp = &l2_outacl_main;
index 63be409..0839142 100644 (file)
@@ -252,6 +252,8 @@ VLIB_REGISTER_NODE (l2_patch_node, static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2_patch_node, l2_patch_node_fn)
+
 int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index, int is_add)
 {
   l2_patch_main_t * l2pm = &l2_patch_main;  
index 93580c2..b66a7d3 100644 (file)
@@ -604,3 +604,5 @@ VLIB_REGISTER_NODE (l2_rw_node) = {
   .next_nodes = { [L2_RW_NEXT_DROP]  = "error-drop"},
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2_rw_node, l2_rw_node_fn)
+
index f5fe3ca..00542a1 100644 (file)
@@ -255,6 +255,8 @@ VLIB_REGISTER_NODE (l2_xcrw_node, static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2_xcrw_node, l2_xcrw_node_fn)
+
 clib_error_t *l2_xcrw_init (vlib_main_t *vm)
 {
   l2_xcrw_main_t * mp = &l2_xcrw_main;
index 1a2bc48..5f0d05c 100644 (file)
@@ -247,6 +247,8 @@ VLIB_REGISTER_NODE (l2t_decap_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2t_decap_node, l2t_decap_node_fn)
+
 void l2tp_decap_init (void) 
 {
   ip6_register_protocol (IP_PROTOCOL_L2TP, l2t_decap_node.index);
index 8f26ab0..eca098c 100644 (file)
@@ -206,6 +206,8 @@ VLIB_REGISTER_NODE (l2t_encap_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2t_encap_node, l2t_encap_node_fn)
+
 void l2tp_encap_init (vlib_main_t * vm)
 {
   l2tp_encap_runtime_t * rt;
index 26514cc..8701c32 100644 (file)
@@ -272,6 +272,8 @@ VLIB_REGISTER_NODE (li_hit_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (li_hit_node, li_hit_node_fn)
+
 #else
 #include <vlib/vlib.h>
 
index 408ca75..75cd022 100644 (file)
@@ -259,6 +259,9 @@ VNET_DEVICE_CLASS (mpls_gre_device_class) = {
 #endif
 };
 
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_gre_device_class,
+                                  mpls_gre_interface_tx)
+
 VNET_HW_INTERFACE_CLASS (mpls_gre_hw_interface_class) = {
   .name = "MPLS-GRE",
   .format_header = format_mpls_gre_header_with_length,
@@ -510,6 +513,8 @@ VNET_DEVICE_CLASS (mpls_eth_device_class) = {
 #endif
 };
 
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_eth_device_class,
+                                  mpls_eth_interface_tx)
 
 VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = {
   .name = "MPLS-ETH",
@@ -676,6 +681,8 @@ VLIB_REGISTER_NODE (mpls_post_rewrite_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (mpls_post_rewrite_node, mpls_post_rewrite)
+
 static u8 * mpls_gre_rewrite (mpls_main_t *mm, mpls_gre_tunnel_t * t)
 {
   ip4_header_t * ip0;
index 6bf5f81..474e2e2 100644 (file)
@@ -278,6 +278,8 @@ VLIB_REGISTER_NODE (mpls_input_node) = {
   .unformat_buffer = unformat_mpls_gre_header,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (mpls_input_node, mpls_input)
+
 static uword
 mpls_ethernet_input (vlib_main_t * vm,
                      vlib_node_runtime_t * node,
@@ -310,6 +312,8 @@ VLIB_REGISTER_NODE (mpls_ethernet_input_node) = {
   .unformat_buffer = unformat_mpls_gre_header,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (mpls_ethernet_input_node, mpls_ethernet_input)
+
 static void
 mpls_setup_nodes (vlib_main_t * vm)
 {
index b443919..e3f4beb 100644 (file)
@@ -153,6 +153,8 @@ VLIB_REGISTER_NODE (mpls_policy_encap_node) =  {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (mpls_policy_encap_node, mpls_policy_encap)
+
 static clib_error_t *
 mpls_policy_encap_init (vlib_main_t * vm)
 {
index 8a76e86..739ce45 100644 (file)
@@ -324,6 +324,9 @@ VLIB_REGISTER_NODE (policer_by_sw_if_index_node, static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (policer_by_sw_if_index_node,
+                             vnet_policer_by_sw_if_index);
+
 
 int test_policer_add_del (u32 rx_sw_if_index, u8 *config_name,
                           int is_add)
index 46318a2..e0ef318 100644 (file)
@@ -653,6 +653,8 @@ VLIB_REGISTER_NODE (sr_rewrite_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (sr_rewrite_node, sr_rewrite)
+
 static int ip6_delete_route_no_next_hop (ip6_address_t *dst_address_arg, 
                                          u32 dst_address_length, 
                                          u32 rx_table_id)
@@ -1911,6 +1913,8 @@ VLIB_REGISTER_NODE (sr_fix_dst_addr_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (sr_fix_dst_addr_node, sr_fix_dst_addr)
+
 static clib_error_t * sr_init (vlib_main_t * vm)
 {
   ip6_sr_main_t * sm = &sr_main;
@@ -2560,6 +2564,8 @@ VLIB_REGISTER_NODE (sr_local_node, static) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (sr_local_node, sr_local)
+
 ip6_sr_main_t * sr_get_main (vlib_main_t * vm)
 {
   vlib_call_init_function (vm, sr_init);
index 80d04ba..ccc0146 100644 (file)
@@ -350,6 +350,8 @@ VLIB_REGISTER_NODE (sr_replicate_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (sr_replicate_node, sr_replicate_node_fn)
+
 clib_error_t *sr_replicate_init (vlib_main_t *vm)
 {
   sr_replicate_main_t *msm = &sr_replicate_main;
index bd61f4b..00acd66 100644 (file)
@@ -550,6 +550,8 @@ VLIB_REGISTER_NODE (vxlan4_input_node) = {
   // $$$$ .unformat_buffer = unformat_vxlan_header,
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (vxlan4_input_node, vxlan4_input)
+
 VLIB_REGISTER_NODE (vxlan6_input_node) = {
   .function = vxlan6_input,
   .name = "vxlan6-input",
@@ -570,3 +572,6 @@ VLIB_REGISTER_NODE (vxlan6_input_node) = {
   .format_trace = format_vxlan_rx_trace,
   // $$$$ .unformat_buffer = unformat_vxlan_header,
 };
+
+VLIB_NODE_FUNCTION_MULTIARCH (vxlan6_input_node, vxlan6_input)
+
index ee5c7d5..387a728 100644 (file)
@@ -586,3 +586,6 @@ VLIB_REGISTER_NODE (vxlan_encap_node) = {
         [VXLAN_ENCAP_NEXT_DROP] = "error-drop",
   },
 };
+
+VLIB_NODE_FUNCTION_MULTIARCH (vxlan_encap_node, vxlan_encap)
+
index ac24886..8a1e23a 100644 (file)
@@ -274,6 +274,8 @@ static VLIB_REGISTER_NODE (sw6_ip6_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (sw6_ip6_node, ip6_l2t_node_fn)
+
 static clib_error_t *
 l2tp_config (vlib_main_t * vm, unformat_input_t * input)
 {
index 5c8327d..f6385a5 100644 (file)
@@ -250,3 +250,5 @@ VLIB_REGISTER_NODE (l2t_l2_node) = {
   },
 };
 
+VLIB_NODE_FUNCTION_MULTIARCH (l2t_l2_node, l2t_l2_node_fn)
+
index 588aadf..22bec40 100644 (file)
@@ -59,6 +59,7 @@ show_vpe_version_command_fn (vlib_main_t * vm,
       _("Compiler", "%s", vpe_compiler);
       _("CPU model name", "%U", format_cpu_model_name);
       _("CPU microarchitecture", "%U", format_cpu_uarch);
+      _("CPU flags", "%U", format_cpu_flags);
       _("Current PID", "%d", getpid());
 #if DPDK > 0
       _("DPDK Version", "%s", rte_version());
index f707994..2540083 100644 (file)
@@ -12,6 +12,8 @@
  * 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>
@@ -59,33 +61,32 @@ int main (int argc, char * argv[])
     u32 size;
     void vlib_set_get_handoff_structure_cb (void *cb);
 
-#if __x86_64__ && !defined(__clang__)
-    __builtin_cpu_init ();
+#if __x86_64__
     const char * msg = "ERROR: This binary requires CPU with %s extensions.\n";
 #define _(a,b) \
-    if (!__builtin_cpu_supports(a))    \
+    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
index f2dbaf1..9008ee3 100644 (file)
 #include <vppinfra/format.h>
 #include <vppinfra/cpu.h>
 
-#if __x86_64__
-#include <cpuid.h>
-#endif
-
 #define foreach_x86_cpu_uarch \
  _(0x06, 0x4f, "Broadwell", "Broadwell-EP/EX") \
  _(0x06, 0x3d, "Broadwell", "Broadwell") \
@@ -108,4 +104,21 @@ format_cpu_model_name (u8 * s, va_list * args)
 #else /* ! __x86_64__ */
   return format (s, "unknown");
 #endif
-}
\ No newline at end of file
+}
+
+u8 *
+format_cpu_flags (u8 * s, va_list * args)
+{
+#if __x86_64__
+#define _(flag, func, reg, bit) \
+  if (clib_cpu_supports_ ## flag()) \
+    s = format (s, #flag " ");
+  foreach_x86_64_flags
+  return s;
+#undef _
+#else /* ! __x86_64__ */
+  return format (s, "unknown");
+#endif
+}
+
+
index 79cdf74..961af70 100644 (file)
 #ifndef included_clib_cpu_h
 #define included_clib_cpu_h
 
+#include <vppinfra/format.h>
+
+/*
+ * multiarchitecture support. Adding new entry will produce
+ * new graph node function variant optimized for specific cpu
+ * microarchitecture.
+ * Order is important for runtime selection, as 1st match wins...
+ */
+
+#if __x86_64__ && CLIB_DEBUG == 0
+#define foreach_march_variant(macro, x) \
+  macro(avx2,  x, "arch=core-avx2")
+#else
+#define foreach_march_variant(macro, x)
+#endif
+
+
+#if __GNUC__ > 4  && !__clang__
+#define CLIB_CPU_OPTIMIZED __attribute__ ((optimize ("tree-vectorize")))
+#else
+#define CLIB_CPU_OPTIMIZED
+#endif
+
+
+#define CLIB_MULTIARCH_ARCH_CHECK(arch, fn, tgt)                       \
+  if (clib_cpu_supports_ ## arch())                                    \
+    return & fn ## _ ##arch;
+
+#define CLIB_MULTIARCH_SELECT_FN(fn,...)                               \
+  __VA_ARGS__ void * fn ## _multiarch_select(void)                     \
+{                                                                      \
+  foreach_march_variant(CLIB_MULTIARCH_ARCH_CHECK, fn)                 \
+  return & fn;                                                         \
+}
+
+#if __x86_64__
+#include "cpuid.h"
+
+#define foreach_x86_64_flags \
+_ (sse3,     1, ecx, 0)   \
+_ (ssse3,    1, ecx, 9)   \
+_ (sse41,    1, ecx, 19)  \
+_ (sse42,    1, ecx, 20)  \
+_ (avx,      1, ecx, 28)  \
+_ (avx2,     7, ebx, 5)   \
+_ (avx512f,  7, ebx, 16)  \
+_ (aes,      1, ecx, 25)  \
+_ (sha,      7, ebx, 29)
+
+static inline int
+clib_get_cpuid(const u32 lev, u32 * eax, u32 *ebx, u32 * ecx, u32 * edx)
+{
+  if ((u32) __get_cpuid_max (0x80000000 & lev, 0) < lev)
+    return 0;
+  if (lev == 7)
+    __cpuid_count(lev, 0, *eax, *ebx, *ecx, *edx);
+  else
+    __cpuid(lev, *eax, *ebx, *ecx, *edx);
+  return 1;
+}
+
+
+#define _(flag, func, reg, bit) \
+static inline int                                                      \
+clib_cpu_supports_ ## flag()                                           \
+{                                                                      \
+  u32 __attribute__((unused)) eax, ebx = 0, ecx = 0, edx  = 0;         \
+  clib_get_cpuid (func, &eax, &ebx, &ecx, &edx);                       \
+                                                                       \
+  return ((reg & (1 << bit)) != 0);                                    \
+}
+  foreach_x86_64_flags
+#undef _
+#endif
+
 format_function_t format_cpu_uarch;
 format_function_t format_cpu_model_name;
+format_function_t format_cpu_flags;
 
-#endif
\ No newline at end of file
+#endif