PPPoE usses a midchain adjacency stack on an interface-tx DPO 15/8015/8
authorNeale Ranns <nranns@cisco.com>
Sat, 12 Aug 2017 09:12:00 +0000 (02:12 -0700)
committerNeale Ranns <nranns@cisco.com>
Mon, 21 Aug 2017 11:07:00 +0000 (04:07 -0700)
1) introduce an interface-tx DPO. This is a simple wrapper around a sw_if_index. enhance DPO stacking functions to allow per-instance next-nodes and hence allow children to stack onto the interface per-instance tx node and not on 'interface-output'.
2) update PPPoE code to use ta midchain stack on a interface-tx DPO of the encap-interface. This remove the need for pppoe_encap node (which is replaced by the adj-midchain-tx) and interface-output node is no longer used (see above). Since PPPoE encap node is no longer needed, the PPPoE seesion does not need to be retrieved in the data-path, hence the cahce misses are removed.

Change-Id: Id8b40f53daa14889a9c51d802e14fed7fba4399a
Signed-off-by: Neale Ranns <nranns@cisco.com>
16 files changed:
src/plugins/pppoe.am
src/plugins/pppoe/pppoe.c
src/plugins/pppoe/pppoe.h
src/plugins/pppoe/pppoe_encap.c [deleted file]
src/vnet.am
src/vnet/adj/adj_midchain.c
src/vnet/dpo/dpo.c
src/vnet/dpo/dpo.h
src/vnet/dpo/interface_dpo.c [deleted file]
src/vnet/dpo/interface_rx_dpo.c [new file with mode: 0644]
src/vnet/dpo/interface_rx_dpo.h [moved from src/vnet/dpo/interface_dpo.h with 62% similarity]
src/vnet/dpo/interface_tx_dpo.c [new file with mode: 0644]
src/vnet/dpo/interface_tx_dpo.h [new file with mode: 0644]
src/vnet/fib/fib_path.c
src/vnet/fib/fib_test.c
test/test_pppoe.py

index 28bd20a..06ed60b 100644 (file)
 vppapitestplugins_LTLIBRARIES += pppoe_test_plugin.la
 vppplugins_LTLIBRARIES += pppoe_plugin.la
 
-pppoe_plugin_la_SOURCES =              \
-    pppoe/pppoe_decap.c                    \
-    pppoe/pppoe_encap.c                    \
-    pppoe/pppoe_tap.c              \
-    pppoe/pppoe_tap_node.c             \
-    pppoe/pppoe.c                      \
+pppoe_plugin_la_SOURCES =      \
+    pppoe/pppoe_decap.c                \
+    pppoe/pppoe_tap.c          \
+    pppoe/pppoe_tap_node.c     \
+    pppoe/pppoe.c              \
     pppoe/pppoe_api.c
 
-BUILT_SOURCES +=                          \
-    pppoe/pppoe.api.h              \
+BUILT_SOURCES +=               \
+    pppoe/pppoe.api.h          \
     pppoe/pppoe.api.json
 
 API_FILES += pppoe/pppoe.api
 
 nobase_apiinclude_HEADERS +=   \
-    pppoe/pppoe_all_api_h.h            \
-    pppoe/pppoe_msg_enum.h             \
+    pppoe/pppoe_all_api_h.h    \
+    pppoe/pppoe_msg_enum.h     \
     pppoe/pppoe.api.h
 
-pppoe_test_plugin_la_SOURCES = \
-    pppoe/pppoe_test.c            \
+pppoe_test_plugin_la_SOURCES = \
+    pppoe/pppoe_test.c         \
     pppoe/pppoe_plugin.api.h
 
 # vi:syntax=automake
index cb587e2..e09ac7d 100644 (file)
 #include <vnet/ethernet/ethernet.h>
 #include <vnet/fib/fib_entry.h>
 #include <vnet/fib/fib_table.h>
-#include <vnet/dpo/dpo.h>
+#include <vnet/dpo/interface_tx_dpo.h>
 #include <vnet/plugin/plugin.h>
 #include <vpp/app/version.h>
 #include <vnet/ppp/packet.h>
 #include <pppoe/pppoe.h>
+#include <vnet/adj/adj_midchain.h>
+#include <vnet/adj/adj_mcast.h>
 
 #include <vppinfra/hash.h>
 #include <vppinfra/bihash_template.c>
@@ -85,7 +87,6 @@ pppoe_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
 VNET_DEVICE_CLASS (pppoe_device_class,static) = {
   .name = "PPPPOE",
   .format_device_name = format_pppoe_name,
-  .format_tx_trace = format_pppoe_encap_trace,
   .tx_function = dummy_interface_tx,
   .admin_up_down_function = pppoe_interface_admin_up_down,
 };
@@ -99,27 +100,19 @@ format_pppoe_header_with_length (u8 * s, va_list * args)
   return s;
 }
 
-/* *INDENT-OFF* */
-VNET_HW_INTERFACE_CLASS (pppoe_hw_class) =
-{
-  .name = "PPPPOE",
-  .format_header = format_pppoe_header_with_length,
-  .build_rewrite = default_build_rewrite,
-  .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
-};
-/* *INDENT-ON* */
-
-#define foreach_copy_field                      \
-_(session_id)                                   \
-_(encap_if_index)                               \
-_(decap_fib_index)                              \
-_(client_ip)
-
-static void
-eth_pppoe_rewrite (pppoe_session_t * t, bool is_ip6)
+static u8 *
+pppoe_build_rewrite (vnet_main_t * vnm,
+                    u32 sw_if_index,
+                    vnet_link_t link_type, const void *dst_address)
 {
-  u8 *rw = 0;
   int len = sizeof (pppoe_header_t) + sizeof (ethernet_header_t);
+  pppoe_main_t *pem = &pppoe_main;
+  pppoe_session_t *t;
+  u32 session_id;
+  u8 *rw = 0;
+
+  session_id = pem->session_index_by_sw_if_index[sw_if_index];
+  t = pool_elt_at_index (pem->sessions, session_id);
 
   vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
 
@@ -134,21 +127,112 @@ eth_pppoe_rewrite (pppoe_session_t * t, bool is_ip6)
   pppoe->session_id = clib_host_to_net_u16 (t->session_id);
   pppoe->length = 0;           /* To be filled in at run-time */
 
-  if (!is_ip6)
+  switch (link_type)
     {
+    case VNET_LINK_IP4:
       pppoe->ppp_proto = clib_host_to_net_u16 (PPP_PROTOCOL_ip4);
+      break;
+    case VNET_LINK_IP6:
+      pppoe->ppp_proto = clib_host_to_net_u16 (PPP_PROTOCOL_ip6);
+      break;
+    default:
+      break;
     }
-  else
+
+  return rw;
+}
+
+/**
+ * @brief Fixup the adj rewrite post encap. Insert the packet's length
+ */
+static void
+pppoe_fixup (vlib_main_t * vm, ip_adjacency_t * adj, vlib_buffer_t * b0)
+{
+  pppoe_header_t *pppoe0;
+
+  pppoe0 = vlib_buffer_get_current (b0);
+
+  pppoe0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
+                                        - sizeof (pppoe_header_t)
+                                        - sizeof (ethernet_header_t));
+}
+
+static void
+pppoe_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
+{
+  pppoe_main_t *pem = &pppoe_main;
+  dpo_id_t dpo = DPO_INVALID;
+  ip_adjacency_t *adj;
+  pppoe_session_t *t;
+  u32 session_id;
+
+  ASSERT (ADJ_INDEX_INVALID != ai);
+
+  adj = adj_get (ai);
+
+  switch (adj->lookup_next_index)
     {
-      pppoe->ppp_proto = clib_host_to_net_u16 (PPP_PROTOCOL_ip6);
+    case IP_LOOKUP_NEXT_ARP:
+    case IP_LOOKUP_NEXT_GLEAN:
+      adj_nbr_midchain_update_rewrite (ai, pppoe_fixup,
+                                      ADJ_FLAG_NONE,
+                                      pppoe_build_rewrite (vnm,
+                                                           sw_if_index,
+                                                           adj->ia_link,
+                                                           NULL));
+      break;
+    case IP_LOOKUP_NEXT_MCAST:
+      /*
+       * Construct a partial rewrite from the known ethernet mcast dest MAC
+       * There's no MAC fixup, so the last 2 parameters are 0
+       */
+      adj_mcast_midchain_update_rewrite (ai, pppoe_fixup,
+                                        ADJ_FLAG_NONE,
+                                        pppoe_build_rewrite (vnm,
+                                                             sw_if_index,
+                                                             adj->ia_link,
+                                                             NULL), 0, 0);
+      break;
+
+    case IP_LOOKUP_NEXT_DROP:
+    case IP_LOOKUP_NEXT_PUNT:
+    case IP_LOOKUP_NEXT_LOCAL:
+    case IP_LOOKUP_NEXT_REWRITE:
+    case IP_LOOKUP_NEXT_MIDCHAIN:
+    case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
+    case IP_LOOKUP_NEXT_ICMP_ERROR:
+    case IP_LOOKUP_N_NEXT:
+      ASSERT (0);
+      break;
     }
 
-  t->rewrite = rw;
-  _vec_len (t->rewrite) = len;
+  session_id = pem->session_index_by_sw_if_index[sw_if_index];
+  t = pool_elt_at_index (pem->sessions, session_id);
+  interface_tx_dpo_add_or_lock (vnet_link_to_dpo_proto (adj->ia_link),
+                               t->encap_if_index, &dpo);
+
+  adj_nbr_midchain_stack (ai, &dpo);
 
-  return;
+  dpo_reset (&dpo);
 }
 
+/* *INDENT-OFF* */
+VNET_HW_INTERFACE_CLASS (pppoe_hw_class) =
+{
+  .name = "PPPPOE",
+  .format_header = format_pppoe_header_with_length,
+  .build_rewrite = pppoe_build_rewrite,
+  .update_adjacency = pppoe_update_adj,
+  .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
+};
+/* *INDENT-ON* */
+
+#define foreach_copy_field                      \
+_(session_id)                                   \
+_(encap_if_index)                               \
+_(decap_fib_index)                              \
+_(client_ip)
+
 static bool
 pppoe_decap_next_is_valid (pppoe_main_t * pem, u32 is_ip6,
                           u32 decap_fib_index)
