aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vnet/Makefile.am2
-rw-r--r--vnet/vnet/lisp-cp/control.c100
-rw-r--r--vnet/vnet/lisp-cp/control.h10
-rw-r--r--vnet/vnet/lisp-gpe/decap.c65
-rw-r--r--vnet/vnet/lisp-gpe/encap.c232
-rw-r--r--vnet/vnet/lisp-gpe/interface.c516
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe.c425
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe.h36
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe_error.def1
-rw-r--r--vpp-api-test/vat/api_format.c57
-rw-r--r--vpp/api/api.c23
-rw-r--r--vpp/api/vpe.api22
12 files changed, 950 insertions, 539 deletions
diff --git a/vnet/Makefile.am b/vnet/Makefile.am
index 2ce40f3e..f7c1f30b 100644
--- a/vnet/Makefile.am
+++ b/vnet/Makefile.am
@@ -477,7 +477,7 @@ endif
libvnet_la_SOURCES += \
vnet/lisp-gpe/lisp_gpe.c \
- vnet/lisp-gpe/encap.c \
+ vnet/lisp-gpe/interface.c \
vnet/lisp-gpe/decap.c
nobase_include_HEADERS += \
diff --git a/vnet/vnet/lisp-cp/control.c b/vnet/vnet/lisp-cp/control.c
index 3448fb3e..f067cf6d 100644
--- a/vnet/vnet/lisp-cp/control.c
+++ b/vnet/vnet/lisp-cp/control.c
@@ -18,7 +18,8 @@
#include <vnet/lisp-cp/lisp_msg_serdes.h>
#include <vnet/lisp-gpe/lisp_gpe.h>
-/* Adds mapping to map-cache but does NOT program LISP forwarding */
+/* Stores mapping in map-cache. It does NOT program data plane forwarding for
+ * remote/learned mappings. */
int
vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
u32 * map_index_result)
@@ -32,11 +33,12 @@ vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
if (a->is_add)
{
/* TODO check if overwriting and take appropriate actions */
- if (mi != GID_LOOKUP_MISS) {
+ if (mi != GID_LOOKUP_MISS)
+ {
clib_warning("eid %U found in the eid-table", format_ip_address,
&a->deid);
return VNET_API_ERROR_VALUE_EXIST;
- }
+ }
pool_get(lcm->mapping_pool, m);
m->eid = a->deid;
@@ -65,18 +67,17 @@ vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
{
/* mark as local */
vec_add1(lcm->local_mappings_indexes, map_index);
-
- /* XXX do something else? */
}
map_index_result[0] = map_index;
}
else
{
- if (mi == GID_LOOKUP_MISS) {
+ if (mi == GID_LOOKUP_MISS)
+ {
clib_warning("eid %U not found in the eid-table", format_ip_address,
&a->deid);
return VNET_API_ERROR_INVALID_VALUE;
- }
+ }
/* clear locator-set to eids binding */
eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids,
@@ -115,6 +116,66 @@ vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
return 0;
}
+/* Stores mapping in map-cache and programs data plane for local mappings. */
+int
+vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
+ u32 * map_index_result)
+{
+ uword * table_id, * refc;
+ u32 rv;
+ vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
+ lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+
+ /* store/remove mapping from map-cache */
+ rv = vnet_lisp_add_del_mapping (a, map_index_result);
+ if (rv)
+ return rv;
+
+ table_id = hash_get(lcm->table_id_by_vni, /* default for now */ 0);
+
+ if (!table_id)
+ {
+ clib_warning ("vni %d not associated to a vrf!", 0);
+ return VNET_API_ERROR_INVALID_VALUE;
+ }
+
+ refc = hash_get(lcm->dp_if_refcount_by_vni, 0);
+
+ /* enable/disable data-plane interface */
+ if (a->is_add)
+ {
+ /* create interface or update refcount */
+ if (!refc)
+ {
+ ai->is_add = 1;
+ ai->vni = 0; /* default for now, pass vni as parameter */
+ ai->table_id = table_id[0];
+ vnet_lisp_gpe_add_del_iface (ai, 0);
+ }
+ else
+ {
+ refc[0]++;
+ }
+ }
+ else
+ {
+ /* since this is a remove for an existing eid, the iface should exist */
+ ASSERT(refc != 0);
+ refc[0]--;
+
+ /* remove iface if needed */
+ if (refc[0] == 0)
+ {
+ ai->is_add = 0;
+ ai->vni = 0; /* default for now, pass vni as parameter */
+ ai->table_id = table_id[0];
+ vnet_lisp_gpe_add_del_iface (ai, 0);
+ }
+ }
+
+ return rv;
+}
+
static clib_error_t *
lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
@@ -171,7 +232,7 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
a->locator_set_index = locator_set_index;
a->local = 1;
- vnet_lisp_add_del_mapping (a, &map_index);
+ vnet_lisp_add_del_local_mapping (a, &map_index);
done:
vec_free(eids);
return error;
@@ -650,7 +711,8 @@ lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = {
.path = "lisp locator-set",
- .short_help = "lisp locator-set add/del <name> <iface-name> <priority> <weight>",
+ .short_help = "lisp locator-set add/del <name> iface <iface-name> "
+ "<priority> <weight>",
.function = lisp_add_del_locator_set_command_fn,
};
@@ -1251,7 +1313,7 @@ del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index,
a->is_add = 0;
a->dlocator = fe->dst_loc;
a->slocator = fe->src_loc;
- a->iid = 0; // XXX should be part of mapping/eid
+ a->vni = 0; // XXX should be part of mapping/eid
gid_address_copy(&a->deid, &fe->deid);
vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
@@ -1268,8 +1330,9 @@ add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
locator_set_t * dst_ls, * src_ls;
u32 i, minp = ~0;
locator_t * dl = 0;
- uword * feip = 0;
+ uword * feip = 0, * tidp;
vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
+
memset (a, 0, sizeof(*a));
/* remove entry if it already exists */
@@ -1334,10 +1397,20 @@ add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
}
gid_address_copy (&a->deid, &dst_map->eid);
- a->iid = 0; // XXX should be part of mapping/eid
+ a->vni = 0; // XXX should be part of mapping/eid
+
+ tidp = hash_get(lcm->table_id_by_vni, a->vni);
+ if (!tidp)
+ {
+ clib_warning("vni %d not associated to a vrf!", a->vni);
+ return;
+ }
+ a->table_id = tidp[0];
+
u8 ipver = ip_prefix_version(&gid_address_ippref(&a->deid));
a->decap_next_index = (ipver == IP4) ?
LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
+
/* XXX tunnels work only with IP4 now */
vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
@@ -1611,6 +1684,9 @@ lisp_cp_init (vlib_main_t *vm)
gid_dictionary_init (&lcm->mapping_index_by_gid);
gid_dictionary_init (&lcm->mapping_index_by_gid);
+ /* default vrf mapped to vni 0 */
+ hash_set(lcm->table_id_by_vni, 0, 0);
+
udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
lisp_cp_input_node.index, 1 /* is_ip4 */);
udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
diff --git a/vnet/vnet/lisp-cp/control.h b/vnet/vnet/lisp-cp/control.h
index 53d90fca..f87a6d5e 100644
--- a/vnet/vnet/lisp-cp/control.h
+++ b/vnet/vnet/lisp-cp/control.h
@@ -91,6 +91,12 @@ typedef struct
/* vector of map-resolver addresses */
ip_address_t * map_resolvers;
+ /* Lookup vrf by vni */
+ uword * table_id_by_vni;
+
+ /* Number of src prefixes in a vni that use an interface */
+ uword * dp_if_refcount_by_vni;
+
/* commodity */
ip4_main_t * im4;
ip6_main_t * im6;
@@ -122,7 +128,6 @@ typedef struct
int
vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
u32 * ls_index);
-
int
vnet_lisp_add_del_locator_set_name (vnet_lisp_add_del_locator_set_args_t * a,
u32 * ls_index);
@@ -146,6 +151,9 @@ typedef struct
int
vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t *a,
u32 * map_index);
+int
+vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
+ u32 * map_index_result);
typedef struct
{
diff --git a/vnet/vnet/lisp-gpe/decap.c b/vnet/vnet/lisp-gpe/decap.c
index 356dbf2e..5d88462b 100644
--- a/vnet/vnet/lisp-gpe/decap.c
+++ b/vnet/vnet/lisp-gpe/decap.c
@@ -52,7 +52,6 @@ next_proto_to_next_index[LISP_GPE_NEXT_PROTOS] ={
LISP_GPE_INPUT_NEXT_DROP,
LISP_GPE_INPUT_NEXT_IP4_INPUT,
LISP_GPE_INPUT_NEXT_IP6_INPUT,
- LISP_GPE_INPUT_NEXT_DROP,
LISP_GPE_INPUT_NEXT_DROP
};
@@ -85,6 +84,7 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
u32 n_left_from, next_index, * from, * to_next;
lisp_gpe_tunnel_key_t last_key;
u32 pkts_decapsulated = 0;
+ lisp_gpe_main_t * lgm = &lisp_gpe_main;
memset (&last_key, 0xff, sizeof (last_key));
@@ -104,8 +104,8 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
u32 bi0, bi1;
vlib_buffer_t * b0, * b1;
ip4_udp_lisp_gpe_header_t * iul0, * iul1;
- u32 error0, error1;
- u32 next0, next1;
+ u32 next0, next1, error0, error1;
+ uword * si0, * si1;
next0 = next1 = LISP_GPE_INPUT_NEXT_IP4_INPUT;
@@ -156,14 +156,35 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
vnet_update_l2_len (b0);
vnet_update_l2_len (b1);
- /* TODO hash to map iid to fib */
- vnet_buffer(b0)->sw_if_index[VLIB_TX] = iul0->lisp.iid;
- vnet_buffer(b1)->sw_if_index[VLIB_TX] = iul1->lisp.iid;
+ /* map iid/vni to lisp-gpe sw_if_index which is used by ipx_input to
+ * decide the rx vrf and the input features to be applied */
+ si0 = hash_get(lgm->tunnel_term_sw_if_index_by_vni, iul0->lisp.iid);
+ si1 = hash_get(lgm->tunnel_term_sw_if_index_by_vni, iul1->lisp.iid);
- pkts_decapsulated += 2;
+ if (si0)
+ {
+ vnet_buffer(b0)->sw_if_index[VLIB_RX] = si0[0];
+ pkts_decapsulated++;
+ error0 = 0;
+ }
+ else
+ {
+ next0 = LISP_GPE_INPUT_NEXT_DROP;
+ error0 = LISP_GPE_ERROR_NO_SUCH_TUNNEL;
+ }
+
+ if (si1)
+ {
+ vnet_buffer(b1)->sw_if_index[VLIB_RX] = si1[0];
+ pkts_decapsulated++;
+ error0 = 0;
+ }
+ else
+ {
+ next1 = LISP_GPE_INPUT_NEXT_DROP;
+ error1 = LISP_GPE_ERROR_NO_SUCH_TUNNEL;
+ }
- /* TODO error handling if security is implemented */
- error0 = error1 = 0;
b0->error = error0 ? node->errors[error0] : 0;
b1->error = error1 ? node->errors[error1] : 0;
@@ -197,6 +218,7 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
u32 next0;
ip4_udp_lisp_gpe_header_t * iul0;
u32 error0;
+ uword * si0;
bi0 = from[0];
to_next[0] = bi0;
@@ -228,18 +250,29 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
/* Required to make the l2 tag push / pop code work on l2 subifs */
vnet_update_l2_len (b0);
- /* TODO hash to map iid to fib */
- vnet_buffer(b0)->sw_if_index[VLIB_TX] = iul0->lisp.iid;
- pkts_decapsulated ++;
+ /* map iid/vni to lisp-gpe sw_if_index which is used by ipx_input to
+ * decide the rx vrf and the input features to be applied */
+ si0 = hash_get(lgm->tunnel_term_sw_if_index_by_vni, iul0->lisp.iid);
+
+ if (si0)
+ {
+ vnet_buffer(b0)->sw_if_index[VLIB_RX] = si0[0];
+ pkts_decapsulated++;
+ error0 = 0;
+ }
+ else
+ {
+ next0 = LISP_GPE_INPUT_NEXT_DROP;
+ error0 = LISP_GPE_ERROR_NO_SUCH_TUNNEL;
+ }
/* TODO error handling if security is implemented */
- error0 = 0;
b0->error = error0 ? node->errors[error0] : 0;
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
- lisp_gpe_rx_trace_t *tr
- = vlib_add_trace (vm, node, b0, sizeof (*tr));
+ lisp_gpe_rx_trace_t *tr = vlib_add_trace (vm, node, b0,
+ sizeof(*tr));
tr->next_index = next0;
tr->error = error0;
tr->h = iul0->lisp;
diff --git a/vnet/vnet/lisp-gpe/encap.c b/vnet/vnet/lisp-gpe/encap.c
deleted file mode 100644
index a8158782..00000000
--- a/vnet/vnet/lisp-gpe/encap.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vppinfra/error.h>
-#include <vppinfra/hash.h>
-#include <vnet/vnet.h>
-#include <vnet/ip/ip.h>
-#include <vnet/ip/udp.h>
-#include <vnet/ethernet/ethernet.h>
-#include <vnet/lisp-gpe/lisp_gpe.h>
-
-/* Statistics (not really errors) */
-#define foreach_lisp_gpe_encap_error \
-_(ENCAPSULATED, "good packets encapsulated")
-
-static char * lisp_gpe_encap_error_strings[] = {
-#define _(sym,string) string,
- foreach_lisp_gpe_encap_error
-#undef _
-};
-
-typedef enum {
-#define _(sym,str) LISP_GPE_ENCAP_ERROR_##sym,
- foreach_lisp_gpe_encap_error
-#undef _
- LISP_GPE_ENCAP_N_ERROR,
-} lisp_gpe_encap_error_t;
-
-typedef enum
-{
- LISP_GPE_ENCAP_NEXT_DROP,
- LISP_GPE_ENCAP_NEXT_IP4_LOOKUP,
- LISP_GPE_ENCAP_N_NEXT,
-} lisp_gpe_encap_next_t;
-
-typedef struct
-{
- u32 tunnel_index;
-} lisp_gpe_encap_trace_t;
-
-u8 *
-format_lisp_gpe_encap_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 *);
- lisp_gpe_encap_trace_t * t = va_arg (*args, lisp_gpe_encap_trace_t *);
-
- s = format (s, "LISP-GPE-ENCAP: tunnel %d", t->tunnel_index);
- return s;
-}
-
-static uword
-lisp_gpe_encap (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;
- u32 pkts_encapsulated = 0;
-
- from = vlib_frame_vector_args (from_frame);
- n_left_from = from_frame->n_vectors;
-
- next_index = node->cached_next_index;
-
- while (n_left_from > 0)
- {
- u32 n_left_to_next;
-
- vlib_get_next_frame (vm, node, next_index,
- to_next, n_left_to_next);
-
- while (n_left_from >= 4 && n_left_to_next >= 2)
- {
- u32 bi0, bi1;
- vlib_buffer_t * b0, * b1;
- u32 next0, next1;
- u32 adj_index0, adj_index1, tunnel_index0, tunnel_index1;
- ip_adjacency_t * adj0, * adj1;
- lisp_gpe_tunnel_t * t0, * t1;
-
- next0 = next1 = LISP_GPE_ENCAP_NEXT_IP4_LOOKUP;
-
- /* Prefetch next iteration. */
- {
- vlib_buffer_t * p2, *p3;
-
- p2 = vlib_get_buffer (vm, from[2]);
- p3 = vlib_get_buffer (vm, from[3]);
-
- vlib_prefetch_buffer_header(p2, LOAD);
- vlib_prefetch_buffer_header(p3, LOAD);
-
- CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
- CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
- }
-
- bi0 = from[0];
- bi1 = from[1];
- to_next[0] = bi0;
- to_next[1] = bi1;
- from += 2;
- to_next += 2;
- n_left_to_next -= 2;
- n_left_from -= 2;
-
- b0 = vlib_get_buffer (vm, bi0);
- b1 = vlib_get_buffer (vm, bi1);
-
- /* Get adjacency and from it the tunnel_index */
- adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
- adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
-
- adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
- adj1 = ip_get_adjacency (lgm->lookup_main, adj_index1);
-
- tunnel_index0 = adj0->rewrite_header.sw_if_index;
- tunnel_index1 = adj1->rewrite_header.sw_if_index;
-
- t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
- t1 = pool_elt_at_index (lgm->tunnels, tunnel_index1);
-
- ASSERT(t0 != 0);
- ASSERT(t1 != 0);
-
- ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
- ip4_udp_encap_two (vm, b0, b1, t0->rewrite, t1->rewrite, 36);
-
- /* Reset to look up tunnel partner in the configured FIB */
- vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
- vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->encap_fib_index;
-
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- lisp_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b0,
- sizeof(*tr));
- tr->tunnel_index = t0 - lgm->tunnels;
- }
- if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
- {
- lisp_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b1,
- sizeof(*tr));
- tr->tunnel_index = t1 - lgm->tunnels;
- }
-
- pkts_encapsulated += 2;
-
- vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
- n_left_to_next, bi0, bi1, next0,
- next1);
- }
-
- while (n_left_from > 0 && n_left_to_next > 0)
- {
- vlib_buffer_t * b0;
- u32 bi0, adj_index0, tunnel_index0;
- u32 next0 = LISP_GPE_ENCAP_NEXT_IP4_LOOKUP;
- lisp_gpe_tunnel_t * t0 = 0;
- ip_adjacency_t * adj0;
-
- 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);
-
- /* Get adjacency and from it the tunnel_index */
- adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
- adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
-
- tunnel_index0 = adj0->rewrite_header.sw_if_index;
- t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
-
- ASSERT(t0 != 0);
-
- ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
- ip4_udp_encap_one (vm, b0, t0->rewrite, 36);
-
- /* Reset to look up tunnel partner in the configured FIB */
- vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
-
- pkts_encapsulated++;
-
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- lisp_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b0,
- sizeof(*tr));
- tr->tunnel_index = t0 - lgm->tunnels;
- }
- 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, node->node_index,
- LISP_GPE_ENCAP_ERROR_ENCAPSULATED,
- pkts_encapsulated);
- return from_frame->n_vectors;
-}
-
-VLIB_REGISTER_NODE (lisp_gpe_encap_node) = {
- .function = lisp_gpe_encap,
- .name = "lisp-gpe-encap",
- .vector_size = sizeof (u32),
- .format_trace = format_lisp_gpe_encap_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
-
- .n_errors = ARRAY_LEN(lisp_gpe_encap_error_strings),
- .error_strings = lisp_gpe_encap_error_strings,
-
- .n_next_nodes = LISP_GPE_ENCAP_N_NEXT,
-
- .next_nodes = {
- [LISP_GPE_ENCAP_NEXT_DROP] = "error-drop",
- [LISP_GPE_ENCAP_NEXT_IP4_LOOKUP] = "ip4-lookup",
- },
-};
diff --git a/vnet/vnet/lisp-gpe/interface.c b/vnet/vnet/lisp-gpe/interface.c
new file mode 100644
index 00000000..0f7f6fca
--- /dev/null
+++ b/vnet/vnet/lisp-gpe/interface.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vppinfra/error.h>
+#include <vppinfra/hash.h>
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ip/udp.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/lisp-gpe/lisp_gpe.h>
+
+#define foreach_lisp_gpe_tx_next \
+ _(DROP, "error-drop") \
+ _(IP4_LOOKUP, "ip4-lookup")
+
+typedef enum
+{
+#define _(sym,str) LISP_GPE_TX_NEXT_##sym,
+ foreach_lisp_gpe_tx_next
+#undef _
+ LISP_GPE_TX_N_NEXT,
+} lisp_gpe_tx_next_t;
+
+typedef struct
+{
+ u32 tunnel_index;
+} lisp_gpe_tx_trace_t;
+
+u8 *
+format_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 *);
+ lisp_gpe_tx_trace_t * t = va_arg (*args, lisp_gpe_tx_trace_t *);
+
+ s = format (s, "LISP-GPE-TX: tunnel %d", t->tunnel_index);
+ return s;
+}
+
+static uword
+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;
+ u32 pkts_encapsulated = 0;
+
+ from = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index,
+ to_next, n_left_to_next);
+
+ while (n_left_from >= 4 && n_left_to_next >= 2)
+ {
+ u32 bi0, bi1;
+ vlib_buffer_t * b0, * b1;
+ u32 next0, next1;
+ u32 adj_index0, adj_index1, tunnel_index0, tunnel_index1;
+ ip_adjacency_t * adj0, * adj1;
+ lisp_gpe_tunnel_t * t0, * t1;
+
+ next0 = next1 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
+
+ /* Prefetch next iteration. */
+ {
+ vlib_buffer_t * p2, *p3;
+
+ p2 = vlib_get_buffer (vm, from[2]);
+ p3 = vlib_get_buffer (vm, from[3]);
+
+ vlib_prefetch_buffer_header(p2, LOAD);
+ vlib_prefetch_buffer_header(p3, LOAD);
+
+ CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
+ CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+
+ bi0 = from[0];
+ bi1 = from[1];
+ to_next[0] = bi0;
+ to_next[1] = bi1;
+ from += 2;
+ to_next += 2;
+ n_left_to_next -= 2;
+ n_left_from -= 2;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ b1 = vlib_get_buffer (vm, bi1);
+
+ /* Get adjacency and from it the tunnel_index */
+ adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+ adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
+
+ adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
+ adj1 = ip_get_adjacency (lgm->lookup_main, adj_index1);
+
+ tunnel_index0 = adj0->rewrite_header.node_index;
+ tunnel_index1 = adj1->rewrite_header.node_index;
+
+ t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
+ t1 = pool_elt_at_index (lgm->tunnels, tunnel_index1);
+
+ ASSERT(t0 != 0);
+ ASSERT(t1 != 0);
+
+ ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
+ ip4_udp_encap_two (vm, b0, b1, t0->rewrite, t1->rewrite, 36);
+
+ /* Reset to look up tunnel partner in the configured FIB */
+ vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
+ vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->encap_fib_index;
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
+ sizeof(*tr));
+ tr->tunnel_index = t0 - lgm->tunnels;
+ }
+ if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b1,
+ sizeof(*tr));
+ tr->tunnel_index = t1 - lgm->tunnels;
+ }
+
+ pkts_encapsulated += 2;
+
+ vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
+ n_left_to_next, bi0, bi1, next0,
+ next1);
+ }
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ vlib_buffer_t * b0;
+ u32 bi0, adj_index0, tunnel_index0;
+ u32 next0 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
+ lisp_gpe_tunnel_t * t0 = 0;
+ ip_adjacency_t * adj0;
+
+ 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);
+
+ /* Get adjacency and from it the tunnel_index */
+ adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+ adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
+
+ tunnel_index0 = adj0->rewrite_header.node_index;
+ t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
+
+ ASSERT(t0 != 0);
+
+ ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
+ ip4_udp_encap_one (vm, b0, t0->rewrite, 36);
+
+ /* Reset to look up tunnel partner in the configured FIB */
+ vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
+
+ pkts_encapsulated++;
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
+ sizeof(*tr));
+ tr->tunnel_index = t0 - lgm->tunnels;
+ }
+ 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, node->node_index,
+ LISP_GPE_ERROR_ENCAPSULATED, pkts_encapsulated);
+ return from_frame->n_vectors;
+}
+
+static u8 *
+format_lisp_gpe_name (u8 * s, va_list * args)
+{
+ u32 dev_instance = va_arg (*args, u32);
+ return format (s, "lisp_gpe%d", dev_instance);
+}
+
+VNET_DEVICE_CLASS (lisp_gpe_device_class,static) = {
+ .name = "LISP_GPE",
+ .format_device_name = format_lisp_gpe_name,
+ .format_tx_trace = format_lisp_gpe_tx_trace,
+ .tx_function = lisp_gpe_interface_tx,
+ .no_flatten_output_chains = 1,
+};
+
+static uword
+dummy_set_rewrite (vnet_main_t * vnm, u32 sw_if_index, u32 l3_type,
+ void * dst_address, void * rewrite, uword max_rewrite_bytes)
+{
+ return 0;
+}
+
+u8 *
+format_lisp_gpe_header_with_length (u8 * s, va_list * args)
+{
+ lisp_gpe_header_t * h = va_arg (*args, lisp_gpe_header_t *);
+ u32 max_header_bytes = va_arg (*args, u32);
+ u32 header_bytes;
+
+ header_bytes = sizeof (h[0]);
+ if (max_header_bytes != 0 && header_bytes > max_header_bytes)
+ return format (s, "lisp-gpe header truncated");
+
+ s = format (s, "flags: ");
+#define _(n,v) if (h->flags & v) s = format (s, "%s ", #n);
+ foreach_lisp_gpe_flag_bit;
+#undef _
+
+ s = format (s, "\n ver_res %d res %d next_protocol %d iid %d(%x)",
+ h->ver_res, h->res, h->next_protocol,
+ clib_net_to_host_u32 (h->iid),
+ clib_net_to_host_u32 (h->iid));
+ return s;
+}
+
+VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
+ .name = "LISP_GPE",
+ .format_header = format_lisp_gpe_header_with_length,
+ .set_rewrite = dummy_set_rewrite,
+};
+
+int
+add_del_ip_prefix_route (ip_prefix_t * dst_prefix, u32 table_id,
+ ip_adjacency_t * add_adj, u8 is_add, u32 * adj_index)
+{
+ uword * p;
+
+ if (ip_prefix_version(dst_prefix) == IP4)
+ {
+ ip4_main_t * im4 = &ip4_main;
+ ip4_add_del_route_args_t a;
+ ip4_address_t addr = ip_prefix_v4(dst_prefix);
+
+ memset(&a, 0, sizeof(a));
+ a.flags = IP4_ROUTE_FLAG_TABLE_ID;
+ a.table_index_or_table_id = table_id;
+ a.adj_index = ~0;
+ a.dst_address_length = ip_prefix_len(dst_prefix);
+ a.dst_address = addr;
+ a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL;
+ a.add_adj = add_adj;
+ a.n_add_adj = 1;
+ ip4_add_del_route (im4, &a);
+
+ if (is_add)
+ {
+ p = ip4_get_route (im4, table_id, 0, addr.as_u8,
+ ip_prefix_len(dst_prefix));
+ if (p == 0)
+ {
+ clib_warning("Failed to insert route for eid %U!",
+ format_ip4_address_and_length, addr.as_u8,
+ ip_prefix_len(dst_prefix));
+ return -1;
+ }
+ adj_index[0] = p[0];
+ }
+ }
+ else
+ {
+ ip6_main_t * im6 = &ip6_main;
+ ip6_add_del_route_args_t a;
+ ip6_address_t addr = ip_prefix_v6(dst_prefix);
+
+ memset(&a, 0, sizeof(a));
+ a.flags = IP6_ROUTE_FLAG_TABLE_ID;
+ a.table_index_or_table_id = table_id;
+ a.adj_index = ~0;
+ a.dst_address_length = ip_prefix_len(dst_prefix);
+ a.dst_address = addr;
+ a.flags |= is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL;
+ a.add_adj = add_adj;
+ a.n_add_adj = 1;
+
+ ip6_add_del_route (im6, &a);
+
+ if (is_add)
+ {
+ adj_index[0] = ip6_get_route (im6, table_id, 0, &addr,
+ ip_prefix_len(dst_prefix));
+ if (adj_index[0] == 0)
+ {
+ clib_warning("Failed to insert route for eid %U!",
+ format_ip6_address_and_length, addr.as_u8,
+ ip_prefix_len(dst_prefix));
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static void
+add_del_lisp_gpe_default_route (u32 table_id, u8 is_v4, u8 is_add)
+{
+ lisp_gpe_main_t * lgm = &lisp_gpe_main;
+ ip_adjacency_t adj;
+ ip_prefix_t prefix;
+ u32 adj_index = 0;
+
+ /* setup adjacency */
+ memset (&adj, 0, sizeof(adj));
+
+ adj.n_adj = 1;
+ adj.explicit_fib_index = ~0;
+ adj.lookup_next_index = lgm->ip4_lookup_next_lgpe_ip4_lookup;
+ /* default route has tunnel_index ~0 */
+ adj.rewrite_header.sw_if_index = ~0;
+
+ /* set prefix to 0/0 */
+ memset(&prefix, 0, sizeof(prefix));
+ ip_prefix_version(&prefix) = is_v4 ? IP4 : IP6;
+
+ /* add/delete route for prefix */
+ add_del_ip_prefix_route (&prefix, table_id, &adj, is_add, &adj_index);
+}
+
+static void
+lisp_gpe_iface_set_table (u32 sw_if_index, u32 table_id, u8 is_ip4)
+{
+ if (is_ip4)
+ {
+ ip4_main_t * im4 = &ip4_main;
+ ip4_fib_t * fib;
+ fib = find_ip4_fib_by_table_index_or_id (im4, table_id,
+ IP4_ROUTE_FLAG_TABLE_ID);
+
+ /* fib's created if it doesn't exist */
+ ASSERT(fib != 0);
+
+ vec_validate(im4->fib_index_by_sw_if_index, sw_if_index);
+ im4->fib_index_by_sw_if_index[sw_if_index] = fib->index;
+ }
+ else
+ {
+ ip6_main_t * im6 = &ip6_main;
+ ip6_fib_t * fib;
+ fib = find_ip6_fib_by_table_index_or_id (im6, table_id,
+ IP6_ROUTE_FLAG_TABLE_ID);
+
+ /* fib's created if it doesn't exist */
+ ASSERT(fib != 0);
+
+ vec_validate(im6->fib_index_by_sw_if_index, sw_if_index);
+ im6->fib_index_by_sw_if_index[sw_if_index] = fib->index;
+ }
+}
+
+void
+vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
+ u32 * hw_if_indexp)
+{
+ lisp_gpe_main_t * lgm = &lisp_gpe_main;
+ vnet_main_t * vnm = lgm->vnet_main;
+ vnet_hw_interface_t * hi;
+ u32 hw_if_index = ~0, lookup_next_index, flen;
+ uword * hip, * vni;
+
+ hip = hash_get(lgm->lisp_gpe_hw_if_index_by_table_id, a->table_id);
+
+ if (a->is_add)
+ {
+ if (hip)
+ {
+ clib_warning ("Interface for vrf %d already exists", a->table_id);
+ return;
+ }
+
+ /* create hw lisp_gpeX iface if needed, otherwise reuse existing */
+ flen = vec_len(lgm->free_lisp_gpe_tunnel_hw_if_indices);
+ if (flen > 0)
+ {
+ hw_if_index = lgm->free_lisp_gpe_tunnel_hw_if_indices[flen - 1];
+ _vec_len(lgm->free_lisp_gpe_tunnel_hw_if_indices) -= 1;
+ }
+ else
+ {
+ hw_if_index = vnet_register_interface (vnm,
+ lisp_gpe_device_class.index,
+ a->table_id,
+ lisp_gpe_hw_class.index, 0);
+ }
+
+ hi = vnet_get_hw_interface (vnm, hw_if_index);
+ hash_set(lgm->lisp_gpe_hw_if_index_by_table_id, a->table_id, hw_if_index);
+
+ /* set tunnel termination: post decap, packets are tagged as having been
+ * originated by lisp-gpe interface */
+ hash_set(lgm->tunnel_term_sw_if_index_by_vni, a->vni, hi->sw_if_index);
+ hash_set(lgm->vni_by_tunnel_term_sw_if_index, hi->sw_if_index, a->vni);
+
+ /* set ingress arc from lgpe_ip4_lookup */
+ lookup_next_index = vlib_node_add_next (lgm->vlib_main,
+ lgpe_ip4_lookup_node.index,
+ hi->output_node_index);
+ hash_set(lgm->lgpe_ip4_lookup_next_index_by_table_id, a->table_id,
+ lookup_next_index);
+
+ /* insert default routes that point to lgpe-ipx-lookup */
+ add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */1, 1);
+ add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */0, 1);
+
+ /* set egress arcs */
+#define _(sym,str) vlib_node_add_named_next_with_slot (vnm->vlib_main, \
+ hi->tx_node_index, str, LISP_GPE_TX_NEXT_##sym);
+ foreach_lisp_gpe_tx_next
+#undef _
+
+ /* set interface in appropriate v4 and v6 FIBs */
+ lisp_gpe_iface_set_table (hi->sw_if_index, a->table_id, 1);
+ lisp_gpe_iface_set_table (hi->sw_if_index, a->table_id, 0);
+
+ /* 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);
+ }
+ else
+ {
+ if (hip == 0)
+ {
+ clib_warning("The interface for vrf %d doesn't exist", a->table_id);
+ return;
+ }
+ hi = vnet_get_hw_interface (vnm, hip[0]);
+
+ /* disable interface */
+ vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0/* down */);
+ vnet_hw_interface_set_flags (vnm, hi->hw_if_index, 0/* down */);
+ hash_unset(lgm->lisp_gpe_hw_if_index_by_table_id, a->table_id);
+ vec_add1(lgm->free_lisp_gpe_tunnel_hw_if_indices, hi->hw_if_index);
+
+ /* clean tunnel termination and vni to sw_if_index binding */
+ vni = hash_get(lgm->vni_by_tunnel_term_sw_if_index, hi->sw_if_index);
+ hash_unset(lgm->tunnel_term_sw_if_index_by_vni, vni[0]);
+ hash_unset(lgm->vni_by_tunnel_term_sw_if_index, hi->sw_if_index);
+
+ /* unset default routes */
+ add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */1, 0);
+ add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */0, 0);
+ }
+}
+
+static clib_error_t *
+lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, * line_input = &_line_input;
+ u8 is_add = 1;
+ u32 table_id;
+
+ vnet_lisp_gpe_add_del_iface_args_t _a, * a = &_a;
+
+ /* Get a line of input. */
+ if (! unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "add"))
+ is_add = 1;
+ else if (unformat (line_input, "del"))
+ is_add = 0;
+ else if (unformat (line_input, "vrf %d", &table_id))
+ ;
+ else
+ {
+ return clib_error_return (0, "parse error: '%U'",
+ format_unformat_error, line_input);
+ }
+ }
+
+ a->is_add = is_add;
+ a->table_id = table_id;
+ vnet_lisp_gpe_add_del_iface (a, 0);
+ return 0;
+}
+
+VLIB_CLI_COMMAND (add_del_lisp_gpe_iface_command, static) = {
+ .path = "lisp gpe iface",
+ .short_help = "lisp gpe iface add/del table-index <table_index> vrf <vrf>",
+ .function = lisp_gpe_add_del_iface_command_fn,
+};
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe.c b/vnet/vnet/lisp-gpe/lisp_gpe.c
index b8072494..fd1e1a46 100644
--- a/vnet/vnet/lisp-gpe/lisp_gpe.c
+++ b/vnet/vnet/lisp-gpe/lisp_gpe.c
@@ -177,7 +177,7 @@ ip4_sd_fib_clear_src_fib (lisp_gpe_main_t * lgm, ip4_fib_t * fib)
int
ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_index,
+ ip_prefix_t * src_prefix, u32 table_id,
ip_adjacency_t * add_adj, u8 is_add)
{
uword * p;
@@ -196,7 +196,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
memset(&src, 0, sizeof(src));
/* lookup dst adj */
- p = ip4_get_route (lgm->im4, table_index, 0, dst.as_u8, dst_address_length);
+ p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8, dst_address_length);
if (is_add)
{
@@ -209,7 +209,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
memset(&a, 0, sizeof(a));
a.flags = IP4_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = table_index; /* vrf */
+ a.table_index_or_table_id = table_id; /* vrf */
a.adj_index = ~0;
a.dst_address_length = dst_address_length;
a.dst_address = dst;
@@ -220,7 +220,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
ip4_add_del_route (lgm->im4, &a);
/* lookup dst adj to obtain the adj index */
- p = ip4_get_route (lgm->im4, table_index, 0, dst.as_u8,
+ p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8,
dst_address_length);
if (p == 0)
{
@@ -283,7 +283,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
/* .. and remove dst route */
memset(&a, 0, sizeof(a));
a.flags = IP4_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = table_index; /* vrf */
+ a.table_index_or_table_id = table_id; /* vrf */
a.adj_index = ~0;
a.dst_address_length = dst_address_length;
a.dst_address = dst;
@@ -297,7 +297,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
static void *
ip4_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_index)
+ ip_prefix_t * src_prefix, u32 table_id)
{
uword * p;
ip4_address_t dst = ip_prefix_v4(dst_prefix), src;
@@ -313,7 +313,7 @@ ip4_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
memset(&src, 0, sizeof(src));
/* lookup dst adj */
- p = ip4_get_route (lgm->im4, table_index, 0, dst.as_u8, dst_address_length);
+ p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8, dst_address_length);
if (p == 0)
return p;
@@ -326,7 +326,6 @@ typedef enum
{
LGPE_IP4_LOOKUP_NEXT_DROP,
LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP,
- LGPE_IP4_LOOKUP_NEXT_LGPE_ENCAP,
LGPE_IP4_LOOKUP_N_NEXT,
} lgpe_ip4_lookup_next_t;
@@ -468,6 +467,12 @@ lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
next0 = src_adj0->lookup_next_index;
next1 = src_adj1->lookup_next_index;
+
+ /* prepare buffer for lisp-gpe output node */
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ src_adj0->rewrite_header.sw_if_index;
+ vnet_buffer (b1)->sw_if_index[VLIB_TX] =
+ src_adj1->rewrite_header.sw_if_index;
}
else
{
@@ -479,6 +484,7 @@ lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
src_adj0 = ip_get_adjacency (lgm->lookup_main,
src_adj_index0);
next0 = src_adj0->lookup_next_index;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = src_adj_index0;
}
if (src_fib_index1 != (u32) ~0)
{
@@ -488,6 +494,7 @@ lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
src_adj1 = ip_get_adjacency (lgm->lookup_main,
src_adj_index1);
next1 = src_adj1->lookup_next_index;
+ vnet_buffer (b1)->sw_if_index[VLIB_TX] = src_adj_index1;
}
}
@@ -530,6 +537,9 @@ lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
src_adj0 = ip_get_adjacency (lgm->lookup_main, src_adj_index0);
next0 = src_adj0->lookup_next_index;
+ /* prepare packet for lisp-gpe output node */
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+ src_adj0->rewrite_header.sw_if_index;
done:
vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
n_left_to_next, bi0, next0);
@@ -551,7 +561,6 @@ VLIB_REGISTER_NODE (lgpe_ip4_lookup_node) = {
.next_nodes = {
[LGPE_IP4_LOOKUP_NEXT_DROP] = "error-drop",
[LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP] = "lisp-cp-lookup",
- [LGPE_IP4_LOOKUP_NEXT_LGPE_ENCAP] = "lisp-gpe-encap",
},
};
@@ -592,7 +601,7 @@ lisp_gpe_rewrite (lisp_gpe_tunnel_t * t)
lisp0->ver_res = t->ver_res;
lisp0->res = t->res;
lisp0->next_protocol = t->next_protocol;
- lisp0->iid = clib_host_to_net_u32 (t->iid);
+ lisp0->iid = clib_host_to_net_u32 (t->vni);
t->rewrite = rw;
return 0;
@@ -615,7 +624,7 @@ _(flags) \
_(next_protocol) \
_(ver_res) \
_(res) \
-_(iid)
+_(vni)
static u32
add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res)
@@ -629,7 +638,7 @@ add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res)
memset(&key, 0, sizeof(key));
gid_address_copy(&key.eid, &a->deid);
key.dst_loc = ip_addr_v4(&a->dlocator).as_u32;
- key.iid = clib_host_to_net_u32 (a->iid);
+ key.iid = clib_host_to_net_u32 (a->vni);
p = mhash_get (&lgm->lisp_gpe_tunnel_by_key, &key);
@@ -688,6 +697,41 @@ add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res)
return 0;
}
+static int
+add_del_negative_fwd_entry (lisp_gpe_main_t * lgm,
+ vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
+{
+ ip_adjacency_t adj;
+ /* setup adjacency for eid */
+ memset (&adj, 0, sizeof(adj));
+ adj.n_adj = 1;
+ adj.explicit_fib_index = ~0;
+
+ ip_prefix_t * dpref = &gid_address_ippref(&a->deid);
+ ip_prefix_t * spref = &gid_address_ippref(&a->seid);
+
+ switch (a->action)
+ {
+ case NO_ACTION:
+ /* TODO update timers? */
+ case FORWARD_NATIVE:
+ /* TODO check if route/next-hop for eid exists in fib and add
+ * more specific for the eid with the next-hop found */
+ case SEND_MAP_REQUEST:
+ /* TODO insert tunnel that always sends map-request */
+ case DROP:
+ /* for drop fwd entries, just add route, no need to add encap tunnel */
+ adj.lookup_next_index = LGPE_IP4_LOOKUP_NEXT_DROP;
+
+ /* add/delete route for prefix */
+ return ip4_sd_fib_add_del_route (lgm, dpref, spref, a->table_id, &adj,
+ a->is_add);
+ break;
+ default:
+ return -1;
+ }
+}
+
int
vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
u32 * hw_if_indexp)
@@ -695,66 +739,59 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
lisp_gpe_main_t * lgm = &lisp_gpe_main;
ip_adjacency_t adj, * adjp;
u32 * adj_index, rv, tun_index = ~0;
- ip_prefix_t * dpref = &gid_address_ippref(&a->deid);
- ip_prefix_t * spref = &gid_address_ippref(&a->seid);
+ ip_prefix_t * dpref, * spref;
+ uword * lookup_next_index, * lgpe_sw_if_index;
+
+ /* treat negative fwd entries separately */
+ if (a->is_negative)
+ return add_del_negative_fwd_entry (lgm, a);
+
+ /* add/del tunnel to tunnels pool and prepares rewrite */
+ rv = add_del_tunnel (a, &tun_index);
+ if (rv)
+ return rv;
+
+ dpref = &gid_address_ippref(&a->deid);
+ spref = &gid_address_ippref(&a->seid);
/* setup adjacency for eid */
memset (&adj, 0, sizeof(adj));
adj.n_adj = 1;
adj.explicit_fib_index = ~0;
- /* treat negative fwd entries separately */
- if (a->is_negative)
+ if (a->is_add)
{
- switch (a->action)
- {
- case NO_ACTION:
- /* TODO update timers? */
- case FORWARD_NATIVE:
- /* TODO check if route/next-hop for eid exists in fib and add
- * more specific for the eid with the next-hop found */
- case SEND_MAP_REQUEST:
- /* TODO insert tunnel that always sends map-request */
- case DROP:
- /* for drop fwd entries, just add route, no need to add encap tunnel */
- adj.lookup_next_index = LGPE_IP4_LOOKUP_NEXT_DROP;
-
- /* add/delete route for prefix */
- rv = ip4_sd_fib_add_del_route (lgm, dpref, spref, a->iid, &adj,
- a->is_add);
- return rv;
- break;
- default:
- return -1;
- }
+ /* send packets that hit this adj to lisp-gpe interface output node in
+ * requested vrf. */
+ lookup_next_index = hash_get(lgm->lgpe_ip4_lookup_next_index_by_table_id,
+ a->table_id);
+ lgpe_sw_if_index = hash_get(lgm->lisp_gpe_hw_if_index_by_table_id,
+ a->table_id);
+
+ /* the assumption is that the interface must've been created before
+ * programming the dp */
+ ASSERT(lookup_next_index != 0);
+ ASSERT(lgpe_sw_if_index != 0);
+
+ adj.lookup_next_index = lookup_next_index[0];
+ adj.rewrite_header.node_index = tun_index;
+ adj.rewrite_header.sw_if_index = lgpe_sw_if_index[0];
}
- /* send packets that hit this adj to lisp-gpe encap */
- adj.lookup_next_index = LGPE_IP4_LOOKUP_NEXT_LGPE_ENCAP;
+ /* add/delete route for prefix */
+ rv = ip4_sd_fib_add_del_route (lgm, dpref, spref, a->table_id, &adj,
+ a->is_add);
- /* add/delete route for prefix
- * TODO use hash to decide fib instead of using iid in clear */
- rv = ip4_sd_fib_add_del_route (lgm, dpref, spref, a->iid, &adj, a->is_add);
-
- if (rv)
- return rv;
-
- /* add/del tunnel to tunnels pool */
- rv = add_del_tunnel (a, &tun_index);
-
- /* reuse sw_if_index for storing the tunnel index */
- if (a->is_add)
+ /* check that everything worked */
+ if (CLIB_DEBUG && a->is_add)
{
- adj_index = ip4_sd_fib_get_route(lgm, dpref, spref, a->iid);
- if (!adj_index)
- {
- clib_warning("Failed to insert fwd entry! For %U",
- format_ip4_address_and_length, ip_prefix_v4(dpref),
- ip_prefix_len(dpref));
- return -1;
- }
+ adj_index = ip4_sd_fib_get_route (lgm, dpref, spref, a->table_id);
+ ASSERT(adj_index != 0);
+
adjp = ip_get_adjacency (lgm->lookup_main, adj_index[0]);
- adjp->rewrite_header.sw_if_index = tun_index;
+
+ ASSERT(adjp != 0);
+ ASSERT(adjp->rewrite_header.node_index == tun_index);
}
return rv;
@@ -810,7 +847,8 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm,
if (vec_len (eids) != vec_len (slocators))
{
- error = clib_error_return (0, "number of eids not equal to that of locators.");
+ error = clib_error_return (0, "number of eids not equal to that of "
+ "locators.");
goto done;
}
@@ -837,105 +875,11 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm,
VLIB_CLI_COMMAND (add_del_lisp_gpe_mapping_tunnel_command, static) = {
.path = "lisp gpe maptunnel",
- .short_help = "lisp gpe maptunnel eid <eid> sloc <src-locator> dloc <dst-locator> [del]",
+ .short_help = "lisp gpe maptunnel eid <eid> sloc <src-locator> "
+ "dloc <dst-locator> [del]",
.function = lisp_gpe_add_del_fwd_entry_command_fn,
};
-int
-add_del_ip_prefix_route (ip_prefix_t * dst_prefix, u32 table_id,
- ip_adjacency_t * add_adj, u8 is_add, u32 * adj_index)
-{
- uword * p;
-
- if (ip_prefix_version(dst_prefix) == IP4)
- {
- ip4_main_t * im4 = &ip4_main;
- ip4_add_del_route_args_t a;
- ip4_address_t addr = ip_prefix_v4(dst_prefix);
-
- memset(&a, 0, sizeof(a));
- a.flags = IP4_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = table_id;
- a.adj_index = ~0;
- a.dst_address_length = ip_prefix_len(dst_prefix);
- a.dst_address = addr;
- a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL;
- a.add_adj = add_adj;
- a.n_add_adj = 1;
- ip4_add_del_route (im4, &a);
-
- if (is_add)
- {
- p = ip4_get_route (im4, table_id, 0, addr.as_u8,
- ip_prefix_len(dst_prefix));
- if (p == 0)
- {
- clib_warning("Failed to insert route for eid %U!",
- format_ip4_address_and_length, addr.as_u8,
- ip_prefix_len(dst_prefix));
- return -1;
- }
- adj_index[0] = p[0];
- }
- }
- else
- {
- ip6_main_t * im6 = &ip6_main;
- ip6_add_del_route_args_t a;
- ip6_address_t addr = ip_prefix_v6(dst_prefix);
-
- memset(&a, 0, sizeof(a));
- a.flags = IP6_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = table_id;
- a.adj_index = ~0;
- a.dst_address_length = ip_prefix_len(dst_prefix);
- a.dst_address = addr;
- a.flags |= is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL;
- a.add_adj = add_adj;
- a.n_add_adj = 1;
-
- ip6_add_del_route (im6, &a);
-
- if (is_add)
- {
- adj_index[0] = ip6_get_route (im6, table_id, 0, &addr,
- ip_prefix_len(dst_prefix));
- if (adj_index[0] == 0)
- {
- clib_warning("Failed to insert route for eid %U!",
- format_ip6_address_and_length, addr.as_u8,
- ip_prefix_len(dst_prefix));
- return -1;
- }
- }
- }
- return 0;
-}
-
-static void
-add_del_lisp_gpe_default_route (u8 is_v4, u8 is_add)
-{
- lisp_gpe_main_t * lgm = &lisp_gpe_main;
- ip_adjacency_t adj;
- ip_prefix_t prefix;
- u32 adj_index = 0;
-
- /* setup adjacency */
- memset (&adj, 0, sizeof(adj));
- adj.n_adj = 1;
- adj.explicit_fib_index = ~0;
- adj.lookup_next_index = lgm->ip4_lookup_next_lgpe_ip4_lookup;
- /* default route has tunnel_index ~0 */
- adj.rewrite_header.sw_if_index = ~0;
-
- /* set prefix to 0/0 */
- memset(&prefix, 0, sizeof(prefix));
- ip_prefix_version(&prefix) = is_v4 ? IP4 : IP6;
-
- /* add/delete route for prefix XXX default table only */
- add_del_ip_prefix_route (&prefix, 0, &adj, is_add, &adj_index);
-}
-
static u8 *
format_decap_next (u8 * s, va_list * args)
{
@@ -949,8 +893,6 @@ format_decap_next (u8 * s, va_list * args)
return format (s, "ip4");
case LISP_GPE_INPUT_NEXT_IP6_INPUT:
return format (s, "ip6");
- case LISP_GPE_INPUT_NEXT_LISP_GPE_ENCAP:
- return format (s, "nsh-lisp-gpe");
default:
return format (s, "unknown %d", next_index);
}
@@ -981,7 +923,7 @@ format_lisp_gpe_tunnel (u8 * s, va_list * args)
s = format (s, "next_protocol %d ver_res %x res %x\n",
t->next_protocol, t->ver_res, t->res);
- s = format (s, "iid %d (0x%x)\n", t->iid, t->iid);
+ s = format (s, "iid %d (0x%x)\n", t->vni, t->vni);
return s;
}
@@ -1009,106 +951,74 @@ VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) = {
.function = show_lisp_gpe_tunnel_command_fn,
};
-static u8 *
-format_lisp_gpe_name (u8 * s, va_list * args)
-{
- u32 dev_instance = va_arg (*args, u32);
- return format (s, "lisp_gpe_tunnel%d", dev_instance);
-}
-
-static uword
-dummy_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame)
-{
- clib_warning("you shouldn't be here, leaking buffers...");
- return frame->n_vectors;
-}
-
-VNET_DEVICE_CLASS (lisp_gpe_device_class,static) = {
- .name = "LISP_GPE",
- .format_device_name = format_lisp_gpe_name,
- .format_tx_trace = format_lisp_gpe_encap_trace,
- .tx_function = dummy_interface_tx,
-};
-
-static uword
-dummy_set_rewrite (vnet_main_t * vnm, u32 sw_if_index, u32 l3_type,
- void * dst_address, void * rewrite, uword max_rewrite_bytes)
-{
- return 0;
-}
-
-u8 *
-format_lisp_gpe_header_with_length (u8 * s, va_list * args)
-{
- lisp_gpe_header_t * h = va_arg (*args, lisp_gpe_header_t *);
- u32 max_header_bytes = va_arg (*args, u32);
- u32 header_bytes;
-
- header_bytes = sizeof (h[0]);
- if (max_header_bytes != 0 && header_bytes > max_header_bytes)
- return format (s, "gre-nsh header truncated");
-
- s = format (s, "flags: ");
-#define _(n,v) if (h->flags & v) s = format (s, "%s ", #n);
- foreach_lisp_gpe_flag_bit;
-#undef _
-
- s = format (s, "\n ver_res %d res %d next_protocol %d iid %d(%x)",
- h->ver_res, h->res, h->next_protocol,
- clib_net_to_host_u32 (h->iid),
- clib_net_to_host_u32 (h->iid));
- return s;
-}
-
-VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
- .name = "LISP_GPE",
- .format_header = format_lisp_gpe_header_with_length,
- .set_rewrite = dummy_set_rewrite,
-};
-
-void
-vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
- u32 * hw_if_indexp)
+clib_error_t *
+vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a)
{
lisp_gpe_main_t * lgm = &lisp_gpe_main;
vnet_main_t * vnm = lgm->vnet_main;
- vnet_hw_interface_t * hi;
- u32 hw_if_index = ~0;
- if (a->is_add)
+ if (a->is_en)
{
- /* create hw lisp_gpe0 iface */
- hw_if_index = vnet_register_interface (vnm, lisp_gpe_device_class.index, 0,
- lisp_gpe_hw_class.index, 0);
-
- hi = vnet_get_hw_interface (vnm, hw_if_index);
- hi->output_node_index = lisp_gpe_encap_node.index;
- lgm->lisp_gpe_hw_if_index = hw_if_index;
-
/* add lgpe_ip4_lookup as possible next_node for ip4 lookup */
- lgm->ip4_lookup_next_lgpe_ip4_lookup = vlib_node_add_next (
- vnm->vlib_main, ip4_lookup_node.index, lgpe_ip4_lookup_node.index);
-
- /* insert default routes that points at lisp-gpe-encap */
- add_del_lisp_gpe_default_route(/* is_v4 */1, 1);
- add_del_lisp_gpe_default_route(/* is_v4 */0, 1);
+ if (lgm->ip4_lookup_next_lgpe_ip4_lookup == ~0)
+ {
+ lgm->ip4_lookup_next_lgpe_ip4_lookup = vlib_node_add_next (
+ vnm->vlib_main, ip4_lookup_node.index,
+ lgpe_ip4_lookup_node.index);
+ }
+ else
+ {
+ /* ask cp to re-add ifaces and defaults */
+ }
}
else
{
- vnet_sw_interface_set_flags (vnm, lgm->lisp_gpe_hw_if_index,
- 0 /* down */);
+ CLIB_UNUSED(uword * val);
+ hash_pair_t * p;
+ u32 * table_ids = 0, * table_id;
+ lisp_gpe_tunnel_key_t * tunnels = 0, * tunnel;
+ vnet_lisp_gpe_add_del_fwd_entry_args_t _at, * at = &_at;
+ vnet_lisp_gpe_add_del_iface_args_t _ai, * ai= &_ai;
+
+ /* remove all tunnels */
+ mhash_foreach(tunnel, val, &lgm->lisp_gpe_tunnel_by_key, ({
+ vec_add1(tunnels, tunnel[0]);
+ }));
+
+ vec_foreach(tunnel, tunnels) {
+ memset(at, 0, sizeof(at[0]));
+ at->is_add = 0;
+ gid_address_copy(&at->deid, &tunnel->eid);
+ ip_addr_v4(&at->dlocator).as_u32= tunnel->dst_loc;
+ vnet_lisp_gpe_add_del_fwd_entry (at, 0);
+ }
+ vec_free(tunnels);
+
+ /* disable all ifaces */
+ hash_foreach_pair(p, lgm->lisp_gpe_hw_if_index_by_table_id, ({
+ vec_add1(table_ids, p->key);
+ }));
+
+ vec_foreach(table_id, table_ids) {
+ ai->is_add = 0;
+ ai->table_id = table_id[0];
+
+ /* disables interface and removes defaults */
+ vnet_lisp_gpe_add_del_iface(ai, 0);
+ }
+ vec_free(table_ids);
}
+
+ return 0;
}
static clib_error_t *
-lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
+lisp_gpe_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, * line_input = &_line_input;
- u8 is_add = 1;
- vnet_lisp_gpe_add_del_iface_args_t _a, * a = &_a;
+ u8 is_en = 1;
+ vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
/* Get a line of input. */
if (! unformat_user (input, unformat_line_input, line_input))
@@ -1116,26 +1026,24 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm,
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (line_input, "up"))
- is_add = 1;
- else if (unformat (line_input, "down"))
- is_add = 0;
+ if (unformat (line_input, "enable"))
+ is_en = 1;
+ else if (unformat (line_input, "disable"))
+ is_en = 0;
else
{
return clib_error_return (0, "parse error: '%U'",
format_unformat_error, line_input);
}
}
-
- a->is_add = is_add;
- vnet_lisp_gpe_add_del_iface (a, 0);
- return 0;
+ a->is_en = is_en;
+ return vnet_lisp_gpe_enable_disable (a);
}
-VLIB_CLI_COMMAND (add_del_lisp_gpe_iface_command, static) = {
- .path = "lisp gpe iface",
- .short_help = "lisp gpe iface [del]",
- .function = lisp_gpe_add_del_iface_command_fn,
+VLIB_CLI_COMMAND (enable_disable_lisp_gpe_command, static) = {
+ .path = "lisp gpe",
+ .short_help = "lisp gpe [enable|disable]",
+ .function = lisp_gpe_enable_disable_command_fn,
};
clib_error_t *
@@ -1154,7 +1062,8 @@ lisp_gpe_init (vlib_main_t *vm)
lgm->vlib_main = vm;
lgm->im4 = &ip4_main;
lgm->lookup_main = &ip4_main.lookup_main;
-
+ lgm->ip4_lookup_next_lgpe_ip4_lookup = ~0;
+
mhash_init (&lgm->lisp_gpe_tunnel_by_key, sizeof(uword),
sizeof(lisp_gpe_tunnel_key_t));
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe.h b/vnet/vnet/lisp-gpe/lisp_gpe.h
index 7e86d57f..1452b798 100644
--- a/vnet/vnet/lisp-gpe/lisp_gpe.h
+++ b/vnet/vnet/lisp-gpe/lisp_gpe.h
@@ -74,15 +74,14 @@ typedef struct
u8 ver_res;
u8 res;
u8 next_protocol;
- u32 iid;
+ u32 vni;
} lisp_gpe_tunnel_t;
#define foreach_lisp_gpe_input_next \
_(DROP, "error-drop") \
_(IP4_INPUT, "ip4-input") \
_(IP6_INPUT, "ip6-input") \
-_(ETHERNET_INPUT, "ethernet-input") \
-_(LISP_GPE_ENCAP, "lisp-gpe-encap")
+_(ETHERNET_INPUT, "ethernet-input")
typedef enum {
#define _(s,n) LISP_GPE_INPUT_NEXT_##s,
@@ -96,7 +95,7 @@ typedef enum {
#include <vnet/lisp-gpe/lisp_gpe_error.def>
#undef lisp_gpe_error
LISP_GPE_N_ERROR,
-} lisp_gpe_input_error_t;
+} lisp_gpe_error_t;
/* As a first step, reuse v4 fib. The goal of the typedef is to shield
* consumers from future updates that may result in the lisp ip4 fib diverging
@@ -114,13 +113,18 @@ typedef struct lisp_gpe_main
/* lookup tunnel by key */
mhash_t lisp_gpe_tunnel_by_key;
- /* lookup tunnel by adjacency index */
- uword * lisp_gpe_tunnel_by_adj_index;
+ /* lookup decap tunnel termination sw_if_index by vni and vice versa */
+ uword * tunnel_term_sw_if_index_by_vni;
+ uword * vni_by_tunnel_term_sw_if_index;
/* Free vlib hw_if_indices */
u32 * free_lisp_gpe_tunnel_hw_if_indices;
- u32 lisp_gpe_hw_if_index;
+ /* Lookup lisp-gpe interfaces by vrf */
+ uword * lisp_gpe_hw_if_index_by_table_id;
+
+ /* Lookup lgpe_ip4_lookup_next by vrf */
+ uword * lgpe_ip4_lookup_next_index_by_table_id;
/* next node indexes that points ip4 lookup to lisp gpe lookup and lisp cp */
u32 ip4_lookup_next_lgpe_ip4_lookup;
@@ -136,10 +140,9 @@ lisp_gpe_main_t lisp_gpe_main;
extern vlib_node_registration_t lgpe_ip4_lookup_node;
extern vlib_node_registration_t lisp_gpe_input_node;
-extern vlib_node_registration_t lisp_gpe_encap_node;
u8 *
-format_lisp_gpe_encap_trace (u8 * s, va_list * args);
+format_lisp_gpe_tx_trace (u8 * s, va_list * args);
u8 *
format_lisp_gpe_header_with_length (u8 * s, va_list * args);
@@ -154,7 +157,7 @@ typedef struct
u8 ver_res;
u8 res;
u8 next_protocol;
- u32 iid; /* host byte order */
+ u32 vni; /* host byte order */
} vnet_lisp_gpe_add_del_tunnel_args_t;
int
@@ -164,12 +167,22 @@ vnet_lisp_gpe_add_del_tunnel (vnet_lisp_gpe_add_del_tunnel_args_t *a,
typedef struct
{
u8 is_add;
+ u32 table_id; /* vrf */
+ u32 vni; /* host byte order */
} vnet_lisp_gpe_add_del_iface_args_t;
void
vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t *a,
u32 * hw_if_indexp);
+typedef struct
+{
+ u8 is_en;
+} vnet_lisp_gpe_enable_disable_args_t;
+
+clib_error_t *
+vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t *a);
+
typedef enum
{
NO_ACTION,
@@ -194,7 +207,8 @@ typedef struct
u8 ver_res;
u8 res;
u8 next_protocol;
- u32 iid; /* host byte order */
+ u32 vni; /* host byte order */
+ u32 table_id;
} vnet_lisp_gpe_add_del_fwd_entry_args_t;
int
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe_error.def b/vnet/vnet/lisp-gpe/lisp_gpe_error.def
index f002ecae..c4c3f75d 100644
--- a/vnet/vnet/lisp-gpe/lisp_gpe_error.def
+++ b/vnet/vnet/lisp-gpe/lisp_gpe_error.def
@@ -13,5 +13,6 @@
* limitations under the License.
*/
+lisp_gpe_error (ENCAPSULATED, "good packets encapsulated")
lisp_gpe_error (DECAPSULATED, "good packets decapsulated")
lisp_gpe_error (NO_SUCH_TUNNEL, "no such tunnel packets")
diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c
index a93a6c57..29629c91 100644
--- a/vpp-api-test/vat/api_format.c
+++ b/vpp-api-test/vat/api_format.c
@@ -1954,8 +1954,6 @@ format_decap_next (u8 * s, va_list * args)
return format (s, "ip4");
case LISP_GPE_INPUT_NEXT_IP6_INPUT:
return format (s, "ip6");
- case LISP_GPE_INPUT_NEXT_LISP_GPE_ENCAP:
- return format (s, "nsh-lisp-gpe");
default:
return format (s, "unknown %d", next_index);
}
@@ -2161,6 +2159,7 @@ _(lisp_add_del_locator_reply) \
_(lisp_add_del_local_eid_reply) \
_(lisp_gpe_add_del_fwd_entry_reply) \
_(lisp_add_del_map_resolver_reply) \
+_(lisp_gpe_enable_disable_reply) \
_(lisp_gpe_add_del_iface_reply)
#define _(n) \
@@ -2329,6 +2328,7 @@ _(LISP_ADD_DEL_LOCATOR_REPLY, lisp_add_del_locator_reply) \
_(LISP_ADD_DEL_LOCAL_EID_REPLY, lisp_add_del_local_eid_reply) \
_(LISP_GPE_ADD_DEL_FWD_ENTRY_REPLY, lisp_gpe_add_del_fwd_entry_reply) \
_(LISP_ADD_DEL_MAP_RESOLVER_REPLY, lisp_add_del_map_resolver_reply) \
+_(LISP_GPE_ENABLE_DISABLE_REPLY, lisp_gpe_enable_disable_reply) \
_(LISP_GPE_ADD_DEL_IFACE_REPLY, lisp_gpe_add_del_iface_reply) \
_(LISP_LOCATOR_SET_DETAILS, lisp_locator_set_details) \
_(LISP_LOCAL_EID_TABLE_DETAILS, lisp_local_eid_table_details) \
@@ -7862,8 +7862,6 @@ static uword unformat_lisp_gpe_decap_next (unformat_input_t * input,
*result = LISP_GPE_INPUT_NEXT_IP6_INPUT;
else if (unformat (input, "ethernet"))
*result = LISP_GPE_INPUT_NEXT_IP6_INPUT;
- else if (unformat (input, "lisp-gpe"))
- *result = LISP_GPE_INPUT_NEXT_LISP_GPE_ENCAP;
else if (unformat (input, "%d", &tmp))
*result = tmp;
else
@@ -9748,13 +9746,55 @@ api_lisp_add_del_map_resolver(vat_main_t * vam)
}
static int
+api_lisp_gpe_enable_disable (vat_main_t * vam)
+{
+ unformat_input_t * input = vam->input;
+ vl_api_lisp_gpe_enable_disable_t *mp;
+ f64 timeout = ~0;
+ u8 is_set = 0;
+ u8 is_en = 1;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "enable")) {
+ is_set = 1;
+ is_en = 1;
+ } else if (unformat(input, "disable")) {
+ is_set = 1;
+ is_en = 0;
+ } else
+ break;
+ }
+
+ if (is_set == 0) {
+ errmsg("Value not set\n");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M(LISP_GPE_ENABLE_DISABLE, lisp_gpe_enable_disable);
+
+ mp->is_en = is_en;
+
+ /* send it... */
+ S;
+
+ /* Wait for a reply... */
+ W;
+
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
api_lisp_gpe_add_del_iface(vat_main_t * vam)
{
unformat_input_t * input = vam->input;
vl_api_lisp_gpe_add_del_iface_t *mp;
f64 timeout = ~0;
u8 is_set = 0;
- u8 is_add = 1;
+ u8 is_add = 1;
+ u32 table_id, vni;
/* Parse args required to build the message */
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
@@ -9764,6 +9804,10 @@ api_lisp_gpe_add_del_iface(vat_main_t * vam)
} else if (unformat(input, "down")) {
is_set = 1;
is_add = 0;
+ } else if (unformat(input, "table_id %d", &table_id)) {
+ ;
+ } else if (unformat(input, "vni %d", &vni)) {
+ ;
} else
break;
}
@@ -9777,6 +9821,8 @@ api_lisp_gpe_add_del_iface(vat_main_t * vam)
M(LISP_GPE_ADD_DEL_IFACE, lisp_gpe_add_del_iface);
mp->is_add = is_add;
+ mp->table_id = table_id;
+ mp->vni = vni;
/* send it... */
S;
@@ -10382,6 +10428,7 @@ _(lisp_add_del_local_eid, "<ipv4|ipv6>/<prefix> " \
_(lisp_gpe_add_del_fwd_entry, "eid <ip4|6-addr>/<prefix> " \
"sloc <ip4/6-addr> dloc <ip4|6-addr> [del]") \
_(lisp_add_del_map_resolver, "<ip4|6-addr> [del]") \
+_(lisp_gpe_enable_disable, "enable|disable") \
_(lisp_gpe_add_del_iface, "up|down") \
_(lisp_locator_set_dump, "") \
_(lisp_local_eid_table_dump, "") \
diff --git a/vpp/api/api.c b/vpp/api/api.c
index 4956a43a..ea766938 100644
--- a/vpp/api/api.c
+++ b/vpp/api/api.c
@@ -321,6 +321,7 @@ _(LISP_ADD_DEL_LOCATOR, lisp_add_del_locator) \
_(LISP_ADD_DEL_LOCAL_EID, lisp_add_del_local_eid) \
_(LISP_GPE_ADD_DEL_FWD_ENTRY, lisp_gpe_add_del_fwd_entry) \
_(LISP_ADD_DEL_MAP_RESOLVER, lisp_add_del_map_resolver) \
+_(LISP_GPE_ENABLE_DISABLE, lisp_gpe_enable_disable) \
_(LISP_GPE_ADD_DEL_IFACE, lisp_gpe_add_del_iface) \
_(LISP_LOCATOR_SET_DUMP, lisp_locator_set_dump) \
_(LISP_LOCAL_EID_TABLE_DUMP, lisp_local_eid_table_dump) \
@@ -4465,7 +4466,7 @@ vl_api_lisp_gpe_add_del_tunnel_t_handler
a->ver_res = mp->ver_res;
a->res = mp->res;
a->next_protocol = mp->next_protocol;
- a->iid = clib_net_to_host_u32 (mp->iid);
+ a->vni = clib_net_to_host_u32 (mp->iid);
rv = vnet_lisp_gpe_add_del_tunnel (a, &sw_if_index);
@@ -4580,7 +4581,7 @@ vl_api_lisp_add_del_local_eid_t_handler(
a->locator_set_index = locator_set_index;
a->local = 1;
- rv = vnet_lisp_add_del_mapping(a, &map_index);
+ rv = vnet_lisp_add_del_local_mapping(a, &map_index);
out:
vec_free(name);
@@ -4684,6 +4685,20 @@ vl_api_lisp_add_del_map_resolver_t_handler(
}
static void
+vl_api_lisp_gpe_enable_disable_t_handler(
+ vl_api_lisp_gpe_enable_disable_t *mp)
+{
+ vl_api_lisp_gpe_enable_disable_reply_t *rmp;
+ int rv = 0;
+ vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
+
+ a->is_en = mp->is_en;
+ vnet_lisp_gpe_enable_disable (a);
+
+ REPLY_MACRO(VL_API_LISP_GPE_ENABLE_DISABLE_REPLY);
+}
+
+static void
vl_api_lisp_gpe_add_del_iface_t_handler(
vl_api_lisp_gpe_add_del_iface_t *mp)
{
@@ -4692,6 +4707,8 @@ vl_api_lisp_gpe_add_del_iface_t_handler(
vnet_lisp_gpe_add_del_iface_args_t _a, * a = &_a;
a->is_add = mp->is_add;
+ a->table_id = mp->table_id;
+ a->vni = mp->vni;
vnet_lisp_gpe_add_del_iface (a, 0);
REPLY_MACRO(VL_API_LISP_GPE_ADD_DEL_IFACE_REPLY);
@@ -4837,7 +4854,7 @@ send_lisp_gpe_tunnel_details (lisp_gpe_tunnel_t *tunnel,
rmp->flags = tunnel->flags;
rmp->ver_res = tunnel->ver_res;
rmp->res = tunnel->res;
- rmp->iid = htonl(tunnel->iid);
+ rmp->iid = htonl(tunnel->vni);
vl_msg_api_send_shmem (q, (u8 *)&rmp);
}
diff --git a/vpp/api/vpe.api b/vpp/api/vpe.api
index f255fdaf..afad1c25 100644
--- a/vpp/api/vpe.api
+++ b/vpp/api/vpe.api
@@ -2239,6 +2239,26 @@ define lisp_add_del_map_resolver_reply {
i32 retval;
};
+/** \brief enable or disable lisp-gpe protocol
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param is_en - enable protocol if non-zero, else disable
+*/
+define lisp_gpe_enable_disable {
+ u32 client_index;
+ u32 context;
+ u8 is_en;
+};
+
+/** \brief Reply for gpe enable/disable
+ @param context - returned sender context, to match reply w/ request
+ @param retval - return code
+*/
+define lisp_gpe_enable_disable_reply {
+ u32 context;
+ i32 retval;
+};
+
/** \brief add or delete gpe_iface
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@@ -2248,6 +2268,8 @@ define lisp_gpe_add_del_iface {
u32 client_index;
u32 context;
u8 is_add;
+ u32 table_id;
+ u32 vni;
};
/** \brief Reply for gpe_iface add/del