aboutsummaryrefslogtreecommitdiffstats
path: root/vnet/vnet/lisp-gpe
diff options
context:
space:
mode:
Diffstat (limited to 'vnet/vnet/lisp-gpe')
-rw-r--r--vnet/vnet/lisp-gpe/interface.c656
-rw-r--r--vnet/vnet/lisp-gpe/ip_forward.c1593
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe.c855
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe.h232
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c437
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe_adjacency.h134
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.c286
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.h157
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe_tunnel.c289
-rw-r--r--vnet/vnet/lisp-gpe/lisp_gpe_tunnel.h89
10 files changed, 2190 insertions, 2538 deletions
diff --git a/vnet/vnet/lisp-gpe/interface.c b/vnet/vnet/lisp-gpe/interface.c
index abfdfdb8..52db1eb3 100644
--- a/vnet/vnet/lisp-gpe/interface.c
+++ b/vnet/vnet/lisp-gpe/interface.c
@@ -26,6 +26,10 @@
#include <vnet/ip/udp.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/lisp-gpe/lisp_gpe.h>
+#include <vnet/adj/adj.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/ip6_fib.h>
#define foreach_lisp_gpe_tx_next \
_(DROP, "error-drop") \
@@ -56,147 +60,6 @@ format_lisp_gpe_tx_trace (u8 * s, va_list * args)
return s;
}
-always_inline void
-get_one_tunnel_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
- lisp_gpe_tunnel_t ** t0, u8 is_v4)
-{
- u32 adj_index0, tunnel_index0;
- ip_adjacency_t *adj0;
-
- /* Get adjacency and from it the tunnel_index */
- adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
-
- if (is_v4)
- adj0 = ip_get_adjacency (lgm->lm4, adj_index0);
- else
- adj0 = ip_get_adjacency (lgm->lm6, adj_index0);
-
- tunnel_index0 = adj0->if_address_index;
- t0[0] = pool_elt_at_index (lgm->tunnels, tunnel_index0);
-
- ASSERT (t0[0] != 0);
-}
-
-always_inline void
-encap_one_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
- lisp_gpe_tunnel_t * t0, u32 * next0)
-{
- ASSERT (sizeof (ip4_udp_lisp_gpe_header_t) == 36);
- ASSERT (sizeof (ip6_udp_lisp_gpe_header_t) == 56);
-
- lisp_gpe_sub_tunnel_t *st0;
- u32 *sti0;
-
- sti0 = vec_elt_at_index (t0->sub_tunnels_lbv,
- vnet_buffer (b0)->ip.flow_hash %
- t0->sub_tunnels_lbv_count);
- st0 = vec_elt_at_index (t0->sub_tunnels, sti0[0]);
- if (st0->is_ip4)
- {
- ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 36, 1);
- next0[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
- }
- else
- {
- ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 56, 0);
- next0[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
- }
-
- /* Reset to look up tunnel partner in the configured FIB */
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
-}
-
-always_inline void
-get_two_tunnels_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
- vlib_buffer_t * b1, lisp_gpe_tunnel_t ** t0,
- lisp_gpe_tunnel_t ** t1, u8 is_v4)
-{
- u32 adj_index0, adj_index1, tunnel_index0, tunnel_index1;
- ip_adjacency_t *adj0, *adj1;
-
- /* 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];
-
- if (is_v4)
- {
- adj0 = ip_get_adjacency (lgm->lm4, adj_index0);
- adj1 = ip_get_adjacency (lgm->lm4, adj_index1);
- }
- else
- {
- adj0 = ip_get_adjacency (lgm->lm6, adj_index0);
- adj1 = ip_get_adjacency (lgm->lm6, adj_index1);
- }
-
- tunnel_index0 = adj0->if_address_index;
- tunnel_index1 = adj1->if_address_index;
-
- t0[0] = pool_elt_at_index (lgm->tunnels, tunnel_index0);
- t1[0] = pool_elt_at_index (lgm->tunnels, tunnel_index1);
-
- ASSERT (t0[0] != 0);
- ASSERT (t1[0] != 0);
-}
-
-always_inline void
-encap_two_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
- vlib_buffer_t * b1, lisp_gpe_tunnel_t * t0,
- lisp_gpe_tunnel_t * t1, u32 * next0, u32 * next1)
-{
- ASSERT (sizeof (ip4_udp_lisp_gpe_header_t) == 36);
- ASSERT (sizeof (ip6_udp_lisp_gpe_header_t) == 56);
-
- lisp_gpe_sub_tunnel_t *st0, *st1;
- u32 *sti0, *sti1;
- sti0 = vec_elt_at_index (t0->sub_tunnels_lbv,
- vnet_buffer (b0)->ip.flow_hash %
- t0->sub_tunnels_lbv_count);
- sti1 =
- vec_elt_at_index (t1->sub_tunnels_lbv,
- vnet_buffer (b1)->ip.flow_hash %
- t1->sub_tunnels_lbv_count);
- st0 = vec_elt_at_index (t0->sub_tunnels, sti0[0]);
- st1 = vec_elt_at_index (t1->sub_tunnels, sti1[0]);
-
- if (PREDICT_TRUE (st0->is_ip4 == st1->is_ip4))
- {
- if (st0->is_ip4)
- {
- ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 36, 1);
- ip_udp_encap_one (lgm->vlib_main, b1, st1->rewrite, 36, 1);
- next0[0] = next1[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
- }
- else
- {
- ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 56, 0);
- ip_udp_encap_one (lgm->vlib_main, b1, st1->rewrite, 56, 0);
- next0[0] = next1[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
- }
- }
- else
- {
- if (st0->is_ip4)
- {
- ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 36, 1);
- ip_udp_encap_one (lgm->vlib_main, b1, st1->rewrite, 56, 1);
- next0[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
- next1[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
- }
- else
- {
- ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 56, 1);
- ip_udp_encap_one (lgm->vlib_main, b1, st1->rewrite, 36, 1);
- next0[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
- next1[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
- }
- }
-
- /* 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;
-}
-
#define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40
/**
@@ -233,81 +96,12 @@ lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
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;
- lisp_gpe_tunnel_t *t0 = 0, *t1 = 0;
- u8 is_v4_eid0, is_v4_eid1;
-
- 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);
-
- is_v4_eid0 = is_v4_packet (vlib_buffer_get_current (b0));
- is_v4_eid1 = is_v4_packet (vlib_buffer_get_current (b1));
-
- if (PREDICT_TRUE (is_v4_eid0 == is_v4_eid1))
- {
- get_two_tunnels_inline (lgm, b0, b1, &t0, &t1,
- is_v4_eid0 ? 1 : 0);
- }
- else
- {
- get_one_tunnel_inline (lgm, b0, &t0, is_v4_eid0 ? 1 : 0);
- get_one_tunnel_inline (lgm, b1, &t1, is_v4_eid1 ? 1 : 0);
- }
-
- encap_two_inline (lgm, b0, b1, t0, t1, &next0, &next1);
-
- 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;
- }
-
- 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)
{
+ u32 bi0, adj_index0, next0;
+ const ip_adjacency_t *adj0;
+ const dpo_id_t *dpo0;
vlib_buffer_t *b0;
- u32 bi0, next0 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
- lisp_gpe_tunnel_t *t0 = 0;
u8 is_v4_0;
bi0 = from[0];
@@ -319,16 +113,23 @@ lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
b0 = vlib_get_buffer (vm, bi0);
+ /* Fixup the checksum and len fields in the LISP tunnel encap
+ * that was applied at the midchain node */
is_v4_0 = is_v4_packet (vlib_buffer_get_current (b0));
- get_one_tunnel_inline (lgm, b0, &t0, is_v4_0 ? 1 : 0);
+ ip_udp_fixup_one (lgm->vlib_main, b0, is_v4_0);
- encap_one_inline (lgm, b0, t0, &next0);
+ /* Follow the DPO on which the midchain is stacked */
+ adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
+ adj0 = adj_get (adj_index0);
+ dpo0 = &adj0->sub_type.midchain.next_dpo;
+ next0 = dpo0->dpoi_next_node;
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
if (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;
+ tr->tunnel_index = adj_index0;
}
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
n_left_to_next, bi0, next0);
@@ -348,7 +149,7 @@ format_lisp_gpe_name (u8 * s, va_list * args)
}
/* *INDENT-OFF* */
-VNET_DEVICE_CLASS (lisp_gpe_device_class,static) = {
+VNET_DEVICE_CLASS (lisp_gpe_device_class) = {
.name = "LISP_GPE",
.format_device_name = format_lisp_gpe_name,
.format_tx_trace = format_lisp_gpe_tx_trace,
@@ -394,133 +195,51 @@ VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
};
/* *INDENT-ON* */
-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)
+static void
+add_del_lisp_gpe_default_route (u32 table_id, fib_protocol_t proto, u8 is_add)
{
- uword *p;
+ fib_prefix_t prefix = {
+ .fp_proto = proto,
+ };
+ u32 fib_index;
- if (ip_prefix_version (dst_prefix) == IP4)
+ if (is_add)
{
- 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 = is_add ? 1 : 0;
-
- 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];
- }
+ /*
+ * Add a deafult route that results in a control plane punt DPO
+ */
+ dpo_id_t cp_punt = DPO_NULL;
+
+ dpo_set (&cp_punt, DPO_LISP_CP, fib_proto_to_dpo (proto), proto);
+
+ fib_index =
+ fib_table_find_or_create_and_lock (prefix.fp_proto, table_id);
+ fib_table_entry_special_dpo_add (fib_index, &prefix, FIB_SOURCE_LISP,
+ FIB_ENTRY_FLAG_EXCLUSIVE, &cp_punt);
+ dpo_unlock (&cp_punt);
}
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 = is_add ? 1 : 0;
-
- 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;
- }
- }
+ fib_index = fib_table_find (prefix.fp_proto, table_id);
+ fib_table_entry_special_remove (fib_index, &prefix, FIB_SOURCE_LISP);
+ fib_table_unlock (fib_index, prefix.fp_proto);
}
- return 0;
}
-static void
-add_del_lisp_gpe_default_route (u32 table_id, u8 is_v4, u8 is_add)
+void
+lisp_gpe_iface_set_table (u32 sw_if_index, u32 table_id)
{
- 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 = is_v4 ? lgm->ip4_lookup_next_lgpe_ip4_lookup :
- lgm->ip6_lookup_next_lgpe_ip6_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);
-}
+ fib_node_index_t fib_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_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
+ vec_validate (ip4_main.fib_index_by_sw_if_index, sw_if_index);
+ ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
+ ip4_sw_interface_enable_disable (sw_if_index, 1);
- /* 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;
- }
+ fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, table_id);
+ vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
+ ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
+ ip6_sw_interface_enable_disable (sw_if_index, 1);
}
#define foreach_l2_lisp_gpe_tx_next \
@@ -605,71 +324,71 @@ l2_flow_hash (vlib_buffer_t * b0)
return (u32) c;
}
-always_inline void
-l2_process_one (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, u32 ti0,
- u32 * next0)
-{
- lisp_gpe_tunnel_t *t0;
-
- t0 = pool_elt_at_index (lgm->tunnels, ti0);
- ASSERT (0 != t0);
-
- if (PREDICT_TRUE (LISP_NO_ACTION == t0->action))
- {
- /* compute 'flow' hash */
- if (PREDICT_TRUE (t0->sub_tunnels_lbv_count > 1))
- vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
- encap_one_inline (lgm, b0, t0, next0);
- }
- else
- {
- l2_process_tunnel_action (b0, t0->action, next0);
- }
-}
-
-always_inline void
-l2_process_two (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, vlib_buffer_t * b1,
- u32 ti0, u32 ti1, u32 * next0, u32 * next1)
-{
- lisp_gpe_tunnel_t *t0, *t1;
-
- t0 = pool_elt_at_index (lgm->tunnels, ti0);
- t1 = pool_elt_at_index (lgm->tunnels, ti1);
-
- ASSERT (0 != t0 && 0 != t1);
-
- if (PREDICT_TRUE (LISP_NO_ACTION == t0->action
- && LISP_NO_ACTION == t1->action))
- {
- if (PREDICT_TRUE (t0->sub_tunnels_lbv_count > 1))
- vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
- if (PREDICT_TRUE (t1->sub_tunnels_lbv_count > 1))
- vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
- encap_two_inline (lgm, b0, b1, t0, t1, next0, next1);
- }
- else
- {
- if (LISP_NO_ACTION == t0->action)
- {
- if (PREDICT_TRUE (t0->sub_tunnels_lbv_count > 1))
- vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
- encap_one_inline (lgm, b0, t0, next0);
- l2_process_tunnel_action (b1, t1->action, next1);
- }
- else if (LISP_NO_ACTION == t1->action)
- {
- if (PREDICT_TRUE (t1->sub_tunnels_lbv_count > 1))
- vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
- encap_one_inline (lgm, b1, t1, next1);
- l2_process_tunnel_action (b0, t0->action, next0);
- }
- else
- {
- l2_process_tunnel_action (b0, t0->action, next0);
- l2_process_tunnel_action (b1, t1->action, next1);
- }
- }
-}
+/* always_inline void */
+/* l2_process_one (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, u32 ti0, */
+/* u32 * next0) */
+/* { */
+/* lisp_gpe_tunnel_t *t0; */
+
+/* t0 = pool_elt_at_index (lgm->tunnels, ti0); */
+/* ASSERT (0 != t0); */
+
+/* if (PREDICT_TRUE (LISP_NO_ACTION == t0->action)) */
+/* { */
+/* /\* compute 'flow' hash *\/ */
+/* if (PREDICT_TRUE (t0->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0); */
+/* encap_one_inline (lgm, b0, t0, next0); */
+/* } */
+/* else */
+/* { */
+/* l2_process_tunnel_action (b0, t0->action, next0); */
+/* } */
+/* } */
+
+/* always_inline void */
+/* l2_process_two (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, vlib_buffer_t * b1, */
+/* u32 ti0, u32 ti1, u32 * next0, u32 * next1) */
+/* { */
+/* lisp_gpe_tunnel_t *t0, *t1; */
+
+/* t0 = pool_elt_at_index (lgm->tunnels, ti0); */
+/* t1 = pool_elt_at_index (lgm->tunnels, ti1); */
+
+/* ASSERT (0 != t0 && 0 != t1); */
+
+/* if (PREDICT_TRUE (LISP_NO_ACTION == t0->action */
+/* && LISP_NO_ACTION == t1->action)) */
+/* { */
+/* if (PREDICT_TRUE (t0->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0); */
+/* if (PREDICT_TRUE (t1->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1); */
+/* encap_two_inline (lgm, b0, b1, t0, t1, next0, next1); */
+/* } */
+/* else */
+/* { */
+/* if (LISP_NO_ACTION == t0->action) */
+/* { */
+/* if (PREDICT_TRUE (t0->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0); */
+/* encap_one_inline (lgm, b0, t0, next0); */
+/* l2_process_tunnel_action (b1, t1->action, next1); */
+/* } */
+/* else if (LISP_NO_ACTION == t1->action) */
+/* { */
+/* if (PREDICT_TRUE (t1->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1); */
+/* encap_one_inline (lgm, b1, t1, next1); */
+/* l2_process_tunnel_action (b0, t0->action, next0); */
+/* } */
+/* else */
+/* { */
+/* l2_process_tunnel_action (b0, t0->action, next0); */
+/* l2_process_tunnel_action (b1, t1->action, next1); */
+/* } */
+/* } */
+/* } */
/**
* @brief LISP-GPE interface TX (encap) function for L2 overlays.
@@ -710,9 +429,9 @@ l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
{
u32 bi0, bi1;
vlib_buffer_t *b0, *b1;
- u32 next0, next1, ti0, ti1;
+ u32 next0, next1;
lisp_gpe_tunnel_t *t0 = 0, *t1 = 0;
- ethernet_header_t *e0, *e1;
+ // ethernet_header_t *e0, *e1;
next0 = next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
@@ -742,49 +461,49 @@ l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
b0 = vlib_get_buffer (vm, bi0);
b1 = vlib_get_buffer (vm, bi1);
- e0 = vlib_buffer_get_current (b0);
- e1 = vlib_buffer_get_current (b1);
+ /* e0 = vlib_buffer_get_current (b0); */
+ /* e1 = vlib_buffer_get_current (b1); */
/* lookup dst + src mac */
- ti0 = lisp_l2_fib_lookup (lgm, vnet_buffer (b0)->l2.bd_index,
- e0->src_address, e0->dst_address);
- ti1 = lisp_l2_fib_lookup (lgm, vnet_buffer (b1)->l2.bd_index,
- e1->src_address, e1->dst_address);
-
- if (PREDICT_TRUE ((u32) ~ 0 != ti0) && (u32) ~ 0 != ti1)
- {
- /* process both tunnels */
- l2_process_two (lgm, b0, b1, ti0, ti1, &next0, &next1);
- }
- else
- {
- if ((u32) ~ 0 != ti0)
- {
- /* process tunnel for b0 */
- l2_process_one (lgm, b0, ti0, &next0);
-
- /* no tunnel found for b1, send to control plane */
- next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
- vnet_buffer (b1)->lisp.overlay_afi = LISP_AFI_MAC;
- }
- else if ((u32) ~ 0 != ti1)
- {
- /* process tunnel for b1 */
- l2_process_one (lgm, b1, ti1, &next1);
-
- /* no tunnel found b0, send to control plane */
- next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
- vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC;
- }
- else
- {
- /* no tunnels found */
- next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
- vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC;
- next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
- vnet_buffer (b1)->lisp.overlay_afi = LISP_AFI_MAC;
- }
- }
+ /* ti0 = lisp_l2_fib_lookup (lgm, vnet_buffer (b0)->l2.bd_index, */
+ /* e0->src_address, e0->dst_address); */
+ /* ti1 = lisp_l2_fib_lookup (lgm, vnet_buffer (b1)->l2.bd_index, */
+ /* e1->src_address, e1->dst_address); */
+
+ /* if (PREDICT_TRUE ((u32) ~ 0 != ti0) && (u32) ~ 0 != ti1) */
+ /* { */
+ /* /\* process both tunnels *\/ */
+ /* l2_process_two (lgm, b0, b1, ti0, ti1, &next0, &next1); */
+ /* } */
+ /* else */
+ /* { */
+ /* if ((u32) ~ 0 != ti0) */
+ /* { */
+ /* /\* process tunnel for b0 *\/ */
+ /* l2_process_one (lgm, b0, ti0, &next0); */
+
+ /* /\* no tunnel found for b1, send to control plane *\/ */
+ /* next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b1)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* } */
+ /* else if ((u32) ~ 0 != ti1) */
+ /* { */
+ /* /\* process tunnel for b1 *\/ */
+ /* l2_process_one (lgm, b1, ti1, &next1); */
+
+ /* /\* no tunnel found b0, send to control plane *\/ */
+ /* next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* } */
+ /* else */
+ /* { */
+ /* /\* no tunnels found *\/ */
+ /* next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b1)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* } */
+ /* } */
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -824,16 +543,16 @@ l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
ti0 = lisp_l2_fib_lookup (lgm, vnet_buffer (b0)->l2.bd_index,
e0->src_address, e0->dst_address);
- if (PREDICT_TRUE ((u32) ~ 0 != ti0))
- {
- l2_process_one (lgm, b0, ti0, &next0);
- }
- else
- {
- /* no tunnel found send to control plane */
- next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
- vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC;
- }
+ /* if (PREDICT_TRUE ((u32) ~ 0 != ti0)) */
+ /* { */
+ /* l2_process_one (lgm, b0, ti0, &next0); */
+ /* } */
+ /* else */
+ /* { */
+ /* /\* no tunnel found send to control plane *\/ */
+ /* next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* } */
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
@@ -973,7 +692,6 @@ lisp_gpe_add_del_l3_iface (lisp_gpe_main_t * lgm,
vnet_main_t *vnm = lgm->vnet_main;
tunnel_lookup_t *l3_ifaces = &lgm->l3_ifaces;
vnet_hw_interface_t *hi;
- u32 lookup_next_index4, lookup_next_index6;
uword *hip, *si;
hip = hash_get (l3_ifaces->hw_if_index_by_dp_table, a->table_id);
@@ -997,30 +715,10 @@ lisp_gpe_add_del_l3_iface (lisp_gpe_main_t * lgm,
hi = create_lisp_gpe_iface (lgm, a->vni, a->table_id,
&lisp_gpe_device_class, l3_ifaces);
- /* set ingress arc from lgpe_ipX_lookup */
- lookup_next_index4 = vlib_node_add_next (lgm->vlib_main,
- lgpe_ip4_lookup_node.index,
- hi->output_node_index);
- lookup_next_index6 = vlib_node_add_next (lgm->vlib_main,
- lgpe_ip6_lookup_node.index,
- hi->output_node_index);
- hash_set (lgm->lgpe_ip4_lookup_next_index_by_table_id, a->table_id,
- lookup_next_index4);
- hash_set (lgm->lgpe_ip6_lookup_next_index_by_table_id, a->table_id,
- lookup_next_index6);
-
- /* 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);
+ /* insert default routes that point to lisp-cp lookup */
+ lisp_gpe_iface_set_table (hi->sw_if_index, a->table_id);
+ add_del_lisp_gpe_default_route (a->table_id, FIB_PROTOCOL_IP4, 1);
+ add_del_lisp_gpe_default_route (a->table_id, FIB_PROTOCOL_IP6, 1);
/* enable interface */
vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
@@ -1037,11 +735,15 @@ lisp_gpe_add_del_l3_iface (lisp_gpe_main_t * lgm,
return -1;
}
+ hi = vnet_get_hw_interface (vnm, hip[0]);
+
remove_lisp_gpe_iface (lgm, hip[0], a->table_id, &lgm->l3_ifaces);
/* 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);
+ ip4_sw_interface_enable_disable (hi->sw_if_index, 0);
+ ip6_sw_interface_enable_disable (hi->sw_if_index, 0);
+ add_del_lisp_gpe_default_route (a->table_id, FIB_PROTOCOL_IP4, 0);
+ add_del_lisp_gpe_default_route (a->table_id, FIB_PROTOCOL_IP6, 0);
}
return 0;
diff --git a/vnet/vnet/lisp-gpe/ip_forward.c b/vnet/vnet/lisp-gpe/ip_forward.c
index bd9951ac..8a24ec03 100644
--- a/vnet/vnet/lisp-gpe/ip_forward.c
+++ b/vnet/vnet/lisp-gpe/ip_forward.c
@@ -12,1492 +12,257 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/**
- * @file
- * @brief LISP-GPE overlay IP forwarding logic and lookup data structures.
- *
- * Provides an implementation of a Source/Dest (SD) IP FIB that leverages the
- * existing destination only FIB. Lookups are done in two stages, first the
- * destination FIB looks up a packet's destination address and then if a
- * an SD entry is hit, the destination adjacency will point to the second
- * stage, the source FIB, where the packet's source is looked up. Note that a
- * miss in the source FIB does not result in an overall SD lookup retry with
- * a less specific entry from the destination FIB.
- */
-#include <vnet/lisp-gpe/lisp_gpe.h>
-
-/** Sets adj index for destination address in IP4 FIB. Similar to the function
- * in ip4_forward but this one avoids calling route callbacks */
-static void
-ip4_sd_fib_set_adj_index (lisp_gpe_main_t * lgm, ip4_fib_t * fib, u32 flags,
- u32 dst_address_u32, u32 dst_address_length,
- u32 adj_index)
-{
- ip_lookup_main_t *lm = lgm->lm4;
- uword *hash;
-
- if (vec_bytes (fib->old_hash_values))
- memset (fib->old_hash_values, ~0, vec_bytes (fib->old_hash_values));
- if (vec_bytes (fib->new_hash_values))
- memset (fib->new_hash_values, ~0, vec_bytes (fib->new_hash_values));
- fib->new_hash_values[0] = adj_index;
-
- /* Make sure adj index is valid. */
- if (CLIB_DEBUG > 0)
- (void) ip_get_adjacency (lm, adj_index);
-
- hash = fib->adj_index_by_dst_address[dst_address_length];
-
- hash = _hash_set3 (hash, dst_address_u32,
- fib->new_hash_values, fib->old_hash_values);
-
- fib->adj_index_by_dst_address[dst_address_length] = hash;
-}
-
-/** Initialize the adjacency index by destination address vector for IP4 FIB.
- * Copied from ip4_forward since it's static */
-static void
-ip4_fib_init_adj_index_by_dst_address (ip_lookup_main_t * lm,
- ip4_fib_t * fib, u32 address_length)
-{
- hash_t *h;
- uword max_index;
-
- ASSERT (lm->fib_result_n_bytes >= sizeof (uword));
- lm->fib_result_n_words = round_pow2 (lm->fib_result_n_bytes, sizeof (uword))
- / sizeof (uword);
-
- fib->adj_index_by_dst_address[address_length] =
- hash_create (32 /* elts */ , lm->fib_result_n_words * sizeof (uword));
-
- hash_set_flags (fib->adj_index_by_dst_address[address_length],
- HASH_FLAG_NO_AUTO_SHRINK);
-
- h = hash_header (fib->adj_index_by_dst_address[address_length]);
- max_index = (hash_value_bytes (h) / sizeof (fib->new_hash_values[0])) - 1;
-
- /* Initialize new/old hash value vectors. */
- vec_validate_init_empty (fib->new_hash_values, max_index, ~0);
- vec_validate_init_empty (fib->old_hash_values, max_index, ~0);
-}
-
-/** Add/del src route to IP4 SD FIB. */
-static void
-ip4_sd_fib_add_del_src_route (lisp_gpe_main_t * lgm,
- ip4_add_del_route_args_t * a)
-{
- ip_lookup_main_t *lm = lgm->lm4;
- ip4_fib_t *fib;
- u32 dst_address, dst_address_length, adj_index, old_adj_index;
- uword *hash, is_del;
-
- /* Either create new adjacency or use given one depending on arguments. */
- if (a->n_add_adj > 0)
- ip_add_adjacency (lm, a->add_adj, a->n_add_adj, &adj_index);
- else
- adj_index = a->adj_index;
-
- dst_address = a->dst_address.data_u32;
- dst_address_length = a->dst_address_length;
-
- fib = pool_elt_at_index (lgm->ip4_src_fibs, a->table_index_or_table_id);
-
- if (!fib->adj_index_by_dst_address[dst_address_length])
- ip4_fib_init_adj_index_by_dst_address (lm, fib, dst_address_length);
-
- hash = fib->adj_index_by_dst_address[dst_address_length];
-
- is_del = (a->flags & IP4_ROUTE_FLAG_DEL) != 0;
-
- if (is_del)
- {
- fib->old_hash_values[0] = ~0;
- hash = _hash_unset (hash, dst_address, fib->old_hash_values);
- fib->adj_index_by_dst_address[dst_address_length] = hash;
- }
- else
- ip4_sd_fib_set_adj_index (lgm, fib, a->flags, dst_address,
- dst_address_length, adj_index);
-
- old_adj_index = fib->old_hash_values[0];
-
- /* Avoid spurious reference count increments */
- if (old_adj_index == adj_index
- && adj_index != ~0 && !(a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY))
- {
- ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index);
- if (adj->share_count > 0)
- adj->share_count--;
- }
-
- ip4_fib_mtrie_add_del_route (fib, a->dst_address, dst_address_length,
- is_del ? old_adj_index : adj_index, is_del);
-
- /* Delete old adjacency index if present and changed. */
- if (!(a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY)
- && old_adj_index != ~0 && old_adj_index != adj_index)
- ip_del_adjacency (lm, old_adj_index);
-}
-
-/** Get src route from IP4 SD FIB. */
-static void *
-ip4_sd_get_src_route (lisp_gpe_main_t * lgm, u32 src_fib_index,
- ip4_address_t * src, u32 address_length)
-{
- ip4_fib_t *fib = pool_elt_at_index (lgm->ip4_src_fibs, src_fib_index);
- uword *hash, *p;
- hash = fib->adj_index_by_dst_address[address_length];
- p = hash_get (hash, src->as_u32);
- return (void *) p;
-}
-
-/* *INDENT-OFF* */
-typedef CLIB_PACKED (struct ip4_route {
- ip4_address_t address;
- u32 address_length : 6;
- u32 index : 26;
-}) ip4_route_t;
-/* *INDENT-ON* */
-
-/** Remove all routes from src IP4 FIB */
-void
-ip4_sd_fib_clear_src_fib (lisp_gpe_main_t * lgm, ip4_fib_t * fib)
-{
- ip4_route_t *routes = 0, *r;
- u32 i;
-
- vec_reset_length (routes);
-
- for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++)
- {
- uword *hash = fib->adj_index_by_dst_address[i];
- hash_pair_t *p;
- ip4_route_t x;
-
- x.address_length = i;
- x.index = 0; /* shut up coverity */
-
- /* *INDENT-OFF* */
- hash_foreach_pair (p, hash,
- ({
- x.address.data_u32 = p->key;
- vec_add1 (routes, x);
- }));
- /* *INDENT-ON* */
- }
-
- vec_foreach (r, routes)
- {
- ip4_add_del_route_args_t a;
-
- memset (&a, 0, sizeof (a));
- a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
- a.table_index_or_table_id = fib - lgm->ip4_src_fibs;
- a.dst_address = r->address;
- a.dst_address_length = r->address_length;
- a.adj_index = ~0;
-
- ip4_sd_fib_add_del_src_route (lgm, &a);
- }
-}
-
-/** Test if IP4 FIB is empty */
-static u8
-ip4_fib_is_empty (ip4_fib_t * fib)
-{
- u8 fib_is_empty;
- int i;
-
- fib_is_empty = 1;
- for (i = ARRAY_LEN (fib->adj_index_by_dst_address) - 1; i >= 0; i--)
- {
- uword *hash = fib->adj_index_by_dst_address[i];
- uword n_elts = hash_elts (hash);
- if (n_elts)
- {
- fib_is_empty = 0;
- break;
- }
- }
- return fib_is_empty;
-}
+#include <vnet/lisp-gpe/lisp_gpe_adjacency.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/fib/fib_entry.h>
+#include <vnet/fib/ip6_fib.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/dpo/lookup_dpo.h>
+#include <vnet/dpo/load_balance.h>
/**
- * @brief Add/del route to IP4 SD FIB.
- *
- * Adds/remove routes to both destination and source FIBs. Entries added
- * to destination FIB are associated to adjacencies that point to the source
- * FIB and store the index of the particular source FIB associated to the
- * destination. Source FIBs are locally managed (see @ref lgm->ip4_src_fibs
- * and @ref lgm->ip6_src_fibs), but the adjacencies are allocated out of the
- * global adjacency pool.
+ * @brief Add route to IP4 or IP6 Destination FIB.
*
- * @param[in] lgm Reference to @ref lisp_gpe_main_t.
- * @param[out] dst_prefix Destination IP4 prefix.
- * @param[in] src_prefix Source IP4 prefix.
- * @param[in] table_id Table id.
- * @param[in] add_adj Pointer to the adjacency to be added.
- * @param[in] is_add Add/del flag.
+ * Add a route to the destination FIB that results in the lookup
+ * in the SRC FIB. The SRC FIB is created is it does not yet exist.
*
- * @return 0 on success.
+ * @param[in] dst_table_id Destination FIB Table-ID
+ * @param[in] dst_prefix Destination IP prefix.
+ * @param[out] src_fib_index The index/ID of the SRC FIB created.
*/
-static int
-ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_id,
- ip_adjacency_t * add_adj, u8 is_add)
-{
- uword *p;
- ip4_add_del_route_args_t a;
- ip_adjacency_t *dst_adjp, dst_adj;
- ip4_address_t dst = ip_prefix_v4 (dst_prefix), src;
- u32 dst_address_length = ip_prefix_len (dst_prefix), src_address_length = 0;
- ip4_fib_t *src_fib;
-
- if (src_prefix)
- {
- src = ip_prefix_v4 (src_prefix);
- src_address_length = ip_prefix_len (src_prefix);
- }
- else
- memset (&src, 0, sizeof (src));
-
- /* lookup dst adj */
- p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8, dst_address_length);
-
- if (is_add)
- {
- /* insert dst prefix to ip4 fib, if it's not in yet */
- if (p == 0)
- {
- /* allocate and init src ip4 fib */
- pool_get (lgm->ip4_src_fibs, src_fib);
- ip4_mtrie_init (&src_fib->mtrie);
-
- /* configure adjacency */
- memset (&dst_adj, 0, sizeof (dst_adj));
-
- /* reuse rewrite header to store pointer to src fib */
- dst_adj.rewrite_header.sw_if_index = src_fib - lgm->ip4_src_fibs;
-
- /* dst adj should point to lisp gpe lookup */
- dst_adj.lookup_next_index = lgm->ip4_lookup_next_lgpe_ip4_lookup;
-
- /* explicit_fib_index is used in IP6 FIB lookup, don't reuse it */
- dst_adj.explicit_fib_index = ~0;
- dst_adj.n_adj = 1;
-
- /* make sure we have different signatures for adj in different tables
- * but with the same lookup_next_index and for adj in the same table
- * but associated to different destinations */
- dst_adj.if_address_index = table_id;
- dst_adj.indirect.next_hop.ip4 = dst;
-
- memset (&a, 0, sizeof (a));
- a.flags = IP4_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = table_id; /* vrf */
- a.adj_index = ~0;
- a.dst_address_length = dst_address_length;
- a.dst_address = dst;
- a.flags |= IP4_ROUTE_FLAG_ADD;
- a.add_adj = &dst_adj;
- a.n_add_adj = 1;
-
- ip4_add_del_route (lgm->im4, &a);
-
- /* lookup dst adj to obtain the adj index */
- p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8,
- dst_address_length);
-
- /* make sure insertion succeeded */
- if (CLIB_DEBUG)
- {
- ASSERT (p != 0);
- dst_adjp = ip_get_adjacency (lgm->lm4, p[0]);
- ASSERT (dst_adjp->rewrite_header.sw_if_index
- == dst_adj.rewrite_header.sw_if_index);
- }
- }
- }
- else
- {
- if (p == 0)
- {
- clib_warning
- ("Trying to delete inexistent dst route for %U. Aborting",
- format_ip4_address_and_length, dst.as_u8, dst_address_length);
- return -1;
- }
- }
-
- dst_adjp = ip_get_adjacency (lgm->lm4, p[0]);
-
- /* add/del src prefix to src fib */
- memset (&a, 0, sizeof (a));
- a.flags = IP4_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = dst_adjp->rewrite_header.sw_if_index;
- a.adj_index = ~0;
- a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL;
- a.add_adj = add_adj;
- a.n_add_adj = is_add ? 1 : 0;
- /* if src prefix is null, add 0/0 */
- a.dst_address_length = src_address_length;
- a.dst_address = src;
- ip4_sd_fib_add_del_src_route (lgm, &a);
-
- /* make sure insertion succeeded */
- if (CLIB_DEBUG && is_add)
- {
- uword *sai;
- ip_adjacency_t *src_adjp;
- sai = ip4_sd_get_src_route (lgm, dst_adjp->rewrite_header.sw_if_index,
- &src, src_address_length);
- ASSERT (sai != 0);
- src_adjp = ip_get_adjacency (lgm->lm4, sai[0]);
- ASSERT (src_adjp->if_address_index == add_adj->if_address_index);
- }
-
- /* if a delete, check if there are elements left in the src fib */
- if (!is_add)
- {
- src_fib = pool_elt_at_index (lgm->ip4_src_fibs,
- dst_adjp->rewrite_header.sw_if_index);
- if (!src_fib)
- return 0;
-
- /* if there's nothing left */
- if (ip4_fib_is_empty (src_fib))
- {
- /* remove the src fib .. */
- pool_put (lgm->ip4_src_fibs, src_fib);
-
- /* .. and remove dst route */
- memset (&a, 0, sizeof (a));
- a.flags = IP4_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = table_id; /* vrf */
- a.adj_index = ~0;
- a.dst_address_length = dst_address_length;
- a.dst_address = dst;
- a.flags |= IP4_ROUTE_FLAG_DEL;
-
- ip4_add_del_route (lgm->im4, &a);
- }
- }
-
- return 0;
-}
-
-/**
- * @brief Retrieve IP4 SD FIB entry.
- *
- * Looks up SD IP4 route by first looking up the destination in VPP's main FIB
- * and subsequently the source in the src FIB. The index of the source FIB is
- * stored in the dst adjacency's rewrite_header.sw_if_index. If source is 0
- * do search with 0/0 src.
- *
- * @param[in] lgm Reference to @ref lisp_gpe_main_t.
- * @param[out] dst_prefix Destination IP4 prefix.
- * @param[in] src_prefix Source IP4 prefix.
- * @param[in] table_id Table id.
- *
- * @return pointer to the adjacency if route found.
- */
-static void *
-ip4_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_id)
-{
- uword *p;
- ip4_address_t dst = ip_prefix_v4 (dst_prefix), src;
- u32 dst_address_length = ip_prefix_len (dst_prefix), src_address_length = 0;
- ip_adjacency_t *dst_adj;
-
- if (src_prefix)
- {
- src = ip_prefix_v4 (src_prefix);
- src_address_length = ip_prefix_len (src_prefix);
- }
- else
- memset (&src, 0, sizeof (src));
-
- /* lookup dst adj */
- p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8, dst_address_length);
- if (p == 0)
- return p;
-
- dst_adj = ip_get_adjacency (lgm->lm4, p[0]);
- return ip4_sd_get_src_route (lgm, dst_adj->rewrite_header.sw_if_index, &src,
- src_address_length);
-}
-
-/** Get src route from IP6 SD FIB. */
-static u32
-ip6_sd_get_src_route (lisp_gpe_main_t * lgm, u32 src_fib_index,
- ip6_address_t * src, u32 address_length)
-{
- int rv;
- BVT (clib_bihash_kv) kv, value;
- ip6_src_fib_t *fib = pool_elt_at_index (lgm->ip6_src_fibs, src_fib_index);
-
- ip6_address_t *mask;
-
- ASSERT (address_length <= 128);
-
- mask = &fib->fib_masks[address_length];
-
- kv.key[0] = src->as_u64[0] & mask->as_u64[0];
- kv.key[1] = src->as_u64[1] & mask->as_u64[1];
- kv.key[2] = address_length;
-
- rv = BV (clib_bihash_search_inline_2) (&fib->ip6_lookup_table, &kv, &value);
- if (rv == 0)
- return value.value;
-
- return 0;
-}
-
-static void
-compute_prefix_lengths_in_search_order (ip6_src_fib_t * fib)
-{
- int i;
- vec_reset_length (fib->prefix_lengths_in_search_order);
- /* Note: bitmap reversed so this is in fact a longest prefix match */
-
- /* *INDENT-OFF* */
- clib_bitmap_foreach(i, fib->non_empty_dst_address_length_bitmap, ({
- int dst_address_length = 128 - i;
- vec_add1 (fib->prefix_lengths_in_search_order, dst_address_length);
- }));
- /* *INDENT-ON* */
-}
-
-/** Add/del src route to IP6 SD FIB. Rewrite of ip6_add_del_route() because
- * it uses im6 to find the FIB .*/
-static void
-ip6_sd_fib_add_del_src_route (lisp_gpe_main_t * lgm,
- ip6_add_del_route_args_t * a)
+u32
+ip_dst_fib_add_route (u32 dst_fib_index, const ip_prefix_t * dst_prefix)
{
- ip_lookup_main_t *lm = lgm->lm6;
- ip6_src_fib_t *fib;
- ip6_address_t dst_address;
- u32 dst_address_length, adj_index;
- uword is_del;
- u32 old_adj_index = ~0;
- BVT (clib_bihash_kv) kv, value;
-
- vlib_smp_unsafe_warning ();
-
- is_del = (a->flags & IP6_ROUTE_FLAG_DEL) != 0;
+ fib_node_index_t src_fib_index;
+ fib_prefix_t dst_fib_prefix;
+ fib_node_index_t dst_fei;
- /* Either create new adjacency or use given one depending on arguments. */
- if (a->n_add_adj > 0)
- {
- ip_add_adjacency (lm, a->add_adj, a->n_add_adj, &adj_index);
- }
- else
- adj_index = a->adj_index;
+ ASSERT (NULL != dst_prefix);
- dst_address = a->dst_address;
- dst_address_length = a->dst_address_length;
- fib = pool_elt_at_index (lgm->ip6_src_fibs, a->table_index_or_table_id);
+ ip_prefix_to_fib_prefix (dst_prefix, &dst_fib_prefix);
- ASSERT (dst_address_length < ARRAY_LEN (fib->fib_masks));
- ip6_address_mask (&dst_address, &fib->fib_masks[dst_address_length]);
+ /*
+ * lookup the destination prefix in the VRF table and retrieve the
+ * LISP associated data
+ */
+ dst_fei = fib_table_lookup_exact_match (dst_fib_index, &dst_fib_prefix);
- /* refcount accounting */
- if (is_del)
+ /*
+ * If the FIB entry is not present, or not LISP sourced, add it
+ */
+ if (dst_fei == FIB_NODE_INDEX_INVALID ||
+ NULL == fib_entry_get_source_data (dst_fei, FIB_SOURCE_LISP))
{
- ASSERT (fib->dst_address_length_refcounts[dst_address_length] > 0);
- if (--fib->dst_address_length_refcounts[dst_address_length] == 0)
- {
- fib->non_empty_dst_address_length_bitmap =
- clib_bitmap_set (fib->non_empty_dst_address_length_bitmap,
- 128 - dst_address_length, 0);
- compute_prefix_lengths_in_search_order (fib);
- }
+ dpo_id_t src_lkup_dpo = DPO_NULL;
+
+ /* create a new src FIB. */
+ src_fib_index =
+ fib_table_create_and_lock (dst_fib_prefix.fp_proto,
+ "LISP-src for [%d,%U]",
+ dst_fib_index,
+ format_fib_prefix, &dst_fib_prefix);
+
+ /*
+ * create a data-path object to perform the source address lookup
+ * in the SRC FIB
+ */
+ lookup_dpo_add_or_lock_w_fib_index (src_fib_index,
+ (ip_prefix_version (dst_prefix) ==
+ IP6 ? DPO_PROTO_IP6 :
+ DPO_PROTO_IP4),
+ LOOKUP_INPUT_SRC_ADDR,
+ LOOKUP_TABLE_FROM_CONFIG,
+ &src_lkup_dpo);
+
+ /*
+ * add the entry to the destination FIB that uses the lookup DPO
+ */
+ dst_fei = fib_table_entry_special_dpo_add (dst_fib_index,
+ &dst_fib_prefix,
+ FIB_SOURCE_LISP,
+ FIB_ENTRY_FLAG_EXCLUSIVE,
+ &src_lkup_dpo);
+
+ /*
+ * the DPO is locked by the FIB entry, and we have no further
+ * need for it.
+ */
+ dpo_unlock (&src_lkup_dpo);
+
+ /*
+ * save the SRC FIB index on the entry so we can retrieve it for
+ * subsequent routes.
+ */
+ fib_entry_set_source_data (dst_fei, FIB_SOURCE_LISP, &src_fib_index);
}
else
{
- fib->dst_address_length_refcounts[dst_address_length]++;
-
- fib->non_empty_dst_address_length_bitmap =
- clib_bitmap_set (fib->non_empty_dst_address_length_bitmap,
- 128 - dst_address_length, 1);
- compute_prefix_lengths_in_search_order (fib);
- }
-
- kv.key[0] = dst_address.as_u64[0];
- kv.key[1] = dst_address.as_u64[1];
- kv.key[2] = dst_address_length;
-
- if (BV (clib_bihash_search) (&fib->ip6_lookup_table, &kv, &value) == 0)
- old_adj_index = value.value;
-
- if (is_del)
- BV (clib_bihash_add_del) (&fib->ip6_lookup_table, &kv, 0 /* is_add */ );
- else
- {
- /* Make sure adj index is valid. */
- if (CLIB_DEBUG > 0)
- (void) ip_get_adjacency (lm, adj_index);
-
- kv.value = adj_index;
-
- BV (clib_bihash_add_del) (&fib->ip6_lookup_table, &kv, 1 /* is_add */ );
+ /*
+ * destination FIB entry already present
+ */
+ src_fib_index = *(u32 *) fib_entry_get_source_data (dst_fei,
+ FIB_SOURCE_LISP);
}
- /* Avoid spurious reference count increments */
- if (old_adj_index == adj_index
- && !(a->flags & IP6_ROUTE_FLAG_KEEP_OLD_ADJACENCY))
- {
- ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index);
- if (adj->share_count > 0)
- adj->share_count--;
- }
-
- /* Delete old adjacency index if present and changed. */
- {
- if (!(a->flags & IP6_ROUTE_FLAG_KEEP_OLD_ADJACENCY)
- && old_adj_index != ~0 && old_adj_index != adj_index)
- ip_del_adjacency (lm, old_adj_index);
- }
-}
-
-static void
-ip6_src_fib_init (ip6_src_fib_t * fib)
-{
- uword i;
-
- for (i = 0; i < ARRAY_LEN (fib->fib_masks); i++)
- {
- u32 j, i0, i1;
-
- i0 = i / 32;
- i1 = i % 32;
-
- for (j = 0; j < i0; j++)
- fib->fib_masks[i].as_u32[j] = ~0;
-
- if (i1)
- fib->fib_masks[i].as_u32[i0] =
- clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
- }
-
- if (fib->lookup_table_nbuckets == 0)
- fib->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
-
- fib->lookup_table_nbuckets = 1 << max_log2 (fib->lookup_table_nbuckets);
-
- if (fib->lookup_table_size == 0)
- fib->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
-
- BV (clib_bihash_init) (&fib->ip6_lookup_table, "ip6 lookup table",
- fib->lookup_table_nbuckets, fib->lookup_table_size);
-
+ return (src_fib_index);
}
/**
- * @brief Add/del route to IP6 SD FIB.
- *
- * Adds/remove routes to both destination and source FIBs. Entries added
- * to destination FIB are associated to adjacencies that point to the source
- * FIB and store the index of the particular source FIB associated to the
- * destination. Source FIBs are locally managed (see @ref lgm->ip4_src_fibs
- * and @ref lgm->ip6_src_fibs), but the adjacencies are allocated out of the
- * global adjacency pool.
+ * @brief Del route to IP4 or IP6 SD FIB.
*
- * @param[in] lgm Reference to @ref lisp_gpe_main_t.
- * @param[out] dst_prefix Destination IP6 prefix.
- * @param[in] src_prefix Source IP6 prefix.
- * @param[in] table_id Table id.
- * @param[in] add_adj Pointer to the adjacency to be added.
- * @param[in] is_add Add/del flag.
+ * Remove routes from both destination and source FIBs.
*
- * @return 0 on success.
+ * @param[in] src_fib_index The index/ID of the SRC FIB
+ * @param[in] src_prefix Source IP prefix.
+ * @param[in] dst_fib_index The index/ID of the DST FIB
+ * @param[in] dst_prefix Destination IP prefix.
*/
-static int
-ip6_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_id,
- ip_adjacency_t * add_adj, u8 is_add)
+void
+ip_src_dst_fib_del_route (u32 src_fib_index,
+ const ip_prefix_t * src_prefix,
+ u32 dst_fib_index, const ip_prefix_t * dst_prefix)
{
- u32 adj_index;
- ip6_add_del_route_args_t a;
- ip_adjacency_t *dst_adjp, dst_adj;
- ip6_address_t dst = ip_prefix_v6 (dst_prefix), src;
- u32 dst_address_length = ip_prefix_len (dst_prefix), src_address_length = 0;
- ip6_src_fib_t *src_fib;
-
- if (src_prefix)
- {
- src = ip_prefix_v6 (src_prefix);
- src_address_length = ip_prefix_len (src_prefix);
- }
- else
- memset (&src, 0, sizeof (src));
-
- /* lookup dst adj and create it if it doesn't exist */
- adj_index = ip6_get_route (lgm->im6, table_id, 0, &dst, dst_address_length);
+ fib_prefix_t dst_fib_prefix, src_fib_prefix;
- if (is_add)
- {
- /* insert dst prefix to ip6 fib, if it's not in yet */
- if (adj_index == 0)
- {
- /* allocate and init src ip6 fib */
- pool_get (lgm->ip6_src_fibs, src_fib);
- memset (src_fib, 0, sizeof (src_fib[0]));
- ip6_src_fib_init (src_fib);
-
- memset (&dst_adj, 0, sizeof (dst_adj));
-
- /* reuse rewrite header to store pointer to src fib */
- dst_adj.rewrite_header.sw_if_index = src_fib - lgm->ip6_src_fibs;
-
- /* dst adj should point to lisp gpe ip lookup */
- dst_adj.lookup_next_index = lgm->ip6_lookup_next_lgpe_ip6_lookup;
-
- /* explicit_fib_index is used in IP6 FIB lookup, don't reuse it */
- dst_adj.explicit_fib_index = ~0;
- dst_adj.n_adj = 1;
-
- /* make sure we have different signatures for adj in different tables
- * but with the same lookup_next_index and for adj in the same table
- * but associated to different destinations */
- dst_adj.if_address_index = table_id;
- dst_adj.indirect.next_hop.ip6 = dst;
-
- memset (&a, 0, sizeof (a));
- a.flags = IP6_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = table_id; /* vrf */
- a.adj_index = ~0;
- a.dst_address_length = dst_address_length;
- a.dst_address = dst;
- a.flags |= IP6_ROUTE_FLAG_ADD;
- a.add_adj = &dst_adj;
- a.n_add_adj = 1;
-
- ip6_add_del_route (lgm->im6, &a);
-
- /* lookup dst adj to obtain the adj index */
- adj_index = ip6_get_route (lgm->im6, table_id, 0, &dst,
- dst_address_length);
-
- /* make sure insertion succeeded */
- if (CLIB_DEBUG)
- {
- ASSERT (adj_index != 0);
- dst_adjp = ip_get_adjacency (lgm->lm6, adj_index);
- ASSERT (dst_adjp->rewrite_header.sw_if_index
- == dst_adj.rewrite_header.sw_if_index);
- }
- }
- }
- else
- {
- if (adj_index == 0)
- {
- clib_warning
- ("Trying to delete inexistent dst route for %U. Aborting",
- format_ip_prefix, dst_prefix);
- return -1;
- }
- }
-
- dst_adjp = ip_get_adjacency (lgm->lm6, adj_index);
-
- /* add/del src prefix to src fib */
- memset (&a, 0, sizeof (a));
- a.flags = IP6_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = dst_adjp->rewrite_header.sw_if_index;
- a.adj_index = ~0;
- a.flags |= is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL;
- a.add_adj = add_adj;
- a.n_add_adj = is_add ? 1 : 0;
- /* if src prefix is null, add ::0 */
- a.dst_address_length = src_address_length;
- a.dst_address = src;
- ip6_sd_fib_add_del_src_route (lgm, &a);
-
- /* make sure insertion succeeded */
- if (CLIB_DEBUG && is_add)
- {
- u32 sai;
- ip_adjacency_t *src_adjp;
- sai = ip6_sd_get_src_route (lgm, dst_adjp->rewrite_header.sw_if_index,
- &src, src_address_length);
- ASSERT (sai != 0);
- src_adjp = ip_get_adjacency (lgm->lm6, sai);
- ASSERT (src_adjp->if_address_index == add_adj->if_address_index);
- }
-
- /* if a delete, check if there are elements left in the src fib */
- if (!is_add)
- {
- src_fib = pool_elt_at_index (lgm->ip6_src_fibs,
- dst_adjp->rewrite_header.sw_if_index);
- if (!src_fib)
- return 0;
-
- /* if there's nothing left */
- if (clib_bitmap_count_set_bits
- (src_fib->non_empty_dst_address_length_bitmap) == 0)
- {
- /* remove src fib .. */
- pool_put (lgm->ip6_src_fibs, src_fib);
+ ASSERT (NULL != dst_prefix);
+ ASSERT (NULL != src_prefix);
- /* .. and remove dst route */
- memset (&a, 0, sizeof (a));
- a.flags = IP6_ROUTE_FLAG_TABLE_ID;
- a.table_index_or_table_id = table_id; /* vrf */
- a.adj_index = ~0;
- a.dst_address_length = dst_address_length;
- a.dst_address = dst;
- a.flags |= IP6_ROUTE_FLAG_DEL;
+ ip_prefix_to_fib_prefix (dst_prefix, &dst_fib_prefix);
+ ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
- ip6_add_del_route (lgm->im6, &a);
- }
- }
-
- return 0;
-}
+ fib_table_entry_delete (src_fib_index, &src_fib_prefix, FIB_SOURCE_LISP);
-/**
- * @brief Retrieve IP6 SD FIB entry.
- *
- * Looks up SD IP6 route by first looking up the destination in VPP's main FIB
- * and subsequently the source in the src FIB. The index of the source FIB is
- * stored in the dst adjacency's @ref rewrite_header.sw_if_index. If source is
- * 0 do search with ::/0 src.
- *
- * @param[in] lgm Reference to @ref lisp_gpe_main_t.
- * @param[out] dst_prefix Destination IP6 prefix.
- * @param[in] src_prefix Source IP6 prefix.
- * @param[in] table_id Table id.
- *
- * @return adjacency index if route found.
- */
-static u32
-ip6_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_id)
-{
- u32 adj_index;
- ip6_address_t dst = ip_prefix_v6 (dst_prefix), src;
- u32 dst_address_length = ip_prefix_len (dst_prefix), src_address_length = 0;
- ip_adjacency_t *dst_adj;
-
- if (src_prefix)
+ if (0 == fib_table_get_num_entries (src_fib_index,
+ src_fib_prefix.fp_proto,
+ FIB_SOURCE_LISP))
{
- src = ip_prefix_v6 (src_prefix);
- src_address_length = ip_prefix_len (src_prefix);
+ /*
+ * there's nothing left, unlock the source FIB and the
+ * destination route
+ */
+ fib_table_entry_special_remove (dst_fib_index,
+ &dst_fib_prefix, FIB_SOURCE_LISP);
+ fib_table_unlock (src_fib_index, src_fib_prefix.fp_proto);
}
- else
- memset (&src, 0, sizeof (src));
-
- /* lookup dst adj */
- adj_index = ip6_get_route (lgm->im6, table_id, 0, &dst, dst_address_length);
- if (adj_index == 0)
- return adj_index;
-
- dst_adj = ip_get_adjacency (lgm->lm6, adj_index);
- return ip6_sd_get_src_route (lgm, dst_adj->rewrite_header.sw_if_index, &src,
- src_address_length);
-}
-
-/**
- * @brief Add/del route to IP4 or IP6 SD FIB.
- *
- * Adds/remove routes to both destination and source FIBs. Entries added
- * to destination FIB are associated to adjacencies that point to the source
- * FIB and store the index of the particular source FIB associated to the
- * destination. Source FIBs are locally managed (see @ref lgm->ip4_src_fibs
- * and @ref lgm->ip6_src_fibs), but the adjacencies are allocated out of the
- * global adjacency pool.
- *
- * @param[in] lgm Reference to @ref lisp_gpe_main_t.
- * @param[out] dst_prefix Destination IP prefix.
- * @param[in] src_prefix Source IP prefix.
- * @param[in] table_id Table id.
- * @param[in] add_adj Pointer to the adjacency to be added.
- * @param[in] is_add Add/del flag.
- *
- * @return 0 on success.
- */
-int
-ip_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_id,
- ip_adjacency_t * add_adj, u8 is_add)
-{
- return (ip_prefix_version (dst_prefix) == IP4 ?
- ip4_sd_fib_add_del_route : ip6_sd_fib_add_del_route) (lgm,
- dst_prefix,
- src_prefix,
- table_id,
- add_adj,
- is_add);
}
/**
- * @brief Retrieve IP4 or IP6 SD FIB entry.
+ * @brief Add route to IP4 or IP6 SRC FIB.
*
- * Looks up SD IP route by first looking up the destination in VPP's main FIB
- * and subsequently the source in the src FIB. The index of the source FIB is
- * stored in the dst adjacency's @ref rewrite_header.sw_if_index. If source is
- * 0 do search with ::/0 src.
+ * Adds a route to in the LISP SRC FIB with the result of the route
+ * being the DPO passed.
*
- * @param[in] lgm Reference to @ref lisp_gpe_main_t.
- * @param[out] dst_prefix Destination IP prefix.
+ * @param[in] src_fib_index The index/ID of the SRC FIB
* @param[in] src_prefix Source IP prefix.
- * @param[in] table_id Table id.
- *
- * @return adjacency index if route found.
+ * @param[in] src_dpo The DPO the route will link to.
*/
-u32
-ip_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_id)
-{
- if (ip_prefix_version (dst_prefix) == IP4)
- {
- u32 *adj_index = ip4_sd_fib_get_route (lgm, dst_prefix, src_prefix,
- table_id);
- return (adj_index == 0) ? 0 : adj_index[0];
- }
- else
- return ip6_sd_fib_get_route (lgm, dst_prefix, src_prefix, table_id);
-}
-
-always_inline void
-ip4_src_fib_lookup_one (lisp_gpe_main_t * lgm, u32 src_fib_index0,
- ip4_address_t * addr0, u32 * src_adj_index0)
-{
- ip4_fib_mtrie_leaf_t leaf0, leaf1;
- ip4_fib_mtrie_t *mtrie0;
-
- /* if default route not hit in ip4 lookup */
- if (PREDICT_TRUE (src_fib_index0 != (u32) ~ 0))
- {
- mtrie0 = &vec_elt_at_index (lgm->ip4_src_fibs, src_fib_index0)->mtrie;
-
- leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
- leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 0);
- leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 1);
- leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2);
- leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3);
-
- /* Handle default route. */
- leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY) ?
- mtrie0->default_leaf : leaf0;
- src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
- }
- else
- src_adj_index0[0] = ~0;
-}
-
-always_inline void
-ip4_src_fib_lookup_two (lisp_gpe_main_t * lgm, u32 src_fib_index0,
- u32 src_fib_index1, ip4_address_t * addr0,
- ip4_address_t * addr1, u32 * src_adj_index0,
- u32 * src_adj_index1)
+void
+ip_src_fib_add_route_w_dpo (u32 src_fib_index,
+ const ip_prefix_t * src_prefix,
+ const dpo_id_t * src_dpo)
{
- ip4_fib_mtrie_leaf_t leaf0, leaf1;
- ip4_fib_mtrie_t *mtrie0, *mtrie1;
-
- /* if default route not hit in ip4 lookup */
- if (PREDICT_TRUE
- (src_fib_index0 != (u32) ~ 0 && src_fib_index1 != (u32) ~ 0))
- {
- mtrie0 = &vec_elt_at_index (lgm->ip4_src_fibs, src_fib_index0)->mtrie;
- mtrie1 = &vec_elt_at_index (lgm->ip4_src_fibs, src_fib_index1)->mtrie;
-
- leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
-
- leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 0);
- leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 0);
+ fib_prefix_t src_fib_prefix;
- leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 1);
- leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 1);
+ ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
- leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2);
- leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 2);
+ /*
+ * add the entry into the source fib.
+ */
+ fib_node_index_t src_fei;
- leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3);
- leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 3);
+ src_fei = fib_table_lookup_exact_match (src_fib_index, &src_fib_prefix);
- /* Handle default route. */
- leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY) ?
- mtrie0->default_leaf : leaf0;
- leaf1 = (leaf1 == IP4_FIB_MTRIE_LEAF_EMPTY) ?
- mtrie1->default_leaf : leaf1;
- src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
- src_adj_index1[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
- }
- else
+ if (FIB_NODE_INDEX_INVALID == src_fei ||
+ !fib_entry_is_sourced (src_fei, FIB_SOURCE_LISP))
{
- ip4_src_fib_lookup_one (lgm, src_fib_index0, addr0, src_adj_index0);
- ip4_src_fib_lookup_one (lgm, src_fib_index1, addr1, src_adj_index1);
+ fib_table_entry_special_dpo_add (src_fib_index,
+ &src_fib_prefix,
+ FIB_SOURCE_LISP,
+ FIB_ENTRY_FLAG_EXCLUSIVE, src_dpo);
}
}
-/**
- * @brief IPv4 src lookup node.
- * @node lgpe-ip4-lookup
- *
- * The LISP IPv4 source lookup dispatch node.
- *
- * This is the IPv4 source lookup dispatch node. It first looks up the
- * adjacency hit in the main (destination) FIB and then uses its
- * <code>rewrite_header.sw_if_index</code>to find the source FIB wherein
- * the source IP is subsequently looked up. Data in the resulting adjacency
- * is used to decide the next node (the lisp_gpe interface) and if a flow
- * hash must be computed, when traffic can be load balanced over multiple
- * tunnels.
- *
- *
- * @param[in] vm vlib_main_t corresponding to current thread.
- * @param[in] node vlib_node_runtime_t data for this node.
- * @param[in] frame vlib_frame_t whose contents should be dispatched.
- *
- * @return number of vectors in frame.
- */
-always_inline uword
-lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * from_frame)
+static void
+ip_address_to_46 (const ip_address_t * addr,
+ ip46_address_t * a, fib_protocol_t * proto)
{
- u32 n_left_from, next_index, *from, *to_next;
- lisp_gpe_main_t *lgm = &lisp_gpe_main;
-
- from = vlib_frame_vector_args (from_frame);
- n_left_from = from_frame->n_vectors;
-
- next_index = node->cached_next_index;
-
- while (n_left_from > 0)
+ *proto = (IP4 == ip_addr_version (addr) ?
+ FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
+ switch (*proto)
{
- 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;
- ip4_header_t *ip0, *ip1;
- u32 dst_adj_index0, src_adj_index0, src_fib_index0;
- u32 dst_adj_index1, src_adj_index1, src_fib_index1;
- ip_adjacency_t *dst_adj0, *src_adj0, *dst_adj1, *src_adj1;
- u32 next0, next1;
-
- next0 = next1 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_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);
-
- ip0 = vlib_buffer_get_current (b0);
- ip1 = vlib_buffer_get_current (b1);
-
- /* dst lookup was done by ip4 lookup */
- dst_adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
- dst_adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
-
- dst_adj0 = ip_get_adjacency (lgm->lm4, dst_adj_index0);
- dst_adj1 = ip_get_adjacency (lgm->lm4, dst_adj_index1);
-
- src_fib_index0 = dst_adj0->rewrite_header.sw_if_index;
- src_fib_index1 = dst_adj1->rewrite_header.sw_if_index;
-
- ip4_src_fib_lookup_two (lgm, src_fib_index0, src_fib_index1,
- &ip0->src_address, &ip1->src_address,
- &src_adj_index0, &src_adj_index1);
-
- /* if a source fib exists */
- if (PREDICT_TRUE ((u32) ~ 0 != src_adj_index0
- && (u32) ~ 0 != src_adj_index1))
- {
- vnet_buffer (b0)->ip.adj_index[VLIB_TX] = src_adj_index0;
- vnet_buffer (b1)->ip.adj_index[VLIB_TX] = src_adj_index1;
-
- src_adj0 = ip_get_adjacency (lgm->lm4, src_adj_index0);
- src_adj1 = ip_get_adjacency (lgm->lm4, src_adj_index1);
-
- next0 = src_adj0->explicit_fib_index;
- next1 = src_adj1->explicit_fib_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;
-
- /* if multipath: saved_lookup_next_index is reused to store
- * nb of sub-tunnels. If greater than 1, multipath is on.
- * Note that flow hash should be 0 after ipx lookup! */
- if (PREDICT_TRUE (src_adj0->saved_lookup_next_index > 1))
- vnet_buffer (b0)->ip.flow_hash =
- ip4_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
-
- if (PREDICT_TRUE (src_adj1->saved_lookup_next_index > 1))
- vnet_buffer (b1)->ip.flow_hash =
- ip4_compute_flow_hash (ip1, IP_FLOW_HASH_DEFAULT);
- }
- else
- {
- if ((u32) ~ 0 != src_adj_index0)
- {
- vnet_buffer (b0)->ip.adj_index[VLIB_TX] = src_adj_index0;
- src_adj0 = ip_get_adjacency (lgm->lm4, src_adj_index0);
- next0 = src_adj0->explicit_fib_index;
- vnet_buffer (b0)->sw_if_index[VLIB_TX] =
- src_adj0->rewrite_header.sw_if_index;
-
- if (PREDICT_TRUE (src_adj0->saved_lookup_next_index > 1))
- vnet_buffer (b0)->ip.flow_hash =
- ip4_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
- }
- else
- {
- next0 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP;
- }
-
- if ((u32) ~ 0 != src_adj_index1)
- {
- vnet_buffer (b1)->ip.adj_index[VLIB_TX] = src_adj_index1;
- src_adj1 = ip_get_adjacency (lgm->lm4, src_adj_index1);
- next1 = src_adj1->explicit_fib_index;
- vnet_buffer (b1)->sw_if_index[VLIB_TX] =
- src_adj1->rewrite_header.sw_if_index;
- if (PREDICT_TRUE (src_adj1->saved_lookup_next_index > 1))
- vnet_buffer (b1)->ip.flow_hash =
- ip4_compute_flow_hash (ip1, IP_FLOW_HASH_DEFAULT);
- }
- else
- {
- next1 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP;
- }
- }
-
- /* mark the packets for CP lookup if needed */
- if (PREDICT_FALSE (LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP == next0))
- vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_IP;
- if (PREDICT_FALSE (LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP == next1))
- vnet_buffer (b1)->lisp.overlay_afi = LISP_AFI_IP;
-
- 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;
- ip4_header_t *ip0;
- u32 bi0, dst_adj_index0, src_adj_index0, src_fib_index0;
- u32 next0 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP;
- ip_adjacency_t *dst_adj0, *src_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);
- ip0 = vlib_buffer_get_current (b0);
-
- /* dst lookup was done by ip4 lookup */
- dst_adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
- dst_adj0 = ip_get_adjacency (lgm->lm4, dst_adj_index0);
- src_fib_index0 = dst_adj0->rewrite_header.sw_if_index;
-
- /* do src lookup */
- ip4_src_fib_lookup_one (lgm, src_fib_index0, &ip0->src_address,
- &src_adj_index0);
-
- /* if a source fib exists */
- if (PREDICT_TRUE ((u32) ~ 0 != src_adj_index0))
- {
- vnet_buffer (b0)->ip.adj_index[VLIB_TX] = src_adj_index0;
- src_adj0 = ip_get_adjacency (lgm->lm4, src_adj_index0);
- next0 = src_adj0->explicit_fib_index;
-
- /* prepare packet for lisp-gpe output node */
- vnet_buffer (b0)->sw_if_index[VLIB_TX] =
- src_adj0->rewrite_header.sw_if_index;
-
- /* if multipath: saved_lookup_next_index is reused to store
- * nb of sub-tunnels. If greater than 1, multipath is on */
- if (PREDICT_TRUE (src_adj0->saved_lookup_next_index > 1))
- vnet_buffer (b0)->ip.flow_hash =
- ip4_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
- }
- else
- {
- next0 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP;
- }
-
- if (PREDICT_FALSE (LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP == next0))
- vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_IP;
-
- 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);
+ case FIB_PROTOCOL_IP4:
+ a->ip4 = addr->ip.v4;
+ break;
+ case FIB_PROTOCOL_IP6:
+ a->ip6 = addr->ip.v6;
+ break;
+ default:
+ ASSERT (0);
+ break;
}
- return from_frame->n_vectors;
}
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (lgpe_ip4_lookup_node) = {
- .function = lgpe_ip4_lookup,
- .name = "lgpe-ip4-lookup",
- .vector_size = sizeof (u32),
-
- .type = VLIB_NODE_TYPE_INTERNAL,
-
- .n_next_nodes = LGPE_IP4_LOOKUP_N_NEXT,
- .next_nodes = {
-#define _(sym,str) [LGPE_IP4_LOOKUP_NEXT_##sym] = str,
- foreach_lgpe_ip4_lookup_next
-#undef _
- },
-};
-/* *INDENT-ON* */
-
-static u32
-ip6_src_fib_lookup (lisp_gpe_main_t * lgm, u32 src_fib_index,
- ip6_address_t * src)
+static fib_route_path_t *
+ip_src_fib_mk_paths (const lisp_fwd_path_t * paths)
{
- int i, len;
- int rv;
- BVT (clib_bihash_kv) kv, value;
- ip6_src_fib_t *fib = pool_elt_at_index (lgm->ip6_src_fibs, src_fib_index);
+ const lisp_gpe_adjacency_t *ladj;
+ fib_route_path_t *rpaths = NULL;
+ u8 best_priority;
+ u32 ii;
- len = vec_len (fib->prefix_lengths_in_search_order);
+ vec_validate (rpaths, vec_len (paths) - 1);
- for (i = 0; i < len; i++)
- {
- int dst_address_length = fib->prefix_lengths_in_search_order[i];
- ip6_address_t *mask;
+ best_priority = paths[0].priority;
- ASSERT (dst_address_length >= 0 && dst_address_length <= 128);
+ vec_foreach_index (ii, paths)
+ {
+ if (paths[0].priority != best_priority)
+ break;
- mask = &fib->fib_masks[dst_address_length];
+ ladj = lisp_gpe_adjacency_get (paths[ii].lisp_adj);
- kv.key[0] = src->as_u64[0] & mask->as_u64[0];
- kv.key[1] = src->as_u64[1] & mask->as_u64[1];
- kv.key[2] = dst_address_length;
+ ip_address_to_46 (&ladj->remote_rloc,
+ &rpaths[ii].frp_addr, &rpaths[ii].frp_proto);
- rv =
- BV (clib_bihash_search_inline_2) (&fib->ip6_lookup_table, &kv,
- &value);
- if (rv == 0)
- return value.value;
- }
-
- return 0;
-}
+ rpaths[ii].frp_sw_if_index = ladj->sw_if_index;
+ rpaths[ii].frp_weight = (paths[ii].weight ? paths[ii].weight : 1);
+ rpaths[ii].frp_label = MPLS_LABEL_INVALID;
+ }
-always_inline void
-ip6_src_fib_lookup_one (lisp_gpe_main_t * lgm, u32 src_fib_index0,
- ip6_address_t * addr0, u32 * src_adj_index0)
-{
- /* if default route not hit in ip6 lookup */
- if (PREDICT_TRUE (src_fib_index0 != (u32) ~ 0))
- src_adj_index0[0] = ip6_src_fib_lookup (lgm, src_fib_index0, addr0);
- else
- src_adj_index0[0] = ~0;
-}
+ ASSERT (0 != vec_len (rpaths));
-always_inline void
-ip6_src_fib_lookup_two (lisp_gpe_main_t * lgm, u32 src_fib_index0,
- u32 src_fib_index1, ip6_address_t * addr0,
- ip6_address_t * addr1, u32 * src_adj_index0,
- u32 * src_adj_index1)
-{
- /* if default route not hit in ip6 lookup */
- if (PREDICT_TRUE
- (src_fib_index0 != (u32) ~ 0 && src_fib_index1 != (u32) ~ 0))
- {
- src_adj_index0[0] = ip6_src_fib_lookup (lgm, src_fib_index0, addr0);
- src_adj_index1[0] = ip6_src_fib_lookup (lgm, src_fib_index1, addr1);
- }
- else
- {
- ip6_src_fib_lookup_one (lgm, src_fib_index0, addr0, src_adj_index0);
- ip6_src_fib_lookup_one (lgm, src_fib_index1, addr1, src_adj_index1);
- }
+ return (rpaths);
}
/**
- * @brief IPv6 src lookup node.
- * @node lgpe-ip6-lookup
- *
- * The LISP IPv6 source lookup dispatch node.
+ * @brief Add route to IP4 or IP6 SRC FIB.
*
- * This is the IPv6 source lookup dispatch node. It first looks up the
- * adjacency hit in the main (destination) FIB and then uses its
- * <code>rewrite_header.sw_if_index</code>to find the source FIB wherein
- * the source IP is subsequently looked up. Data in the resulting adjacency
- * is used to decide the next node (the lisp_gpe interface) and if a flow
- * hash must be computed, when traffic can be load balanced over multiple
- * tunnels.
+ * Adds a route to in the LISP SRC FIB for the tunnel.
*
- * @param[in] vm vlib_main_t corresponding to current thread.
- * @param[in] node vlib_node_runtime_t data for this node.
- * @param[in] frame vlib_frame_t whose contents should be dispatched.
- *
- * @return number of vectors in frame.
+ * @param[in] src_fib_index The index/ID of the SRC FIB
+ * @param[in] src_prefix Source IP prefix.
+ * @param[in] paths The paths from which to construct the
+ * load balance
*/
-always_inline uword
-lgpe_ip6_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * from_frame)
+void
+ip_src_fib_add_route (u32 src_fib_index,
+ const ip_prefix_t * src_prefix,
+ const lisp_fwd_path_t * paths)
{
- u32 n_left_from, next_index, *from, *to_next;
- lisp_gpe_main_t *lgm = &lisp_gpe_main;
-
- from = vlib_frame_vector_args (from_frame);
- n_left_from = from_frame->n_vectors;
-
- next_index = node->cached_next_index;
-
- while (n_left_from > 0)
- {
- u32 n_left_to_next;
-
- vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
- while (n_left_from >= 4 && n_left_to_next >= 2)
- {
- u32 bi0, bi1;
- vlib_buffer_t *b0, *b1;
- ip6_header_t *ip0, *ip1;
- u32 dst_adj_index0, src_adj_index0, src_fib_index0, dst_adj_index1,
- src_adj_index1, src_fib_index1;
- ip_adjacency_t *dst_adj0, *src_adj0, *dst_adj1, *src_adj1;
- u32 next0, next1;
-
- next0 = next1 = LGPE_IP6_LOOKUP_NEXT_LISP_CP_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);
-
- ip0 = vlib_buffer_get_current (b0);
- ip1 = vlib_buffer_get_current (b1);
-
- /* dst lookup was done by ip6 lookup */
- dst_adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
- dst_adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
-
- dst_adj0 = ip_get_adjacency (lgm->lm6, dst_adj_index0);
- dst_adj1 = ip_get_adjacency (lgm->lm6, dst_adj_index1);
-
- src_fib_index0 = dst_adj0->rewrite_header.sw_if_index;
- src_fib_index1 = dst_adj1->rewrite_header.sw_if_index;
-
- ip6_src_fib_lookup_two (lgm, src_fib_index0, src_fib_index1,
- &ip0->src_address, &ip1->src_address,
- &src_adj_index0, &src_adj_index1);
-
- /* if a source fib exists */
- if (PREDICT_TRUE ((u32) ~ 0 != src_adj_index0
- && (u32) ~ 0 != src_adj_index1))
- {
- vnet_buffer (b0)->ip.adj_index[VLIB_TX] = src_adj_index0;
- vnet_buffer (b1)->ip.adj_index[VLIB_TX] = src_adj_index1;
+ fib_prefix_t src_fib_prefix;
+ fib_route_path_t *rpaths;
- src_adj0 = ip_get_adjacency (lgm->lm6, src_adj_index0);
- src_adj1 = ip_get_adjacency (lgm->lm6, src_adj_index1);
+ ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
- next0 = src_adj0->explicit_fib_index;
- next1 = src_adj1->explicit_fib_index;
+ rpaths = ip_src_fib_mk_paths (paths);
- /* 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;
-
- /* if multipath: saved_lookup_next_index is reused to store
- * nb of sub-tunnels. If greater than 1, multipath is on.
- * Note that flow hash should be 0 after ipx lookup! */
- if (PREDICT_TRUE (src_adj0->saved_lookup_next_index > 1))
- vnet_buffer (b0)->ip.flow_hash =
- ip6_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
-
- if (PREDICT_TRUE (src_adj1->saved_lookup_next_index > 1))
- vnet_buffer (b1)->ip.flow_hash =
- ip6_compute_flow_hash (ip1, IP_FLOW_HASH_DEFAULT);
- }
- else
- {
- if (src_adj_index0 != (u32) ~ 0)
- {
- vnet_buffer (b0)->ip.adj_index[VLIB_TX] = src_adj_index0;
- src_adj0 = ip_get_adjacency (lgm->lm6, src_adj_index0);
- next0 = src_adj0->explicit_fib_index;
- vnet_buffer (b0)->sw_if_index[VLIB_TX] =
- src_adj0->rewrite_header.sw_if_index;
-
- if (PREDICT_TRUE (src_adj0->saved_lookup_next_index > 1))
- vnet_buffer (b0)->ip.flow_hash =
- ip6_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
- }
- else
- {
- next0 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP;
- }
-
- if (src_adj_index1 != (u32) ~ 0)
- {
- vnet_buffer (b1)->ip.adj_index[VLIB_TX] = src_adj_index1;
- src_adj1 = ip_get_adjacency (lgm->lm6, src_adj_index1);
- next1 = src_adj1->explicit_fib_index;
- vnet_buffer (b1)->sw_if_index[VLIB_TX] =
- src_adj1->rewrite_header.sw_if_index;
-
- if (PREDICT_TRUE (src_adj1->saved_lookup_next_index > 1))
- vnet_buffer (b1)->ip.flow_hash =
- ip6_compute_flow_hash (ip1, IP_FLOW_HASH_DEFAULT);
- }
- else
- {
- next1 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP;
- }
- }
-
- /* mark the packets for CP lookup if needed */
- if (PREDICT_FALSE (LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP == next0))
- vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_IP;
- if (PREDICT_FALSE (LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP == next1))
- vnet_buffer (b1)->lisp.overlay_afi = LISP_AFI_IP;
-
- 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;
- ip6_header_t *ip0;
- u32 bi0, dst_adj_index0, src_adj_index0, src_fib_index0;
- u32 next0 = LGPE_IP6_LOOKUP_NEXT_LISP_CP_LOOKUP;
- ip_adjacency_t *dst_adj0, *src_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);
- ip0 = vlib_buffer_get_current (b0);
-
- /* dst lookup was done by ip6 lookup */
- dst_adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
- dst_adj0 = ip_get_adjacency (lgm->lm6, dst_adj_index0);
- src_fib_index0 = dst_adj0->rewrite_header.sw_if_index;
-
- /* do src lookup */
- ip6_src_fib_lookup_one (lgm, src_fib_index0, &ip0->src_address,
- &src_adj_index0);
-
- /* if a source fib exists */
- if (PREDICT_TRUE (src_adj_index0 != (u32) ~ 0))
- {
- vnet_buffer (b0)->ip.adj_index[VLIB_TX] = src_adj_index0;
- src_adj0 = ip_get_adjacency (lgm->lm6, src_adj_index0);
- next0 = src_adj0->explicit_fib_index;
-
- /* prepare packet for lisp-gpe output node */
- vnet_buffer (b0)->sw_if_index[VLIB_TX] =
- src_adj0->rewrite_header.sw_if_index;
-
- /* if multipath: saved_lookup_next_index is reused to store
- * nb of sub-tunnels. If greater than 1, multipath is on */
- if (PREDICT_TRUE (src_adj0->saved_lookup_next_index > 1))
- vnet_buffer (b0)->ip.flow_hash =
- ip6_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
- }
- else
- {
- next0 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP;
- }
-
- /* mark the packets for CP lookup if needed */
- if (PREDICT_FALSE (LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP == next0))
- vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_IP;
-
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
- n_left_to_next, bi0, next0);
- }
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- }
- return from_frame->n_vectors;
+ fib_table_entry_update (src_fib_index,
+ &src_fib_prefix,
+ FIB_SOURCE_LISP, FIB_ENTRY_FLAG_NONE, rpaths);
+ vec_free (rpaths);
}
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (lgpe_ip6_lookup_node) = {
- .function = lgpe_ip6_lookup,
- .name = "lgpe-ip6-lookup",
- .vector_size = sizeof (u32),
-
- .type = VLIB_NODE_TYPE_INTERNAL,
-
- .n_next_nodes = LGPE_IP6_LOOKUP_N_NEXT,
- .next_nodes = {
-#define _(sym,str) [LGPE_IP6_LOOKUP_NEXT_##sym] = str,
- foreach_lgpe_ip6_lookup_next
-#undef _
- },
-};
-/* *INDENT-ON* */
-
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe.c b/vnet/vnet/lisp-gpe/lisp_gpe.c
index 579422b4..f05c6a20 100644
--- a/vnet/vnet/lisp-gpe/lisp_gpe.c
+++ b/vnet/vnet/lisp-gpe/lisp_gpe.c
@@ -19,435 +19,230 @@
*/
#include <vnet/lisp-gpe/lisp_gpe.h>
-#include <vppinfra/math.h>
+#include <vnet/lisp-gpe/lisp_gpe_adjacency.h>
+#include <vnet/adj/adj_midchain.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/fib/fib_entry.h>
+#include <vnet/fib/fib_path_list.h>
+#include <vnet/dpo/drop_dpo.h>
+#include <vnet/dpo/load_balance.h>
/** LISP-GPE global state */
lisp_gpe_main_t lisp_gpe_main;
/**
- * @brief Compute IP-UDP-GPE sub-tunnel encap/rewrite header.
- *
- * @param[in] t Parent of the sub-tunnel.
- * @param[in] st Sub-tunnel.
- * @param[in] lp Local and remote locators used in the encap header.
- *
- * @return 0 on success.
+ * @brief A Pool of all LISP forwarding entries
*/
-static int
-lisp_gpe_rewrite (lisp_gpe_tunnel_t * t, lisp_gpe_sub_tunnel_t * st,
- locator_pair_t * lp)
-{
- u8 *rw = 0;
- lisp_gpe_header_t *lisp0;
- int len;
-
- if (ip_addr_version (&lp->lcl_loc) == IP4)
- {
- ip4_header_t *ip0;
- ip4_udp_lisp_gpe_header_t *h0;
- len = sizeof (*h0);
+static lisp_fwd_entry_t *lisp_fwd_entry_pool;
- vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
+/**
+ * DB of all forwarding entries. The Key is:{l-EID,r-EID,vni}
+ * where the EID encodes L2 or L3
+ */
+static uword *lisp_gpe_fwd_entries;
- h0 = (ip4_udp_lisp_gpe_header_t *) rw;
+static void
+create_fib_entries (lisp_fwd_entry_t * lfe)
+{
+ dpo_proto_t dproto;
- /* Fixed portion of the (outer) ip4 header */
- ip0 = &h0->ip4;
- ip0->ip_version_and_header_length = 0x45;
- ip0->ttl = 254;
- ip0->protocol = IP_PROTOCOL_UDP;
+ dproto = (ip_prefix_version (&lfe->key->rmt.ippref) == IP4 ?
+ FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
- /* we fix up the ip4 header length and checksum after-the-fact */
- ip_address_copy_addr (&ip0->src_address, &lp->lcl_loc);
- ip_address_copy_addr (&ip0->dst_address, &lp->rmt_loc);
- ip0->checksum = ip4_header_checksum (ip0);
+ lfe->src_fib_index = ip_dst_fib_add_route (lfe->eid_fib_index,
+ &lfe->key->rmt.ippref);
- /* UDP header, randomize src port on something, maybe? */
- h0->udp.src_port = clib_host_to_net_u16 (4341);
- h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe);
+ if (LISP_FWD_ENTRY_TYPE_NEGATIVE == lfe->type)
+ {
+ dpo_id_t dpo = DPO_NULL;
- /* LISP-gpe header */
- lisp0 = &h0->lisp;
+ switch (lfe->action)
+ {
+ case LISP_NO_ACTION:
+ /* TODO update timers? */
+ case LISP_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 LISP_SEND_MAP_REQUEST:
+ /* insert tunnel that always sends map-request */
+ dpo_set (&dpo, DPO_LISP_CP, 0, dproto);
+ break;
+ case LISP_DROP:
+ /* for drop fwd entries, just add route, no need to add encap tunnel */
+ dpo_copy (&dpo, drop_dpo_get (dproto));
+ break;
+ }
+ ip_src_fib_add_route_w_dpo (lfe->src_fib_index,
+ &lfe->key->lcl.ippref, &dpo);
+ dpo_reset (&dpo);
}
else
{
- ip6_header_t *ip0;
- ip6_udp_lisp_gpe_header_t *h0;
- len = sizeof (*h0);
-
- vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
-
- h0 = (ip6_udp_lisp_gpe_header_t *) rw;
-
- /* Fixed portion of the (outer) ip6 header */
- ip0 = &h0->ip6;
- ip0->ip_version_traffic_class_and_flow_label =
- clib_host_to_net_u32 (0x6 << 28);
- ip0->hop_limit = 254;
- ip0->protocol = IP_PROTOCOL_UDP;
-
- /* we fix up the ip6 header length after-the-fact */
- ip_address_copy_addr (&ip0->src_address, &lp->lcl_loc);
- ip_address_copy_addr (&ip0->dst_address, &lp->rmt_loc);
-
- /* UDP header, randomize src port on something, maybe? */
- h0->udp.src_port = clib_host_to_net_u16 (4341);
- h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe);
-
- /* LISP-gpe header */
- lisp0 = &h0->lisp;
+ ip_src_fib_add_route (lfe->src_fib_index,
+ &lfe->key->lcl.ippref, lfe->paths);
}
-
- lisp0->flags = t->flags;
- lisp0->ver_res = t->ver_res;
- lisp0->res = t->res;
- lisp0->next_protocol = t->next_protocol;
- lisp0->iid = clib_host_to_net_u32 (t->vni);
-
- st->is_ip4 = ip_addr_version (&lp->lcl_loc) == IP4;
- st->rewrite = rw;
- return 0;
}
-static int
-weight_cmp (normalized_sub_tunnel_weights_t * a,
- normalized_sub_tunnel_weights_t * b)
+static void
+delete_fib_entries (lisp_fwd_entry_t * lfe)
{
- int cmp = a->weight - b->weight;
- return (cmp == 0
- ? a->sub_tunnel_index - b->sub_tunnel_index : (cmp > 0 ? -1 : 1));
+ ip_src_dst_fib_del_route (lfe->src_fib_index,
+ &lfe->key->lcl.ippref,
+ lfe->eid_fib_index, &lfe->key->rmt.ippref);
}
-/**
- * @brief Computes sub-tunnel load balancing vector.
- *
- * Algorithm is identical to that used for building unequal-cost multipath
- * adjacencies. Saves normalized sub-tunnel weights and builds load-balancing
- * vector consisting of list of sub-tunnel indexes replicated according to
- * weight.
- *
- * @param[in] t Tunnel for which load balancing vector is computed.
- */
static void
-compute_sub_tunnels_balancing_vector (lisp_gpe_tunnel_t * t)
+gid_to_dp_address (gid_address_t * g, dp_address_t * d)
{
- uword n_sts, i, n_nsts, n_nsts_left;
- f64 sum_weight, norm, error, tolerance;
- normalized_sub_tunnel_weights_t *nsts = 0, *stp;
- lisp_gpe_sub_tunnel_t *sts = t->sub_tunnels;
- u32 *st_lbv = 0;
-
- /* Accept 1% error */
- tolerance = .01;
-
- n_sts = vec_len (sts);
- vec_validate (nsts, 2 * n_sts - 1);
-
- sum_weight = 0;
- for (i = 0; i < n_sts; i++)
+ switch (gid_address_type (g))
{
- /* Find total weight to normalize weights. */
- sum_weight += sts[i].weight;
-
- /* build normalized sub tunnels vector */
- nsts[i].weight = sts[i].weight;
- nsts[i].sub_tunnel_index = i;
- }
-
- n_nsts = n_sts;
- if (n_sts == 1)
- {
- nsts[0].weight = 1;
- _vec_len (nsts) = 1;
- goto build_lbv;
+ case GID_ADDR_IP_PREFIX:
+ case GID_ADDR_SRC_DST:
+ ip_prefix_copy (&d->ippref, &gid_address_ippref (g));
+ d->type = FID_ADDR_IP_PREF;
+ break;
+ case GID_ADDR_MAC:
+ default:
+ mac_copy (&d->mac, &gid_address_mac (g));
+ d->type = FID_ADDR_MAC;
+ break;
}
+}
- /* Sort sub-tunnels by weight */
- qsort (nsts, n_nsts, sizeof (u32), (void *) weight_cmp);
+static lisp_fwd_entry_t *
+find_fwd_entry (lisp_gpe_main_t * lgm,
+ vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
+ lisp_gpe_fwd_entry_key_t * key)
+{
+ uword *p;
- /* Save copies of all next hop weights to avoid being overwritten in loop below. */
- for (i = 0; i < n_nsts; i++)
- nsts[n_nsts + i].weight = nsts[i].weight;
+ memset (key, 0, sizeof (*key));
- /* Try larger and larger power of 2 sized blocks until we
- find one where traffic flows to within 1% of specified weights. */
- for (n_nsts = max_pow2 (n_sts);; n_nsts *= 2)
+ if (GID_ADDR_IP_PREFIX == gid_address_type (&a->rmt_eid))
{
- error = 0;
-
- norm = n_nsts / sum_weight;
- n_nsts_left = n_nsts;
- for (i = 0; i < n_sts; i++)
- {
- f64 nf = nsts[n_sts + i].weight * norm;
- word n = flt_round_nearest (nf);
-
- n = n > n_nsts_left ? n_nsts_left : n;
- n_nsts_left -= n;
- error += fabs (nf - n);
- nsts[i].weight = n;
- }
-
- nsts[0].weight += n_nsts_left;
-
- /* Less than 5% average error per adjacency with this size adjacency block? */
- if (error <= tolerance * n_nsts)
- {
- /* Truncate any next hops with zero weight. */
- _vec_len (nsts) = i;
- break;
- }
+ /*
+ * the ip version of the source is not set to ip6 when the
+ * source is all zeros. force it.
+ */
+ ip_prefix_version (&gid_address_ippref (&a->lcl_eid)) =
+ ip_prefix_version (&gid_address_ippref (&a->rmt_eid));
}
-build_lbv:
+ gid_to_dp_address (&a->rmt_eid, &key->rmt);
+ gid_to_dp_address (&a->lcl_eid, &key->lcl);
+ key->vni = a->vni;
- /* build load balancing vector */
- vec_foreach (stp, nsts)
- {
- for (i = 0; i < stp[0].weight; i++)
- vec_add1 (st_lbv, stp[0].sub_tunnel_index);
- }
+ p = hash_get_mem (lisp_gpe_fwd_entries, key);
- t->sub_tunnels_lbv = st_lbv;
- t->sub_tunnels_lbv_count = n_nsts;
- t->norm_sub_tunnel_weights = nsts;
+ if (NULL != p)
+ {
+ return (pool_elt_at_index (lisp_fwd_entry_pool, p[0]));
+ }
+ return (NULL);
}
-/** Create sub-tunnels and load-balancing vector for all locator pairs
- * associated to a tunnel.*/
-static void
-create_sub_tunnels (lisp_gpe_main_t * lgm, lisp_gpe_tunnel_t * t)
+static int
+lisp_gpe_fwd_entry_path_sort (void *a1, void *a2)
{
- lisp_gpe_sub_tunnel_t st;
- locator_pair_t *lp = 0;
- int i;
-
- /* create sub-tunnels for all locator pairs */
- for (i = 0; i < vec_len (t->locator_pairs); i++)
- {
- lp = &t->locator_pairs[i];
- st.locator_pair_index = i;
- st.parent_index = t - lgm->tunnels;
- st.weight = lp->weight;
-
- /* compute rewrite for sub-tunnel */
- lisp_gpe_rewrite (t, &st, lp);
- vec_add1 (t->sub_tunnels, st);
- }
+ lisp_fwd_path_t *p1 = a1, *p2 = a2;
- /* normalize weights and compute sub-tunnel load balancing vector */
- compute_sub_tunnels_balancing_vector (t);
+ return (p1->priority - p2->priority);
}
-#define foreach_copy_field \
-_(encap_fib_index) \
-_(decap_fib_index) \
-_(decap_next_index) \
-_(vni) \
-_(action)
-
/**
- * @brief Create/delete IP encapsulated tunnel.
+ * @brief Add/Delete LISP IP forwarding entry.
*
- * Builds GPE tunnel for L2 or L3 packets and populates tunnel pool
- * @ref lisp_gpe_tunnel_by_key in @ref lisp_gpe_main_t.
+ * creation of forwarding entries for IP LISP overlay:
*
- * @param[in] a Tunnel parameters.
- * @param[in] is_l2 Flag indicating if encapsulated content is l2.
- * @param[out] tun_index_res Tunnel index.
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] a Parameters for building the forwarding entry.
*
* @return 0 on success.
*/
static int
-add_del_ip_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, u8 is_l2,
- u32 * tun_index_res)
+add_ip_fwd_entry (lisp_gpe_main_t * lgm,
+ vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
{
- lisp_gpe_main_t *lgm = &lisp_gpe_main;
- lisp_gpe_tunnel_t *t = 0;
- lisp_gpe_tunnel_key_t key;
- lisp_gpe_sub_tunnel_t *stp = 0;
- uword *p;
-
- /* prepare tunnel key */
- memset (&key, 0, sizeof (key));
-
- /* fill in the key's remote eid */
- if (!is_l2)
- ip_prefix_copy (&key.rmt.ippref, &gid_address_ippref (&a->rmt_eid));
- else
- mac_copy (&key.rmt.mac, &gid_address_mac (&a->rmt_eid));
-
- key.vni = clib_host_to_net_u32 (a->vni);
-
- p = mhash_get (&lgm->lisp_gpe_tunnel_by_key, &key);
-
- if (a->is_add)
- {
- /* adding a tunnel: tunnel must not already exist */
- if (p)
- return VNET_API_ERROR_INVALID_VALUE;
-
- if (a->decap_next_index >= LISP_GPE_INPUT_N_NEXT)
- return VNET_API_ERROR_INVALID_DECAP_NEXT;
+ lisp_gpe_fwd_entry_key_t key;
+ lisp_fwd_entry_t *lfe;
+ fib_protocol_t fproto;
- pool_get_aligned (lgm->tunnels, t, CLIB_CACHE_LINE_BYTES);
- memset (t, 0, sizeof (*t));
+ lfe = find_fwd_entry (lgm, a, &key);
- /* copy from arg structure */
-#define _(x) t->x = a->x;
- foreach_copy_field;
-#undef _
+ if (NULL != lfe)
+ /* don't support updates */
+ return VNET_API_ERROR_INVALID_VALUE;
- t->locator_pairs = vec_dup (a->locator_pairs);
+ pool_get (lisp_fwd_entry_pool, lfe);
+ memset (lfe, 0, sizeof (*lfe));
+ lfe->key = clib_mem_alloc (sizeof (key));
+ memcpy (lfe->key, &key, sizeof (key));
- /* if vni is non-default */
- if (a->vni)
- t->flags = LISP_GPE_FLAGS_I;
+ hash_set_mem (lisp_gpe_fwd_entries, lfe->key, lfe - lisp_fwd_entry_pool);
- /* work in lisp-gpe not legacy mode */
- t->flags |= LISP_GPE_FLAGS_P;
+ fproto = (IP4 == ip_prefix_version (&fid_addr_ippref (&lfe->key->rmt)) ?
+ FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
- /* next proto */
- if (!is_l2)
- t->next_protocol = ip_prefix_version (&key.rmt.ippref) == IP4 ?
- LISP_GPE_NEXT_PROTO_IP4 : LISP_GPE_NEXT_PROTO_IP6;
- else
- t->next_protocol = LISP_GPE_NEXT_PROTO_ETHERNET;
-
- /* build sub-tunnels for lowest priority locator-pairs */
- if (!a->is_negative)
- create_sub_tunnels (lgm, t);
-
- mhash_set (&lgm->lisp_gpe_tunnel_by_key, &key, t - lgm->tunnels, 0);
+ lfe->type = (a->is_negative ?
+ LISP_FWD_ENTRY_TYPE_NEGATIVE : LISP_FWD_ENTRY_TYPE_NORMAL);
+ lfe->eid_table_id = a->table_id;
+ lfe->eid_fib_index = fib_table_find_or_create_and_lock (fproto,
+ lfe->eid_table_id);
- /* return tunnel index */
- if (tun_index_res)
- tun_index_res[0] = t - lgm->tunnels;
- }
- else
+ if (LISP_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
{
- /* deleting a tunnel: tunnel must exist */
- if (!p)
- {
- clib_warning ("Tunnel for eid %U doesn't exist!",
- format_gid_address, &a->rmt_eid);
- return VNET_API_ERROR_NO_SUCH_ENTRY;
- }
-
- t = pool_elt_at_index (lgm->tunnels, p[0]);
+ lisp_fwd_path_t *path;
+ u32 index;
- mhash_unset (&lgm->lisp_gpe_tunnel_by_key, &key, 0);
+ vec_validate (lfe->paths, vec_len (a->locator_pairs) - 1);
- vec_foreach (stp, t->sub_tunnels)
+ vec_foreach_index (index, a->locator_pairs)
{
- vec_free (stp->rewrite);
+ path = &lfe->paths[index];
+
+ path->priority = a->locator_pairs[index].priority;
+ path->weight = a->locator_pairs[index].weight;
+
+ path->lisp_adj =
+ lisp_gpe_adjacency_find_or_create_and_lock (&a->locator_pairs
+ [index],
+ lfe->eid_table_id,
+ lfe->key->vni);
}
- vec_free (t->sub_tunnels);
- vec_free (t->sub_tunnels_lbv);
- vec_free (t->locator_pairs);
- pool_put (lgm->tunnels, t);
+ vec_sort_with_function (lfe->paths, lisp_gpe_fwd_entry_path_sort);
}
- return 0;
+ create_fib_entries (lfe);
+
+ return (0);
}
-/**
- * @brief Build IP adjacency for LISP Source/Dest FIB.
- *
- * Because LISP forwarding does not follow typical IP forwarding path, the
- * adjacency's fields are overloaded (i.e., hijacked) to carry LISP specific
- * data concerning the lisp-gpe interface the packets hitting the adjacency
- * should be sent to and the tunnel that should be used.
- *
- * @param[in] lgm Reference to @ref lisp_gpe_main_t.
- * @param[out] adj Adjacency to be populated.
- * @param[in] table_id VRF for adjacency.
- * @param[in] vni Virtual Network identifier (tenant id).
- * @param[in] tun_index Tunnel index.
- * @param[in] n_sub_tun Number of sub-tunnels.
- * @param[in] is_negative Flag to indicate if the adjacency is for a
- * negative mapping.
- * @param[in] action Action to be taken for negative mapping.
- * @param[in] ip_ver IP version for the adjacency.
- *
- * @return 0 on success.
- */
-static int
-build_ip_adjacency (lisp_gpe_main_t * lgm, ip_adjacency_t * adj, u32 table_id,
- u32 vni, u32 tun_index, u32 n_sub_tun, u8 is_negative,
- u8 action, u8 ip_ver)
+static void
+del_ip_fwd_entry_i (lisp_fwd_entry_t * lfe)
{
- uword *lookup_next_index, *lgpe_sw_if_index, *lnip;
+ lisp_fwd_path_t *path;
+ fib_protocol_t fproto;
- memset (adj, 0, sizeof (adj[0]));
- adj->n_adj = 1;
- /* fill in lookup_next_index with a 'legal' value to avoid problems */
- adj->lookup_next_index = (ip_ver == IP4) ?
- lgm->ip4_lookup_next_lgpe_ip4_lookup :
- lgm->ip6_lookup_next_lgpe_ip6_lookup;
+ vec_foreach (path, lfe->paths)
+ {
+ lisp_gpe_adjacency_unlock (path->lisp_adj);
+ }
- /* positive mapping */
- if (!is_negative)
- {
- /* send packets that hit this adj to lisp-gpe interface output node in
- * requested vrf. */
- lnip = (ip_ver == IP4) ?
- lgm->lgpe_ip4_lookup_next_index_by_table_id :
- lgm->lgpe_ip6_lookup_next_index_by_table_id;
- lookup_next_index = hash_get (lnip, table_id);
- lgpe_sw_if_index = hash_get (lgm->l3_ifaces.sw_if_index_by_vni, vni);
-
- /* the assumption is that the interface must've been created before
- * programming the dp */
- ASSERT (lookup_next_index != 0 && lgpe_sw_if_index != 0);
-
- /* hijack explicit fib index to store lisp interface node index,
- * if_address_index for the tunnel index and saved lookup next index
- * for the number of sub tunnels */
- adj->explicit_fib_index = lookup_next_index[0];
- adj->if_address_index = tun_index;
- adj->rewrite_header.sw_if_index = lgpe_sw_if_index[0];
- adj->saved_lookup_next_index = n_sub_tun;
- }
- /* negative mapping */
- else
- {
- adj->rewrite_header.sw_if_index = ~0;
- adj->rewrite_header.next_index = ~0;
- adj->if_address_index = tun_index;
+ delete_fib_entries (lfe);
- switch (action)
- {
- case LISP_NO_ACTION:
- /* TODO update timers? */
- case LISP_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 LISP_SEND_MAP_REQUEST:
- /* insert tunnel that always sends map-request */
- adj->explicit_fib_index = (ip_ver == IP4) ?
- LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP :
- LGPE_IP6_LOOKUP_NEXT_LISP_CP_LOOKUP;
- break;
- case LISP_DROP:
- /* for drop fwd entries, just add route, no need to add encap tunnel */
- adj->explicit_fib_index = (ip_ver == IP4 ?
- LGPE_IP4_LOOKUP_NEXT_DROP :
- LGPE_IP6_LOOKUP_NEXT_DROP);
- break;
- default:
- return -1;
- }
- }
- return 0;
+ fproto = (IP4 == ip_prefix_version (&fid_addr_ippref (&lfe->key->rmt)) ?
+ FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
+ fib_table_unlock (lfe->eid_fib_index, fproto);
+
+ hash_unset_mem (lisp_gpe_fwd_entries, lfe->key);
+ clib_mem_free (lfe->key);
+ pool_put (lisp_fwd_entry_pool, lfe);
}
/**
* @brief Add/Delete LISP IP forwarding entry.
*
- * Coordinates the creation/removal of forwarding entries for IP LISP overlay:
- * creates lisp-gpe tunnel, builds tunnel customized forwarding entry and
- * injects new route in Source/Dest FIB.
+ * removal of forwarding entries for IP LISP overlay:
*
* @param[in] lgm Reference to @ref lisp_gpe_main_t.
* @param[in] a Parameters for building the forwarding entry.
@@ -455,63 +250,21 @@ build_ip_adjacency (lisp_gpe_main_t * lgm, ip_adjacency_t * adj, u32 table_id,
* @return 0 on success.
*/
static int
-add_del_ip_fwd_entry (lisp_gpe_main_t * lgm,
- vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
+del_ip_fwd_entry (lisp_gpe_main_t * lgm,
+ vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
{
- ip_adjacency_t adj, *adjp;
- lisp_gpe_tunnel_t *t;
- u32 rv, tun_index = ~0, n_sub_tuns = 0;
- ip_prefix_t *rmt_pref, *lcl_pref;
- u8 ip_ver;
-
- rmt_pref = &gid_address_ippref (&a->rmt_eid);
- lcl_pref = &gid_address_ippref (&a->lcl_eid);
- ip_ver = ip_prefix_version (rmt_pref);
-
- /* add/del tunnel to tunnels pool and prepares rewrite */
- if (0 != a->locator_pairs)
- {
- rv = add_del_ip_tunnel (a, 0 /* is_l2 */ , &tun_index);
- if (rv)
- {
- clib_warning ("failed to build tunnel!");
- return rv;
- }
- if (a->is_add)
- {
- t = pool_elt_at_index (lgm->tunnels, tun_index);
- n_sub_tuns = t->sub_tunnels_lbv_count;
- }
- }
-
- /* setup adjacency for eid */
- rv = build_ip_adjacency (lgm, &adj, a->table_id, a->vni, tun_index,
- n_sub_tuns, a->is_negative, a->action, ip_ver);
-
- /* add/delete route for eid */
- rv |= ip_sd_fib_add_del_route (lgm, rmt_pref, lcl_pref, a->table_id, &adj,
- a->is_add);
-
- if (rv)
- {
- clib_warning ("failed to insert route for tunnel!");
- return rv;
- }
+ lisp_gpe_fwd_entry_key_t key;
+ lisp_fwd_entry_t *lfe;
- /* check that everything worked */
- if (CLIB_DEBUG && a->is_add)
- {
- u32 adj_index;
- adj_index = ip_sd_fib_get_route (lgm, rmt_pref, lcl_pref, a->table_id);
- ASSERT (adj_index != 0);
+ lfe = find_fwd_entry (lgm, a, &key);
- adjp = ip_get_adjacency ((ip_ver == IP4) ? lgm->lm4 : lgm->lm6,
- adj_index);
+ if (NULL == lfe)
+ /* no such entry */
+ return VNET_API_ERROR_INVALID_VALUE;
- ASSERT (adjp != 0 && adjp->if_address_index == tun_index);
- }
+ del_ip_fwd_entry_i (lfe);
- return rv;
+ return (0);
}
static void
@@ -536,7 +289,7 @@ make_mac_fib_key (BVT (clib_bihash_kv) * kv, u16 bd_index, u8 src_mac[6],
*
* @return index of mapping matching the lookup key.
*/
-u32
+index_t
lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
u8 dst_mac[6])
{
@@ -555,7 +308,7 @@ lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
return value.value;
}
- return ~0;
+ return lisp_gpe_main.l2_lb_miss;
}
/**
@@ -601,6 +354,12 @@ l2_fib_init (lisp_gpe_main_t * lgm)
BV (clib_bihash_init) (&lgm->l2_fib, "l2 fib",
1 << max_log2 (L2_FIB_DEFAULT_HASH_NUM_BUCKETS),
L2_FIB_DEFAULT_HASH_MEMORY_SIZE);
+
+ /*
+ * the result from a 'miss' in a L2 Table
+ */
+ lgm->l2_lb_miss = load_balance_create (1, DPO_PROTO_IP4, 0);
+ load_balance_set_bucket (lgm->l2_lb_miss, 0, drop_dpo_get (DPO_PROTO_IP4));
}
/**
@@ -618,27 +377,75 @@ static int
add_del_l2_fwd_entry (lisp_gpe_main_t * lgm,
vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
{
- int rv;
- u32 tun_index;
- bd_main_t *bdm = &bd_main;
- uword *bd_indexp;
-
- /* create tunnel */
- rv = add_del_ip_tunnel (a, 1 /* is_l2 */ , &tun_index);
- if (rv)
- return rv;
-
- bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id);
- if (!bd_indexp)
- {
- clib_warning ("bridge domain %d doesn't exist", a->bd_id);
- return -1;
- }
-
- /* add entry to l2 lisp fib */
- lisp_l2_fib_add_del_entry (lgm, bd_indexp[0], gid_address_mac (&a->lcl_eid),
- gid_address_mac (&a->rmt_eid), tun_index,
- a->is_add);
+ /* lisp_gpe_fwd_entry_key_t key; */
+ /* lisp_fwd_entry_t *lfe; */
+ /* fib_protocol_t fproto; */
+ /* uword *bd_indexp; */
+
+ /* bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id); */
+ /* if (!bd_indexp) */
+ /* { */
+ /* clib_warning ("bridge domain %d doesn't exist", a->bd_id); */
+ /* return -1; */
+ /* } */
+
+ /* lfe = find_fwd_entry(lgm, a, &key); */
+
+ /* if (NULL != lfe) */
+ /* /\* don't support updates *\/ */
+ /* return VNET_API_ERROR_INVALID_VALUE; */
+
+ /* int rv; */
+ /* u32 tun_index; */
+ /* fib_node_index_t old_path_list; */
+ /* bd_main_t *bdm = &bd_main; */
+ /* fib_route_path_t *rpaths; */
+ /* lisp_gpe_tunnel_t *t; */
+ /* const dpo_id_t *dpo; */
+ /* index_t lbi; */
+
+ /* /\* create tunnel *\/ */
+ /* rv = add_del_ip_tunnel (a, 1 /\* is_l2 *\/ , &tun_index, NULL); */
+ /* if (rv) */
+ /* return rv; */
+
+ /* bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id); */
+ /* if (!bd_indexp) */
+ /* { */
+ /* clib_warning ("bridge domain %d doesn't exist", a->bd_id); */
+ /* return -1; */
+ /* } */
+
+ /* t = pool_elt_at_index (lgm->tunnels, tun_index); */
+ /* old_path_list = t->l2_path_list; */
+
+ /* if (LISP_NO_ACTION == t->action) */
+ /* { */
+ /* rpaths = lisp_gpe_mk_paths_for_sub_tunnels (t); */
+
+ /* t->l2_path_list = fib_path_list_create (FIB_PATH_LIST_FLAG_NONE, */
+ /* rpaths); */
+
+ /* vec_free (rpaths); */
+ /* fib_path_list_lock (t->l2_path_list); */
+
+ /* dpo = fib_path_list_contribute_forwarding (t->l2_path_list, */
+ /* FIB_FORW_CHAIN_TYPE_UNICAST_IP); */
+ /* lbi = dpo->dpoi_index; */
+ /* } */
+ /* else if (LISP_SEND_MAP_REQUEST == t->action) */
+ /* { */
+ /* lbi = lgm->l2_lb_cp_lkup; */
+ /* } */
+ /* else */
+ /* { */
+ /* lbi = lgm->l2_lb_miss; */
+ /* } */
+ /* fib_path_list_unlock (old_path_list); */
+
+ /* /\* add entry to l2 lisp fib *\/ */
+ /* lisp_l2_fib_add_del_entry (lgm, bd_indexp[0], gid_address_mac (&a->lcl_eid), */
+ /* gid_address_mac (&a->rmt_eid), lbi, a->is_add); */
return 0;
}
@@ -669,7 +476,11 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
switch (type)
{
case GID_ADDR_IP_PREFIX:
- return add_del_ip_fwd_entry (lgm, a);
+ if (a->is_add)
+ return add_ip_fwd_entry (lgm, a);
+ else
+ return del_ip_fwd_entry (lgm, a);
+ break;
case GID_ADDR_MAC:
return add_del_l2_fwd_entry (lgm, a);
default:
@@ -807,103 +618,77 @@ done:
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (lisp_gpe_add_del_fwd_entry_command, static) = {
- .path = "lisp gpe tunnel",
- .short_help = "lisp gpe tunnel add/del vni <vni> vrf <vrf> [leid <leid>]"
+ .path = "lisp gpe entry",
+ .short_help = "lisp gpe entry add/del vni <vni> vrf <vrf> [leid <leid>]"
"reid <reid> [loc-pair <lloc> <rloc> p <priority> w <weight>] "
"[negative action <action>]",
.function = lisp_gpe_add_del_fwd_entry_command_fn,
};
/* *INDENT-ON* */
-/** Format LISP-GPE next indexes. */
static u8 *
-format_decap_next (u8 * s, va_list * args)
+format_lisp_fwd_path (u8 * s, va_list ap)
{
- u32 next_index = va_arg (*args, u32);
+ lisp_fwd_path_t *lfp = va_arg (ap, lisp_fwd_path_t *);
- switch (next_index)
- {
- case LISP_GPE_INPUT_NEXT_DROP:
- return format (s, "drop");
- case LISP_GPE_INPUT_NEXT_IP4_INPUT:
- return format (s, "ip4");
- case LISP_GPE_INPUT_NEXT_IP6_INPUT:
- return format (s, "ip6");
- default:
- return format (s, "unknown %d", next_index);
- }
- return s;
+ s = format (s, "pirority:%d weight:%d ", lfp->priority, lfp->weight);
+ s = format (s, "adj:[%U]\n",
+ format_lisp_gpe_adjacency,
+ lisp_gpe_adjacency_get (lfp->lisp_adj),
+ LISP_GPE_ADJ_FORMAT_FLAG_NONE);
+
+ return (s);
}
-/** Format LISP-GPE tunnel. */
-u8 *
-format_lisp_gpe_tunnel (u8 * s, va_list * args)
+static u8 *
+format_lisp_gpe_fwd_entry (u8 * s, va_list ap)
{
- lisp_gpe_tunnel_t *t = va_arg (*args, lisp_gpe_tunnel_t *);
- lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
- locator_pair_t *lp = 0;
- normalized_sub_tunnel_weights_t *nstw;
-
- s =
- format (s, "tunnel %d vni %d (0x%x)\n", t - lgm->tunnels, t->vni, t->vni);
- s =
- format (s, " fibs: encap %d, decap %d decap next %U\n",
- t->encap_fib_index, t->decap_fib_index, format_decap_next,
- t->decap_next_index);
- s = format (s, " lisp ver %d ", (t->ver_res >> 6));
-
-#define _(n,v) if (t->flags & v) s = format (s, "%s-bit ", #n);
- foreach_lisp_gpe_flag_bit;
-#undef _
-
- s = format (s, "next_protocol %d ver_res %x res %x\n",
- t->next_protocol, t->ver_res, t->res);
-
- s = format (s, " locator-pairs:\n");
- vec_foreach (lp, t->locator_pairs)
- {
- s = format (s, " local: %U remote: %U weight %d\n",
- format_ip_address, &lp->lcl_loc, format_ip_address,
- &lp->rmt_loc, lp->weight);
- }
+ lisp_fwd_entry_t *lfe = va_arg (ap, lisp_fwd_entry_t *);
- s = format (s, " active sub-tunnels:\n");
- vec_foreach (nstw, t->norm_sub_tunnel_weights)
- {
- lp = vec_elt_at_index (t->locator_pairs, nstw->sub_tunnel_index);
- s = format (s, " local: %U remote: %U weight %d\n", format_ip_address,
- &lp->lcl_loc, format_ip_address, &lp->rmt_loc, nstw->weight);
- }
- return s;
+ s = format (s, "VNI:%d VRF:%d EID: %U -> %U",
+ lfe->key->vni, lfe->eid_table_id,
+ format_fid_address, &lfe->key->lcl,
+ format_fid_address, &lfe->key->rmt);
+ if (LISP_FWD_ENTRY_TYPE_NEGATIVE == lfe->type)
+ {
+ s = format (s, "\n Negative - action:%U",
+ format_negative_mapping_action, lfe->action);
+ }
+ else
+ {
+ lisp_fwd_path_t *path;
+
+ s = format (s, "\n via:");
+ vec_foreach (path, lfe->paths)
+ {
+ s = format (s, "\n %U", format_lisp_fwd_path, path);
+ }
+ }
+
+ return (s);
}
-/** CLI command to show LISP-GPE tunnels. */
static clib_error_t *
-show_lisp_gpe_tunnel_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
+lisp_gpe_fwd_entry_show (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
{
- lisp_gpe_main_t *lgm = &lisp_gpe_main;
- lisp_gpe_tunnel_t *t;
-
- if (pool_elts (lgm->tunnels) == 0)
- vlib_cli_output (vm, "No lisp-gpe tunnels configured...");
+ lisp_fwd_entry_t *lfe;
- /* *INDENT-OFF* */
- pool_foreach (t, lgm->tunnels,
+/* *INDENT-OFF* */
+ pool_foreach (lfe, lisp_fwd_entry_pool,
({
- vlib_cli_output (vm, "%U", format_lisp_gpe_tunnel, t);
+ vlib_cli_output (vm, "%U", format_lisp_gpe_fwd_entry, lfe);
}));
- /* *INDENT-ON* */
+/* *INDENT-ON* */
- return 0;
+ return (NULL);
}
/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) =
-{
- .path = "show lisp gpe tunnel",
- .function = show_lisp_gpe_tunnel_command_fn,
+VLIB_CLI_COMMAND (lisp_gpe_fwd_entry_show_command, static) = {
+ .path = "show lisp gpe entry",
+ .short_help = "show lisp gpe entry vni <vni> vrf <vrf> [leid <leid>] reid <reid>",
+ .function = lisp_gpe_fwd_entry_show,
};
/* *INDENT-ON* */
@@ -921,29 +706,9 @@ 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;
if (a->is_en)
{
- /* add lgpe_ip4_lookup as possible next_node for ip4 lookup */
- 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);
- }
- /* add lgpe_ip6_lookup as possible next_node for ip6 lookup */
- if (lgm->ip6_lookup_next_lgpe_ip6_lookup == ~0)
- {
- lgm->ip6_lookup_next_lgpe_ip6_lookup =
- vlib_node_add_next (vnm->vlib_main, ip6_lookup_node.index,
- lgpe_ip6_lookup_node.index);
- }
- else
- {
- /* ask cp to re-add ifaces and defaults */
- }
-
lgm->is_en = 1;
}
else
@@ -951,37 +716,17 @@ vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a)
CLIB_UNUSED (uword * val);
hash_pair_t *p;
u32 *dp_tables = 0, *dp_table;
- 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;
+ lisp_fwd_entry_t *lfe;
- /* remove all tunnels */
-
+ /* remove all entries */
/* *INDENT-OFF* */
- mhash_foreach(tunnel, val, &lgm->lisp_gpe_tunnel_by_key, ({
- vec_add1(tunnels, tunnel[0]);
+ pool_foreach (lfe, lisp_fwd_entry_pool,
+ ({
+ del_ip_fwd_entry_i (lfe);
}));
/* *INDENT-ON* */
- vec_foreach (tunnel, tunnels)
- {
- memset (at, 0, sizeof (at[0]));
- at->is_add = 0;
- if (tunnel->rmt.type == GID_ADDR_IP_PREFIX)
- {
- gid_address_type (&at->rmt_eid) = GID_ADDR_IP_PREFIX;
- ip_prefix_copy (&gid_address_ippref (&at->rmt_eid),
- &tunnel->rmt.ippref);
- }
- else
- {
- gid_address_type (&at->rmt_eid) = GID_ADDR_MAC;
- mac_copy (&gid_address_mac (&at->rmt_eid), &tunnel->rmt.mac);
- }
- vnet_lisp_gpe_add_del_fwd_entry (at, 0);
- }
- vec_free (tunnels);
-
/* disable all l3 ifaces */
/* *INDENT-OFF* */
@@ -1109,6 +854,7 @@ format_vnet_lisp_gpe_status (u8 * s, va_list * args)
return format (s, "%s", lgm->is_en ? "enabled" : "disabled");
}
+
/** LISP-GPE init function. */
clib_error_t *
lisp_gpe_init (vlib_main_t * vm)
@@ -1128,11 +874,10 @@ lisp_gpe_init (vlib_main_t * vm)
lgm->im6 = &ip6_main;
lgm->lm4 = &ip4_main.lookup_main;
lgm->lm6 = &ip6_main.lookup_main;
- lgm->ip4_lookup_next_lgpe_ip4_lookup = ~0;
- lgm->ip6_lookup_next_lgpe_ip6_lookup = ~0;
- mhash_init (&lgm->lisp_gpe_tunnel_by_key, sizeof (uword),
- sizeof (lisp_gpe_tunnel_key_t));
+ lisp_gpe_fwd_entries = hash_create_mem (0,
+ sizeof (lisp_gpe_fwd_entry_key_t),
+ sizeof (uword));
l2_fib_init (lgm);
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe.h b/vnet/vnet/lisp-gpe/lisp_gpe.h
index 4a8bdfe7..66009cc1 100644
--- a/vnet/vnet/lisp-gpe/lisp_gpe.h
+++ b/vnet/vnet/lisp-gpe/lisp_gpe.h
@@ -30,6 +30,7 @@
#include <vnet/ip/udp.h>
#include <vnet/lisp-cp/lisp_types.h>
#include <vnet/lisp-gpe/lisp_gpe_packet.h>
+#include <vnet/adj/adj_types.h>
/** IP4-UDP-LISP encap header */
/* *INDENT-OFF* */
@@ -49,37 +50,6 @@ typedef CLIB_PACKED (struct {
}) ip6_udp_lisp_gpe_header_t;
/* *INDENT-ON* */
-/** LISP-GPE tunnel key */
-typedef struct
-{
- union
- {
- struct
- {
- dp_address_t rmt;
- dp_address_t lcl;
- u32 vni;
- };
- u8 as_u8[40];
- };
-} lisp_gpe_tunnel_key_t;
-
-typedef struct lisp_gpe_sub_tunnel
-{
- /** Rewrite string. $$$$ embed vnet_rewrite header */
- u8 *rewrite;
- u32 parent_index;
- u32 locator_pair_index;
- u8 weight;
- u8 is_ip4;
-} lisp_gpe_sub_tunnel_t;
-
-typedef struct nomalized_sub_tunnel
-{
- u32 sub_tunnel_index;
- u8 weight;
-} normalized_sub_tunnel_weights_t;
-
/** LISP-GPE tunnel structure */
typedef struct
{
@@ -87,17 +57,7 @@ typedef struct
locator_pair_t *locator_pairs;
/** locator-pairs with best priority become sub-tunnels */
- lisp_gpe_sub_tunnel_t *sub_tunnels;
-
- /** sub-tunnels load balancing vector: contains list of sub-tunnel
- * indexes replicated according to weight */
- u32 *sub_tunnels_lbv;
-
- /** number of entries in load balancing vector */
- u32 sub_tunnels_lbv_count;
-
- /** normalized sub tunnel weights */
- normalized_sub_tunnel_weights_t *norm_sub_tunnel_weights;
+ u32 *sub_tunnels;
/** decap next index */
u32 decap_next_index;
@@ -109,10 +69,16 @@ typedef struct
u32 encap_fib_index; /* tunnel partner lookup here */
u32 decap_fib_index; /* inner IP lookup here */
+ /** index of the source address lookup FIB */
+ u32 src_fib_index;
+
/** vnet intfc hw/sw_if_index */
u32 hw_if_index;
u32 sw_if_index;
+ /** L2 path-list */
+ fib_node_index_t l2_path_list;
+
/** action for 'negative' tunnels */
u8 action;
@@ -124,6 +90,112 @@ typedef struct
u32 vni;
} lisp_gpe_tunnel_t;
+/**
+ * @brief A path on which to forward lisp traffic
+ */
+typedef struct lisp_fwd_path_t_
+{
+ /**
+ * The adjacency constructed for the locator pair
+ */
+ index_t lisp_adj;
+
+ /**
+ * Priority. Only the paths with the best priority will be installed in FIB
+ */
+ u8 priority;
+
+ /**
+ * [UE]CMP weigt for the path
+ */
+ u8 weight;
+
+} lisp_fwd_path_t;
+
+/**
+ * @brief A Forwarding entry can be 'normal' or 'negative'
+ * Negative implies we deliberately want to add a FIB entry for an EID
+ * that results in 'spcial' behaviour determined by an 'action'.
+ * @normal' means send it down some tunnels.
+ */
+typedef enum lisp_fwd_entry_type_t_
+{
+ LISP_FWD_ENTRY_TYPE_NORMAL,
+ LISP_FWD_ENTRY_TYPE_NEGATIVE,
+} lisp_fwd_entry_type_t;
+
+typedef enum
+{
+ NO_ACTION,
+ FORWARD_NATIVE,
+ SEND_MAP_REQUEST,
+ DROP
+} negative_fwd_actions_e;
+
+/**
+ * LISP-GPE fwd entry key
+ */
+typedef struct lisp_gpe_fwd_entry_key_t_
+{
+ dp_address_t rmt;
+ dp_address_t lcl;
+ u32 vni;
+} lisp_gpe_fwd_entry_key_t;
+
+/**
+ * @brief A LISP Forwarding Entry
+ *
+ * A forwarding entry is from a locai EID to a remote EID over a set of rloc pairs
+ */
+typedef struct lisp_fwd_entry_t_
+{
+ /**
+ * The Entry's key: {lEID,r-EID,vni}
+ */
+ lisp_gpe_fwd_entry_key_t *key;
+
+ /**
+ * The VRF (in the case of L3) or Bridge-Domain (for L2) index
+ */
+ union
+ {
+ u32 eid_table_id;
+ u32 eid_bd_index;
+ };
+
+ /**
+ * The forwarding entry type
+ */
+ lisp_fwd_entry_type_t type;
+
+ union
+ {
+ /**
+ * @brief When the type is 'normal'
+ * The RLOC pair that form the route's paths. i.e. where to send
+ * packets for this route.
+ */
+ lisp_fwd_path_t *paths;
+
+ /**
+ * @brief When the type is negative. The action to take.
+ */
+ negative_fwd_actions_e action;
+ };
+
+ /**
+ * The FIB index for the overlay, i.e. the FIB in which the EIDs
+ * are present
+ */
+ u32 eid_fib_index;
+
+ /**
+ * The SRC-FIB index for created for anding source-route entries
+ */
+ u32 src_fib_index;
+} lisp_fwd_entry_t;
+
+
#define foreach_lisp_gpe_ip_input_next \
_(DROP, "error-drop") \
_(IP4_INPUT, "ip4-input") \
@@ -147,30 +219,6 @@ typedef enum
LISP_GPE_N_ERROR,
} lisp_gpe_error_t;
-/** IP4 source FIB.
- * 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 from ip4 fib
- */
-typedef ip4_fib_t ip4_src_fib_t;
-
-/** IP6 source FIB */
-typedef struct ip6_src_fib
-{
- BVT (clib_bihash) ip6_lookup_table;
-
- /** bitmap/vector of mask widths to search */
- uword *non_empty_dst_address_length_bitmap;
- u8 *prefix_lengths_in_search_order;
- ip6_address_t fib_masks[129];
- i32 dst_address_length_refcounts[129];
-
- /** ip6 lookup table config parameters */
- u32 lookup_table_nbuckets;
- uword lookup_table_size;
-} ip6_src_fib_t;
-
-/** Tunnel lookup structure for L2 and L3 tunnels */
typedef struct tunnel_lookup
{
/** Lookup lisp-gpe interfaces by dp table (eg. vrf/bridge index) */
@@ -178,6 +226,8 @@ typedef struct tunnel_lookup
/** lookup decap tunnel termination sw_if_index by vni and vice versa */
uword *sw_if_index_by_vni;
+
+ // FIXME - Need this?
uword *vni_by_sw_if_index;
} tunnel_lookup_t;
@@ -187,9 +237,6 @@ typedef struct lisp_gpe_main
/** pool of encap tunnel instances */
lisp_gpe_tunnel_t *tunnels;
- /** lookup tunnel by key */
- mhash_t lisp_gpe_tunnel_by_key;
-
/** Free vlib hw_if_indices */
u32 *free_tunnel_hw_if_indices;
@@ -197,21 +244,8 @@ typedef struct lisp_gpe_main
/* L3 data structures
* ================== */
-
- /** Pool of src fibs that are paired with dst fibs */
- ip4_src_fib_t *ip4_src_fibs;
- ip6_src_fib_t *ip6_src_fibs;
-
tunnel_lookup_t l3_ifaces;
- /** Lookup lgpe_ipX_lookup_next by vrf */
- uword *lgpe_ip4_lookup_next_index_by_table_id;
- uword *lgpe_ip6_lookup_next_index_by_table_id;
-
- /** next node indexes that point ip4/6 lookup to lisp gpe ip lookup */
- u32 ip4_lookup_next_lgpe_ip4_lookup;
- u32 ip6_lookup_next_lgpe_ip6_lookup;
-
/* L2 data structures
* ================== */
@@ -220,6 +254,10 @@ typedef struct lisp_gpe_main
tunnel_lookup_t l2_ifaces;
+ /** Load-balance for a miss in the table */
+ index_t l2_lb_miss;
+ index_t l2_lb_cp_lkup;
+
/** convenience */
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
@@ -238,10 +276,10 @@ vnet_lisp_gpe_get_main ()
return &lisp_gpe_main;
}
-extern vlib_node_registration_t lgpe_ip4_lookup_node;
-extern vlib_node_registration_t lgpe_ip6_lookup_node;
+
extern vlib_node_registration_t lisp_gpe_ip4_input_node;
extern vlib_node_registration_t lisp_gpe_ip6_input_node;
+extern vnet_hw_interface_class_t lisp_gpe_hw_class;
u8 *format_lisp_gpe_header_with_length (u8 * s, va_list * args);
@@ -291,7 +329,7 @@ typedef struct
u8 is_negative;
/** action for negative mappings */
- u8 action;
+ negative_fwd_actions_e action;
/** local eid */
gid_address_t lcl_eid;
@@ -332,13 +370,23 @@ int
vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
u32 * hw_if_indexp);
-int
-ip_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_id,
- ip_adjacency_t * add_adj, u8 is_add);
-u32
-ip_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
- ip_prefix_t * src_prefix, u32 table_id);
+extern void
+ip_src_fib_add_route (u32 src_fib_index,
+ const ip_prefix_t * src_prefix,
+ const lisp_fwd_path_t * paths);
+extern void
+ip_src_dst_fib_del_route (u32 src_fib_index,
+ const ip_prefix_t * src_prefix,
+ u32 dst_table_id, const ip_prefix_t * dst_prefix);
+extern void
+ip_src_fib_add_route_w_dpo (u32 src_fib_index,
+ const ip_prefix_t * src_prefix,
+ const dpo_id_t * src_dpo);
+extern u32
+ip_dst_fib_add_route (u32 dst_table_id, const ip_prefix_t * dst_prefix);
+
+extern fib_route_path_t *lisp_gpe_mk_paths_for_sub_tunnels (lisp_gpe_tunnel_t
+ * t);
#define foreach_lgpe_ip4_lookup_next \
_(DROP, "error-drop") \
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c b/vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c
new file mode 100644
index 00000000..861f0dd3
--- /dev/null
+++ b/vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c
@@ -0,0 +1,437 @@
+/*
+ * 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.
+ */
+/**
+ * @file
+ * @brief Common utility functions for IPv4, IPv6 and L2 LISP-GPE adjacencys.
+ *
+ */
+
+#include <vnet/dpo/dpo.h>
+#include <vnet/lisp-gpe/lisp_gpe_sub_interface.h>
+#include <vnet/lisp-gpe/lisp_gpe_adjacency.h>
+#include <vnet/lisp-gpe/lisp_gpe_tunnel.h>
+#include <vnet/fib/fib_entry.h>
+#include <vnet/adj/adj_midchain.h>
+
+/**
+ * Memory pool of all adjacencies
+ */
+static lisp_gpe_adjacency_t *lisp_adj_pool;
+
+/**
+ * Hash table of all adjacencies. key:{nh, itf}
+ * We never have an all zeros address since the interfaces are multi-access,
+ * therefore there is no ambiguity between a v4 and v6 next-hop, so we don't
+ * need to add the protocol to the key.
+ */
+static
+BVT (clib_bihash)
+ lisp_adj_db;
+
+#define LISP_ADJ_SET_KEY(_key, _itf, _nh) \
+{ \
+ _key.key[0] = (_nh)->ip.v6.as_u64[0]; \
+ _key.key[1] = (_nh)->ip.v6.as_u64[1]; \
+ _key.key[2] = (_itf); \
+}
+
+ static index_t lisp_adj_find (const ip_address_t * addr, u32 sw_if_index)
+{
+ BVT (clib_bihash_kv) kv;
+
+ LISP_ADJ_SET_KEY (kv, sw_if_index, addr);
+
+ if (BV (clib_bihash_search) (&lisp_adj_db, &kv, &kv) < 0)
+ {
+ return (INDEX_INVALID);
+ }
+ else
+ {
+ return (kv.value);
+ }
+}
+
+static void
+lisp_adj_insert (const ip_address_t * addr, u32 sw_if_index, index_t ai)
+{
+ BVT (clib_bihash_kv) kv;
+
+ LISP_ADJ_SET_KEY (kv, sw_if_index, addr);
+ kv.value = ai;
+
+ BV (clib_bihash_add_del) (&lisp_adj_db, &kv, 1);
+}
+
+static void
+lisp_adj_remove (const ip_address_t * addr, u32 sw_if_index)
+{
+ BVT (clib_bihash_kv) kv;
+
+ LISP_ADJ_SET_KEY (kv, sw_if_index, addr);
+
+ BV (clib_bihash_add_del) (&lisp_adj_db, &kv, 0);
+}
+
+static lisp_gpe_adjacency_t *
+lisp_gpe_adjacency_get_i (index_t lai)
+{
+ return (pool_elt_at_index (lisp_adj_pool, lai));
+}
+
+fib_forward_chain_type_t
+lisp_gpe_adj_get_fib_chain_type (const lisp_gpe_adjacency_t * ladj)
+{
+ switch (ip_addr_version (&ladj->remote_rloc))
+ {
+ case IP4:
+ return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
+ case IP6:
+ return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
+ default:
+ ASSERT (0);
+ break;
+ }
+ return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
+}
+
+/**
+ * @brief Stack the tunnel's midchain on the IP forwarding chain of the via
+ */
+static void
+lisp_gpe_adj_stack (lisp_gpe_adjacency_t * ladj)
+{
+ const lisp_gpe_tunnel_2_t *lgt;
+ dpo_id_t tmp = DPO_NULL;
+ fib_link_t linkt;
+
+ lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
+ fib_entry_contribute_forwarding (lgt->fib_entry_index,
+ lisp_gpe_adj_get_fib_chain_type (ladj),
+ &tmp);
+
+ FOR_EACH_FIB_IP_LINK (linkt)
+ {
+ adj_nbr_midchain_stack (ladj->adjs[linkt], &tmp);
+ }
+ dpo_reset (&tmp);
+}
+
+static lisp_gpe_next_protocol_e
+lisp_gpe_adj_proto_from_fib_link_type (fib_link_t linkt)
+{
+ switch (linkt)
+ {
+ case FIB_LINK_IP4:
+ return (LISP_GPE_INPUT_NEXT_IP4_INPUT);
+ case FIB_LINK_IP6:
+ return (LISP_GPE_INPUT_NEXT_IP6_INPUT);
+ default:
+ ASSERT (0);
+ }
+ return (LISP_GPE_INPUT_NEXT_DROP);
+}
+
+index_t
+lisp_gpe_adjacency_find_or_create_and_lock (const locator_pair_t * pair,
+ u32 overlay_table_id, u32 vni)
+{
+ const lisp_gpe_tunnel_2_t *lgt;
+ lisp_gpe_adjacency_t *ladj;
+ index_t lai, l3si;
+
+ /*
+ * first find the L3 sub-interface that corresponds to the loacl-rloc and vni
+ */
+ l3si = lisp_gpe_sub_interface_find_or_create_and_lock (&pair->lcl_loc,
+ overlay_table_id,
+ vni);
+
+ /*
+ * find an existing or create a new adj
+ */
+ lai = lisp_adj_find (&pair->rmt_loc, l3si);
+
+ if (INDEX_INVALID == lai)
+ {
+ const lisp_gpe_sub_interface_t *l3s;
+ u8 *rewrite = NULL;
+ fib_link_t linkt;
+ fib_prefix_t nh;
+
+ pool_get (lisp_adj_pool, ladj);
+ memset (ladj, 0, sizeof (*ladj));
+ lai = (ladj - lisp_adj_pool);
+
+ ladj->remote_rloc = pair->rmt_loc;
+ ladj->vni = vni;
+ /* transfer the lock to the adj */
+ ladj->lisp_l3_sub_index = l3si;
+
+ l3s = lisp_gpe_sub_interface_get (l3si);
+ ladj->sw_if_index = l3s->sw_if_index;
+
+ /* if vni is non-default */
+ if (ladj->vni)
+ ladj->flags = LISP_GPE_FLAGS_I;
+
+ /* work in lisp-gpe not legacy mode */
+ ladj->flags |= LISP_GPE_FLAGS_P;
+
+ /*
+ * find the tunnel that will provide the underlying transport
+ * and hence the rewrite.
+ * The RLOC FIB index is default table - always.
+ */
+ ladj->tunnel_index = lisp_gpe_tunnel_find_or_create_and_lock (pair, 0);
+
+ lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
+
+ /*
+ * become of child of the RLOC FIB entry so we are updated when
+ * its reachability changes, allowing us to re-stack the midcahins
+ */
+ ladj->fib_entry_child_index = fib_entry_child_add (lgt->fib_entry_index,
+ FIB_NODE_TYPE_LISP_ADJ,
+ lai);
+ ip_address_to_fib_prefix (&pair->rmt_loc, &nh);
+
+ /*
+ * construct and stack the FIB midchain adjacencies
+ */
+ FOR_EACH_FIB_IP_LINK (linkt)
+ {
+ ladj->adjs[linkt] = adj_nbr_add_or_lock (nh.fp_proto,
+ linkt,
+ &nh.fp_addr,
+ ladj->sw_if_index);
+
+ rewrite =
+ lisp_gpe_tunnel_build_rewrite (lgt, ladj,
+ lisp_gpe_adj_proto_from_fib_link_type
+ (linkt));
+
+ adj_nbr_midchain_update_rewrite (ladj->adjs[linkt],
+ vnet_get_sup_hw_interface
+ (vnet_get_main (),
+ ladj->sw_if_index)->tx_node_index,
+ rewrite);
+
+ vec_free (rewrite);
+ }
+
+ lisp_gpe_adj_stack (ladj);
+
+ lisp_adj_insert (&ladj->remote_rloc, ladj->lisp_l3_sub_index, lai);
+ }
+ else
+ {
+ /* unlock the interface from the find. */
+ lisp_gpe_sub_interface_unlock (l3si);
+ ladj = lisp_gpe_adjacency_get_i (lai);
+ }
+
+ ladj->locks++;
+
+ return (lai);
+}
+
+/**
+ * @brief Get a pointer to a tunnel from a pointer to a FIB node
+ */
+static lisp_gpe_adjacency_t *
+lisp_gpe_adjacency_from_fib_node (const fib_node_t * node)
+{
+ return ((lisp_gpe_adjacency_t *)
+ ((char *) node -
+ STRUCT_OFFSET_OF (lisp_gpe_adjacency_t, fib_node)));
+}
+
+static void
+lisp_gpe_adjacency_last_lock_gone (lisp_gpe_adjacency_t * ladj)
+{
+ /*
+ * no children so we are not counting locks. no-op.
+ * at least not counting
+ */
+ lisp_adj_remove (&ladj->remote_rloc, ladj->lisp_l3_sub_index);
+
+ /*
+ * unlock the resources this adj holds
+ */
+ lisp_gpe_tunnel_unlock (ladj->tunnel_index);
+ lisp_gpe_sub_interface_unlock (ladj->lisp_l3_sub_index);
+
+ pool_put (lisp_adj_pool, ladj);
+}
+
+void
+lisp_gpe_adjacency_unlock (index_t lai)
+{
+ lisp_gpe_adjacency_t *ladj;
+
+ ladj = lisp_gpe_adjacency_get_i (lai);
+
+ ladj->locks--;
+
+ if (0 == ladj->locks)
+ {
+ lisp_gpe_adjacency_last_lock_gone (ladj);
+ }
+}
+
+const lisp_gpe_adjacency_t *
+lisp_gpe_adjacency_get (index_t lai)
+{
+ return (lisp_gpe_adjacency_get_i (lai));
+}
+
+
+/**
+ * @brief LISP GPE tunnel back walk
+ *
+ * The FIB entry through which this tunnel resolves has been updated.
+ * re-stack the midchain on the new forwarding.
+ */
+static fib_node_back_walk_rc_t
+lisp_gpe_adjacency_back_walk (fib_node_t * node,
+ fib_node_back_walk_ctx_t * ctx)
+{
+ lisp_gpe_adj_stack (lisp_gpe_adjacency_from_fib_node (node));
+
+ return (FIB_NODE_BACK_WALK_CONTINUE);
+}
+
+static fib_node_t *
+lisp_gpe_adjacency_get_fib_node (fib_node_index_t index)
+{
+ lisp_gpe_adjacency_t *ladj;
+
+ ladj = pool_elt_at_index (lisp_adj_pool, index);
+ return (&ladj->fib_node);
+}
+
+static void
+lisp_gpe_adjacency_last_fib_lock_gone (fib_node_t * node)
+{
+ lisp_gpe_adjacency_last_lock_gone (lisp_gpe_adjacency_from_fib_node (node));
+}
+
+const static fib_node_vft_t lisp_gpe_tuennel_vft = {
+ .fnv_get = lisp_gpe_adjacency_get_fib_node,
+ .fnv_back_walk = lisp_gpe_adjacency_back_walk,
+ .fnv_last_lock = lisp_gpe_adjacency_last_fib_lock_gone,
+};
+
+u8 *
+format_lisp_gpe_adjacency (u8 * s, va_list * args)
+{
+ lisp_gpe_adjacency_t *ladj = va_arg (*args, lisp_gpe_adjacency_t *);
+ lisp_gpe_adjacency_format_flags_t flags =
+ va_arg (args, lisp_gpe_adjacency_format_flags_t);
+
+ if (flags & LISP_GPE_ADJ_FORMAT_FLAG_DETAIL)
+ {
+ s =
+ format (s, "index %d locks:%d\n", ladj - lisp_adj_pool, ladj->locks);
+ }
+
+ s = format (s, " vni: %d,", ladj->vni);
+ s = format (s, " remote-RLOC: %U,", format_ip_address, &ladj->remote_rloc);
+
+ if (flags & LISP_GPE_ADJ_FORMAT_FLAG_DETAIL)
+ {
+ s = format (s, " %U\n",
+ format_lisp_gpe_sub_interface,
+ lisp_gpe_sub_interface_get (ladj->lisp_l3_sub_index));
+ s = format (s, " %U\n",
+ format_lisp_gpe_tunnel,
+ lisp_gpe_tunnel_get (ladj->tunnel_index));
+ s = format (s, " FIB adjacencies: IPV4:%d IPv6:%d\n",
+ ladj->adjs[FIB_LINK_IP4], ladj->adjs[FIB_LINK_IP6]);
+ }
+ else
+ {
+ s = format (s, " LISP L3 sub-interface index: %d,",
+ ladj->lisp_l3_sub_index);
+ s = format (s, " LISP tunnel index: %d", ladj->tunnel_index);
+ }
+
+
+ return (s);
+}
+
+static clib_error_t *
+lisp_gpe_adjacency_show (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ lisp_gpe_adjacency_t *ladj;
+ index_t index;
+
+ if (pool_elts (lisp_adj_pool) == 0)
+ vlib_cli_output (vm, "No lisp-gpe Adjacencies");
+
+ if (unformat (input, "%d", &index))
+ {
+ ladj = lisp_gpe_adjacency_get_i (index);
+ vlib_cli_output (vm, "%U", format_lisp_gpe_adjacency, ladj,
+ LISP_GPE_ADJ_FORMAT_FLAG_DETAIL);
+ }
+ else
+ {
+ /* *INDENT-OFF* */
+ pool_foreach (ladj, lisp_adj_pool,
+ ({
+ vlib_cli_output (vm, "[%d] %U\n",
+ ladj - lisp_adj_pool,
+ format_lisp_gpe_adjacency, ladj,
+ LISP_GPE_ADJ_FORMAT_FLAG_NONE);
+ }));
+ /* *INDENT-ON* */
+ }
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) =
+{
+ .path = "show lisp gpe adjacency",
+ .function = lisp_gpe_adjacency_show,
+};
+/* *INDENT-ON* */
+
+#define LISP_ADJ_NBR_DEFAULT_HASH_NUM_BUCKETS (256)
+#define LISP_ADJ_NBR_DEFAULT_HASH_MEMORY_SIZE (1<<20)
+
+static clib_error_t *
+lisp_gpe_adj_module_init (vlib_main_t * vm)
+{
+ BV (clib_bihash_init) (&lisp_adj_db,
+ "Adjacency Neighbour table",
+ LISP_ADJ_NBR_DEFAULT_HASH_NUM_BUCKETS,
+ LISP_ADJ_NBR_DEFAULT_HASH_MEMORY_SIZE);
+
+ fib_node_register_type (FIB_NODE_TYPE_LISP_ADJ, &lisp_gpe_tuennel_vft);
+ return (NULL);
+}
+
+VLIB_INIT_FUNCTION (lisp_gpe_adj_module_init)
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe_adjacency.h b/vnet/vnet/lisp-gpe/lisp_gpe_adjacency.h
new file mode 100644
index 00000000..f6a66cdd
--- /dev/null
+++ b/vnet/vnet/lisp-gpe/lisp_gpe_adjacency.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+/**
+ * @file
+ * @brief Common utility functions for IPv4, IPv6 and L2 LISP-GPE adjacencys.
+ *
+ */
+
+#ifndef LISP_GPE_ADJACENCY_H__
+#define LISP_GPE_ADJACENCY_H__
+
+#include <vnet/fib/fib_node.h>
+#include <vnet/lisp-gpe/lisp_gpe.h>
+
+/**
+ * @brief A LISP GPE Adjacency.
+ *
+ * A adjacency represents peer on an L3 sub-interface to which to send traffic.
+ * adjacencies are thus present in the EID space.
+ * The peer is identified by the key:{remote-rloc, sub-interface}, which is
+ * equivalent to the usal adjacency key {next-hop, interface}. So curiously
+ * the rloc address from the underlay is used as a next hop address in the overlay
+ * This is OK because:
+ * 1 - the RLOC is unique in the underlay AND there is only one underlay VRF per
+ * overlay
+ * 2 - the RLOC may overlap with an address in the overlay, but we do not create
+ * an adj-fib (i.e. a route in the overlay FIB for the rloc)
+ *
+ *
+ */
+typedef struct lisp_gpe_adjacency_t_
+{
+ /**
+ * The LISP adj is a part of the FIB control plane graph.
+ */
+ fib_node_t fib_node;
+
+ /**
+ * remote RLOC. The adjacency's next-hop
+ */
+ ip_address_t remote_rloc;
+
+ /**
+ * The VNI. Used in combination with the local-rloc to get the sub-interface
+ */
+ u32 vni;
+
+ /**
+ * The number of locks/reference counts on the adjacency.
+ */
+ u32 locks;
+
+ /**
+ * The index of the LISP L3 subinterface
+ */
+ u32 lisp_l3_sub_index;
+
+ /**
+ * The SW IF index of the sub-interface this adjacency uses.
+ * Cached for convenience from the LISP L3 sub-interface
+ */
+ u32 sw_if_index;
+
+ /**
+ * The index of the LISP GPE tunnel that provides the transport
+ * in the underlay.
+ */
+ u32 tunnel_index;
+
+ /**
+ * Per-link-type FIB adjacencies contributed.
+ * These will be used as a result of a FIB lookup.
+ */
+ adj_index_t adjs[FIB_LINK_NUM];
+
+ /**
+ * This adjacency is a child of the FIB entry to reach the RLOC.
+ * This is so when the reachability of that RLOC changes, we can restack
+ * the FIB adjacnecies.
+ */
+ u32 fib_entry_child_index;
+
+ /**
+ * LISP header fields in HOST byte order
+ */
+ u8 flags;
+ u8 ver_res;
+ u8 res;
+ u8 next_protocol;
+
+} lisp_gpe_adjacency_t;
+
+extern index_t lisp_gpe_adjacency_find_or_create_and_lock (const
+ locator_pair_t *
+ pair,
+ u32 rloc_fib_index,
+ u32 vni);
+
+extern void lisp_gpe_adjacency_unlock (index_t l3si);
+
+extern const lisp_gpe_adjacency_t *lisp_gpe_adjacency_get (index_t l3si);
+
+/**
+ * @brief Flags for displaying the adjacency
+ */
+typedef enum lisp_gpe_adjacency_format_flags_t_
+{
+ LISP_GPE_ADJ_FORMAT_FLAG_NONE,
+ LISP_GPE_ADJ_FORMAT_FLAG_DETAIL,
+} lisp_gpe_adjacency_format_flags_t;
+
+extern u8 *format_lisp_gpe_adjacency (u8 * s, va_list * args);
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.c b/vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.c
new file mode 100644
index 00000000..220802b1
--- /dev/null
+++ b/vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.c
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+/**
+ * @file
+ * @brief LISP sub-interfaces.
+ *
+ */
+#include <vnet/lisp-gpe/lisp_gpe_sub_interface.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/interface.h>
+
+/**
+ * @brief Pool of all l3-sub-interfaces
+ */
+static lisp_gpe_sub_interface_t *lisp_gpe_sub_interface_pool;
+
+/**
+ * A DB of all LISP L3 sub-interfaces. The key is:{VNI,l-RLOC}
+ */
+static uword *lisp_gpe_sub_interfaces;
+
+/**
+ * A DB of all VNET L3 sub-interfaces. The key is:{VNI,l-RLOC}
+ * Used in the data-plane for interface lookup on decap.
+ */
+uword *lisp_gpe_sub_interfaces_sw_if_index;
+
+/**
+ * The next available sub-interface ID. FIXME
+ */
+static u32 lisp_gpe_sub_interface_id;
+
+
+static index_t
+lisp_gpe_sub_interface_db_find (const ip_address_t * lrloc, u32 vni)
+{
+ uword *p;
+
+ lisp_gpe_sub_interface_key_t key = {
+ .local_rloc = *lrloc,
+ .vni = clib_host_to_net_u32 (vni),
+ };
+
+ p = hash_get_mem (lisp_gpe_sub_interfaces, &key);
+
+ if (NULL == p)
+ return (INDEX_INVALID);
+ else
+ return (p[0]);
+}
+
+static void
+lisp_gpe_sub_interface_db_insert (const lisp_gpe_sub_interface_t * l3s)
+{
+ hash_set_mem (lisp_gpe_sub_interfaces,
+ &l3s->key, l3s - lisp_gpe_sub_interface_pool);
+ hash_set_mem (lisp_gpe_sub_interfaces_sw_if_index,
+ &l3s->key, l3s->sw_if_index);
+}
+
+static void
+lisp_gpe_sub_interface_db_remove (const lisp_gpe_sub_interface_t * l3s)
+{
+ hash_unset_mem (lisp_gpe_sub_interfaces, &l3s->key);
+ hash_unset_mem (lisp_gpe_sub_interfaces_sw_if_index, &l3s->key);
+}
+
+lisp_gpe_sub_interface_t *
+lisp_gpe_sub_interface_get_i (index_t l3si)
+{
+ return (pool_elt_at_index (lisp_gpe_sub_interface_pool, l3si));
+}
+
+static void
+lisp_gpe_sub_interface_set_table (u32 sw_if_index, u32 table_id)
+{
+ fib_node_index_t fib_index;
+
+ fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id);
+ ASSERT (FIB_NODE_INDEX_INVALID != fib_index);
+
+ vec_validate (ip4_main.fib_index_by_sw_if_index, sw_if_index);
+ ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
+ // FIXME. enable When we get an adj
+ ip4_sw_interface_enable_disable (sw_if_index, 1);
+
+ fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, table_id);
+ ASSERT (FIB_NODE_INDEX_INVALID != fib_index);
+
+ vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
+ ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
+ // FIXME. enable When we get an adj
+ ip6_sw_interface_enable_disable (sw_if_index, 1);
+}
+
+static void
+lisp_gpe_sub_interface_unset_table (u32 sw_if_index, u32 table_id)
+{
+ ip4_main.fib_index_by_sw_if_index[sw_if_index] = 0;
+ ip4_sw_interface_enable_disable (sw_if_index, 0);
+
+ ip6_main.fib_index_by_sw_if_index[sw_if_index] = 0;
+ ip6_sw_interface_enable_disable (sw_if_index, 0);
+}
+
+index_t
+lisp_gpe_sub_interface_find_or_create_and_lock (const ip_address_t * lrloc,
+ u32 overlay_table_id, u32 vni)
+{
+ lisp_gpe_sub_interface_t *l3s;
+ lisp_gpe_main_t *lgm = &lisp_gpe_main;
+ index_t l3si;
+
+ l3si = lisp_gpe_sub_interface_db_find (lrloc, vni);
+
+ if (INDEX_INVALID == l3si)
+ {
+ vnet_hw_interface_t *hi;
+ clib_error_t *error;
+ u32 sub_sw_if_index;
+ uword *p;
+
+ /*
+ * find the main interface from the VNI
+ */
+ p = hash_get (lgm->l3_ifaces.sw_if_index_by_vni, vni);
+
+ if (NULL == p)
+ return (INDEX_INVALID);
+
+ hi = vnet_get_hw_interface (vnet_get_main (), p[0]);
+
+ if (NULL == hi)
+ return (INDEX_INVALID);
+
+ vnet_sw_interface_t sub_itf_template = {
+ .type = VNET_SW_INTERFACE_TYPE_SUB,
+ .sup_sw_if_index = hi->sw_if_index,
+ .sub.id = lisp_gpe_sub_interface_id++,
+ };
+
+ error = vnet_create_sw_interface (vnet_get_main (),
+ &sub_itf_template, &sub_sw_if_index);
+
+ if (NULL != error)
+ return (INDEX_INVALID);
+
+ pool_get (lisp_gpe_sub_interface_pool, l3s);
+ memset (l3s, 0, sizeof (*l3s));
+ l3s->key = clib_mem_alloc (sizeof (*l3s->key));
+ memset (l3s->key, 0, sizeof (*l3s->key));
+
+ l3s->key->local_rloc = *lrloc;
+ l3s->key->vni = clib_host_to_net_u32 (vni);
+ l3s->main_sw_if_index = hi->sw_if_index;
+ l3s->sw_if_index = sub_sw_if_index;
+ l3s->eid_table_id = overlay_table_id;
+
+ l3si = (l3s - lisp_gpe_sub_interface_pool);
+
+ lisp_gpe_sub_interface_set_table (l3s->sw_if_index, l3s->eid_table_id);
+ vnet_sw_interface_set_flags (vnet_get_main (),
+ l3s->sw_if_index,
+ VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+
+ lisp_gpe_sub_interface_db_insert (l3s);
+ }
+ else
+ {
+ l3s = lisp_gpe_sub_interface_get_i (l3si);
+ }
+
+ l3s->locks++;
+
+ return (l3si);
+}
+
+void
+lisp_gpe_sub_interface_unlock (index_t l3si)
+{
+ lisp_gpe_sub_interface_t *l3s;
+
+ l3s = lisp_gpe_sub_interface_get_i (l3si);
+
+ l3s->locks--;
+
+ if (0 == l3s->locks)
+ {
+ lisp_gpe_sub_interface_unset_table (l3s->sw_if_index,
+ l3s->eid_table_id);
+
+ vnet_sw_interface_set_flags (vnet_get_main (), l3s->sw_if_index, 0);
+ vnet_delete_sub_interface (l3s->sw_if_index);
+
+ lisp_gpe_sub_interface_db_remove (l3s);
+
+ clib_mem_free (l3s->key);
+ pool_put (lisp_gpe_sub_interface_pool, l3s);
+ }
+}
+
+const lisp_gpe_sub_interface_t *
+lisp_gpe_sub_interface_get (index_t l3si)
+{
+ return (lisp_gpe_sub_interface_get_i (l3si));
+}
+
+u8 *
+format_lisp_gpe_sub_interface (u8 * s, va_list ap)
+{
+ lisp_gpe_sub_interface_t *l3s = va_arg (ap, lisp_gpe_sub_interface_t *);
+ vnet_main_t *vnm = vnet_get_main ();
+
+ s = format (s, "%=16U",
+ format_vnet_sw_interface_name,
+ vnm, vnet_get_sw_interface (vnm, l3s->sw_if_index));
+ s = format (s, "%=10d", clib_net_to_host_u32 (l3s->key->vni));
+ s = format (s, "%=12d", l3s->sw_if_index);
+ s = format (s, "%U", format_ip_address, &l3s->key->local_rloc);
+
+ return (s);
+}
+
+/** CLI command to show LISP-GPE interfaces. */
+static clib_error_t *
+lisp_gpe_sub_interface_show (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ lisp_gpe_sub_interface_t *l3s;
+
+ vlib_cli_output (vm, "%=16s%=10s%=12s%s", "Name", "VNI", "SW IF Index",
+ "local RLOC");
+
+ /* *INDENT-OFF* */
+ pool_foreach (l3s, lisp_gpe_sub_interface_pool,
+ ({
+ vlib_cli_output (vm, "%U", format_lisp_gpe_sub_interface, l3s);
+ }));
+ /* *INDENT-ON* */
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (lisp_gpe_sub_interface_command) = {
+ .path = "show lisp gpe sub-interface",
+ .short_help = "show lisp gpe sub-interface",
+ .function = lisp_gpe_sub_interface_show,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+lisp_gpe_sub_interface_module_init (vlib_main_t * vm)
+{
+ lisp_gpe_sub_interfaces =
+ hash_create_mem (0,
+ sizeof (lisp_gpe_sub_interface_key_t), sizeof (uword));
+ lisp_gpe_sub_interfaces_sw_if_index =
+ hash_create_mem (0,
+ sizeof (lisp_gpe_sub_interface_key_t), sizeof (uword));
+
+ return (NULL);
+}
+
+VLIB_INIT_FUNCTION (lisp_gpe_sub_interface_module_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.h b/vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.h
new file mode 100644
index 00000000..ad942f41
--- /dev/null
+++ b/vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.h
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+/**
+ * @file
+ * @brief LISP sub-interfaces.
+ *
+ */
+
+#ifndef __LISP_GPE_SUB_INTERFACE_H__
+#define __LISP_GPE_SUB_INTERFACE_H__
+
+#include <vnet/lisp-gpe/lisp_gpe.h>
+
+/**
+ * A Key for lookup in the L£ sub-interface DB
+ */
+typedef struct lisp_gpe_sub_interface_key_t_
+{
+ /**
+ * The local-RLOC. This is the interface's 'source' address.
+ */
+ ip_address_t local_rloc;
+
+ /**
+ * The VNI. In network byte order!
+ */
+ u32 vni;
+} lisp_gpe_sub_interface_key_t;
+
+/**
+ * @brief A LISP L3 sub-interface
+ *
+ * A LISP sub-interface is a multi-access interface, whose local address is a
+ * single local-RLOC. Adjacencies that form on this sub-interface, represent
+ * remote RLOCs.
+ * This is analogous to an ethernet interface.
+ * As with all interface types it can only be present in one VRF, hence a
+ * LISP sub-interface is per-local-rloc and per-VNI.
+ */
+typedef struct lisp_gpe_sub_interface_t_
+{
+ /**
+ * The interface's key inthe DB; rloc & vni;
+ * The key is allocated from the heap so it can be used in the hash-table.
+ * if it's part of the object, then it is subjet to realloc, which no-worky.
+ */
+ lisp_gpe_sub_interface_key_t *key;
+
+ /**
+ * The Table-ID in the overlay that this interface is bound to.
+ */
+ u32 eid_table_id;
+
+ /**
+ * A reference counting lock on the number of users of this interface.
+ * When this count drops to 0 the interface is deleted.
+ */
+ u32 locks;
+
+ /**
+ * The SW if index assigned to this sub-interface
+ */
+ u32 sw_if_index;
+
+ /**
+ * The SW IF index assigned to the main interface of which this is a sub.
+ */
+ u32 main_sw_if_index;
+} lisp_gpe_sub_interface_t;
+
+extern index_t lisp_gpe_sub_interface_find_or_create_and_lock (const
+ ip_address_t *
+ lrloc,
+ u32
+ eid_table_id,
+ u32 vni);
+
+extern u8 *format_lisp_gpe_sub_interface (u8 * s, va_list ap);
+
+extern void lisp_gpe_sub_interface_unlock (index_t itf);
+
+extern const lisp_gpe_sub_interface_t *lisp_gpe_sub_interface_get (index_t
+ itf);
+
+/**
+ * A DB of all L3 sub-interfaces. The key is:{VNI,l-RLOC}
+ */
+extern uword *lisp_gpe_sub_interfaces_sw_if_index;
+
+/**
+ * @brief
+ * Get a VNET L3 interface matching the local-RLOC and VNI
+ * Called from the data-plane
+ */
+always_inline u32
+lisp_gpe_sub_interface_find_ip6 (const ip6_address_t * addr, u32 vni)
+{
+ lisp_gpe_sub_interface_key_t key;
+ const uword *p;
+
+ key.local_rloc.ip.v6.as_u64[0] = addr->as_u64[0];
+ key.local_rloc.ip.v6.as_u64[1] = addr->as_u64[1];
+ key.local_rloc.version = IP6;
+ key.vni = vni;
+
+ p = hash_get_mem (&lisp_gpe_sub_interfaces_sw_if_index, &key);
+
+ if (NULL != p)
+ return p[0];
+
+ return (INDEX_INVALID);
+}
+
+/**
+ * @brief
+ * Get a VNET L3 interface matching the local-RLOC and VNI
+ * Called from the data-plane
+ */
+always_inline index_t
+lisp_gpe_sub_interface_find_ip4 (const ip4_address_t * addr, u32 vni)
+{
+ lisp_gpe_sub_interface_key_t key;
+ const uword *p;
+
+ key.local_rloc.ip.v4.as_u32 = addr->as_u32;
+ key.local_rloc.version = IP4;
+ key.vni = vni;
+
+ p = hash_get_mem (&lisp_gpe_sub_interfaces_sw_if_index, &key);
+
+ if (NULL != p)
+ return p[0];
+
+ return (INDEX_INVALID);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
+
+#endif
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe_tunnel.c b/vnet/vnet/lisp-gpe/lisp_gpe_tunnel.c
new file mode 100644
index 00000000..0aecc0a1
--- /dev/null
+++ b/vnet/vnet/lisp-gpe/lisp_gpe_tunnel.c
@@ -0,0 +1,289 @@
+/*
+ * 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.
+ */
+/**
+ * @file
+ * @brief Common utility functions for IPv4, IPv6 and L2 LISP-GPE tunnels.
+ *
+ */
+#include <vnet/lisp-gpe/lisp_gpe.h>
+#include <vnet/lisp-gpe/lisp_gpe_tunnel.h>
+#include <vnet/lisp-gpe/lisp_gpe_adjacency.h>
+
+#include <vnet/fib/fib_table.h>
+
+/**
+ * @brief Pool of all LISP tunnels
+ */
+static lisp_gpe_tunnel_2_t *lisp_gpe_tunnel_pool;
+
+/**
+ * @brief a DB of all tunnels
+ */
+static uword *lisp_gpe_tunnel_db;
+
+/**
+ * @brief Compute IP-UDP-GPE sub-tunnel encap/rewrite header.
+ *
+ * @param[in] t Parent of the sub-tunnel.
+ * @param[in] st Sub-tunnel.
+ * @param[in] lp Local and remote locators used in the encap header.
+ *
+ * @return 0 on success.
+ */
+u8 *
+lisp_gpe_tunnel_build_rewrite (const lisp_gpe_tunnel_2_t * lgt,
+ const lisp_gpe_adjacency_t * ladj,
+ lisp_gpe_next_protocol_e payload_proto)
+{
+ lisp_gpe_header_t *lisp0;
+ u8 *rw = 0;
+ int len;
+
+ if (IP4 == ip_addr_version (&lgt->key->lcl))
+ {
+ ip4_udp_lisp_gpe_header_t *h0;
+ ip4_header_t *ip0;
+
+ len = sizeof (*h0);
+
+ vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
+
+ h0 = (ip4_udp_lisp_gpe_header_t *) rw;
+
+ /* Fixed portion of the (outer) ip4 header */
+ ip0 = &h0->ip4;
+ ip0->ip_version_and_header_length = 0x45;
+ ip0->ttl = 254;
+ ip0->protocol = IP_PROTOCOL_UDP;
+
+ /* we fix up the ip4 header length and checksum after-the-fact */
+ ip_address_copy_addr (&ip0->src_address, &lgt->key->lcl);
+ ip_address_copy_addr (&ip0->dst_address, &lgt->key->rmt);
+ ip0->checksum = ip4_header_checksum (ip0);
+
+ /* UDP header, randomize src port on something, maybe? */
+ h0->udp.src_port = clib_host_to_net_u16 (4341);
+ h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe);
+
+ /* LISP-gpe header */
+ lisp0 = &h0->lisp;
+ }
+ else
+ {
+ ip6_udp_lisp_gpe_header_t *h0;
+ ip6_header_t *ip0;
+
+ len = sizeof (*h0);
+
+ vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
+
+ h0 = (ip6_udp_lisp_gpe_header_t *) rw;
+
+ /* Fixed portion of the (outer) ip6 header */
+ ip0 = &h0->ip6;
+ ip0->ip_version_traffic_class_and_flow_label =
+ clib_host_to_net_u32 (0x6 << 28);
+ ip0->hop_limit = 254;
+ ip0->protocol = IP_PROTOCOL_UDP;
+
+ /* we fix up the ip6 header length after-the-fact */
+ ip_address_copy_addr (&ip0->src_address, &lgt->key->lcl);
+ ip_address_copy_addr (&ip0->dst_address, &lgt->key->rmt);
+
+ /* UDP header, randomize src port on something, maybe? */
+ h0->udp.src_port = clib_host_to_net_u16 (4341);
+ h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe);
+
+ /* LISP-gpe header */
+ lisp0 = &h0->lisp;
+ }
+
+ lisp0->flags = ladj->flags;
+ lisp0->ver_res = 0;
+ lisp0->res = 0;
+ lisp0->next_protocol = payload_proto;
+ lisp0->iid = clib_host_to_net_u32 (ladj->vni);
+
+ return (rw);
+}
+
+static lisp_gpe_tunnel_2_t *
+lisp_gpe_tunnel_db_find (const lisp_gpe_tunnel_key_t * key)
+{
+ uword *p;
+
+ p = hash_get_mem (lisp_gpe_tunnel_db, (void *) key);
+
+ if (NULL != p)
+ {
+ return (pool_elt_at_index (lisp_gpe_tunnel_pool, p[0]));
+ }
+ return (NULL);
+}
+
+lisp_gpe_tunnel_2_t *
+lisp_gpe_tunnel_get_i (index_t lgti)
+{
+ return (pool_elt_at_index (lisp_gpe_tunnel_pool, lgti));
+}
+
+index_t
+lisp_gpe_tunnel_find_or_create_and_lock (const locator_pair_t * pair,
+ u32 rloc_fib_index)
+{
+ lisp_gpe_tunnel_key_t key = {
+ .lcl = pair->lcl_loc,
+ .rmt = pair->rmt_loc,
+ .fib_index = rloc_fib_index,
+ };
+ lisp_gpe_tunnel_2_t *lgt;
+ fib_prefix_t pfx;
+
+ lgt = lisp_gpe_tunnel_db_find (&key);
+
+ if (NULL == lgt)
+ {
+ pool_get (lisp_gpe_tunnel_pool, lgt);
+ memset (lgt, 0, sizeof (*lgt));
+
+ lgt->key = clib_mem_alloc (sizeof (*lgt->key));
+ memset (lgt->key, 0, sizeof (*lgt->key));
+
+ lgt->key->rmt = pair->rmt_loc;
+ lgt->key->lcl = pair->lcl_loc;
+ lgt->key->fib_index = rloc_fib_index;
+
+ /*
+ * source the FIB entry for the RLOC so we can track its forwarding
+ * chain
+ */
+ ip_address_to_fib_prefix (&lgt->key->rmt, &pfx);
+
+ lgt->fib_entry_index = fib_table_entry_special_add (rloc_fib_index,
+ &pfx,
+ FIB_SOURCE_RR,
+ FIB_ENTRY_FLAG_NONE,
+ ADJ_INDEX_INVALID);
+
+ hash_set_mem (lisp_gpe_tunnel_db, &lgt->key,
+ (lgt - lisp_gpe_tunnel_pool));
+ }
+
+ lgt->locks++;
+
+ return (lgt - lisp_gpe_tunnel_pool);
+}
+
+void
+lisp_gpe_tunnel_unlock (index_t lgti)
+{
+ lisp_gpe_tunnel_2_t *lgt;
+
+ lgt = lisp_gpe_tunnel_get_i (lgti);
+ lgt->locks--;
+
+ if (0 == lgt->locks)
+ {
+ hash_unset_mem (lisp_gpe_tunnel_db, &lgt->key);
+ clib_mem_free (lgt->key);
+ pool_put (lisp_gpe_tunnel_pool, lgt);
+ }
+}
+
+const lisp_gpe_tunnel_2_t *
+lisp_gpe_tunnel_get (index_t lgti)
+{
+ return (lisp_gpe_tunnel_get_i (lgti));
+}
+
+/** Format LISP-GPE tunnel. */
+u8 *
+format_lisp_gpe_tunnel (u8 * s, va_list * args)
+{
+ lisp_gpe_tunnel_2_t *lgt = va_arg (*args, lisp_gpe_tunnel_2_t *);
+
+ s = format (s, "tunnel %d\n", lgt - lisp_gpe_tunnel_pool);
+ s = format (s, " fib-index: %d, locks:%d \n",
+ lgt->key->fib_index, lgt->locks);
+ s = format (s, " lisp ver 0\n");
+
+ s = format (s, " locator-pair:\n");
+ s = format (s, " local: %U remote: %U\n",
+ format_ip_address, &lgt->key->lcl,
+ format_ip_address, &lgt->key->rmt);
+ s = format (s, " RLOC FIB entry: %d\n", lgt->fib_entry_index);
+
+ return s;
+}
+
+/**
+ * CLI command to show LISP-GPE tunnels.
+ */
+static clib_error_t *
+show_lisp_gpe_tunnel_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ lisp_gpe_tunnel_2_t *lgt;
+ index_t index;
+
+ if (pool_elts (lisp_gpe_tunnel_pool) == 0)
+ vlib_cli_output (vm, "No lisp-gpe tunnels configured...");
+
+ if (unformat (input, "%d", &index))
+ {
+ lgt = lisp_gpe_tunnel_get_i (index);
+ vlib_cli_output (vm, "%U", format_lisp_gpe_tunnel, lgt);
+ }
+ else
+ {
+ /* *INDENT-OFF* */
+ pool_foreach (lgt, lisp_gpe_tunnel_pool,
+ ({
+ vlib_cli_output (vm, "%U", format_lisp_gpe_tunnel, lgt);
+ }));
+ /* *INDENT-ON* */
+ }
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) =
+{
+ .path = "show lisp gpe tunnel",
+ .function = show_lisp_gpe_tunnel_command_fn,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+lisp_gpe_tunnel_module_init (vlib_main_t * vm)
+{
+ lisp_gpe_tunnel_db = hash_create_mem (0,
+ sizeof (lisp_gpe_fwd_entry_key_t),
+ sizeof (uword));
+
+ return (NULL);
+}
+
+VLIB_INIT_FUNCTION (lisp_gpe_tunnel_module_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe_tunnel.h b/vnet/vnet/lisp-gpe/lisp_gpe_tunnel.h
new file mode 100644
index 00000000..d417fa99
--- /dev/null
+++ b/vnet/vnet/lisp-gpe/lisp_gpe_tunnel.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+/**
+ * @file
+ * @brief Common utility functions for IPv4, IPv6 and L2 LISP-GPE tunnels.
+ *
+ */
+
+#ifndef LISP_GPE_TUNNEL_H__
+#define LISP_GPE_TUNNEL_H__
+
+#include <vnet/lisp-gpe/lisp_gpe.h>
+#include <vnet/lisp-gpe/lisp_gpe_packet.h>
+
+/**
+ * Forward declaration
+ */
+struct lisp_gpe_adjacency_t_;
+
+/**
+ * A Key for a tunnel
+ */
+typedef struct lisp_gpe_tunnel_key_t_
+{
+ ip_address_t rmt;
+ ip_address_t lcl;
+ u32 fib_index;
+} lisp_gpe_tunnel_key_t;
+
+/**
+ * @brief A LISP GPE Tunnel.
+ *
+ * A tunnel represents an associatation between a local and remote RLOC.
+ * As such it represents a unique LISP rewrite.
+ */
+typedef struct lisp_gpe_tunnel_2_t_
+{
+ /**
+ * RLOC pair and rloc fib_index. This is the tunnel's key.
+ */
+ lisp_gpe_tunnel_key_t *key;
+
+ /**
+ * number of reference counting locks
+ */
+ u32 locks;
+
+ /**
+ * the FIB entry through which the remote rloc is reachable
+ s */
+ fib_node_index_t fib_entry_index;
+} lisp_gpe_tunnel_2_t;
+
+extern index_t lisp_gpe_tunnel_find_or_create_and_lock (const locator_pair_t *
+ pair,
+ u32 rloc_fib_index);
+
+extern void lisp_gpe_tunnel_unlock (index_t lgti);
+
+extern const lisp_gpe_tunnel_2_t *lisp_gpe_tunnel_get (index_t lgti);
+
+extern u8 *lisp_gpe_tunnel_build_rewrite (const lisp_gpe_tunnel_2_t * lgt,
+ const struct lisp_gpe_adjacency_t_
+ *ladj,
+ lisp_gpe_next_protocol_e
+ payload_proto);
+extern u8 *format_lisp_gpe_tunnel (u8 * s, va_list * args);
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */