diff options
-rw-r--r-- | vnet/vnet/adj/adj_midchain.c | 3 | ||||
-rw-r--r-- | vnet/vnet/fib/fib_entry_src_mpls.c | 13 | ||||
-rw-r--r-- | vnet/vnet/fib/fib_node.h | 2 | ||||
-rw-r--r-- | vnet/vnet/fib/fib_table.c | 19 | ||||
-rw-r--r-- | vnet/vnet/fib/fib_test.c | 51 | ||||
-rw-r--r-- | vnet/vnet/mpls/interface.c | 943 | ||||
-rw-r--r-- | vnet/vnet/mpls/mpls.c | 330 | ||||
-rw-r--r-- | vnet/vnet/mpls/mpls.h | 96 | ||||
-rw-r--r-- | vnet/vnet/mpls/mpls_lookup.c | 6 | ||||
-rw-r--r-- | vnet/vnet/mpls/mpls_output.c | 1 | ||||
-rw-r--r-- | vnet/vnet/mpls/node.c | 2 | ||||
-rw-r--r-- | vnet/vnet/mpls/pg.c | 2 | ||||
-rw-r--r-- | vnet/vnet/mpls/policy_encap.c | 1 | ||||
-rw-r--r-- | vpp-api-test/vat/api_format.c | 615 | ||||
-rw-r--r-- | vpp/vpp-api/api.c | 650 | ||||
-rw-r--r-- | vpp/vpp-api/custom_dump.c | 80 | ||||
-rw-r--r-- | vpp/vpp-api/test_client.c | 85 | ||||
-rw-r--r-- | vpp/vpp-api/vpe.api | 223 |
18 files changed, 903 insertions, 2219 deletions
diff --git a/vnet/vnet/adj/adj_midchain.c b/vnet/vnet/adj/adj_midchain.c index 2fbedae2220..9f6c8e474d8 100644 --- a/vnet/vnet/adj/adj_midchain.c +++ b/vnet/vnet/adj/adj_midchain.c @@ -116,9 +116,6 @@ adj_mdichain_tx_inline (vlib_main_t * vm, vlib_put_next_frame (vm, node, next_index, n_left_to_next); } - vlib_node_increment_counter (vm, gre_input_node.index, - GRE_ERROR_PKTS_ENCAP, frame->n_vectors); - return frame->n_vectors; } diff --git a/vnet/vnet/fib/fib_entry_src_mpls.c b/vnet/vnet/fib/fib_entry_src_mpls.c index 4f4a023fb3d..4079d8fc8cd 100644 --- a/vnet/vnet/fib/fib_entry_src_mpls.c +++ b/vnet/vnet/fib/fib_entry_src_mpls.c @@ -118,6 +118,19 @@ fib_entry_src_mpls_set_data (fib_entry_src_t *src, else { fib_index = mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID); + + /* + * if this is a change in label, reomve the old one first + */ + if (src->mpls.fesm_label != label) + { + FOR_EACH_MPLS_EOS_BIT(eos) + { + ASSERT(FIB_NODE_INDEX_INVALID != src->mpls.fesm_lfes[eos]); + fib_table_entry_delete_index(src->mpls.fesm_lfes[eos], + FIB_SOURCE_SPECIAL); + } + } } src->mpls.fesm_label = label; diff --git a/vnet/vnet/fib/fib_node.h b/vnet/vnet/fib/fib_node.h index 2f9a107ab8b..253c42dd777 100644 --- a/vnet/vnet/fib/fib_node.h +++ b/vnet/vnet/fib/fib_node.h @@ -37,7 +37,6 @@ typedef enum fib_node_type_t_ { FIB_NODE_TYPE_MPLS_ENTRY, FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY, FIB_NODE_TYPE_LISP_ADJ, - FIB_NODE_TYPE_MPLS_GRE_TUNNEL, FIB_NODE_TYPE_GRE_TUNNEL, /** * Marker. New types before this one. leave the test last. @@ -57,7 +56,6 @@ typedef enum fib_node_type_t_ { [FIB_NODE_TYPE_ADJ] = "adj", \ [FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY] = "lisp-gpe-fwd-entry", \ [FIB_NODE_TYPE_LISP_ADJ] = "lisp-adj", \ - [FIB_NODE_TYPE_MPLS_GRE_TUNNEL] = "mpls-gre-tunnel", \ [FIB_NODE_TYPE_GRE_TUNNEL] = "gre-tunnel", \ } diff --git a/vnet/vnet/fib/fib_table.c b/vnet/vnet/fib/fib_table.c index 84c8708851c..d293d8152af 100644 --- a/vnet/vnet/fib/fib_table.c +++ b/vnet/vnet/fib/fib_table.c @@ -805,10 +805,21 @@ fib_table_entry_local_label_add (u32 fib_index, { fib_node_index_t fib_entry_index; - fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, - FIB_SOURCE_MPLS, - FIB_ENTRY_FLAG_NONE, - NULL); + fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix); + + if (FIB_NODE_INDEX_INVALID == fib_entry_index || + !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS)) + { + /* + * only source the prefix once. this allows the label change + * operation to work + */ + fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, + FIB_SOURCE_MPLS, + FIB_ENTRY_FLAG_NONE, + NULL); + } + fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label); return (fib_entry_index); diff --git a/vnet/vnet/fib/fib_test.c b/vnet/vnet/fib/fib_test.c index 1e459cf1a6c..bdd6e95f8d9 100644 --- a/vnet/vnet/fib/fib_test.c +++ b/vnet/vnet/fib/fib_test.c @@ -5558,11 +5558,58 @@ fib_test_label (void) "label 99 over 10.10.10.1"); /* - * remove the local label + * change the local label + */ + fib_table_entry_local_label_add(fib_index, + &pfx_1_1_1_1_s_32, + 25005); + + fib_prefix_t pfx_25005_eos = { + .fp_proto = FIB_PROTOCOL_MPLS, + .fp_label = 25005, + .fp_eos = MPLS_EOS, + }; + fib_prefix_t pfx_25005_neos = { + .fp_proto = FIB_PROTOCOL_MPLS, + .fp_label = 25005, + .fp_eos = MPLS_NON_EOS, + }; + + FIB_TEST((FIB_NODE_INDEX_INVALID == + fib_table_lookup(fib_index, &pfx_24001_eos)), + "24001/eos removed after label change"); + FIB_TEST((FIB_NODE_INDEX_INVALID == + fib_table_lookup(fib_index, &pfx_24001_neos)), + "24001/eos removed after label change"); + + fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID, + &pfx_25005_eos); + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_MPLS_EOS, + 2, + &l99_eos_o_10_10_10_1, + &adj_o_10_10_11_2), + "25005/eos LB 2 buckets via: " + "label 99 over 10.10.10.1, " + "adj over 10.10.11.2"); + + fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID, + &pfx_25005_neos); + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, + 1, + &l99_neos_o_10_10_10_1), + "25005/neos LB 1 buckets via: " + "label 99 over 10.10.10.1"); + + /* + * remove the local label. + * the check that the MPLS entries are gone is done by the fact the + * MPLS table is no longer present. */ fib_table_entry_local_label_remove(fib_index, &pfx_1_1_1_1_s_32, - 24001); + 25005); fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32); FIB_TEST(fib_test_validate_entry(fei, diff --git a/vnet/vnet/mpls/interface.c b/vnet/vnet/mpls/interface.c index 0baf2d3b127..fc297cd10ae 100644 --- a/vnet/vnet/mpls/interface.c +++ b/vnet/vnet/mpls/interface.c @@ -17,249 +17,12 @@ #include <vnet/vnet.h> #include <vnet/pg/pg.h> -#include <vnet/gre/gre.h> #include <vnet/mpls/mpls.h> #include <vnet/fib/ip4_fib.h> #include <vnet/adj/adj_midchain.h> #include <vnet/dpo/classify_dpo.h> /* manually added to the interface output node */ -#define MPLS_GRE_OUTPUT_NEXT_POST_REWRITE 1 - -static uword -mpls_gre_interface_tx (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - mpls_main_t * gm = &mpls_main; - vnet_main_t * vnm = gm->vnet_main; - u32 next_index; - u32 * from, * to_next, n_left_from, n_left_to_next; - - /* Vector of buffer / pkt indices we're supposed to process */ - from = vlib_frame_vector_args (frame); - - /* Number of buffers / pkts */ - n_left_from = frame->n_vectors; - - /* Speculatively send the first buffer to the last disposition we used */ - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - /* set up to enqueue to our disposition with index = next_index */ - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - /* - * As long as we have enough pkts left to process two pkts - * and prefetch two pkts... - */ - while (n_left_from >= 4 && n_left_to_next >= 2) - { - vlib_buffer_t * b0, * b1; - u32 bi0, next0, bi1, next1; - mpls_gre_tunnel_t * t0, * t1; - u32 sw_if_index0, sw_if_index1; - vnet_hw_interface_t * hi0, * hi1; - u8 * dst0, * dst1; - - /* Prefetch the 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); - - /* - * Prefetch packet data. We expect to overwrite - * the inbound L2 header with an ip header and a - * gre header. Might want to prefetch the last line - * of rewrite space as well; need profile data - */ - CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); - } - - /* Pick up the next two buffer indices */ - bi0 = from[0]; - bi1 = from[1]; - - /* Speculatively enqueue them where we sent the last buffer */ - 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); - - sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX]; - sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX]; - - /* get h/w intfcs */ - hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); - hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1); - - /* hw_instance = tunnel pool index */ - t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance); - t1 = pool_elt_at_index (gm->gre_tunnels, hi1->hw_instance); - - /* Apply rewrite - $$$$$ fixme don't use memcpy */ - vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data)); - vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data)); - - dst0 = vlib_buffer_get_current (b0); - dst1 = vlib_buffer_get_current (b1); - - clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data)); - clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data)); - - /* Fix TX fib indices */ - vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index; - vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->outer_fib_index; - - /* mpls-post-rewrite takes it from here... */ - next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE; - next1 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE; - - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->tunnel_id = t0 - gm->gre_tunnels; - tr->length = b0->current_length; - tr->src.as_u32 = t0->tunnel_src.as_u32; - tr->dst.as_u32 = t0->tunnel_dst.as_u32; - tr->lookup_miss = 0; - tr->mpls_encap_index = t0->encap_index; - } - if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) - { - mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node, - b1, sizeof (*tr)); - tr->tunnel_id = t1 - gm->gre_tunnels; - tr->length = b1->current_length; - tr->src.as_u32 = t1->tunnel_src.as_u32; - tr->dst.as_u32 = t1->tunnel_dst.as_u32; - tr->lookup_miss = 0; - tr->mpls_encap_index = t1->encap_index; - } - - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - vlib_buffer_t * b0; - u32 bi0, next0; - mpls_gre_tunnel_t * t0; - u32 sw_if_index0; - vnet_hw_interface_t * hi0; - u8 * dst0; - - 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); - - sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX]; - - hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); - - t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance); - - /* Apply rewrite - $$$$$ fixme don't use memcpy */ - vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data)); - - dst0 = vlib_buffer_get_current (b0); - - clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data)); - - /* Fix the TX fib index */ - vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index; - - /* mpls-post-rewrite takes it from here... */ - next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE; - - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->tunnel_id = t0 - gm->gre_tunnels; - tr->length = b0->current_length; - tr->src.as_u32 = t0->tunnel_src.as_u32; - tr->dst.as_u32 = t0->tunnel_dst.as_u32; - tr->lookup_miss = 0; - tr->mpls_encap_index = t0->encap_index; - } - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, gre_input_node.index, - GRE_ERROR_PKTS_ENCAP, frame->n_vectors); - - return frame->n_vectors; -} - -static u8 * format_mpls_gre_tunnel_name (u8 * s, va_list * args) -{ - u32 dev_instance = va_arg (*args, u32); - return format (s, "mpls-gre%d", dev_instance); -} - -static u8 * format_mpls_gre_device (u8 * s, va_list * args) -{ - u32 dev_instance = va_arg (*args, u32); - CLIB_UNUSED (int verbose) = va_arg (*args, int); - - s = format (s, "MPLS-GRE tunnel: id %d\n", dev_instance); - return s; -} - -VNET_DEVICE_CLASS (mpls_gre_device_class) = { - .name = "MPLS-GRE tunnel device", - .format_device_name = format_mpls_gre_tunnel_name, - .format_device = format_mpls_gre_device, - .format_tx_trace = format_mpls_gre_tx_trace, - .tx_function = mpls_gre_interface_tx, - .no_flatten_output_chains = 1, -#ifdef SOON - .clear counter = 0; - .admin_up_down_function = 0; -#endif -}; - -VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_gre_device_class, - mpls_gre_interface_tx) - -VNET_HW_INTERFACE_CLASS (mpls_gre_hw_interface_class) = { - .name = "MPLS-GRE", - .format_header = format_mpls_gre_header_with_length, -#if 0 - .unformat_header = unformat_mpls_gre_header, -#endif - .build_rewrite = default_build_rewrite, - .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P, -}; - -/* manually added to the interface output node */ #define MPLS_ETH_OUTPUT_NEXT_OUTPUT 1 static uword @@ -497,63 +260,6 @@ VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = { .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P, }; -static void -mpls_gre_fixup (vlib_main_t *vm, - ip_adjacency_t *adj, - vlib_buffer_t * b0) -{ - ip4_header_t * ip0; - - ip0 = vlib_buffer_get_current (b0); - - /* Fixup the checksum and len fields in the GRE tunnel encap - * that was applied at the midchain node */ - ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); - ip0->checksum = ip4_header_checksum (ip0); -} - -static u8 * mpls_gre_rewrite (mpls_main_t *mm, mpls_gre_tunnel_t * t) -{ - ip4_header_t * ip0; - ip4_gre_and_mpls_header_t * h0; - u8 * rewrite_data = 0; - mpls_encap_t * e; - mpls_unicast_header_t *lp0; - int i; - - /* look up the encap label stack using the RX FIB */ - e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index, t->tunnel_dst.as_u32); - - if (e == 0) - { - clib_warning ("no label for inner fib index %d, dst %U", - t->inner_fib_index, format_ip4_address, - &t->tunnel_dst); - return 0; - } - - vec_validate (rewrite_data, sizeof (*h0) - + sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1); - memset (rewrite_data, 0, sizeof (*h0)); - - h0 = (ip4_gre_and_mpls_header_t *) rewrite_data; - /* Copy the encap label stack */ - lp0 = h0->labels; - for (i = 0; i < vec_len(e->labels); i++) - lp0[i] = e->labels[i]; - ip0 = &h0->ip4; - h0->gre.protocol = clib_host_to_net_u16(GRE_PROTOCOL_mpls_unicast); - ip0->ip_version_and_header_length = 0x45; - ip0->ttl = 254; - ip0->protocol = IP_PROTOCOL_GRE; - /* $$$ fixup ip4 header length and checksum after-the-fact */ - ip0->src_address.as_u32 = t->tunnel_src.as_u32; - ip0->dst_address.as_u32 = t->tunnel_dst.as_u32; - ip0->checksum = ip4_header_checksum (ip0); - - return (rewrite_data); -} - u8 mpls_sw_interface_is_enabled (u32 sw_if_index) { @@ -622,606 +328,6 @@ mpls_sw_interface_enable_disable (mpls_main_t * mm, cm->config_index_by_sw_if_index[sw_if_index] = ci; } -static mpls_gre_tunnel_t * -mpls_gre_tunnel_from_fib_node (fib_node_t *node) -{ -#if (CLIB_DEBUG > 0) - ASSERT(FIB_NODE_TYPE_MPLS_GRE_TUNNEL == node->fn_type); -#endif - return ((mpls_gre_tunnel_t*)node); -} - -/* - * mpls_gre_tunnel_stack - * - * 'stack' (resolve the recursion for) the tunnel's midchain adjacency - */ -static void -mpls_gre_tunnel_stack (mpls_gre_tunnel_t *mgt) -{ - /* - * find the adjacency that is contributed by the FIB entry - * that this tunnel resovles via, and use it as the next adj - * in the midchain - */ - adj_nbr_midchain_stack(mgt->adj_index, - fib_entry_contribute_ip_forwarding(mgt->fei)); -} - -/** - * Function definition to backwalk a FIB node - */ -static fib_node_back_walk_rc_t -mpls_gre_tunnel_back_walk (fib_node_t *node, - fib_node_back_walk_ctx_t *ctx) -{ - mpls_gre_tunnel_stack(mpls_gre_tunnel_from_fib_node(node)); - - return (FIB_NODE_BACK_WALK_CONTINUE); -} - -/** - * Function definition to get a FIB node from its index - */ -static fib_node_t* -mpls_gre_tunnel_fib_node_get (fib_node_index_t index) -{ - mpls_gre_tunnel_t * mgt; - mpls_main_t * mm; - - mm = &mpls_main; - mgt = pool_elt_at_index(mm->gre_tunnels, index); - - return (&mgt->mgt_node); -} - -/** - * Function definition to inform the FIB node that its last lock has gone. - */ -static void -mpls_gre_tunnel_last_lock_gone (fib_node_t *node) -{ - /* - * The MPLS GRE tunnel is a root of the graph. As such - * it never has children and thus is never locked. - */ - ASSERT(0); -} - -/* - * Virtual function table registered by MPLS GRE tunnels - * for participation in the FIB object graph. - */ -const static fib_node_vft_t mpls_gre_vft = { - .fnv_get = mpls_gre_tunnel_fib_node_get, - .fnv_last_lock = mpls_gre_tunnel_last_lock_gone, - .fnv_back_walk = mpls_gre_tunnel_back_walk, -}; - -static mpls_gre_tunnel_t * -mpls_gre_tunnel_find (ip4_address_t *src, - ip4_address_t *dst, - ip4_address_t *intfc, - u32 inner_fib_index) -{ - mpls_main_t * mm = &mpls_main; - mpls_gre_tunnel_t *tp; - int found_tunnel = 0; - - /* suppress duplicate mpls interface generation. */ - pool_foreach (tp, mm->gre_tunnels, - ({ - /* - * If we have a tunnel which matches (src, dst, intfc/mask) - * AND the expected route is in the FIB, it's a dup - */ - if (!memcmp (&tp->tunnel_src, src, sizeof (*src)) - && !memcmp (&tp->tunnel_dst, dst, sizeof (*dst)) - && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc)) - && tp->inner_fib_index == inner_fib_index) - { - found_tunnel = 1; - goto found; - } - })); - -found: - if (found_tunnel) - { - return (tp); - } - return (NULL); -} - -int mpls_gre_tunnel_add (ip4_address_t *src, - ip4_address_t *dst, - ip4_address_t *intfc, - u32 mask_width, - u32 inner_fib_index, - u32 outer_fib_index, - u32 * tunnel_sw_if_index, - u8 l2_only) -{ - mpls_main_t * mm = &mpls_main; - gre_main_t * gm = &gre_main; - vnet_main_t * vnm = vnet_get_main(); - mpls_gre_tunnel_t *tp; - ip_adjacency_t adj; - u8 * rewrite_data; - mpls_encap_t * e = 0; - u32 hw_if_index = ~0; - vnet_hw_interface_t * hi; - u32 slot; - const ip46_address_t zero_nh = { - .ip4.as_u32 = 0, - }; - - tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index); - - /* Add, duplicate */ - if (NULL != tp) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, dst->as_u32); - if (e == 0) - return VNET_API_ERROR_NO_SUCH_LABEL; - - pool_get(mm->gre_tunnels, tp); - memset (tp, 0, sizeof (*tp)); - fib_node_init(&tp->mgt_node, - FIB_NODE_TYPE_MPLS_GRE_TUNNEL); - - if (vec_len (mm->free_gre_sw_if_indices) > 0) - { - hw_if_index = - mm->free_gre_sw_if_indices[vec_len(mm->free_gre_sw_if_indices)-1]; - _vec_len (mm->free_gre_sw_if_indices) -= 1; - hi = vnet_get_hw_interface (vnm, hw_if_index); - hi->dev_instance = tp - mm->gre_tunnels; - hi->hw_instance = tp - mm->gre_tunnels; - } - else - { - hw_if_index = vnet_register_interface - (vnm, mpls_gre_device_class.index, tp - mm->gre_tunnels, - mpls_gre_hw_interface_class.index, - tp - mm->gre_tunnels); - hi = vnet_get_hw_interface (vnm, hw_if_index); - - /* ... to make the IP and L2 x-connect cases identical */ - slot = vlib_node_add_named_next_with_slot - (vnm->vlib_main, hi->tx_node_index, - "mpls-post-rewrite", MPLS_GRE_OUTPUT_NEXT_POST_REWRITE); - - ASSERT (slot == MPLS_GRE_OUTPUT_NEXT_POST_REWRITE); - } - - *tunnel_sw_if_index = hi->sw_if_index; - vnet_sw_interface_set_flags (vnm, hi->sw_if_index, - VNET_SW_INTERFACE_FLAG_ADMIN_UP); - vec_validate(ip4_main.fib_index_by_sw_if_index, *tunnel_sw_if_index); - ip4_main.fib_index_by_sw_if_index[*tunnel_sw_if_index] = outer_fib_index; - - tp->hw_if_index = hw_if_index; - - /* bind the MPLS and IPv4 FIBs to the interface and enable */ - vec_validate(mm->fib_index_by_sw_if_index, hi->sw_if_index); - mm->fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index; - mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 1); - ip4_main.fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index; - ip4_sw_interface_enable_disable(hi->sw_if_index, 1); - - tp->tunnel_src.as_u32 = src->as_u32; - tp->tunnel_dst.as_u32 = dst->as_u32; - tp->intfc_address.as_u32 = intfc->as_u32; - tp->mask_width = mask_width; - tp->inner_fib_index = inner_fib_index; - tp->outer_fib_index = outer_fib_index; - tp->encap_index = e - mm->encaps; - tp->l2_only = l2_only; - - /* Add the tunnel to the hash table of all GRE tunnels */ - u64 key = (u64)src->as_u32 << 32 | (u64)dst->as_u32; - - ASSERT(NULL == hash_get (gm->tunnel_by_key, key)); - hash_set (gm->tunnel_by_key, key, tp - mm->gre_tunnels); - - /* Create the adjacency and add to v4 fib */ - memset(&adj, 0, sizeof (adj)); - adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE; - - rewrite_data = mpls_gre_rewrite (mm, tp); - if (rewrite_data == 0) - { - if (*tunnel_sw_if_index != ~0) - { - hi = vnet_get_hw_interface (vnm, tp->hw_if_index); - vnet_sw_interface_set_flags (vnm, hi->sw_if_index, - 0 /* admin down */); - vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index); - } - pool_put (mm->gre_tunnels, tp); - return VNET_API_ERROR_NO_SUCH_LABEL; - } - - /* Save a copy of the rewrite data for L2 x-connect */ - vec_free (tp->rewrite_data); - - tp->rewrite_data = rewrite_data; - - if (!l2_only) - { - /* - * source the FIB entry for the tunnel's destination - * and become a child thereof. The tunnel will then get poked - * when the forwarding for the entry updates, and the tunnel can - * re-stack accordingly - */ - const fib_prefix_t tun_dst_pfx = { - .fp_len = 32, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4 = *dst, - } - }; - - tp->fei = fib_table_entry_special_add(outer_fib_index, - &tun_dst_pfx, - FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); - tp->sibling_index = fib_entry_child_add(tp->fei, - FIB_NODE_TYPE_MPLS_GRE_TUNNEL, - tp - mm->gre_tunnels); - - /* - * create and update the midchain adj this tunnel sources. - * This is the adj the route we add below will resolve to. - */ - tp->adj_index = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, - FIB_LINK_IP4, - &zero_nh, - hi->sw_if_index); - - adj_nbr_midchain_update_rewrite(tp->adj_index, - mpls_gre_fixup, - ADJ_MIDCHAIN_FLAG_NONE, - rewrite_data); - mpls_gre_tunnel_stack(tp); - - /* - * Update the route for the tunnel's subnet to point through the tunnel - */ - const fib_prefix_t tun_sub_net_pfx = { - .fp_len = tp->mask_width, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4 = tp->intfc_address, - }, - }; - - fib_table_entry_update_one_path(inner_fib_index, - &tun_sub_net_pfx, - FIB_SOURCE_INTERFACE, - (FIB_ENTRY_FLAG_CONNECTED | - FIB_ENTRY_FLAG_ATTACHED), - FIB_PROTOCOL_IP4, - &zero_nh, - hi->sw_if_index, - ~0, // invalid fib index - 1, - MPLS_LABEL_INVALID, - FIB_ROUTE_PATH_FLAG_NONE); - } - - return 0; -} - -static int -mpls_gre_tunnel_del (ip4_address_t *src, - ip4_address_t *dst, - ip4_address_t *intfc, - u32 mask_width, - u32 inner_fib_index, - u32 outer_fib_index, - u32 * tunnel_sw_if_index, - u8 l2_only) -{ - mpls_main_t * mm = &mpls_main; - vnet_main_t * vnm = vnet_get_main(); - gre_main_t * gm = &gre_main; - mpls_gre_tunnel_t *tp; - vnet_hw_interface_t * hi; - - tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index); - - /* Delete, and we can't find the tunnel */ - if (NULL == tp) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - hi = vnet_get_hw_interface (vnm, tp->hw_if_index); - - if (!l2_only) - { - /* - * unsource the FIB entry for the tunnel's destination - */ - const fib_prefix_t tun_dst_pfx = { - .fp_len = 32, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4 = *dst, - } - }; - - fib_entry_child_remove(tp->fei, - tp->sibling_index); - fib_table_entry_special_remove(outer_fib_index, - &tun_dst_pfx, - FIB_SOURCE_RR); - tp->fei = FIB_NODE_INDEX_INVALID; - adj_unlock(tp->adj_index); - - /* - * unsource the route for the tunnel's subnet - */ - const fib_prefix_t tun_sub_net_pfx = { - .fp_len = tp->mask_width, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4 = tp->intfc_address, - }, - }; - - fib_table_entry_delete(inner_fib_index, - &tun_sub_net_pfx, - FIB_SOURCE_INTERFACE); - } - - u64 key = ((u64)tp->tunnel_src.as_u32 << 32 | - (u64)tp->tunnel_src.as_u32); - - hash_unset (gm->tunnel_by_key, key); - mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 0); - ip4_sw_interface_enable_disable(hi->sw_if_index, 0); - - vnet_sw_interface_set_flags (vnm, hi->sw_if_index, - 0 /* admin down */); - vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index); - vec_free (tp->rewrite_data); - fib_node_deinit(&tp->mgt_node); - pool_put (mm->gre_tunnels, tp); - - return 0; -} - -int -vnet_mpls_gre_add_del_tunnel (ip4_address_t *src, - ip4_address_t *dst, - ip4_address_t *intfc, - u32 mask_width, - u32 inner_fib_id, u32 outer_fib_id, - u32 * tunnel_sw_if_index, - u8 l2_only, - u8 is_add) -{ - u32 inner_fib_index = 0; - u32 outer_fib_index = 0; - u32 dummy; - ip4_main_t * im = &ip4_main; - - /* No questions, no answers */ - if (NULL == tunnel_sw_if_index) - tunnel_sw_if_index = &dummy; - - *tunnel_sw_if_index = ~0; - - if (inner_fib_id != (u32)~0) - { - uword * p; - - p = hash_get (im->fib_index_by_table_id, inner_fib_id); - if (! p) - return VNET_API_ERROR_NO_SUCH_INNER_FIB; - inner_fib_index = p[0]; - } - - if (outer_fib_id != 0) - { - uword * p; - - p = hash_get (im->fib_index_by_table_id, outer_fib_id); - if (! p) - return VNET_API_ERROR_NO_SUCH_FIB; - outer_fib_index = p[0]; - } - - if (is_add) - { - return (mpls_gre_tunnel_add(src,dst,intfc, mask_width, - inner_fib_index, - outer_fib_index, - tunnel_sw_if_index, - l2_only)); - } - else - { - return (mpls_gre_tunnel_del(src,dst,intfc, mask_width, - inner_fib_index, - outer_fib_index, - tunnel_sw_if_index, - l2_only)); - } -} - -/* - * Remove all mpls tunnels in the specified fib - */ -int vnet_mpls_gre_delete_fib_tunnels (u32 fib_id) -{ - mpls_main_t * mm = &mpls_main; - vnet_main_t * vnm = mm->vnet_main; - mpls_gre_tunnel_t *tp; - u32 fib_index = 0; - u32 * tunnels_to_delete = 0; - vnet_hw_interface_t * hi; - int i; - - fib_index = ip4_fib_index_from_table_id(fib_id); - if (~0 == fib_index) - return VNET_API_ERROR_NO_SUCH_INNER_FIB; - - pool_foreach (tp, mm->gre_tunnels, - ({ - if (tp->inner_fib_index == fib_index) - vec_add1 (tunnels_to_delete, tp - mm->gre_tunnels); - })); - - for (i = 0; i < vec_len(tunnels_to_delete); i++) { - tp = pool_elt_at_index (mm->gre_tunnels, tunnels_to_delete[i]); - - /* Delete, the route if not already gone */ - if (FIB_NODE_INDEX_INVALID != tp->fei && !tp->l2_only) - { - const fib_prefix_t tun_dst_pfx = { - .fp_len = 32, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4 = tp->tunnel_dst, - } - }; - - fib_entry_child_remove(tp->fei, - tp->sibling_index); - fib_table_entry_special_remove(tp->outer_fib_index, - &tun_dst_pfx, - FIB_SOURCE_RR); - tp->fei = FIB_NODE_INDEX_INVALID; - adj_unlock(tp->adj_index); - - const fib_prefix_t tun_sub_net_pfx = { - .fp_len = tp->mask_width, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4 = tp->intfc_address, - }, - }; - - fib_table_entry_delete(tp->inner_fib_index, - &tun_sub_net_pfx, - FIB_SOURCE_INTERFACE); - } - - hi = vnet_get_hw_interface (vnm, tp->hw_if_index); - vnet_sw_interface_set_flags (vnm, hi->sw_if_index, - 0 /* admin down */); - vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index); - vec_free (tp->rewrite_data); - pool_put (mm->gre_tunnels, tp); - } - - vec_free(tunnels_to_delete); - - return (0); -} - -static clib_error_t * -create_mpls_gre_tunnel_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, * line_input = &_line_input; - ip4_address_t src, dst, intfc; - int src_set = 0, dst_set = 0, intfc_set = 0; - u32 mask_width; - u32 inner_fib_id = (u32)~0; - u32 outer_fib_id = 0; - int rv; - u8 is_del = 0; - u8 l2_only = 0; - u32 tunnel_intfc_sw_if_index = ~0; - - /* Get a line of input. */ - if (! unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "src %U", - unformat_ip4_address, &src)) - src_set = 1; - else if (unformat (line_input, "dst %U", - unformat_ip4_address, &dst)) - dst_set = 1; - else if (unformat (line_input, "intfc %U/%d", - unformat_ip4_address, &intfc, &mask_width)) - intfc_set = 1; - else if (unformat (line_input, "inner-fib-id %d", &inner_fib_id)) - ; - else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id)) - ; - else if (unformat (line_input, "del")) - is_del = 1; - else if (unformat (line_input, "l2-only")) - l2_only = 1; - else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - } - - if (!src_set) - return clib_error_return (0, "missing: src <ip-address>"); - - if (!dst_set) - return clib_error_return (0, "missing: dst <ip-address>"); - - if (!intfc_set) - return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>"); - - - rv = vnet_mpls_gre_add_del_tunnel (&src, &dst, &intfc, mask_width, - inner_fib_id, outer_fib_id, - &tunnel_intfc_sw_if_index, - l2_only, !is_del); - - switch (rv) - { - case 0: - if (!is_del) - vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), tunnel_intfc_sw_if_index); - break; - - case VNET_API_ERROR_NO_SUCH_INNER_FIB: - return clib_error_return (0, "inner fib ID %d doesn't exist\n", - inner_fib_id); - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "outer fib ID %d doesn't exist\n", - outer_fib_id); - - case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "tunnel not found\n"); - - case VNET_API_ERROR_NO_SUCH_LABEL: - /* - * This happens when there's no MPLS label for the dst address - * no need for two error messages. - */ - break; - - default: - return clib_error_return (0, "vnet_mpls_gre_add_del_tunnel returned %d", - rv); - } - return 0; -} - -VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = { - .path = "create mpls gre tunnel", - .short_help = - "create mpls gre tunnel [del] src <addr> dst <addr> intfc <addr>/<mw>", - .function = create_mpls_gre_tunnel_command_fn, -}; - u8 * format_mpls_encap_index (u8 * s, va_list * args) { mpls_main_t * mm = va_arg (*args, mpls_main_t *); @@ -1239,40 +345,6 @@ u8 * format_mpls_encap_index (u8 * s, va_list * args) return s; } -u8 * format_mpls_gre_tunnel (u8 * s, va_list * args) -{ - mpls_gre_tunnel_t * t = va_arg (*args, mpls_gre_tunnel_t *); - mpls_main_t * mm = &mpls_main; - - if (t->l2_only == 0) - { - s = format (s, "[%d]: src %U, dst %U, adj %U/%d, labels %U\n", - t - mm->gre_tunnels, - format_ip4_address, &t->tunnel_src, - format_ip4_address, &t->tunnel_dst, - format_ip4_address, &t->intfc_address, - t->mask_width, - format_mpls_encap_index, mm, t->encap_index); - - s = format (s, " inner fib index %d, outer fib index %d", - t->inner_fib_index, t->outer_fib_index); - } - else - { - s = format (s, "[%d]: src %U, dst %U, key %U, labels %U\n", - t - mm->gre_tunnels, - format_ip4_address, &t->tunnel_src, - format_ip4_address, &t->tunnel_dst, - format_ip4_address, &t->intfc_address, - format_mpls_encap_index, mm, t->encap_index); - - s = format (s, " l2 interface %d, outer fib index %d", - t->hw_if_index, t->outer_fib_index); - } - - return s; -} - u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args) { mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *); @@ -1299,20 +371,8 @@ show_mpls_tunnel_command_fn (vlib_main_t * vm, vlib_cli_command_t * cmd) { mpls_main_t * mm = &mpls_main; - mpls_gre_tunnel_t * gt; mpls_eth_tunnel_t * et; - if (pool_elts (mm->gre_tunnels)) - { - vlib_cli_output (vm, "MPLS-GRE tunnels"); - pool_foreach (gt, mm->gre_tunnels, - ({ - vlib_cli_output (vm, "%U", format_mpls_gre_tunnel, gt); - })); - } - else - vlib_cli_output (vm, "No MPLS-GRE tunnels"); - if (pool_elts (mm->eth_tunnels)) { vlib_cli_output (vm, "MPLS-Ethernet tunnels"); @@ -1339,9 +399,6 @@ clib_error_t *mpls_interface_init (vlib_main_t *vm) { clib_error_t * error; - fib_node_register_type(FIB_NODE_TYPE_MPLS_GRE_TUNNEL, - &mpls_gre_vft); - if ((error = vlib_call_init_function (vm, mpls_policy_encap_init))) return error; diff --git a/vnet/vnet/mpls/mpls.c b/vnet/vnet/mpls/mpls.c index b28736ba5a7..ac35e5d4144 100644 --- a/vnet/vnet/mpls/mpls.c +++ b/vnet/vnet/mpls/mpls.c @@ -96,25 +96,29 @@ u8 * format_mpls_header (u8 * s, va_list * args) vnet_mpls_uc_get_s(hdr.label_exp_s_ttl))); } -u8 * format_mpls_gre_tx_trace (u8 * s, va_list * args) +uword +unformat_mpls_header (unformat_input_t * input, va_list * args) { - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - mpls_gre_tx_trace_t * t = va_arg (*args, mpls_gre_tx_trace_t *); - mpls_main_t * mm = &mpls_main; - - if (t->lookup_miss) - s = format (s, "MPLS: lookup miss"); - else - { - s = format (s, "MPLS: tunnel %d labels %U len %d src %U dst %U", - t->tunnel_id, - format_mpls_encap_index, mm, t->mpls_encap_index, - clib_net_to_host_u16 (t->length), - format_ip4_address, &t->src.as_u8, - format_ip4_address, &t->dst.as_u8); - } - return s; + u8 ** result = va_arg (*args, u8 **); + mpls_unicast_header_t _h, * h = &_h; + u32 label, label_exp_s_ttl; + + if (! unformat (input, "MPLS %d", &label)) + return 0; + + label_exp_s_ttl = (label<<12) | (1<<8) /* s-bit */ | 0xFF; + h->label_exp_s_ttl = clib_host_to_net_u32 (label_exp_s_ttl); + + /* Add gre, mpls headers to result. */ + { + void * p; + u32 h_n_bytes = sizeof (h[0]); + + vec_add2 (*result, p, h_n_bytes); + clib_memcpy (p, h, h_n_bytes); + } + + return 1; } u8 * format_mpls_eth_tx_trace (u8 * s, va_list * args) @@ -156,62 +160,6 @@ u8 * format_mpls_eth_header_with_length (u8 * s, va_list * args) return s; } -u8 * format_mpls_gre_header_with_length (u8 * s, va_list * args) -{ - gre_header_t * h = va_arg (*args, gre_header_t *); - mpls_unicast_header_t * m = (mpls_unicast_header_t *)(h+1); - u32 max_header_bytes = va_arg (*args, u32); - uword header_bytes; - - header_bytes = sizeof (h[0]); - if (max_header_bytes != 0 && header_bytes > max_header_bytes) - return format (s, "gre header truncated"); - - s = format - (s, "GRE-MPLS label %d", - vnet_mpls_uc_get_label (clib_net_to_host_u32 (m->label_exp_s_ttl))); - - return s; -} - -u8 * format_mpls_gre_header (u8 * s, va_list * args) -{ - gre_header_t * h = va_arg (*args, gre_header_t *); - return format (s, "%U", format_mpls_gre_header_with_length, h, 0); -} - -uword -unformat_mpls_gre_header (unformat_input_t * input, va_list * args) -{ - u8 ** result = va_arg (*args, u8 **); - gre_header_t _g, * g = &_g; - mpls_unicast_header_t _h, * h = &_h; - u32 label, label_exp_s_ttl; - - if (! unformat (input, "MPLS %d", &label)) - return 0; - - g->protocol = clib_host_to_net_u16 (GRE_PROTOCOL_mpls_unicast); - - label_exp_s_ttl = (label<<12) | (1<<8) /* s-bit */ | 0xFF; - h->label_exp_s_ttl = clib_host_to_net_u32 (label_exp_s_ttl); - - /* Add gre, mpls headers to result. */ - { - void * p; - u32 g_n_bytes = sizeof (g[0]); - u32 h_n_bytes = sizeof (h[0]); - - vec_add2 (*result, p, g_n_bytes); - clib_memcpy (p, g, g_n_bytes); - - vec_add2 (*result, p, h_n_bytes); - clib_memcpy (p, h, h_n_bytes); - } - - return 1; -} - uword unformat_mpls_label_net_byte_order (unformat_input_t * input, va_list * args) @@ -443,217 +391,6 @@ VLIB_CLI_COMMAND (mpls_del_encap_command, static) = { .function = mpls_del_encap_command_fn, }; -int vnet_mpls_add_del_decap (u32 rx_fib_id, - u32 tx_fib_id, - u32 label_host_byte_order, - int s_bit, int next_index, int is_add) -{ - mpls_main_t * mm = &mpls_main; - ip4_main_t * im = &ip4_main; - mpls_decap_t * d; - u32 rx_fib_index, tx_fib_index_or_output_swif_index; - uword *p; - u64 key; - - p = hash_get (im->fib_index_by_table_id, rx_fib_id); - if (! p) - return VNET_API_ERROR_NO_SUCH_FIB; - - rx_fib_index = p[0]; - - /* L3 decap => transform fib ID to fib index */ - if (next_index == MPLS_LOOKUP_NEXT_IP4_INPUT) - { - p = hash_get (im->fib_index_by_table_id, tx_fib_id); - if (! p) - return VNET_API_ERROR_NO_SUCH_INNER_FIB; - - tx_fib_index_or_output_swif_index = p[0]; - } - else - { - /* L2 decap, tx_fib_id is actually the output sw_if_index */ - tx_fib_index_or_output_swif_index = tx_fib_id; - } - - key = ((u64) rx_fib_index<<32) | ((u64) label_host_byte_order<<12) - | ((u64) s_bit<<8); - - p = hash_get (mm->mpls_decap_by_rx_fib_and_label, key); - - /* If deleting, or replacing an old entry */ - if (is_add == 0 || p) - { - if (is_add == 0 && p == 0) - return VNET_API_ERROR_NO_SUCH_LABEL; - - d = pool_elt_at_index (mm->decaps, p[0]); - hash_unset (mm->mpls_decap_by_rx_fib_and_label, key); - pool_put (mm->decaps, d); - /* Deleting, we're done... */ - if (is_add == 0) - return 0; - } - - /* add decap entry... */ - pool_get (mm->decaps, d); - memset (d, 0, sizeof (*d)); - d->tx_fib_index = tx_fib_index_or_output_swif_index; - d->next_index = next_index; - - hash_set (mm->mpls_decap_by_rx_fib_and_label, key, d - mm->decaps); - - return 0; -} - -uword -unformat_mpls_gre_input_next (unformat_input_t * input, va_list * args) -{ - u32 * result = va_arg (*args, u32 *); - int rv = 0; - - if (unformat (input, "lookup")) - { - *result = MPLS_LOOKUP_NEXT_IP4_INPUT; - rv = 1; - } - else if (unformat (input, "output")) - { - *result = MPLS_LOOKUP_NEXT_L2_OUTPUT; - rv = 1; - } - return rv; -} - -static clib_error_t * -mpls_add_decap_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t * vnm = vnet_get_main(); - u32 rx_fib_id = 0; - u32 tx_fib_or_sw_if_index; - u32 label; - int s_bit = 1; - u32 next_index = 1; /* ip4_lookup, see node.c */ - int tx_fib_id_set = 0; - int label_set = 0; - int rv; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "fib %d", &tx_fib_or_sw_if_index)) - tx_fib_id_set = 1; - else if (unformat (input, "sw_if_index %d", &tx_fib_or_sw_if_index)) - tx_fib_id_set = 1; - else if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, - &tx_fib_or_sw_if_index)) - tx_fib_id_set = 1; - else if (unformat (input, "rx-fib %d", &rx_fib_id)) - ; - else if (unformat (input, "label %d", &label)) - label_set = 1; - else if (unformat (input, "s-bit-clear")) - s_bit = 0; - else if (unformat (input, "next %U", unformat_mpls_gre_input_next, - &next_index)) - ; - else - break; - } - - if (tx_fib_id_set == 0) - return clib_error_return (0, "lookup FIB ID not set"); - if (label_set == 0) - return clib_error_return (0, "missing label"); - - rv = vnet_mpls_add_del_decap (rx_fib_id, tx_fib_or_sw_if_index, - label, s_bit, next_index, 1 /* is_add */); - switch (rv) - { - case 0: - break; - - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "no such rx fib id %d", rx_fib_id); - - case VNET_API_ERROR_NO_SUCH_INNER_FIB: - return clib_error_return (0, "no such tx fib / swif %d", - tx_fib_or_sw_if_index); - - default: - return clib_error_return (0, "vnet_mpls_add_del_decap returned %d", - rv); - } - return 0; -} - -VLIB_CLI_COMMAND (mpls_add_decap_command, static) = { - .path = "mpls decap add", - .short_help = - "mpls decap add fib <id> label <nn> [s-bit-clear] [next-index <nn>]", - .function = mpls_add_decap_command_fn, -}; - -static clib_error_t * -mpls_del_decap_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - u32 rx_fib_id = 0; - u32 tx_fib_id = 0; - u32 label; - int s_bit = 1; - int label_set = 0; - int rv; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "rx-fib %d", &rx_fib_id)) - ; - else if (unformat (input, "label %d", &label)) - label_set = 1; - else if (unformat (input, "s-bit-clear")) - s_bit = 0; - } - - if (!label_set) - return clib_error_return (0, "label not set"); - - rv = vnet_mpls_add_del_decap (rx_fib_id, - tx_fib_id /* not interesting */, - label, s_bit, - 0 /* next_index not interesting */, - 0 /* is_add */); - switch (rv) - { - case 0: - break; - - case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "no such rx fib id %d", rx_fib_id); - - case VNET_API_ERROR_NO_SUCH_INNER_FIB: - return clib_error_return (0, "no such lookup fib id %d", tx_fib_id); - - case VNET_API_ERROR_NO_SUCH_LABEL: - return clib_error_return (0, "no such label %d rx fib id %d", - label, rx_fib_id); - - default: - return clib_error_return (0, "vnet_mpls_add_del_decap returned %d", - rv); - } - return 0; -} - - -VLIB_CLI_COMMAND (mpls_del_decap_command, static) = { - .path = "mpls decap delete", - .short_help = "mpls decap delete label <label> rx-fib <id> [s-bit-clear]", - .function = mpls_del_decap_command_fn, -}; - int mpls_dest_cmp(void * a1, void * a2) { @@ -943,28 +680,6 @@ int mpls_fib_reset_labels (u32 fib_id) pool_put_index (mm->encaps, s->entry_index); } - vec_reset_length(records); - - hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label, - ({ - if (fib_index == (u32) (key>>32)) { - vec_add2 (records, s, 1); - s->entry_index = value; - s->fib_index = fib_index; - s->s_bit = key & (1<<8); - s->dest = (u32)((key & 0xFFFFFFFF)>>12); - } - })); - - vec_foreach (s, records) - { - key = ((u64) fib_index <<32) | ((u64) s->dest<<12) | - ((u64) s->s_bit); - - hash_unset (mm->mpls_decap_by_rx_fib_and_label, key); - pool_put_index (mm->decaps, s->entry_index); - } - vec_free(records); return 0; } @@ -981,7 +696,6 @@ static clib_error_t * mpls_init (vlib_main_t * vm) return error; mm->mpls_encap_by_fib_and_dest = hash_create (0, sizeof (uword)); - mm->mpls_decap_by_rx_fib_and_label = hash_create (0, sizeof (uword)); return vlib_call_init_function (vm, mpls_input_init); } diff --git a/vnet/vnet/mpls/mpls.h b/vnet/vnet/mpls/mpls.h index 35755333e1d..da663b0b788 100644 --- a/vnet/vnet/mpls/mpls.h +++ b/vnet/vnet/mpls/mpls.h @@ -12,11 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef included_vnet_mpls_gre_h -#define included_vnet_mpls_gre_h +#ifndef included_vnet_mpls_h +#define included_vnet_mpls_h #include <vnet/vnet.h> -#include <vnet/gre/gre.h> #include <vnet/mpls/packet.h> #include <vnet/mpls/mpls_types.h> #include <vnet/ip/ip4_packet.h> @@ -24,43 +23,17 @@ #include <vnet/fib/fib_node.h> #include <vnet/adj/adj.h> -typedef CLIB_PACKED (struct { - ip4_header_t ip4; /* 20 bytes */ - gre_header_t gre; /* 4 bytes */ - mpls_unicast_header_t labels[0]; /* 4 bytes each */ -}) ip4_gre_and_mpls_header_t; - -extern vnet_hw_interface_class_t mpls_gre_hw_interface_class; - typedef enum { #define mpls_error(n,s) MPLS_ERROR_##n, #include <vnet/mpls/error.def> #undef mpls_error MPLS_N_ERROR, -} mpls_gre_error_t; +} mpls_error_t; /* * No protocol info, MPLS labels don't have a next-header field * presumably the label field tells all... */ - -typedef struct { - fib_node_t mgt_node; - ip4_address_t tunnel_src; - ip4_address_t tunnel_dst; - ip4_address_t intfc_address; - u32 mask_width; - u32 inner_fib_index; - u32 outer_fib_index; - u32 encap_index; - u32 hw_if_index; /* L2 x-connect capable tunnel intfc */ - u8 * rewrite_data; - u8 l2_only; - fib_node_index_t fei; /* FIB Entry index for the tunnel's destination */ - adj_index_t adj_index; /* The midchain adj this tunnel creates */ - u32 sibling_index; -} mpls_gre_tunnel_t; - typedef struct { u8 tunnel_dst[6]; ip4_address_t intfc_address; @@ -81,11 +54,6 @@ typedef struct { u32 output_next_index; } mpls_encap_t; -typedef struct { - u32 tx_fib_index; - u32 next_index; /* e.g. ip4/6-input, l2-input */ -} mpls_decap_t; - #define MPLS_FIB_DEFAULT_TABLE_ID 0 /** @@ -134,10 +102,6 @@ typedef struct { u32 mpls_rx_feature_not_enabled; u32 mpls_tx_feature_interface_output; - /* pool of gre tunnel instances */ - mpls_gre_tunnel_t *gre_tunnels; - u32 * free_gre_sw_if_indices; - /* pool of ethernet tunnel instances */ mpls_eth_tunnel_t *eth_tunnels; u32 * free_eth_sw_if_indices; @@ -146,10 +110,6 @@ typedef struct { mpls_encap_t * encaps; uword * mpls_encap_by_fib_and_dest; - /* Decap side: map rx label to FIB */ - mpls_decap_t * decaps; - uword * mpls_decap_by_rx_fib_and_label; - /* mpls-o-e policy tunnel next index for ip4/ip6-classify */ u32 ip4_classify_mpls_policy_encap_next_index; u32 ip6_classify_mpls_policy_encap_next_index; @@ -197,7 +157,6 @@ __VA_ARGS__ vnet_feature_registration_t tx_##x extern clib_error_t * mpls_feature_init(vlib_main_t * vm); format_function_t format_mpls_protocol; -format_function_t format_mpls_gre_header_with_length; format_function_t format_mpls_eth_header_with_length; format_function_t format_mpls_encap_index; @@ -211,25 +170,17 @@ extern vlib_node_registration_t mpls_policy_encap_node; extern vlib_node_registration_t mpls_output_node; extern vlib_node_registration_t mpls_midchain_node; -extern vnet_device_class_t mpls_gre_device_class; - /* Parse mpls protocol as 0xXXXX or protocol name. In either host or network byte order. */ unformat_function_t unformat_mpls_protocol_host_byte_order; unformat_function_t unformat_mpls_protocol_net_byte_order; unformat_function_t unformat_mpls_label_net_byte_order; -unformat_function_t unformat_mpls_gre_header; -unformat_function_t unformat_pg_mpls_gre_header; unformat_function_t unformat_mpls_unicast_label; /* Parse mpls header. */ unformat_function_t unformat_mpls_header; unformat_function_t unformat_pg_mpls_header; -/* manually added to the interface output node in mpls.c */ -#define MPLS_GRE_OUTPUT_NEXT_LOOKUP 1 -#define MPLS_GRE_OUTPUT_NEXT_DROP VNET_INTERFACE_TX_NEXT_DROP - void mpls_sw_interface_enable_disable (mpls_main_t * mm, u32 sw_if_index, u8 is_enable); @@ -239,18 +190,6 @@ u8 mpls_sw_interface_is_enabled (u32 sw_if_index); mpls_encap_t * mpls_encap_by_fib_and_dest (mpls_main_t * mm, u32 rx_fib, u32 dst_address); -int mpls_label_from_fib_id_and_dest (mpls_main_t *gm, u32 fib_id, - u32 dst_address, u32 *labelp); - -int vnet_mpls_gre_add_del_tunnel (ip4_address_t *src, - ip4_address_t *dst, - ip4_address_t *intfc, - u32 mask_width, - u32 inner_fib_id, u32 outer_fib_id, - u32 * tunnel_intfc_sw_if_index, - u8 l2_only, - u8 is_add); - int vnet_mpls_ethernet_add_del_tunnel (u8 *dst, ip4_address_t *intfc, u32 mask_width, @@ -260,15 +199,8 @@ int vnet_mpls_ethernet_add_del_tunnel (u8 *dst, u8 l2_only, u8 is_add); -int vnet_mpls_gre_delete_fib_tunnels (u32 fib_id); - int mpls_fib_reset_labels (u32 fib_id); -int vnet_mpls_add_del_decap (u32 rx_fib_id, - u32 tx_fib_id, - u32 label_host_byte_order, - int s_bit, int next_index, int is_add); - int vnet_mpls_add_del_encap (ip4_address_t *dest, u32 fib_id, u32 *labels_host_byte_order, u32 policy_tunnel_index, @@ -278,26 +210,6 @@ int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm, mpls_encap_t * e, u32 policy_tunnel_index); -typedef struct { - u32 lookup_miss; - - /* Tunnel-id / index in tunnel vector */ - u32 tunnel_id; - - /* mpls encap index */ - u32 mpls_encap_index; - - /* pkt length */ - u32 length; - - /* tunnel ip4 addresses */ - ip4_address_t src; - ip4_address_t dst; -} mpls_gre_tx_trace_t; - -u8 * format_mpls_gre_tx_trace (u8 * s, va_list * args); -u8 * format_mpls_gre_header (u8 * s, va_list * args); - #define foreach_mpls_input_next \ _(DROP, "error-drop") \ _(LOOKUP, "mpls-lookup") @@ -369,4 +281,4 @@ mpls_fib_index_cmp(void * a1, void * a2); int mpls_label_cmp(void * a1, void * a2); -#endif /* included_vnet_mpls_gre_h */ +#endif /* included_vnet_mpls_h */ diff --git a/vnet/vnet/mpls/mpls_lookup.c b/vnet/vnet/mpls/mpls_lookup.c index 31ad68c4bc6..9d29cecff90 100644 --- a/vnet/vnet/mpls/mpls_lookup.c +++ b/vnet/vnet/mpls/mpls_lookup.c @@ -1,5 +1,5 @@ /* - * node.c: mpls-o-gre decap processing + * mpls_lookup.c: MPLS lookup * * Copyright (c) 2012-2014 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); @@ -167,9 +167,9 @@ VLIB_REGISTER_NODE (mpls_lookup_node) = { .sibling_of = "ip4-lookup", - .format_buffer = format_mpls_gre_header_with_length, + .format_buffer = format_mpls_header, .format_trace = format_mpls_lookup_trace, - .unformat_buffer = unformat_mpls_gre_header, + .unformat_buffer = unformat_mpls_header, }; VLIB_NODE_FUNCTION_MULTIARCH (mpls_lookup_node, mpls_lookup) diff --git a/vnet/vnet/mpls/mpls_output.c b/vnet/vnet/mpls/mpls_output.c index 1d5d18224e3..739e85db275 100644 --- a/vnet/vnet/mpls/mpls_output.c +++ b/vnet/vnet/mpls/mpls_output.c @@ -17,6 +17,7 @@ #include <vlib/vlib.h> #include <vnet/pg/pg.h> +#include <vnet/ip/ip.h> #include <vnet/mpls/mpls.h> typedef struct { diff --git a/vnet/vnet/mpls/node.c b/vnet/vnet/mpls/node.c index 1b435f31f0b..5b8f2569e77 100644 --- a/vnet/vnet/mpls/node.c +++ b/vnet/vnet/mpls/node.c @@ -1,5 +1,5 @@ /* - * node.c: mpls-o-gre decap processing + * node.c: MPLS input * * Copyright (c) 2012-2014 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/vnet/vnet/mpls/pg.c b/vnet/vnet/mpls/pg.c index f04b53075d3..6ff86e32f67 100644 --- a/vnet/vnet/mpls/pg.c +++ b/vnet/vnet/mpls/pg.c @@ -1,5 +1,5 @@ /* - * pg.c: packet generator mpls/gre interface + * pg.c: packet generator mpls interface * * Copyright (c) 2012 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/vnet/vnet/mpls/policy_encap.c b/vnet/vnet/mpls/policy_encap.c index 278e8e6d7ce..d48a153b37d 100644 --- a/vnet/vnet/mpls/policy_encap.c +++ b/vnet/vnet/mpls/policy_encap.c @@ -18,6 +18,7 @@ #include <vlib/vlib.h> #include <vnet/pg/pg.h> #include <vnet/mpls/mpls.h> +#include <vnet/classify/vnet_classify.h> typedef struct { u32 next_index; diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c index 71c6f24136a..0e55732341d 100644 --- a/vpp-api-test/vat/api_format.c +++ b/vpp-api-test/vat/api_format.c @@ -1093,40 +1093,6 @@ static void vl_api_add_node_next_reply_t_handler_json vam->result_ready = 1; } -static void vl_api_mpls_gre_add_del_tunnel_reply_t_handler - (vl_api_mpls_gre_add_del_tunnel_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - u32 sw_if_index = ntohl (mp->tunnel_sw_if_index); - - if (retval >= 0 && sw_if_index != (u32) ~ 0) - { - errmsg ("tunnel_sw_if_index %d\n", sw_if_index); - } - vam->retval = retval; - vam->result_ready = 1; -} - -static void vl_api_mpls_gre_add_del_tunnel_reply_t_handler_json - (vl_api_mpls_gre_add_del_tunnel_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t node; - - vat_json_init_object (&node); - vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); - vat_json_object_add_uint (&node, "tunnel_sw_if_index", - ntohl (mp->tunnel_sw_if_index)); - - vat_json_print (vam->ofp, &node); - vat_json_free (&node); - - vam->retval = ntohl (mp->retval); - vam->result_ready = 1; -} - - static void vl_api_show_version_reply_t_handler (vl_api_show_version_reply_t * mp) { @@ -3518,10 +3484,11 @@ _(bridge_domain_add_del_reply) \ _(sw_interface_set_l2_xconnect_reply) \ _(l2fib_add_del_reply) \ _(ip_add_del_route_reply) \ +_(mpls_route_add_del_reply) \ +_(mpls_ip_bind_unbind_reply) \ _(proxy_arp_add_del_reply) \ _(proxy_arp_intfc_enable_disable_reply) \ _(mpls_add_del_encap_reply) \ -_(mpls_add_del_decap_reply) \ _(mpls_ethernet_add_del_tunnel_2_reply) \ _(sw_interface_set_unnumbered_reply) \ _(ip_neighbor_add_del_reply) \ @@ -3676,12 +3643,12 @@ _(TAP_MODIFY_REPLY, tap_modify_reply) \ _(TAP_DELETE_REPLY, tap_delete_reply) \ _(SW_INTERFACE_TAP_DETAILS, sw_interface_tap_details) \ _(IP_ADD_DEL_ROUTE_REPLY, ip_add_del_route_reply) \ +_(MPLS_ROUTE_ADD_DEL_REPLY, mpls_route_add_del_reply) \ +_(MPLS_IP_BIND_UNBIND_REPLY, mpls_ip_bind_unbind_reply) \ _(PROXY_ARP_ADD_DEL_REPLY, proxy_arp_add_del_reply) \ _(PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY, \ proxy_arp_intfc_enable_disable_reply) \ _(MPLS_ADD_DEL_ENCAP_REPLY, mpls_add_del_encap_reply) \ -_(MPLS_ADD_DEL_DECAP_REPLY, mpls_add_del_decap_reply) \ -_(MPLS_GRE_ADD_DEL_TUNNEL_REPLY, mpls_gre_add_del_tunnel_reply) \ _(MPLS_ETHERNET_ADD_DEL_TUNNEL_REPLY, \ mpls_ethernet_add_del_tunnel_reply) \ _(MPLS_ETHERNET_ADD_DEL_TUNNEL_2_REPLY, \ @@ -3815,10 +3782,9 @@ _(POLICER_CLASSIFY_SET_INTERFACE_REPLY, policer_classify_set_interface_reply) \ _(POLICER_CLASSIFY_DETAILS, policer_classify_details) \ _(NETMAP_CREATE_REPLY, netmap_create_reply) \ _(NETMAP_DELETE_REPLY, netmap_delete_reply) \ -_(MPLS_GRE_TUNNEL_DETAILS, mpls_gre_tunnel_details) \ _(MPLS_ETH_TUNNEL_DETAILS, mpls_eth_tunnel_details) \ _(MPLS_FIB_ENCAP_DETAILS, mpls_fib_encap_details) \ -_(MPLS_FIB_DECAP_DETAILS, mpls_fib_decap_details) \ +_(MPLS_FIB_DETAILS, mpls_fib_details) \ _(CLASSIFY_TABLE_IDS_REPLY, classify_table_ids_reply) \ _(CLASSIFY_TABLE_BY_INTERFACE_REPLY, classify_table_by_interface_reply) \ _(CLASSIFY_TABLE_INFO_REPLY, classify_table_info_reply) \ @@ -5752,7 +5718,7 @@ api_ip_add_del_route (vat_main_t * vam) u8 is_multipath = 0; u8 address_set = 0; u8 address_length_set = 0; - u32 lookup_in_vrf = 0; + u32 next_hop_table_id = 0; u32 resolve_attempts = 0; u32 dst_address_length = 0; u8 next_hop_set = 0; @@ -5768,6 +5734,7 @@ api_ip_add_del_route (vat_main_t * vam) u32 classify_table_index = ~0; u8 is_classify = 0; u8 resolve_host = 0, resolve_attached = 0; + mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID; /* Parse args required to build the message */ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) @@ -5835,7 +5802,11 @@ api_ip_add_del_route (vat_main_t * vam) create_vrf_if_needed = 1; else if (unformat (i, "count %d", &count)) ; - else if (unformat (i, "lookup-in-vrf %d", &lookup_in_vrf)) + else if (unformat (i, "lookup-in-vrf %d", &next_hop_table_id)) + ; + else if (unformat (i, "next-hop-table %d", &next_hop_table_id)) + ; + else if (unformat (i, "out-label %d", &next_hop_out_label)) ; else if (unformat (i, "random")) random_add_del = 1; @@ -5909,7 +5880,7 @@ api_ip_add_del_route (vat_main_t * vam) M (IP_ADD_DEL_ROUTE, ip_add_del_route); mp->next_hop_sw_if_index = ntohl (sw_if_index); - mp->vrf_id = ntohl (vrf_id); + mp->table_id = ntohl (vrf_id); if (resolve_attempts > 0) { mp->resolve_attempts = ntohl (resolve_attempts); @@ -5928,8 +5899,9 @@ api_ip_add_del_route (vat_main_t * vam) mp->not_last = not_last; mp->next_hop_weight = next_hop_weight; mp->dst_address_length = dst_address_length; - mp->lookup_in_vrf = ntohl (lookup_in_vrf); + mp->next_hop_table_id = ntohl (next_hop_table_id); mp->classify_table_index = ntohl (classify_table_index); + mp->next_hop_out_label = ntohl (next_hop_out_label); if (is_ipv6) { @@ -6007,6 +5979,299 @@ api_ip_add_del_route (vat_main_t * vam) } static int +api_mpls_route_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_mpls_route_add_del_t *mp; + f64 timeout; + u32 sw_if_index = ~0, table_id = 0; + u8 create_table_if_needed = 0; + u8 is_add = 1; + u8 next_hop_weight = 1; + u8 is_multipath = 0; + u32 next_hop_table_id = 0; + u8 next_hop_set = 0; + ip4_address_t v4_next_hop_address = { + .as_u32 = 0, + }; + ip6_address_t v6_next_hop_address = { {0} }; + int count = 1; + int j; + f64 before = 0; + u32 classify_table_index = ~0; + u8 is_classify = 0; + u8 resolve_host = 0, resolve_attached = 0; + mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID; + mpls_label_t local_label = MPLS_LABEL_INVALID; + u8 is_eos = 1; + u8 next_hop_proto_is_ip4 = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "%d", &local_label)) + ; + else if (unformat (i, "eos")) + is_eos = 1; + else if (unformat (i, "non-eos")) + is_eos = 0; + else if (unformat (i, "via %U", unformat_ip4_address, + &v4_next_hop_address)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 1; + } + else if (unformat (i, "via %U", unformat_ip6_address, + &v6_next_hop_address)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 0; + } + else if (unformat (i, "weight %d", &next_hop_weight)) + ; + else if (unformat (i, "create-table")) + create_table_if_needed = 1; + else if (unformat (i, "classify %d", &classify_table_index)) + { + is_classify = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "resolve-via-host")) + resolve_host = 1; + else if (unformat (i, "resolve-via-attached")) + resolve_attached = 1; + else if (unformat (i, "multipath")) + is_multipath = 1; + else if (unformat (i, "count %d", &count)) + ; + else if (unformat (i, "lookup-in-ip4-table %d", &next_hop_table_id)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 1; + } + else if (unformat (i, "lookup-in-ip6-table %d", &next_hop_table_id)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 0; + } + else if (unformat (i, "next-hop-table %d", &next_hop_table_id)) + ; + else if (unformat (i, "out-label %d", &next_hop_out_label)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!next_hop_set && !is_classify) + { + errmsg ("next hop / classify not set\n"); + return -99; + } + + if (MPLS_LABEL_INVALID == local_label) + { + errmsg ("missing label\n"); + return -99; + } + + if (count > 1) + { + /* Turn on async mode */ + vam->async_mode = 1; + vam->async_errors = 0; + before = vat_time_now (vam); + } + + for (j = 0; j < count; j++) + { + /* Construct the API message */ + M (MPLS_ROUTE_ADD_DEL, mpls_route_add_del); + + mp->mr_next_hop_sw_if_index = ntohl (sw_if_index); + mp->mr_table_id = ntohl (table_id); + mp->mr_create_table_if_needed = create_table_if_needed; + + mp->mr_is_add = is_add; + mp->mr_next_hop_proto_is_ip4 = next_hop_proto_is_ip4; + mp->mr_is_classify = is_classify; + mp->mr_is_multipath = is_multipath; + mp->mr_is_resolve_host = resolve_host; + mp->mr_is_resolve_attached = resolve_attached; + mp->mr_next_hop_weight = next_hop_weight; + mp->mr_next_hop_table_id = ntohl (next_hop_table_id); + mp->mr_classify_table_index = ntohl (classify_table_index); + mp->mr_next_hop_out_label = ntohl (next_hop_out_label); + mp->mr_label = ntohl (local_label); + mp->mr_eos = is_eos; + + if (next_hop_set) + { + if (next_hop_proto_is_ip4) + { + clib_memcpy (mp->mr_next_hop, + &v4_next_hop_address, + sizeof (v4_next_hop_address)); + } + else + { + clib_memcpy (mp->mr_next_hop, + &v6_next_hop_address, + sizeof (v6_next_hop_address)); + } + } + local_label++; + + /* send it... */ + S; + /* If we receive SIGTERM, stop now... */ + if (vam->do_exit) + break; + } + + /* When testing multiple add/del ops, use a control-ping to sync */ + if (count > 1) + { + vl_api_control_ping_t *mp; + f64 after; + + /* Shut off async mode */ + vam->async_mode = 0; + + M (CONTROL_PING, control_ping); + S; + + timeout = vat_time_now (vam) + 1.0; + while (vat_time_now (vam) < timeout) + if (vam->result_ready == 1) + goto out; + vam->retval = -99; + + out: + if (vam->retval == -99) + errmsg ("timeout\n"); + + if (vam->async_errors > 0) + { + errmsg ("%d asynchronous errors\n", vam->async_errors); + vam->retval = -98; + } + vam->async_errors = 0; + after = vat_time_now (vam); + + /* slim chance, but we might have eaten SIGTERM on the first iteration */ + if (j > 0) + count = j; + + fformat (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec\n", + count, after - before, count / (after - before)); + } + else + { + /* Wait for a reply... */ + W; + } + + /* Return the good/bad news */ + return (vam->retval); +} + +static int +api_mpls_ip_bind_unbind (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_mpls_ip_bind_unbind_t *mp; + f64 timeout; + u32 ip_table_id = 0; + u8 create_table_if_needed = 0; + u8 is_bind = 1; + u8 is_ip4 = 1; + ip4_address_t v4_address; + ip6_address_t v6_address; + u32 address_length; + u8 address_set = 0; + mpls_label_t local_label = MPLS_LABEL_INVALID; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U/%d", unformat_ip4_address, + &v4_address, &address_length)) + { + is_ip4 = 1; + address_set = 1; + } + else if (unformat (i, "%U/%d", unformat_ip6_address, + &v6_address, &address_length)) + { + is_ip4 = 0; + address_set = 1; + } + else if (unformat (i, "%d", &local_label)) + ; + else if (unformat (i, "create-table")) + create_table_if_needed = 1; + else if (unformat (i, "table-id %d", &ip_table_id)) + ; + else if (unformat (i, "unbind")) + is_bind = 0; + else if (unformat (i, "bind")) + is_bind = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!address_set) + { + errmsg ("IP addres not set\n"); + return -99; + } + + if (MPLS_LABEL_INVALID == local_label) + { + errmsg ("missing label\n"); + return -99; + } + + /* Construct the API message */ + M (MPLS_IP_BIND_UNBIND, mpls_ip_bind_unbind); + + mp->mb_create_table_if_needed = create_table_if_needed; + mp->mb_is_bind = is_bind; + mp->mb_is_ip4 = is_ip4; + mp->mb_ip_table_id = ntohl (ip_table_id); + mp->mb_mpls_table_id = 0; + mp->mb_label = ntohl (local_label); + mp->mb_address_length = address_length; + + if (is_ip4) + clib_memcpy (mp->mb_address, &v4_address, sizeof (v4_address)); + else + clib_memcpy (mp->mb_address, &v6_address, sizeof (v6_address)); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* Return the good/bad news */ + return (vam->retval); +} + +static int api_proxy_arp_add_del (vat_main_t * vam) { unformat_input_t *i = vam->input; @@ -6097,55 +6362,6 @@ api_proxy_arp_intfc_enable_disable (vat_main_t * vam) } static int -api_mpls_add_del_decap (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - vl_api_mpls_add_del_decap_t *mp; - f64 timeout; - u32 rx_vrf_id = 0; - u32 tx_vrf_id = 0; - u32 label = 0; - u8 is_add = 1; - u8 s_bit = 1; - u32 next_index = 1; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "rx_vrf_id %d", &rx_vrf_id)) - ; - else if (unformat (i, "tx_vrf_id %d", &tx_vrf_id)) - ; - else if (unformat (i, "label %d", &label)) - ; - else if (unformat (i, "next-index %d", &next_index)) - ; - else if (unformat (i, "del")) - is_add = 0; - else if (unformat (i, "s-bit-clear")) - s_bit = 0; - else - { - clib_warning ("parse error '%U'", format_unformat_error, i); - return -99; - } - } - - M (MPLS_ADD_DEL_DECAP, mpls_add_del_decap); - - mp->rx_vrf_id = ntohl (rx_vrf_id); - mp->tx_vrf_id = ntohl (tx_vrf_id); - mp->label = ntohl (label); - mp->next_index = ntohl (next_index); - mp->s_bit = s_bit; - mp->is_add = is_add; - - S; - W; - /* NOTREACHED */ - return 0; -} - -static int api_mpls_add_del_encap (vat_main_t * vam) { unformat_input_t *i = vam->input; @@ -6198,63 +6414,6 @@ api_mpls_add_del_encap (vat_main_t * vam) } static int -api_mpls_gre_add_del_tunnel (vat_main_t * vam) -{ - unformat_input_t *i = vam->input; - vl_api_mpls_gre_add_del_tunnel_t *mp; - f64 timeout; - u32 inner_vrf_id = 0; - u32 outer_vrf_id = 0; - ip4_address_t src_address; - ip4_address_t dst_address; - ip4_address_t intfc_address; - u32 tmp; - u8 intfc_address_length = 0; - u8 is_add = 1; - u8 l2_only = 0; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "inner_vrf_id %d", &inner_vrf_id)) - ; - else if (unformat (i, "outer_vrf_id %d", &outer_vrf_id)) - ; - else if (unformat (i, "src %U", unformat_ip4_address, &src_address)) - ; - else if (unformat (i, "dst %U", unformat_ip4_address, &dst_address)) - ; - else if (unformat (i, "adj %U/%d", unformat_ip4_address, - &intfc_address, &tmp)) - intfc_address_length = tmp; - else if (unformat (i, "l2-only")) - l2_only = 1; - else if (unformat (i, "del")) - is_add = 0; - else - { - clib_warning ("parse error '%U'", format_unformat_error, i); - return -99; - } - } - - M (MPLS_GRE_ADD_DEL_TUNNEL, mpls_gre_add_del_tunnel); - - mp->inner_vrf_id = ntohl (inner_vrf_id); - mp->outer_vrf_id = ntohl (outer_vrf_id); - clib_memcpy (mp->src_address, &src_address, sizeof (src_address)); - clib_memcpy (mp->dst_address, &dst_address, sizeof (dst_address)); - clib_memcpy (mp->intfc_address, &intfc_address, sizeof (intfc_address)); - mp->intfc_address_length = intfc_address_length; - mp->l2_only = l2_only; - mp->is_add = is_add; - - S; - W; - /* NOTREACHED */ - return 0; -} - -static int api_mpls_ethernet_add_del_tunnel (vat_main_t * vam) { unformat_input_t *i = vam->input; @@ -14491,117 +14650,6 @@ api_netmap_delete (vat_main_t * vam) return 0; } -static void vl_api_mpls_gre_tunnel_details_t_handler - (vl_api_mpls_gre_tunnel_details_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 i; - i32 len = ntohl (mp->nlabels); - - if (mp->l2_only == 0) - { - fformat (vam->ofp, "[%d]: src %U, dst %U, adj %U/%d, labels ", - ntohl (mp->tunnel_index), - format_ip4_address, &mp->tunnel_src, - format_ip4_address, &mp->tunnel_dst, - format_ip4_address, &mp->intfc_address, - ntohl (mp->mask_width)); - for (i = 0; i < len; i++) - { - fformat (vam->ofp, "%u ", ntohl (mp->labels[i])); - } - fformat (vam->ofp, "\n"); - fformat (vam->ofp, " inner fib index %d, outer fib index %d\n", - ntohl (mp->inner_fib_index), ntohl (mp->outer_fib_index)); - } - else - { - fformat (vam->ofp, "[%d]: src %U, dst %U, key %U, labels ", - ntohl (mp->tunnel_index), - format_ip4_address, &mp->tunnel_src, - format_ip4_address, &mp->tunnel_dst, - format_ip4_address, &mp->intfc_address); - for (i = 0; i < len; i++) - { - fformat (vam->ofp, "%u ", ntohl (mp->labels[i])); - } - fformat (vam->ofp, "\n"); - fformat (vam->ofp, " l2 interface %d, outer fib index %d\n", - ntohl (mp->hw_if_index), ntohl (mp->outer_fib_index)); - } -} - -static void vl_api_mpls_gre_tunnel_details_t_handler_json - (vl_api_mpls_gre_tunnel_details_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t *node = NULL; - struct in_addr ip4; - i32 i; - i32 len = ntohl (mp->nlabels); - - if (VAT_JSON_ARRAY != vam->json_tree.type) - { - ASSERT (VAT_JSON_NONE == vam->json_tree.type); - vat_json_init_array (&vam->json_tree); - } - node = vat_json_array_add (&vam->json_tree); - - vat_json_init_object (node); - vat_json_object_add_uint (node, "tunnel_index", ntohl (mp->tunnel_index)); - clib_memcpy (&ip4, &(mp->intfc_address), sizeof (ip4)); - vat_json_object_add_ip4 (node, "intfc_address", ip4); - vat_json_object_add_uint (node, "inner_fib_index", - ntohl (mp->inner_fib_index)); - vat_json_object_add_uint (node, "mask_width", ntohl (mp->mask_width)); - vat_json_object_add_uint (node, "encap_index", ntohl (mp->encap_index)); - vat_json_object_add_uint (node, "hw_if_index", ntohl (mp->hw_if_index)); - vat_json_object_add_uint (node, "l2_only", ntohl (mp->l2_only)); - clib_memcpy (&ip4, &(mp->tunnel_src), sizeof (ip4)); - vat_json_object_add_ip4 (node, "tunnel_src", ip4); - clib_memcpy (&ip4, &(mp->tunnel_dst), sizeof (ip4)); - vat_json_object_add_ip4 (node, "tunnel_dst", ip4); - vat_json_object_add_uint (node, "outer_fib_index", - ntohl (mp->outer_fib_index)); - vat_json_object_add_uint (node, "label_count", len); - for (i = 0; i < len; i++) - { - vat_json_object_add_uint (node, "label", ntohl (mp->labels[i])); - } -} - -static int -api_mpls_gre_tunnel_dump (vat_main_t * vam) -{ - vl_api_mpls_gre_tunnel_dump_t *mp; - f64 timeout; - i32 index = -1; - - /* Parse args required to build the message */ - while (unformat_check_input (vam->input) != UNFORMAT_END_OF_INPUT) - { - if (!unformat (vam->input, "tunnel_index %d", &index)) - { - index = -1; - break; - } - } - - fformat (vam->ofp, " tunnel_index %d\n", index); - - M (MPLS_GRE_TUNNEL_DUMP, mpls_gre_tunnel_dump); - mp->tunnel_index = htonl (index); - S; - - /* Use a control ping for synchronization */ - { - vl_api_control_ping_t *mp; - M (CONTROL_PING, control_ping); - S; - } - W; -} - static void vl_api_mpls_eth_tunnel_details_t_handler (vl_api_mpls_eth_tunnel_details_t * mp) { @@ -14755,23 +14803,21 @@ api_mpls_fib_encap_dump (vat_main_t * vam) W; } -static void vl_api_mpls_fib_decap_details_t_handler - (vl_api_mpls_fib_decap_details_t * mp) +static void +vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp) { vat_main_t *vam = &vat_main; fformat (vam->ofp, - "RX table %d, TX table/intfc %u, swif_tag '%s', label %u, s_bit %u\n", - ntohl (mp->rx_table_id), ntohl (mp->tx_table_id), mp->swif_tag, - ntohl (mp->label), ntohl (mp->s_bit)); + "table-id %d, label %u, ess_bit %u\n", + ntohl (mp->table_id), ntohl (mp->label), mp->eos_bit); } -static void vl_api_mpls_fib_decap_details_t_handler_json - (vl_api_mpls_fib_decap_details_t * mp) +static void vl_api_mpls_fib_details_t_handler_json + (vl_api_mpls_fib_details_t * mp) { vat_main_t *vam = &vat_main; vat_json_node_t *node = NULL; - struct in_addr ip4; if (VAT_JSON_ARRAY != vam->json_tree.type) { @@ -14781,24 +14827,18 @@ static void vl_api_mpls_fib_decap_details_t_handler_json node = vat_json_array_add (&vam->json_tree); vat_json_init_object (node); - vat_json_object_add_uint (node, "table", ntohl (mp->fib_index)); - vat_json_object_add_uint (node, "entry_index", ntohl (mp->entry_index)); - clib_memcpy (&ip4, &(mp->dest), sizeof (ip4)); - vat_json_object_add_ip4 (node, "dest", ip4); - vat_json_object_add_uint (node, "s_bit", ntohl (mp->s_bit)); + vat_json_object_add_uint (node, "table", ntohl (mp->table_id)); + vat_json_object_add_uint (node, "s_bit", mp->eos_bit); vat_json_object_add_uint (node, "label", ntohl (mp->label)); - vat_json_object_add_uint (node, "rx_table_id", ntohl (mp->rx_table_id)); - vat_json_object_add_uint (node, "tx_table_id", ntohl (mp->tx_table_id)); - vat_json_object_add_string_copy (node, "swif_tag", mp->swif_tag); } static int -api_mpls_fib_decap_dump (vat_main_t * vam) +api_mpls_fib_dump (vat_main_t * vam) { - vl_api_mpls_fib_decap_dump_t *mp; + vl_api_mpls_fib_dump_t *mp; f64 timeout; - M (MPLS_FIB_DECAP_DUMP, mpls_fib_decap_dump); + M (MPLS_FIB_DUMP, mpls_fib_dump); S; /* Use a control ping for synchronization */ @@ -16149,21 +16189,23 @@ _(tap_delete, \ "<vpp-if-name> | sw_if_index <id>") \ _(sw_interface_tap_dump, "") \ _(ip_add_del_route, \ - "<addr>/<mask> via <addr> [vrf <n>]\n" \ + "<addr>/<mask> via <addr> [table-id <n>]\n" \ + "[<intfc> | sw_if_index <id>] [resolve-attempts <n>]\n" \ + "[weight <n>] [drop] [local] [classify <n>] [del]\n" \ + "[multipath] [count <n>]") \ +_(mpls_route_add_del, \ + "<label> <eos> via <addr> [table-id <n>]\n" \ "[<intfc> | sw_if_index <id>] [resolve-attempts <n>]\n" \ "[weight <n>] [drop] [local] [classify <n>] [del]\n" \ "[multipath] [count <n>]") \ +_(mpls_ip_bind_unbind, \ + "<label> <addr/len>") \ _(proxy_arp_add_del, \ "<lo-ip4-addr> - <hi-ip4-addr> [vrf <n>] [del]") \ _(proxy_arp_intfc_enable_disable, \ "<intfc> | sw_if_index <id> enable | disable") \ _(mpls_add_del_encap, \ "label <n> dst <ip4-addr> [vrf <n>] [del]") \ -_(mpls_add_del_decap, \ - "label <n> [rx_vrf_id <n>] [tx_vrf_id] [s-bit-clear][del]") \ -_(mpls_gre_add_del_tunnel, \ - "inner_vrf_id <n> outer_vrf_id <n> src <ip4-address> dst <ip4-address>\n" \ - "adj <ip4-address>/<mask-width> [del]") \ _(sw_interface_set_unnumbered, \ "<intfc> | sw_if_index <id> unnum_if_index <id> [del]") \ _(ip_neighbor_add_del, \ @@ -16374,10 +16416,9 @@ _(policer_classify_dump, "type [ip4|ip6|l2]") \ _(netmap_create, "name <interface name> [hw-addr <mac>] [pipe] " \ "[master|slave]") \ _(netmap_delete, "name <interface name>") \ -_(mpls_gre_tunnel_dump, "tunnel_index <tunnel-id>") \ _(mpls_eth_tunnel_dump, "tunnel_index <tunnel-id>") \ _(mpls_fib_encap_dump, "") \ -_(mpls_fib_decap_dump, "") \ +_(mpls_fib_dump, "") \ _(classify_table_ids, "") \ _(classify_table_by_interface, "sw_if_index <sw_if_index>") \ _(classify_table_info, "table_id <nn>") \ diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c index b0e0412b127..33f87702056 100644 --- a/vpp/vpp-api/api.c +++ b/vpp/vpp-api/api.c @@ -282,6 +282,8 @@ _(SW_INTERFACE_DUMP, sw_interface_dump) \ _(SW_INTERFACE_DETAILS, sw_interface_details) \ _(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ _(IP_ADD_DEL_ROUTE, ip_add_del_route) \ +_(MPLS_ROUTE_ADD_DEL, mpls_route_add_del) \ +_(MPLS_IP_BIND_UNBIND, mpls_ip_bind_unbind) \ _(IS_ADDRESS_REACHABLE, is_address_reachable) \ _(SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address) \ _(SW_INTERFACE_SET_TABLE, sw_interface_set_table) \ @@ -305,11 +307,9 @@ _(TAP_DELETE, tap_delete) \ _(SW_INTERFACE_TAP_DUMP, sw_interface_tap_dump) \ _(CREATE_VLAN_SUBIF, create_vlan_subif) \ _(CREATE_SUBIF, create_subif) \ -_(MPLS_GRE_ADD_DEL_TUNNEL, mpls_gre_add_del_tunnel) \ _(MPLS_ETHERNET_ADD_DEL_TUNNEL, mpls_ethernet_add_del_tunnel) \ _(MPLS_ETHERNET_ADD_DEL_TUNNEL_2, mpls_ethernet_add_del_tunnel_2) \ _(MPLS_ADD_DEL_ENCAP, mpls_add_del_encap) \ -_(MPLS_ADD_DEL_DECAP, mpls_add_del_decap) \ _(PROXY_ARP_ADD_DEL, proxy_arp_add_del) \ _(PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable) \ _(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del) \ @@ -426,14 +426,12 @@ _(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface) \ _(POLICER_CLASSIFY_DUMP, policer_classify_dump) \ _(NETMAP_CREATE, netmap_create) \ _(NETMAP_DELETE, netmap_delete) \ -_(MPLS_GRE_TUNNEL_DUMP, mpls_gre_tunnel_dump) \ -_(MPLS_GRE_TUNNEL_DETAILS, mpls_gre_tunnel_details) \ _(MPLS_ETH_TUNNEL_DUMP, mpls_eth_tunnel_dump) \ _(MPLS_ETH_TUNNEL_DETAILS, mpls_eth_tunnel_details) \ _(MPLS_FIB_ENCAP_DUMP, mpls_fib_encap_dump) \ _(MPLS_FIB_ENCAP_DETAILS, mpls_fib_encap_details) \ -_(MPLS_FIB_DECAP_DUMP, mpls_fib_decap_dump) \ -_(MPLS_FIB_DECAP_DETAILS, mpls_fib_decap_details) \ +_(MPLS_FIB_DUMP, mpls_fib_dump) \ +_(MPLS_FIB_DETAILS, mpls_fib_details) \ _(CLASSIFY_TABLE_IDS,classify_table_ids) \ _(CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface) \ _(CLASSIFY_TABLE_INFO,classify_table_info) \ @@ -1031,44 +1029,57 @@ VLIB_REGISTER_NODE (vpe_resolver_process_node,static) = { /* *INDENT-ON* */ static int -ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp, - u32 fib_index, - const fib_prefix_t * prefix, - const ip46_address_t * next_hop, - u32 next_hop_sw_if_index, - u32 next_hop_fib_index, u32 next_hop_weight) +add_del_route_t_handler (u8 is_multipath, + u8 is_add, + u8 is_drop, + u8 is_local, + u8 is_classify, + u32 classify_table_index, + u8 is_resolve_host, + u8 is_resolve_attached, + u32 fib_index, + const fib_prefix_t * prefix, + u8 next_hop_proto_is_ip4, + const ip46_address_t * next_hop, + u32 next_hop_sw_if_index, + u8 next_hop_fib_index, + u32 next_hop_weight, u32 next_hop_out_label) { vnet_classify_main_t *cm = &vnet_classify_main; fib_protocol_t proto = prefix->fp_proto; stats_main_t *sm = &stats_main; - if (mp->is_multipath) + if (is_multipath) { fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE; dslock (sm, 1 /* release hint */ , 10 /* tag */ ); - if (mp->is_resolve_host) + if (is_resolve_host) path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST; - if (mp->is_resolve_attached) + if (is_resolve_attached) path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED; - if (mp->is_add) + if (is_add) fib_table_entry_path_add (fib_index, prefix, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - prefix->fp_proto, + (next_hop_proto_is_ip4 ? + FIB_PROTOCOL_IP4 : + FIB_PROTOCOL_IP6), next_hop, next_hop_sw_if_index, next_hop_fib_index, next_hop_weight, - MPLS_LABEL_INVALID, path_flags); + next_hop_out_label, path_flags); else fib_table_entry_path_remove (fib_index, prefix, FIB_SOURCE_API, - prefix->fp_proto, + (next_hop_proto_is_ip4 ? + FIB_PROTOCOL_IP4 : + FIB_PROTOCOL_IP6), next_hop, next_hop_sw_if_index, next_hop_fib_index, @@ -1080,26 +1091,26 @@ ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp, dslock (sm, 1 /* release hint */ , 2 /* tag */ ); - if (mp->is_drop || mp->is_local || mp->is_classify || mp->lookup_in_vrf) + if (is_drop || is_local || is_classify) { /* * special route types that link directly to the adj */ - if (mp->is_add) + if (is_add) { dpo_id_t dpo = DPO_NULL; dpo_proto_t dproto; dproto = fib_proto_to_dpo (prefix->fp_proto); - if (mp->is_drop) + if (is_drop) dpo_copy (&dpo, drop_dpo_get (dproto)); - else if (mp->is_local) + else if (is_local) receive_dpo_add_or_lock (dproto, ~0, NULL, &dpo); - else if (mp->is_classify) + else if (is_classify) { if (pool_is_free_index (cm->tables, - ntohl (mp->classify_table_index))) + ntohl (classify_table_index))) { dsunlock (sm); return VNET_API_ERROR_NO_SUCH_TABLE; @@ -1107,25 +1118,7 @@ ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp, dpo_set (&dpo, DPO_CLASSIFY, proto, classify_dpo_create (prefix->fp_proto, - ntohl - (mp->classify_table_index))); - } - else if (mp->lookup_in_vrf) - { - next_hop_fib_index = - fib_table_id_find_fib_index (dproto, - ntohl (mp->lookup_in_vrf)); - if (~0 == next_hop_fib_index) - { - dsunlock (sm); - return VNET_API_ERROR_NO_SUCH_INNER_FIB; - } - - lookup_dpo_add_or_lock_w_fib_index (next_hop_fib_index, - dproto, - LOOKUP_INPUT_DST_ADDR, - LOOKUP_TABLE_FROM_CONFIG, - &dpo); + ntohl (classify_table_index))); } else { @@ -1146,25 +1139,27 @@ ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp, } else { - if (mp->is_add) + if (is_add) { fib_route_path_flags_t path_flags = FIB_ROUTE_PATH_FLAG_NONE; - if (mp->is_resolve_host) + if (is_resolve_host) path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST; - if (mp->is_resolve_attached) + if (is_resolve_attached) path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED; fib_table_entry_update_one_path (fib_index, prefix, FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, - prefix->fp_proto, + (next_hop_proto_is_ip4 ? + FIB_PROTOCOL_IP4 : + FIB_PROTOCOL_IP6), next_hop, next_hop_sw_if_index, next_hop_fib_index, next_hop_weight, - MPLS_LABEL_INVALID, path_flags); + next_hop_out_label, path_flags); } else { @@ -1177,19 +1172,23 @@ ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp, } static int -ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) +add_del_route_check (fib_protocol_t table_proto, + u32 table_id, + u32 next_hop_sw_if_index, + fib_protocol_t next_hop_table_proto, + u32 next_hop_table_id, + u8 create_missing_tables, + u32 * fib_index, u32 * next_hop_fib_index) { - vpe_api_main_t *vam = &vpe_api_main; - vnet_main_t *vnm = vam->vnet_main; - u32 fib_index; + vnet_main_t *vnm = vnet_get_main (); - fib_index = ip4_fib_index_from_table_id (ntohl (mp->vrf_id)); - if (~0 == fib_index) + *fib_index = fib_table_find (table_proto, ntohl (table_id)); + if (~0 == *fib_index) { - if (mp->create_vrf_if_needed) + if (create_missing_tables) { - fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, - ntohl (mp->vrf_id)); + *fib_index = fib_table_find_or_create_and_lock (table_proto, + ntohl (table_id)); } else { @@ -1198,10 +1197,54 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) } } - if (~0 != ntohl (mp->next_hop_sw_if_index) && - pool_is_free_index (vnm->interface_main.sw_interfaces, - ntohl (mp->next_hop_sw_if_index))) - return VNET_API_ERROR_NO_MATCHING_INTERFACE; + if (~0 != ntohl (next_hop_sw_if_index)) + { + if (pool_is_free_index (vnm->interface_main.sw_interfaces, + ntohl (next_hop_sw_if_index))) + { + return VNET_API_ERROR_NO_MATCHING_INTERFACE; + } + } + else + { + *next_hop_fib_index = fib_table_find (next_hop_table_proto, + ntohl (next_hop_table_id)); + + if (~0 == *next_hop_fib_index) + { + if (create_missing_tables) + { + *next_hop_fib_index = + fib_table_find_or_create_and_lock (next_hop_table_proto, + ntohl (next_hop_table_id)); + } + else + { + /* No such VRF, and we weren't asked to create one */ + return VNET_API_ERROR_NO_SUCH_FIB; + } + } + } + + return (0); +} + +static int +ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) +{ + u32 fib_index, next_hop_fib_index; + int rv; + + rv = add_del_route_check (FIB_PROTOCOL_IP4, + mp->table_id, + mp->next_hop_sw_if_index, + FIB_PROTOCOL_IP4, + mp->next_hop_table_id, + mp->create_vrf_if_needed, + &fib_index, &next_hop_fib_index); + + if (0 != rv) + return (rv); fib_prefix_t pfx = { .fp_len = mp->dst_address_length, @@ -1213,50 +1256,109 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) memset (&nh, 0, sizeof (nh)); memcpy (&nh.ip4, mp->next_hop_address, sizeof (nh.ip4)); - return (ip_add_del_route_t_handler (mp, fib_index, &pfx, &nh, - ntohl (mp->next_hop_sw_if_index), - fib_index, (u32) mp->next_hop_weight)); + return (add_del_route_t_handler (mp->is_multipath, mp->is_add, mp->is_drop, mp->is_local, mp->is_classify, mp->classify_table_index, mp->is_resolve_host, mp->is_resolve_attached, fib_index, &pfx, 1, // is_ip4 + &nh, + ntohl (mp->next_hop_sw_if_index), + next_hop_fib_index, + mp->next_hop_weight, + ntohl (mp->next_hop_out_label))); } static int ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) { - vnet_main_t *vnm = vnet_get_main (); - u32 fib_index; + u32 fib_index, next_hop_fib_index; + int rv; + + rv = add_del_route_check (FIB_PROTOCOL_IP6, + mp->table_id, + mp->next_hop_sw_if_index, + FIB_PROTOCOL_IP6, + mp->next_hop_table_id, + mp->create_vrf_if_needed, + &fib_index, &next_hop_fib_index); + + if (0 != rv) + return (rv); + + fib_prefix_t pfx = { + .fp_len = mp->dst_address_length, + .fp_proto = FIB_PROTOCOL_IP6, + }; + clib_memcpy (&pfx.fp_addr.ip6, mp->dst_address, sizeof (pfx.fp_addr.ip6)); + + ip46_address_t nh; + memset (&nh, 0, sizeof (nh)); + memcpy (&nh.ip6, mp->next_hop_address, sizeof (nh.ip6)); + + return (add_del_route_t_handler (mp->is_multipath, mp->is_add, mp->is_drop, mp->is_local, mp->is_classify, mp->classify_table_index, mp->is_resolve_host, mp->is_resolve_attached, fib_index, &pfx, 0, // is_ip4 + &nh, ntohl (mp->next_hop_sw_if_index), + next_hop_fib_index, + mp->next_hop_weight, + ntohl (mp->next_hop_out_label))); +} + +static int +mpls_route_add_del_t_handler (vnet_main_t * vnm, + vl_api_mpls_route_add_del_t * mp) +{ + u32 fib_index, next_hop_fib_index; - fib_index = ip6_fib_index_from_table_id (ntohl (mp->vrf_id)); - if (~0 == fib_index) + int rv; + + fib_prefix_t pfx = { + .fp_len = 21, + .fp_proto = FIB_PROTOCOL_MPLS, + .fp_eos = mp->mr_eos, + .fp_label = ntohl (mp->mr_label), + }; + if (pfx.fp_eos) { - if (mp->create_vrf_if_needed) + if (mp->mr_next_hop_proto_is_ip4) { - fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, - ntohl (mp->vrf_id)); + pfx.fp_payload_proto = DPO_PROTO_IP4; } else { - /* No such VRF, and we weren't asked to create one */ - return VNET_API_ERROR_NO_SUCH_FIB; + pfx.fp_payload_proto = DPO_PROTO_IP6; } } + else + { + pfx.fp_payload_proto = DPO_PROTO_MPLS; + } - if (~0 != ntohl (mp->next_hop_sw_if_index) && - pool_is_free_index (vnm->interface_main.sw_interfaces, - ntohl (mp->next_hop_sw_if_index))) - return VNET_API_ERROR_NO_MATCHING_INTERFACE; + rv = add_del_route_check (FIB_PROTOCOL_MPLS, + mp->mr_table_id, + mp->mr_next_hop_sw_if_index, + dpo_proto_to_fib (pfx.fp_payload_proto), + mp->mr_next_hop_table_id, + mp->mr_create_table_if_needed, + &fib_index, &next_hop_fib_index); - fib_prefix_t pfx = { - .fp_len = mp->dst_address_length, - .fp_proto = FIB_PROTOCOL_IP6, - }; - clib_memcpy (&pfx.fp_addr.ip6, mp->dst_address, sizeof (pfx.fp_addr.ip6)); + if (0 != rv) + return (rv); ip46_address_t nh; memset (&nh, 0, sizeof (nh)); - memcpy (&nh.ip6, mp->next_hop_address, sizeof (nh.ip6)); - return (ip_add_del_route_t_handler (mp, fib_index, &pfx, - &nh, ntohl (mp->next_hop_sw_if_index), - fib_index, (u32) mp->next_hop_weight)); + if (mp->mr_next_hop_proto_is_ip4) + memcpy (&nh.ip4, mp->mr_next_hop, sizeof (nh.ip4)); + else + memcpy (&nh.ip6, mp->mr_next_hop, sizeof (nh.ip6)); + + return (add_del_route_t_handler (mp->mr_is_multipath, mp->mr_is_add, 0, // mp->is_drop, + 0, // mp->is_local, + mp->mr_is_classify, + mp->mr_classify_table_index, + mp->mr_is_resolve_host, + mp->mr_is_resolve_attached, + fib_index, &pfx, + mp->mr_next_hop_proto_is_ip4, + &nh, ntohl (mp->mr_next_hop_sw_if_index), + next_hop_fib_index, + mp->mr_next_hop_weight, + ntohl (mp->mr_next_hop_out_label))); } void @@ -1278,6 +1380,95 @@ vl_api_ip_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp) REPLY_MACRO (VL_API_IP_ADD_DEL_ROUTE_REPLY); } +void +vl_api_mpls_route_add_del_t_handler (vl_api_mpls_route_add_del_t * mp) +{ + vl_api_mpls_route_add_del_reply_t *rmp; + vnet_main_t *vnm; + int rv; + + vnm = vnet_get_main (); + vnm->api_errno = 0; + + rv = mpls_route_add_del_t_handler (vnm, mp); + + rv = (rv == 0) ? vnm->api_errno : rv; + + REPLY_MACRO (VL_API_MPLS_ROUTE_ADD_DEL_REPLY); +} + +static int +mpls_ip_bind_unbind_handler (vnet_main_t * vnm, + vl_api_mpls_ip_bind_unbind_t * mp) +{ + u32 mpls_fib_index, ip_fib_index; + + mpls_fib_index = + fib_table_find (FIB_PROTOCOL_MPLS, ntohl (mp->mb_mpls_table_id)); + + if (~0 == mpls_fib_index) + { + if (mp->mb_create_table_if_needed) + { + mpls_fib_index = + fib_table_find_or_create_and_lock (FIB_PROTOCOL_MPLS, + ntohl (mp->mb_mpls_table_id)); + } + else + return VNET_API_ERROR_NO_SUCH_FIB; + } + + ip_fib_index = fib_table_find ((mp->mb_is_ip4 ? + FIB_PROTOCOL_IP4 : + FIB_PROTOCOL_IP6), + ntohl (mp->mb_ip_table_id)); + if (~0 == ip_fib_index) + return VNET_API_ERROR_NO_SUCH_FIB; + + fib_prefix_t pfx = { + .fp_len = mp->mb_address_length, + }; + + if (mp->mb_is_ip4) + { + pfx.fp_proto = FIB_PROTOCOL_IP4; + clib_memcpy (&pfx.fp_addr.ip4, mp->mb_address, + sizeof (pfx.fp_addr.ip4)); + } + else + { + pfx.fp_proto = FIB_PROTOCOL_IP6; + clib_memcpy (&pfx.fp_addr.ip6, mp->mb_address, + sizeof (pfx.fp_addr.ip6)); + } + + if (mp->mb_is_bind) + fib_table_entry_local_label_add (ip_fib_index, &pfx, + ntohl (mp->mb_label)); + else + fib_table_entry_local_label_remove (ip_fib_index, &pfx, + ntohl (mp->mb_label)); + + return (0); +} + +void +vl_api_mpls_ip_bind_unbind_t_handler (vl_api_mpls_ip_bind_unbind_t * mp) +{ + vl_api_mpls_route_add_del_reply_t *rmp; + vnet_main_t *vnm; + int rv; + + vnm = vnet_get_main (); + vnm->api_errno = 0; + + rv = mpls_ip_bind_unbind_handler (vnm, mp); + + rv = (rv == 0) ? vnm->api_errno : rv; + + REPLY_MACRO (VL_API_MPLS_ROUTE_ADD_DEL_REPLY); +} + static void vl_api_sw_interface_add_del_address_t_handler (vl_api_sw_interface_add_del_address_t * mp) @@ -2169,35 +2360,6 @@ out: } static void -vl_api_mpls_gre_add_del_tunnel_t_handler (vl_api_mpls_gre_add_del_tunnel_t * - mp) -{ - vl_api_mpls_gre_add_del_tunnel_reply_t *rmp; - int rv = 0; - stats_main_t *sm = &stats_main; - u32 tunnel_sw_if_index = ~0; - - dslock (sm, 1 /* release hint */ , 5 /* tag */ ); - - rv = vnet_mpls_gre_add_del_tunnel ((ip4_address_t *) (mp->src_address), - (ip4_address_t *) (mp->dst_address), - (ip4_address_t *) (mp->intfc_address), - (u32) (mp->intfc_address_length), - ntohl (mp->inner_vrf_id), - ntohl (mp->outer_vrf_id), - &tunnel_sw_if_index, - mp->l2_only, mp->is_add); - dsunlock (sm); - - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_MPLS_GRE_ADD_DEL_TUNNEL_REPLY, - ({ - rmp->tunnel_sw_if_index = ntohl(tunnel_sw_if_index); - })); - /* *INDENT-ON* */ -} - -static void vl_api_mpls_ethernet_add_del_tunnel_t_handler (vl_api_mpls_ethernet_add_del_tunnel_t * mp) { @@ -2364,19 +2526,6 @@ vl_api_mpls_add_del_encap_t_handler (vl_api_mpls_add_del_encap_t * mp) } static void -vl_api_mpls_add_del_decap_t_handler (vl_api_mpls_add_del_decap_t * mp) -{ - vl_api_mpls_add_del_decap_reply_t *rmp; - int rv; - - rv = vnet_mpls_add_del_decap (ntohl (mp->rx_vrf_id), ntohl (mp->tx_vrf_id), - ntohl (mp->label), ntohl (mp->next_index), - mp->s_bit, mp->is_add); - - REPLY_MACRO (VL_API_MPLS_ADD_DEL_DECAP_REPLY); -} - -static void vl_api_proxy_arp_add_del_t_handler (vl_api_proxy_arp_add_del_t * mp) { vl_api_proxy_arp_add_del_reply_t *rmp; @@ -2967,9 +3116,6 @@ ip4_reset_fib_t_handler (vl_api_reset_fib_t * mp) if (fib->table_id != target_fib_id) continue; - /* remove any mpls/gre tunnels in this fib */ - vnet_mpls_gre_delete_fib_tunnels (fib->table_id); - /* remove any mpls encap/decap labels */ mpls_fib_reset_labels (fib->table_id); @@ -7387,41 +7533,40 @@ vl_api_netmap_delete_t_handler (vl_api_netmap_delete_t * mp) } static void -vl_api_mpls_gre_tunnel_details_t_handler (vl_api_mpls_gre_tunnel_details_t * +vl_api_mpls_eth_tunnel_details_t_handler (vl_api_mpls_eth_tunnel_details_t * mp) { clib_warning ("BUG"); } static void -send_mpls_gre_tunnel_entry (vpe_api_main_t * am, +send_mpls_eth_tunnel_entry (vpe_api_main_t * am, unix_shared_memory_queue_t * q, - mpls_gre_tunnel_t * gt, u32 index, u32 context) + mpls_eth_tunnel_t * et, u32 index, u32 context) { - vl_api_mpls_gre_tunnel_details_t *mp; mpls_main_t *mm = &mpls_main; mpls_encap_t *e; int i; u32 nlabels; + vl_api_mpls_eth_tunnel_details_t *mp; - e = pool_elt_at_index (mm->encaps, gt->encap_index); + e = pool_elt_at_index (mm->encaps, et->encap_index); nlabels = vec_len (e->labels); mp = vl_msg_api_alloc (sizeof (*mp) + nlabels * sizeof (u32)); memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_MPLS_GRE_TUNNEL_DETAILS); + mp->_vl_msg_id = ntohs (VL_API_MPLS_ETH_TUNNEL_DETAILS); mp->context = context; mp->tunnel_index = htonl (index); - mp->tunnel_src = gt->tunnel_src.as_u32; - mp->tunnel_dst = gt->tunnel_dst.as_u32; - mp->intfc_address = gt->intfc_address.as_u32; - mp->mask_width = htonl (gt->mask_width); - mp->inner_fib_index = htonl (gt->inner_fib_index); - mp->outer_fib_index = htonl (gt->outer_fib_index); - mp->encap_index = htonl (gt->encap_index); - mp->hw_if_index = htonl (gt->hw_if_index); - mp->l2_only = htonl (gt->l2_only); + memcpy (mp->tunnel_dst_mac, et->tunnel_dst, 6); + mp->intfc_address = et->intfc_address.as_u32; + mp->tx_sw_if_index = htonl (et->tx_sw_if_index); + mp->inner_fib_index = htonl (et->inner_fib_index); + mp->mask_width = htonl (et->mask_width); + mp->encap_index = htonl (et->encap_index); + mp->hw_if_index = htonl (et->hw_if_index); + mp->l2_only = htonl (et->l2_only); mp->nlabels = htonl (nlabels); for (i = 0; i < nlabels; i++) @@ -7435,12 +7580,12 @@ send_mpls_gre_tunnel_entry (vpe_api_main_t * am, } static void -vl_api_mpls_gre_tunnel_dump_t_handler (vl_api_mpls_gre_tunnel_dump_t * mp) +vl_api_mpls_eth_tunnel_dump_t_handler (vl_api_mpls_eth_tunnel_dump_t * mp) { vpe_api_main_t *am = &vpe_api_main; unix_shared_memory_queue_t *q; mpls_main_t *mm = &mpls_main; - mpls_gre_tunnel_t *gt; + mpls_eth_tunnel_t *et; u32 index = ntohl (mp->tunnel_index); q = vl_api_client_index_to_input_queue (mp->client_index); @@ -7449,19 +7594,19 @@ vl_api_mpls_gre_tunnel_dump_t_handler (vl_api_mpls_gre_tunnel_dump_t * mp) if (index != ~0) { - if (!pool_is_free_index (mm->gre_tunnels, index)) + if (!pool_is_free_index (mm->eth_tunnels, index)) { - gt = pool_elt_at_index (mm->gre_tunnels, index); - send_mpls_gre_tunnel_entry (am, q, gt, gt - mm->gre_tunnels, + et = pool_elt_at_index (mm->eth_tunnels, index); + send_mpls_eth_tunnel_entry (am, q, et, et - mm->eth_tunnels, mp->context); } } else { /* *INDENT-OFF* */ - pool_foreach (gt, mm->gre_tunnels, + pool_foreach (et, mm->eth_tunnels, ({ - send_mpls_gre_tunnel_entry (am, q, gt, gt - mm->gre_tunnels, + send_mpls_eth_tunnel_entry (am, q, et, et - mm->eth_tunnels, mp->context); })); /* *INDENT-ON* */ @@ -7469,84 +7614,71 @@ vl_api_mpls_gre_tunnel_dump_t_handler (vl_api_mpls_gre_tunnel_dump_t * mp) } static void -vl_api_mpls_eth_tunnel_details_t_handler (vl_api_mpls_eth_tunnel_details_t * - mp) +vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp) { clib_warning ("BUG"); } static void -send_mpls_eth_tunnel_entry (vpe_api_main_t * am, - unix_shared_memory_queue_t * q, - mpls_eth_tunnel_t * et, u32 index, u32 context) +send_mpls_fib_details (vpe_api_main_t * am, + unix_shared_memory_queue_t * q, + u32 table_id, u32 label, u32 eos, u32 context) { - mpls_main_t *mm = &mpls_main; - mpls_encap_t *e; - int i; - u32 nlabels; - vl_api_mpls_eth_tunnel_details_t *mp; + vl_api_mpls_fib_details_t *mp; - e = pool_elt_at_index (mm->encaps, et->encap_index); - nlabels = vec_len (e->labels); - - mp = vl_msg_api_alloc (sizeof (*mp) + nlabels * sizeof (u32)); + mp = vl_msg_api_alloc (sizeof (*mp)); memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_MPLS_ETH_TUNNEL_DETAILS); + mp->_vl_msg_id = ntohs (VL_API_MPLS_FIB_DETAILS); mp->context = context; - mp->tunnel_index = htonl (index); - memcpy (mp->tunnel_dst_mac, et->tunnel_dst, 6); - mp->intfc_address = et->intfc_address.as_u32; - mp->tx_sw_if_index = htonl (et->tx_sw_if_index); - mp->inner_fib_index = htonl (et->inner_fib_index); - mp->mask_width = htonl (et->mask_width); - mp->encap_index = htonl (et->encap_index); - mp->hw_if_index = htonl (et->hw_if_index); - mp->l2_only = htonl (et->l2_only); - mp->nlabels = htonl (nlabels); - - for (i = 0; i < nlabels; i++) - { - mp->labels[i] = - htonl (vnet_mpls_uc_get_label - (clib_host_to_net_u32 (e->labels[i].label_exp_s_ttl))); - } + mp->table_id = htonl (table_id); + mp->eos_bit = eos; + mp->label = htonl (label); vl_msg_api_send_shmem (q, (u8 *) & mp); } static void -vl_api_mpls_eth_tunnel_dump_t_handler (vl_api_mpls_eth_tunnel_dump_t * mp) +vl_api_mpls_fib_dump_t_handler (vl_api_mpls_fib_dump_t * mp) { vpe_api_main_t *am = &vpe_api_main; unix_shared_memory_queue_t *q; mpls_main_t *mm = &mpls_main; - mpls_eth_tunnel_t *et; - u32 index = ntohl (mp->tunnel_index); + fib_table_t *fib_table; + fib_node_index_t lfei, *lfeip, *lfeis = NULL; + mpls_label_t key; + fib_prefix_t pfx; + u32 fib_index; q = vl_api_client_index_to_input_queue (mp->client_index); if (q == 0) return; - if (index != ~0) - { - if (!pool_is_free_index (mm->eth_tunnels, index)) - { - et = pool_elt_at_index (mm->eth_tunnels, index); - send_mpls_eth_tunnel_entry (am, q, et, et - mm->eth_tunnels, - mp->context); - } - } - else - { - /* *INDENT-OFF* */ - pool_foreach (et, mm->eth_tunnels, - ({ - send_mpls_eth_tunnel_entry (am, q, et, et - mm->eth_tunnels, - mp->context); - })); - /* *INDENT-ON* */ - } + /* *INDENT-OFF* */ + pool_foreach (fib_table, mm->fibs, + ({ + hash_foreach(key, lfei, fib_table->mpls.mf_entries, + ({ + vec_add1(lfeis, lfei); + })); + })); + vec_sort_with_function(lfeis, fib_entry_cmp_for_sort); + + vec_foreach(lfeip, lfeis) + { + fib_entry_get_prefix(*lfeip, &pfx); + fib_index = fib_entry_get_fib_index(*lfeip); + + fib_table = fib_table_get(fib_index, pfx.fp_proto); + + send_mpls_fib_details (am, q, + fib_table->ft_table_id, + pfx.fp_label, + pfx.fp_eos, + mp->context); + } + + vec_free (lfeis); } static void @@ -7643,108 +7775,6 @@ out: } static void -vl_api_mpls_fib_decap_details_t_handler (vl_api_mpls_fib_decap_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -send_mpls_fib_decap_details (vpe_api_main_t * am, - unix_shared_memory_queue_t * q, - show_mpls_fib_t * s, - u32 rx_table_id, - u32 tx_table_id, char *swif_tag, u32 context) -{ - vl_api_mpls_fib_decap_details_t *mp; - - mp = vl_msg_api_alloc (sizeof (*mp)); - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_MPLS_FIB_DECAP_DETAILS); - mp->context = context; - - mp->fib_index = htonl (s->fib_index); - mp->entry_index = htonl (s->entry_index); - mp->dest = s->dest; - mp->s_bit = htonl (s->s_bit); - mp->label = htonl (s->label); - mp->rx_table_id = htonl (rx_table_id); - mp->tx_table_id = htonl (tx_table_id); - strncpy ((char *) mp->swif_tag, - (char *) swif_tag, ARRAY_LEN (mp->swif_tag) - 1); - - vl_msg_api_send_shmem (q, (u8 *) & mp); -} - -static void -vl_api_mpls_fib_decap_dump_t_handler (vl_api_mpls_fib_decap_dump_t * mp) -{ - vpe_api_main_t *am = &vpe_api_main; - unix_shared_memory_queue_t *q; - vlib_main_t *vm = &vlib_global_main; - u64 key; - u32 value; - show_mpls_fib_t *records = 0; - show_mpls_fib_t *s; - mpls_main_t *mm = &mpls_main; - ip4_fib_t *rx_fib; - ip4_fib_t *tx_fib; - u32 tx_table_id; - char *swif_tag; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* *INDENT-OFF* */ - hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label, - ({ - vec_add2 (records, s, 1); - s->fib_index = (u32)(key>>32); - s->entry_index = (u32) value; - s->label = ((u32) key)>>12; - s->s_bit = (key & (1<<8)) != 0; - })); - /* *INDENT-ON* */ - - if (!vec_len (records)) - { - vlib_cli_output (vm, "MPLS decap table empty"); - goto out; - } - - vec_sort_with_function (records, mpls_label_cmp); - vlib_cli_output (vm, "MPLS decap table"); - vlib_cli_output (vm, "%=10s%=15s%=6s%=6s", "RX Table", "TX Table/Intfc", - "Label", "S-bit"); - vec_foreach (s, records) - { - mpls_decap_t *d; - d = pool_elt_at_index (mm->decaps, s->entry_index); - if (d->next_index == MPLS_LOOKUP_NEXT_IP4_INPUT) - { - tx_fib = ip4_fib_get (d->tx_fib_index); - tx_table_id = tx_fib->table_id; - swif_tag = " "; - } - else - { - tx_table_id = d->tx_fib_index; - swif_tag = "(i) "; - } - rx_fib = ip4_fib_get (s->fib_index); - - vlib_cli_output (vm, "%=10d%=10d%=5s%=6d%=6d", rx_fib->table_id, - tx_table_id, swif_tag, s->label, s->s_bit); - - send_mpls_fib_decap_details (am, q, s, rx_fib->table_id, - tx_table_id, swif_tag, mp->context); - } - -out: - vec_free (records); -} - -static void vl_api_classify_table_ids_t_handler (vl_api_classify_table_ids_t * mp) { unix_shared_memory_queue_t *q; diff --git a/vpp/vpp-api/custom_dump.c b/vpp/vpp-api/custom_dump.c index 887c9fc7459..cce6bb83853 100644 --- a/vpp/vpp-api/custom_dump.c +++ b/vpp/vpp-api/custom_dump.c @@ -477,8 +477,8 @@ static void *vl_api_ip_add_del_route_t_print s = format (s, "via %U ", format_ip4_address, mp->next_hop_address); } - if (mp->vrf_id != 0) - s = format (s, "vrf %d ", ntohl (mp->vrf_id)); + if (mp->table_id != 0) + s = format (s, "vrf %d ", ntohl (mp->table_id)); if (mp->create_vrf_if_needed) s = format (s, "create-vrf "); @@ -498,8 +498,8 @@ static void *vl_api_ip_add_del_route_t_print if (mp->is_multipath) s = format (s, "multipath "); - if (mp->lookup_in_vrf) - s = format (s, "lookup-in-vrf %d ", ntohl (mp->lookup_in_vrf)); + if (mp->next_hop_table_id) + s = format (s, "lookup-in-vrf %d ", ntohl (mp->next_hop_table_id)); FINISH; } @@ -537,30 +537,6 @@ static void *vl_api_proxy_arp_intfc_enable_disable_t_print FINISH; } -static void *vl_api_mpls_add_del_decap_t_print - (vl_api_mpls_add_del_decap_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: mpls_add_del_decap "); - - s = format (s, "rx_vrf_id %d ", ntohl (mp->rx_vrf_id)); - - s = format (s, "tx_vrf_id %d ", ntohl (mp->tx_vrf_id)); - - s = format (s, "label %d ", ntohl (mp->label)); - - s = format (s, "next-index %d ", ntohl (mp->next_index)); - - if (mp->s_bit == 0) - s = format (s, "s-bit-clear "); - - if (mp->is_add == 0) - s = format (s, "del "); - - FINISH; -} - static void *vl_api_mpls_add_del_encap_t_print (vl_api_mpls_add_del_encap_t * mp, void *handle) { @@ -582,33 +558,6 @@ static void *vl_api_mpls_add_del_encap_t_print FINISH; } -static void *vl_api_mpls_gre_add_del_tunnel_t_print - (vl_api_mpls_gre_add_del_tunnel_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: mpls_gre_add_del_tunnel "); - - s = format (s, "src %U ", format_ip4_address, mp->src_address); - - s = format (s, "dst %U ", format_ip4_address, mp->dst_address); - - s = format (s, "adj %U/%d ", format_ip4_address, - (ip4_address_t *) mp->intfc_address, mp->intfc_address_length); - - s = format (s, "inner-vrf_id %d ", ntohl (mp->inner_vrf_id)); - - s = format (s, "outer-vrf_id %d ", ntohl (mp->outer_vrf_id)); - - if (mp->is_add == 0) - s = format (s, "del "); - - if (mp->l2_only) - s = format (s, "l2-only "); - - FINISH; -} - static void *vl_api_mpls_ethernet_add_del_tunnel_t_print (vl_api_mpls_ethernet_add_del_tunnel_t * mp, void *handle) { @@ -2060,18 +2009,6 @@ static void *vl_api_sw_interface_clear_stats_t_print FINISH; } -static void *vl_api_mpls_gre_tunnel_dump_t_print - (vl_api_mpls_gre_tunnel_dump_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: mpls_gre_tunnel_dump "); - - s = format (s, "tunnel_index %d ", ntohl (mp->tunnel_index)); - - FINISH; -} - static void *vl_api_mpls_eth_tunnel_dump_t_print (vl_api_mpls_eth_tunnel_dump_t * mp, void *handle) { @@ -2094,8 +2031,8 @@ static void *vl_api_mpls_fib_encap_dump_t_print FINISH; } -static void *vl_api_mpls_fib_decap_dump_t_print - (vl_api_mpls_fib_decap_dump_t * mp, void *handle) +static void *vl_api_mpls_fib_dump_t_print + (vl_api_mpls_fib_dump_t * mp, void *handle) { u8 *s; @@ -2871,9 +2808,7 @@ _(SW_INTERFACE_TAP_DUMP, sw_interface_tap_dump) \ _(IP_ADD_DEL_ROUTE, ip_add_del_route) \ _(PROXY_ARP_ADD_DEL, proxy_arp_add_del) \ _(PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable) \ -_(MPLS_ADD_DEL_DECAP, mpls_add_del_decap) \ _(MPLS_ADD_DEL_ENCAP, mpls_add_del_encap) \ -_(MPLS_GRE_ADD_DEL_TUNNEL, mpls_gre_add_del_tunnel) \ _(MPLS_ETHERNET_ADD_DEL_TUNNEL, mpls_ethernet_add_del_tunnel) \ _(MPLS_ETHERNET_ADD_DEL_TUNNEL_2, mpls_ethernet_add_del_tunnel_2) \ _(SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered) \ @@ -2951,10 +2886,9 @@ _(COP_WHITELIST_ENABLE_DISABLE, cop_whitelist_enable_disable) \ _(AF_PACKET_CREATE, af_packet_create) \ _(AF_PACKET_DELETE, af_packet_delete) \ _(SW_INTERFACE_CLEAR_STATS, sw_interface_clear_stats) \ -_(MPLS_GRE_TUNNEL_DUMP, mpls_gre_tunnel_dump) \ _(MPLS_ETH_TUNNEL_DUMP, mpls_eth_tunnel_dump) \ _(MPLS_FIB_ENCAP_DUMP, mpls_fib_encap_dump) \ -_(MPLS_FIB_DECAP_DUMP, mpls_fib_decap_dump) \ +_(MPLS_FIB_DUMP, mpls_fib_dump) \ _(CLASSIFY_TABLE_IDS,classify_table_ids) \ _(CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface) \ _(CLASSIFY_TABLE_INFO,classify_table_info) \ diff --git a/vpp/vpp-api/test_client.c b/vpp/vpp-api/test_client.c index 8ca7a4b5651..d6192497268 100644 --- a/vpp/vpp-api/test_client.c +++ b/vpp/vpp-api/test_client.c @@ -225,26 +225,12 @@ vl_api_create_vlan_subif_reply_t_handler (vl_api_create_vlan_subif_reply_t * } static void - vl_api_mpls_gre_add_del_tunnel_reply_t_handler - (vl_api_mpls_gre_add_del_tunnel_reply_t * mp) -{ - fformat (stdout, "add_del mpls gre tunnel reply %d\n", ntohl (mp->retval)); -} - -static void vl_api_mpls_add_del_encap_reply_t_handler (vl_api_mpls_add_del_encap_reply_t * mp) { fformat (stdout, "add del mpls label reply %d\n", ntohl (mp->retval)); } -static void -vl_api_mpls_add_del_decap_reply_t_handler (vl_api_mpls_add_del_decap_reply_t * - mp) -{ - fformat (stdout, "add del mpls decap label reply %d\n", ntohl (mp->retval)); -} - static void vl_api_proxy_arp_add_del_reply_t_handler (vl_api_proxy_arp_add_del_reply_t * mp) { @@ -604,9 +590,7 @@ _(SW_INTERFACE_ADD_DEL_ADDRESS_REPLY, sw_interface_add_del_address_reply) \ _(SW_INTERFACE_SET_TABLE_REPLY, sw_interface_set_table_reply) \ _(TAP_CONNECT_REPLY, tap_connect_reply) \ _(CREATE_VLAN_SUBIF_REPLY, create_vlan_subif_reply) \ -_(MPLS_GRE_ADD_DEL_TUNNEL_REPLY, mpls_gre_add_del_tunnel_reply) \ _(MPLS_ADD_DEL_ENCAP_REPLY, mpls_add_del_encap_reply) \ -_(MPLS_ADD_DEL_DECAP_REPLY, mpls_add_del_decap_reply) \ _(PROXY_ARP_ADD_DEL_REPLY, proxy_arp_add_del_reply) \ _(PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY, proxy_arp_intfc_enable_disable_reply) \ _(IP_NEIGHBOR_ADD_DEL_REPLY, ip_neighbor_add_del_reply) \ @@ -751,7 +735,7 @@ add_del_ip4_route (test_main_t * tm, int enable_disable) mp->_vl_msg_id = ntohs (VL_API_IP_ADD_DEL_ROUTE); mp->client_index = tm->my_client_index; mp->context = 0xdeadbeef; - mp->vrf_id = ntohl (0); + mp->table_id = ntohl (0); mp->create_vrf_if_needed = 1; /* Arp, please, if needed */ mp->resolve_if_needed = 1; @@ -916,63 +900,6 @@ create_vlan_subif (test_main_t * tm, u32 vlan_id) } void -create_mpls_gre_tunnel (test_main_t * tm, u32 vrf_id, u32 label, u8 is_add) -{ - vl_api_mpls_add_del_encap_t *lp; - vl_api_mpls_add_del_decap_t *dlp; - vl_api_mpls_gre_add_del_tunnel_t *mp; - u32 tmp; - - dlp = vl_msg_api_alloc (sizeof (*dlp)); - memset (dlp, 0, sizeof (*dlp)); - dlp->_vl_msg_id = ntohs (VL_API_MPLS_ADD_DEL_DECAP); - dlp->client_index = tm->my_client_index; - dlp->context = 0xdeadbeef; - dlp->tx_vrf_id = ntohl (vrf_id); - dlp->label = ntohl (label); - dlp->s_bit = 1; - dlp->is_add = is_add; - vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & dlp); - - lp = vl_msg_api_alloc (sizeof (*lp) + sizeof (u32)); - memset (lp, 0, sizeof (*lp) + sizeof (u32)); - lp->_vl_msg_id = ntohs (VL_API_MPLS_ADD_DEL_ENCAP); - lp->client_index = tm->my_client_index; - lp->context = 0xdeadbeef; - lp->vrf_id = ntohl (vrf_id); - lp->labels[0] = ntohl (label); - lp->nlabels = 1; - lp->is_add = is_add; - /* dst: 5.0.0.1 */ - tmp = ntohl (0x05000001); - clib_memcpy (lp->dst_address, &tmp, 4); - - vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & lp); - - mp = vl_msg_api_alloc (sizeof (*mp)); - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_MPLS_GRE_ADD_DEL_TUNNEL); - mp->client_index = tm->my_client_index; - mp->context = 0xdeadbeef; - mp->inner_vrf_id = ntohl (vrf_id); - mp->outer_vrf_id = 0; - mp->is_add = is_add; - - /* src: 6.0.0.1 */ - tmp = ntohl (0x06000001); - clib_memcpy (mp->src_address, &tmp, 4); - /* dst: 5.0.0.1 */ - tmp = ntohl (0x05000001); - clib_memcpy (mp->dst_address, &tmp, 4); - /* intfc: 5.0.0.1/24 */ - tmp = ntohl (0x05000001); - clib_memcpy (mp->intfc_address, &tmp, 4); - mp->intfc_address_length = 24; - - vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & mp); -} - -void add_del_proxy_arp (test_main_t * tm, int is_add) { vl_api_proxy_arp_add_del_t *mp; @@ -1441,16 +1368,6 @@ main (int argc, char **argv) connect_unix_tap (tm, "foo"); break; - case 'M': - create_mpls_gre_tunnel (tm, 11 /* fib */ , 123 /* label */ , - 1 /* is_add */ ); - break; - - case 'm': - create_mpls_gre_tunnel (tm, 11 /* fib */ , 123 /* label */ , - 0 /* is_add */ ); - break; - case 'n': add_ip4_neighbor (tm, 1 /* is_add */ ); add_ip6_neighbor (tm, 1 /* is_add */ ); diff --git a/vpp/vpp-api/vpe.api b/vpp/vpp-api/vpe.api index 0fe9d200668..ac84bdc5cd5 100644 --- a/vpp/vpp-api/vpe.api +++ b/vpp/vpp-api/vpe.api @@ -367,6 +367,120 @@ define create_vlan_subif_reply u32 sw_if_index; }; +/** \brief MPLS Route Add / del route + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param mr_label - The MPLS label value + @param mr_eos - The End of stack bit + @param mr_table_id - The MPLS table-id the route is added in + @param mr_classify_table_index - If this is a classify route, + this is the classify table index + @param mr_create_table_if_needed - If the MPLS or IP tables do not exist, + create them + @param mr_is_add - Is this a route add or delete + @param mr_is_classify - Is this route result a classify + @param mr_is_multipath - Is this route update a multipath - i.e. is this + a path addition to an existing route + @param mr_is_resolve_host - Recurse resolution constraint via a host prefix + @param mr_is_resolve_attached - Recurse resolution constraint via attached prefix + @param mr_next_hop_proto_is_ip4 - The next-hop is IPV4 + @param mr_next_hop_weight - The weight, for UCMP + @param mr_next_hop[16] - the nextop address + @param mr_next_hop_sw_if_index - the next-hop SW interface + @param mr_next_hop_table_id - the next-hop table-id (if appropriate) + @param mr_next_hop_out_label - the next-hop output label +*/ +define mpls_route_add_del +{ + u32 client_index; + u32 context; + u32 mr_label; + u8 mr_eos; + u32 mr_table_id; + u32 mr_classify_table_index; + u8 mr_create_table_if_needed; + u8 mr_is_add; + u8 mr_is_classify; + u8 mr_is_multipath; + u8 mr_is_resolve_host; + u8 mr_is_resolve_attached; + u8 mr_next_hop_proto_is_ip4; + u8 mr_next_hop_weight; + u8 mr_next_hop[16]; + u32 mr_next_hop_sw_if_index; + u32 mr_next_hop_table_id; + u32 mr_next_hop_out_label; +}; + +/** \brief Reply for MPLS route add / del request + @param context - returned sender context, to match reply w/ request + @param retval - return code +*/ +define mpls_route_add_del_reply +{ + u32 context; + i32 retval; +}; + +/** \brief Dump MPLS fib table + @param client_index - opaque cookie to identify the sender +*/ +define mpls_fib_dump +{ + u32 client_index; + u32 context; +}; + +/** \brief mpls FIB table response + @param table_id - MPLS fib table id + @param s_bit - End-of-stack bit + @param label - MPLS label value +*/ +define mpls_fib_details +{ + u32 context; + u32 table_id; + u8 eos_bit; + u32 label; +}; + +/** \brief Bind/Unbind an MPLS local label to an IP prefix. i.e. create + a per-prefix label entry. + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param mb_mpls_table_id - The MPLS table-id the MPLS entry will be added in + @param mb_label - The MPLS label value to bind + @param mb_ip_table_id - The IP table-id of the IP prefix to bind to. + @param mb_create_table_if_needed - Create either/both tables if required. + @param mb_is_bind - Bind or unbind + @param mb_is_ip4 - The prefix to bind to is IPv4 + @param mb_address_length - Length of IP prefix + @param mb_address[16] - IP prefix/ +*/ +define mpls_ip_bind_unbind +{ + u32 client_index; + u32 context; + u32 mb_mpls_table_id; + u32 mb_label; + u32 mb_ip_table_id; + u8 mb_create_table_if_needed; + u8 mb_is_bind; + u8 mb_is_ip4; + u8 mb_address_length; + u8 mb_address[16]; +}; + +/** \brief Reply for MPLS IP bind/unbind request + @param context - returned sender context, to match reply w/ request + @param retval - return code +*/ +define mpls_ip_bind_unbind_reply +{ + u32 context; + i32 retval; +}; + /** \brief Add / del route request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -394,10 +508,11 @@ define ip_add_del_route u32 client_index; u32 context; u32 next_hop_sw_if_index; - u32 vrf_id; - u32 lookup_in_vrf; + u32 table_id; u32 resolve_attempts; u32 classify_table_index; + u32 next_hop_out_label; + u32 next_hop_table_id; u8 create_vrf_if_needed; u8 resolve_if_needed; u8 is_add; @@ -426,44 +541,6 @@ define ip_add_del_route_reply i32 retval; }; -/* works */ -/** \brief Add / del gre tunnel request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - software index of the new vlan's parent interface - @param inner_vrf_id - - @param outer_vrf_id - - @param is_add - 1 if adding the tunnel, 0 if deleting - @param src_address[4] - tunnel source address - @param dst_address[4] - tunnel destination address - @param intf_address - - @param intf_address_length - -*/ -define mpls_gre_add_del_tunnel -{ - u32 client_index; - u32 context; - u32 inner_vrf_id; - u32 outer_vrf_id; - u8 is_add; - u8 l2_only; - u8 src_address[4]; - u8 dst_address[4]; - u8 intfc_address[4]; - u8 intfc_address_length; -}; - -/** \brief Reply for add / del tunnel request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define mpls_gre_add_del_tunnel_reply -{ - u32 context; - i32 retval; - u32 tunnel_sw_if_index; -}; - /** \brief Add / del MPLS encapsulation request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -495,38 +572,6 @@ define mpls_add_del_encap_reply i32 retval; }; -/** \brief Add / del MPLS decapsulation request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param rx_vrf_id - receive vrf - @param tx_vrf_id - transmit vrf - @param label - - @param next_index - - @param s_bit - - @param is_add - 1 if adding the encap, 0 if deleting -*/ -define mpls_add_del_decap -{ - u32 client_index; - u32 context; - u32 rx_vrf_id; - u32 tx_vrf_id; - u32 label; - u32 next_index; - u8 s_bit; - u8 is_add; -}; - -/** \brief Reply for MPLS decap add / del request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define mpls_add_del_decap_reply -{ - u32 context; - i32 retval; -}; - /** \brief Proxy ARP add / del request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -4522,40 +4567,6 @@ define mpls_fib_encap_details u32 labels[nlabels]; }; -/** \brief Dump mpls fib decap table - @param client_index - opaque cookie to identify the sender - @param fib_index - mpls fib entry identifier or -1 in case of all entries -*/ -define mpls_fib_decap_dump -{ - u32 client_index; - u32 context; -}; - -/** \brief mpls fib decap table response - @param fib_index - fib table id - @param entry_index - reference to mpls label table - @param dest - destination ipv4 addr - @param s_bit - - @param label - mpls labels - @param rx_table_id - rx fib id - @param tx_table_id - tx fib id - @param swif_tag - -*/ -define mpls_fib_decap_details -{ - u32 context; - - u32 fib_index; - u32 entry_index; - u32 dest; - u32 s_bit; - u32 label; - u32 rx_table_id; - u32 tx_table_id; - u8 swif_tag[8]; -}; - /** \brief Classify get table IDs request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request |