@@ -231,8 +315,6 @@ int vnet_pppoe_add_del_session
 
       clib_memcpy (t->client_mac, a->client_mac, 6);
 
-      eth_pppoe_rewrite (t, is_ip6);
-
       /* update pppoe fib with session_index */
       result.fields.session_index = t - pem->sessions;
       pppoe_update_1 (&pem->session_table,
@@ -285,9 +367,6 @@ int vnet_pppoe_add_del_session
       vnet_sw_interface_set_flags (vnm, sw_if_index,
                                   VNET_SW_INTERFACE_FLAG_ADMIN_UP);
 
-      /* Set pppoe session output node */
-      hi->output_node_index = pppoe_encap_node.index;
-
       /* add reverse route for client ip */
       fib_table_entry_path_add (a->decap_fib_index, &pfx,
                                FIB_SOURCE_PLUGIN_HI, FIB_ENTRY_FLAG_NONE,
@@ -328,7 +407,6 @@ int vnet_pppoe_add_del_session
                                   sw_if_index, ~0, 1,
                                   FIB_ROUTE_PATH_FLAG_NONE);
 
-      vec_free (t->rewrite);
       pool_put (pem->sessions, t);
     }
 
index 37d628e..b06c068 100644 (file)
@@ -48,9 +48,6 @@ typedef struct
 
 typedef struct
 {
-  /* Rewrite string */
-  u8 *rewrite;
-
   /* pppoe session_id in HOST byte order */
   u16 session_id;
 
@@ -177,11 +174,8 @@ typedef struct
 extern pppoe_main_t pppoe_main;
 
 extern vlib_node_registration_t pppoe_input_node;
-extern vlib_node_registration_t pppoe_encap_node;
 extern vlib_node_registration_t pppoe_tap_dispatch_node;
 
-u8 *format_pppoe_encap_trace (u8 * s, va_list * args);
-
 typedef struct
 {
   u8 is_add;
diff --git a/src/plugins/pppoe/pppoe_encap.c b/src/plugins/pppoe/pppoe_encap.c
deleted file mode 100644 (file)
index 69bec61..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (c) 2017 Intel and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vppinfra/error.h>
-#include <vppinfra/hash.h>
-#include <vnet/vnet.h>
-#include <vnet/ip/ip.h>
-#include <vnet/ethernet/ethernet.h>
-#include <pppoe/pppoe.h>
-
-/* Statistics (not all errors) */
-#define foreach_pppoe_encap_error    \
-_(ENCAPSULATED, "good packets encapsulated")
-
-static char * pppoe_encap_error_strings[] = {
-#define _(sym,string) string,
-  foreach_pppoe_encap_error
-#undef _
-};
-
-typedef enum {
-#define _(sym,str) PPPOE_ENCAP_ERROR_##sym,
-    foreach_pppoe_encap_error
-#undef _
-    PPPOE_ENCAP_N_ERROR,
-} pppoe_encap_error_t;
-
-#define foreach_pppoe_encap_next       \
-_(DROP, "error-drop")                  \
-_(INTERFACE, "interface-output" )      \
-
-typedef enum
-{
-#define _(s,n) PPPOE_ENCAP_NEXT_##s,
-  foreach_pppoe_encap_next
-#undef _
-    PPPOE_ENCAP_N_NEXT,
-} pppoe_encap_next_t;
-
-typedef struct {
-  u32 session_index;
-  u32 session_id;
-} pppoe_encap_trace_t;
-
-u8 * format_pppoe_encap_trace (u8 * s, va_list * args)
-{
-  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
-  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  pppoe_encap_trace_t * t
-      = va_arg (*args, pppoe_encap_trace_t *);
-
-  s = format (s, "PPPOE encap to pppoe_session%d session_id %d",
-             t->session_index, t->session_id);
-  return s;
-}
-
-
-#define foreach_fixed_header2_offset            \
-        _(0) _(1)
-
-
-static uword
-pppoe_encap (vlib_main_t * vm,
-             vlib_node_runtime_t * node,
-             vlib_frame_t * from_frame)
-{
-  u32 n_left_from, next_index, * from, * to_next;
-  pppoe_main_t * pem = &pppoe_main;
-  vnet_main_t * vnm = pem->vnet_main;
-  vnet_interface_main_t * im = &vnm->interface_main;
-  u32 pkts_encapsulated = 0;
-  u32 thread_index = vlib_get_thread_index();
-  u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
-  u32 sw_if_index0 = 0, sw_if_index1 = 0;
-  u32 next0 = 0, next1 = 0;
-  pppoe_session_t * t0 = NULL, * t1 = NULL;
-
-  from = vlib_frame_vector_args (from_frame);
-  n_left_from = from_frame->n_vectors;
-
-  next_index = node->cached_next_index;
-  stats_sw_if_index = node->runtime_data[0];
-  stats_n_packets = stats_n_bytes = 0;
-
-  while (n_left_from > 0)
-    {
-      u32 n_left_to_next;
-
-      vlib_get_next_frame (vm, node, next_index,
-                          to_next, n_left_to_next);
-
-      while (n_left_from >= 4 && n_left_to_next >= 2)
-       {
-          u32 bi0, bi1;
-         vlib_buffer_t * b0, * b1;
-         u32 len0, len1;
-         ethernet_header_t * eth0, * eth1;
-          pppoe_header_t * pppoe0, * pppoe1;
-          u64 * copy_src0, * copy_dst0;
-          u64 * copy_src1, * copy_dst1;
-          u16 * copy_src_last0, * copy_dst_last0;
-          u16 * copy_src_last1, * copy_dst_last1;
-          u16 new_l0, new_l1;
-          u32 session_id0, session_id1;
-
-         /* Prefetch next iteration. */
-         {
-           vlib_buffer_t * p2, * p3;
-
-           p2 = vlib_get_buffer (vm, from[2]);
-           p3 = vlib_get_buffer (vm, from[3]);
-
-           vlib_prefetch_buffer_header (p2, LOAD);
-           vlib_prefetch_buffer_header (p3, LOAD);
-
-           CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
-           CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
-         }
-
-         bi0 = from[0];
-         bi1 = from[1];
-         to_next[0] = bi0;
-         to_next[1] = bi1;
-         from += 2;
-         to_next += 2;
-         n_left_to_next -= 2;
-         n_left_from -= 2;
-
-         b0 = vlib_get_buffer (vm, bi0);
-         b1 = vlib_get_buffer (vm, bi1);
-
-         /* Get next node index and if-index from session */
-         sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_TX];
-         session_id0 = pem->session_index_by_sw_if_index[sw_if_index0];
-         t0 = pool_elt_at_index(pem->sessions, session_id0);
-         next0 = PPPOE_ENCAP_NEXT_INTERFACE;
-          vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_if_index;
-
-          /* Get next node index and if-index from session */
-         sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_TX];
-         session_id1 = pem->session_index_by_sw_if_index[sw_if_index1];
-         t1 = pool_elt_at_index(pem->sessions, session_id1);
-         next1 = PPPOE_ENCAP_NEXT_INTERFACE;
-          vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->encap_if_index;
-
-          /* Apply the rewrite string. $$$$ vnet_rewrite? */
-          vlib_buffer_advance (b0, -(word)_vec_len(t0->rewrite));
-          vlib_buffer_advance (b1, -(word)_vec_len(t1->rewrite));
-
-          eth0 = (ethernet_header_t *)(vlib_buffer_get_current(b0));
-          eth1 = (ethernet_header_t *)(vlib_buffer_get_current(b1));
-
-         /* Copy the fixed header */
-         copy_dst0 = (u64 *) eth0;
-         copy_src0 = (u64 *) t0->rewrite;
-         copy_dst1 = (u64 *) eth1;
-         copy_src1 = (u64 *) t1->rewrite;
-         /* Copy first 8-bytes at a time */
-#define _(offs) copy_dst0[offs] = copy_src0[offs];
-         foreach_fixed_header2_offset;
-#undef _
-         /* Last 6 octets. Hopefully gcc will be our friend */
-          copy_dst_last0 = (u16 *)(&copy_dst0[2]);
-          copy_src_last0 = (u16 *)(&copy_src0[2]);
-          copy_dst_last0[0] = copy_src_last0[0];
-          copy_dst_last0[1] = copy_src_last0[1];
-          copy_dst_last0[2] = copy_src_last0[2];
-
-#define _(offs) copy_dst1[offs] = copy_src1[offs];
-         foreach_fixed_header2_offset;
-#undef _
-         /* Last 6 octets. Hopefully gcc will be our friend */
-          copy_dst_last1 = (u16 *)(&copy_dst1[2]);
-          copy_src_last1 = (u16 *)(&copy_src1[2]);
-          copy_dst_last1[0] = copy_src_last1[0];
-          copy_dst_last1[1] = copy_src_last1[1];
-          copy_dst_last1[2] = copy_src_last1[2];
-
-          /* Fix PPPoE length */
-         new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain(vm, b0)
-                                        - sizeof (*pppoe0) - sizeof(*eth0));
-         pppoe0 = (pppoe_header_t *)(eth0 + 1);
-         pppoe0->length = new_l0;
-
-         new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain(vm, b1)
-                                        - sizeof (*pppoe1) - sizeof(*eth1));
-         pppoe1 = (pppoe_header_t *)(eth1 + 1);
-         pppoe1->length = new_l1;
-
-          pkts_encapsulated += 2;
-         len0 = vlib_buffer_length_in_chain (vm, b0);
-         len1 = vlib_buffer_length_in_chain (vm, b1);
-         stats_n_packets += 2;
-         stats_n_bytes += len0 + len1;
-
-         /* Batch stats increment on the same pppoe session so counter is not
-            incremented per packet. Note stats are still incremented for deleted
-            and admin-down session where packets are dropped. It is not worthwhile
-            to check for this rare case and affect normal path performance. */
-         if (PREDICT_FALSE ((sw_if_index0 != stats_sw_if_index) ||
-                            (sw_if_index1 != stats_sw_if_index)))
-           {
-             stats_n_packets -= 2;
-             stats_n_bytes -= len0 + len1;
-             if (sw_if_index0 == sw_if_index1)
-               {
-                 if (stats_n_packets)
-                   vlib_increment_combined_counter
-                     (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
-                      thread_index, stats_sw_if_index,
-                      stats_n_packets, stats_n_bytes);
-                 stats_sw_if_index = sw_if_index0;
-                 stats_n_packets = 2;
-                 stats_n_bytes = len0 + len1;
-               }
-             else
-               {
-                 vlib_increment_combined_counter
-                     (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
-                      thread_index, sw_if_index0, 1, len0);
-                 vlib_increment_combined_counter
-                     (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
-                      thread_index, sw_if_index1, 1, len1);
-               }
-           }
-
-         if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
-            {
-              pppoe_encap_trace_t *tr =
-                vlib_add_trace (vm, node, b0, sizeof (*tr));
-              tr->session_index = t0 - pem->sessions;
-              tr->session_id = t0->session_id;
-           }
-
-          if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
-            {
-              pppoe_encap_trace_t *tr =
-                vlib_add_trace (vm, node, b1, sizeof (*tr));
-              tr->session_index = t1 - pem->sessions;
-              tr->session_id = t1->session_id;
-            }
-
-         vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
-                                          to_next, n_left_to_next,
-                                          bi0, bi1, next0, next1);
-       }
-
-      while (n_left_from > 0 && n_left_to_next > 0)
-       {
-         u32 bi0;
-         vlib_buffer_t * b0;
-         ethernet_header_t * eth0;
-          pppoe_header_t * pppoe0;
-          u64 * copy_src0, * copy_dst0;
-          u16 * copy_src_last0, * copy_dst_last0;
-          u16 new_l0;
-          u32 len0;
-          u32 session_id0;
-
-         bi0 = from[0];
-         to_next[0] = bi0;
-         from += 1;
-         to_next += 1;
-         n_left_from -= 1;
-         n_left_to_next -= 1;
-
-         b0 = vlib_get_buffer (vm, bi0);
-
-         /* Get next node index and if-index from session */
-         sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_TX];
-         session_id0 = pem->session_index_by_sw_if_index[sw_if_index0];
-         t0 = pool_elt_at_index(pem->sessions, session_id0);
-         next0 = PPPOE_ENCAP_NEXT_INTERFACE;
-          vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_if_index;
-
-          /* Apply the rewrite string. $$$$ vnet_rewrite? */
-          vlib_buffer_advance (b0, -(word)_vec_len(t0->rewrite));
-
-          eth0 = (ethernet_header_t *)(vlib_buffer_get_current(b0));
-         /* Copy the fixed header */
-         copy_dst0 = (u64 *) eth0;
-         copy_src0 = (u64 *) t0->rewrite;
-
-         /* Copy first 8-bytes at a time */
-#define _(offs) copy_dst0[offs] = copy_src0[offs];
-         foreach_fixed_header2_offset;
-#undef _
-         /* Last 6 octets. Hopefully gcc will be our friend */
-          copy_dst_last0 = (u16 *)(&copy_dst0[2]);
-          copy_src_last0 = (u16 *)(&copy_src0[2]);
-          copy_dst_last0[0] = copy_src_last0[0];
-          copy_dst_last0[1] = copy_src_last0[1];
-          copy_dst_last0[2] = copy_src_last0[2];
-
-          /* Fix PPPoE length */
-         new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain(vm, b0)
-                                        - sizeof (*pppoe0) - sizeof(*eth0));
-         pppoe0 = (pppoe_header_t *)(eth0 + 1);
-         pppoe0->length = new_l0;
-
-          pkts_encapsulated ++;
-         len0 = vlib_buffer_length_in_chain (vm, b0);
-         stats_n_packets += 1;
-         stats_n_bytes += len0;
-
-         /* Batch stats increment on the same pppoe session so counter is not
-            incremented per packet. Note stats are still incremented for deleted
-            and admin-down session where packets are dropped. It is not worthwhile
-            to check for this rare case and affect normal path performance. */
-         if (PREDICT_FALSE (sw_if_index0 != stats_sw_if_index))
-           {
-             stats_n_packets -= 1;
-             stats_n_bytes -= len0;
-             if (stats_n_packets)
-               vlib_increment_combined_counter
-                 (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
-                  thread_index, stats_sw_if_index,
-                  stats_n_packets, stats_n_bytes);
-             stats_n_packets = 1;
-             stats_n_bytes = len0;
-             stats_sw_if_index = sw_if_index0;
-           }
-
-          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
-            {
-              pppoe_encap_trace_t *tr =
-                vlib_add_trace (vm, node, b0, sizeof (*tr));
-              tr->session_index = t0 - pem->sessions;
-              tr->session_id = t0->session_id;
-            }
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                          to_next, n_left_to_next,
-                                          bi0, next0);
-       }
-
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-    }
-
-  /* Do we still need this now that session tx stats is kept? */
-  vlib_node_increment_counter (vm, node->node_index,
-                               PPPOE_ENCAP_ERROR_ENCAPSULATED,
-                               pkts_encapsulated);
-
-  /* Increment any remaining batch stats */
-  if (stats_n_packets)
-    {
-      vlib_increment_combined_counter
-       (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX,
-        thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
-      node->runtime_data[0] = stats_sw_if_index;
-    }
-
-  return from_frame->n_vectors;
-}
-
-VLIB_REGISTER_NODE (pppoe_encap_node) = {
-  .function = pppoe_encap,
-  .name = "pppoe-encap",
-  .vector_size = sizeof (u32),
-  .format_trace = format_pppoe_encap_trace,
-  .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_errors = ARRAY_LEN(pppoe_encap_error_strings),
-  .error_strings = pppoe_encap_error_strings,
-  .n_next_nodes = PPPOE_ENCAP_N_NEXT,
-  .next_nodes = {
-#define _(s,n) [PPPOE_ENCAP_NEXT_##s] = n,
-    foreach_pppoe_encap_next
-#undef _
-  },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (pppoe_encap_node, pppoe_encap)
-
index 9821069..182ec1f 100644 (file)
@@ -1011,7 +1011,8 @@ libvnet_la_SOURCES +=                             \
   vnet/dpo/lookup_dpo.c                        \
   vnet/dpo/classify_dpo.c                      \
   vnet/dpo/replicate_dpo.c                     \
-  vnet/dpo/interface_dpo.c                     \
+  vnet/dpo/interface_rx_dpo.c                          \
+  vnet/dpo/interface_tx_dpo.c                          \
   vnet/dpo/mpls_disposition.c                  \
   vnet/dpo/mpls_label_dpo.c
 
index a93a1c3..e9a510b 100644 (file)
@@ -65,8 +65,7 @@ adj_midchain_tx_inline (vlib_main_t * vm,
        /* set up to enqueue to our disposition with index = next_index */
        vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
 
-
-       while (n_left_from >= 4 && n_left_to_next > 2)
+       while (n_left_from >= 8 && n_left_to_next > 4)
        {
            u32 bi0, adj_index0, next0;
            const ip_adjacency_t * adj0;
@@ -76,49 +75,75 @@ adj_midchain_tx_inline (vlib_main_t * vm,
            const ip_adjacency_t * adj1;
            const dpo_id_t *dpo1;
            vlib_buffer_t * b1;
+           u32 bi2, adj_index2, next2;
+           const ip_adjacency_t * adj2;
+           const dpo_id_t *dpo2;
+           vlib_buffer_t * b2;
+           u32 bi3, adj_index3, next3;
+           const ip_adjacency_t * adj3;
+           const dpo_id_t *dpo3;
+           vlib_buffer_t * b3;
 
            /* Prefetch next iteration. */
            {
-               vlib_buffer_t * p2, * p3;
-
-               p2 = vlib_get_buffer (vm, from[2]);
-               p3 = vlib_get_buffer (vm, from[3]);
-
-               vlib_prefetch_buffer_header (p2, LOAD);
-               vlib_prefetch_buffer_header (p3, LOAD);
-
-               CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
-               CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
+               vlib_buffer_t * p4, * p5;
+               vlib_buffer_t * p6, * p7;
+
+               p4 = vlib_get_buffer (vm, from[4]);
+               p5 = vlib_get_buffer (vm, from[5]);
+               p6 = vlib_get_buffer (vm, from[6]);
+               p7 = vlib_get_buffer (vm, from[7]);
+
+               vlib_prefetch_buffer_header (p4, LOAD);
+               vlib_prefetch_buffer_header (p5, LOAD);
+               vlib_prefetch_buffer_header (p6, LOAD);
+               vlib_prefetch_buffer_header (p7, LOAD);
            }
 
            bi0 = from[0];
            to_next[0] = bi0;
            bi1 = from[1];
            to_next[1] = bi1;
+           bi2 = from[2];
+           to_next[2] = bi2;
+           bi3 = from[3];
+           to_next[3] = bi3;
 
-           from += 2;
-           to_next += 2;
-           n_left_from -= 2;
-           n_left_to_next -= 2;
+           from += 4;
+           to_next += 4;
+           n_left_from -= 4;
+           n_left_to_next -= 4;
 
            b0 = vlib_get_buffer(vm, bi0);
            b1 = vlib_get_buffer(vm, bi1);
+           b2 = vlib_get_buffer(vm, bi2);
+           b3 = vlib_get_buffer(vm, bi3);
 
            /* Follow the DPO on which the midchain is stacked */
            adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
            adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
+           adj_index2 = vnet_buffer(b2)->ip.adj_index[VLIB_TX];
+           adj_index3 = vnet_buffer(b3)->ip.adj_index[VLIB_TX];
 
            adj0 = adj_get(adj_index0);
            adj1 = adj_get(adj_index1);
+           adj2 = adj_get(adj_index2);
+           adj3 = adj_get(adj_index3);
 
            dpo0 = &adj0->sub_type.midchain.next_dpo;
            dpo1 = &adj1->sub_type.midchain.next_dpo;
+           dpo2 = &adj2->sub_type.midchain.next_dpo;
+           dpo3 = &adj3->sub_type.midchain.next_dpo;
 
            next0 = dpo0->dpoi_next_node;
            next1 = dpo1->dpoi_next_node;
+           next2 = dpo2->dpoi_next_node;
+           next3 = dpo3->dpoi_next_node;
 
-           vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
-           vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+            vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
+            vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+            vnet_buffer(b2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
+            vnet_buffer(b3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
 
            if (interface_count)
            {
@@ -134,6 +159,18 @@ adj_midchain_tx_inline (vlib_main_t * vm,
                                                 adj1->rewrite_header.sw_if_index,
                                                 1,
                                                 vlib_buffer_length_in_chain (vm, b1));
+               vlib_increment_combined_counter (im->combined_sw_if_counters
+                                                + VNET_INTERFACE_COUNTER_TX,
+                                                thread_index,
+                                                adj2->rewrite_header.sw_if_index,
+                                                1,
+                                                vlib_buffer_length_in_chain (vm, b2));
+               vlib_increment_combined_counter (im->combined_sw_if_counters
+                                                + VNET_INTERFACE_COUNTER_TX,
+                                                thread_index,
+                                                adj3->rewrite_header.sw_if_index,
+                                                1,
+                                                vlib_buffer_length_in_chain (vm, b3));
            }
 
            if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
@@ -148,11 +185,23 @@ adj_midchain_tx_inline (vlib_main_t * vm,
                                                              b1, sizeof (*tr));
                tr->ai = adj_index1;
            }
+           if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
+           {
+               adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
+                                                             b2, sizeof (*tr));
+               tr->ai = adj_index2;
+           }
+           if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
+           {
+               adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
+                                                             b3, sizeof (*tr));
+               tr->ai = adj_index3;
+           }
 
-           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
+           vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
                                             to_next, n_left_to_next,
-                                            bi0, bi1,
-                                            next0, next1);
+                                            bi0, bi1, bi2, bi3,
+                                            next0, next1, next2, next3);
        }
        while (n_left_from > 0 && n_left_to_next > 0)
        {
@@ -175,7 +224,7 @@ adj_midchain_tx_inline (vlib_main_t * vm,
            adj0 = adj_get(adj_index0);
            dpo0 = &adj0->sub_type.midchain.next_dpo;
            next0 = dpo0->dpoi_next_node;
-           vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+            vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
 
            if (interface_count)
            {
@@ -392,6 +441,17 @@ adj_nbr_midchain_get_tx_node (ip_adjacency_t *adj)
             adj_midchain_tx_node.index);
 }
 
+static u32
+adj_nbr_midchain_get_feature_node (ip_adjacency_t *adj)
+{
+    if (adj->ia_flags & ADJ_FLAG_MIDCHAIN_NO_COUNT)
+    {
+        return (adj_midchain_tx_no_count_feature_node[adj->ia_link]);
+    }
+
+    return (adj_midchain_tx_feature_node[adj->ia_link]);
+}
+
 /**
  * adj_midchain_setup
  *
@@ -414,10 +474,7 @@ adj_midchain_setup (adj_index_t adj_index,
     adj->ia_flags |= flags;
 
     arc_index = adj_midchain_get_feature_arc_index_for_link_type (adj);
-    feature_index = (flags & ADJ_FLAG_MIDCHAIN_NO_COUNT) ?
-                    adj_midchain_tx_no_count_feature_node[adj->ia_link] :
-                    adj_midchain_tx_feature_node[adj->ia_link];
-
+    feature_index = adj_nbr_midchain_get_feature_node(adj);
     tx_node = adj_nbr_midchain_get_tx_node(adj);
 
     vnet_feature_enable_disable_with_index (arc_index, feature_index,
@@ -432,8 +489,8 @@ adj_midchain_setup (adj_index_t adj_index,
      * need to get to the stacked child's node.
      */
     dpo_stack_from_node(tx_node,
-                       &adj->sub_type.midchain.next_dpo,
-                       drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
+                        &adj->sub_type.midchain.next_dpo,
+                        drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
 }
 
 /**
@@ -495,10 +552,9 @@ adj_nbr_midchain_unstack (adj_index_t adj_index)
      * stack on the drop
      */
     dpo_stack(DPO_ADJACENCY_MIDCHAIN,
-             vnet_link_to_dpo_proto(adj->ia_link),
-             &adj->sub_type.midchain.next_dpo,
-             drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
-
+              vnet_link_to_dpo_proto(adj->ia_link),
+              &adj->sub_type.midchain.next_dpo,
+              drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
     CLIB_MEMORY_BARRIER();
 }
 
@@ -537,9 +593,9 @@ format_adj_midchain (u8* s, va_list *ap)
                format_vnet_rewrite,
                &adj->rewrite_header, sizeof (adj->rewrite_data), indent);
     s = format (s, "\n%Ustacked-on:\n%U%U",
-               format_white_space, indent,
-               format_white_space, indent+2,
-               format_dpo_id, &adj->sub_type.midchain.next_dpo, indent+2);
+                format_white_space, indent,
+                format_white_space, indent+2,
+                format_dpo_id, &adj->sub_type.midchain.next_dpo, indent+2);
 
     return (s);
 }
