From 1357f3b175b4d5b05fb25e9be356695fea9f7e35 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Sun, 16 Oct 2016 12:01:42 -0700 Subject: Deprecate MPLSoGRE tunnels (VPP-502) Add shared memory APIs for MPLS routes and MPLS to IP prefix bindings. Change-Id: I85b074a4dadc8249c410fdabd8ea019d20479cf8 Signed-off-by: Neale Ranns --- vnet/vnet/adj/adj_midchain.c | 3 - vnet/vnet/fib/fib_entry_src_mpls.c | 13 + vnet/vnet/fib/fib_node.h | 2 - vnet/vnet/fib/fib_table.c | 19 +- vnet/vnet/fib/fib_test.c | 51 +- vnet/vnet/mpls/interface.c | 943 ------------------------------------- vnet/vnet/mpls/mpls.c | 330 +------------ vnet/vnet/mpls/mpls.h | 96 +--- vnet/vnet/mpls/mpls_lookup.c | 6 +- vnet/vnet/mpls/mpls_output.c | 1 + vnet/vnet/mpls/node.c | 2 +- vnet/vnet/mpls/pg.c | 2 +- vnet/vnet/mpls/policy_encap.c | 1 + 13 files changed, 110 insertions(+), 1359 deletions(-) (limited to 'vnet') 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,248 +17,11 @@ #include #include -#include #include #include #include #include -/* 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 @@ -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 "); - - if (!dst_set) - return clib_error_return (0, "missing: dst "); - - if (!intfc_set) - return clib_error_return (0, "missing: intfc /"); - - - 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 dst intfc /", - .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 label [s-bit-clear] [next-index ]", - .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