From ce1b4c7f05ce28d7b73eb7ed0a8ea4bd483f09e9 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Thu, 26 Jan 2017 14:25:34 -0800 Subject: Basic support for LISP-GPE encapsulated NSH packets Change-Id: I97fedb0f70dd18ed9bbe985407cc5fe714e8a2e2 Signed-off-by: Florin Coras --- src/vnet/adj/adj_internal.h | 4 +- src/vnet/adj/adj_midchain.c | 20 +++++ src/vnet/adj/adj_nsh.c | 211 ++++++++++++++++++++++++++++++++++++++++++++ src/vnet/adj/adj_nsh.h | 31 +++++++ 4 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 src/vnet/adj/adj_nsh.c create mode 100644 src/vnet/adj/adj_nsh.h (limited to 'src/vnet/adj') diff --git a/src/vnet/adj/adj_internal.h b/src/vnet/adj/adj_internal.h index ece59121e9c..306686255b8 100644 --- a/src/vnet/adj/adj_internal.h +++ b/src/vnet/adj/adj_internal.h @@ -20,7 +20,7 @@ #include #include #include - +#include /** * big switch to turn on Adjacency debugging @@ -53,6 +53,8 @@ adj_get_rewrite_node (vnet_link_t linkt) return (mpls_output_node.index); case VNET_LINK_ETHERNET: return (adj_l2_rewrite_node.index); + case VNET_LINK_NSH: + return (adj_nsh_rewrite_node.index); case VNET_LINK_ARP: break; } diff --git a/src/vnet/adj/adj_midchain.c b/src/vnet/adj/adj_midchain.c index 8c6ab5aa17b..35cdb003708 100644 --- a/src/vnet/adj/adj_midchain.c +++ b/src/vnet/adj/adj_midchain.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -308,6 +309,18 @@ VNET_FEATURE_INIT (adj_midchain_tx_no_count_ethernet, static) = { .runs_before = VNET_FEATURES ("error-drop"), .feature_index_ptr = &adj_midchain_tx_no_count_feature_node[VNET_LINK_ETHERNET], }; +VNET_FEATURE_INIT (adj_midchain_tx_nsh, static) = { + .arc_name = "nsh-output", + .node_name = "adj-midchain-tx", + .runs_before = VNET_FEATURES ("error-drop"), + .feature_index_ptr = &adj_midchain_tx_feature_node[VNET_LINK_NSH], +}; +VNET_FEATURE_INIT (adj_midchain_tx_no_count_nsh, static) = { + .arc_name = "nsh-output", + .node_name = "adj-midchain-tx-no-count", + .runs_before = VNET_FEATURES ("error-drop"), + .feature_index_ptr = &adj_midchain_tx_no_count_feature_node[VNET_LINK_NSH], +}; static inline u32 adj_get_midchain_node (vnet_link_t link) @@ -321,6 +334,8 @@ adj_get_midchain_node (vnet_link_t link) return (mpls_midchain_node.index); case VNET_LINK_ETHERNET: return (adj_l2_midchain_node.index); + case VNET_LINK_NSH: + return (adj_nsh_midchain_node.index); case VNET_LINK_ARP: break; } @@ -354,6 +369,11 @@ adj_midchain_get_feature_arc_index_for_link_type (const ip_adjacency_t *adj) arc = ethernet_main.output_feature_arc_index; break; } + case VNET_LINK_NSH: + { + arc = nsh_main_dummy.output_feature_arc_index; + break; + } case VNET_LINK_ARP: ASSERT(0); break; diff --git a/src/vnet/adj/adj_nsh.c b/src/vnet/adj/adj_nsh.c new file mode 100644 index 00000000000..9a0f9d8b9d6 --- /dev/null +++ b/src/vnet/adj/adj_nsh.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2017 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 +#include +#include + +nsh_main_dummy_t nsh_main_dummy; + +/** + * @brief Trace data for a NSH Midchain + */ +typedef struct adj_nsh_trace_t_ { + /** Adjacency index taken. */ + u32 adj_index; +} adj_nsh_trace_t; + +static u8 * +format_adj_nsh_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_nsh_trace_t * t = va_arg (*args, adj_nsh_trace_t *); + + s = format (s, "adj-idx %d : %U", + t->adj_index, + format_ip_adjacency, t->adj_index, FORMAT_IP_ADJACENCY_NONE); + return s; +} + +typedef enum adj_nsh_rewrite_next_t_ +{ + ADJ_NSH_REWRITE_NEXT_DROP, +} adj_gpe_rewrite_next_t; + +always_inline uword +adj_nsh_rewrite_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame, + int is_midchain) +{ + u32 * from = vlib_frame_vector_args (frame); + u32 n_left_from, n_left_to_next, * to_next, next_index; + u32 cpu_index = os_get_cpu_number(); + + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + ip_adjacency_t * adj0; + vlib_buffer_t * p0; + char *h0; + u32 pi0, rw_len0, adj_index0, next0 = 0; + u32 tx_sw_if_index0; + + pi0 = to_next[0] = from[0]; + from += 1; + n_left_from -= 1; + to_next += 1; + n_left_to_next -= 1; + + p0 = vlib_get_buffer (vm, pi0); + h0 = vlib_buffer_get_current (p0); + + adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; + + /* We should never rewrite a pkt using the MISS adjacency */ + ASSERT(adj_index0); + + adj0 = adj_get (adj_index0); + + /* Guess we are only writing on simple IP4 header. */ + vnet_rewrite_one_header(adj0[0], h0, sizeof(ip4_header_t)); + + /* Update packet buffer attributes/set output interface. */ + rw_len0 = adj0[0].rewrite_header.data_bytes; + vnet_buffer(p0)->ip.save_rewrite_length = rw_len0; + + vlib_increment_combined_counter(&adjacency_counters, + cpu_index, + adj_index0, + /* packet increment */ 0, + /* byte increment */ rw_len0); + + /* Check MTU of outgoing interface. */ + if (PREDICT_TRUE((vlib_buffer_length_in_chain (vm, p0) <= + adj0[0].rewrite_header.max_l3_packet_bytes))) + { + /* Don't adjust the buffer for ttl issue; icmp-error node wants + * to see the IP headerr */ + p0->current_data -= rw_len0; + p0->current_length += rw_len0; + tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index; + + if (is_midchain) + { + adj0->sub_type.midchain.fixup_func(vm, adj0, p0); + } + + vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0; + + /* + * Follow the feature ARC. this will result eventually in + * the midchain-tx node + */ + vnet_feature_arc_start (nsh_main_dummy.output_feature_arc_index, + tx_sw_if_index0, &next0, p0); + } + else + { + /* can't fragment NSH */ + next0 = ADJ_NSH_REWRITE_NEXT_DROP; + } + + if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) + { + adj_nsh_trace_t *tr = vlib_add_trace (vm, node, + p0, sizeof (*tr)); + tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX]; + } + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + pi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +static uword +adj_nsh_rewrite (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return adj_nsh_rewrite_inline (vm, node, frame, 0); +} + +static uword +adj_nsh_midchain (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return adj_nsh_rewrite_inline (vm, node, frame, 1); +} + +VLIB_REGISTER_NODE (adj_nsh_rewrite_node) = { + .function = adj_nsh_rewrite, + .name = "adj-nsh-rewrite", + .vector_size = sizeof (u32), + + .format_trace = format_adj_nsh_trace, + + .n_next_nodes = 1, + .next_nodes = { + [ADJ_NSH_REWRITE_NEXT_DROP] = "error-drop", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (adj_nsh_rewrite_node, adj_nsh_rewrite) + +VLIB_REGISTER_NODE (adj_nsh_midchain_node) = { + .function = adj_nsh_midchain, + .name = "adj-nsh-midchain", + .vector_size = sizeof (u32), + + .format_trace = format_adj_nsh_trace, + + .n_next_nodes = 1, + .next_nodes = { + [ADJ_NSH_REWRITE_NEXT_DROP] = "error-drop", + }, +}; + +VLIB_NODE_FUNCTION_MULTIARCH (adj_nsh_midchain_node, adj_nsh_midchain) + +/* Built-in ip4 tx feature path definition */ +/* *INDENT-OFF* */ +VNET_FEATURE_ARC_INIT (nsh_output, static) = +{ + .arc_name = "nsh-output", + .start_nodes = VNET_FEATURES ("adj-nsh-midchain"), + .arc_index_ptr = &nsh_main_dummy.output_feature_arc_index, +}; + +VNET_FEATURE_INIT (nsh_tx_drop, static) = +{ + .arc_name = "nsh-output", + .node_name = "error-drop", + .runs_before = 0, /* not before any other features */ +}; +/* *INDENT-ON* */ diff --git a/src/vnet/adj/adj_nsh.h b/src/vnet/adj/adj_nsh.h new file mode 100644 index 00000000000..5501fbb9bdc --- /dev/null +++ b/src/vnet/adj/adj_nsh.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 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. + */ + +#ifndef __ADJ_NSH_H__ +#define __ADJ_NSH_H__ + +#include + +extern vlib_node_registration_t adj_nsh_midchain_node; +extern vlib_node_registration_t adj_nsh_rewrite_node; + +typedef struct _nsh_main_dummy +{ + u8 output_feature_arc_index; +} nsh_main_dummy_t; + +extern nsh_main_dummy_t nsh_main_dummy; + +#endif -- cgit 1.2.3-korg