From 8082380922c65702251d5242058f7b5f35011574 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Mon, 20 Feb 2017 18:23:41 -0800 Subject: MAP pre-resolve - use FIB to track pre-resolved next-hop Change-Id: I9ea16881caf7aee57f0daf4ac2e8b82c672f87e9 Signed-off-by: Neale Ranns --- src/vnet/map/ip4_map.c | 16 ++--- src/vnet/map/ip6_map.c | 16 ++--- src/vnet/map/map.c | 172 ++++++++++++++++++++++++++++++++++++++++++------- src/vnet/map/map.h | 41 ++++++++++-- 4 files changed, 190 insertions(+), 55 deletions(-) (limited to 'src/vnet/map') diff --git a/src/vnet/map/ip4_map.c b/src/vnet/map/ip4_map.c index 9fd10f62..2be9ad37 100644 --- a/src/vnet/map/ip4_map.c +++ b/src/vnet/map/ip4_map.c @@ -173,18 +173,10 @@ static_always_inline bool ip4_map_ip6_lookup_bypass (vlib_buffer_t * p0, ip4_header_t * ip) { #ifdef MAP_SKIP_IP6_LOOKUP - map_main_t *mm = &map_main; - u32 adj_index0 = mm->adj6_index; - if (adj_index0 > 0) + if (FIB_NODE_INDEX_INVALID != pre_resolved[FIB_PROTOCOL_IP6].fei) { - ip_lookup_main_t *lm6 = &ip6_main.lookup_main; - ip_adjacency_t *adj = ip_get_adjacency (lm6, mm->adj6_index); - if (adj->n_adj > 1) - { - u32 hash_c0 = ip4_compute_flow_hash (ip, IP_FLOW_HASH_DEFAULT); - adj_index0 += (hash_c0 & (adj->n_adj - 1)); - } - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0; + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = + pre_resolved[FIB_PROTOCOL_IP6].dpo.dpoi_index; return (true); } #endif @@ -773,7 +765,7 @@ VLIB_REGISTER_NODE(ip4_map_node) = { .next_nodes = { [IP4_MAP_NEXT_IP6_LOOKUP] = "ip6-lookup", #ifdef MAP_SKIP_IP6_LOOKUP - [IP4_MAP_NEXT_IP6_REWRITE] = "ip6-rewrite", + [IP4_MAP_NEXT_IP6_REWRITE] = "ip6-load-balance", #endif [IP4_MAP_NEXT_IP4_FRAGMENT] = "ip4-frag", [IP4_MAP_NEXT_IP6_FRAGMENT] = "ip6-frag", diff --git a/src/vnet/map/ip6_map.c b/src/vnet/map/ip6_map.c index d2945059..f7eb768f 100644 --- a/src/vnet/map/ip6_map.c +++ b/src/vnet/map/ip6_map.c @@ -151,18 +151,10 @@ static_always_inline bool ip6_map_ip4_lookup_bypass (vlib_buffer_t * p0, ip4_header_t * ip) { #ifdef MAP_SKIP_IP6_LOOKUP - map_main_t *mm = &map_main; - u32 adj_index0 = mm->adj4_index; - if (adj_index0 > 0) + if (FIB_NODE_INDEX_INVALID != pre_resolved[FIB_PROTOCOL_IP4].fei) { - ip_lookup_main_t *lm4 = &ip4_main.lookup_main; - ip_adjacency_t *adj = ip_get_adjacency (lm4, mm->adj4_index); - if (adj->n_adj > 1) - { - u32 hash_c0 = ip4_compute_flow_hash (ip, IP_FLOW_HASH_DEFAULT); - adj_index0 += (hash_c0 & (adj->n_adj - 1)); - } - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0; + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = + pre_resolved[FIB_PROTOCOL_IP4].dpo.dpoi_index; return (true); } #endif @@ -1195,7 +1187,7 @@ VLIB_REGISTER_NODE(ip6_map_node) = { .next_nodes = { [IP6_MAP_NEXT_IP4_LOOKUP] = "ip4-lookup", #ifdef MAP_SKIP_IP6_LOOKUP - [IP6_MAP_NEXT_IP4_REWRITE] = "ip4-rewrite", + [IP6_MAP_NEXT_IP4_REWRITE] = "ip4-load-balance", #endif [IP6_MAP_NEXT_IP6_REASS] = "ip6-map-ip6-reass", [IP6_MAP_NEXT_IP4_REASS] = "ip6-map-ip4-reass", diff --git a/src/vnet/map/map.c b/src/vnet/map/map.c index a2d28118..6823a46e 100644 --- a/src/vnet/map/map.c +++ b/src/vnet/map/map.c @@ -41,6 +41,7 @@ crc_u32 (u32 data, u32 value) } #endif + /* * This code supports the following MAP modes: * @@ -437,23 +438,141 @@ map_add_del_psid (u32 map_domain_index, u16 psid, ip6_address_t * tep, } #ifdef MAP_SKIP_IP6_LOOKUP +/** + * Pre-resolvd per-protocol global next-hops + */ +map_main_pre_resolved_t pre_resolved[FIB_PROTOCOL_MAX]; + static void -map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6) +map_pre_resolve_init (map_main_pre_resolved_t * pr) { - map_main_t *mm = &map_main; - ip6_main_t *im6 = &ip6_main; + pr->fei = FIB_NODE_INDEX_INVALID; + fib_node_init (&pr->node, FIB_NODE_TYPE_MAP_E); +} + +static u8 * +format_map_pre_resolve (u8 * s, va_list ap) +{ + map_main_pre_resolved_t *pr = va_arg (ap, map_main_pre_resolved_t *); + + if (FIB_NODE_INDEX_INVALID != pr->fei) + { + fib_prefix_t pfx; + + fib_entry_get_prefix (pr->fei, &pfx); + + return (format (s, "%U (%u)", + format_ip46_address, &pfx.fp_addr, IP46_TYPE_ANY, + pr->dpo.dpoi_index)); + } + else + { + return (format (s, "un-set")); + } +} + + +/** + * Function definition to inform the FIB node that its last lock has gone. + */ +static void +map_last_lock_gone (fib_node_t * node) +{ + /* + * The MAP is a root of the graph. As such + * it never has children and thus is never locked. + */ + ASSERT (0); +} + +static map_main_pre_resolved_t * +map_from_fib_node (fib_node_t * node) +{ +#if (CLIB_DEBUG > 0) + ASSERT (FIB_NODE_TYPE_MAP_E == node->fn_type); +#endif + return ((map_main_pre_resolved_t *) + (((char *) node) - + STRUCT_OFFSET_OF (map_main_pre_resolved_t, node))); +} + +static void +map_stack (map_main_pre_resolved_t * pr) +{ + const dpo_id_t *dpo; - if (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0) + dpo = fib_entry_contribute_ip_forwarding (pr->fei); + + dpo_copy (&pr->dpo, dpo); +} + +/** + * Function definition to backwalk a FIB node + */ +static fib_node_back_walk_rc_t +map_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx) +{ + map_stack (map_from_fib_node (node)); + + return (FIB_NODE_BACK_WALK_CONTINUE); +} + +/** + * Function definition to get a FIB node from its index + */ +static fib_node_t * +map_fib_node_get (fib_node_index_t index) +{ + return (&pre_resolved[index].node); +} + +/* + * Virtual function table registered by MPLS GRE tunnels + * for participation in the FIB object graph. + */ +const static fib_node_vft_t map_vft = { + .fnv_get = map_fib_node_get, + .fnv_last_lock = map_last_lock_gone, + .fnv_back_walk = map_back_walk, +}; + +static void +map_fib_resolve (map_main_pre_resolved_t * pr, + fib_protocol_t proto, u8 len, const ip46_address_t * addr) +{ + fib_prefix_t pfx = { + .fp_proto = proto, + .fp_len = len, + .fp_addr = *addr, + }; + + pr->fei = fib_table_entry_special_add (0, // default fib + &pfx, + FIB_SOURCE_RR, + FIB_ENTRY_FLAG_NONE, + ADJ_INDEX_INVALID); + pr->sibling = fib_entry_child_add (pr->fei, FIB_NODE_TYPE_MAP_E, proto); + map_stack (pr); +} + +static void +map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6) +{ + if (ip6 && (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0)) { - // FIXME NOT an ADJ - mm->adj6_index = ip6_fib_table_fwding_lookup (im6, 0, ip6); - clib_warning ("FIB lookup results in: %u", mm->adj6_index); + ip46_address_t addr = { + .ip6 = *ip6, + }; + map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP6], + FIB_PROTOCOL_IP6, 128, &addr); } - if (ip4->as_u32 != 0) + if (ip4 && (ip4->as_u32 != 0)) { - // FIXME NOT an ADJ - mm->adj4_index = ip4_fib_table_lookup_lb (0, ip4); - clib_warning ("FIB lookup results in: %u", mm->adj4_index); + ip46_address_t addr = { + .ip4 = *ip4, + }; + map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP4], + FIB_PROTOCOL_IP4, 32, &addr); } } #endif @@ -695,9 +814,8 @@ map_pre_resolve_command_fn (vlib_main_t * vm, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t ip4nh; - ip6_address_t ip6nh; - map_main_t *mm = &map_main; + ip4_address_t ip4nh, *p_v4 = NULL; + ip6_address_t ip6nh, *p_v6 = NULL; clib_error_t *error = NULL; memset (&ip4nh, 0, sizeof (ip4nh)); @@ -710,10 +828,10 @@ map_pre_resolve_command_fn (vlib_main_t * vm, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "ip4-nh %U", unformat_ip4_address, &ip4nh)) - mm->preresolve_ip4 = ip4nh; + p_v4 = &ip4nh; else if (unformat (line_input, "ip6-nh %U", unformat_ip6_address, &ip6nh)) - mm->preresolve_ip6 = ip6nh; + p_v6 = &ip6nh; else { error = clib_error_return (0, "unknown input `%U'", @@ -722,7 +840,7 @@ map_pre_resolve_command_fn (vlib_main_t * vm, } } - map_pre_resolve (&ip4nh, &ip6nh); + map_pre_resolve (p_v4, p_v6); done: unformat_free (line_input); @@ -1113,9 +1231,10 @@ show_map_stats_command_fn (vlib_main_t * vm, unformat_input_t * input, #if MAP_SKIP_IP6_LOOKUP vlib_cli_output (vm, - "MAP pre-resolve: IP6 next-hop: %U (%u), IP4 next-hop: %U (%u)\n", - format_ip6_address, &mm->preresolve_ip6, mm->adj6_index, - format_ip4_address, &mm->preresolve_ip4, mm->adj4_index); + "MAP pre-resolve: IP6 next-hop: %U, IP4 next-hop: %U\n", + format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP6], + format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP4]); + #endif if (mm->tc_copy) @@ -2180,10 +2299,12 @@ map_init (vlib_main_t * vm) mm->vlib_main = vm; #ifdef MAP_SKIP_IP6_LOOKUP - memset (&mm->preresolve_ip4, 0, sizeof (mm->preresolve_ip4)); - memset (&mm->preresolve_ip6, 0, sizeof (mm->preresolve_ip6)); - mm->adj4_index = 0; - mm->adj6_index = 0; + fib_protocol_t proto; + + FOR_EACH_FIB_PROTOCOL (proto) + { + map_pre_resolve_init (&pre_resolved[proto]); + } #endif /* traffic class */ @@ -2238,6 +2359,9 @@ map_init (vlib_main_t * vm) mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE; map_ip6_reass_reinit (NULL, NULL); +#ifdef MAP_SKIP_IP6_LOOKUP + fib_node_register_type (FIB_NODE_TYPE_MAP_E, &map_vft); +#endif map_dpo_module_init (); return 0; diff --git a/src/vnet/map/map.h b/src/vnet/map/map.h index f446b739..616d42c0 100644 --- a/src/vnet/map/map.h +++ b/src/vnet/map/map.h @@ -198,6 +198,40 @@ typedef struct { map_ip6_fragment_t fragments[MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY]; } map_ip6_reass_t; +#ifdef MAP_SKIP_IP6_LOOKUP +/** + * A pre-resolved next-hop + */ +typedef struct map_main_pre_resolved_t_ +{ + /** + * Linkage into the FIB graph + */ + fib_node_t node; + + /** + * The FIB entry index of the next-hop + */ + fib_node_index_t fei; + + /** + * This object sibling index on the FIB entry's child dependency list + */ + u32 sibling; + + /** + * The Load-balance object index to use to forward + */ + dpo_id_t dpo; +} map_main_pre_resolved_t; + +/** + * Pre-resolved next hops for v4 and v6. Why these are global and not + * per-domain is beyond me. + */ +extern map_main_pre_resolved_t pre_resolved[FIB_PROTOCOL_MAX]; +#endif + typedef struct { /* pool of MAP domains */ map_domain_t *domains; @@ -207,13 +241,6 @@ typedef struct { vlib_combined_counter_main_t *domain_counters; volatile u32 *counter_lock; -#ifdef MAP_SKIP_IP6_LOOKUP - /* pre-presolve */ - u32 adj6_index, adj4_index; - ip4_address_t preresolve_ip4; - ip6_address_t preresolve_ip6; -#endif - /* Traffic class: zero, copy (~0) or fixed value */ u8 tc; bool tc_copy; -- cgit 1.2.3-korg