2 * interface.c: mpls interfaces
4 * Copyright (c) 2012 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/vnet.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/mpls/mpls.h>
21 #include <vnet/fib/ip4_fib.h>
22 #include <vnet/adj/adj_midchain.h>
23 #include <vnet/dpo/classify_dpo.h>
25 /* manually added to the interface output node */
26 #define MPLS_ETH_OUTPUT_NEXT_OUTPUT 1
29 mpls_eth_interface_tx (vlib_main_t * vm,
30 vlib_node_runtime_t * node,
33 mpls_main_t * gm = &mpls_main;
34 vnet_main_t * vnm = gm->vnet_main;
36 u32 * from, * to_next, n_left_from, n_left_to_next;
38 /* Vector of buffer / pkt indices we're supposed to process */
39 from = vlib_frame_vector_args (frame);
41 /* Number of buffers / pkts */
42 n_left_from = frame->n_vectors;
44 /* Speculatively send the first buffer to the last disposition we used */
45 next_index = node->cached_next_index;
47 while (n_left_from > 0)
49 /* set up to enqueue to our disposition with index = next_index */
50 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
53 * As long as we have enough pkts left to process two pkts
54 * and prefetch two pkts...
56 while (n_left_from >= 4 && n_left_to_next >= 2)
58 vlib_buffer_t * b0, * b1;
59 u32 bi0, next0, bi1, next1;
60 mpls_eth_tunnel_t * t0, * t1;
61 u32 sw_if_index0, sw_if_index1;
62 vnet_hw_interface_t * hi0, * hi1;
65 /* Prefetch the next iteration */
67 vlib_buffer_t * p2, * p3;
69 p2 = vlib_get_buffer (vm, from[2]);
70 p3 = vlib_get_buffer (vm, from[3]);
72 vlib_prefetch_buffer_header (p2, LOAD);
73 vlib_prefetch_buffer_header (p3, LOAD);
76 * Prefetch packet data. We expect to overwrite
77 * the inbound L2 header with an ip header and a
78 * gre header. Might want to prefetch the last line
79 * of rewrite space as well; need profile data
81 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
82 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
85 /* Pick up the next two buffer indices */
89 /* Speculatively enqueue them where we sent the last buffer */
97 b0 = vlib_get_buffer (vm, bi0);
98 b1 = vlib_get_buffer (vm, bi1);
100 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
101 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
104 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
105 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
107 /* hw_instance = tunnel pool index */
108 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
109 t1 = pool_elt_at_index (gm->eth_tunnels, hi1->hw_instance);
111 /* Apply rewrite - $$$$$ fixme don't use memcpy */
112 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
113 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
115 dst0 = vlib_buffer_get_current (b0);
116 dst1 = vlib_buffer_get_current (b1);
118 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
119 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
121 /* Fix TX fib indices */
122 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
123 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->tx_sw_if_index;
125 /* mpls-post-rewrite takes it from here... */
126 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
127 next1 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
129 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
131 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
134 tr->tunnel_id = t0 - gm->eth_tunnels;
135 tr->tx_sw_if_index = t0->tx_sw_if_index;
136 tr->mpls_encap_index = t0->encap_index;
137 tr->length = b0->current_length;
138 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
139 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
141 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
143 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
146 tr->tunnel_id = t1 - gm->eth_tunnels;
147 tr->tx_sw_if_index = t1->tx_sw_if_index;
148 tr->mpls_encap_index = t1->encap_index;
149 tr->length = b1->current_length;
150 hi1 = vnet_get_sup_hw_interface (vnm, t1->tx_sw_if_index);
151 clib_memcpy (tr->dst, hi1->hw_address, sizeof (tr->dst));
154 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
155 to_next, n_left_to_next,
156 bi0, bi1, next0, next1);
158 while (n_left_from > 0 && n_left_to_next > 0)
162 mpls_eth_tunnel_t * t0;
164 vnet_hw_interface_t * hi0;
174 b0 = vlib_get_buffer (vm, bi0);
176 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
178 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
180 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
182 /* Apply rewrite - $$$$$ fixme don't use memcpy */
183 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
185 dst0 = vlib_buffer_get_current (b0);
187 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
189 /* Fix the TX interface */
190 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
192 /* Send the packet */
193 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
195 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
197 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
200 tr->tunnel_id = t0 - gm->eth_tunnels;
201 tr->tx_sw_if_index = t0->tx_sw_if_index;
202 tr->mpls_encap_index = t0->encap_index;
203 tr->length = b0->current_length;
204 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
205 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
208 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
209 to_next, n_left_to_next,
213 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
216 vlib_node_increment_counter (vm, mpls_input_node.index,
217 MPLS_ERROR_PKTS_ENCAP, frame->n_vectors);
219 return frame->n_vectors;
222 static u8 * format_mpls_eth_tunnel_name (u8 * s, va_list * args)
224 u32 dev_instance = va_arg (*args, u32);
225 return format (s, "mpls-eth%d", dev_instance);
228 static u8 * format_mpls_eth_device (u8 * s, va_list * args)
230 u32 dev_instance = va_arg (*args, u32);
231 CLIB_UNUSED (int verbose) = va_arg (*args, int);
233 s = format (s, "MPLS-ETH tunnel: id %d\n", dev_instance);
237 VNET_DEVICE_CLASS (mpls_eth_device_class) = {
238 .name = "MPLS-ETH tunnel device",
239 .format_device_name = format_mpls_eth_tunnel_name,
240 .format_device = format_mpls_eth_device,
241 .format_tx_trace = format_mpls_eth_tx_trace,
242 .tx_function = mpls_eth_interface_tx,
243 .no_flatten_output_chains = 1,
246 .admin_up_down_function = 0;
250 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_eth_device_class,
251 mpls_eth_interface_tx)
253 VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = {
255 .format_header = format_mpls_eth_header_with_length,
257 .unformat_header = unformat_mpls_eth_header,
259 .build_rewrite = default_build_rewrite,
260 .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
264 mpls_sw_interface_is_enabled (u32 sw_if_index)
266 mpls_main_t * mm = &mpls_main;
268 if (vec_len(mm->mpls_enabled_by_sw_if_index) < sw_if_index)
271 return (mm->mpls_enabled_by_sw_if_index[sw_if_index]);
275 mpls_sw_interface_enable_disable (mpls_main_t * mm,
279 vlib_main_t * vm = vlib_get_main();
280 ip_config_main_t * cm = &mm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
281 vnet_config_main_t * vcm = &cm->config_main;
282 u32 lookup_feature_index;
283 fib_node_index_t lfib_index;
286 vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
289 * enable/disable only on the 1<->0 transition
293 if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
296 lfib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS,
297 MPLS_FIB_DEFAULT_TABLE_ID);
298 vec_validate(mm->fib_index_by_sw_if_index, 0);
299 mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
303 ASSERT(mm->mpls_enabled_by_sw_if_index[sw_if_index] > 0);
304 if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
307 fib_table_unlock(mm->fib_index_by_sw_if_index[sw_if_index],
311 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
312 ci = cm->config_index_by_sw_if_index[sw_if_index];
314 lookup_feature_index = mm->mpls_rx_feature_lookup;
317 ci = vnet_config_add_feature (vm, vcm,
319 lookup_feature_index,
321 /* # bytes of config data */ 0);
323 ci = vnet_config_del_feature (vm, vcm, ci,
324 lookup_feature_index,
326 /* # bytes of config data */ 0);
328 cm->config_index_by_sw_if_index[sw_if_index] = ci;
331 u8 * format_mpls_encap_index (u8 * s, va_list * args)
333 mpls_main_t * mm = va_arg (*args, mpls_main_t *);
334 u32 entry_index = va_arg (*args, u32);
338 e = pool_elt_at_index (mm->encaps, entry_index);
340 for (i = 0; i < vec_len (e->labels); i++)
342 (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
343 (e->labels[i].label_exp_s_ttl)));
348 u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
350 mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
351 mpls_main_t * mm = &mpls_main;
353 s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
355 format_ethernet_address, &t->tunnel_dst,
356 format_ip4_address, &t->intfc_address,
358 format_mpls_encap_index, mm, t->encap_index);
361 s = format (s, " tx on %U, rx fib index %d",
362 format_vnet_sw_if_index_name, mm->vnet_main, t->tx_sw_if_index,
368 static clib_error_t *
369 show_mpls_tunnel_command_fn (vlib_main_t * vm,
370 unformat_input_t * input,
371 vlib_cli_command_t * cmd)
373 mpls_main_t * mm = &mpls_main;
374 mpls_eth_tunnel_t * et;
376 if (pool_elts (mm->eth_tunnels))
378 vlib_cli_output (vm, "MPLS-Ethernet tunnels");
379 pool_foreach (et, mm->eth_tunnels,
381 vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
385 vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
390 VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
391 .path = "show mpls tunnel",
392 .short_help = "show mpls tunnel",
393 .function = show_mpls_tunnel_command_fn,
397 /* force inclusion from application's main.c */
398 clib_error_t *mpls_interface_init (vlib_main_t *vm)
400 clib_error_t * error;
402 if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
407 VLIB_INIT_FUNCTION(mpls_interface_init);
410 static u8 * mpls_ethernet_rewrite (mpls_main_t *mm, mpls_eth_tunnel_t * t)
412 u8 * rewrite_data = 0;
414 mpls_unicast_header_t *lp0;
417 /* look up the encap label stack using the RX FIB and adjacency address*/
418 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index,
419 t->intfc_address.as_u32);
423 clib_warning ("no label for inner fib index %d, dst %U",
424 t->inner_fib_index, format_ip4_address,
429 vec_validate (rewrite_data,
430 sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
432 /* Copy the encap label stack */
433 lp0 = (mpls_unicast_header_t *) rewrite_data;
435 for (i = 0; i < vec_len(e->labels); i++)
436 lp0[i] = e->labels[i];
438 return (rewrite_data);
441 int vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
442 ip4_address_t *intfc,
446 u32 * tunnel_sw_if_index,
450 ip4_main_t * im = &ip4_main;
451 ip_lookup_main_t * lm = &im->lookup_main;
452 mpls_main_t * mm = &mpls_main;
453 vnet_main_t * vnm = vnet_get_main();
454 mpls_eth_tunnel_t *tp;
455 u32 inner_fib_index = 0;
459 int found_tunnel = 0;
460 mpls_encap_t * e = 0;
461 u32 hw_if_index = ~0;
462 vnet_hw_interface_t * hi;
466 if (tunnel_sw_if_index == 0)
467 tunnel_sw_if_index = &dummy;
469 *tunnel_sw_if_index = ~0;
471 if (inner_fib_id != (u32)~0)
475 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
477 return VNET_API_ERROR_NO_SUCH_FIB;
478 inner_fib_index = p[0];
481 /* suppress duplicate mpls interface generation. */
482 pool_foreach (tp, mm->eth_tunnels,
485 * If we have a tunnel which matches (src, dst, intfc/mask)
486 * AND the expected route is in the FIB, it's a dup
488 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
489 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
490 && tp->inner_fib_index == inner_fib_index
491 && FIB_NODE_INDEX_INVALID != tp->fei)
501 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
504 return VNET_API_ERROR_NO_SUCH_LABEL;
518 /* Delete, and we can't find the tunnel */
519 if (is_add == 0 && found_tunnel == 0)
520 return VNET_API_ERROR_NO_SUCH_ENTRY;
522 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
524 return VNET_API_ERROR_NO_SUCH_LABEL;
526 pool_get(mm->eth_tunnels, tp);
527 memset (tp, 0, sizeof (*tp));
529 if (vec_len (mm->free_eth_sw_if_indices) > 0)
532 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
533 _vec_len (mm->free_eth_sw_if_indices) -= 1;
534 hi = vnet_get_hw_interface (vnm, hw_if_index);
535 hi->dev_instance = tp - mm->eth_tunnels;
536 hi->hw_instance = tp - mm->eth_tunnels;
540 hw_if_index = vnet_register_interface
541 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
542 mpls_eth_hw_interface_class.index,
543 tp - mm->eth_tunnels);
544 hi = vnet_get_hw_interface (vnm, hw_if_index);
546 /* ... to make the IP and L2 x-connect cases identical */
547 slot = vlib_node_add_named_next_with_slot
548 (vnm->vlib_main, hi->tx_node_index,
549 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
551 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
554 *tunnel_sw_if_index = hi->sw_if_index;
555 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
556 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
558 tp->hw_if_index = hw_if_index;
561 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
562 tp->intfc_address.as_u32 = intfc->as_u32;
563 tp->mask_width = mask_width;
564 tp->inner_fib_index = inner_fib_index;
565 tp->encap_index = e - mm->encaps;
566 tp->tx_sw_if_index = tx_sw_if_index;
567 tp->l2_only = l2_only;
569 /* Create the adjacency and add to v4 fib */
570 memset(&adj, 0, sizeof (adj));
571 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
573 rewrite_data = mpls_ethernet_rewrite (mm, tp);
574 if (rewrite_data == 0)
576 if (*tunnel_sw_if_index != ~0)
578 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
579 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
581 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
584 pool_put (mm->eth_tunnels, tp);
585 return VNET_API_ERROR_NO_SUCH_LABEL;
588 vnet_rewrite_for_sw_interface
592 ip4_rewrite_node.index,
595 sizeof (adj.rewrite_data));
598 * Prepend the (0,1,2) VLAN tag ethernet header
599 * we just built to the mpls header stack
601 vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
602 clib_memcpy(rewrite_data,
603 vnet_rewrite_get_data_internal(&adj.rewrite_header,
604 sizeof (adj.rewrite_data)),
605 adj.rewrite_header.data_bytes);
607 vnet_rewrite_set_data_internal (&adj.rewrite_header,
608 sizeof(adj.rewrite_data),
610 vec_len(rewrite_data));
612 vec_free (tp->rewrite_data);
614 tp->rewrite_data = rewrite_data;
617 ip_add_adjacency (lm, &adj, 1 /* one adj */,
624 const fib_prefix_t pfx = {
626 .ip4 = tp->intfc_address,
628 .fp_len = tp->mask_width,
629 .fp_proto = FIB_PROTOCOL_IP4,
632 tp->fei = fib_table_entry_special_add(tp->inner_fib_index,
639 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
640 tp->fei = FIB_NODE_INDEX_INVALID;
643 if (is_add == 0 && found_tunnel)
645 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
646 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
648 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
649 vec_free (tp->rewrite_data);
650 pool_put (mm->eth_tunnels, tp);
656 static clib_error_t *
657 create_mpls_ethernet_tunnel_command_fn (vlib_main_t * vm,
658 unformat_input_t * input,
659 vlib_cli_command_t * cmd)
661 unformat_input_t _line_input, * line_input = &_line_input;
662 vnet_main_t * vnm = vnet_get_main();
666 int dst_set = 0, intfc_set = 0;
668 u32 inner_fib_id = (u32)~0;
673 u32 sw_if_index = ~0;
675 /* Get a line of input. */
676 if (! unformat_user (input, unformat_line_input, line_input))
679 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
681 if (unformat (line_input, "dst %U",
682 unformat_ethernet_address, &dst))
684 else if (unformat (line_input, "adj %U/%d",
685 unformat_ip4_address, &intfc, &mask_width))
687 else if (unformat (line_input, "tx-intfc %U",
688 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
690 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
692 else if (unformat (line_input, "l2-only"))
694 else if (unformat (line_input, "del"))
697 return clib_error_return (0, "unknown input '%U'",
698 format_unformat_error, line_input);
702 return clib_error_return (0, "missing tx-intfc");
705 return clib_error_return (0, "missing: dst <ethernet-address>");
708 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
711 rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
712 inner_fib_id, tx_sw_if_index,
720 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
722 case VNET_API_ERROR_NO_SUCH_FIB:
723 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
726 case VNET_API_ERROR_NO_SUCH_ENTRY:
727 return clib_error_return (0, "tunnel not found\n");
729 case VNET_API_ERROR_NO_SUCH_LABEL:
731 * This happens when there's no MPLS label for the dst address
732 * no need for two error messages.
734 return clib_error_return (0, "no label for %U in fib %d",
735 format_ip4_address, &intfc, inner_fib_id);
739 return clib_error_return (0, "vnet_mpls_ethernet_add_del_tunnel returned %d", rv);
746 VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
747 .path = "create mpls ethernet tunnel",
749 "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
750 .function = create_mpls_ethernet_tunnel_command_fn,
754 int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
756 u32 policy_tunnel_index)
758 mpls_eth_tunnel_t * t;
760 u8 * rewrite_data = 0;
762 mpls_unicast_header_t *lp;
765 if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
766 return VNET_API_ERROR_NO_SUCH_ENTRY;
768 t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
770 memset (&adj, 0, sizeof (adj));
773 vnet_rewrite_for_sw_interface
777 mpls_policy_encap_node.index,
780 sizeof (adj.rewrite_data));
782 vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
784 clib_memcpy(rewrite_data,
785 vnet_rewrite_get_data_internal(&adj.rewrite_header,
786 sizeof (adj.rewrite_data)),
787 adj.rewrite_header.data_bytes);
789 /* Append the label stack */
791 vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
793 lp = (mpls_unicast_header_t *) label_start;
795 for (i = 0; i < vec_len(e->labels); i++)
796 lp[i] = e->labels[i];
798 /* Remember the rewrite data */
799 e->rewrite = rewrite_data;
800 e->output_next_index = adj.rewrite_header.next_index;
805 int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
806 ip4_address_t *intfc,
810 u32 * tunnel_sw_if_index,
811 u32 classify_table_index,
812 u32 * new_tunnel_index,
816 ip4_main_t * im = &ip4_main;
817 mpls_main_t * mm = &mpls_main;
818 vnet_main_t * vnm = vnet_get_main();
819 mpls_eth_tunnel_t *tp;
820 u32 inner_fib_index = 0;
821 int found_tunnel = 0;
822 mpls_encap_t * e = 0;
823 u32 hw_if_index = ~0;
824 vnet_hw_interface_t * hi;
828 if (tunnel_sw_if_index == 0)
829 tunnel_sw_if_index = &dummy;
831 *tunnel_sw_if_index = ~0;
833 if (inner_fib_id != (u32)~0)
837 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
839 return VNET_API_ERROR_NO_SUCH_FIB;
840 inner_fib_index = p[0];
843 /* suppress duplicate mpls interface generation. */
844 pool_foreach (tp, mm->eth_tunnels,
847 * If we have a tunnel which matches (src, dst, intfc/mask)
848 * AND the expected route is in the FIB, it's a dup
850 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
851 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
852 && tp->inner_fib_index == inner_fib_index
853 && FIB_NODE_INDEX_INVALID != tp->fei)
875 /* Delete, and we can't find the tunnel */
876 if (is_add == 0 && found_tunnel == 0)
877 return VNET_API_ERROR_NO_SUCH_ENTRY;
879 pool_get(mm->eth_tunnels, tp);
880 memset (tp, 0, sizeof (*tp));
882 if (vec_len (mm->free_eth_sw_if_indices) > 0)
885 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
886 _vec_len (mm->free_eth_sw_if_indices) -= 1;
887 hi = vnet_get_hw_interface (vnm, hw_if_index);
888 hi->dev_instance = tp - mm->eth_tunnels;
889 hi->hw_instance = tp - mm->eth_tunnels;
893 hw_if_index = vnet_register_interface
894 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
895 mpls_eth_hw_interface_class.index,
896 tp - mm->eth_tunnels);
897 hi = vnet_get_hw_interface (vnm, hw_if_index);
899 /* ... to make the IP and L2 x-connect cases identical */
900 slot = vlib_node_add_named_next_with_slot
901 (vnm->vlib_main, hi->tx_node_index,
902 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
904 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
907 *tunnel_sw_if_index = hi->sw_if_index;
908 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
909 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
911 tp->hw_if_index = hw_if_index;
914 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
915 tp->intfc_address.as_u32 = intfc->as_u32;
916 tp->mask_width = mask_width;
917 tp->inner_fib_index = inner_fib_index;
918 tp->encap_index = e - mm->encaps;
919 tp->tx_sw_if_index = tx_sw_if_index;
920 tp->l2_only = l2_only;
921 tp->fei = FIB_NODE_INDEX_INVALID;
923 if (new_tunnel_index)
924 *new_tunnel_index = tp - mm->eth_tunnels;
930 const fib_prefix_t pfx = {
932 .ip4 = tp->intfc_address,
934 .fp_len = tp->mask_width,
935 .fp_proto = FIB_PROTOCOL_IP4,
937 dpo_id_t dpo = DPO_INVALID;
944 classify_dpo_create(DPO_PROTO_IP4,
945 classify_table_index));
947 tp->fei = fib_table_entry_special_dpo_add(tp->inner_fib_index,
950 FIB_ENTRY_FLAG_EXCLUSIVE,
956 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
957 tp->fei = FIB_NODE_INDEX_INVALID;
960 if (is_add == 0 && found_tunnel)
962 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
963 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
965 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
966 pool_put (mm->eth_tunnels, tp);
972 static clib_error_t *
973 create_mpls_ethernet_policy_tunnel_command_fn (vlib_main_t * vm,
974 unformat_input_t * input,
975 vlib_cli_command_t * cmd)
977 unformat_input_t _line_input, * line_input = &_line_input;
978 vnet_main_t * vnm = vnet_get_main();
982 int dst_set = 0, intfc_set = 0;
984 u32 inner_fib_id = (u32)~0;
985 u32 classify_table_index = (u32)~0;
986 u32 new_tunnel_index;
992 /* Get a line of input. */
993 if (! unformat_user (input, unformat_line_input, line_input))
996 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
998 if (unformat (line_input, "dst %U",
999 unformat_ethernet_address, &dst))
1001 else if (unformat (line_input, "adj %U/%d",
1002 unformat_ip4_address, &intfc, &mask_width))
1004 else if (unformat (line_input, "tx-intfc %U",
1005 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1007 else if (unformat (line_input, "classify-table-index %d",
1008 &classify_table_index))
1010 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1012 else if (unformat (line_input, "l2-only"))
1014 else if (unformat (line_input, "del"))
1017 return clib_error_return (0, "unknown input '%U'",
1018 format_unformat_error, line_input);
1021 if (classify_table_index == ~0)
1022 return clib_error_return (0, "missing classify_table_index");
1025 return clib_error_return (0, "missing tx-intfc");
1028 return clib_error_return (0, "missing: dst <ethernet-address>");
1031 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1034 rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
1035 inner_fib_id, tx_sw_if_index,
1036 0 /* tunnel sw_if_index */,
1037 classify_table_index,
1044 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), new_tunnel_index);
1046 case VNET_API_ERROR_NO_SUCH_FIB:
1047 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1050 case VNET_API_ERROR_NO_SUCH_ENTRY:
1051 return clib_error_return (0, "tunnel not found\n");
1053 case VNET_API_ERROR_NO_SUCH_LABEL:
1055 * This happens when there's no MPLS label for the dst address
1056 * no need for two error messages.
1058 return clib_error_return (0, "no label for %U in fib %d",
1059 format_ip4_address, &intfc, inner_fib_id);
1063 return clib_error_return (0, "vnet_mpls_ethernet_add_del_policy_tunnel returned %d", rv);
1070 VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
1071 .path = "create mpls ethernet policy tunnel",
1073 "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
1074 " classify-table-index <nn>",
1075 .function = create_mpls_ethernet_policy_tunnel_command_fn,
1078 static clib_error_t *
1079 mpls_interface_enable_disable (vlib_main_t * vm,
1080 unformat_input_t * input,
1081 vlib_cli_command_t * cmd)
1083 vnet_main_t * vnm = vnet_get_main();
1084 clib_error_t * error = 0;
1085 u32 sw_if_index, enable;
1089 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1091 error = clib_error_return (0, "unknown interface `%U'",
1092 format_unformat_error, input);
1096 if (unformat (input, "enable"))
1098 else if (unformat (input, "disable"))
1102 error = clib_error_return (0, "expected 'enable' or 'disable'",
1103 format_unformat_error, input);
1107 mpls_sw_interface_enable_disable(&mpls_main, sw_if_index, enable);
1113 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
1114 .path = "set interface mpls",
1115 .function = mpls_interface_enable_disable,
1116 .short_help = "Enable/Disable an interface for MPLS forwarding",