From 0bfe5d8c792abcdbcf27bfcc7b7b353fba04aee2 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 25 Aug 2016 15:29:12 +0100 Subject: A Protocol Independent Hierarchical FIB (VPP-352) Main Enhancements: - Protocol Independent FIB API - Hierarchical FIB entries. Dynamic recursive route resolution. - Extranet Support. - Integration of IP and MPLS forwarding. - Separation of FIB and Adjacency databases. - Data-Plane Object forwarding model. Change-Id: I52dc815c0d0aa8b493e3cf6b978568f3cc82296c Signed-off-by: Neale Ranns --- plugins/ila-plugin/ila/ila.c | 390 +++++++++++++++++++++++++++---------------- 1 file changed, 249 insertions(+), 141 deletions(-) (limited to 'plugins/ila-plugin/ila/ila.c') diff --git a/plugins/ila-plugin/ila/ila.c b/plugins/ila-plugin/ila/ila.c index 99d1db8a..029dd219 100644 --- a/plugins/ila-plugin/ila/ila.c +++ b/plugins/ila-plugin/ila/ila.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include static ila_main_t ila_main; @@ -39,7 +41,6 @@ static char *ila_error_strings[] = { }; typedef enum { - ILA_ILA2SIR_NEXT_IP6_REWRITE, ILA_ILA2SIR_NEXT_DROP, ILA_ILA2SIR_N_NEXT, } ila_ila2sir_next_t; @@ -56,6 +57,16 @@ static ila_entry_t ila_sir2ila_default_entry = { .dir = ILA_DIR_ILA2SIR, //Will pass the packet with no }; +/** + * @brief Dynamically registered DPO Type for ILA + */ +static dpo_type_t ila_dpo_type; + +/** + * @brief Dynamically registered FIB node type for ILA + */ +static fib_node_type_t ila_fib_node_type; + u8 * format_half_ip6_address (u8 * s, va_list * va) { @@ -120,28 +131,29 @@ format_ila_entry (u8 * s, va_list * va) if (!e) { return format (s, "%-15s%=40s%=40s%+16s%+18s%+11s", "Type", "SIR Address", - "ILA Address", "Adjacency Index", "Checksum Mode", "Direction"); - + "ILA Address", "Checksum Mode", "Direction", "Next DPO"); } else if (vnm) { - if (e->ila_adj_index == ~0) + if (ip6_address_is_zero(&e->next_hop)) { - return format (s, "%-15U%=40U%=40U%16s%18U%11U", + return format (s, "%-15U%=40U%=40U%18U%11U%s", format_ila_type, e->type, format_ip6_address, &e->sir_address, format_ip6_address, &e->ila_address, - "n/a", format_csum_mode, e->csum_mode, - format_ila_direction, e->dir); + format_csum_mode, e->csum_mode, + format_ila_direction, e->dir, + "n/a"); } else { - return format (s, "%-15U%=40U%=40U%16d%18U%11U", + return format (s, "%-15U%=40U%=40U%18U%11U%U", format_ila_type, e->type, format_ip6_address, &e->sir_address, format_ip6_address, &e->ila_address, - e->ila_adj_index, format_csum_mode, e->csum_mode, - format_ila_direction, e->dir); + format_csum_mode, e->csum_mode, + format_ila_direction, e->dir, + format_dpo_id, &e->ila_dpo, 0); } } @@ -239,8 +251,6 @@ static uword ila_ila2sir (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - ip6_main_t *im = &ip6_main; - ip_lookup_main_t *lm = &im->lookup_main; u32 n_left_from, *from, next_index, *to_next, n_left_to_next; ila_main_t *ilm = &ila_main; @@ -256,10 +266,8 @@ ila_ila2sir (vlib_main_t * vm, { u32 pi0, pi1; vlib_buffer_t *p0, *p1; - ip_adjacency_t *adj0, *adj1; ila_entry_t *ie0, *ie1; ip6_header_t *ip60, *ip61; - ila_adj_data_t *ad0, *ad1; ip6_address_t *sir_address0, *sir_address1; { @@ -287,14 +295,10 @@ ila_ila2sir (vlib_main_t * vm, ip61 = vlib_buffer_get_current (p1); sir_address0 = &ip60->dst_address; sir_address1 = &ip61->dst_address; - adj0 = - ip_get_adjacency (lm, vnet_buffer (p0)->ip.adj_index[VLIB_TX]); - adj1 = - ip_get_adjacency (lm, vnet_buffer (p1)->ip.adj_index[VLIB_TX]); - ad0 = (ila_adj_data_t *) & adj0->opaque; - ad1 = (ila_adj_data_t *) & adj1->opaque; - ie0 = pool_elt_at_index (ilm->entries, ad0->entry_index); - ie1 = pool_elt_at_index (ilm->entries, ad1->entry_index); + ie0 = pool_elt_at_index (ilm->entries, + vnet_buffer (p0)->ip.adj_index[VLIB_TX]); + ie1 = pool_elt_at_index (ilm->entries, + vnet_buffer (p1)->ip.adj_index[VLIB_TX]); if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) { @@ -321,13 +325,13 @@ ila_ila2sir (vlib_main_t * vm, ip61->dst_address.as_u64[0] = sir_address1->as_u64[0]; ip61->dst_address.as_u64[1] = sir_address1->as_u64[1]; - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_adj_index; - vnet_buffer (p1)->ip.adj_index[VLIB_TX] = ie1->ila_adj_index; + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; + vnet_buffer (p1)->ip.adj_index[VLIB_TX] = ie1->ila_dpo.dpoi_index; vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, n_left_to_next, pi0, pi1, - ILA_ILA2SIR_NEXT_IP6_REWRITE, - ILA_ILA2SIR_NEXT_IP6_REWRITE); + ie0->ila_dpo.dpoi_next_node, + ie1->ila_dpo.dpoi_next_node); } /* Single loop */ @@ -335,8 +339,6 @@ ila_ila2sir (vlib_main_t * vm, { u32 pi0; vlib_buffer_t *p0; - ip_adjacency_t *adj0; - ila_adj_data_t *ad0; ila_entry_t *ie0; ip6_header_t *ip60; ip6_address_t *sir_address0; @@ -350,10 +352,8 @@ ila_ila2sir (vlib_main_t * vm, p0 = vlib_get_buffer (vm, pi0); ip60 = vlib_buffer_get_current (p0); sir_address0 = &ip60->dst_address; - adj0 = - ip_get_adjacency (lm, vnet_buffer (p0)->ip.adj_index[VLIB_TX]); - ad0 = (ila_adj_data_t *) & adj0->opaque; - ie0 = pool_elt_at_index (ilm->entries, ad0->entry_index); + ie0 = pool_elt_at_index (ilm->entries, + vnet_buffer (p0)->ip.adj_index[VLIB_TX]); if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) { @@ -367,11 +367,11 @@ ila_ila2sir (vlib_main_t * vm, sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_adj_index; + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, - ILA_ILA2SIR_NEXT_IP6_REWRITE); + ie0->ila_dpo.dpoi_next_node); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } @@ -379,16 +379,22 @@ ila_ila2sir (vlib_main_t * vm, return frame->n_vectors; } +/** *INDENT-OFF* */ VLIB_REGISTER_NODE (ila_ila2sir_node, static) = { - .function = ila_ila2sir,.name = "ila-to-sir",.vector_size = - sizeof (u32),.format_trace = format_ila_ila2sir_trace,.n_errors = - ILA_N_ERROR,.error_strings = ila_error_strings,.n_next_nodes = - ILA_ILA2SIR_N_NEXT,.next_nodes = + .function = ila_ila2sir, + .name = "ila-to-sir", + .vector_size = sizeof (u32), + .format_trace = format_ila_ila2sir_trace, + .n_errors = ILA_N_ERROR, + .error_strings = ila_error_strings, + .n_next_nodes = ILA_ILA2SIR_N_NEXT, + .next_nodes = { - [ILA_ILA2SIR_NEXT_IP6_REWRITE] = "ip6-rewrite", - [ILA_ILA2SIR_NEXT_DROP] = "error-drop"} -,}; + [ILA_ILA2SIR_NEXT_DROP] = "error-drop" + }, +}; +/** *INDENT-ON* */ typedef enum { @@ -580,28 +586,48 @@ ila_sir2ila (vlib_main_t * vm, return frame->n_vectors; } +/** *INDENT-OFF* */ VLIB_REGISTER_NODE (ila_sir2ila_node, static) = { - .function = ila_sir2ila,.name = "sir-to-ila",.vector_size = - sizeof (u32),.format_trace = format_ila_sir2ila_trace,.n_errors = - ILA_N_ERROR,.error_strings = ila_error_strings,.n_next_nodes = - ILA_SIR2ILA_N_NEXT,.next_nodes = + .function = ila_sir2ila,.name = "sir-to-ila", + .vector_size = sizeof (u32), + .format_trace = format_ila_sir2ila_trace, + .n_errors = ILA_N_ERROR, + .error_strings = ila_error_strings, + .n_next_nodes = ILA_SIR2ILA_N_NEXT, + .next_nodes = { - [ILA_SIR2ILA_NEXT_DROP] = "error-drop"} -,}; + [ILA_SIR2ILA_NEXT_DROP] = "error-drop" + }, +}; +/** *INDENT-ON* */ +/** *INDENT-OFF* */ VNET_IP6_UNICAST_FEATURE_INIT (ila_sir2ila, static) = { .node_name = "sir-to-ila", .runs_before = ORDER_CONSTRAINTS{"ip6-lookup", 0}, .feature_index = &ila_main.ila_sir2ila_feature_index, }; +/** *INDENT-ON* */ + +static void +ila_entry_stack (ila_entry_t *ie) +{ + /* + * restack on the next-hop's FIB entry + */ + dpo_stack(ila_dpo_type, + DPO_PROTO_IP6, + &ie->ila_dpo, + fib_entry_contribute_ip_forwarding( + ie->next_hop_fib_entry_index)); +} int ila_add_del_entry (ila_add_del_entry_args_t * args) { ila_main_t *ilm = &ila_main; - ip6_main_t *im6 = &ip6_main; BVT (clib_bihash_kv) kv, value; //Sanity check @@ -642,7 +668,7 @@ ila_add_del_entry (ila_add_del_entry_args_t * args) pool_get (ilm->entries, e); e->type = args->type; e->sir_address = args->sir_address; - e->ila_adj_index = args->local_adj_index; + e->next_hop = args->next_hop_address; e->csum_mode = args->csum_mode; e->dir = args->dir; @@ -698,31 +724,56 @@ ila_add_del_entry (ila_add_del_entry_args_t * args) BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, 1 /* is_add */ ); - if (e->ila_adj_index != ~0) + if (!ip6_address_is_zero(&e->next_hop)) { - //This is a local entry - let's create a local adjacency - ip_adjacency_t adj; - ip6_add_del_route_args_t route_args; - ila_adj_data_t *ad; - - //Adjacency - memset (&adj, 0, sizeof (adj)); - adj.explicit_fib_index = ~0; - adj.lookup_next_index = ilm->ip6_lookup_next_index; - ad = (ila_adj_data_t *) & adj.opaque; - ad->entry_index = e - ilm->entries; - - //Route - memset (&route_args, 0, sizeof (route_args)); - route_args.table_index_or_table_id = 0; - route_args.flags = IP6_ROUTE_FLAG_ADD; - route_args.dst_address = e->ila_address; - route_args.dst_address_length = 128; - route_args.adj_index = ~0; - route_args.add_adj = &adj; - route_args.n_add_adj = 1; - - ip6_add_del_route (im6, &route_args); + /* + * become a child of the FIB netry for the next-hop + * so we are informed when its forwarding changes + */ + fib_prefix_t next_hop = { + .fp_addr = { + .ip6 = e->next_hop, + }, + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + e->next_hop_fib_entry_index = + fib_table_entry_special_add(0, + &next_hop, + FIB_SOURCE_RR, + FIB_ENTRY_FLAG_NONE, + ADJ_INDEX_INVALID); + e->next_hop_child_index = + fib_entry_child_add(e->next_hop_fib_entry_index, + ila_fib_node_type, + e - ilm->entries); + + /* + * Create a route that results in the ILA entry + */ + dpo_id_t dpo = DPO_NULL; + fib_prefix_t pfx = { + .fp_addr = { + .ip6 = e->ila_address, + }, + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + dpo_set(&dpo, ila_dpo_type, DPO_PROTO_IP6, e - ilm->entries); + + fib_table_entry_special_dpo_add(0, + &pfx, + FIB_SOURCE_PLUGIN_HI, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo); + dpo_reset(&dpo); + + /* + * finally stack the ILA entry so it will forward to the next-hop + */ + ila_entry_stack (e); } } else @@ -740,21 +791,27 @@ ila_add_del_entry (ila_add_del_entry_args_t * args) e = &ilm->entries[value.value]; - if (e->ila_adj_index != ~0) + if (!ip6_address_is_zero(&e->next_hop)) { - //Delete that route - Associated adjacency will be deleted too - ip6_add_del_route_args_t route_args; - memset (&route_args, 0, sizeof (route_args)); - route_args.table_index_or_table_id = 0; - route_args.flags = IP6_ROUTE_FLAG_DEL; - route_args.dst_address = e->ila_address; - route_args.dst_address_length = 128; - route_args.adj_index = ~0; - route_args.add_adj = NULL; - route_args.n_add_adj = 0; - - ip6_add_del_route (im6, &route_args); + fib_prefix_t pfx = { + .fp_addr = { + .ip6 = e->ila_address, + }, + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_PLUGIN_HI); + /* + * remove this ILA entry as child of the FIB netry for the next-hop + */ + fib_entry_child_remove(e->next_hop_fib_entry_index, + e->next_hop_child_index); + fib_table_entry_delete_index(e->next_hop_fib_entry_index, + FIB_SOURCE_RR); + e->next_hop_fib_entry_index = FIB_NODE_INDEX_INVALID; } + dpo_reset (&e->ila_dpo); BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, 0 /* is_add */ ); @@ -796,24 +853,103 @@ vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h, return error; } -u8 *ila_format_adjacency(u8 * s, va_list * va) +u8 *format_ila_dpo (u8 * s, va_list * va) { + index_t index = va_arg (*va, index_t); + CLIB_UNUSED(u32 indent) = va_arg (*va, u32); ila_main_t *ilm = &ila_main; - __attribute((unused)) ip_lookup_main_t *lm = va_arg (*va, ip_lookup_main_t *); - ip_adjacency_t *adj = va_arg (*va, ip_adjacency_t *); - ila_adj_data_t * ad = (ila_adj_data_t *) & adj->opaque; - ila_entry_t *ie = pool_elt_at_index (ilm->entries, ad->entry_index); - return format(s, "idx:%d sir:%U", ad->entry_index, format_ip6_address, &ie->sir_address); + ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); + return format(s, "ILA: idx:%d sir:%U", + index, + format_ip6_address, &ie->sir_address); +} + +/** + * @brief no-op lock function. + * The lifetime of the ILA entry is managed by the control plane + */ +static void +ila_dpo_lock (dpo_id_t *dpo) +{ } +/** + * @brief no-op unlock function. + * The lifetime of the ILA entry is managed by the control plane + */ +static void +ila_dpo_unlock (dpo_id_t *dpo) +{ +} + +const static dpo_vft_t ila_vft = { + .dv_lock = ila_dpo_lock, + .dv_unlock = ila_dpo_unlock, + .dv_format = format_ila_dpo, +}; +const static char* const ila_ip6_nodes[] = +{ + "ila-to-sir", + NULL, +}; +const static char* const * const ila_nodes[DPO_PROTO_NUM] = +{ + [DPO_PROTO_IP6] = ila_ip6_nodes, +}; + +static fib_node_t * +ila_fib_node_get_node (fib_node_index_t index) +{ + ila_main_t *ilm = &ila_main; + ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); + + return (&ie->ila_fib_node); +} + +/** + * @brief no-op unlock function. + * The lifetime of the ILA entry is managed by the control plane + */ +static void +ila_fib_node_last_lock_gone (fib_node_t *node) +{ +} + +static ila_entry_t * +ila_entry_from_fib_node (fib_node_t *node) +{ + return ((ila_entry_t*)(((char*)node) - + STRUCT_OFFSET_OF(ila_entry_t, ila_fib_node))); +} + +/** + * @brief + * Callback function invoked when the forwarding changes for the ILA next-hop + */ +static fib_node_back_walk_rc_t +ila_fib_node_back_walk_notify (fib_node_t *node, + fib_node_back_walk_ctx_t *ctx) +{ + ila_entry_stack(ila_entry_from_fib_node(node)); + + return (FIB_NODE_BACK_WALK_CONTINUE); +} + +/* + * ILA's FIB graph node virtual function table + */ +static const fib_node_vft_t ila_fib_node_vft = { + .fnv_get = ila_fib_node_get_node, + .fnv_last_lock = ila_fib_node_last_lock_gone, + .fnv_back_walk = ila_fib_node_back_walk_notify, +}; + clib_error_t * ila_init (vlib_main_t * vm) { ila_main_t *ilm = &ila_main; ilm->entries = NULL; - ASSERT (sizeof (ila_adj_data_t) < IP_ADJACENCY_OPAQUE_SZ); - ilm->lookup_table_nbuckets = ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS; ilm->lookup_table_nbuckets = 1 << max_log2 (ilm->lookup_table_nbuckets); ilm->lookup_table_size = ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE; @@ -822,15 +958,12 @@ ila_init (vlib_main_t * vm) "ila id to entry index table", ilm->lookup_table_nbuckets, ilm->lookup_table_size); + ila_dpo_type = dpo_register_new_type(&ila_vft, ila_nodes); + ila_fib_node_type = fib_node_register_new_type(&ila_fib_node_vft); + return NULL; } -VNET_IP6_REGISTER_ADJACENCY(ila2sir) = { - .node_name = "ila-to-sir", - .fn = ila_format_adjacency, - .next_index = &ila_main.ip6_lookup_next_index -}; - VLIB_INIT_FUNCTION (ila_init); static clib_error_t * @@ -839,9 +972,7 @@ ila_entry_command_fn (vlib_main_t * vm, { unformat_input_t _line_input, *line_input = &_line_input; ila_add_del_entry_args_t args = { 0 }; - ip6_address_t next_hop; u8 next_hop_set = 0; - ip6_main_t *im6 = &ip6_main; int ret; args.type = ILA_TYPE_IID; @@ -856,32 +987,27 @@ ila_entry_command_fn (vlib_main_t * vm, { if (unformat (line_input, "type %U", unformat_ila_type, &args.type)) ; - else - if (unformat - (line_input, "sir-address %U", unformat_ip6_address, - &args.sir_address)) - ; - else - if (unformat - (line_input, "locator %U", unformat_half_ip6_address, - &args.locator)) + else if (unformat + (line_input, "sir-address %U", unformat_ip6_address, + &args.sir_address)) ; - else if (unformat (line_input, "adj-index %u", &args.local_adj_index)) + else if (unformat + (line_input, "locator %U", unformat_half_ip6_address, + &args.locator)) ; - else - if (unformat - (line_input, "csum-mode %U", unformat_ila_csum_mode, - &args.csum_mode)) + else if (unformat + (line_input, "csum-mode %U", unformat_ila_csum_mode, + &args.csum_mode)) ; else if (unformat (line_input, "vnid %x", &args.vnid)) ; - else - if (unformat - (line_input, "next-hop %U", unformat_ip6_address, &next_hop)) - next_hop_set = 1; + else if (unformat + (line_input, "next-hop %U", unformat_ip6_address, + &args.next_hop_address)) + ; else if (unformat (line_input, "direction %U", unformat_ila_direction, &args.dir)) - ; + next_hop_set = 1; else if (unformat (line_input, "del")) args.is_del = 1; else @@ -891,26 +1017,8 @@ ila_entry_command_fn (vlib_main_t * vm, unformat_free (line_input); - if (next_hop_set) - { - if (args.local_adj_index != ~0) - return clib_error_return (0, - "Specified both next hop and adjacency index"); - - u32 ai = ip6_get_route (im6, 0, 0, &next_hop, 128); - if (ai == 0) - return clib_error_return (0, "No route to next-hop %U", - format_ip6_address, &next_hop); - - ip_lookup_main_t *lm6 = &ip6_main.lookup_main; - ip_adjacency_t *adj6 = ip_get_adjacency (lm6, ai); - if (adj6->lookup_next_index != IP_LOOKUP_NEXT_REWRITE) - { - return clib_error_return (0, - "Next-Hop route has to be a rewrite route"); - } - args.local_adj_index = ai; - } + if (!next_hop_set) + return clib_error_return (0, "Specified a next hop"); if ((ret = ila_add_del_entry (&args))) return clib_error_return (0, "ila_add_del_entry returned error %d", ret); -- cgit 1.2.3-korg