diff options
Diffstat (limited to 'vnet/vnet/lisp-gpe')
-rw-r--r-- | vnet/vnet/lisp-gpe/interface.c | 656 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/ip_forward.c | 1593 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe.c | 855 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe.h | 232 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c | 437 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe_adjacency.h | 134 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.c | 286 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.h | 157 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe_tunnel.c | 289 | ||||
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe_tunnel.h | 89 |
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: + */ |