summaryrefslogtreecommitdiffstats
path: root/vnet/vnet/adj/adj_midchain.c
diff options
context:
space:
mode:
Diffstat (limited to 'vnet/vnet/adj/adj_midchain.c')
-rw-r--r--vnet/vnet/adj/adj_midchain.c394
1 files changed, 352 insertions, 42 deletions
diff --git a/vnet/vnet/adj/adj_midchain.c b/vnet/vnet/adj/adj_midchain.c
index 4b9b6a414d2..562a90d6e1d 100644
--- a/vnet/vnet/adj/adj_midchain.c
+++ b/vnet/vnet/adj/adj_midchain.c
@@ -15,10 +15,210 @@
#include <vnet/adj/adj_nbr.h>
#include <vnet/adj/adj_internal.h>
+#include <vnet/adj/adj_l2.h>
+#include <vnet/adj/adj_midchain.h>
#include <vnet/ethernet/arp_packet.h>
#include <vnet/dpo/drop_dpo.h>
#include <vnet/fib/fib_walk.h>
+/**
+ * The two midchain tx feature node indices
+ */
+static u32 adj_midchain_tx_feature_node[FIB_LINK_NUM];
+static u32 adj_midchain_tx_no_count_feature_node[FIB_LINK_NUM];
+
+/**
+ * @brief Trace data for packets traversing the midchain tx node
+ */
+typedef struct adj_midchain_tx_trace_t_
+{
+ /**
+ * @brief the midchain adj we are traversing
+ */
+ adj_index_t ai;
+} adj_midchain_tx_trace_t;
+
+always_inline uword
+adj_mdichain_tx_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame,
+ int interface_count)
+{
+ u32 * from, * to_next, n_left_from, n_left_to_next;
+ u32 next_index;
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_interface_main_t *im = &vnm->interface_main;
+ u32 cpu_index = vm->cpu_index;
+
+ /* Vector of buffer / pkt indices we're supposed to process */
+ from = vlib_frame_vector_args (frame);
+
+ /* Number of buffers / pkts */
+ n_left_from = frame->n_vectors;
+
+ /* Speculatively send the first buffer to the last disposition we used */
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ /* 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);
+
+ /*
+ * FIXME DUAL LOOP
+ */
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0, adj_index0, next0;
+ const ip_adjacency_t * adj0;
+ const dpo_id_t *dpo0;
+ vlib_buffer_t * b0;
+
+ 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);
+
+ /* Follow the DPO on which the midchain is stacked */
+ adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+ 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;
+
+ if (interface_count)
+ {
+ vlib_increment_combined_counter (im->combined_sw_if_counters
+ + VNET_INTERFACE_COUNTER_TX,
+ cpu_index,
+ adj0->rewrite_header.sw_if_index,
+ 1,
+ vlib_buffer_length_in_chain (vm, b0));
+ }
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node,
+ b0, sizeof (*tr));
+ tr->ai = adj_index0;
+ }
+
+ 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);
+ }
+
+ vlib_node_increment_counter (vm, gre_input_node.index,
+ GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
+
+ return frame->n_vectors;
+}
+
+static u8 *
+format_adj_midchain_tx_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 *);
+ adj_midchain_tx_trace_t *tr = va_arg (*args, adj_midchain_tx_trace_t*);
+
+ s = format(s, "adj-midchain:[%d]:%U", tr->ai,
+ format_ip_adjacency, vnet_get_main(), tr->ai,
+ FORMAT_IP_ADJACENCY_NONE);
+
+ return (s);
+}
+
+static uword
+adj_midchain_tx (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return (adj_mdichain_tx_inline(vm, node, frame, 1));
+}
+
+VLIB_REGISTER_NODE (adj_midchain_tx_node, static) = {
+ .function = adj_midchain_tx,
+ .name = "adj-midchain-tx",
+ .vector_size = sizeof (u32),
+
+ .format_trace = format_adj_midchain_tx_trace,
+
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "error-drop",
+ },
+};
+
+static uword
+adj_midchain_tx_no_count (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return (adj_mdichain_tx_inline(vm, node, frame, 0));
+}
+
+VLIB_REGISTER_NODE (adj_midchain_tx_no_count_node, static) = {
+ .function = adj_midchain_tx_no_count,
+ .name = "adj-midchain-tx-no-count",
+ .vector_size = sizeof (u32),
+
+ .format_trace = format_adj_midchain_tx_trace,
+
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "error-drop",
+ },
+};
+
+VNET_IP4_TX_FEATURE_INIT (adj_midchain_tx_ip4, static) = {
+ .node_name = "adj-midchain-tx",
+ .runs_before = ORDER_CONSTRAINTS {"interface-output"},
+ .feature_index = &adj_midchain_tx_feature_node[FIB_LINK_IP4],
+};
+VNET_IP4_TX_FEATURE_INIT (adj_midchain_tx_no_count_ip4, static) = {
+ .node_name = "adj-midchain-tx-no-count",
+ .runs_before = ORDER_CONSTRAINTS {"interface-output"},
+ .feature_index = &adj_midchain_tx_no_count_feature_node[FIB_LINK_IP4],
+};
+VNET_IP6_TX_FEATURE_INIT (adj_midchain_tx_ip6, static) = {
+ .node_name = "adj-midchain-tx",
+ .runs_before = ORDER_CONSTRAINTS {"interface-output"},
+ .feature_index = &adj_midchain_tx_feature_node[FIB_LINK_IP6],
+};
+VNET_IP6_TX_FEATURE_INIT (adj_midchain_tx_no_count_ip6, static) = {
+ .node_name = "adj-midchain-tx-no-count",
+ .runs_before = ORDER_CONSTRAINTS {"interface-output"},
+ .feature_index = &adj_midchain_tx_no_count_feature_node[FIB_LINK_IP6],
+};
+VNET_MPLS_TX_FEATURE_INIT (adj_midchain_tx_mpls, static) = {
+ .node_name = "adj-midchain-txs",
+ .runs_before = ORDER_CONSTRAINTS {"interface-output"},
+ .feature_index = &adj_midchain_tx_feature_node[FIB_LINK_MPLS],
+};
+VNET_MPLS_TX_FEATURE_INIT (adj_midchain_tx_no_count_mpls, static) = {
+ .node_name = "adj-midchain-tx-no-count",
+ .runs_before = ORDER_CONSTRAINTS {"interface-output"},
+ .feature_index = &adj_midchain_tx_no_count_feature_node[FIB_LINK_MPLS],
+};
+VNET_ETHERNET_TX_FEATURE_INIT (adj_midchain_tx_ethernet, static) = {
+ .node_name = "adj-midchain-tx",
+ .runs_before = ORDER_CONSTRAINTS {"error-drop"},
+ .feature_index = &adj_midchain_tx_feature_node[FIB_LINK_ETHERNET],
+};
+VNET_ETHERNET_TX_FEATURE_INIT (adj_midchain_tx_no_count_ethernet, static) = {
+ .node_name = "adj-midchain-tx-no-count",
+ .runs_before = ORDER_CONSTRAINTS {"error-drop"},
+ .feature_index = &adj_midchain_tx_no_count_feature_node[FIB_LINK_ETHERNET],
+};
+
static inline u32
adj_get_midchain_node (fib_link_t link)
{
@@ -29,11 +229,50 @@ adj_get_midchain_node (fib_link_t link)
return (ip6_midchain_node.index);
case FIB_LINK_MPLS:
return (mpls_midchain_node.index);
+ case FIB_LINK_ETHERNET:
+ return (adj_l2_midchain_node.index);
}
ASSERT(0);
return (0);
}
+static ip_config_main_t *
+adj_midchain_get_cofing_for_link_type (const ip_adjacency_t *adj)
+{
+ ip_config_main_t *cm = NULL;
+
+ switch (adj->ia_link)
+ {
+ case FIB_LINK_IP4:
+ {
+ ip4_main_t * im = &ip4_main;
+ ip_lookup_main_t * lm = &im->lookup_main;
+ cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
+ break;
+ }
+ case FIB_LINK_IP6:
+ {
+ ip6_main_t * im = &ip6_main;
+ ip_lookup_main_t * lm = &im->lookup_main;
+ cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
+ break;
+ }
+ case FIB_LINK_MPLS:
+ {
+ mpls_main_t * mm = &mpls_main;
+ cm = &mm->feature_config_mains[VNET_IP_TX_FEAT];
+ break;
+ }
+ case FIB_LINK_ETHERNET:
+ {
+ cm = &ethernet_main.feature_config_mains[VNET_IP_TX_FEAT];
+ break;
+ }
+ }
+
+ return (cm);
+}
+
/**
* adj_nbr_midchain_update_rewrite
*
@@ -43,16 +282,57 @@ adj_get_midchain_node (fib_link_t link)
*/
void
adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
- u32 post_rewrite_node,
+ adj_midchain_fixup_t fixup,
+ adj_midchain_flag_t flags,
u8 *rewrite)
{
+ vnet_config_main_t * vcm;
+ ip_config_main_t *cm;
ip_adjacency_t *adj;
+ u32 ci;
ASSERT(ADJ_INDEX_INVALID != adj_index);
adj = adj_get(adj_index);
adj->lookup_next_index = IP_LOOKUP_NEXT_MIDCHAIN;
- adj->sub_type.midchain.tx_function_node = post_rewrite_node;
+ adj->sub_type.midchain.fixup_func = fixup;
+
+ cm = adj_midchain_get_cofing_for_link_type(adj);
+ vcm = &(cm->config_main);
+ vec_validate_init_empty(cm->config_index_by_sw_if_index,
+ adj->rewrite_header.sw_if_index, ~0);
+ ci = cm->config_index_by_sw_if_index[adj->rewrite_header.sw_if_index];
+
+ /*
+ * Choose the adj tx function based on whether the client wants
+ * to count against the interface or not and insert the appropriate
+ * TX feature.
+ */
+ if (flags & ADJ_MIDCHAIN_FLAG_NO_COUNT)
+ {
+ adj->sub_type.midchain.tx_function_node =
+ adj_midchain_tx_no_count_node.index;
+
+ ci = vnet_config_add_feature(
+ vlib_get_main(),
+ vcm, ci,
+ adj_midchain_tx_no_count_feature_node[adj->ia_link],
+ /* config data */ 0,
+ /* # bytes of config data */ 0);
+ }
+ else
+ {
+ adj->sub_type.midchain.tx_function_node =
+ adj_midchain_tx_node.index;
+ ci = vnet_config_add_feature(
+ vlib_get_main(),
+ vcm, ci,
+ adj_midchain_tx_feature_node[adj->ia_link],
+ /* config data */ 0,
+ /* # bytes of config data */ 0);
+ }
+
+ cm->config_index_by_sw_if_index[adj->rewrite_header.sw_if_index] = ci;
if (NULL != rewrite)
{
@@ -61,7 +341,7 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
* use a dummy rewrite header to get the interface to print into.
*/
ip_adjacency_t dummy;
- dpo_id_t tmp = DPO_NULL;
+ dpo_id_t tmp = DPO_NULL;
vnet_rewrite_for_tunnel(vnet_get_main(),
adj->rewrite_header.sw_if_index,
@@ -73,26 +353,26 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
/*
* this is an update of an existing rewrite.
- * packets are in flight. we'll need to briefly stack on the drop DPO
- * whilst the rewrite is written, so any packets that see the partial update
- * are binned.
- */
- if (!dpo_id_is_valid(&adj->sub_type.midchain.next_dpo))
- {
- /*
- * not stacked yet. stack on the drop
- */
- dpo_stack(DPO_ADJACENCY_MIDCHAIN,
- fib_proto_to_dpo(adj->ia_nh_proto),
- &adj->sub_type.midchain.next_dpo,
- drop_dpo_get(fib_proto_to_dpo(adj->ia_nh_proto)));
- }
-
- dpo_copy(&tmp, &adj->sub_type.midchain.next_dpo);
- dpo_stack(DPO_ADJACENCY_MIDCHAIN,
- fib_proto_to_dpo(adj->ia_nh_proto),
- &adj->sub_type.midchain.next_dpo,
- drop_dpo_get(fib_proto_to_dpo(adj->ia_nh_proto)));
+ * packets are in flight. we'll need to briefly stack on the drop DPO
+ * whilst the rewrite is written, so any packets that see the partial update
+ * are binned.
+ */
+ if (!dpo_id_is_valid(&adj->sub_type.midchain.next_dpo))
+ {
+ /*
+ * not stacked yet. stack on the drop
+ */
+ dpo_stack(DPO_ADJACENCY_MIDCHAIN,
+ fib_link_to_dpo_proto(adj->ia_link),
+ &adj->sub_type.midchain.next_dpo,
+ drop_dpo_get(fib_link_to_dpo_proto(adj->ia_link)));
+ }
+
+ dpo_copy(&tmp, &adj->sub_type.midchain.next_dpo);
+ dpo_stack(DPO_ADJACENCY_MIDCHAIN,
+ fib_link_to_dpo_proto(adj->ia_link),
+ &adj->sub_type.midchain.next_dpo,
+ drop_dpo_get(fib_link_to_dpo_proto(adj->ia_link)));
CLIB_MEMORY_BARRIER();
@@ -102,17 +382,16 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
CLIB_MEMORY_BARRIER();
- /*
- * The graph arc used/created here is from the post-rewirte node to the
- * child's registered node. This is because post adj processing the next
- * node is the interface's specific node, then the post-write-node (aka
- * the interface's tx-function) - from there we need to get to the stacked
- * child's node.
- */
- dpo_stack_from_node(adj->sub_type.midchain.tx_function_node,
- &adj->sub_type.midchain.next_dpo,
- &tmp);
- dpo_reset(&tmp);
+ /*
+ * The graph arc used/created here is from the midchain-tx node to the
+ * child's registered node. This is because post adj processing the next
+ * node are any output features, then the midchain-tx. from there we
+ * need to get to the stacked child's node.
+ */
+ dpo_stack_from_node(adj->sub_type.midchain.tx_function_node,
+ &adj->sub_type.midchain.next_dpo,
+ &tmp);
+ dpo_reset(&tmp);
}
else
{
@@ -130,6 +409,31 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
}
/**
+ * adj_nbr_midchain_unstack
+ *
+ * Unstack the adj. stack it on drop
+ */
+void
+adj_nbr_midchain_unstack (adj_index_t adj_index)
+{
+ ip_adjacency_t *adj;
+
+ ASSERT(ADJ_INDEX_INVALID != adj_index);
+
+ adj = adj_get(adj_index);
+
+ /*
+ * stack on the drop
+ */
+ dpo_stack(DPO_ADJACENCY_MIDCHAIN,
+ fib_link_to_dpo_proto(adj->ia_link),
+ &adj->sub_type.midchain.next_dpo,
+ drop_dpo_get(fib_link_to_dpo_proto(adj->ia_link)));
+
+ CLIB_MEMORY_BARRIER();
+}
+
+/**
* adj_nbr_midchain_stack
*/
void
@@ -145,8 +449,8 @@ adj_nbr_midchain_stack (adj_index_t adj_index,
ASSERT(IP_LOOKUP_NEXT_MIDCHAIN == adj->lookup_next_index);
dpo_stack_from_node(adj->sub_type.midchain.tx_function_node,
- &adj->sub_type.midchain.next_dpo,
- next);
+ &adj->sub_type.midchain.next_dpo,
+ next);
}
u8*
@@ -161,13 +465,13 @@ format_adj_midchain (u8* s, va_list *ap)
s = format (s, " via %U ",
format_ip46_address, &adj->sub_type.nbr.next_hop);
s = format (s, " %U",
- format_vnet_rewrite,
- vnm->vlib_main, &adj->rewrite_header,
- sizeof (adj->rewrite_data), indent);
+ format_vnet_rewrite,
+ vnm->vlib_main, &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);
}
@@ -211,12 +515,18 @@ const static char* const midchain_mpls_nodes[] =
"mpls-midchain",
NULL,
};
+const static char* const midchain_ethernet_nodes[] =
+{
+ "adj-l2-midchain",
+ NULL,
+};
const static char* const * const midchain_nodes[DPO_PROTO_NUM] =
{
[DPO_PROTO_IP4] = midchain_ip4_nodes,
[DPO_PROTO_IP6] = midchain_ip6_nodes,
[DPO_PROTO_MPLS] = midchain_mpls_nodes,
+ [DPO_PROTO_ETHERNET] = midchain_ethernet_nodes,
};
void