summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2017-08-12 02:12:00 -0700
committerNeale Ranns <nranns@cisco.com>2017-08-21 04:07:00 -0700
commit43161a873375ddf156cf6fbe8764bfc206b38fa0 (patch)
tree939e5455aaff68341d387b559f743dc049b03377
parent352829f538783afe8609f09850f45536a4779b70 (diff)
PPPoE usses a midchain adjacency stack on an interface-tx DPO
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>
-rw-r--r--src/plugins/pppoe.am23
-rw-r--r--src/plugins/pppoe/pppoe.c144
-rw-r--r--src/plugins/pppoe/pppoe.h6
-rw-r--r--src/plugins/pppoe/pppoe_encap.c384
-rw-r--r--src/vnet.am3
-rw-r--r--src/vnet/adj/adj_midchain.c126
-rw-r--r--src/vnet/dpo/dpo.c107
-rw-r--r--src/vnet/dpo/dpo.h19
-rw-r--r--src/vnet/dpo/interface_dpo.c446
-rw-r--r--src/vnet/dpo/interface_rx_dpo.c445
-rw-r--r--src/vnet/dpo/interface_rx_dpo.h (renamed from src/vnet/dpo/interface_dpo.h)34
-rw-r--r--src/vnet/dpo/interface_tx_dpo.c92
-rw-r--r--src/vnet/dpo/interface_tx_dpo.h33
-rw-r--r--src/vnet/fib/fib_path.c14
-rw-r--r--src/vnet/fib/fib_test.c14
-rw-r--r--test/test_pppoe.py3
16 files changed, 901 insertions, 992 deletions
diff --git a/src/plugins/pppoe.am b/src/plugins/pppoe.am
index 28bd20a0425..06ed60b4978 100644
--- a/src/plugins/pppoe.am
+++ b/src/plugins/pppoe.am
@@ -14,27 +14,26 @@
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
diff --git a/src/plugins/pppoe/pppoe.c b/src/plugins/pppoe/pppoe.c
index cb587e2934b..e09ac7d993e 100644
--- a/src/plugins/pppoe/pppoe.c
+++ b/src/plugins/pppoe/pppoe.c
@@ -24,11 +24,13 @@
#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);
}
diff --git a/src/plugins/pppoe/pppoe.h b/src/plugins/pppoe/pppoe.h
index 37d628eb903..b06c068f405 100644
--- a/src/plugins/pppoe/pppoe.h
+++ b/src/plugins/pppoe/pppoe.h
@@ -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
index 69bec61dec1..00000000000
--- a/src/plugins/pppoe/pppoe_encap.c
+++ /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)
-
diff --git a/src/vnet.am b/src/vnet.am
index 9821069a062..182ec1f4047 100644
--- a/src/vnet.am
+++ b/src/vnet.am
@@ -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
diff --git a/src/vnet/adj/adj_midchain.c b/src/vnet/adj/adj_midchain.c
index a93a1c3e1b7..e9a510b004c 100644
--- a/src/vnet/adj/adj_midchain.c
+++ b/src/vnet/adj/adj_midchain.c
@@ -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);
}
diff --git a/src/vnet/dpo/dpo.c b/src/vnet/dpo/dpo.c
index aa7708385a5..bd18b66bfd5 100644
--- a/src/vnet/dpo/dpo.c
+++ b/src/vnet/dpo/dpo.c
@@ -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);
diff --git a/src/vnet/dpo/dpo.h b/src/vnet/dpo/dpo.h
index 42fc51d4b6c..33562968272 100644
--- a/src/vnet/dpo/dpo.h
+++ b/src/vnet/dpo/dpo.h
@@ -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" \
}
/**
@@ -332,6 +334,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
*/
typedef struct dpo_vft_t_
@@ -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
index 780bfa2a293..00000000000
--- a/src/vnet/dpo/interface_dpo.c
+++ /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
index 00000000000..a624f514564
--- /dev/null
+++ b/src/vnet/dpo/interface_rx_dpo.c
@@ -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)
diff --git a/src/vnet/dpo/interface_dpo.h b/src/vnet/dpo/interface_rx_dpo.h
index 1538dfbbf06..edecce08675 100644
--- a/src/vnet/dpo/interface_dpo.h
+++ b/src/vnet/dpo/interface_rx_dpo.h
@@ -12,17 +12,19 @@
* 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
index 00000000000..f7c8bfda85b
--- /dev/null
+++ b/src/vnet/dpo/interface_tx_dpo.c
@@ -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
index 00000000000..0c560adaaa4
--- /dev/null
+++ b/src/vnet/dpo/interface_tx_dpo.h
@@ -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
diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c
index 58050ccb307..cf5a463d53c 100644
--- a/src/vnet/fib/fib_path.c
+++ b/src/vnet/fib/fib_path.c
@@ -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:
diff --git a/src/vnet/fib/fib_test.c b/src/vnet/fib/fib_test.c
index 7ca4cb3a1d7..6867cca8959 100644
--- a/src/vnet/fib/fib_test.c
+++ b/src/vnet/fib/fib_test.c
@@ -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);
}
diff --git a/test/test_pppoe.py b/test/test_pppoe.py
index 0baf45467e5..1d0aeffda37 100644
--- a/test/test_pppoe.py
+++ b/test/test_pppoe.py
@@ -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