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>
diff --git a/src/vnet/dpo/dpo.c b/src/vnet/dpo/dpo.c
index aa77083..bd18b66 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->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 @@
{
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 @@
*/
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 @@
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 @@
{
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_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 @@
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 42fc51d..3356296 100644
--- a/src/vnet/dpo/dpo.h
+++ b/src/vnet/dpo/dpo.h
@@ -112,7 +112,8 @@
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 @@
[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_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 @@
* 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 780bfa2..0000000
--- 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 0000000..a624f51
--- /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
similarity index 62%
rename from src/vnet/dpo/interface_dpo.h
rename to src/vnet/dpo/interface_rx_dpo.h
index 1538dfb..edecce0 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 @@
* 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 0000000..f7c8bfd
--- /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 0000000..0c560ad
--- /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