index aa77083..bd18b66 100644 (file)
@@ -37,7 +37,8 @@
 #include <vnet/dpo/classify_dpo.h>
 #include <vnet/dpo/ip_null_dpo.h>
 #include <vnet/dpo/replicate_dpo.h>
-#include <vnet/dpo/interface_dpo.h>
+#include <vnet/dpo/interface_rx_dpo.h>
+#include <vnet/dpo/interface_tx_dpo.h>
 #include <vnet/dpo/mpls_disposition.h>
 
 /**
@@ -275,6 +276,29 @@ dpo_is_adj (const dpo_id_t *dpo)
            (dpo->dpoi_type == DPO_ADJACENCY_GLEAN));
 }
 
+static u32 *
+dpo_default_get_next_node (const dpo_id_t *dpo)
+{
+    u32 *node_indices = NULL;
+    const char *node_name;
+    u32 ii = 0;
+
+    node_name = dpo_nodes[dpo->dpoi_type][dpo->dpoi_proto][ii];
+    while (NULL != node_name)
+    {
+        vlib_node_t *node;
+
+        node = vlib_get_node_by_name(vlib_get_main(), (u8*) node_name);
+        ASSERT(NULL != node);
+        vec_add1(node_indices, node->index);
+
+        ++ii;
+        node_name = dpo_nodes[dpo->dpoi_type][dpo->dpoi_proto][ii];
+    }
+
+    return (node_indices);
+}
+
 void
 dpo_register (dpo_type_t type,
              const dpo_vft_t *vft,
@@ -282,6 +306,10 @@ dpo_register (dpo_type_t type,
 {
     vec_validate(dpo_vfts, type);
     dpo_vfts[type] = *vft;
+    if (NULL == dpo_vfts[type].dv_get_next_node)
+    {
+        dpo_vfts[type].dv_get_next_node = dpo_default_get_next_node;
+    }
 
     vec_validate(dpo_nodes, type);
     dpo_nodes[type] = nodes;
@@ -340,24 +368,25 @@ dpo_get_next_node (dpo_type_t child_type,
      */
     if (~0 == dpo_edges[child_type][child_proto][parent_type][parent_proto])
     {
-        vlib_node_t *parent_node, *child_node;
+        vlib_node_t *child_node;
+        u32 *parent_indices;
         vlib_main_t *vm;
-        u32 edge ,pp, cc;
+        u32 edge, *pi, cc;
 
         vm = vlib_get_main();
 
-        vlib_worker_thread_barrier_sync(vm);
-
+        ASSERT(NULL != dpo_vfts[parent_type].dv_get_next_node);
         ASSERT(NULL != dpo_nodes[child_type]);
         ASSERT(NULL != dpo_nodes[child_type][child_proto]);
-        ASSERT(NULL != dpo_nodes[parent_type]);
-        ASSERT(NULL != dpo_nodes[parent_type][parent_proto]);
 
         cc = 0;
+        parent_indices = dpo_vfts[parent_type].dv_get_next_node(parent_dpo);
+
+        vlib_worker_thread_barrier_sync(vm);
 
         /*
-         * create a graph arc from each of the parent's registered node types,
-         * to each of the childs.
+         * create a graph arc from each of the child's registered node types,
+         * to each of the parent's.
          */
         while (NULL != dpo_nodes[child_type][child_proto][cc])
         {
@@ -365,17 +394,9 @@ dpo_get_next_node (dpo_type_t child_type,
                 vlib_get_node_by_name(vm,
                                       (u8*) dpo_nodes[child_type][child_proto][cc]);
 
-            pp = 0;
-
-            while (NULL != dpo_nodes[parent_type][parent_proto][pp])
+            vec_foreach(pi, parent_indices)
             {
-                parent_node =
-                    vlib_get_node_by_name(vm,
-                                          (u8*) dpo_nodes[parent_type][parent_proto][pp]);
-
-                edge = vlib_node_add_next(vm,
-                                          child_node->index,
-                                          parent_node->index);
+                edge = vlib_node_add_next(vm, child_node->index, *pi);
 
                 if (~0 == dpo_edges[child_type][child_proto][parent_type][parent_proto])
                 {
@@ -385,12 +406,12 @@ dpo_get_next_node (dpo_type_t child_type,
                 {
                     ASSERT(dpo_edges[child_type][child_proto][parent_type][parent_proto] == edge);
                 }
-                pp++;
             }
             cc++;
         }
 
         vlib_worker_thread_barrier_release(vm);
+        vec_free(parent_indices);
     }
 
     return (dpo_edges[child_type][child_proto][parent_type][parent_proto]);
@@ -451,38 +472,39 @@ dpo_stack_from_node (u32 child_node_index,
                      dpo_id_t *dpo,
                      const dpo_id_t *parent)
 {
-    dpo_proto_t parent_proto;
-    vlib_node_t *parent_node;
     dpo_type_t parent_type;
+    u32 *parent_indices;
     vlib_main_t *vm;
-    u32 edge;
+    u32 edge, *pi;
 
+    edge = 0;
     parent_type = parent->dpoi_type;
-    parent_proto = parent->dpoi_proto;
-
     vm = vlib_get_main();
 
-    ASSERT(NULL != dpo_nodes[parent_type]);
-    ASSERT(NULL != dpo_nodes[parent_type][parent_proto]);
+    ASSERT(NULL != dpo_vfts[parent_type].dv_get_next_node);
+    parent_indices = dpo_vfts[parent_type].dv_get_next_node(parent);
+    ASSERT(parent_indices);
 
-    parent_node =
-        vlib_get_node_by_name(vm, (u8*) dpo_nodes[parent_type][parent_proto][0]);
-
-    edge = vlib_node_get_next(vm,
-                              child_node_index,
-                              parent_node->index);
-
-    if (~0 == edge)
+    /*
+     * This loop is purposefully written with the worker thread lock in the
+     * inner loop because;
+     *  1) the likelihood that the edge does not exist is smaller
+     *  2) the likelihood there is more than one node is even smaller
+     * so we are optimising for not need to take the lock
+     */
+    vec_foreach(pi, parent_indices)
     {
-        vlib_worker_thread_barrier_sync(vm);
+        edge = vlib_node_get_next(vm, child_node_index, *pi);
 
-        edge = vlib_node_add_next(vm,
-                                  child_node_index,
-                                  parent_node->index);
+        if (~0 == edge)
+        {
+            vlib_worker_thread_barrier_sync(vm);
 
-        vlib_worker_thread_barrier_release(vm);
-    }
+            edge = vlib_node_add_next(vm, child_node_index, *pi);
 
+            vlib_worker_thread_barrier_release(vm);
+        }
+    }
     dpo_stack_i(edge, dpo, parent);
 }
 
@@ -498,7 +520,8 @@ dpo_module_init (vlib_main_t * vm)
     lookup_dpo_module_init();
     ip_null_dpo_module_init();
     replicate_module_init();
-    interface_dpo_module_init();
+    interface_rx_dpo_module_init();
+    interface_tx_dpo_module_init();
     mpls_disp_dpo_module_init();
 
     return (NULL);
index 42fc51d..3356296 100644 (file)
@@ -112,7 +112,8 @@ typedef enum dpo_type_t_ {
     DPO_MPLS_LABEL,
     DPO_MPLS_DISPOSITION,
     DPO_MFIB_ENTRY,
-    DPO_INTERFACE,
+    DPO_INTERFACE_RX,
+    DPO_INTERFACE_TX,
     DPO_LAST,
 } __attribute__((packed)) dpo_type_t;
 
@@ -138,7 +139,8 @@ typedef enum dpo_type_t_ {
     [DPO_MPLS_LABEL] = "dpo-mpls-label", \
     [DPO_MPLS_DISPOSITION] = "dpo-mpls-diposition", \
     [DPO_MFIB_ENTRY] = "dpo-mfib_entry", \
-    [DPO_INTERFACE] = "dpo-interface"  \
+    [DPO_INTERFACE_RX] = "dpo-interface-rx",   \
+    [DPO_INTERFACE_TX] = "dpo-interface-tx"    \
 }
 
 /**
@@ -331,6 +333,12 @@ typedef void (*dpo_unlock_fn_t)(dpo_id_t *dpo);
  */
 typedef void (*dpo_mem_show_t)(void);
 
+/**
+ * @brief Given a DPO instance return a vector of node indices that
+ * the type/instance will use.
+ */
+typedef u32* (*dpo_get_next_node_t)(const dpo_id_t *dpo);
+
 /**
  * @brief A virtual function table regisitered for a DPO type
  */
@@ -352,6 +360,13 @@ typedef struct dpo_vft_t_
      * A show memory usage function
      */
     dpo_mem_show_t dv_mem_show;
+    /**
+     * A function to get the next VLIB node given an instance
+     * of the DPO. If this is null, then the node's name MUST be
+     * retreiveable from the nodes names array passed in the register
+     * function
+     */
+    dpo_get_next_node_t dv_get_next_node;
 } dpo_vft_t;
 
 
diff --git a/src/vnet/dpo/interface_dpo.c b/src/vnet/dpo/interface_dpo.c
deleted file mode 100644 (file)
index 780bfa2..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vnet/dpo/interface_dpo.h>
-#include <vnet/fib/fib_node.h>
-
-/*
- * The 'DB' of interface DPOs.
- * There is only one  per-interface per-protocol, so this is a per-interface
- * vector
- */
-static index_t *interface_dpo_db[DPO_PROTO_NUM];
-
-static interface_dpo_t *
-interface_dpo_alloc (void)
-{
-    interface_dpo_t *ido;
-
-    pool_get(interface_dpo_pool, ido);
-
-    return (ido);
-}
-
-static inline interface_dpo_t *
-interface_dpo_get_from_dpo (const dpo_id_t *dpo)
-{
-    ASSERT(DPO_INTERFACE == dpo->dpoi_type);
-
-    return (interface_dpo_get(dpo->dpoi_index));
-}
-
-static inline index_t
-interface_dpo_get_index (interface_dpo_t *ido)
-{
-    return (ido - interface_dpo_pool);
-}
-
-static void
-interface_dpo_lock (dpo_id_t *dpo)
-{
-    interface_dpo_t *ido;
-
-    ido = interface_dpo_get_from_dpo(dpo);
-    ido->ido_locks++;
-}
-
-static void
-interface_dpo_unlock (dpo_id_t *dpo)
-{
-    interface_dpo_t *ido;
-
-    ido = interface_dpo_get_from_dpo(dpo);
-    ido->ido_locks--;
-
-    if (0 == ido->ido_locks)
-    {
-       interface_dpo_db[ido->ido_proto][ido->ido_sw_if_index] =
-            INDEX_INVALID;
-        pool_put(interface_dpo_pool, ido);
-    }
-}
-
-/*
- * interface_dpo_add_or_lock
- *
- * Add/create and lock a new or lock an existing for the interface DPO
- * on the interface and protocol given
- */
-void
-interface_dpo_add_or_lock (dpo_proto_t proto,
-                           u32 sw_if_index,
-                           dpo_id_t *dpo)
-{
-    interface_dpo_t *ido;
-
-    vec_validate_init_empty(interface_dpo_db[proto],
-                            sw_if_index,
-                            INDEX_INVALID);
-
-    if (INDEX_INVALID == interface_dpo_db[proto][sw_if_index])
-    {
-       ido = interface_dpo_alloc();
-
-        ido->ido_sw_if_index = sw_if_index;
-        ido->ido_proto = proto;
-
-       interface_dpo_db[proto][sw_if_index] =
-            interface_dpo_get_index(ido);
-    }
-    else
-    {
-       ido = interface_dpo_get(interface_dpo_db[proto][sw_if_index]);
-    }
-
-    dpo_set(dpo, DPO_INTERFACE, proto, interface_dpo_get_index(ido));
-}
-
-
-static clib_error_t *
-interface_dpo_interface_state_change (vnet_main_t * vnm,
-                                      u32 sw_if_index,
-                                      u32 flags)
-{
-    /*
-     */
-    return (NULL);
-}
-
-VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(
-    interface_dpo_interface_state_change);
-
-/**
- * @brief Registered callback for HW interface state changes
- */
-static clib_error_t *
-interface_dpo_hw_interface_state_change (vnet_main_t * vnm,
-                                         u32 hw_if_index,
-                                         u32 flags)
-{
-    return (NULL);
-}
-
-VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(
-    interface_dpo_hw_interface_state_change);
-
-static clib_error_t *
-interface_dpo_interface_delete (vnet_main_t * vnm,
-                                u32 sw_if_index,
-                                u32 is_add)
-{
-    return (NULL);
-}
-
-VNET_SW_INTERFACE_ADD_DEL_FUNCTION(
-    interface_dpo_interface_delete);
-
-u8*
-format_interface_dpo (u8* s, va_list *ap)
-{
-    index_t index = va_arg(*ap, index_t);
-    CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
-    vnet_main_t * vnm = vnet_get_main();
-    interface_dpo_t *ido = interface_dpo_get(index);
-
-    return (format(s, "%U-dpo: %U",
-                   format_vnet_sw_interface_name,
-                   vnm,
-                   vnet_get_sw_interface(vnm, ido->ido_sw_if_index),
-                   format_dpo_proto, ido->ido_proto));
-}
-
-static void
-interface_dpo_mem_show (void)
-{
-    fib_show_memory_usage("Interface",
-                         pool_elts(interface_dpo_pool),
-                         pool_len(interface_dpo_pool),
-                         sizeof(interface_dpo_t));
-}
-
-
-const static dpo_vft_t interface_dpo_vft = {
-    .dv_lock = interface_dpo_lock,
-    .dv_unlock = interface_dpo_unlock,
-    .dv_format = format_interface_dpo,
-    .dv_mem_show = interface_dpo_mem_show,
-};
-
-/**
- * @brief The per-protocol VLIB graph nodes that are assigned to a glean
- *        object.
- *
- * this means that these graph nodes are ones from which a glean is the
- * parent object in the DPO-graph.
- */
-const static char* const interface_dpo_ip4_nodes[] =
-{
-    "interface-dpo-ip4",
-    NULL,
-};
-const static char* const interface_dpo_ip6_nodes[] =
-{
-    "interface-dpo-ip4",
-    NULL,
-};
-const static char* const interface_dpo_l2_nodes[] =
-{
-    "interface-dpo-l2",
-    NULL,
-};
-
-const static char* const * const interface_dpo_nodes[DPO_PROTO_NUM] =
-{
-    [DPO_PROTO_IP4]  = interface_dpo_ip4_nodes,
-    [DPO_PROTO_IP6]  = interface_dpo_ip6_nodes,
-    [DPO_PROTO_ETHERNET]  = interface_dpo_l2_nodes,
-    [DPO_PROTO_MPLS] = NULL,
-};
-
-void
-interface_dpo_module_init (void)
-{
-    dpo_register(DPO_INTERFACE,
-                 &interface_dpo_vft,
-                 interface_dpo_nodes);
-}
-
-/**
- * @brief Interface DPO trace data
- */
-typedef struct interface_dpo_trace_t_
-{
-    u32 sw_if_index;
-} interface_dpo_trace_t;
-
-typedef enum interface_dpo_next_t_
-{
-    INTERFACE_DPO_DROP = 0,
-    INTERFACE_DPO_INPUT = 1,
-} interface_dpo_next_t;
-
-always_inline uword
-interface_dpo_inline (vlib_main_t * vm,
-                      vlib_node_runtime_t * node,
-                      vlib_frame_t * from_frame)
-{
-    u32 n_left_from, next_index, * from, * to_next;
-    u32 thread_index = vlib_get_thread_index ();
-    vnet_interface_main_t *im;
-
-    im = &vnet_get_main ()->interface_main;
-    from = vlib_frame_vector_args (from_frame);
-    n_left_from = from_frame->n_vectors;
-
-    next_index = node->cached_next_index;
-
-    while (n_left_from > 0)
-    {
-        u32 n_left_to_next;
-
-        vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
-
-       while (n_left_from >= 4 && n_left_to_next > 2)
-       {
-           const interface_dpo_t *ido0, *ido1;
-           u32 bi0, idoi0, bi1, idoi1;
-           vlib_buffer_t *b0, *b1;
-
-           bi0 = from[0];
-           to_next[0] = bi0;
-           bi1 = from[1];
-           to_next[1] = bi1;
-           from += 2;
-           to_next += 2;
-           n_left_from -= 2;
-           n_left_to_next -= 2;
-
-           b0 = vlib_get_buffer (vm, bi0);
-           b1 = vlib_get_buffer (vm, bi1);
-
-           idoi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
-           idoi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
-           ido0 = interface_dpo_get(idoi0);
-           ido1 = interface_dpo_get(idoi1);
-
-           vnet_buffer(b0)->sw_if_index[VLIB_RX] = ido0->ido_sw_if_index;
-           vnet_buffer(b1)->sw_if_index[VLIB_RX] = ido1->ido_sw_if_index;
-
-            vlib_increment_combined_counter (im->combined_sw_if_counters
-                                             + VNET_INTERFACE_COUNTER_RX,
-                                             thread_index,
-                                             ido0->ido_sw_if_index,
-                                             1,
-                                             vlib_buffer_length_in_chain (vm, b0));
-            vlib_increment_combined_counter (im->combined_sw_if_counters
-                                             + VNET_INTERFACE_COUNTER_RX,
-                                             thread_index,
-                                             ido1->ido_sw_if_index,
-                                             1,
-                                             vlib_buffer_length_in_chain (vm, b1));
-
-           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
-           {
-               interface_dpo_trace_t *tr0;
-
-                tr0 = vlib_add_trace (vm, node, b0, sizeof (*tr0));
-               tr0->sw_if_index = ido0->ido_sw_if_index;
-           }
-           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
-           {
-               interface_dpo_trace_t *tr1;
-
-                tr1 = vlib_add_trace (vm, node, b1, sizeof (*tr1));
-               tr1->sw_if_index = ido1->ido_sw_if_index;
-           }
-
-           vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
-                                           n_left_to_next, bi0, bi1,
-                                            INTERFACE_DPO_INPUT,
-                                            INTERFACE_DPO_INPUT);
-       }
-
-       while (n_left_from > 0 && n_left_to_next > 0)
-       {
-           const interface_dpo_t * ido0;
-           vlib_buffer_t * b0;
-           u32 bi0, idoi0;
-
-           bi0 = from[0];
-           to_next[0] = bi0;
-           from += 1;
-           to_next += 1;
-           n_left_from -= 1;
-           n_left_to_next -= 1;
-
-           b0 = vlib_get_buffer (vm, bi0);
-
-           idoi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
-           ido0 = interface_dpo_get(idoi0);
-
-            /* Swap the RX interface of the packet to the one the
-             * interface DPR represents */
-           vnet_buffer(b0)->sw_if_index[VLIB_RX] = ido0->ido_sw_if_index;
-
-            /* Bump the interface's RX coutners */
-            vlib_increment_combined_counter (im->combined_sw_if_counters
-                                             + VNET_INTERFACE_COUNTER_RX,
-                                             thread_index,
-                                             ido0->ido_sw_if_index,
-                                             1,
-                                             vlib_buffer_length_in_chain (vm, b0));
-
-           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
-           {
-               interface_dpo_trace_t *tr;
-
-                tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
-               tr->sw_if_index = ido0->ido_sw_if_index;
-           }
-
-           vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
-                                           n_left_to_next, bi0,
-                                            INTERFACE_DPO_INPUT);
-       }
-        vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-    }
-    return from_frame->n_vectors;
-}
-
-static u8 *
-format_interface_dpo_trace (u8 * s, va_list * args)
-{
-    CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
-    CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-    interface_dpo_trace_t * t = va_arg (*args, interface_dpo_trace_t *);
-    uword indent = format_get_indent (s);
-    s = format (s, "%U sw_if_index:%d",
-                format_white_space, indent,
-                t->sw_if_index);
-    return s;
-}
-
-static uword
-interface_dpo_ip4 (vlib_main_t * vm,
-                   vlib_node_runtime_t * node,
-                   vlib_frame_t * from_frame)
-{
-    return (interface_dpo_inline(vm, node, from_frame));
-}
-
-static uword
-interface_dpo_ip6 (vlib_main_t * vm,
-                   vlib_node_runtime_t * node,
-                   vlib_frame_t * from_frame)
-{
-    return (interface_dpo_inline(vm, node, from_frame));
-}
-
-static uword
-interface_dpo_l2 (vlib_main_t * vm,
-                   vlib_node_runtime_t * node,
-                   vlib_frame_t * from_frame)
-{
-    return (interface_dpo_inline(vm, node, from_frame));
-}
-
-VLIB_REGISTER_NODE (interface_dpo_ip4_node) = {
-    .function = interface_dpo_ip4,
-    .name = "interface-dpo-ip4",
-    .vector_size = sizeof (u32),
-    .format_trace = format_interface_dpo_trace,
-
-    .n_next_nodes = 2,
-    .next_nodes = {
-        [INTERFACE_DPO_DROP] = "ip4-drop",
-        [INTERFACE_DPO_INPUT] = "ip4-input",
-    },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (interface_dpo_ip4_node,
-                              interface_dpo_ip4)
-
-VLIB_REGISTER_NODE (interface_dpo_ip6_node) = {
-    .function = interface_dpo_ip6,
-    .name = "interface-dpo-ip6",
-    .vector_size = sizeof (u32),
-    .format_trace = format_interface_dpo_trace,
-
-    .n_next_nodes = 2,
-    .next_nodes = {
-        [INTERFACE_DPO_DROP] = "ip6-drop",
-        [INTERFACE_DPO_INPUT] = "ip6-input",
-    },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (interface_dpo_ip6_node,
-                              interface_dpo_ip6)
-
-VLIB_REGISTER_NODE (interface_dpo_l2_node) = {
-    .function = interface_dpo_l2,
-    .name = "interface-dpo-l2",
-    .vector_size = sizeof (u32),
-    .format_trace = format_interface_dpo_trace,
-
-    .n_next_nodes = 2,
-    .next_nodes = {
-        [INTERFACE_DPO_DROP] = "error-drop",
-        [INTERFACE_DPO_INPUT] = "l2-input",
-    },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (interface_dpo_l2_node,
-                              interface_dpo_l2)
-
diff --git a/src/vnet/dpo/interface_rx_dpo.c b/src/vnet/dpo/interface_rx_dpo.c
new file mode 100644 (file)
index 0000000..a624f51
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/dpo/interface_rx_dpo.h>
+#include <vnet/fib/fib_node.h>
+
+/*
+ * The 'DB' of interface DPOs.
+ * There is only one  per-interface per-protocol, so this is a per-interface
+ * vector
+ */
+static index_t *interface_rx_dpo_db[DPO_PROTO_NUM];
+
+static interface_rx_dpo_t *
+interface_rx_dpo_alloc (void)
+{
+    interface_rx_dpo_t *ido;
+
+    pool_get(interface_rx_dpo_pool, ido);
+
+    return (ido);
+}
+
+static inline interface_rx_dpo_t *
+interface_rx_dpo_get_from_dpo (const dpo_id_t *dpo)
+{
+    ASSERT(DPO_INTERFACE_RX == dpo->dpoi_type);
+
+    return (interface_rx_dpo_get(dpo->dpoi_index));
+}
+
+static inline index_t
+interface_rx_dpo_get_index (interface_rx_dpo_t *ido)
+{
+    return (ido - interface_rx_dpo_pool);
+}
+
+static void
+interface_rx_dpo_lock (dpo_id_t *dpo)
+{
+    interface_rx_dpo_t *ido;
+
+    ido = interface_rx_dpo_get_from_dpo(dpo);
+    ido->ido_locks++;
+}
+
+static void
+interface_rx_dpo_unlock (dpo_id_t *dpo)
+{
+    interface_rx_dpo_t *ido;
+
+    ido = interface_rx_dpo_get_from_dpo(dpo);
+    ido->ido_locks--;
+
+    if (0 == ido->ido_locks)
+    {
+        interface_rx_dpo_db[ido->ido_proto][ido->ido_sw_if_index] =
+            INDEX_INVALID;
+        pool_put(interface_rx_dpo_pool, ido);
+    }
+}
+
+/*
+ * interface_rx_dpo_add_or_lock
+ *
+ * Add/create and lock a new or lock an existing for the interface DPO
+ * on the interface and protocol given
+ */
+void
+interface_rx_dpo_add_or_lock (dpo_proto_t proto,
+                              u32 sw_if_index,
+                              dpo_id_t *dpo)
+{
+    interface_rx_dpo_t *ido;
+
+    vec_validate_init_empty(interface_rx_dpo_db[proto],
+                            sw_if_index,
+                            INDEX_INVALID);
+
+    if (INDEX_INVALID == interface_rx_dpo_db[proto][sw_if_index])
+    {
+        ido = interface_rx_dpo_alloc();
+
+        ido->ido_sw_if_index = sw_if_index;
+        ido->ido_proto = proto;
+
+        interface_rx_dpo_db[proto][sw_if_index] =
+            interface_rx_dpo_get_index(ido);
+    }
+    else
+    {
+        ido = interface_rx_dpo_get(interface_rx_dpo_db[proto][sw_if_index]);
+    }
+
+    dpo_set(dpo, DPO_INTERFACE_RX, proto, interface_rx_dpo_get_index(ido));
+}
+
+
+static clib_error_t *
+interface_rx_dpo_interface_state_change (vnet_main_t * vnm,
+                                         u32 sw_if_index,
+                                         u32 flags)
+{
+    /*
+     */
+    return (NULL);
+}
+
+VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(
+    interface_rx_dpo_interface_state_change);
+
+/**
+ * @brief Registered callback for HW interface state changes
+ */
+static clib_error_t *
+interface_rx_dpo_hw_interface_state_change (vnet_main_t * vnm,
+                                            u32 hw_if_index,
+                                            u32 flags)
+{
+    return (NULL);
+}
+
+VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(
+    interface_rx_dpo_hw_interface_state_change);
+
+static clib_error_t *
+interface_rx_dpo_interface_delete (vnet_main_t * vnm,
+                                   u32 sw_if_index,
+                                   u32 is_add)
+{
+    return (NULL);
+}
+
+VNET_SW_INTERFACE_ADD_DEL_FUNCTION(
+    interface_rx_dpo_interface_delete);
+
+u8*
+format_interface_rx_dpo (u8* s, va_list *ap)
+{
+    index_t index = va_arg(*ap, index_t);
+    CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
+    vnet_main_t * vnm = vnet_get_main();
+    interface_rx_dpo_t *ido = interface_rx_dpo_get(index);
+
+    return (format(s, "%U-dpo: %U",
+                   format_vnet_sw_interface_name,
+                   vnm,
+                   vnet_get_sw_interface(vnm, ido->ido_sw_if_index),
+                   format_dpo_proto, ido->ido_proto));
+}
+
+static void
+interface_rx_dpo_mem_show (void)
+{
+    fib_show_memory_usage("Interface",
+                          pool_elts(interface_rx_dpo_pool),
+                          pool_len(interface_rx_dpo_pool),
+                          sizeof(interface_rx_dpo_t));
+}
+
+
+const static dpo_vft_t interface_rx_dpo_vft = {
+    .dv_lock = interface_rx_dpo_lock,
+    .dv_unlock = interface_rx_dpo_unlock,
+    .dv_format = format_interface_rx_dpo,
+    .dv_mem_show = interface_rx_dpo_mem_show,
+};
+
+/**
+ * @brief The per-protocol VLIB graph nodes that are assigned to a glean
+ *        object.
+ *
+ * this means that these graph nodes are ones from which a glean is the
+ * parent object in the DPO-graph.
+ */
+const static char* const interface_rx_dpo_ip4_nodes[] =
+{
+    "interface-rx-dpo-ip4",
+    NULL,
+};
+const static char* const interface_rx_dpo_ip6_nodes[] =
+{
+    "interface-rx-dpo-ip6",
+    NULL,
+};
+const static char* const interface_rx_dpo_l2_nodes[] =
+{
+    "interface-rx-dpo-l2",
+    NULL,
+};
+
+const static char* const * const interface_rx_dpo_nodes[DPO_PROTO_NUM] =
+{
+    [DPO_PROTO_IP4]  = interface_rx_dpo_ip4_nodes,
+    [DPO_PROTO_IP6]  = interface_rx_dpo_ip6_nodes,
+    [DPO_PROTO_ETHERNET]  = interface_rx_dpo_l2_nodes,
+    [DPO_PROTO_MPLS] = NULL,
+};
+
+void
+interface_rx_dpo_module_init (void)
+{
+    dpo_register(DPO_INTERFACE_RX,
+                 &interface_rx_dpo_vft,
+                 interface_rx_dpo_nodes);
+}
+
+/**
+ * @brief Interface DPO trace data
+ */
+typedef struct interface_rx_dpo_trace_t_
+{
+    u32 sw_if_index;
+} interface_rx_dpo_trace_t;
+
+typedef enum interface_rx_dpo_next_t_
+{
+    INTERFACE_RX_DPO_DROP = 0,
+    INTERFACE_RX_DPO_INPUT = 1,
+} interface_rx_dpo_next_t;
+
+always_inline uword
+interface_rx_dpo_inline (vlib_main_t * vm,
+                         vlib_node_runtime_t * node,
+                         vlib_frame_t * from_frame)
+{
+    u32 n_left_from, next_index, * from, * to_next;
+    u32 thread_index = vlib_get_thread_index ();
+    vnet_interface_main_t *im;
+
+    im = &vnet_get_main ()->interface_main;
+    from = vlib_frame_vector_args (from_frame);
+    n_left_from = from_frame->n_vectors;
+
+    next_index = node->cached_next_index;
+
+    while (n_left_from > 0)
+    {
+        u32 n_left_to_next;
+
+        vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
+
+        while (n_left_from >= 4 && n_left_to_next > 2)
+        {
+            const interface_rx_dpo_t *ido0, *ido1;
+            u32 bi0, idoi0, bi1, idoi1;
+            vlib_buffer_t *b0, *b1;
+
+            bi0 = from[0];
+            to_next[0] = bi0;
+            bi1 = from[1];
+            to_next[1] = bi1;
+            from += 2;
+            to_next += 2;
+            n_left_from -= 2;
+            n_left_to_next -= 2;
+
+            b0 = vlib_get_buffer (vm, bi0);
+            b1 = vlib_get_buffer (vm, bi1);
+
+            idoi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+            idoi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
+            ido0 = interface_rx_dpo_get(idoi0);
+            ido1 = interface_rx_dpo_get(idoi1);
+
+            vnet_buffer(b0)->sw_if_index[VLIB_RX] = ido0->ido_sw_if_index;
+            vnet_buffer(b1)->sw_if_index[VLIB_RX] = ido1->ido_sw_if_index;
+
+            vlib_increment_combined_counter (im->combined_sw_if_counters
+                                             + VNET_INTERFACE_COUNTER_RX,
+                                             thread_index,
+                                             ido0->ido_sw_if_index,
+                                             1,
+                                             vlib_buffer_length_in_chain (vm, b0));
+            vlib_increment_combined_counter (im->combined_sw_if_counters
+                                             + VNET_INTERFACE_COUNTER_RX,
+                                             thread_index,
+                                             ido1->ido_sw_if_index,
+                                             1,
+                                             vlib_buffer_length_in_chain (vm, b1));
+
+            if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+            {
+                interface_rx_dpo_trace_t *tr0;
+
+                tr0 = vlib_add_trace (vm, node, b0, sizeof (*tr0));
+                tr0->sw_if_index = ido0->ido_sw_if_index;
+            }
+            if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
+            {
+                interface_rx_dpo_trace_t *tr1;
+
+                tr1 = vlib_add_trace (vm, node, b1, sizeof (*tr1));
+                tr1->sw_if_index = ido1->ido_sw_if_index;
+            }
+
+            vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
+                                            n_left_to_next, bi0, bi1,
+                                            INTERFACE_RX_DPO_INPUT,
+                                            INTERFACE_RX_DPO_INPUT);
+        }
+
+        while (n_left_from > 0 && n_left_to_next > 0)
+        {
+            const interface_rx_dpo_t * ido0;
+            vlib_buffer_t * b0;
+            u32 bi0, idoi0;
+
+            bi0 = from[0];
+            to_next[0] = bi0;
+            from += 1;
+            to_next += 1;
+            n_left_from -= 1;
+            n_left_to_next -= 1;
+
+            b0 = vlib_get_buffer (vm, bi0);
+
+            idoi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+            ido0 = interface_rx_dpo_get(idoi0);
+
+            /* Swap the RX interface of the packet to the one the
+             * interface DPR represents */
+            vnet_buffer(b0)->sw_if_index[VLIB_RX] = ido0->ido_sw_if_index;
+
+            /* Bump the interface's RX coutners */
+            vlib_increment_combined_counter (im->combined_sw_if_counters
+                                             + VNET_INTERFACE_COUNTER_RX,
+                                             thread_index,
+                                             ido0->ido_sw_if_index,
+                                             1,
+                                             vlib_buffer_length_in_chain (vm, b0));
+
+            if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+            {
+                interface_rx_dpo_trace_t *tr;
+
+                tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
+                tr->sw_if_index = ido0->ido_sw_if_index;
+            }
+
+            vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
+                                            n_left_to_next, bi0,
+                                            INTERFACE_RX_DPO_INPUT);
+        }
+        vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+    return from_frame->n_vectors;
+}
+
+static u8 *
+format_interface_rx_dpo_trace (u8 * s, va_list * args)
+{
+    CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+    CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+    interface_rx_dpo_trace_t * t = va_arg (*args, interface_rx_dpo_trace_t *);
+    uword indent = format_get_indent (s);
+    s = format (s, "%U sw_if_index:%d",
+                format_white_space, indent,
+                t->sw_if_index);
+    return s;
+}
+
+static uword
+interface_rx_dpo_ip4 (vlib_main_t * vm,
+                      vlib_node_runtime_t * node,
+                      vlib_frame_t * from_frame)
+{
+    return (interface_rx_dpo_inline(vm, node, from_frame));
+}
+
+static uword
+interface_rx_dpo_ip6 (vlib_main_t * vm,
+                      vlib_node_runtime_t * node,
+                      vlib_frame_t * from_frame)
+{
+    return (interface_rx_dpo_inline(vm, node, from_frame));
+}
+
+static uword
+interface_rx_dpo_l2 (vlib_main_t * vm,
+                     vlib_node_runtime_t * node,
+                     vlib_frame_t * from_frame)
+{
+    return (interface_rx_dpo_inline(vm, node, from_frame));
+}
+
+VLIB_REGISTER_NODE (interface_rx_dpo_ip4_node) = {
+    .function = interface_rx_dpo_ip4,
+    .name = "interface-rx-dpo-ip4",
+    .vector_size = sizeof (u32),
+    .format_trace = format_interface_rx_dpo_trace,
+
+    .n_next_nodes = 2,
+    .next_nodes = {
+        [INTERFACE_RX_DPO_DROP] = "ip4-drop",
+        [INTERFACE_RX_DPO_INPUT] = "ip4-input",
+    },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (interface_rx_dpo_ip4_node,
+                              interface_rx_dpo_ip4)
+
+VLIB_REGISTER_NODE (interface_rx_dpo_ip6_node) = {
+    .function = interface_rx_dpo_ip6,
+    .name = "interface-rx-dpo-ip6",
+    .vector_size = sizeof (u32),
+    .format_trace = format_interface_rx_dpo_trace,
+
+    .n_next_nodes = 2,
+    .next_nodes = {
+        [INTERFACE_RX_DPO_DROP] = "ip6-drop",
+        [INTERFACE_RX_DPO_INPUT] = "ip6-input",
+    },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (interface_rx_dpo_ip6_node,
+                              interface_rx_dpo_ip6)
+
+VLIB_REGISTER_NODE (interface_rx_dpo_l2_node) = {
+    .function = interface_rx_dpo_l2,
+    .name = "interface-rx-dpo-l2",
+    .vector_size = sizeof (u32),
+    .format_trace = format_interface_rx_dpo_trace,
+
+    .n_next_nodes = 2,
+    .next_nodes = {
+        [INTERFACE_RX_DPO_DROP] = "error-drop",
+        [INTERFACE_RX_DPO_INPUT] = "l2-input",
+    },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (interface_rx_dpo_l2_node,
+                              interface_rx_dpo_l2)
similarity index 62%
rename from src/vnet/dpo/interface_dpo.h
rename to src/vnet/dpo/interface_rx_dpo.h
index 1538dfb..edecce0 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/**
- * @brief
- * The data-path object representing interfaceing the packet, i.e. it's for-us
- */
 
-#ifndef __INTERFACE_DPO_H__
-#define __INTERFACE_DPO_H__
+#ifndef __INTERFACE_RX_DPO_H__
+#define __INTERFACE_RX_DPO_H__
 
 #include <vnet/dpo/dpo.h>
 
-typedef struct interface_dpo_t_
+/**
+ * @brief
+ * The data-path object representing a change of receive interface.
+ * If a packet encounters an object of this type in the data-path, it's
+ * RX interface is changed.
+ */
+typedef struct interface_rx_dpo_t_
 {
     /**
      * The Software interface index that the packets will be given
@@ -45,23 +47,23 @@ typedef struct interface_dpo_t_
      * number of locks.
      */
     u16 ido_locks;
-} interface_dpo_t;
+} interface_rx_dpo_t;
 
-extern void interface_dpo_add_or_lock (dpo_proto_t proto,
-                                       u32 sw_if_index,
-                                       dpo_id_t *dpo);
+extern void interface_rx_dpo_add_or_lock (dpo_proto_t proto,
+                                          u32 sw_if_index,
+                                          dpo_id_t *dpo);
 
-extern void interface_dpo_module_init(void);
+extern void interface_rx_dpo_module_init(void);
 
 /**
  * @brief pool of all interface DPOs
  */
-interface_dpo_t *interface_dpo_pool;
+interface_rx_dpo_t *interface_rx_dpo_pool;
 
-static inline interface_dpo_t *
-interface_dpo_get (index_t index)
+static inline interface_rx_dpo_t *
+interface_rx_dpo_get (index_t index)
 {
-    return (pool_elt_at_index(interface_dpo_pool, index));
+    return (pool_elt_at_index(interface_rx_dpo_pool, index));
 }
 
 #endif
diff --git a/src/vnet/dpo/interface_tx_dpo.c b/src/vnet/dpo/interface_tx_dpo.c
new file mode 100644 (file)
index 0000000..f7c8bfd
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/dpo/interface_tx_dpo.h>
+#include <vnet/adj/rewrite.h>
+
+/*
+ * We do not lock nor unlock these DPOs since there is nothing to lock
+ * all we do is construct DPO object wrappers around a sw_if_index
+ */
+static void
+interface_tx_dpo_lock (dpo_id_t *dpo)
+{
+}
+
+static void
+interface_tx_dpo_unlock (dpo_id_t *dpo)
+{
+}
+
+/*
+ * interface_tx_dpo_add_or_lock
+ *
+ * construct DPO object wrappers around a sw_if_index
+ */
+void
+interface_tx_dpo_add_or_lock (dpo_proto_t proto,
+                              u32 sw_if_index,
+                              dpo_id_t *dpo)
+{
+    dpo_set(dpo, DPO_INTERFACE_TX, proto, sw_if_index);
+}
+
+u8*
+format_interface_tx_dpo (u8* s, va_list *ap)
+{
+    index_t index = va_arg(*ap, index_t);
+    CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
+    vnet_main_t * vnm = vnet_get_main();
+
+    return (format(s, "%U-dpo:",
+                   format_vnet_sw_interface_name,
+                   vnm,
+                   vnet_get_sw_interface(vnm, index)));
+}
+
+static void
+interface_tx_dpo_mem_show (void)
+{
+}
+
+u32*
+interface_tx_dpo_get_next_node (const dpo_id_t *dpo)
+{
+    u32 *node_indices = NULL;
+
+    /*
+     * return the interface's TX node for the wrapped sw_if_index
+     */
+    vec_add1(node_indices,
+             vnet_tx_node_index_for_sw_interface(vnet_get_main(),
+                                                 dpo->dpoi_index));
+
+    return (node_indices);
+}
+
+const static dpo_vft_t interface_tx_dpo_vft = {
+    .dv_lock = interface_tx_dpo_lock,
+    .dv_unlock = interface_tx_dpo_unlock,
+    .dv_format = format_interface_tx_dpo,
+    .dv_mem_show = interface_tx_dpo_mem_show,
+    .dv_get_next_node = interface_tx_dpo_get_next_node,
+};
+
+void
+interface_tx_dpo_module_init (void)
+{
+    dpo_register(DPO_INTERFACE_TX, &interface_tx_dpo_vft, NULL);
+}
+
diff --git a/src/vnet/dpo/interface_tx_dpo.h b/src/vnet/dpo/interface_tx_dpo.h
new file mode 100644 (file)
index 0000000..0c560ad
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @brief
+ * The data-path object representing transmitting the packet on a n interface.
+ * This is a convenient DPO wrapper around a simple interface transmit and thus
+ * allows us to represent direct interface transmit in the DPO model.
+ */
+
+#ifndef __INTERFACE_TX_DPO_H__
+#define __INTERFACE_TX_DPO_H__
+
+#include <vnet/dpo/dpo.h>
+
+extern void interface_tx_dpo_add_or_lock (dpo_proto_t proto,
+                                          u32 sw_if_index,
+                                          dpo_id_t *dpo);
+
+extern void interface_tx_dpo_module_init(void);
+
+#endif
index 58050cc..cf5a463 100644 (file)
@@ -21,7 +21,7 @@
 #include <vnet/dpo/receive_dpo.h>
 #include <vnet/dpo/load_balance_map.h>
 #include <vnet/dpo/lookup_dpo.h>
-#include <vnet/dpo/interface_dpo.h>
+#include <vnet/dpo/interface_rx_dpo.h>
 #include <vnet/dpo/mpls_disposition.h>
 
 #include <vnet/adj/adj.h>
@@ -1707,9 +1707,9 @@ fib_path_resolve (fib_node_index_t path_index)
        /*
         * Resolve via a receive DPO.
         */
-       interface_dpo_add_or_lock(path->fp_nh_proto,
-                                  path->intf_rx.fp_interface,
-                                  &path->fp_dpo);
+       interface_rx_dpo_add_or_lock(path->fp_nh_proto,
+                                     path->intf_rx.fp_interface,
+                                     &path->fp_dpo);
        break;
     }
     case FIB_PATH_TYPE_EXCLUSIVE:
@@ -2041,9 +2041,9 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
             /*
              * Create the adj needed for sending IP multicast traffic
              */
-            interface_dpo_add_or_lock(fib_forw_chain_type_to_dpo_proto(fct),
-                                      path->attached.fp_interface,
-                                      dpo);
+            interface_rx_dpo_add_or_lock(fib_forw_chain_type_to_dpo_proto(fct),
+                                         path->attached.fp_interface,
+                                         dpo);
             break;
         case FIB_PATH_TYPE_RECEIVE:
         case FIB_PATH_TYPE_SPECIAL:
index 7ca4cb3..6867cca 100644 (file)
@@ -25,7 +25,7 @@
 #include <vnet/dpo/receive_dpo.h>
 #include <vnet/dpo/ip_null_dpo.h>
 #include <vnet/bfd/bfd_main.h>
-#include <vnet/dpo/interface_dpo.h>
+#include <vnet/dpo/interface_rx_dpo.h>
 #include <vnet/dpo/replicate_dpo.h>
 
 #include <vnet/mpls/mpls.h>
@@ -407,7 +407,7 @@ fib_test_validate_rep_v (const replicate_t *rep,
            }
            break;
        case FT_REP_INTF:
-            FIB_TEST_LB((DPO_INTERFACE == dpo->dpoi_type),
+            FIB_TEST_LB((DPO_INTERFACE_RX == dpo->dpoi_type),
                         "bucket %d stacks on %U",
                         bucket,
                         format_dpo_type, dpo->dpoi_type);
@@ -589,7 +589,7 @@ fib_test_validate_lb_v (const load_balance_t *lb,
                        exp->adj.adj);
            break;
        case FT_LB_INTF:
-           FIB_TEST_I((DPO_INTERFACE == dpo->dpoi_type),
+           FIB_TEST_I((DPO_INTERFACE_RX == dpo->dpoi_type),
                       "bucket %d stacks on %U",
                       bucket,
                       format_dpo_type, dpo->dpoi_type);
@@ -8523,7 +8523,7 @@ lfib_test (void)
      */
     dpo_id_t idpo = DPO_INVALID;
 
-    interface_dpo_add_or_lock(DPO_PROTO_IP4,
+    interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
                               tm->hw[0]->sw_if_index,
                               &idpo);
 
@@ -8667,9 +8667,9 @@ lfib_test (void)
     FIB_TEST(lb_count == pool_elts(load_balance_pool),
             "Load-balance resources freed %d of %d",
              lb_count, pool_elts(load_balance_pool));
-    FIB_TEST(0 == pool_elts(interface_dpo_pool),
-            "interface_dpo resources freed %d of %d",
-             0, pool_elts(interface_dpo_pool));
+    FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
+            "interface_rx_dpo resources freed %d of %d",
+             0, pool_elts(interface_rx_dpo_pool));
 
     return (0);
 }
index 0baf454..1d0aeff 100644 (file)
@@ -281,7 +281,7 @@ class TestPPPoE(VppTestCase):
         #
         self.vapi.cli("clear trace")
         tx2 = self.create_stream_ip4(self.pg1, self.pg0,
-                                     self.pg0.remote_ip4, self.dst_ip)
+                                     self.pg0.remote_ip4, self.dst_ip, 65)
         self.pg1.add_stream(tx2)
 
         self.pg_enable_capture(self.pg_interfaces)
@@ -293,6 +293,7 @@ class TestPPPoE(VppTestCase):
         self.logger.info(self.vapi.cli("show pppoe fib"))
         self.logger.info(self.vapi.cli("show pppoe session"))
         self.logger.info(self.vapi.cli("show ip fib"))
+        self.logger.info(self.vapi.cli("show adj"))
 
         #
         # test case cleanup