aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/mpls
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/mpls')
-rw-r--r--src/vnet/mpls/error.def32
-rw-r--r--src/vnet/mpls/interface.c43
-rw-r--r--src/vnet/mpls/mpls.api122
-rw-r--r--src/vnet/mpls/mpls.c15
-rw-r--r--src/vnet/mpls/mpls.h26
-rw-r--r--src/vnet/mpls/mpls_api.c69
-rw-r--r--src/vnet/mpls/mpls_features.c1
-rw-r--r--src/vnet/mpls/mpls_input.c11
-rw-r--r--src/vnet/mpls/mpls_lookup.c244
-rw-r--r--src/vnet/mpls/mpls_output.c253
-rw-r--r--src/vnet/mpls/mpls_tunnel.c17
11 files changed, 494 insertions, 339 deletions
diff --git a/src/vnet/mpls/error.def b/src/vnet/mpls/error.def
deleted file mode 100644
index 9941b18baf4..00000000000
--- a/src/vnet/mpls/error.def
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * mpls_error.def: mpls errors
- *
- * Copyright (c) 2012 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.
- */
-
-mpls_error (NONE, "no error")
-mpls_error (UNKNOWN_PROTOCOL, "unknown protocol")
-mpls_error (UNSUPPORTED_VERSION, "unsupported version")
-mpls_error (PKTS_DECAP, "MPLS input packets decapsulated")
-mpls_error (PKTS_ENCAP, "MPLS output packets encapsulated")
-mpls_error (PKTS_NEED_FRAG, "MPLS output packets needs fragmentation")
-mpls_error (NO_LABEL, "MPLS no label for fib/dst")
-mpls_error (TTL_EXPIRED, "MPLS ttl expired")
-mpls_error (S_NOT_SET, "MPLS s-bit not set")
-mpls_error (BAD_LABEL, "invalid FIB id in label")
-mpls_error (NOT_IP4, "non-ip4 packets dropped")
-mpls_error (DISALLOWED_FIB, "disallowed FIB id")
-mpls_error (NOT_ENABLED, "MPLS not enabled")
-mpls_error (DROP, "MPLS DROP DPO")
-mpls_error (PUNT, "MPLS PUNT DPO")
diff --git a/src/vnet/mpls/interface.c b/src/vnet/mpls/interface.c
index fd075c92d3d..fd654dca891 100644
--- a/src/vnet/mpls/interface.c
+++ b/src/vnet/mpls/interface.c
@@ -22,6 +22,14 @@
#include <vnet/adj/adj_midchain.h>
#include <vnet/dpo/classify_dpo.h>
+typedef struct
+{
+ mpls_interface_state_change_function_t *function;
+ uword function_opaque;
+} mpls_interface_state_change_callback_t;
+
+/** Functions to call when interface becomes MPLS enabled/disabled. */
+static mpls_interface_state_change_callback_t *state_change_callbacks;
u8
mpls_sw_interface_is_enabled (u32 sw_if_index)
@@ -34,11 +42,20 @@ mpls_sw_interface_is_enabled (u32 sw_if_index)
return (mm->mpls_enabled_by_sw_if_index[sw_if_index]);
}
+void
+mpls_interface_state_change_add_callback (
+ mpls_interface_state_change_function_t *function, uword opaque)
+{
+ mpls_interface_state_change_callback_t cb = {
+ .function = function,
+ .function_opaque = opaque,
+ };
+ vec_add1 (state_change_callbacks, cb);
+}
+
int
-mpls_sw_interface_enable_disable (mpls_main_t * mm,
- u32 sw_if_index,
- u8 is_enable,
- u8 is_api)
+mpls_sw_interface_enable_disable (mpls_main_t *mm, u32 sw_if_index,
+ u8 is_enable)
{
fib_node_index_t lfib_index;
vnet_main_t *vnm = vnet_get_main ();
@@ -60,8 +77,7 @@ mpls_sw_interface_enable_disable (mpls_main_t * mm,
if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
return (0);
- fib_table_lock(lfib_index, FIB_PROTOCOL_MPLS,
- (is_api? FIB_SOURCE_API: FIB_SOURCE_CLI));
+ fib_table_lock (lfib_index, FIB_PROTOCOL_MPLS, FIB_SOURCE_INTERFACE);
vec_validate(mm->fib_index_by_sw_if_index, sw_if_index);
mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
@@ -72,9 +88,8 @@ mpls_sw_interface_enable_disable (mpls_main_t * mm,
if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
return (0);
- fib_table_unlock(mm->fib_index_by_sw_if_index[sw_if_index],
- FIB_PROTOCOL_MPLS,
- (is_api? FIB_SOURCE_API: FIB_SOURCE_CLI));
+ fib_table_unlock (mm->fib_index_by_sw_if_index[sw_if_index],
+ FIB_PROTOCOL_MPLS, FIB_SOURCE_INTERFACE);
}
vnet_feature_enable_disable ("mpls-input", "mpls-not-enabled",
@@ -85,6 +100,12 @@ mpls_sw_interface_enable_disable (mpls_main_t * mm,
else if (hi->l3_if_count)
hi->l3_if_count--;
+ {
+ mpls_interface_state_change_callback_t *cb;
+ vec_foreach (cb, state_change_callbacks)
+ cb->function (mm, cb->function_opaque, sw_if_index, is_enable);
+ }
+
return (0);
}
@@ -118,7 +139,7 @@ mpls_interface_enable_disable (vlib_main_t * vm,
goto done;
}
- rv = mpls_sw_interface_enable_disable(&mpls_main, sw_if_index, enable, 0);
+ rv = mpls_sw_interface_enable_disable (&mpls_main, sw_if_index, enable);
if (VNET_API_ERROR_NO_SUCH_FIB == rv)
error = clib_error_return (0, "default MPLS table must be created first");
@@ -128,7 +149,7 @@ mpls_interface_enable_disable (vlib_main_t * vm,
}
/*?
- * This command enables an interface to accpet MPLS packets
+ * This command enables an interface to accept MPLS packets
*
* @cliexpar
* @cliexstart{set interface mpls}
diff --git a/src/vnet/mpls/mpls.api b/src/vnet/mpls/mpls.api
index 9d4ec0bf7bf..5d775dafdfc 100644
--- a/src/vnet/mpls/mpls.api
+++ b/src/vnet/mpls/mpls.api
@@ -92,6 +92,26 @@ define mpls_tunnel_details
vl_api_mpls_tunnel_t mt_tunnel;
};
+/** \brief Dump mpls enabled interface(s)
+ @param client_index - opaque cookie to identify the sender
+ @param sw_if_index - sw_if_index of a specific interface, or -1 (default)
+ to return all MPLS enabled interfaces
+*/
+define mpls_interface_dump
+{
+ u32 client_index;
+ u32 context;
+ vl_api_interface_index_t sw_if_index [default=0xffffffff];
+};
+
+/** \brief mpls enabled interface details
+*/
+define mpls_interface_details
+{
+ u32 context;
+ vl_api_interface_index_t sw_if_index;
+};
+
/** \brief MPLS Route Add / del route
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@@ -212,6 +232,108 @@ autoreply define sw_interface_set_mpls_enable
bool enable [default=true];
};
+counters mpls {
+ none {
+ severity info;
+ type counter64;
+ units "packets";
+ description "no error";
+ };
+ unknown_protocol {
+ severity error;
+ type counter64;
+ units "packets";
+ description "unknown protocol";
+ };
+ unsupported_version {
+ severity error;
+ type counter64;
+ units "packets";
+ description "unsupported version";
+ };
+ pkts_decap {
+ severity info;
+ type counter64;
+ units "packets";
+ description "MPLS input packets decapsulated";
+ };
+ pkts_encap {
+ severity info;
+ type counter64;
+ units "packets";
+ description "MPLS output packets encapsulated";
+ };
+ pkts_need_frag {
+ severity info;
+ type counter64;
+ units "packets";
+ description "MPLS output packets needs fragmentation";
+ };
+ no_label {
+ severity error;
+ type counter64;
+ units "packets";
+ description "MPLS no label for fib/dst";
+ };
+ ttl_expired {
+ severity error;
+ type counter64;
+ units "packets";
+ description "MPLS ttl expired";
+ };
+ s_not_set {
+ severity error;
+ type counter64;
+ units "packets";
+ description "MPLS s-bit not set";
+ };
+ bad_label {
+ severity error;
+ type counter64;
+ units "packets";
+ description "invalid FIB id in label";
+ };
+ not_ip4 {
+ severity error;
+ type counter64;
+ units "packets";
+ description "non-ip4 packets dropped";
+ };
+ disallowed_fib {
+ severity error;
+ type counter64;
+ units "packets";
+ description "disallowed FIB id";
+ };
+ not_enabled {
+ severity error;
+ type counter64;
+ units "packets";
+ description "MPLS not enabled";
+ };
+ drop {
+ severity error;
+ type counter64;
+ units "packets";
+ description "MPLS DROP DPO";
+ };
+ punt {
+ severity error;
+ type counter64;
+ units "packets";
+ description "MPLS PUNT DPO";
+ };
+};
+
+paths {
+ "/err/mpls-input" "mpls";
+ "/err/mpls-output" "mpls";
+ "/err/mpls-lookup" "mpls";
+ "/err/mpls-midchain" "mpls";
+ "/err/mpls-adj-incomplete" "mpls";
+ "/err/mpls-frag" "mpls";
+};
+
/*
* Local Variables:
* eval: (c-set-style "gnu")
diff --git a/src/vnet/mpls/mpls.c b/src/vnet/mpls/mpls.c
index 4076a8980a9..7d922b003cc 100644
--- a/src/vnet/mpls/mpls.c
+++ b/src/vnet/mpls/mpls.c
@@ -370,7 +370,13 @@ done:
VLIB_CLI_COMMAND (mpls_local_label_command, static) = {
.path = "mpls local-label",
.function = vnet_mpls_local_label,
- .short_help = "mpls local-label [add|del] <label-value> [eos|non-eos] via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-attached] [rx-ip4 <interface>] [out-labels <value value value>]",
+ .short_help =
+ "mpls local-label [add|del] <label-value> [eos|non-eos] via "
+ "[next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight "
+ "<value>] [preference <value>] [udp-encap-id <value>] "
+ "[ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] "
+ "[mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-attached] "
+ "[rx-ip4|rx-ip6 <interface>] [out-labels <value value value>]",
};
clib_error_t *
@@ -425,17 +431,16 @@ vnet_mpls_table_cmd (vlib_main_t * vm,
}
done:
- unformat_free (line_input);
- return error;
+ vec_free (name);
+ unformat_free (line_input);
+ return error;
}
-/* *INDENT-ON* */
/*?
* This command is used to add or delete MPLS Tables. All
* Tables must be explicitly added before that can be used,
* Including the default table.
?*/
-/* *INDENT-OFF* */
VLIB_CLI_COMMAND (mpls_table_command, static) = {
.path = "mpls table",
.short_help = "mpls table [add|del] <table-id>",
diff --git a/src/vnet/mpls/mpls.h b/src/vnet/mpls/mpls.h
index 00b493f4576..6baaaad95ba 100644
--- a/src/vnet/mpls/mpls.h
+++ b/src/vnet/mpls/mpls.h
@@ -23,22 +23,18 @@
#include <vnet/fib/fib_node.h>
#include <vnet/adj/adj.h>
-typedef enum
-{
-#define mpls_error(n,s) MPLS_ERROR_##n,
-#include <vnet/mpls/error.def>
-#undef mpls_error
- MPLS_N_ERROR,
-} mpls_error_t;
+struct mpls_main_t;
/**
* @brief Definition of a callback for receiving MPLS interface state change
* notifications
*/
-typedef void (*mpls_interface_state_change_callback_t) (u32 sw_if_index,
- u32 is_enable);
+typedef void (mpls_interface_state_change_function_t) (struct mpls_main_t *mm,
+ uword opaque,
+ u32 sw_if_index,
+ u32 is_enable);
-typedef struct
+typedef struct mpls_main_t
{
/* MPLS FIB index for each software interface */
u32 *fib_index_by_sw_if_index;
@@ -85,12 +81,14 @@ unformat_function_t unformat_mpls_unicast_label;
unformat_function_t unformat_mpls_header;
unformat_function_t unformat_pg_mpls_header;
-int mpls_sw_interface_enable_disable (mpls_main_t * mm,
- u32 sw_if_index,
- u8 is_enable, u8 is_api);
-
u8 mpls_sw_interface_is_enabled (u32 sw_if_index);
+void mpls_interface_state_change_add_callback (
+ mpls_interface_state_change_function_t *function, uword opaque);
+
+int mpls_sw_interface_enable_disable (mpls_main_t *mm, u32 sw_if_index,
+ u8 is_enable);
+
int mpls_dest_cmp (void *a1, void *a2);
int mpls_fib_index_cmp (void *a1, void *a2);
diff --git a/src/vnet/mpls/mpls_api.c b/src/vnet/mpls/mpls_api.c
index e89732f0d10..58998a6576c 100644
--- a/src/vnet/mpls/mpls_api.c
+++ b/src/vnet/mpls/mpls_api.c
@@ -199,19 +199,15 @@ vl_api_mpls_route_add_del_t_handler (vl_api_mpls_route_add_del_t * mp)
rv = mpls_route_add_del_t_handler (vnm, mp, &stats_index);
- /* *INDENT-OFF* */
REPLY_MACRO2 (VL_API_MPLS_ROUTE_ADD_DEL_REPLY,
({
rmp->stats_index = htonl (stats_index);
}));
- /* *INDENT-ON* */
}
void
mpls_table_create (u32 table_id, u8 is_api, const u8 * name)
{
- u32 fib_index;
-
/*
* The MPLS defult table must also be explicitly created via the API.
* So in contrast to IP, it gets no special treatment here.
@@ -222,16 +218,11 @@ mpls_table_create (u32 table_id, u8 is_api, const u8 * name)
* i.e. it can be added many times via the API but needs to be
* deleted only once.
*/
- fib_index = fib_table_find (FIB_PROTOCOL_MPLS, table_id);
-
- if (~0 == fib_index)
- {
fib_table_find_or_create_and_lock_w_name (FIB_PROTOCOL_MPLS,
table_id,
(is_api ?
FIB_SOURCE_API :
FIB_SOURCE_CLI), name);
- }
}
static void
@@ -277,13 +268,11 @@ vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp)
vec_free (rpaths);
out:
- /* *INDENT-OFF* */
REPLY_MACRO2(VL_API_MPLS_TUNNEL_ADD_DEL_REPLY,
({
rmp->sw_if_index = ntohl(tunnel_sw_if_index);
rmp->tunnel_index = ntohl(tunnel_index);
}));
- /* *INDENT-ON* */
}
static void
@@ -295,9 +284,8 @@ static void
VALIDATE_SW_IF_INDEX (mp);
- rv = mpls_sw_interface_enable_disable (&mpls_main,
- ntohl (mp->sw_if_index),
- mp->enable, 1);
+ rv = mpls_sw_interface_enable_disable (&mpls_main, ntohl (mp->sw_if_index),
+ mp->enable);
BAD_SW_IF_INDEX_LABEL;
REPLY_MACRO (VL_API_SW_INTERFACE_SET_MPLS_ENABLE_REPLY);
@@ -409,12 +397,58 @@ vl_api_mpls_table_dump_t_handler (vl_api_mpls_table_dump_t * mp)
if (!reg)
return;
- /* *INDENT-OFF* */
pool_foreach (fib_table, mm->fibs)
{
send_mpls_table_details(am, reg, mp->context, fib_table);
}
- /* *INDENT-ON* */
+}
+
+static void
+send_mpls_interface_details (vpe_api_main_t *am, vl_api_registration_t *reg,
+ u32 context, const u32 sw_if_index)
+{
+ vl_api_mpls_interface_details_t *mp;
+
+ mp = vl_msg_api_alloc_zero (sizeof (*mp));
+ mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MPLS_INTERFACE_DETAILS);
+ mp->context = context;
+
+ mp->sw_if_index = htonl (sw_if_index);
+ vl_api_send_msg (reg, (u8 *) mp);
+}
+
+static void
+vl_api_mpls_interface_dump_t_handler (vl_api_mpls_interface_dump_t *mp)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+ vl_api_registration_t *reg;
+ vnet_interface_main_t *im = &vnet_main.interface_main;
+ vnet_sw_interface_t *si;
+ u32 sw_if_index = ~0;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+ sw_if_index = ntohl (mp->sw_if_index);
+
+ if (sw_if_index == ~0)
+ {
+ pool_foreach (si, im->sw_interfaces)
+ {
+ if (mpls_sw_interface_is_enabled (si->sw_if_index))
+ {
+ send_mpls_interface_details (am, reg, mp->context,
+ si->sw_if_index);
+ }
+ }
+ }
+ else
+ {
+ if (mpls_sw_interface_is_enabled (sw_if_index))
+ {
+ send_mpls_interface_details (am, reg, mp->context, sw_if_index);
+ }
+ }
}
static void
@@ -516,7 +550,8 @@ mpls_api_hookup (vlib_main_t * vm)
/*
* Trace space for 8 MPLS encap labels
*/
- am->api_trace_cfg[VL_API_MPLS_TUNNEL_ADD_DEL].size += 8 * sizeof (u32);
+ vl_api_increase_msg_trace_size (am, VL_API_MPLS_TUNNEL_ADD_DEL,
+ 8 * sizeof (u32));
/*
* Set up the (msg_name, crc, message-id) table
diff --git a/src/vnet/mpls/mpls_features.c b/src/vnet/mpls/mpls_features.c
index 070f90a1cc6..3b535032908 100644
--- a/src/vnet/mpls/mpls_features.c
+++ b/src/vnet/mpls/mpls_features.c
@@ -16,6 +16,7 @@
*/
#include <vnet/mpls/mpls.h>
+#include <vnet/mpls/mpls.api_enum.h>
static u8 *
format_mpls_drop_trace (u8 * s, va_list * args)
diff --git a/src/vnet/mpls/mpls_input.c b/src/vnet/mpls/mpls_input.c
index 37fa1aead12..0505d9a1829 100644
--- a/src/vnet/mpls/mpls_input.c
+++ b/src/vnet/mpls/mpls_input.c
@@ -19,6 +19,7 @@
#include <vnet/pg/pg.h>
#include <vnet/mpls/mpls.h>
#include <vnet/feature/feature.h>
+#include <vnet/mpls/mpls.api_enum.h>
typedef struct {
u32 next_index;
@@ -236,12 +237,6 @@ VLIB_NODE_FN (mpls_input_node) (vlib_main_t * vm,
return mpls_input_inline (vm, node, from_frame);
}
-static char * mpls_error_strings[] = {
-#define mpls_error(n,s) s,
-#include "error.def"
-#undef mpls_error
-};
-
VLIB_REGISTER_NODE (mpls_input_node) = {
.name = "mpls-input",
/* Takes a vector of packets. */
@@ -250,7 +245,7 @@ VLIB_REGISTER_NODE (mpls_input_node) = {
.runtime_data_bytes = sizeof(mpls_input_runtime_t),
.n_errors = MPLS_N_ERROR,
- .error_strings = mpls_error_strings,
+ .error_counters = mpls_error_counters,
.n_next_nodes = MPLS_INPUT_N_NEXT,
.next_nodes = {
@@ -283,10 +278,8 @@ static clib_error_t * mpls_input_init (vlib_main_t * vm)
return 0;
}
-/* *INDENT-OFF* */
VLIB_INIT_FUNCTION (mpls_input_init) =
{
.runs_after = VLIB_INITS("mpls_init"),
};
-/* *INDENT-ON* */
#endif /* CLIB_MARCH_VARIANT */
diff --git a/src/vnet/mpls/mpls_lookup.c b/src/vnet/mpls/mpls_lookup.c
index 07c5cc47198..a5ac56534a5 100644
--- a/src/vnet/mpls/mpls_lookup.c
+++ b/src/vnet/mpls/mpls_lookup.c
@@ -20,6 +20,7 @@
#include <vnet/fib/mpls_fib.h>
#include <vnet/dpo/load_balance_map.h>
#include <vnet/dpo/replicate_dpo.h>
+#include <vnet/mpls/mpls.api_enum.h>
/**
* The arc/edge from the MPLS lookup node to the MPLS replicate node
@@ -43,13 +44,13 @@ format_mpls_lookup_trace (u8 * s, va_list * args)
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
mpls_lookup_trace_t * t = va_arg (*args, mpls_lookup_trace_t *);
- s = format (s, "MPLS: next [%d], lookup fib index %d, LB index %d hash %x "
- "label %d eos %d",
- t->next_index, t->lfib_index, t->lb_index, t->hash,
- vnet_mpls_uc_get_label(
- clib_net_to_host_u32(t->label_net_byte_order)),
- vnet_mpls_uc_get_s(
- clib_net_to_host_u32(t->label_net_byte_order)));
+ s = format (
+ s,
+ "MPLS: next [%d], lookup fib index %d, LB index %d hash 0x%08x "
+ "label %d eos %d",
+ t->next_index, t->lfib_index, t->lb_index, t->hash,
+ vnet_mpls_uc_get_label (clib_net_to_host_u32 (t->label_net_byte_order)),
+ vnet_mpls_uc_get_s (clib_net_to_host_u32 (t->label_net_byte_order)));
return s;
}
@@ -454,18 +455,12 @@ VLIB_NODE_FN (mpls_lookup_node) (vlib_main_t * vm,
return from_frame->n_vectors;
}
-static char * mpls_error_strings[] = {
-#define mpls_error(n,s) s,
-#include "error.def"
-#undef mpls_error
-};
-
VLIB_REGISTER_NODE (mpls_lookup_node) = {
.name = "mpls-lookup",
/* Takes a vector of packets. */
.vector_size = sizeof (u32),
.n_errors = MPLS_N_ERROR,
- .error_strings = mpls_error_strings,
+ .error_counters = mpls_error_counters,
.sibling_of = "mpls-load-balance",
@@ -487,8 +482,8 @@ format_mpls_load_balance_trace (u8 * s, va_list * args)
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
mpls_load_balance_trace_t * t = va_arg (*args, mpls_load_balance_trace_t *);
- s = format (s, "MPLS: next [%d], LB index %d hash %d",
- t->next_index, t->lb_index, t->hash);
+ s = format (s, "MPLS: next [%d], LB index %d hash 0x%08x", t->next_index,
+ t->lb_index, t->hash);
return s;
}
@@ -558,75 +553,77 @@ VLIB_NODE_FN (mpls_load_balance_node) (vlib_main_t * vm,
* We don't want to use the same hash value at each level in the recursion
* graph as that would lead to polarisation
*/
- hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
- hc1 = vnet_buffer (p1)->ip.flow_hash = 0;
-
- if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
- {
- if (PREDICT_TRUE (vnet_buffer(p0)->ip.flow_hash))
- {
- hc0 = vnet_buffer(p0)->ip.flow_hash = vnet_buffer(p0)->ip.flow_hash >> 1;
- }
- else
- {
- hc0 = vnet_buffer(p0)->ip.flow_hash = mpls_compute_flow_hash(mpls0, hc0);
- }
- dpo0 = load_balance_get_fwd_bucket(lb0, (hc0 & lb0->lb_n_buckets_minus_1));
- }
- else
- {
- dpo0 = load_balance_get_bucket_i (lb0, 0);
- }
- if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
- {
- if (PREDICT_TRUE (vnet_buffer(p1)->ip.flow_hash))
- {
- hc1 = vnet_buffer(p1)->ip.flow_hash = vnet_buffer(p1)->ip.flow_hash >> 1;
- }
- else
- {
- hc1 = vnet_buffer(p1)->ip.flow_hash = mpls_compute_flow_hash(mpls1, hc1);
- }
- dpo1 = load_balance_get_fwd_bucket(lb1, (hc1 & lb1->lb_n_buckets_minus_1));
- }
- else
- {
- dpo1 = load_balance_get_bucket_i (lb1, 0);
- }
-
- next0 = dpo0->dpoi_next_node;
- next1 = dpo1->dpoi_next_node;
-
- vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
- vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
-
- vlib_increment_combined_counter
- (cm, thread_index, lbi0, 1,
- vlib_buffer_length_in_chain (vm, p0));
- vlib_increment_combined_counter
- (cm, thread_index, lbi1, 1,
- vlib_buffer_length_in_chain (vm, p1));
-
- if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
- {
- mpls_load_balance_trace_t *tr = vlib_add_trace (vm, node,
- p0, sizeof (*tr));
- tr->next_index = next0;
- tr->lb_index = lbi0;
- tr->hash = hc0;
- }
- if (PREDICT_FALSE(p1->flags & VLIB_BUFFER_IS_TRACED))
- {
- mpls_load_balance_trace_t *tr = vlib_add_trace (vm, node,
- p1, sizeof (*tr));
- tr->next_index = next1;
- tr->lb_index = lbi1;
- tr->hash = hc1;
- }
-
- vlib_validate_buffer_enqueue_x2 (vm, node, next,
- to_next, n_left_to_next,
- pi0, pi1, next0, next1);
+ hc0 = hc1 = 0;
+
+ if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
+ {
+ if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
+ {
+ hc0 = vnet_buffer (p0)->ip.flow_hash =
+ vnet_buffer (p0)->ip.flow_hash >> 1;
+ }
+ else
+ {
+ hc0 = vnet_buffer (p0)->ip.flow_hash =
+ mpls_compute_flow_hash (mpls0, lb0->lb_hash_config);
+ }
+ dpo0 = load_balance_get_fwd_bucket (
+ lb0, (hc0 & lb0->lb_n_buckets_minus_1));
+ }
+ else
+ {
+ dpo0 = load_balance_get_bucket_i (lb0, 0);
+ }
+ if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
+ {
+ if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
+ {
+ hc1 = vnet_buffer (p1)->ip.flow_hash =
+ vnet_buffer (p1)->ip.flow_hash >> 1;
+ }
+ else
+ {
+ hc1 = vnet_buffer (p1)->ip.flow_hash =
+ mpls_compute_flow_hash (mpls1, lb1->lb_hash_config);
+ }
+ dpo1 = load_balance_get_fwd_bucket (
+ lb1, (hc1 & lb1->lb_n_buckets_minus_1));
+ }
+ else
+ {
+ dpo1 = load_balance_get_bucket_i (lb1, 0);
+ }
+
+ next0 = dpo0->dpoi_next_node;
+ next1 = dpo1->dpoi_next_node;
+
+ vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+ vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
+
+ vlib_increment_combined_counter (
+ cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
+ vlib_increment_combined_counter (
+ cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
+
+ if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ mpls_load_balance_trace_t *tr =
+ vlib_add_trace (vm, node, p0, sizeof (*tr));
+ tr->next_index = next0;
+ tr->lb_index = lbi0;
+ tr->hash = hc0;
+ }
+ if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ mpls_load_balance_trace_t *tr =
+ vlib_add_trace (vm, node, p1, sizeof (*tr));
+ tr->next_index = next1;
+ tr->lb_index = lbi1;
+ tr->hash = hc1;
+ }
+
+ vlib_validate_buffer_enqueue_x2 (
+ vm, node, next, to_next, n_left_to_next, pi0, pi1, next0, next1);
}
while (n_left_from > 0 && n_left_to_next > 0)
@@ -651,44 +648,45 @@ VLIB_NODE_FN (mpls_load_balance_node) (vlib_main_t * vm,
lb0 = load_balance_get(lbi0);
- hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
- if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
- {
- if (PREDICT_TRUE (vnet_buffer(p0)->ip.flow_hash))
- {
- hc0 = vnet_buffer(p0)->ip.flow_hash = vnet_buffer(p0)->ip.flow_hash >> 1;
- }
- else
- {
- hc0 = vnet_buffer(p0)->ip.flow_hash = mpls_compute_flow_hash(mpls0, hc0);
- }
- dpo0 = load_balance_get_fwd_bucket(lb0, (hc0 & lb0->lb_n_buckets_minus_1));
- }
- else
- {
- dpo0 = load_balance_get_bucket_i (lb0, 0);
- }
-
- next0 = dpo0->dpoi_next_node;
- vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
-
- if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
- {
- mpls_load_balance_trace_t *tr = vlib_add_trace (vm, node,
- p0, sizeof (*tr));
- tr->next_index = next0;
- tr->lb_index = lbi0;
- tr->hash = hc0;
- }
-
- vlib_increment_combined_counter
- (cm, thread_index, lbi0, 1,
- vlib_buffer_length_in_chain (vm, p0));
-
- vlib_validate_buffer_enqueue_x1 (vm, node, next,
- to_next, n_left_to_next,
- pi0, next0);
- }
+ hc0 = 0;
+ if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
+ {
+ if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
+ {
+ hc0 = vnet_buffer (p0)->ip.flow_hash =
+ vnet_buffer (p0)->ip.flow_hash >> 1;
+ }
+ else
+ {
+ hc0 = vnet_buffer (p0)->ip.flow_hash =
+ mpls_compute_flow_hash (mpls0, lb0->lb_hash_config);
+ }
+ dpo0 = load_balance_get_fwd_bucket (
+ lb0, (hc0 & lb0->lb_n_buckets_minus_1));
+ }
+ else
+ {
+ dpo0 = load_balance_get_bucket_i (lb0, 0);
+ }
+
+ next0 = dpo0->dpoi_next_node;
+ vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+
+ if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ mpls_load_balance_trace_t *tr =
+ vlib_add_trace (vm, node, p0, sizeof (*tr));
+ tr->next_index = next0;
+ tr->lb_index = lbi0;
+ tr->hash = hc0;
+ }
+
+ vlib_increment_combined_counter (
+ cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next,
+ n_left_to_next, pi0, next0);
+ }
vlib_put_next_frame (vm, node, next, n_left_to_next);
}
diff --git a/src/vnet/mpls/mpls_output.c b/src/vnet/mpls/mpls_output.c
index a1d2d3baa88..9c1d7316db7 100644
--- a/src/vnet/mpls/mpls_output.c
+++ b/src/vnet/mpls/mpls_output.c
@@ -20,6 +20,7 @@
#include <vnet/mpls/mpls.h>
#include <vnet/ip/ip_frag.h>
#include <vnet/adj/adj_dp.h>
+#include <vnet/mpls/mpls.api_enum.h>
typedef struct {
/* Adjacency taken. */
@@ -317,12 +318,6 @@ mpls_output_inline (vlib_main_t * vm,
return from_frame->n_vectors;
}
-static char * mpls_error_strings[] = {
-#define mpls_error(n,s) s,
-#include "error.def"
-#undef mpls_error
-};
-
VLIB_NODE_FN (mpls_output_node) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
@@ -335,7 +330,7 @@ VLIB_REGISTER_NODE (mpls_output_node) = {
/* Takes a vector of packets. */
.vector_size = sizeof (u32),
.n_errors = MPLS_N_ERROR,
- .error_strings = mpls_error_strings,
+ .error_counters = mpls_error_counters,
.n_next_nodes = MPLS_OUTPUT_N_NEXT,
.next_nodes = {
@@ -357,18 +352,12 @@ VLIB_REGISTER_NODE (mpls_midchain_node) = {
.vector_size = sizeof (u32),
.n_errors = MPLS_N_ERROR,
- .error_strings = mpls_error_strings,
+ .error_counters = mpls_error_counters,
.sibling_of = "mpls-output",
.format_trace = format_mpls_output_trace,
};
-static char *mpls_frag_error_strings[] = {
-#define _(sym,string) string,
- foreach_ip_frag_error
-#undef _
-};
-
typedef struct mpls_frag_trace_t_
{
u16 pkt_size;
@@ -377,11 +366,12 @@ typedef struct mpls_frag_trace_t_
typedef enum
{
- MPLS_FRAG_NEXT_REWRITE,
- MPLS_FRAG_NEXT_REWRITE_MIDCHAIN,
- MPLS_FRAG_NEXT_ICMP_ERROR,
- MPLS_FRAG_NEXT_DROP,
- MPLS_FRAG_N_NEXT,
+ MPLS_FRAG_NEXT_REWRITE,
+ MPLS_FRAG_NEXT_REWRITE_MIDCHAIN,
+ MPLS_FRAG_NEXT_ICMP4_ERROR,
+ MPLS_FRAG_NEXT_ICMP6_ERROR,
+ MPLS_FRAG_NEXT_DROP,
+ MPLS_FRAG_N_NEXT,
} mpls_frag_next_t;
static uword
@@ -390,9 +380,7 @@ mpls_frag (vlib_main_t * vm,
vlib_frame_t * frame)
{
u32 n_left_from, next_index, * from, * to_next, n_left_to_next, *frags;
- vlib_node_runtime_t * error_node;
- error_node = vlib_node_get_runtime (vm, mpls_output_node.index);
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
next_index = node->cached_next_index;
@@ -410,91 +398,111 @@ mpls_frag (vlib_main_t * vm,
mpls_frag_next_t next0;
u32 pi0, adj_index0;
ip_frag_error_t error0 = IP_FRAG_ERROR_NONE;
- i16 encap_size;
- u8 is_ip4;
-
- pi0 = to_next[0] = from[0];
- p0 = vlib_get_buffer (vm, pi0);
- from += 1;
- n_left_from -= 1;
- is_ip4 = vnet_buffer (p0)->mpls.pyld_proto == DPO_PROTO_IP4;
-
- adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
- adj0 = adj_get(adj_index0);
-
- /* the size of the MPLS stack */
- encap_size = vnet_buffer(p0)->l3_hdr_offset - p0->current_data;
-
- /* IP fragmentation */
- if (is_ip4)
- error0 = ip4_frag_do_fragment (vm, pi0,
- adj0->rewrite_header.max_l3_packet_bytes,
- encap_size, &frags);
- else
- error0 = ip6_frag_do_fragment (vm, pi0,
- adj0->rewrite_header.max_l3_packet_bytes,
- encap_size, &frags);
-
- if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
- {
- mpls_frag_trace_t *tr =
- vlib_add_trace (vm, node, p0, sizeof (*tr));
- tr->mtu = adj0->rewrite_header.max_l3_packet_bytes;
- tr->pkt_size = vlib_buffer_length_in_chain(vm, p0);
- }
-
- if (PREDICT_TRUE(error0 == IP_FRAG_ERROR_NONE))
- {
- /* Free original buffer chain */
- vlib_buffer_free_one (vm, pi0); /* Free original packet */
- next0 = (IP_LOOKUP_NEXT_MIDCHAIN == adj0->lookup_next_index ?
- MPLS_FRAG_NEXT_REWRITE_MIDCHAIN :
- MPLS_FRAG_NEXT_REWRITE);
- }
- else if (is_ip4 && error0 == IP_FRAG_ERROR_DONT_FRAGMENT_SET)
- {
- icmp4_error_set_vnet_buffer (
- p0, ICMP4_destination_unreachable,
- ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
- vnet_buffer (p0)->ip_frag.mtu);
- next0 = MPLS_FRAG_NEXT_ICMP_ERROR;
- }
- else
- {
- vlib_error_count (vm, mpls_output_node.index, error0, 1);
- vec_add1 (frags, pi0); /* Get rid of the original buffer */
- next0 = MPLS_FRAG_NEXT_DROP;
- }
-
- /* Send fragments that were added in the frame */
- u32 *frag_from, frag_left;
-
- frag_from = frags;
- frag_left = vec_len (frags);
-
- while (frag_left > 0)
- {
- while (frag_left > 0 && n_left_to_next > 0)
- {
- u32 i;
- i = to_next[0] = frag_from[0];
- frag_from += 1;
- frag_left -= 1;
- to_next += 1;
- n_left_to_next -= 1;
-
- p0 = vlib_get_buffer (vm, i);
- p0->error = error_node->errors[error0];
-
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next, i,
- next0);
- }
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- vlib_get_next_frame (vm, node, next_index, to_next,
- n_left_to_next);
- }
- vec_reset_length (frags);
+ i16 encap_size, mtu;
+ u8 is_ip4;
+
+ pi0 = to_next[0] = from[0];
+ p0 = vlib_get_buffer (vm, pi0);
+ from += 1;
+ n_left_from -= 1;
+ is_ip4 = vnet_buffer (p0)->mpls.pyld_proto == DPO_PROTO_IP4;
+
+ adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
+ adj0 = adj_get (adj_index0);
+
+ /* the size of the MPLS stack */
+ encap_size = vnet_buffer (p0)->l3_hdr_offset - p0->current_data;
+ mtu = adj0->rewrite_header.max_l3_packet_bytes - encap_size;
+
+ /* IP fragmentation */
+ if (is_ip4)
+ error0 = ip4_frag_do_fragment (vm, pi0, mtu, encap_size, &frags);
+ else
+ {
+ if (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
+ {
+ /* only fragment locally generated IPv6 */
+ error0 = IP_FRAG_ERROR_DONT_FRAGMENT_SET;
+ }
+ else
+ {
+ error0 =
+ ip6_frag_do_fragment (vm, pi0, mtu, encap_size, &frags);
+ }
+ }
+
+ if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ mpls_frag_trace_t *tr =
+ vlib_add_trace (vm, node, p0, sizeof (*tr));
+ tr->mtu = mtu;
+ tr->pkt_size = vlib_buffer_length_in_chain (vm, p0);
+ }
+
+ if (PREDICT_TRUE (error0 == IP_FRAG_ERROR_NONE))
+ {
+ /* Free original buffer chain */
+ vlib_buffer_free_one (vm, pi0);
+ next0 = (IP_LOOKUP_NEXT_MIDCHAIN == adj0->lookup_next_index ?
+ MPLS_FRAG_NEXT_REWRITE_MIDCHAIN :
+ MPLS_FRAG_NEXT_REWRITE);
+ }
+ else
+ {
+ vlib_error_count (vm, node->node_index, error0, 1);
+
+ if (error0 == IP_FRAG_ERROR_DONT_FRAGMENT_SET)
+ {
+ vlib_buffer_advance (p0, encap_size);
+ if (is_ip4)
+ {
+ icmp4_error_set_vnet_buffer (
+ p0, ICMP4_destination_unreachable,
+ ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
+ mtu);
+ next0 = MPLS_FRAG_NEXT_ICMP4_ERROR;
+ }
+ else
+ {
+ icmp6_error_set_vnet_buffer (p0, ICMP6_packet_too_big,
+ 0, mtu);
+ next0 = MPLS_FRAG_NEXT_ICMP6_ERROR;
+ }
+ }
+ else
+ {
+ next0 = MPLS_FRAG_NEXT_DROP;
+ }
+
+ /* Get rid of the original buffer */
+ vec_add1 (frags, pi0);
+ }
+
+ /* Send fragments that were added in the frame */
+ u32 *frag_from, frag_left;
+
+ frag_from = frags;
+ frag_left = vec_len (frags);
+
+ while (frag_left > 0)
+ {
+ while (frag_left > 0 && n_left_to_next > 0)
+ {
+ u32 i;
+ i = to_next[0] = frag_from[0];
+ frag_from += 1;
+ frag_left -= 1;
+ to_next += 1;
+ n_left_to_next -= 1;
+
+ vlib_validate_buffer_enqueue_x1 (
+ vm, node, next_index, to_next, n_left_to_next, i, next0);
+ }
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ vlib_get_next_frame (vm, node, next_index, to_next,
+ n_left_to_next);
+ }
+ vec_reset_length (frags);
}
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
@@ -515,22 +523,21 @@ format_mpls_frag_trace (u8 * s, va_list * args)
}
VLIB_REGISTER_NODE (mpls_frag_node) = {
- .function = mpls_frag,
- .name = "mpls-frag",
- .vector_size = sizeof (u32),
- .format_trace = format_mpls_frag_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
-
- .n_errors = IP_FRAG_N_ERROR,
- .error_strings = mpls_frag_error_strings,
-
- .n_next_nodes = MPLS_FRAG_N_NEXT,
- .next_nodes = {
- [MPLS_FRAG_NEXT_REWRITE] = "mpls-output",
- [MPLS_FRAG_NEXT_REWRITE_MIDCHAIN] = "mpls-midchain",
- [MPLS_FRAG_NEXT_ICMP_ERROR] = "ip4-icmp-error",
- [MPLS_FRAG_NEXT_DROP] = "mpls-drop"
- },
+ .function = mpls_frag,
+ .name = "mpls-frag",
+ .vector_size = sizeof (u32),
+ .format_trace = format_mpls_frag_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = IP_FRAG_N_ERROR,
+ .error_counters = ip_frag_error_counters,
+
+ .n_next_nodes = MPLS_FRAG_N_NEXT,
+ .next_nodes = { [MPLS_FRAG_NEXT_REWRITE] = "mpls-output",
+ [MPLS_FRAG_NEXT_REWRITE_MIDCHAIN] = "mpls-midchain",
+ [MPLS_FRAG_NEXT_ICMP4_ERROR] = "ip4-icmp-error",
+ [MPLS_FRAG_NEXT_ICMP6_ERROR] = "ip6-icmp-error",
+ [MPLS_FRAG_NEXT_DROP] = "mpls-drop" },
};
/*
@@ -649,7 +656,7 @@ VLIB_REGISTER_NODE (mpls_adj_incomplete_node) = {
/* Takes a vector of packets. */
.vector_size = sizeof (u32),
.n_errors = MPLS_N_ERROR,
- .error_strings = mpls_error_strings,
+ .error_counters = mpls_error_counters,
.n_next_nodes = MPLS_ADJ_INCOMPLETE_N_NEXT,
.next_nodes = {
diff --git a/src/vnet/mpls/mpls_tunnel.c b/src/vnet/mpls/mpls_tunnel.c
index 54458eacdf8..b03a4a57f68 100644
--- a/src/vnet/mpls/mpls_tunnel.c
+++ b/src/vnet/mpls/mpls_tunnel.c
@@ -265,10 +265,8 @@ mpls_tunnel_collect_forwarding (fib_node_index_t pl_index,
* found a matching extension. stack it to obtain the forwarding
* info for this path.
*/
- ctx->next_hops = fib_path_ext_stack(path_ext,
- ctx->fct,
- ctx->fct,
- ctx->next_hops);
+ ctx->next_hops =
+ fib_path_ext_stack (path_ext, DPO_PROTO_MPLS, ctx->fct, ctx->next_hops);
return (FIB_PATH_LIST_WALK_CONTINUE);
}
@@ -638,6 +636,7 @@ vnet_mpls_tunnel_del (u32 sw_if_index)
mt->mt_sibling_index);
dpo_reset(&mt->mt_l2_lb);
+ vnet_reset_interface_l3_output_node (vlib_get_main (), mt->mt_sw_if_index);
vnet_delete_hw_interface (vnet_get_main(), mt->mt_hw_if_index);
pool_put(mpls_tunnel_pool, mt);
@@ -685,6 +684,9 @@ vnet_mpls_tunnel_create (u8 l2_only,
if (mt->mt_flags & MPLS_TUNNEL_FLAG_L2)
vnet_set_interface_output_node (vnm, mt->mt_hw_if_index,
mpls_tunnel_tx.index);
+ else
+ vnet_set_interface_l3_output_node (vnm->vlib_main, hi->sw_if_index,
+ (u8 *) "tunnel-output");
/* Standard default MPLS tunnel MTU. */
vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, 9000);
@@ -930,7 +932,12 @@ done:
VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
.path = "mpls tunnel",
.short_help =
- "mpls tunnel [multicast] [l2-only] via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]",
+ "mpls tunnel [multicast] [l2-only] via [next-hop-address] "
+ "[next-hop-interface] [next-hop-table <value>] [weight <value>] "
+ "[preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table "
+ "<value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] "
+ "[resolve-via-host] [resolve-via-connected] [rx-ip4|rx-ip6 <interface>] "
+ "[out-labels <value value value>]",
.function = vnet_create_mpls_tunnel_command_fn,
};