aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2017-01-26 14:25:34 -0800
committerNeale Ranns <nranns@cisco.com>2017-02-13 08:51:30 +0000
commitce1b4c7f05ce28d7b73eb7ed0a8ea4bd483f09e9 (patch)
tree5e7f6cab01b2df39d12d3865af7c809916c51d63
parentfdd81af6afe6c782ad2c1a139210378badec626b (diff)
Basic support for LISP-GPE encapsulated NSH packets
Change-Id: I97fedb0f70dd18ed9bbe985407cc5fe714e8a2e2 Signed-off-by: Florin Coras <fcoras@cisco.com>
-rw-r--r--src/vnet.am2
-rw-r--r--src/vnet/adj/adj_internal.h4
-rw-r--r--src/vnet/adj/adj_midchain.c20
-rw-r--r--src/vnet/adj/adj_nsh.c211
-rw-r--r--src/vnet/adj/adj_nsh.h31
-rw-r--r--src/vnet/dpo/dpo.c2
-rw-r--r--src/vnet/dpo/dpo.h6
-rw-r--r--src/vnet/fib/fib_entry_delegate.c4
-rw-r--r--src/vnet/fib/fib_entry_delegate.h3
-rw-r--r--src/vnet/fib/fib_entry_src.c1
-rw-r--r--src/vnet/fib/fib_path.c4
-rw-r--r--src/vnet/fib/fib_types.c6
-rw-r--r--src/vnet/fib/fib_types.h11
-rw-r--r--src/vnet/gre/gre.c3
-rw-r--r--src/vnet/interface.c1
-rw-r--r--src/vnet/interface.h4
-rw-r--r--src/vnet/lisp-cp/control.c32
-rw-r--r--src/vnet/lisp-cp/lisp_api.c2
-rw-r--r--src/vnet/lisp-cp/lisp_cp_dpo.c5
-rw-r--r--src/vnet/lisp-cp/lisp_types.c43
-rw-r--r--src/vnet/lisp-cp/lisp_types.h15
-rw-r--r--src/vnet/lisp-gpe/interface.c196
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe.c2
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe.h9
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe_adjacency.c8
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c309
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h31
-rw-r--r--src/vnet/mfib/mfib_entry.c1
28 files changed, 944 insertions, 22 deletions
diff --git a/src/vnet.am b/src/vnet.am
index 9b148f69ffa..a8cc696f383 100644
--- a/src/vnet.am
+++ b/src/vnet.am
@@ -958,12 +958,14 @@ libvnet_la_SOURCES += \
vnet/adj/adj_midchain.c \
vnet/adj/adj_mcast.c \
vnet/adj/adj_l2.c \
+ vnet/adj/adj_nsh.c \
vnet/adj/adj.c
nobase_include_HEADERS += \
vnet/adj/adj.h \
vnet/adj/adj_types.h \
vnet/adj/adj_glean.h \
+ vnet/adj/adj_nsh.h \
vnet/adj/adj_nbr.h
########################################
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 <vnet/ip/ip.h>
#include <vnet/mpls/mpls.h>
#include <vnet/adj/adj_l2.h>
-
+#include <vnet/adj/adj_nsh.h>
/**
* 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 <vnet/adj/adj_nbr.h>
#include <vnet/adj/adj_internal.h>
#include <vnet/adj/adj_l2.h>
+#include <vnet/adj/adj_nsh.h>
#include <vnet/adj/adj_midchain.h>
#include <vnet/ethernet/arp_packet.h>
#include <vnet/dpo/drop_dpo.h>
@@ -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 <vnet/vnet.h>
+#include <vnet/adj/adj_nsh.h>
+#include <vnet/ip/ip.h>
+
+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 <vnet/adj/adj.h>
+
+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
diff --git a/src/vnet/dpo/dpo.c b/src/vnet/dpo/dpo.c
index cc2fa0eb91c..d8e075a7f2f 100644
--- a/src/vnet/dpo/dpo.c
+++ b/src/vnet/dpo/dpo.c
@@ -98,6 +98,8 @@ vnet_link_to_dpo_proto (vnet_link_t linkt)
return (DPO_PROTO_MPLS);
case VNET_LINK_ETHERNET:
return (DPO_PROTO_ETHERNET);
+ case VNET_LINK_NSH:
+ return (DPO_PROTO_NSH);
case VNET_LINK_ARP:
break;
}
diff --git a/src/vnet/dpo/dpo.h b/src/vnet/dpo/dpo.h
index aff4e1b82cc..48b92d3d3d6 100644
--- a/src/vnet/dpo/dpo.h
+++ b/src/vnet/dpo/dpo.h
@@ -67,9 +67,10 @@ typedef enum dpo_proto_t_
DPO_PROTO_IP6,
DPO_PROTO_ETHERNET,
DPO_PROTO_MPLS,
+ DPO_PROTO_NSH,
} __attribute__((packed)) dpo_proto_t;
-#define DPO_PROTO_NUM ((dpo_proto_t)(DPO_PROTO_MPLS+1))
+#define DPO_PROTO_NUM ((dpo_proto_t)(DPO_PROTO_NSH+1))
#define DPO_PROTO_NONE ((dpo_proto_t)(DPO_PROTO_NUM+1))
#define DPO_PROTOS { \
@@ -77,11 +78,12 @@ typedef enum dpo_proto_t_
[DPO_PROTO_IP6] = "ip6", \
[DPO_PROTO_ETHERNET] = "ethernet", \
[DPO_PROTO_MPLS] = "mpls", \
+ [DPO_PROTO_NSH] = "nsh", \
}
#define FOR_EACH_DPO_PROTO(_proto) \
for (_proto = DPO_PROTO_IP4; \
- _proto <= DPO_PROTO_MPLS; \
+ _proto <= DPO_PROTO_NSH; \
_proto++)
/**
diff --git a/src/vnet/fib/fib_entry_delegate.c b/src/vnet/fib/fib_entry_delegate.c
index efe402d1482..70840b160a1 100644
--- a/src/vnet/fib/fib_entry_delegate.c
+++ b/src/vnet/fib/fib_entry_delegate.c
@@ -122,6 +122,8 @@ fib_entry_chain_type_to_delegate_type (fib_forward_chain_type_t fct)
case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
break;
+ case FIB_FORW_CHAIN_TYPE_NSH:
+ return (FIB_ENTRY_DELEGATE_CHAIN_NSH);
}
ASSERT(0);
return (FIB_ENTRY_DELEGATE_CHAIN_UNICAST_IP4);
@@ -142,6 +144,8 @@ fib_entry_delegate_type_to_chain_type (fib_entry_delegate_type_t fdt)
return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
case FIB_ENTRY_DELEGATE_CHAIN_ETHERNET:
return (FIB_FORW_CHAIN_TYPE_ETHERNET);
+ case FIB_ENTRY_DELEGATE_CHAIN_NSH:
+ return (FIB_FORW_CHAIN_TYPE_NSH);
case FIB_ENTRY_DELEGATE_COVERED:
case FIB_ENTRY_DELEGATE_ATTACHED_IMPORT:
case FIB_ENTRY_DELEGATE_ATTACHED_EXPORT:
diff --git a/src/vnet/fib/fib_entry_delegate.h b/src/vnet/fib/fib_entry_delegate.h
index 6d3a6549f32..d9183c5f181 100644
--- a/src/vnet/fib/fib_entry_delegate.h
+++ b/src/vnet/fib/fib_entry_delegate.h
@@ -35,6 +35,7 @@ typedef enum fib_entry_delegate_type_t_ {
FIB_ENTRY_DELEGATE_CHAIN_MPLS_EOS = FIB_FORW_CHAIN_TYPE_MPLS_EOS,
FIB_ENTRY_DELEGATE_CHAIN_MPLS_NON_EOS = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
FIB_ENTRY_DELEGATE_CHAIN_ETHERNET = FIB_FORW_CHAIN_TYPE_ETHERNET,
+ FIB_ENTRY_DELEGATE_CHAIN_NSH = FIB_FORW_CHAIN_TYPE_NSH,
/**
* Dependency list of covered entries.
* these are more specific entries that are interested in changes
@@ -51,7 +52,7 @@ typedef enum fib_entry_delegate_type_t_ {
#define FOR_EACH_DELEGATE_CHAIN(_entry, _fdt, _fed, _body) \
{ \
for (_fdt = FIB_ENTRY_DELEGATE_CHAIN_UNICAST_IP4; \
- _fdt <= FIB_ENTRY_DELEGATE_CHAIN_ETHERNET; \
+ _fdt <= FIB_ENTRY_DELEGATE_CHAIN_NSH; \
_fdt++) \
{ \
_fed = fib_entry_delegate_get(_entry, _fdt); \
diff --git a/src/vnet/fib/fib_entry_src.c b/src/vnet/fib/fib_entry_src.c
index d54787cd4d1..57109153b57 100644
--- a/src/vnet/fib/fib_entry_src.c
+++ b/src/vnet/fib/fib_entry_src.c
@@ -355,6 +355,7 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
break;
}
case FIB_FORW_CHAIN_TYPE_ETHERNET:
+ case FIB_FORW_CHAIN_TYPE_NSH:
ASSERT(0);
break;
}
diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c
index 080057f37a9..aa545b5ed45 100644
--- a/src/vnet/fib/fib_path.c
+++ b/src/vnet/fib/fib_path.c
@@ -1755,6 +1755,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
case FIB_FORW_CHAIN_TYPE_ETHERNET:
+ case FIB_FORW_CHAIN_TYPE_NSH:
{
adj_index_t ai;
@@ -1787,6 +1788,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
case FIB_FORW_CHAIN_TYPE_ETHERNET:
+ case FIB_FORW_CHAIN_TYPE_NSH:
ASSERT(0);
break;
}
@@ -1809,6 +1811,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
case FIB_FORW_CHAIN_TYPE_ETHERNET:
+ case FIB_FORW_CHAIN_TYPE_NSH:
ASSERT(0);
break;
}
@@ -1824,6 +1827,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
case FIB_FORW_CHAIN_TYPE_ETHERNET:
+ case FIB_FORW_CHAIN_TYPE_NSH:
break;
case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
diff --git a/src/vnet/fib/fib_types.c b/src/vnet/fib/fib_types.c
index 3ecb38e8b6c..2837a59db01 100644
--- a/src/vnet/fib/fib_types.c
+++ b/src/vnet/fib/fib_types.c
@@ -279,6 +279,8 @@ fib_forw_chain_type_from_dpo_proto (dpo_proto_t proto)
return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
case DPO_PROTO_ETHERNET:
return (FIB_FORW_CHAIN_TYPE_ETHERNET);
+ case DPO_PROTO_NSH:
+ return (FIB_FORW_CHAIN_TYPE_NSH);
}
ASSERT(0);
return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
@@ -297,6 +299,8 @@ fib_forw_chain_type_to_link_type (fib_forward_chain_type_t fct)
return (VNET_LINK_IP6);
case FIB_FORW_CHAIN_TYPE_ETHERNET:
return (VNET_LINK_ETHERNET);
+ case FIB_FORW_CHAIN_TYPE_NSH:
+ return (VNET_LINK_NSH);
case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
/*
* insufficient information to to convert
@@ -322,6 +326,8 @@ fib_forw_chain_type_to_dpo_proto (fib_forward_chain_type_t fct)
return (DPO_PROTO_IP6);
case FIB_FORW_CHAIN_TYPE_ETHERNET:
return (DPO_PROTO_ETHERNET);
+ case FIB_FORW_CHAIN_TYPE_NSH:
+ return (DPO_PROTO_NSH);
case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
return (DPO_PROTO_MPLS);
diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h
index c51bc9c0722..05e0e0af4c9 100644
--- a/src/vnet/fib/fib_types.h
+++ b/src/vnet/fib/fib_types.h
@@ -105,10 +105,14 @@ typedef enum fib_forward_chain_type_t_ {
FIB_FORW_CHAIN_TYPE_MCAST_IP6,
/**
* Contribute an object that is to be used to forward Ethernet packets.
+ */
+ FIB_FORW_CHAIN_TYPE_ETHERNET,
+ /**
+ * Contribute an object that is to be used to forward NSH packets.
* This is last in the list since it is not valid for many FIB objects,
* and thus their array of per-chain-type DPOs can be sized smaller.
*/
- FIB_FORW_CHAIN_TYPE_ETHERNET,
+ FIB_FORW_CHAIN_TYPE_NSH,
} __attribute__ ((packed)) fib_forward_chain_type_t;
#define FIB_FORW_CHAINS { \
@@ -119,14 +123,15 @@ typedef enum fib_forward_chain_type_t_ {
[FIB_FORW_CHAIN_TYPE_MCAST_IP6] = "multicast-ip6", \
[FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS] = "mpls-neos", \
[FIB_FORW_CHAIN_TYPE_MPLS_EOS] = "mpls-eos", \
+ [FIB_FORW_CHAIN_TYPE_NSH] = "nsh", \
}
-#define FIB_FORW_CHAIN_NUM (FIB_FORW_CHAIN_TYPE_MPLS_ETHERNET+1)
+#define FIB_FORW_CHAIN_NUM (FIB_FORW_CHAIN_TYPE_NSH+1)
#define FIB_FORW_CHAIN_MPLS_NUM (FIB_FORW_CHAIN_TYPE_MPLS_EOS+1)
#define FOR_EACH_FIB_FORW_CHAIN(_item) \
for (_item = FIB_FORW_CHAIN_TYPE_UNICAST_IP4; \
- _item <= FIB_FORW_CHAIN_TYPE_ETHERNET; \
+ _item <= FIB_FORW_CHAIN_TYPE_NSH; \
_item++)
#define FOR_EACH_FIB_FORW_MPLS_CHAIN(_item) \
diff --git a/src/vnet/gre/gre.c b/src/vnet/gre/gre.c
index 0faed13eb29..cd43a3afce9 100644
--- a/src/vnet/gre/gre.c
+++ b/src/vnet/gre/gre.c
@@ -177,6 +177,9 @@ gre_proto_from_vnet_link (vnet_link_t link)
return (GRE_PROTOCOL_teb);
case VNET_LINK_ARP:
return (GRE_PROTOCOL_arp);
+ case VNET_LINK_NSH:
+ ASSERT(0);
+ break;
}
ASSERT(0);
return (GRE_PROTOCOL_ip4);
diff --git a/src/vnet/interface.c b/src/vnet/interface.c
index 9454ac183b1..2a1e70e8927 100644
--- a/src/vnet/interface.c
+++ b/src/vnet/interface.c
@@ -1364,6 +1364,7 @@ vnet_link_to_l3_proto (vnet_link_t link)
case VNET_LINK_ARP:
return (VNET_L3_PACKET_TYPE_ARP);
case VNET_LINK_ETHERNET:
+ case VNET_LINK_NSH:
ASSERT (0);
break;
}
diff --git a/src/vnet/interface.h b/src/vnet/interface.h
index d42e5fda84c..7b791751392 100644
--- a/src/vnet/interface.h
+++ b/src/vnet/interface.h
@@ -240,6 +240,7 @@ typedef enum vnet_link_t_
VNET_LINK_MPLS,
VNET_LINK_ETHERNET,
VNET_LINK_ARP,
+ VNET_LINK_NSH,
} __attribute__ ((packed)) vnet_link_t;
#define VNET_LINKS { \
@@ -248,13 +249,14 @@ typedef enum vnet_link_t_
[VNET_LINK_IP6] = "ipv6", \
[VNET_LINK_MPLS] = "mpls", \
[VNET_LINK_ARP] = "arp", \
+ [VNET_LINK_NSH] = "nsh", \
}
/**
* @brief Number of link types. Not part of the enum so it does not have to be included in
* switch statements
*/
-#define VNET_LINK_NUM (VNET_LINK_ARP+1)
+#define VNET_LINK_NUM (VNET_LINK_NSH+1)
/**
* @brief Convert a link to to an Ethertype
diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c
index cc73dfc5f02..f0383e16f05 100644
--- a/src/vnet/lisp-cp/control.c
+++ b/src/vnet/lisp-cp/control.c
@@ -2700,6 +2700,11 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
gid_address_vni (dst) = vni;
gid_address_vni (src) = vni;
}
+ else if (LISP_AFI_LCAF == type)
+ {
+ /* Eventually extend this to support NSH and other */
+ ASSERT (0);
+ }
}
static uword
@@ -2818,6 +2823,14 @@ lisp_cp_lookup_l2 (vlib_main_t * vm,
return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_MAC));
}
+static uword
+lisp_cp_lookup_nsh (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+{
+ /* TODO decide if NSH should be propagated as LCAF or not */
+ return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_LCAF));
+}
+
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = {
.function = lisp_cp_lookup_ip4,
@@ -2875,6 +2888,25 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = {
};
/* *INDENT-ON* */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = {
+ .function = lisp_cp_lookup_nsh,
+ .name = "lisp-cp-lookup-nsh",
+ .vector_size = sizeof (u32),
+ .format_trace = format_lisp_cp_lookup_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = LISP_CP_LOOKUP_N_ERROR,
+ .error_strings = lisp_cp_lookup_error_strings,
+
+ .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
+
+ .next_nodes = {
+ [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
+ },
+};
+/* *INDENT-ON* */
+
/* lisp_cp_input statistics */
#define foreach_lisp_cp_input_error \
_(DROP, "drop") \
diff --git a/src/vnet/lisp-cp/lisp_api.c b/src/vnet/lisp-cp/lisp_api.c
index a877540b3ed..78d32e17aa6 100644
--- a/src/vnet/lisp-cp/lisp_api.c
+++ b/src/vnet/lisp-cp/lisp_api.c
@@ -714,6 +714,8 @@ fid_type_to_api_type (fid_address_t * fid)
case FID_ADDR_MAC:
return 2;
+ case FID_ADDR_NSH:
+ return 3;
}
return ~0;
diff --git a/src/vnet/lisp-cp/lisp_cp_dpo.c b/src/vnet/lisp-cp/lisp_cp_dpo.c
index 185b07a2c1b..848f621e35f 100644
--- a/src/vnet/lisp-cp/lisp_cp_dpo.c
+++ b/src/vnet/lisp-cp/lisp_cp_dpo.c
@@ -79,12 +79,17 @@ const static char *const lisp_cp_ethernet_nodes[] = {
NULL,
};
+const static char *const lisp_cp_nsh_nodes[] = {
+ "lisp-cp-lookup-nsh",
+ NULL,
+};
const static char *const *const lisp_cp_nodes[DPO_PROTO_NUM] = {
[DPO_PROTO_IP4] = lisp_cp_ip4_nodes,
[DPO_PROTO_IP6] = lisp_cp_ip6_nodes,
[DPO_PROTO_ETHERNET] = lisp_cp_ethernet_nodes,
[DPO_PROTO_MPLS] = NULL,
+ [DPO_PROTO_NSH] = lisp_cp_nsh_nodes,
};
clib_error_t *
diff --git a/src/vnet/lisp-cp/lisp_types.c b/src/vnet/lisp-cp/lisp_types.c
index 748905d2fa4..4a3d05b70ed 100644
--- a/src/vnet/lisp-cp/lisp_types.c
+++ b/src/vnet/lisp-cp/lisp_types.c
@@ -202,6 +202,20 @@ format_mac_address (u8 * s, va_list * args)
a[0], a[1], a[2], a[3], a[4], a[5]);
}
+uword
+unformat_nsh_address (unformat_input_t * input, va_list * args)
+{
+ nsh_t *a = va_arg (*args, nsh_t *);
+ return unformat (input, "SPI:%d SI:%d", &a->spi, &a->si);
+}
+
+u8 *
+format_nsh_address (u8 * s, va_list * args)
+{
+ nsh_t *a = va_arg (*args, nsh_t *);
+ return format (s, "SPI:%d SI:%d", a->spi, a->si);
+}
+
u8 *
format_fid_address (u8 * s, va_list * args)
{
@@ -211,9 +225,10 @@ format_fid_address (u8 * s, va_list * args)
{
case FID_ADDR_IP_PREF:
return format (s, "%U", format_ip_prefix, &fid_addr_ippref (a));
-
case FID_ADDR_MAC:
return format (s, "%U", format_mac_address, &fid_addr_mac (a));
+ case FID_ADDR_NSH:
+ return format (s, "%U", format_nsh_address, &fid_addr_nsh (a));
default:
clib_warning ("Can't format fid address type %d!", fid_addr_type (a));
@@ -239,6 +254,8 @@ format_gid_address (u8 * s, va_list * args)
case GID_ADDR_MAC:
return format (s, "[%d] %U", gid_address_vni (a), format_mac_address,
&gid_address_mac (a));
+ case GID_ADDR_NSH:
+ return format (s, "%U", format_nsh_address, &gid_address_nsh (a));
default:
clib_warning ("Can't format gid type %d", type);
return 0;
@@ -252,6 +269,7 @@ unformat_fid_address (unformat_input_t * i, va_list * args)
fid_address_t *a = va_arg (*args, fid_address_t *);
ip_prefix_t ippref;
u8 mac[6] = { 0 };
+ nsh_t nsh;
if (unformat (i, "%U", unformat_ip_prefix, &ippref))
{
@@ -263,6 +281,11 @@ unformat_fid_address (unformat_input_t * i, va_list * args)
fid_addr_type (a) = FID_ADDR_MAC;
mac_copy (fid_addr_mac (a), mac);
}
+ else if (unformat (i, "%U", unformat_nsh_address, &nsh))
+ {
+ fid_addr_type (a) = FID_ADDR_NSH;
+ nsh_copy (&fid_addr_nsh (a), mac);
+ }
else
return 0;
@@ -301,6 +324,7 @@ unformat_gid_address (unformat_input_t * input, va_list * args)
u8 mac[6] = { 0 };
ip_prefix_t ippref;
fid_address_t sim1, sim2;
+ nsh_t nsh;
memset (&ippref, 0, sizeof (ippref));
memset (&sim1, 0, sizeof (sim1));
@@ -323,6 +347,11 @@ unformat_gid_address (unformat_input_t * input, va_list * args)
mac_copy (gid_address_mac (a), mac);
gid_address_type (a) = GID_ADDR_MAC;
}
+ else if (unformat (input, "%U", unformat_nsh_address, &nsh))
+ {
+ nsh_copy (&gid_address_nsh (a), &nsh);
+ gid_address_type (a) = GID_ADDR_NSH;
+ }
else
return 0;
@@ -588,6 +617,10 @@ fid_addr_parse (u8 * p, fid_address_t * a)
case FID_ADDR_IP_PREF:
return ip_address_parse (p, afi, ip_addr);
+
+ case FID_ADDR_NSH:
+ ASSERT (0);
+ break;
}
return ~0;
}
@@ -918,6 +951,12 @@ mac_copy (void *dst, void *src)
}
void
+nsh_copy (void *dst, void *src)
+{
+ clib_memcpy (dst, src, sizeof (nsh_t));
+}
+
+void
sd_copy (void *dst, void *src)
{
clib_memcpy (dst, src, sizeof (source_dest_t));
@@ -1083,6 +1122,8 @@ fid_address_length (fid_address_t * a)
return ip_prefix_length (&fid_addr_ippref (a));
case FID_ADDR_MAC:
return 0;
+ case FID_ADDR_NSH:
+ return 0;
}
return 0;
}
diff --git a/src/vnet/lisp-cp/lisp_types.h b/src/vnet/lisp-cp/lisp_types.h
index ac58b894c2d..e43f5ab030e 100644
--- a/src/vnet/lisp-cp/lisp_types.h
+++ b/src/vnet/lisp-cp/lisp_types.h
@@ -89,6 +89,7 @@ typedef enum
GID_ADDR_LCAF,
GID_ADDR_MAC,
GID_ADDR_SRC_DST,
+ GID_ADDR_NSH,
GID_ADDR_NO_ADDRESS,
GID_ADDR_TYPES
} gid_address_type_t;
@@ -106,7 +107,8 @@ typedef enum
typedef enum fid_addr_type_t_
{
FID_ADDR_IP_PREF,
- FID_ADDR_MAC
+ FID_ADDR_MAC,
+ FID_ADDR_NSH
} __attribute__ ((packed)) fid_addr_type_t;
/* flat address type */
@@ -116,6 +118,7 @@ typedef struct
{
ip_prefix_t ippref;
u8 mac[6];
+ u32 nsh;
};
fid_addr_type_t type;
} fid_address_t;
@@ -124,6 +127,7 @@ typedef fid_address_t dp_address_t;
#define fid_addr_ippref(_a) (_a)->ippref
#define fid_addr_mac(_a) (_a)->mac
+#define fid_addr_nsh(_a) (_a)->nsh
#define fid_addr_type(_a) (_a)->type
u8 *format_fid_address (u8 * s, va_list * args);
@@ -155,6 +159,12 @@ typedef struct
typedef struct
{
+ u32 spi;
+ u8 si;
+} nsh_t;
+
+typedef struct
+{
/* the union needs to be at the beginning! */
union
{
@@ -177,6 +187,7 @@ typedef struct _gid_address_t
lcaf_t lcaf;
u8 mac[6];
source_dest_t sd;
+ nsh_t nsh;
};
u8 type;
u32 vni;
@@ -232,6 +243,7 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version);
#define gid_address_ip_version(_a) ip_addr_version(&gid_address_ip(_a))
#define gid_address_lcaf(_a) (_a)->lcaf
#define gid_address_mac(_a) (_a)->mac
+#define gid_address_nsh(_a) (_a)->nsh
#define gid_address_vni(_a) (_a)->vni
#define gid_address_vni_mask(_a) (_a)->vni_mask
#define gid_address_sd_dst_ippref(_a) sd_dst_ippref(&(_a)->sd)
@@ -249,6 +261,7 @@ void gid_address_ip_set (gid_address_t * dst, void *src, u8 version);
_(ip_prefix) \
_(lcaf) \
_(mac) \
+ _(nsh) \
_(sd)
/* *INDENT-OFF* */
diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c
index 3288b2414b7..d12dc362dac 100644
--- a/src/vnet/lisp-gpe/interface.c
+++ b/src/vnet/lisp-gpe/interface.c
@@ -201,7 +201,7 @@ VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
typedef struct
{
- u32 lb_index;
+ u32 dpo_index;
} l2_lisp_gpe_tx_trace_t;
static u8 *
@@ -211,7 +211,7 @@ format_l2_lisp_gpe_tx_trace (u8 * s, va_list * args)
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
l2_lisp_gpe_tx_trace_t *t = va_arg (*args, l2_lisp_gpe_tx_trace_t *);
- s = format (s, "L2-LISP-GPE-TX: load-balance %d", t->lb_index);
+ s = format (s, "L2-LISP-GPE-TX: load-balance %d", t->dpo_index);
return s;
}
@@ -278,7 +278,7 @@ l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
{
l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
sizeof (*tr));
- tr->lb_index = lbi0;
+ tr->dpo_index = lbi0;
}
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
n_left_to_next, bi0, l2_arc_to_lb);
@@ -306,6 +306,110 @@ VNET_DEVICE_CLASS (l2_lisp_gpe_device_class,static) = {
};
/* *INDENT-ON* */
+typedef struct
+{
+ u32 dpo_index;
+} nsh_lisp_gpe_tx_trace_t;
+
+u8 *
+format_nsh_lisp_gpe_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 *);
+ nsh_lisp_gpe_tx_trace_t *t = va_arg (*args, nsh_lisp_gpe_tx_trace_t *);
+
+ s = format (s, "NSH-GPE-TX: tunnel %d", t->dpo_index);
+ return s;
+}
+
+/**
+ * @brief LISP-GPE interface TX for NSH overlays.
+ * @node nsh_lisp_gpe_interface_tx
+ *
+ * The NSH LISP-GPE interface TX function.
+ *
+ * @param[in] vm vlib_main_t corresponding to the current thread.
+ * @param[in] node vlib_node_runtime_t data for this node.
+ * @param[in] frame vlib_frame_t whose contents should be dispatched.
+ *
+ * @return number of vectors in frame.
+ */
+static uword
+nsh_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ u32 n_left_from, next_index, *from, *to_next;
+ lisp_gpe_main_t *lgm = &lisp_gpe_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 > 0 && n_left_to_next > 0)
+ {
+ vlib_buffer_t *b0;
+ u32 bi0;
+ u32 *nsh0, next0;
+ const dpo_id_t *dpo0;
+
+ 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);
+ nsh0 = vlib_buffer_get_current (b0);
+
+ vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_LCAF;
+
+ /* lookup SPI + SI (second word of the NSH header).
+ * NB: Load balancing was done by the control plane */
+ dpo0 = lisp_nsh_fib_lookup (lgm, nsh0[1]);
+
+ next0 = dpo0->dpoi_next_node;
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+
+ if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ nsh_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
+ sizeof (*tr));
+ tr->dpo_index = dpo0->dpoi_index;
+ }
+ 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);
+ }
+
+ return from_frame->n_vectors;
+}
+
+static u8 *
+format_nsh_lisp_gpe_name (u8 * s, va_list * args)
+{
+ u32 dev_instance = va_arg (*args, u32);
+ return format (s, "nsh_lisp_gpe%d", dev_instance);
+}
+
+/* *INDENT-OFF* */
+VNET_DEVICE_CLASS (nsh_lisp_gpe_device_class,static) = {
+ .name = "NSH_LISP_GPE",
+ .format_device_name = format_nsh_lisp_gpe_name,
+ .format_tx_trace = format_nsh_lisp_gpe_tx_trace,
+ .tx_function = nsh_lisp_gpe_interface_tx,
+};
+/* *INDENT-ON* */
+
static vnet_hw_interface_t *
lisp_gpe_create_iface (lisp_gpe_main_t * lgm, u32 vni, u32 dp_table,
vnet_device_class_t * dev_class,
@@ -615,6 +719,72 @@ lisp_gpe_del_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id)
lisp_gpe_remove_iface (lgm, hip[0], bd_index, &lgm->l2_ifaces);
}
+/**
+ * @brief Add LISP-GPE NSH interface.
+ *
+ * Creates LISP-GPE interface, sets it in L3 mode.
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] a Parameters to create interface.
+ *
+ * @return sw_if_index.
+ */
+u32
+lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm)
+{
+ vnet_main_t *vnm = lgm->vnet_main;
+ tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces;
+ vnet_hw_interface_t *hi;
+ uword *hip, *si;
+
+ hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0);
+
+ if (hip)
+ {
+ clib_warning ("NSH interface 0 already exists");
+ return ~0;
+ }
+
+ si = hash_get (nsh_ifaces->sw_if_index_by_vni, 0);
+ if (si)
+ {
+ clib_warning ("NSH interface already exists");
+ return ~0;
+ }
+
+ /* create lisp iface and populate tunnel tables */
+ hi = lisp_gpe_create_iface (lgm, 0, 0,
+ &nsh_lisp_gpe_device_class, &lgm->nsh_ifaces);
+
+ /* enable interface */
+ vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
+ VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+ vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
+ VNET_HW_INTERFACE_FLAG_LINK_UP);
+
+ return (hi->sw_if_index);
+}
+
+/**
+ * @brief Del LISP-GPE NSH interface.
+ *
+ */
+void
+lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm)
+{
+ tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces;
+ uword *hip;
+
+ hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0);
+
+ if (hip == 0)
+ {
+ clib_warning ("The NSH 0 interface doesn't exist");
+ return;
+ }
+ lisp_gpe_remove_iface (lgm, hip[0], 0, &lgm->nsh_ifaces);
+}
+
static clib_error_t *
lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
@@ -623,6 +793,7 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
u8 is_add = 1;
u32 table_id, vni, bd_id;
u8 vni_is_set = 0, vrf_is_set = 0, bd_index_is_set = 0;
+ u8 nsh_iface = 0;
if (vnet_lisp_gpe_enable_disable_status () == 0)
{
@@ -651,6 +822,10 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
{
bd_index_is_set = 1;
}
+ else if (unformat (line_input, "nsh"))
+ {
+ nsh_iface = 1;
+ }
else
{
return clib_error_return (0, "parse error: '%U'",
@@ -689,6 +864,21 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
lisp_gpe_tenant_l3_iface_unlock (vni);
}
+ if (nsh_iface)
+ {
+ if (is_add)
+ {
+ if (~0 == lisp_gpe_add_nsh_iface (&lisp_gpe_main))
+ {
+ return clib_error_return (0, "NSH interface not created");
+ }
+ else
+ {
+ lisp_gpe_del_nsh_iface (&lisp_gpe_main);
+ }
+ }
+ }
+
return (NULL);
}
diff --git a/src/vnet/lisp-gpe/lisp_gpe.c b/src/vnet/lisp-gpe/lisp_gpe.c
index e78d45c9020..e76c03f0033 100644
--- a/src/vnet/lisp-gpe/lisp_gpe.c
+++ b/src/vnet/lisp-gpe/lisp_gpe.c
@@ -151,6 +151,7 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm,
gid_address_copy (&a->lcl_eid, leid);
gid_address_copy (&a->rmt_eid, reid);
a->locator_pairs = pairs;
+ a->action = action;
rv = vnet_lisp_gpe_add_del_fwd_entry (a, 0);
if (0 != rv)
@@ -291,7 +292,6 @@ format_vnet_lisp_gpe_status (u8 * s, va_list * args)
return format (s, "%s", lgm->is_en ? "enabled" : "disabled");
}
-
/** LISP-GPE init function. */
clib_error_t *
lisp_gpe_init (vlib_main_t * vm)
diff --git a/src/vnet/lisp-gpe/lisp_gpe.h b/src/vnet/lisp-gpe/lisp_gpe.h
index 3288c99ffee..e92df38542c 100644
--- a/src/vnet/lisp-gpe/lisp_gpe.h
+++ b/src/vnet/lisp-gpe/lisp_gpe.h
@@ -119,6 +119,15 @@ typedef struct lisp_gpe_main
/** Load-balance for a miss in the table */
dpo_id_t l2_lb_cp_lkup;
+ /* NSH data structures
+ * ================== */
+
+ BVT (clib_bihash) nsh_fib;
+
+ tunnel_lookup_t nsh_ifaces;
+
+ const dpo_id_t *nsh_cp_lkup;
+
/** convenience */
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
diff --git a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c
index 8c96a25cc5d..1dbf8677f71 100644
--- a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c
+++ b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c
@@ -211,6 +211,8 @@ lisp_gpe_adj_proto_from_vnet_link_type (vnet_link_t linkt)
return (LISP_GPE_NEXT_PROTO_IP6);
case VNET_LINK_ETHERNET:
return (LISP_GPE_NEXT_PROTO_ETHERNET);
+ case VNET_LINK_NSH:
+ return (LISP_GPE_NEXT_PROTO_NSH);
default:
ASSERT (0);
}
@@ -254,14 +256,14 @@ lisp_gpe_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
ladj = pool_elt_at_index (lisp_adj_pool, lai);
lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
linkt = adj_get_link_type (ai);
-
adj_nbr_midchain_update_rewrite
(ai, lisp_gpe_fixup,
(VNET_LINK_ETHERNET == linkt ?
ADJ_MIDCHAIN_FLAG_NO_COUNT :
ADJ_MIDCHAIN_FLAG_NONE),
- lisp_gpe_tunnel_build_rewrite
- (lgt, ladj, lisp_gpe_adj_proto_from_vnet_link_type (linkt)));
+ lisp_gpe_tunnel_build_rewrite (lgt, ladj,
+ lisp_gpe_adj_proto_from_vnet_link_type
+ (linkt)));
lisp_gpe_adj_stack_one (ladj, ai);
}
diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
index 7ad8679e8c0..e51b585e1be 100644
--- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
+++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
@@ -340,10 +340,14 @@ gid_to_dp_address (gid_address_t * g, dp_address_t * d)
d->type = FID_ADDR_IP_PREF;
break;
case GID_ADDR_MAC:
- default:
mac_copy (&d->mac, &gid_address_mac (g));
d->type = FID_ADDR_MAC;
break;
+ case GID_ADDR_NSH:
+ default:
+ d->nsh = gid_address_nsh (g).spi << 8 | gid_address_nsh (g).si;
+ d->type = FID_ADDR_NSH;
+ break;
}
}
@@ -671,7 +675,7 @@ del_l2_fwd_entry (lisp_gpe_main_t * lgm,
}
/**
- * @brief Construct and insert the forwarding information used by a L2 entry
+ * @brief Construct and insert the forwarding information used by an L2 entry
*/
static void
lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
@@ -688,7 +692,16 @@ lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
}
else
{
- dpo_copy (&dpo, &lgm->l2_lb_cp_lkup);
+ switch (lfe->action)
+ {
+ case SEND_MAP_REQUEST:
+ dpo_copy (&dpo, &lgm->l2_lb_cp_lkup);
+ break;
+ case NO_ACTION:
+ case FORWARD_NATIVE:
+ case DROP:
+ dpo_copy (&dpo, drop_dpo_get (DPO_PROTO_ETHERNET));
+ }
}
/* add entry to l2 lisp fib */
@@ -785,6 +798,276 @@ add_l2_fwd_entry (lisp_gpe_main_t * lgm,
}
/**
+ * @brief Lookup NSH SD FIB entry
+ *
+ * Does an SPI+SI lookup in the NSH LISP FIB.
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] spi_si SPI + SI.
+ *
+ * @return next node index.
+ */
+const dpo_id_t *
+lisp_nsh_fib_lookup (lisp_gpe_main_t * lgm, u32 spi_si)
+{
+ int rv;
+ BVT (clib_bihash_kv) kv, value;
+
+ memset (&kv, 0, sizeof (kv));
+ kv.key[0] = spi_si;
+ rv = BV (clib_bihash_search_inline_2) (&lgm->nsh_fib, &kv, &value);
+
+ if (rv != 0)
+ {
+ return lgm->nsh_cp_lkup;
+ }
+ else
+ {
+ lisp_gpe_fwd_entry_t *lfe;
+ lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, value.value);
+ return &lfe->nsh.choice;
+ }
+}
+
+/**
+ * @brief Add/del NSH FIB entry
+ *
+ * Inserts value in NSH FIB keyed by SPI+SI. If entry is
+ * overwritten the associated value is returned.
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] spi_si SPI + SI.
+ * @param[in] dpo Load balanced mapped to SPI + SI
+ *
+ * @return ~0 or value of overwritten entry.
+ */
+static u32
+lisp_nsh_fib_add_del_entry (u32 spi_si, u32 lfei, u8 is_add)
+{
+ lisp_gpe_main_t *lgm = &lisp_gpe_main;
+ BVT (clib_bihash_kv) kv, value;
+ u32 old_val = ~0;
+
+ memset (&kv, 0, sizeof (kv));
+ kv.key[0] = spi_si;
+ kv.value = 0ULL;
+
+ if (BV (clib_bihash_search) (&lgm->nsh_fib, &kv, &value) == 0)
+ old_val = value.value;
+
+ if (!is_add)
+ BV (clib_bihash_add_del) (&lgm->nsh_fib, &kv, 0 /* is_add */ );
+ else
+ {
+ kv.value = lfei;
+ BV (clib_bihash_add_del) (&lgm->nsh_fib, &kv, 1 /* is_add */ );
+ }
+ return old_val;
+}
+
+#define NSH_FIB_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
+#define NSH_FIB_DEFAULT_HASH_MEMORY_SIZE (32<<20)
+
+static void
+nsh_fib_init (lisp_gpe_main_t * lgm)
+{
+ BV (clib_bihash_init) (&lgm->nsh_fib, "nsh fib",
+ 1 << max_log2 (NSH_FIB_DEFAULT_HASH_NUM_BUCKETS),
+ NSH_FIB_DEFAULT_HASH_MEMORY_SIZE);
+
+ /*
+ * the result from a 'miss' in a NSH Table
+ */
+ lgm->nsh_cp_lkup = lisp_cp_dpo_get (DPO_PROTO_NSH);
+}
+
+static void
+del_nsh_fwd_entry_i (lisp_gpe_main_t * lgm, lisp_gpe_fwd_entry_t * lfe)
+{
+ lisp_fwd_path_t *path;
+
+ if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
+ {
+ vec_foreach (path, lfe->paths)
+ {
+ lisp_gpe_adjacency_unlock (path->lisp_adj);
+ }
+ fib_path_list_child_remove (lfe->nsh.path_list_index,
+ lfe->nsh.child_index);
+ dpo_reset (&lfe->nsh.choice);
+ }
+
+ lisp_nsh_fib_add_del_entry (fid_addr_nsh (&lfe->key->rmt), (u32) ~ 0, 0);
+
+ hash_unset_mem (lgm->lisp_gpe_fwd_entries, lfe->key);
+ clib_mem_free (lfe->key);
+ pool_put (lgm->lisp_fwd_entry_pool, lfe);
+}
+
+/**
+ * @brief Delete LISP NSH forwarding entry.
+ *
+ * Coordinates the removal of forwarding entries for NSH LISP overlay:
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] a Parameters for building the forwarding entry.
+ *
+ * @return 0 on success.
+ */
+static int
+del_nsh_fwd_entry (lisp_gpe_main_t * lgm,
+ vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
+{
+ lisp_gpe_fwd_entry_key_t key;
+ lisp_gpe_fwd_entry_t *lfe;
+
+ lfe = find_fwd_entry (lgm, a, &key);
+
+ if (NULL == lfe)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ del_nsh_fwd_entry_i (lgm, lfe);
+
+ return (0);
+}
+
+/**
+ * @brief Construct and insert the forwarding information used by an NSH entry
+ */
+static void
+lisp_gpe_nsh_update_fwding (lisp_gpe_fwd_entry_t * lfe)
+{
+ lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
+ dpo_id_t dpo = DPO_INVALID;
+ vnet_hw_interface_t *hi;
+ uword *hip;
+
+ if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
+ {
+ fib_path_list_contribute_forwarding (lfe->nsh.path_list_index,
+ FIB_FORW_CHAIN_TYPE_NSH,
+ &lfe->nsh.dpo);
+
+ /*
+ * LISP encap is always the same for this SPI+SI so we do that hash now
+ * and stack on the choice.
+ */
+ if (DPO_LOAD_BALANCE == lfe->nsh.dpo.dpoi_type)
+ {
+ const dpo_id_t *tmp;
+ const load_balance_t *lb;
+ int hash;
+
+ lb = load_balance_get (lfe->nsh.dpo.dpoi_index);
+ hash = fid_addr_nsh (&lfe->key->rmt) % lb->lb_n_buckets;
+ tmp =
+ load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1);
+
+ dpo_copy (&dpo, tmp);
+ }
+ }
+ else
+ {
+ switch (lfe->action)
+ {
+ case SEND_MAP_REQUEST:
+ dpo_copy (&dpo, lgm->nsh_cp_lkup);
+ break;
+ case NO_ACTION:
+ case FORWARD_NATIVE:
+ case DROP:
+ dpo_copy (&dpo, drop_dpo_get (DPO_PROTO_NSH));
+ }
+ }
+
+ /* We have only one nsh-lisp interface (no NSH virtualization) */
+ hip = hash_get (lgm->nsh_ifaces.hw_if_index_by_dp_table, 0);
+ hi = vnet_get_hw_interface (lgm->vnet_main, hip[0]);
+
+ dpo_stack_from_node (hi->tx_node_index, &lfe->nsh.choice, &dpo);
+
+ /* add entry to nsh lisp fib */
+ lisp_nsh_fib_add_del_entry (fid_addr_nsh (&lfe->key->rmt),
+ lfe - lgm->lisp_fwd_entry_pool, 1);
+
+ dpo_reset (&dpo);
+}
+
+/**
+ * @brief Add LISP NSH forwarding entry.
+ *
+ * Coordinates the creation of forwarding entries for L2 LISP overlay:
+ * creates lisp-gpe tunnel and injects new entry in Source/Dest L2 FIB.
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] a Parameters for building the forwarding entry.
+ *
+ * @return 0 on success.
+ */
+static int
+add_nsh_fwd_entry (lisp_gpe_main_t * lgm,
+ vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
+{
+ lisp_gpe_fwd_entry_key_t key;
+ lisp_gpe_fwd_entry_t *lfe;
+
+ lfe = find_fwd_entry (lgm, a, &key);
+
+ if (NULL != lfe)
+ /* don't support updates */
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ pool_get (lgm->lisp_fwd_entry_pool, lfe);
+ memset (lfe, 0, sizeof (*lfe));
+ lfe->key = clib_mem_alloc (sizeof (key));
+ memcpy (lfe->key, &key, sizeof (key));
+
+ hash_set_mem (lgm->lisp_gpe_fwd_entries, lfe->key,
+ lfe - lgm->lisp_fwd_entry_pool);
+
+ lfe->type = (a->is_negative ?
+ LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE :
+ LISP_GPE_FWD_ENTRY_TYPE_NORMAL);
+ lfe->tenant = 0;
+
+ if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
+ {
+ fib_route_path_t *rpaths;
+
+ /*
+ * Make the sorted array of LISP paths with their resp. adjacency
+ */
+ lisp_gpe_fwd_entry_mk_paths (lfe, a);
+
+ /*
+ * From the LISP paths, construct a FIB path list that will
+ * contribute a load-balance.
+ */
+ rpaths = lisp_gpe_mk_fib_paths (lfe->paths);
+
+ lfe->nsh.path_list_index =
+ fib_path_list_create (FIB_PATH_LIST_FLAG_NONE, rpaths);
+
+ /*
+ * become a child of the path-list so we receive updates when
+ * its forwarding state changes. this includes an implicit lock.
+ */
+ lfe->nsh.child_index =
+ fib_path_list_child_add (lfe->nsh.path_list_index,
+ FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY,
+ lfe - lgm->lisp_fwd_entry_pool);
+ }
+ else
+ {
+ lfe->action = a->action;
+ }
+
+ lisp_gpe_nsh_update_fwding (lfe);
+
+ return 0;
+}
+
+/**
* @brief conver from the embedded fib_node_t struct to the LSIP entry
*/
static lisp_gpe_fwd_entry_t *
@@ -802,7 +1085,12 @@ static fib_node_back_walk_rc_t
lisp_gpe_fib_node_back_walk (fib_node_t * node,
fib_node_back_walk_ctx_t * ctx)
{
- lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_from_fib_node (node));
+ lisp_gpe_fwd_entry_t *lfe = lisp_gpe_fwd_entry_from_fib_node (node);
+
+ if (fid_addr_type (&lfe->key->rmt) == FID_ADDR_MAC)
+ lisp_gpe_l2_update_fwding (lfe);
+ else if (fid_addr_type (&lfe->key->rmt) == FID_ADDR_NSH)
+ lisp_gpe_nsh_update_fwding (lfe);
return (FIB_NODE_BACK_WALK_CONTINUE);
}
@@ -877,6 +1165,11 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
return add_l2_fwd_entry (lgm, a);
else
return del_l2_fwd_entry (lgm, a);
+ case GID_ADDR_NSH:
+ if (a->is_add)
+ return add_nsh_fwd_entry (lgm, a);
+ else
+ return del_nsh_fwd_entry (lgm, a);
default:
clib_warning ("Forwarding entries for type %d not supported!", type);
return -1;
@@ -903,6 +1196,9 @@ vnet_lisp_gpe_fwd_entry_flush (void)
case FID_ADDR_IP_PREF:
del_ip_fwd_entry_i (lgm, lfe);
break;
+ case FID_ADDR_NSH:
+ del_nsh_fwd_entry_i (lgm, lfe);
+ break;
}
}));
/* *INDENT-ON* */
@@ -967,6 +1263,10 @@ format_lisp_gpe_fwd_entry (u8 * s, va_list ap)
s = format (s, " fib-path-list:%d\n", lfe->l2.path_list_index);
s = format (s, " dpo:%U\n", format_dpo_id, &lfe->l2.dpo, 0);
break;
+ case FID_ADDR_NSH:
+ s = format (s, " fib-path-list:%d\n", lfe->nsh.path_list_index);
+ s = format (s, " dpo:%U\n", format_dpo_id, &lfe->nsh.dpo, 0);
+ break;
case FID_ADDR_IP_PREF:
break;
}
@@ -1036,6 +1336,7 @@ lisp_gpe_fwd_entry_init (vlib_main_t * vm)
return (error);
l2_fib_init (lgm);
+ nsh_fib_init (lgm);
fib_node_register_type (FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY, &lisp_fwd_vft);
diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h
index f79236711ea..d58895a3e28 100644
--- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h
+++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h
@@ -81,7 +81,7 @@ typedef struct lisp_gpe_fwd_entry_t_
fib_node_t node;
/**
- * The Entry's key: {lEID,r-EID,vni}
+ * The Entry's key: {lEID,rEID,vni}
*/
lisp_gpe_fwd_entry_key_t *key;
@@ -150,6 +150,33 @@ typedef struct lisp_gpe_fwd_entry_t_
*/
dpo_id_t dpo;
} l2;
+
+ /**
+ * Fields relevant to an NSH entry
+ */
+ struct
+ {
+ /**
+ * The path-list created for the forwarding
+ */
+ fib_node_index_t path_list_index;
+
+ /**
+ * Child index of this entry on the path-list
+ */
+ u32 child_index;
+
+ /**
+ * The DPO contributed by NSH
+ */
+ dpo_id_t dpo;
+
+ /**
+ * The DPO used for forwarding. Obtained after stacking tx node
+ * onto lb choice
+ */
+ dpo_id_t choice;
+ } nsh;
};
union
@@ -177,6 +204,8 @@ extern void vnet_lisp_gpe_fwd_entry_flush (void);
extern u32 lisp_l2_fib_lookup (lisp_gpe_main_t * lgm,
u16 bd_index, u8 src_mac[8], u8 dst_mac[8]);
+extern const dpo_id_t *lisp_nsh_fib_lookup (lisp_gpe_main_t * lgm,
+ u32 spi_si);
#endif
/*
diff --git a/src/vnet/mfib/mfib_entry.c b/src/vnet/mfib/mfib_entry.c
index f1b6e8ee84e..acbe90bb109 100644
--- a/src/vnet/mfib/mfib_entry.c
+++ b/src/vnet/mfib/mfib_entry.c
@@ -465,6 +465,7 @@ mfib_entry_src_collect_forwarding (fib_node_index_t pl_index,
case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
case FIB_FORW_CHAIN_TYPE_ETHERNET:
+ case FIB_FORW_CHAIN_TYPE_NSH:
ASSERT(0);
break;
}