summaryrefslogtreecommitdiffstats
path: root/vnet/vnet/mpls
diff options
context:
space:
mode:
Diffstat (limited to 'vnet/vnet/mpls')
-rw-r--r--vnet/vnet/mpls/interface.c992
-rw-r--r--vnet/vnet/mpls/mpls.c451
-rw-r--r--vnet/vnet/mpls/mpls.h78
-rw-r--r--vnet/vnet/mpls/mpls_lookup.c27
-rw-r--r--vnet/vnet/mpls/mpls_tunnel.c779
-rw-r--r--vnet/vnet/mpls/mpls_tunnel.h98
-rw-r--r--vnet/vnet/mpls/policy_encap.c181
7 files changed, 1033 insertions, 1573 deletions
diff --git a/vnet/vnet/mpls/interface.c b/vnet/vnet/mpls/interface.c
index a0f6f2f2474..692a2d1eb62 100644
--- a/vnet/vnet/mpls/interface.c
+++ b/vnet/vnet/mpls/interface.c
@@ -22,243 +22,6 @@
#include <vnet/adj/adj_midchain.h>
#include <vnet/dpo/classify_dpo.h>
-/* manually added to the interface output node */
-#define MPLS_ETH_OUTPUT_NEXT_OUTPUT 1
-
-static uword
-mpls_eth_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_eth_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->eth_tunnels, hi0->hw_instance);
- t1 = pool_elt_at_index (gm->eth_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->tx_sw_if_index;
- vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->tx_sw_if_index;
-
- /* mpls-post-rewrite takes it from here... */
- next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
- next1 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
-
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
- b0, sizeof (*tr));
- tr->lookup_miss = 0;
- tr->tunnel_id = t0 - gm->eth_tunnels;
- tr->tx_sw_if_index = t0->tx_sw_if_index;
- tr->mpls_encap_index = t0->encap_index;
- tr->length = b0->current_length;
- hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
- clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
- }
- if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
- {
- mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
- b1, sizeof (*tr));
- tr->lookup_miss = 0;
- tr->tunnel_id = t1 - gm->eth_tunnels;
- tr->tx_sw_if_index = t1->tx_sw_if_index;
- tr->mpls_encap_index = t1->encap_index;
- tr->length = b1->current_length;
- hi1 = vnet_get_sup_hw_interface (vnm, t1->tx_sw_if_index);
- clib_memcpy (tr->dst, hi1->hw_address, sizeof (tr->dst));
- }
-
- 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_eth_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->eth_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 interface */
- vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
-
- /* Send the packet */
- next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
-
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
- b0, sizeof (*tr));
- tr->lookup_miss = 0;
- tr->tunnel_id = t0 - gm->eth_tunnels;
- tr->tx_sw_if_index = t0->tx_sw_if_index;
- tr->mpls_encap_index = t0->encap_index;
- tr->length = b0->current_length;
- hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
- clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
- }
-
- 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, mpls_input_node.index,
- MPLS_ERROR_PKTS_ENCAP, frame->n_vectors);
-
- return frame->n_vectors;
-}
-
-static u8 * format_mpls_eth_tunnel_name (u8 * s, va_list * args)
-{
- u32 dev_instance = va_arg (*args, u32);
- return format (s, "mpls-eth%d", dev_instance);
-}
-
-static u8 * format_mpls_eth_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-ETH tunnel: id %d\n", dev_instance);
- return s;
-}
-
-VNET_DEVICE_CLASS (mpls_eth_device_class) = {
- .name = "MPLS-ETH tunnel device",
- .format_device_name = format_mpls_eth_tunnel_name,
- .format_device = format_mpls_eth_device,
- .format_tx_trace = format_mpls_eth_tx_trace,
- .tx_function = mpls_eth_interface_tx,
- .no_flatten_output_chains = 1,
-#ifdef SOON
- .clear counter = 0;
- .admin_up_down_function = 0;
-#endif
-};
-
-VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_eth_device_class,
- mpls_eth_interface_tx)
-
-VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = {
- .name = "MPLS-ETH",
- .format_header = format_mpls_eth_header_with_length,
-#if 0
- .unformat_header = unformat_mpls_eth_header,
-#endif
- .build_rewrite = default_build_rewrite,
- .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
-};
u8
mpls_sw_interface_is_enabled (u32 sw_if_index)
@@ -308,753 +71,6 @@ mpls_sw_interface_enable_disable (mpls_main_t * mm,
}
-u8 * format_mpls_encap_index (u8 * s, va_list * args)
-{
- mpls_main_t * mm = va_arg (*args, mpls_main_t *);
- u32 entry_index = va_arg (*args, u32);
- mpls_encap_t * e;
- int i;
-
- e = pool_elt_at_index (mm->encaps, entry_index);
-
- for (i = 0; i < vec_len (e->labels); i++)
- s = format
- (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
- (e->labels[i].label_exp_s_ttl)));
-
- return s;
-}
-
-u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
-{
- mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
- mpls_main_t * mm = &mpls_main;
-
- s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
- t - mm->eth_tunnels,
- format_ethernet_address, &t->tunnel_dst,
- format_ip4_address, &t->intfc_address,
- t->mask_width,
- format_mpls_encap_index, mm, t->encap_index);
-
-
- s = format (s, " tx on %U, rx fib index %d",
- format_vnet_sw_if_index_name, mm->vnet_main, t->tx_sw_if_index,
- t->inner_fib_index);
-
- return s;
-}
-
-static clib_error_t *
-show_mpls_tunnel_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- mpls_main_t * mm = &mpls_main;
- mpls_eth_tunnel_t * et;
-
- if (pool_elts (mm->eth_tunnels))
- {
- vlib_cli_output (vm, "MPLS-Ethernet tunnels");
- pool_foreach (et, mm->eth_tunnels,
- ({
- vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
- }));
- }
- else
- vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
-
- return 0;
-}
-
-VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
- .path = "show mpls tunnel",
- .short_help = "show mpls tunnel",
- .function = show_mpls_tunnel_command_fn,
-};
-
-
-/* force inclusion from application's main.c */
-clib_error_t *mpls_interface_init (vlib_main_t *vm)
-{
- clib_error_t * error;
-
- if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
- return error;
-
- return 0;
-}
-VLIB_INIT_FUNCTION(mpls_interface_init);
-
-
-static u8 * mpls_ethernet_rewrite (mpls_main_t *mm, mpls_eth_tunnel_t * t)
-{
- 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 and adjacency address*/
- e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index,
- t->intfc_address.as_u32);
-
- if (e == 0)
- {
- clib_warning ("no label for inner fib index %d, dst %U",
- t->inner_fib_index, format_ip4_address,
- &t->intfc_address);
- return 0;
- }
-
- vec_validate (rewrite_data,
- sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
-
- /* Copy the encap label stack */
- lp0 = (mpls_unicast_header_t *) rewrite_data;
-
- for (i = 0; i < vec_len(e->labels); i++)
- lp0[i] = e->labels[i];
-
- return (rewrite_data);
-}
-
-int vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
- ip4_address_t *intfc,
- u32 mask_width,
- u32 inner_fib_id,
- u32 tx_sw_if_index,
- u32 * tunnel_sw_if_index,
- u8 l2_only,
- u8 is_add)
-{
- ip4_main_t * im = &ip4_main;
- ip_lookup_main_t * lm = &im->lookup_main;
- mpls_main_t * mm = &mpls_main;
- vnet_main_t * vnm = vnet_get_main();
- mpls_eth_tunnel_t *tp;
- u32 inner_fib_index = 0;
- ip_adjacency_t adj;
- u32 adj_index;
- u8 * rewrite_data;
- int found_tunnel = 0;
- mpls_encap_t * e = 0;
- u32 hw_if_index = ~0;
- vnet_hw_interface_t * hi;
- u32 slot;
- u32 dummy;
-
- if (tunnel_sw_if_index == 0)
- 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_FIB;
- inner_fib_index = p[0];
- }
-
- /* suppress duplicate mpls interface generation. */
- pool_foreach (tp, mm->eth_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_dst, dst, sizeof (*dst))
- && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
- && tp->inner_fib_index == inner_fib_index
- && FIB_NODE_INDEX_INVALID != tp->fei)
- {
- found_tunnel = 1;
-
- if (is_add)
- {
- if (l2_only)
- return 1;
- else
- {
- e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
- intfc->as_u32);
- if (e == 0)
- return VNET_API_ERROR_NO_SUCH_LABEL;
-
- goto reinstall_it;
- }
- }
- else
- {
- /* Delete */
- goto add_del_route;
- }
-
- }
- }));
-
- /* Delete, and we can't find the tunnel */
- if (is_add == 0 && found_tunnel == 0)
- return VNET_API_ERROR_NO_SUCH_ENTRY;
-
- e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
- if (e == 0)
- return VNET_API_ERROR_NO_SUCH_LABEL;
-
- pool_get(mm->eth_tunnels, tp);
- memset (tp, 0, sizeof (*tp));
-
- if (vec_len (mm->free_eth_sw_if_indices) > 0)
- {
- hw_if_index =
- mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
- _vec_len (mm->free_eth_sw_if_indices) -= 1;
- hi = vnet_get_hw_interface (vnm, hw_if_index);
- hi->dev_instance = tp - mm->eth_tunnels;
- hi->hw_instance = tp - mm->eth_tunnels;
- }
- else
- {
- hw_if_index = vnet_register_interface
- (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
- mpls_eth_hw_interface_class.index,
- tp - mm->eth_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,
- "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
-
- ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
- }
-
- *tunnel_sw_if_index = hi->sw_if_index;
- vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
- VNET_SW_INTERFACE_FLAG_ADMIN_UP);
-
- tp->hw_if_index = hw_if_index;
-
- reinstall_it:
- clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
- tp->intfc_address.as_u32 = intfc->as_u32;
- tp->mask_width = mask_width;
- tp->inner_fib_index = inner_fib_index;
- tp->encap_index = e - mm->encaps;
- tp->tx_sw_if_index = tx_sw_if_index;
- tp->l2_only = l2_only;
-
- /* Create the adjacency and add to v4 fib */
- memset(&adj, 0, sizeof (adj));
- adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
-
- rewrite_data = mpls_ethernet_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_eth_sw_if_indices, tp->hw_if_index);
- }
-
- pool_put (mm->eth_tunnels, tp);
- return VNET_API_ERROR_NO_SUCH_LABEL;
- }
-
- vnet_rewrite_for_sw_interface
- (vnm,
- VNET_LINK_MPLS,
- tx_sw_if_index,
- ip4_rewrite_node.index,
- tp->tunnel_dst,
- &adj.rewrite_header,
- sizeof (adj.rewrite_data));
-
- /*
- * Prepend the (0,1,2) VLAN tag ethernet header
- * we just built to the mpls header stack
- */
- vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
- clib_memcpy(rewrite_data,
- vnet_rewrite_get_data_internal(&adj.rewrite_header,
- sizeof (adj.rewrite_data)),
- adj.rewrite_header.data_bytes);
-
- vnet_rewrite_set_data_internal (&adj.rewrite_header,
- sizeof(adj.rewrite_data),
- rewrite_data,
- vec_len(rewrite_data));
-
- vec_free (tp->rewrite_data);
-
- tp->rewrite_data = rewrite_data;
-
- if (!l2_only)
- ip_add_adjacency (lm, &adj, 1 /* one adj */,
- &adj_index);
-
- add_del_route:
-
- if (!l2_only)
- {
- const fib_prefix_t pfx = {
- .fp_addr = {
- .ip4 = tp->intfc_address,
- },
- .fp_len = tp->mask_width,
- .fp_proto = FIB_PROTOCOL_IP4,
- };
- if (is_add)
- tp->fei = fib_table_entry_special_add(tp->inner_fib_index,
- &pfx,
- FIB_SOURCE_API,
- FIB_ENTRY_FLAG_NONE,
- adj_index);
- else
- {
- fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
- tp->fei = FIB_NODE_INDEX_INVALID;
- }
- }
- if (is_add == 0 && found_tunnel)
- {
- 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_eth_sw_if_indices, tp->hw_if_index);
- vec_free (tp->rewrite_data);
- pool_put (mm->eth_tunnels, tp);
- }
-
- return 0;
-}
-
-static clib_error_t *
-create_mpls_ethernet_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;
- vnet_main_t * vnm = vnet_get_main();
- ip4_address_t intfc;
- int adj_set = 0;
- u8 dst[6];
- int dst_set = 0, intfc_set = 0;
- u32 mask_width;
- u32 inner_fib_id = (u32)~0;
- int rv;
- u8 is_del = 0;
- u8 l2_only = 0;
- u32 tx_sw_if_index;
- u32 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, "dst %U",
- unformat_ethernet_address, &dst))
- dst_set = 1;
- else if (unformat (line_input, "adj %U/%d",
- unformat_ip4_address, &intfc, &mask_width))
- adj_set = 1;
- else if (unformat (line_input, "tx-intfc %U",
- unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
- intfc_set = 1;
- else if (unformat (line_input, "fib-id %d", &inner_fib_id))
- ;
- else if (unformat (line_input, "l2-only"))
- l2_only = 1;
- else if (unformat (line_input, "del"))
- is_del = 1;
- else
- return clib_error_return (0, "unknown input '%U'",
- format_unformat_error, line_input);
- }
-
- if (!intfc_set)
- return clib_error_return (0, "missing tx-intfc");
-
- if (!dst_set)
- return clib_error_return (0, "missing: dst <ethernet-address>");
-
- if (!adj_set)
- return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
-
-
- rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
- inner_fib_id, tx_sw_if_index,
- &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(), sw_if_index);
- break;
- case VNET_API_ERROR_NO_SUCH_FIB:
- return clib_error_return (0, "rx fib ID %d doesn't exist\n",
- inner_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.
- */
- return clib_error_return (0, "no label for %U in fib %d",
- format_ip4_address, &intfc, inner_fib_id);
- break;
-
- default:
- return clib_error_return (0, "vnet_mpls_ethernet_add_del_tunnel returned %d", rv);
- break;
- }
- return 0;
-}
-
-
-VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
- .path = "create mpls ethernet tunnel",
- .short_help =
- "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
- .function = create_mpls_ethernet_tunnel_command_fn,
-};
-
-
-int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
- mpls_encap_t * e,
- u32 policy_tunnel_index)
-{
- mpls_eth_tunnel_t * t;
- ip_adjacency_t adj;
- u8 * rewrite_data = 0;
- u8 * label_start;
- mpls_unicast_header_t *lp;
- int i;
-
- if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
- return VNET_API_ERROR_NO_SUCH_ENTRY;
-
- t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
-
- memset (&adj, 0, sizeof (adj));
-
- /* Build L2 encap */
- vnet_rewrite_for_sw_interface
- (mm->vnet_main,
- VNET_LINK_MPLS,
- t->tx_sw_if_index,
- mpls_policy_encap_node.index,
- t->tunnel_dst,
- &adj.rewrite_header,
- sizeof (adj.rewrite_data));
-
- vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
-
- clib_memcpy(rewrite_data,
- vnet_rewrite_get_data_internal(&adj.rewrite_header,
- sizeof (adj.rewrite_data)),
- adj.rewrite_header.data_bytes);
-
- /* Append the label stack */
-
- vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
-
- lp = (mpls_unicast_header_t *) label_start;
-
- for (i = 0; i < vec_len(e->labels); i++)
- lp[i] = e->labels[i];
-
- /* Remember the rewrite data */
- e->rewrite = rewrite_data;
- e->output_next_index = adj.rewrite_header.next_index;
-
- return 0;
-}
-
-int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
- ip4_address_t *intfc,
- u32 mask_width,
- u32 inner_fib_id,
- u32 tx_sw_if_index,
- u32 * tunnel_sw_if_index,
- u32 classify_table_index,
- u32 * new_tunnel_index,
- u8 l2_only,
- u8 is_add)
-{
- ip4_main_t * im = &ip4_main;
- mpls_main_t * mm = &mpls_main;
- vnet_main_t * vnm = vnet_get_main();
- mpls_eth_tunnel_t *tp;
- u32 inner_fib_index = 0;
- int found_tunnel = 0;
- mpls_encap_t * e = 0;
- u32 hw_if_index = ~0;
- vnet_hw_interface_t * hi;
- u32 slot;
- u32 dummy;
-
- if (tunnel_sw_if_index == 0)
- 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_FIB;
- inner_fib_index = p[0];
- }
-
- /* suppress duplicate mpls interface generation. */
- pool_foreach (tp, mm->eth_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_dst, dst, sizeof (*dst))
- && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
- && tp->inner_fib_index == inner_fib_index
- && FIB_NODE_INDEX_INVALID != tp->fei)
- {
- found_tunnel = 1;
-
- if (is_add)
- {
- if (l2_only)
- return 1;
- else
- {
- goto reinstall_it;
- }
- }
- else
- {
- /* Delete */
- goto add_del_route;
- }
-
- }
- }));
-
- /* Delete, and we can't find the tunnel */
- if (is_add == 0 && found_tunnel == 0)
- return VNET_API_ERROR_NO_SUCH_ENTRY;
-
- pool_get(mm->eth_tunnels, tp);
- memset (tp, 0, sizeof (*tp));
-
- if (vec_len (mm->free_eth_sw_if_indices) > 0)
- {
- hw_if_index =
- mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
- _vec_len (mm->free_eth_sw_if_indices) -= 1;
- hi = vnet_get_hw_interface (vnm, hw_if_index);
- hi->dev_instance = tp - mm->eth_tunnels;
- hi->hw_instance = tp - mm->eth_tunnels;
- }
- else
- {
- hw_if_index = vnet_register_interface
- (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
- mpls_eth_hw_interface_class.index,
- tp - mm->eth_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,
- "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
-
- ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
- }
-
- *tunnel_sw_if_index = hi->sw_if_index;
- vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
- VNET_SW_INTERFACE_FLAG_ADMIN_UP);
-
- tp->hw_if_index = hw_if_index;
-
- reinstall_it:
- clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
- tp->intfc_address.as_u32 = intfc->as_u32;
- tp->mask_width = mask_width;
- tp->inner_fib_index = inner_fib_index;
- tp->encap_index = e - mm->encaps;
- tp->tx_sw_if_index = tx_sw_if_index;
- tp->l2_only = l2_only;
- tp->fei = FIB_NODE_INDEX_INVALID;
-
- if (new_tunnel_index)
- *new_tunnel_index = tp - mm->eth_tunnels;
-
- add_del_route:
-
- if (!l2_only)
- {
- const fib_prefix_t pfx = {
- .fp_addr = {
- .ip4 = tp->intfc_address,
- },
- .fp_len = tp->mask_width,
- .fp_proto = FIB_PROTOCOL_IP4,
- };
- dpo_id_t dpo = DPO_INVALID;
-
- if (is_add)
- {
- dpo_set(&dpo,
- DPO_CLASSIFY,
- DPO_PROTO_IP4,
- classify_dpo_create(DPO_PROTO_IP4,
- classify_table_index));
-
- tp->fei = fib_table_entry_special_dpo_add(tp->inner_fib_index,
- &pfx,
- FIB_SOURCE_API,
- FIB_ENTRY_FLAG_EXCLUSIVE,
- &dpo);
- dpo_reset(&dpo);
- }
- else
- {
- fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
- tp->fei = FIB_NODE_INDEX_INVALID;
- }
- }
- if (is_add == 0 && found_tunnel)
- {
- 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_eth_sw_if_indices, tp->hw_if_index);
- pool_put (mm->eth_tunnels, tp);
- }
-
- return 0;
-}
-
-static clib_error_t *
-create_mpls_ethernet_policy_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;
- vnet_main_t * vnm = vnet_get_main();
- ip4_address_t intfc;
- int adj_set = 0;
- u8 dst[6];
- int dst_set = 0, intfc_set = 0;
- u32 mask_width;
- u32 inner_fib_id = (u32)~0;
- u32 classify_table_index = (u32)~0;
- u32 new_tunnel_index;
- int rv;
- u8 is_del = 0;
- u8 l2_only = 0;
- u32 tx_sw_if_index;
-
- /* 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, "dst %U",
- unformat_ethernet_address, &dst))
- dst_set = 1;
- else if (unformat (line_input, "adj %U/%d",
- unformat_ip4_address, &intfc, &mask_width))
- adj_set = 1;
- else if (unformat (line_input, "tx-intfc %U",
- unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
- intfc_set = 1;
- else if (unformat (line_input, "classify-table-index %d",
- &classify_table_index))
- ;
- else if (unformat (line_input, "fib-id %d", &inner_fib_id))
- ;
- else if (unformat (line_input, "l2-only"))
- l2_only = 1;
- else if (unformat (line_input, "del"))
- is_del = 1;
- else
- return clib_error_return (0, "unknown input '%U'",
- format_unformat_error, line_input);
- }
-
- if (classify_table_index == ~0)
- return clib_error_return (0, "missing classify_table_index");
-
- if (!intfc_set)
- return clib_error_return (0, "missing tx-intfc");
-
- if (!dst_set)
- return clib_error_return (0, "missing: dst <ethernet-address>");
-
- if (!adj_set)
- return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
-
-
- rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
- inner_fib_id, tx_sw_if_index,
- 0 /* tunnel sw_if_index */,
- classify_table_index,
- &new_tunnel_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(), new_tunnel_index);
- break;
- case VNET_API_ERROR_NO_SUCH_FIB:
- return clib_error_return (0, "rx fib ID %d doesn't exist\n",
- inner_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.
- */
- return clib_error_return (0, "no label for %U in fib %d",
- format_ip4_address, &intfc, inner_fib_id);
- break;
-
- default:
- return clib_error_return (0, "vnet_mpls_ethernet_add_del_policy_tunnel returned %d", rv);
- break;
- }
-
- return 0;
-}
-
-VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
- .path = "create mpls ethernet policy tunnel",
- .short_help =
- "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
- " classify-table-index <nn>",
- .function = create_mpls_ethernet_policy_tunnel_command_fn,
-};
-
static clib_error_t *
mpls_interface_enable_disable (vlib_main_t * vm,
unformat_input_t * input,
@@ -1090,6 +106,14 @@ mpls_interface_enable_disable (vlib_main_t * vm,
return error;
}
+/*?
+ * This command enables an interface to accpet MPLS packets
+ *
+ * @cliexpar
+ * @cliexstart{set interface mpls}
+ * set interface mpls GigEthernet0/8/0 enable
+ * @cliexend
+ ?*/
VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
.path = "set interface mpls",
.function = mpls_interface_enable_disable,
diff --git a/vnet/vnet/mpls/mpls.c b/vnet/vnet/mpls/mpls.c
index aa1d963dca1..e6ae4980067 100644
--- a/vnet/vnet/mpls/mpls.c
+++ b/vnet/vnet/mpls/mpls.c
@@ -121,45 +121,6 @@ unformat_mpls_header (unformat_input_t * input, va_list * args)
return 1;
}
-u8 * format_mpls_eth_tx_trace (u8 * s, 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_eth_tx_trace_t * t = va_arg (*args, mpls_eth_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 tx_sw_index %d dst %U",
- t->tunnel_id,
- format_mpls_encap_index, mm, t->mpls_encap_index,
- clib_net_to_host_u16 (t->length),
- t->tx_sw_if_index,
- format_ethernet_address, t->dst);
- }
- return s;
-}
-
-u8 * format_mpls_eth_header_with_length (u8 * s, va_list * args)
-{
- ethernet_header_t * h = va_arg (*args, ethernet_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, "ethernet header truncated");
-
- s = format
- (s, "ETHERNET-MPLS label %d",
- vnet_mpls_uc_get_label (clib_net_to_host_u32 (m->label_exp_s_ttl)));
-
- return s;
-}
-
uword
unformat_mpls_label_net_byte_order (unformat_input_t * input,
va_list * args)
@@ -176,157 +137,6 @@ unformat_mpls_label_net_byte_order (unformat_input_t * input,
return 1;
}
-mpls_encap_t *
-mpls_encap_by_fib_and_dest (mpls_main_t * mm, u32 rx_fib, u32 dst_address)
-{
- uword * p;
- mpls_encap_t * e;
- u64 key;
-
- key = ((u64)rx_fib<<32) | ((u64) dst_address);
- p = hash_get (mm->mpls_encap_by_fib_and_dest, key);
-
- if (!p)
- return 0;
-
- e = pool_elt_at_index (mm->encaps, p[0]);
- return e;
-}
-
-int vnet_mpls_add_del_encap (ip4_address_t *dest, u32 fib_id,
- u32 *labels_host_byte_order,
- u32 policy_tunnel_index,
- int no_dst_hash, u32 * indexp, int is_add)
-{
- mpls_main_t * mm = &mpls_main;
- ip4_main_t * im = &ip4_main;
- mpls_encap_t * e;
- u32 label_net_byte_order, label_host_byte_order;
- u32 fib_index;
- u64 key;
- uword *p;
- int i;
-
- p = hash_get (im->fib_index_by_table_id, fib_id);
- if (! p)
- return VNET_API_ERROR_NO_SUCH_FIB;
-
- fib_index = p[0];
-
- key = ((u64)fib_index<<32) | ((u64) dest->as_u32);
-
- if (is_add)
- {
- pool_get (mm->encaps, e);
- memset (e, 0, sizeof (*e));
-
- for (i = 0; i < vec_len (labels_host_byte_order); i++)
- {
- mpls_unicast_header_t h;
- label_host_byte_order = labels_host_byte_order[i];
-
- /* Reformat label into mpls_unicast_header_t */
- label_host_byte_order <<= 12;
- // FIXME NEOS AND EOS
- //if (i == vec_len(labels_host_byte_order) - 1)
- // label_host_byte_order |= 1<<8; /* S=1 */
- label_host_byte_order |= 0xff; /* TTL=FF */
- label_net_byte_order = clib_host_to_net_u32 (label_host_byte_order);
- h.label_exp_s_ttl = label_net_byte_order;
- vec_add1 (e->labels, h);
- }
- if (no_dst_hash == 0)
- hash_set (mm->mpls_encap_by_fib_and_dest, key, e - mm->encaps);
- if (indexp)
- *indexp = e - mm->encaps;
- if (policy_tunnel_index != ~0)
- return vnet_mpls_policy_tunnel_add_rewrite (mm, e, policy_tunnel_index);
- }
- else
- {
- p = hash_get (mm->mpls_encap_by_fib_and_dest, key);
- if (!p)
- return VNET_API_ERROR_NO_SUCH_LABEL;
-
- e = pool_elt_at_index (mm->encaps, p[0]);
-
- vec_free (e->labels);
- vec_free (e->rewrite);
- pool_put(mm->encaps, e);
-
- if (no_dst_hash == 0)
- hash_unset (mm->mpls_encap_by_fib_and_dest, key);
- }
- return 0;
-}
-
-static clib_error_t *
-mpls_add_encap_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- u32 fib_id;
- u32 *labels = 0;
- u32 this_label;
- ip4_address_t dest;
- u32 policy_tunnel_index = ~0;
- int no_dst_hash = 0;
- int rv;
- int fib_set = 0;
- int dest_set = 0;
-
- while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (input, "fib %d", &fib_id))
- fib_set = 1;
- else if (unformat (input, "dest %U", unformat_ip4_address, &dest))
- dest_set = 1;
- else if (unformat (input, "no-dst-hash"))
- no_dst_hash = 1;
- else if (unformat (input, "label %d", &this_label))
- vec_add1 (labels, this_label);
- else if (unformat (input, "policy-tunnel %d", &policy_tunnel_index))
- ;
- else
- break;
- }
-
- if (fib_set == 0)
- return clib_error_return (0, "fib-id missing");
- if (dest_set == 0)
- return clib_error_return (0, "destination IP address missing");
- if (vec_len (labels) == 0)
- return clib_error_return (0, "label stack missing");
-
- rv = vnet_mpls_add_del_encap (&dest, fib_id, labels,
- policy_tunnel_index,
- no_dst_hash, 0 /* indexp */,
- 1 /* is_add */);
- vec_free (labels);
-
- switch (rv)
- {
- case 0:
- break;
-
- case VNET_API_ERROR_NO_SUCH_FIB:
- return clib_error_return (0, "fib id %d unknown", fib_id);
-
- default:
- return clib_error_return (0, "vnet_mpls_add_del_encap returned %d",
- rv);
- }
-
- return 0;
-}
-
-VLIB_CLI_COMMAND (mpls_add_encap_command, static) = {
- .path = "mpls encap add",
- .short_help =
- "mpls encap add label <label> ... fib <id> dest <ip4-address>",
- .function = mpls_add_encap_command_fn,
-};
-
u8 * format_mpls_unicast_header_host_byte_order (u8 * s, va_list * args)
{
mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
@@ -351,46 +161,6 @@ u8 * format_mpls_unicast_header_net_byte_order (u8 * s, va_list * args)
&h_host);
}
-static clib_error_t *
-mpls_del_encap_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- u32 fib_id;
- ip4_address_t dest;
- int rv;
-
- if (unformat (input, "fib %d dest %U", &fib_id,
- unformat_ip4_address, &dest))
- {
- rv = vnet_mpls_add_del_encap (&dest, fib_id, 0 /* labels */,
- ~0 /* policy_tunnel_index */,
- 0 /* no_dst_hash */,
- 0 /* indexp */,
- 0 /* is_add */);
- switch (rv)
- {
- case VNET_API_ERROR_NO_SUCH_FIB:
- return clib_error_return (0, "fib id %d unknown", fib_id);
- case VNET_API_ERROR_NO_SUCH_ENTRY:
- return clib_error_return (0, "dest %U not in fib %d",
- format_ip4_address, &dest, fib_id);
- default:
- break;
- }
- return 0;
- }
- else
- return clib_error_return (0, "unknown input `%U'",
- format_unformat_error, input);
-}
-
-VLIB_CLI_COMMAND (mpls_del_encap_command, static) = {
- .path = "mpls encap delete",
- .short_help = "mpls encap delete fib <id> dest <ip4-address>",
- .function = mpls_del_encap_command_fn,
-};
-
int
mpls_dest_cmp(void * a1, void * a2)
{
@@ -419,65 +189,22 @@ mpls_label_cmp(void * a1, void * a2)
}
static clib_error_t *
-show_mpls_fib_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- 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;
-
- hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest,
- ({
- vec_add2 (records, s, 1);
- s->fib_index = (u32)(key>>32);
- s->dest = (u32)(key & 0xFFFFFFFF);
- s->entry_index = (u32) value;
- }));
-
- if (!vec_len(records))
- {
- vlib_cli_output (vm, "MPLS encap table empty");
- }
- /* sort output by dst address within fib */
- vec_sort_with_function (records, mpls_dest_cmp);
- vec_sort_with_function (records, mpls_fib_index_cmp);
- vlib_cli_output (vm, "MPLS encap table");
- vlib_cli_output (vm, "%=6s%=16s%=16s", "Table", "Dest address", "Labels");
- vec_foreach (s, records)
- {
- rx_fib = ip4_fib_get (s->fib_index);
- vlib_cli_output (vm, "%=6d%=16U%=16U", rx_fib->table_id,
- format_ip4_address, &s->dest,
- format_mpls_encap_index, mm, s->entry_index);
- }
-
- vec_free(records);
- return 0;
-}
-
-VLIB_CLI_COMMAND (show_mpls_fib_command, static) = {
- .path = "show mpls encap",
- .short_help = "show mpls encap",
- .function = show_mpls_fib_command_fn,
-};
-
-static clib_error_t *
vnet_mpls_local_label (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, * line_input = &_line_input;
fib_route_path_t *rpaths = NULL, rpath;
- clib_error_t * error = 0;
u32 table_id, is_del, is_ip;
- fib_prefix_t pfx;
mpls_label_t local_label;
+ mpls_label_t out_label;
+ clib_error_t * error;
mpls_eos_bit_t eos;
+ vnet_main_t * vnm;
+ fib_prefix_t pfx;
+ vnm = vnet_get_main();
+ error = NULL;
is_ip = 0;
table_id = 0;
eos = MPLS_EOS;
@@ -519,13 +246,99 @@ vnet_mpls_local_label (vlib_main_t * vm,
pfx.fp_proto = FIB_PROTOCOL_IP6;
is_ip = 1;
}
+ else if (unformat (line_input, "via %U %U weight %u",
+ unformat_ip4_address,
+ &rpath.frp_addr.ip4,
+ unformat_vnet_sw_interface, vnm,
+ &rpath.frp_sw_if_index,
+ &rpath.frp_weight))
+ {
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ vec_add1(rpaths, rpath);
+ }
+
+ else if (unformat (line_input, "via %U %U weight %u",
+ unformat_ip6_address,
+ &rpath.frp_addr.ip6,
+ unformat_vnet_sw_interface, vnm,
+ &rpath.frp_sw_if_index,
+ &rpath.frp_weight))
+ {
+ rpath.frp_proto = FIB_PROTOCOL_IP6;
+ vec_add1(rpaths, rpath);
+ }
+
+ else if (unformat (line_input, "via %U %U",
+ unformat_ip4_address,
+ &rpath.frp_addr.ip4,
+ unformat_vnet_sw_interface, vnm,
+ &rpath.frp_sw_if_index))
+ {
+ rpath.frp_weight = 1;
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ vec_add1(rpaths, rpath);
+ }
+
+ else if (unformat (line_input, "via %U %U",
+ unformat_ip6_address,
+ &rpath.frp_addr.ip6,
+ unformat_vnet_sw_interface, vnm,
+ &rpath.frp_sw_if_index))
+ {
+ rpath.frp_weight = 1;
+ rpath.frp_proto = FIB_PROTOCOL_IP6;
+ vec_add1(rpaths, rpath);
+ }
+ else if (unformat (line_input, "via %U next-hop-table %d",
+ unformat_ip4_address,
+ &rpath.frp_addr.ip4,
+ &rpath.frp_fib_index))
+ {
+ rpath.frp_weight = 1;
+ rpath.frp_sw_if_index = ~0;
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ vec_add1(rpaths, rpath);
+ }
+ else if (unformat (line_input, "via %U next-hop-table %d",
+ unformat_ip6_address,
+ &rpath.frp_addr.ip6,
+ &rpath.frp_fib_index))
+ {
+ rpath.frp_weight = 1;
+ rpath.frp_sw_if_index = ~0;
+ rpath.frp_proto = FIB_PROTOCOL_IP6;
+ vec_add1(rpaths, rpath);
+ }
+ else if (unformat (line_input, "via %U",
+ unformat_ip4_address,
+ &rpath.frp_addr.ip4))
+ {
+ /*
+ * the recursive next-hops are by default in the same table
+ * as the prefix
+ */
+ rpath.frp_fib_index = table_id;
+ rpath.frp_weight = 1;
+ rpath.frp_sw_if_index = ~0;
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ vec_add1(rpaths, rpath);
+ }
+ else if (unformat (line_input, "via %U",
+ unformat_ip6_address,
+ &rpath.frp_addr.ip6))
+ {
+ rpath.frp_fib_index = table_id;
+ rpath.frp_weight = 1;
+ rpath.frp_sw_if_index = ~0;
+ rpath.frp_proto = FIB_PROTOCOL_IP6;
+ vec_add1(rpaths, rpath);
+ }
else if (unformat (line_input, "%d", &local_label))
;
else if (unformat (line_input,
"ip4-lookup-in-table %d",
&rpath.frp_fib_index))
{
- rpath.frp_label = MPLS_LABEL_INVALID;
rpath.frp_proto = FIB_PROTOCOL_IP4;
rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
pfx.fp_payload_proto = DPO_PROTO_IP4;
@@ -535,7 +348,6 @@ vnet_mpls_local_label (vlib_main_t * vm,
"ip6-lookup-in-table %d",
&rpath.frp_fib_index))
{
- rpath.frp_label = MPLS_LABEL_INVALID;
rpath.frp_proto = FIB_PROTOCOL_IP6;
rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
vec_add1(rpaths, rpath);
@@ -545,16 +357,26 @@ vnet_mpls_local_label (vlib_main_t * vm,
"mpls-lookup-in-table %d",
&rpath.frp_fib_index))
{
- rpath.frp_label = MPLS_LABEL_INVALID;
rpath.frp_proto = FIB_PROTOCOL_MPLS;
rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
pfx.fp_payload_proto = DPO_PROTO_MPLS;
vec_add1(rpaths, rpath);
}
+ else if (unformat (line_input, "out-label %U",
+ unformat_mpls_unicast_label,
+ &out_label))
+ {
+ if (vec_len(rpaths) == 0)
+ {
+ error = clib_error_return(0 , "Paths then labels");
+ goto done;
+ }
+ vec_add1(rpaths[vec_len(rpaths)-1].frp_label_stack, out_label);
+ }
else
{
error = clib_error_return (0, "unkown input: %U",
- format_unformat_error, input);
+ format_unformat_error, line_input);
goto done;
}
@@ -596,6 +418,7 @@ vnet_mpls_local_label (vlib_main_t * vm,
pfx.fp_proto = FIB_PROTOCOL_MPLS;
pfx.fp_len = 21;
pfx.fp_label = local_label;
+ pfx.fp_payload_proto = DPO_PROTO_MPLS;
if (NULL == rpaths)
{
@@ -606,17 +429,20 @@ vnet_mpls_local_label (vlib_main_t * vm,
/*
* the CLI parsing stored table Ids, swap to FIB indicies
*/
- fi = fib_table_id_find_fib_index(dpo_proto_to_fib(pfx.fp_payload_proto),
- rpaths[0].frp_fib_index);
-
- if (~0 == fi)
+ if (FIB_NODE_INDEX_INVALID == rpath.frp_sw_if_index)
{
- error = clib_error_return(0 , "%U Via table %d does not exist",
- format_fib_protocol, pfx.fp_payload_proto,
- rpaths[0].frp_fib_index);
- goto done;
+ fi = fib_table_id_find_fib_index(dpo_proto_to_fib(pfx.fp_payload_proto),
+ rpaths[0].frp_fib_index);
+
+ if (~0 == fi)
+ {
+ error = clib_error_return(0 , "%U Via table %d does not exist",
+ format_fib_protocol, pfx.fp_payload_proto,
+ rpaths[0].frp_fib_index);
+ goto done;
+ }
+ rpaths[0].frp_fib_index = fi;
}
- rpaths[0].frp_fib_index = fi;
fib_index = mpls_fib_index_from_table_id(table_id);
@@ -653,44 +479,15 @@ VLIB_CLI_COMMAND (mpls_local_label_command, static) = {
.short_help = "Create/Delete MPL local labels",
};
-int mpls_fib_reset_labels (u32 fib_id)
+int
+mpls_fib_reset_labels (u32 fib_id)
{
- u64 key;
- u32 value;
- show_mpls_fib_t *records = 0;
- show_mpls_fib_t *s;
- mpls_main_t * mm = &mpls_main;
- ip4_main_t * im = &ip4_main;
- u32 fib_index;
- uword *p;
-
- p = hash_get (im->fib_index_by_table_id, fib_id);
- if (! p)
- return VNET_API_ERROR_NO_SUCH_FIB;
-
- fib_index = p[0];
-
- hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest,
- ({
- if (fib_index == (u32)(key>>32)) {
- vec_add2 (records, s, 1);
- s->dest = (u32)(key & 0xFFFFFFFF);
- s->entry_index = (u32) value;
- }
- }));
-
- vec_foreach (s, records)
- {
- key = ((u64)fib_index<<32) | ((u64) s->dest);
- hash_unset (mm->mpls_encap_by_fib_and_dest, key);
- pool_put_index (mm->encaps, s->entry_index);
- }
-
- vec_free(records);
+ // FIXME
return 0;
}
-static clib_error_t * mpls_init (vlib_main_t * vm)
+static clib_error_t *
+mpls_init (vlib_main_t * vm)
{
mpls_main_t * mm = &mpls_main;
clib_error_t * error;
@@ -701,8 +498,6 @@ static clib_error_t * mpls_init (vlib_main_t * vm)
if ((error = vlib_call_init_function (vm, ip_main_init)))
return error;
- mm->mpls_encap_by_fib_and_dest = 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 59fc761ea2c..b6fdbce7d70 100644
--- a/vnet/vnet/mpls/mpls.h
+++ b/vnet/vnet/mpls/mpls.h
@@ -30,30 +30,6 @@ typedef enum {
MPLS_N_ERROR,
} mpls_error_t;
-/*
- * No protocol info, MPLS labels don't have a next-header field
- * presumably the label field tells all...
- */
-typedef struct {
- u8 tunnel_dst[6];
- ip4_address_t intfc_address;
- u32 tx_sw_if_index;
- u32 inner_fib_index;
- u32 mask_width;
- u32 encap_index;
- u32 hw_if_index;
- u8 * rewrite_data;
- u8 l2_only;
- fib_node_index_t fei;
-} mpls_eth_tunnel_t;
-
-typedef struct {
- mpls_unicast_header_t *labels;
- /* only for policy tunnels */
- u8 * rewrite;
- u32 output_next_index;
-} mpls_encap_t;
-
#define MPLS_FIB_DEFAULT_TABLE_ID 0
/**
@@ -94,18 +70,6 @@ typedef struct {
/** A hash table to lookup the mpls_fib by table ID */
uword *fib_index_by_table_id;
- /* pool of ethernet tunnel instances */
- mpls_eth_tunnel_t *eth_tunnels;
- u32 * free_eth_sw_if_indices;
-
- /* Encap side: map (fib, dst_address) to mpls label stack */
- mpls_encap_t * encaps;
- uword * mpls_encap_by_fib_and_dest;
-
- /* 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;
-
/* Feature arc indices */
u8 input_feature_arc_index;
u8 output_feature_arc_index;
@@ -123,7 +87,6 @@ extern mpls_main_t mpls_main;
extern clib_error_t * mpls_feature_init(vlib_main_t * vm);
format_function_t format_mpls_protocol;
-format_function_t format_mpls_eth_header_with_length;
format_function_t format_mpls_encap_index;
format_function_t format_mpls_eos_bit;
@@ -153,29 +116,8 @@ void mpls_sw_interface_enable_disable (mpls_main_t * mm,
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 vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
- ip4_address_t *intfc,
- u32 mask_width,
- u32 inner_fib_id,
- u32 tx_sw_if_index,
- u32 * tunnel_sw_if_index,
- u8 l2_only,
- u8 is_add);
-
int mpls_fib_reset_labels (u32 fib_id);
-int vnet_mpls_add_del_encap (ip4_address_t *dest, u32 fib_id,
- u32 *labels_host_byte_order,
- u32 policy_tunnel_index,
- int no_dst_hash, u32 * indexp, int is_add);
-
-int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
- mpls_encap_t * e,
- u32 policy_tunnel_index);
-
#define foreach_mpls_input_next \
_(DROP, "error-drop") \
_(LOOKUP, "mpls-lookup")
@@ -211,26 +153,6 @@ typedef enum {
} mpls_output_next_t;
typedef struct {
- u32 lookup_miss;
-
- /* Tunnel-id / index in tunnel vector */
- u32 tunnel_id;
-
- /* output interface */
- u32 tx_sw_if_index;
-
- /* mpls encap index */
- u32 mpls_encap_index;
-
- /* pkt length */
- u32 length;
-
- u8 dst[6];
-} mpls_eth_tx_trace_t;
-
-u8 * format_mpls_eth_tx_trace (u8 * s, va_list * args);
-
-typedef struct {
u32 fib_index;
u32 entry_index;
u32 dest;
diff --git a/vnet/vnet/mpls/mpls_lookup.c b/vnet/vnet/mpls/mpls_lookup.c
index 34ba79e40fd..2d34cbde341 100644
--- a/vnet/vnet/mpls/mpls_lookup.c
+++ b/vnet/vnet/mpls/mpls_lookup.c
@@ -170,6 +170,19 @@ mpls_lookup (vlib_main_t * vm,
vlib_buffer_length_in_chain (vm, b1));
/*
+ * before we pop the label copy th values we need to maintain.
+ * The label header is in network byte order.
+ * last byte is the TTL.
+ * bits 2 to 4 inclusive are the EXP bits
+ */
+ vnet_buffer (b0)->mpls.ttl = ((char*)h0)[3];
+ vnet_buffer (b0)->mpls.exp = (((char*)h0)[2] & 0xe) >> 1;
+ vnet_buffer (b0)->mpls.first = 1;
+ vnet_buffer (b1)->mpls.ttl = ((char*)h1)[3];
+ vnet_buffer (b1)->mpls.exp = (((char*)h1)[2] & 0xe) >> 1;
+ vnet_buffer (b1)->mpls.first = 1;
+
+ /*
* pop the label that was just used in the lookup
*/
vlib_buffer_advance(b0, sizeof(*h0));
@@ -223,8 +236,8 @@ mpls_lookup (vlib_main_t * vm,
lfib_index0 = vec_elt(mm->fib_index_by_sw_if_index,
vnet_buffer(b0)->sw_if_index[VLIB_RX]);
- lbi0 = mpls_fib_table_forwarding_lookup (lfib_index0, h0);
- lb0 = load_balance_get(lbi0);
+ lbi0 = mpls_fib_table_forwarding_lookup(lfib_index0, h0);
+ lb0 = load_balance_get(lbi0);
hash_c0 = vnet_buffer(b0)->ip.flow_hash = 0;
if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
@@ -248,6 +261,16 @@ mpls_lookup (vlib_main_t * vm,
vlib_buffer_length_in_chain (vm, b0));
/*
+ * before we pop the label copy th values we need to maintain.
+ * The label header is in network byte order.
+ * last byte is the TTL.
+ * bits 2 to 4 inclusive are the EXP bits
+ */
+ vnet_buffer (b0)->mpls.ttl = ((char*)h0)[3];
+ vnet_buffer (b0)->mpls.exp = (((char*)h0)[2] & 0xe) >> 1;
+ vnet_buffer (b0)->mpls.first = 1;
+
+ /*
* pop the label that was just used in the lookup
*/
vlib_buffer_advance(b0, sizeof(*h0));
diff --git a/vnet/vnet/mpls/mpls_tunnel.c b/vnet/vnet/mpls/mpls_tunnel.c
new file mode 100644
index 00000000000..656bf330b1a
--- /dev/null
+++ b/vnet/vnet/mpls/mpls_tunnel.c
@@ -0,0 +1,779 @@
+/*
+ * mpls_tunnel.c: MPLS tunnel interfaces (i.e. for RSVP-TE)
+ *
+ * Copyright (c) 2012 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vnet/mpls/mpls_tunnel.h>
+#include <vnet/ip/ip.h>
+#include <vnet/fib/fib_path_list.h>
+#include <vnet/adj/adj_midchain.h>
+
+/**
+ * @brief pool of tunnel instances
+ */
+static mpls_tunnel_t *mpls_tunnel_pool;
+
+/**
+ * @brief Pool of free tunnel SW indices - i.e. recycled indices
+ */
+static u32 * mpls_tunnel_free_hw_if_indices;
+
+/**
+ * @brief DB of SW index to tunnel index
+ */
+static u32 *mpls_tunnel_db;
+
+/**
+ * @brief Get a tunnel object from a SW interface index
+ */
+static mpls_tunnel_t*
+mpls_tunnel_get_from_sw_if_index (u32 sw_if_index)
+{
+ if ((vec_len(mpls_tunnel_db) < sw_if_index) ||
+ (~0 == mpls_tunnel_db[sw_if_index]))
+ return (NULL);
+
+ return (pool_elt_at_index(mpls_tunnel_pool,
+ mpls_tunnel_db[sw_if_index]));
+}
+
+/**
+ * @brief Return true if the label stack is imp-null only
+ */
+static fib_forward_chain_type_t
+mpls_tunnel_get_fwd_chain_type (const mpls_tunnel_t *mt)
+{
+ if ((1 == vec_len(mt->mt_label_stack)) &&
+ (mt->mt_label_stack[0] == MPLS_IETF_IMPLICIT_NULL_LABEL))
+ {
+ /*
+ * the only label in the label stack is implicit null
+ * we need to build an IP chain.
+ */
+ if (FIB_PROTOCOL_IP4 == fib_path_list_get_proto(mt->mt_path_list))
+ {
+ return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
+ }
+ else
+ {
+ return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
+ }
+ }
+ else
+ {
+ return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
+ }
+}
+
+/**
+ * @brief Build a rewrite string for the MPLS tunnel.
+ *
+ * We have choices here;
+ * 1 - have an Adjacency with a zero length string and stack it on
+ * MPLS label objects
+ * 2 - put the label header rewrites in the adjacency string.
+ *
+ * We choose 2 since it results in fewer graph nodes in the egress path
+ */
+static u8*
+mpls_tunnel_build_rewrite (vnet_main_t * vnm,
+ u32 sw_if_index,
+ vnet_link_t link_type,
+ const void *dst_address)
+{
+ mpls_unicast_header_t *muh;
+ mpls_tunnel_t *mt;
+ u8 *rewrite;
+ u32 mti, ii;
+
+ rewrite = NULL;
+ mti = mpls_tunnel_db[sw_if_index];
+ mt = pool_elt_at_index(mpls_tunnel_pool, mti);
+
+ vec_validate(rewrite, (sizeof(*muh) * vec_len(mt->mt_label_stack)) - 1);
+ muh = (mpls_unicast_header_t *)rewrite;
+
+ /*
+ * The last (inner most) label in the stack may be EOS, all the rest Non-EOS
+ */
+ for (ii = 0; ii < vec_len(mt->mt_label_stack)-1; ii++)
+ {
+ vnet_mpls_uc_set_label(&muh[ii].label_exp_s_ttl, mt->mt_label_stack[ii]);
+ vnet_mpls_uc_set_ttl(&muh[ii].label_exp_s_ttl, 255);
+ vnet_mpls_uc_set_exp(&muh[ii].label_exp_s_ttl, 0);
+ vnet_mpls_uc_set_s(&muh[ii].label_exp_s_ttl, MPLS_NON_EOS);
+ muh[ii].label_exp_s_ttl = clib_host_to_net_u32(muh[ii].label_exp_s_ttl);
+ }
+
+ vnet_mpls_uc_set_label(&muh[ii].label_exp_s_ttl, mt->mt_label_stack[ii]);
+ vnet_mpls_uc_set_ttl(&muh[ii].label_exp_s_ttl, 255);
+ vnet_mpls_uc_set_exp(&muh[ii].label_exp_s_ttl, 0);
+
+ if (VNET_LINK_MPLS == link_type &&
+ mt->mt_label_stack[ii] != MPLS_IETF_IMPLICIT_NULL_LABEL)
+ vnet_mpls_uc_set_s(&muh[ii].label_exp_s_ttl, MPLS_NON_EOS);
+ else
+ vnet_mpls_uc_set_s(&muh[ii].label_exp_s_ttl, MPLS_EOS);
+
+ muh[ii].label_exp_s_ttl = clib_host_to_net_u32(muh[ii].label_exp_s_ttl);
+
+ return ((u8*)muh);
+}
+
+/**
+ * mpls_tunnel_stack
+ *
+ * 'stack' (resolve the recursion for) the tunnel's midchain adjacency
+ */
+static void
+mpls_tunnel_stack (adj_index_t ai)
+{
+ ip_adjacency_t *adj;
+ mpls_tunnel_t *mt;
+ u32 sw_if_index;
+
+ adj = adj_get(ai);
+ sw_if_index = adj->rewrite_header.sw_if_index;
+
+ mt = mpls_tunnel_get_from_sw_if_index(sw_if_index);
+
+ if (NULL == mt)
+ return;
+
+ /*
+ * find the adjacency that is contributed by the FIB path-list
+ * that this tunnel resovles via, and use it as the next adj
+ * in the midchain
+ */
+ if (vnet_hw_interface_get_flags(vnet_get_main(),
+ mt->mt_hw_if_index) &
+ VNET_HW_INTERFACE_FLAG_LINK_UP)
+ {
+ dpo_id_t dpo = DPO_INVALID;
+
+ fib_path_list_contribute_forwarding(mt->mt_path_list,
+ mpls_tunnel_get_fwd_chain_type(mt),
+ &dpo);
+
+ if (DPO_LOAD_BALANCE == dpo.dpoi_type)
+ {
+ /*
+ * we don't support multiple paths, so no need to load-balance.
+ * pull the first and only choice and stack directly on that.
+ */
+ load_balance_t *lb;
+
+ lb = load_balance_get (dpo.dpoi_index);
+
+ ASSERT(1 == lb->lb_n_buckets);
+
+ dpo_copy(&dpo, load_balance_get_bucket_i (lb, 0));
+ }
+
+ adj_nbr_midchain_stack(ai, &dpo);
+ dpo_reset(&dpo);
+ }
+ else
+ {
+ adj_nbr_midchain_unstack(ai);
+ }
+}
+
+/**
+ * @brief Call back when restacking all adjacencies on a MPLS interface
+ */
+static adj_walk_rc_t
+mpls_adj_walk_cb (adj_index_t ai,
+ void *ctx)
+{
+ mpls_tunnel_stack(ai);
+
+ return (ADJ_WALK_RC_CONTINUE);
+}
+
+static void
+mpls_tunnel_restack (mpls_tunnel_t *mt)
+{
+ fib_protocol_t proto;
+
+ /*
+ * walk all the adjacencies on the MPLS interface and restack them
+ */
+ FOR_EACH_FIB_PROTOCOL(proto)
+ {
+ adj_nbr_walk(mt->mt_sw_if_index,
+ proto,
+ mpls_adj_walk_cb,
+ NULL);
+ }
+}
+
+static clib_error_t *
+mpls_tunnel_admin_up_down (vnet_main_t * vnm,
+ u32 hw_if_index,
+ u32 flags)
+{
+ vnet_hw_interface_t * hi;
+ mpls_tunnel_t *mt;
+
+ hi = vnet_get_hw_interface (vnm, hw_if_index);
+
+ mt = mpls_tunnel_get_from_sw_if_index(hi->sw_if_index);
+
+ if (NULL == mt)
+ return (NULL);
+
+ if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
+ vnet_hw_interface_set_flags (vnm, hw_if_index,
+ VNET_HW_INTERFACE_FLAG_LINK_UP);
+ else
+ vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */);
+
+ mpls_tunnel_restack(mt);
+
+ return (NULL);
+}
+
+/**
+ * @brief Fixup the adj rewrite post encap. This is a no-op since the
+ * rewrite is a stack of labels.
+ */
+static void
+mpls_tunnel_fixup (vlib_main_t *vm,
+ ip_adjacency_t *adj,
+ vlib_buffer_t *b0)
+{
+}
+
+static void
+mpls_tunnel_update_adj (vnet_main_t * vnm,
+ u32 sw_if_index,
+ adj_index_t ai)
+{
+ adj_nbr_midchain_update_rewrite(
+ ai, mpls_tunnel_fixup,
+ ADJ_MIDCHAIN_FLAG_NONE,
+ mpls_tunnel_build_rewrite(vnm, sw_if_index,
+ adj_get_link_type(ai),
+ NULL));
+
+ mpls_tunnel_stack(ai);
+}
+
+static u8 *
+format_mpls_tunnel_name (u8 * s, va_list * args)
+{
+ u32 dev_instance = va_arg (*args, u32);
+ return format (s, "mpls-tunnel%d", dev_instance);
+}
+
+static u8 *
+format_mpls_tunnel_device (u8 * s, va_list * args)
+{
+ u32 dev_instance = va_arg (*args, u32);
+ CLIB_UNUSED (int verbose) = va_arg (*args, int);
+
+ return (format (s, "MPLS-tunnel: id %d\n", dev_instance));
+}
+
+/**
+ * @brief Packet trace structure
+ */
+typedef struct mpls_tunnel_trace_t_
+{
+ /**
+ * Tunnel-id / index in tunnel vector
+ */
+ u32 tunnel_id;
+} mpls_tunnel_trace_t;
+
+static u8 *
+format_mpls_tunnel_tx_trace (u8 * s,
+ 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_tunnel_trace_t * t = va_arg (*args, mpls_tunnel_trace_t *);
+
+ s = format (s, "MPLS: tunnel %d", t->tunnel_id);
+ return s;
+}
+
+/**
+ * @brief TX function. Only called L2. L3 traffic uses the adj-midchains
+ */
+static uword
+mpls_tunnel_tx (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ u32 next_index;
+ u32 * from, * to_next, n_left_from, n_left_to_next;
+ vnet_interface_output_runtime_t * rd = (void *) node->runtime_data;
+ const mpls_tunnel_t *mt;
+
+ mt = pool_elt_at_index(mpls_tunnel_pool, rd->dev_instance);
+
+ /* 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);
+
+ /*
+ * FIXME DUAL LOOP
+ */
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ vlib_buffer_t * b0;
+ u32 bi0;
+
+ 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);
+
+ vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mt->mt_l2_adj;
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ mpls_tunnel_trace_t *tr = vlib_add_trace (vm, node,
+ b0, sizeof (*tr));
+ tr->tunnel_id = rd->dev_instance;
+ }
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, mt->mt_l2_tx_arc);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ return frame->n_vectors;
+}
+
+VNET_DEVICE_CLASS (mpls_tunnel_class) = {
+ .name = "MPLS tunnel device",
+ .format_device_name = format_mpls_tunnel_name,
+ .format_device = format_mpls_tunnel_device,
+ .format_tx_trace = format_mpls_tunnel_tx_trace,
+ .tx_function = mpls_tunnel_tx,
+ .no_flatten_output_chains = 1,
+ .admin_up_down_function = mpls_tunnel_admin_up_down,
+};
+
+VNET_HW_INTERFACE_CLASS (mpls_tunnel_hw_interface_class) = {
+ .name = "MPLS-Tunnel",
+// .format_header = format_mpls_eth_header_with_length,
+// .unformat_header = unformat_mpls_eth_header,
+ .update_adjacency = mpls_tunnel_update_adj,
+ .build_rewrite = mpls_tunnel_build_rewrite,
+ .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
+};
+
+const mpls_tunnel_t *
+mpls_tunnel_get (u32 mti)
+{
+ return (pool_elt_at_index(mpls_tunnel_pool, mti));
+}
+
+/**
+ * @brief Walk all the MPLS tunnels
+ */
+void
+mpls_tunnel_walk (mpls_tunnel_walk_cb_t cb,
+ void *ctx)
+{
+ u32 mti;
+
+ pool_foreach_index(mti, mpls_tunnel_pool,
+ ({
+ cb(mti, ctx);
+ }));
+}
+
+void
+vnet_mpls_tunnel_del (u32 sw_if_index)
+{
+ mpls_tunnel_t *mt;
+
+ mt = mpls_tunnel_get_from_sw_if_index(sw_if_index);
+
+ if (NULL == mt)
+ return;
+
+ fib_path_list_child_remove(mt->mt_path_list,
+ mt->mt_sibling_index);
+ if (ADJ_INDEX_INVALID != mt->mt_l2_adj)
+ adj_unlock(mt->mt_l2_adj);
+
+ vec_free(mt->mt_label_stack);
+
+ vec_add1 (mpls_tunnel_free_hw_if_indices, mt->mt_hw_if_index);
+ pool_put(mpls_tunnel_pool, mt);
+ mpls_tunnel_db[sw_if_index] = ~0;
+}
+
+void
+vnet_mpls_tunnel_add (fib_route_path_t *rpaths,
+ mpls_label_t *label_stack,
+ u8 l2_only,
+ u32 *sw_if_index)
+{
+ vnet_hw_interface_t * hi;
+ mpls_tunnel_t *mt;
+ vnet_main_t * vnm;
+ u32 mti;
+
+ vnm = vnet_get_main();
+ pool_get(mpls_tunnel_pool, mt);
+ memset (mt, 0, sizeof (*mt));
+ mti = mt - mpls_tunnel_pool;
+ fib_node_init(&mt->mt_node, FIB_NODE_TYPE_MPLS_TUNNEL);
+ mt->mt_l2_adj = ADJ_INDEX_INVALID;
+
+ /*
+ * Create a new, or re=use and old, tunnel HW interface
+ */
+ if (vec_len (mpls_tunnel_free_hw_if_indices) > 0)
+ {
+ mt->mt_hw_if_index =
+ mpls_tunnel_free_hw_if_indices[vec_len(mpls_tunnel_free_hw_if_indices)-1];
+ _vec_len (mpls_tunnel_free_hw_if_indices) -= 1;
+ hi = vnet_get_hw_interface (vnm, mt->mt_hw_if_index);
+ hi->hw_instance = mti;
+ hi->dev_instance = mti;
+ }
+ else
+ {
+ mt->mt_hw_if_index = vnet_register_interface(
+ vnm,
+ mpls_tunnel_class.index,
+ mti,
+ mpls_tunnel_hw_interface_class.index,
+ mti);
+ hi = vnet_get_hw_interface(vnm, mt->mt_hw_if_index);
+ }
+
+ /*
+ * Add the new tunnel to the tunnel DB - key:SW if index
+ */
+ mt->mt_sw_if_index = hi->sw_if_index;
+ vec_validate_init_empty(mpls_tunnel_db, mt->mt_sw_if_index, ~0);
+ mpls_tunnel_db[mt->mt_sw_if_index] = mti;
+
+ /*
+ * construct a path-list from the path provided
+ */
+ mt->mt_path_list = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, rpaths);
+ mt->mt_sibling_index = fib_path_list_child_add(mt->mt_path_list,
+ FIB_NODE_TYPE_MPLS_TUNNEL,
+ mti);
+
+ mt->mt_label_stack = vec_dup(label_stack);
+
+ if (l2_only)
+ {
+ mt->mt_l2_adj =
+ adj_nbr_add_or_lock(fib_path_list_get_proto(mt->mt_path_list),
+ VNET_LINK_ETHERNET,
+ &zero_addr,
+ mt->mt_sw_if_index);
+
+ mt->mt_l2_tx_arc = vlib_node_add_named_next(vlib_get_main(),
+ hi->tx_node_index,
+ "adj-l2-midchain");
+ }
+
+ *sw_if_index = mt->mt_sw_if_index;
+}
+
+static clib_error_t *
+vnet_create_mpls_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;
+ vnet_main_t * vnm = vnet_get_main();
+ u8 is_del = 0;
+ u8 l2_only = 0;
+ fib_route_path_t rpath, *rpaths = NULL;
+ mpls_label_t out_label = MPLS_LABEL_INVALID, *labels = NULL;
+ u32 sw_if_index;
+
+ memset(&rpath, 0, sizeof(rpath));
+
+ /* 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, "del %U",
+ unformat_vnet_sw_interface, vnm,
+ &sw_if_index))
+ is_del = 1;
+ else if (unformat (line_input, "add"))
+ is_del = 0;
+ else if (unformat (line_input, "out-label %U",
+ unformat_mpls_unicast_label, &out_label))
+ {
+ vec_add1(labels, out_label);
+ }
+ else if (unformat (line_input, "via %U %U",
+ unformat_ip4_address,
+ &rpath.frp_addr.ip4,
+ unformat_vnet_sw_interface, vnm,
+ &rpath.frp_sw_if_index))
+ {
+ rpath.frp_weight = 1;
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ }
+
+ else if (unformat (line_input, "via %U %U",
+ unformat_ip6_address,
+ &rpath.frp_addr.ip6,
+ unformat_vnet_sw_interface, vnm,
+ &rpath.frp_sw_if_index))
+ {
+ rpath.frp_weight = 1;
+ rpath.frp_proto = FIB_PROTOCOL_IP6;
+ }
+ else if (unformat (line_input, "via %U",
+ unformat_ip6_address,
+ &rpath.frp_addr.ip6))
+ {
+ rpath.frp_fib_index = 0;
+ rpath.frp_weight = 1;
+ rpath.frp_sw_if_index = ~0;
+ rpath.frp_proto = FIB_PROTOCOL_IP6;
+ }
+ else if (unformat (line_input, "via %U",
+ unformat_ip4_address,
+ &rpath.frp_addr.ip4))
+ {
+ rpath.frp_fib_index = 0;
+ rpath.frp_weight = 1;
+ rpath.frp_sw_if_index = ~0;
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ }
+ 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 (is_del)
+ {
+ vnet_mpls_tunnel_del(sw_if_index);
+ }
+ else
+ {
+ if (0 == vec_len(labels))
+ return clib_error_return (0, "No Output Labels '%U'",
+ format_unformat_error, line_input);
+
+ vec_add1(rpaths, rpath);
+ vnet_mpls_tunnel_add(rpaths, labels, l2_only, &sw_if_index);
+ }
+
+ vec_free(labels);
+ vec_free(rpaths);
+
+ return (NULL);
+}
+
+/*?
+ * This command create a uni-directional MPLS tunnel
+ *
+ * @cliexpar
+ * @cliexstart{create mpls tunnel}
+ * create mpls tunnel via 10.0.0.1 GigEthernet0/8/0 out-label 33 out-label 34
+ * @cliexend
+ ?*/
+VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
+ .path = "mpls tunnel",
+ .short_help =
+ "mpls tunnel via [addr] [interface] [out-labels]",
+ .function = vnet_create_mpls_tunnel_command_fn,
+};
+
+static u8 *
+format_mpls_tunnel (u8 * s, va_list * args)
+{
+ mpls_tunnel_t *mt = va_arg (*args, mpls_tunnel_t *);
+ int ii;
+
+ s = format(s, "mpls_tunnel%d: sw_if_index:%d hw_if_index:%d",
+ mt - mpls_tunnel_pool,
+ mt->mt_sw_if_index,
+ mt->mt_hw_if_index);
+ s = format(s, "\n label-stack:\n ");
+ for (ii = 0; ii < vec_len(mt->mt_label_stack); ii++)
+ {
+ s = format(s, "%d, ", mt->mt_label_stack[ii]);
+ }
+ s = format(s, "\n via:\n");
+ s = fib_path_list_format(mt->mt_path_list, s);
+ s = format(s, "\n");
+
+ return (s);
+}
+
+static clib_error_t *
+show_mpls_tunnel_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ mpls_tunnel_t * mt;
+ u32 mti = ~0;
+
+ if (pool_elts (mpls_tunnel_pool) == 0)
+ vlib_cli_output (vm, "No MPLS tunnels configured...");
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%d", &mti))
+ ;
+ else
+ break;
+ }
+
+ if (~0 == mti)
+ {
+ pool_foreach (mt, mpls_tunnel_pool,
+ ({
+ vlib_cli_output (vm, "[@%d] %U",
+ mt - mpls_tunnel_pool,
+ format_mpls_tunnel, mt);
+ }));
+ }
+ else
+ {
+ if (pool_is_free_index(mpls_tunnel_pool, mti))
+ return clib_error_return (0, "Not atunnel index %d", mti);
+
+ mt = pool_elt_at_index(mpls_tunnel_pool, mti);
+
+ vlib_cli_output (vm, "[@%d] %U",
+ mt - mpls_tunnel_pool,
+ format_mpls_tunnel, mt);
+ }
+
+ return 0;
+}
+
+/*?
+ * This command to show MPLS tunnels
+ *
+ * @cliexpar
+ * @cliexstart{sh mpls tunnel 2}
+ * [@2] mpls_tunnel2: sw_if_index:5 hw_if_index:5
+ * label-stack:
+ * 3,
+ * via:
+ * index:26 locks:1 proto:ipv4 uPRF-list:26 len:1 itfs:[2, ]
+ * index:26 pl-index:26 ipv4 weight=1 attached-nexthop: oper-flags:resolved,
+ * 10.0.0.2 loop0
+ * [@0]: ipv4 via 10.0.0.2 loop0: IP4: de:ad:00:00:00:00 -> 00:00:11:aa:bb:cc
+ * @cliexend
+ ?*/
+VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
+ .path = "show mpls tunnel",
+ .function = show_mpls_tunnel_command_fn,
+};
+
+static mpls_tunnel_t *
+mpls_tunnel_from_fib_node (fib_node_t *node)
+{
+#if (CLIB_DEBUG > 0)
+ ASSERT(FIB_NODE_TYPE_MPLS_TUNNEL == node->fn_type);
+#endif
+ return ((mpls_tunnel_t*) (((char*)node) -
+ STRUCT_OFFSET_OF(mpls_tunnel_t, mt_node)));
+}
+
+/**
+ * Function definition to backwalk a FIB node
+ */
+static fib_node_back_walk_rc_t
+mpls_tunnel_back_walk (fib_node_t *node,
+ fib_node_back_walk_ctx_t *ctx)
+{
+ mpls_tunnel_restack(mpls_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_tunnel_fib_node_get (fib_node_index_t index)
+{
+ mpls_tunnel_t * mt;
+
+ mt = pool_elt_at_index(mpls_tunnel_pool, index);
+
+ return (&mt->mt_node);
+}
+
+/**
+ * Function definition to inform the FIB node that its last lock has gone.
+ */
+static void
+mpls_tunnel_last_lock_gone (fib_node_t *node)
+{
+ /*
+ * The MPLS MPLS 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 MPLS tunnels
+ * for participation in the FIB object graph.
+ */
+const static fib_node_vft_t mpls_vft = {
+ .fnv_get = mpls_tunnel_fib_node_get,
+ .fnv_last_lock = mpls_tunnel_last_lock_gone,
+ .fnv_back_walk = mpls_tunnel_back_walk,
+};
+
+static clib_error_t *
+mpls_tunnel_init (vlib_main_t *vm)
+{
+ fib_node_register_type(FIB_NODE_TYPE_MPLS_TUNNEL, &mpls_vft);
+
+ return 0;
+}
+VLIB_INIT_FUNCTION(mpls_tunnel_init);
diff --git a/vnet/vnet/mpls/mpls_tunnel.h b/vnet/vnet/mpls/mpls_tunnel.h
new file mode 100644
index 00000000000..ee56c0fc8e3
--- /dev/null
+++ b/vnet/vnet/mpls/mpls_tunnel.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPLS_TUNNEL_H__
+#define __MPLS_TUNNEL_H__
+
+#include <vnet/mpls/mpls.h>
+
+/**
+ * @brief A uni-directional MPLS tunnel
+ */
+typedef struct mpls_tunnel_t_
+{
+ /**
+ * @brief The tunnel hooks into the FIB control plane graph.
+ */
+ fib_node_t mt_node;
+
+ /**
+ * @brief If the tunnel is an L2 tunnel, this is the link type ETHERNET
+ * adjacency
+ */
+ adj_index_t mt_l2_adj;
+
+ /**
+ * @brief on a L2 tunnel this is the VLIB arc from the L2-tx to the l2-midchain
+ */
+ u32 mt_l2_tx_arc;
+
+ /**
+ * @brief The path-list over which the tunnel's destination is reachable
+ */
+ fib_node_index_t mt_path_list;
+
+ /**
+ * @brief sibling index on the path-list so notifications are received.
+ */
+ u32 mt_sibling_index;
+
+ /**
+ * @brief The Label stack to apply to egress packets
+ */
+ mpls_label_t *mt_label_stack;
+
+ /**
+ * @brief Flag to indicate the tunnel is only for L2 traffic, that is
+ * this tunnel belongs in a bridge domain.
+ */
+ u8 mt_l2_only;
+
+ /**
+ * @brief The HW interface index of the tunnel interfaces
+ */
+ u32 mt_hw_if_index;
+
+ /**
+ * @brief The SW interface index of the tunnel interfaces
+ */
+ u32 mt_sw_if_index;
+
+} mpls_tunnel_t;
+
+/**
+ * @brief Create a new MPLS tunnel
+ */
+extern void vnet_mpls_tunnel_add (fib_route_path_t *rpath,
+ mpls_label_t *label_stack,
+ u8 l2_only,
+ u32 *sw_if_index);
+
+extern void vnet_mpls_tunnel_del (u32 sw_if_index);
+
+extern const mpls_tunnel_t *mpls_tunnel_get(u32 index);
+
+/**
+ * @brief Callback function invoked while walking MPLS tunnels
+ */
+typedef void (*mpls_tunnel_walk_cb_t)(u32 index, void *ctx);
+
+/**
+ * @brief Walk all the MPLS tunnels
+ */
+extern void mpls_tunnel_walk(mpls_tunnel_walk_cb_t cb,
+ void *ctx);
+
+#endif
diff --git a/vnet/vnet/mpls/policy_encap.c b/vnet/vnet/mpls/policy_encap.c
deleted file mode 100644
index d48a153b37d..00000000000
--- a/vnet/vnet/mpls/policy_encap.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * policy_encap.c: mpls-o-e policy encap
- *
- * Copyright (c) 2012-2014 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#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;
- u32 encap_index;
-} mpls_policy_encap_trace_t;
-
-u8 * format_mpls_policy_encap_trace (u8 * s, 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_policy_encap_trace_t * t = va_arg (*args, mpls_policy_encap_trace_t *);
-
- s = format (s, "MPLS-POLICY-ENCAP: next-index %d encap-index %d",
- t->next_index, t->encap_index);
-
- return s;
-}
-
-vlib_node_registration_t mpls_policy_encap_node;
-
-#define foreach_mpls_policy_encap_next \
-_(DROP, "error-drop")
-
-typedef enum {
-#define _(s,n) MPLS_POLICY_ENCAP_NEXT_##s,
- foreach_mpls_policy_encap_next
-#undef _
- MPLS_POLICY_ENCAP_N_NEXT,
-} mpls_policy_encap_next_t;
-
-#define foreach_mpls_policy_error \
-_(PKTS_ENCAP, "mpls policy tunnel packets encapsulated")
-
-typedef enum {
-#define _(n,s) MPLS_POLICY_ENCAP_ERROR_##n,
- foreach_mpls_policy_error
- MPLS_POLICY_ENCAP_N_ERROR,
-#undef _
-} mpls_policy_encap_error_t;
-
-static char * mpls_policy_encap_error_strings[] =
- {
-#define _(n,s) s,
- foreach_mpls_policy_error
-#undef _
-};
-
-static uword
-mpls_policy_encap (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * from_frame)
-{
- u32 n_left_from, next_index, * from, * to_next;
- mpls_main_t * mm = &mpls_main;
-
- from = vlib_frame_vector_args (from_frame);
- n_left_from = from_frame->n_vectors;
-
- next_index = node->cached_next_index;
-
- while (n_left_from > 0)
- {
- u32 n_left_to_next;
-
- vlib_get_next_frame (vm, node, next_index,
- to_next, n_left_to_next);
-
- while (n_left_from > 0 && n_left_to_next > 0)
- {
- u32 bi0;
- vlib_buffer_t * b0;
- u8 * h0;
- u32 encap_index0;
- u32 next0;
- mpls_encap_t * e0;
-
- 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);
-
- encap_index0 = vnet_buffer(b0)->l2_classify.opaque_index;
-
- e0 = pool_elt_at_index (mm->encaps, encap_index0);
-
- vlib_buffer_advance (b0, -(word)vec_len(e0->rewrite));
- h0 = vlib_buffer_get_current (b0);
- clib_memcpy (h0, e0->rewrite, vec_len(e0->rewrite));
-
- next0 = e0->output_next_index;
-
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- mpls_policy_encap_trace_t *tr =
- vlib_add_trace (vm, node, b0, sizeof (*tr));
- tr->next_index = next0;
- tr->encap_index = encap_index0;
- }
- 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, mpls_policy_encap_node.index,
- MPLS_POLICY_ENCAP_ERROR_PKTS_ENCAP,
- from_frame->n_vectors);
- return from_frame->n_vectors;
-}
-
-VLIB_REGISTER_NODE (mpls_policy_encap_node) = {
- .function = mpls_policy_encap,
- .name = "mpls-policy-encap",
- /* Takes a vector of packets. */
- .vector_size = sizeof (u32),
-
- .runtime_data_bytes = 0,
-
- .n_errors = MPLS_POLICY_ENCAP_N_ERROR,
- .error_strings = mpls_policy_encap_error_strings,
-
- .format_trace = format_mpls_policy_encap_trace,
-
- .n_next_nodes = MPLS_POLICY_ENCAP_N_NEXT,
- .next_nodes = {
-#define _(s,n) [MPLS_POLICY_ENCAP_NEXT_##s] = n,
- foreach_mpls_policy_encap_next
-#undef _
- },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (mpls_policy_encap_node, mpls_policy_encap)
-
-static clib_error_t *
-mpls_policy_encap_init (vlib_main_t * vm)
-{
- mpls_main_t * mm = &mpls_main;
- clib_error_t * error;
-
- if ((error = vlib_call_init_function (vm, mpls_init)))
- return error;
-
- mm->ip4_classify_mpls_policy_encap_next_index =
- vlib_node_add_next (mm->vlib_main,
- ip4_classify_node.index,
- mpls_policy_encap_node.index);
-
- mm->ip6_classify_mpls_policy_encap_next_index =
- vlib_node_add_next (mm->vlib_main,
- ip6_classify_node.index,
- mpls_policy_encap_node.index);
-
- return 0;
-}
-
-VLIB_INIT_FUNCTION (mpls_policy_encap_init);