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 fib_node_index_t lfib_index;
281 vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
284 * enable/disable only on the 1<->0 transition
288 if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
291 lfib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS,
292 MPLS_FIB_DEFAULT_TABLE_ID);
293 vec_validate(mm->fib_index_by_sw_if_index, 0);
294 mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
298 ASSERT(mm->mpls_enabled_by_sw_if_index[sw_if_index] > 0);
299 if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
302 fib_table_unlock(mm->fib_index_by_sw_if_index[sw_if_index],
306 vnet_feature_enable_disable ("mpls-input", "mpls-lookup", sw_if_index,
311 u8 * format_mpls_encap_index (u8 * s, va_list * args)
313 mpls_main_t * mm = va_arg (*args, mpls_main_t *);
314 u32 entry_index = va_arg (*args, u32);
318 e = pool_elt_at_index (mm->encaps, entry_index);
320 for (i = 0; i < vec_len (e->labels); i++)
322 (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
323 (e->labels[i].label_exp_s_ttl)));
328 u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
330 mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
331 mpls_main_t * mm = &mpls_main;
333 s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
335 format_ethernet_address, &t->tunnel_dst,
336 format_ip4_address, &t->intfc_address,
338 format_mpls_encap_index, mm, t->encap_index);
341 s = format (s, " tx on %U, rx fib index %d",
342 format_vnet_sw_if_index_name, mm->vnet_main, t->tx_sw_if_index,
348 static clib_error_t *
349 show_mpls_tunnel_command_fn (vlib_main_t * vm,
350 unformat_input_t * input,
351 vlib_cli_command_t * cmd)
353 mpls_main_t * mm = &mpls_main;
354 mpls_eth_tunnel_t * et;
356 if (pool_elts (mm->eth_tunnels))
358 vlib_cli_output (vm, "MPLS-Ethernet tunnels");
359 pool_foreach (et, mm->eth_tunnels,
361 vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
365 vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
370 VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
371 .path = "show mpls tunnel",
372 .short_help = "show mpls tunnel",
373 .function = show_mpls_tunnel_command_fn,
377 /* force inclusion from application's main.c */
378 clib_error_t *mpls_interface_init (vlib_main_t *vm)
380 clib_error_t * error;
382 if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
387 VLIB_INIT_FUNCTION(mpls_interface_init);
390 static u8 * mpls_ethernet_rewrite (mpls_main_t *mm, mpls_eth_tunnel_t * t)
392 u8 * rewrite_data = 0;
394 mpls_unicast_header_t *lp0;
397 /* look up the encap label stack using the RX FIB and adjacency address*/
398 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index,
399 t->intfc_address.as_u32);
403 clib_warning ("no label for inner fib index %d, dst %U",
404 t->inner_fib_index, format_ip4_address,
409 vec_validate (rewrite_data,
410 sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
412 /* Copy the encap label stack */
413 lp0 = (mpls_unicast_header_t *) rewrite_data;
415 for (i = 0; i < vec_len(e->labels); i++)
416 lp0[i] = e->labels[i];
418 return (rewrite_data);
421 int vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
422 ip4_address_t *intfc,
426 u32 * tunnel_sw_if_index,
430 ip4_main_t * im = &ip4_main;
431 ip_lookup_main_t * lm = &im->lookup_main;
432 mpls_main_t * mm = &mpls_main;
433 vnet_main_t * vnm = vnet_get_main();
434 mpls_eth_tunnel_t *tp;
435 u32 inner_fib_index = 0;
439 int found_tunnel = 0;
440 mpls_encap_t * e = 0;
441 u32 hw_if_index = ~0;
442 vnet_hw_interface_t * hi;
446 if (tunnel_sw_if_index == 0)
447 tunnel_sw_if_index = &dummy;
449 *tunnel_sw_if_index = ~0;
451 if (inner_fib_id != (u32)~0)
455 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
457 return VNET_API_ERROR_NO_SUCH_FIB;
458 inner_fib_index = p[0];
461 /* suppress duplicate mpls interface generation. */
462 pool_foreach (tp, mm->eth_tunnels,
465 * If we have a tunnel which matches (src, dst, intfc/mask)
466 * AND the expected route is in the FIB, it's a dup
468 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
469 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
470 && tp->inner_fib_index == inner_fib_index
471 && FIB_NODE_INDEX_INVALID != tp->fei)
481 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
484 return VNET_API_ERROR_NO_SUCH_LABEL;
498 /* Delete, and we can't find the tunnel */
499 if (is_add == 0 && found_tunnel == 0)
500 return VNET_API_ERROR_NO_SUCH_ENTRY;
502 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
504 return VNET_API_ERROR_NO_SUCH_LABEL;
506 pool_get(mm->eth_tunnels, tp);
507 memset (tp, 0, sizeof (*tp));
509 if (vec_len (mm->free_eth_sw_if_indices) > 0)
512 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
513 _vec_len (mm->free_eth_sw_if_indices) -= 1;
514 hi = vnet_get_hw_interface (vnm, hw_if_index);
515 hi->dev_instance = tp - mm->eth_tunnels;
516 hi->hw_instance = tp - mm->eth_tunnels;
520 hw_if_index = vnet_register_interface
521 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
522 mpls_eth_hw_interface_class.index,
523 tp - mm->eth_tunnels);
524 hi = vnet_get_hw_interface (vnm, hw_if_index);
526 /* ... to make the IP and L2 x-connect cases identical */
527 slot = vlib_node_add_named_next_with_slot
528 (vnm->vlib_main, hi->tx_node_index,
529 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
531 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
534 *tunnel_sw_if_index = hi->sw_if_index;
535 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
536 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
538 tp->hw_if_index = hw_if_index;
541 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
542 tp->intfc_address.as_u32 = intfc->as_u32;
543 tp->mask_width = mask_width;
544 tp->inner_fib_index = inner_fib_index;
545 tp->encap_index = e - mm->encaps;
546 tp->tx_sw_if_index = tx_sw_if_index;
547 tp->l2_only = l2_only;
549 /* Create the adjacency and add to v4 fib */
550 memset(&adj, 0, sizeof (adj));
551 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
553 rewrite_data = mpls_ethernet_rewrite (mm, tp);
554 if (rewrite_data == 0)
556 if (*tunnel_sw_if_index != ~0)
558 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
559 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
561 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
564 pool_put (mm->eth_tunnels, tp);
565 return VNET_API_ERROR_NO_SUCH_LABEL;
568 vnet_rewrite_for_sw_interface
572 ip4_rewrite_node.index,
575 sizeof (adj.rewrite_data));
578 * Prepend the (0,1,2) VLAN tag ethernet header
579 * we just built to the mpls header stack
581 vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
582 clib_memcpy(rewrite_data,
583 vnet_rewrite_get_data_internal(&adj.rewrite_header,
584 sizeof (adj.rewrite_data)),
585 adj.rewrite_header.data_bytes);
587 vnet_rewrite_set_data_internal (&adj.rewrite_header,
588 sizeof(adj.rewrite_data),
590 vec_len(rewrite_data));
592 vec_free (tp->rewrite_data);
594 tp->rewrite_data = rewrite_data;
597 ip_add_adjacency (lm, &adj, 1 /* one adj */,
604 const fib_prefix_t pfx = {
606 .ip4 = tp->intfc_address,
608 .fp_len = tp->mask_width,
609 .fp_proto = FIB_PROTOCOL_IP4,
612 tp->fei = fib_table_entry_special_add(tp->inner_fib_index,
619 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
620 tp->fei = FIB_NODE_INDEX_INVALID;
623 if (is_add == 0 && found_tunnel)
625 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
626 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
628 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
629 vec_free (tp->rewrite_data);
630 pool_put (mm->eth_tunnels, tp);
636 static clib_error_t *
637 create_mpls_ethernet_tunnel_command_fn (vlib_main_t * vm,
638 unformat_input_t * input,
639 vlib_cli_command_t * cmd)
641 unformat_input_t _line_input, * line_input = &_line_input;
642 vnet_main_t * vnm = vnet_get_main();
646 int dst_set = 0, intfc_set = 0;
648 u32 inner_fib_id = (u32)~0;
653 u32 sw_if_index = ~0;
655 /* Get a line of input. */
656 if (! unformat_user (input, unformat_line_input, line_input))
659 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
661 if (unformat (line_input, "dst %U",
662 unformat_ethernet_address, &dst))
664 else if (unformat (line_input, "adj %U/%d",
665 unformat_ip4_address, &intfc, &mask_width))
667 else if (unformat (line_input, "tx-intfc %U",
668 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
670 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
672 else if (unformat (line_input, "l2-only"))
674 else if (unformat (line_input, "del"))
677 return clib_error_return (0, "unknown input '%U'",
678 format_unformat_error, line_input);
682 return clib_error_return (0, "missing tx-intfc");
685 return clib_error_return (0, "missing: dst <ethernet-address>");
688 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
691 rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
692 inner_fib_id, tx_sw_if_index,
700 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
702 case VNET_API_ERROR_NO_SUCH_FIB:
703 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
706 case VNET_API_ERROR_NO_SUCH_ENTRY:
707 return clib_error_return (0, "tunnel not found\n");
709 case VNET_API_ERROR_NO_SUCH_LABEL:
711 * This happens when there's no MPLS label for the dst address
712 * no need for two error messages.
714 return clib_error_return (0, "no label for %U in fib %d",
715 format_ip4_address, &intfc, inner_fib_id);
719 return clib_error_return (0, "vnet_mpls_ethernet_add_del_tunnel returned %d", rv);
726 VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
727 .path = "create mpls ethernet tunnel",
729 "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
730 .function = create_mpls_ethernet_tunnel_command_fn,
734 int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
736 u32 policy_tunnel_index)
738 mpls_eth_tunnel_t * t;
740 u8 * rewrite_data = 0;
742 mpls_unicast_header_t *lp;
745 if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
746 return VNET_API_ERROR_NO_SUCH_ENTRY;
748 t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
750 memset (&adj, 0, sizeof (adj));
753 vnet_rewrite_for_sw_interface
757 mpls_policy_encap_node.index,
760 sizeof (adj.rewrite_data));
762 vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
764 clib_memcpy(rewrite_data,
765 vnet_rewrite_get_data_internal(&adj.rewrite_header,
766 sizeof (adj.rewrite_data)),
767 adj.rewrite_header.data_bytes);
769 /* Append the label stack */
771 vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
773 lp = (mpls_unicast_header_t *) label_start;
775 for (i = 0; i < vec_len(e->labels); i++)
776 lp[i] = e->labels[i];
778 /* Remember the rewrite data */
779 e->rewrite = rewrite_data;
780 e->output_next_index = adj.rewrite_header.next_index;
785 int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
786 ip4_address_t *intfc,
790 u32 * tunnel_sw_if_index,
791 u32 classify_table_index,
792 u32 * new_tunnel_index,
796 ip4_main_t * im = &ip4_main;
797 mpls_main_t * mm = &mpls_main;
798 vnet_main_t * vnm = vnet_get_main();
799 mpls_eth_tunnel_t *tp;
800 u32 inner_fib_index = 0;
801 int found_tunnel = 0;
802 mpls_encap_t * e = 0;
803 u32 hw_if_index = ~0;
804 vnet_hw_interface_t * hi;
808 if (tunnel_sw_if_index == 0)
809 tunnel_sw_if_index = &dummy;
811 *tunnel_sw_if_index = ~0;
813 if (inner_fib_id != (u32)~0)
817 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
819 return VNET_API_ERROR_NO_SUCH_FIB;
820 inner_fib_index = p[0];
823 /* suppress duplicate mpls interface generation. */
824 pool_foreach (tp, mm->eth_tunnels,
827 * If we have a tunnel which matches (src, dst, intfc/mask)
828 * AND the expected route is in the FIB, it's a dup
830 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
831 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
832 && tp->inner_fib_index == inner_fib_index
833 && FIB_NODE_INDEX_INVALID != tp->fei)
855 /* Delete, and we can't find the tunnel */
856 if (is_add == 0 && found_tunnel == 0)
857 return VNET_API_ERROR_NO_SUCH_ENTRY;
859 pool_get(mm->eth_tunnels, tp);
860 memset (tp, 0, sizeof (*tp));
862 if (vec_len (mm->free_eth_sw_if_indices) > 0)
865 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
866 _vec_len (mm->free_eth_sw_if_indices) -= 1;
867 hi = vnet_get_hw_interface (vnm, hw_if_index);
868 hi->dev_instance = tp - mm->eth_tunnels;
869 hi->hw_instance = tp - mm->eth_tunnels;
873 hw_if_index = vnet_register_interface
874 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
875 mpls_eth_hw_interface_class.index,
876 tp - mm->eth_tunnels);
877 hi = vnet_get_hw_interface (vnm, hw_if_index);
879 /* ... to make the IP and L2 x-connect cases identical */
880 slot = vlib_node_add_named_next_with_slot
881 (vnm->vlib_main, hi->tx_node_index,
882 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
884 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
887 *tunnel_sw_if_index = hi->sw_if_index;
888 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
889 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
891 tp->hw_if_index = hw_if_index;
894 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
895 tp->intfc_address.as_u32 = intfc->as_u32;
896 tp->mask_width = mask_width;
897 tp->inner_fib_index = inner_fib_index;
898 tp->encap_index = e - mm->encaps;
899 tp->tx_sw_if_index = tx_sw_if_index;
900 tp->l2_only = l2_only;
901 tp->fei = FIB_NODE_INDEX_INVALID;
903 if (new_tunnel_index)
904 *new_tunnel_index = tp - mm->eth_tunnels;
910 const fib_prefix_t pfx = {
912 .ip4 = tp->intfc_address,
914 .fp_len = tp->mask_width,
915 .fp_proto = FIB_PROTOCOL_IP4,
917 dpo_id_t dpo = DPO_INVALID;
924 classify_dpo_create(DPO_PROTO_IP4,
925 classify_table_index));
927 tp->fei = fib_table_entry_special_dpo_add(tp->inner_fib_index,
930 FIB_ENTRY_FLAG_EXCLUSIVE,
936 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
937 tp->fei = FIB_NODE_INDEX_INVALID;
940 if (is_add == 0 && found_tunnel)
942 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
943 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
945 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
946 pool_put (mm->eth_tunnels, tp);
952 static clib_error_t *
953 create_mpls_ethernet_policy_tunnel_command_fn (vlib_main_t * vm,
954 unformat_input_t * input,
955 vlib_cli_command_t * cmd)
957 unformat_input_t _line_input, * line_input = &_line_input;
958 vnet_main_t * vnm = vnet_get_main();
962 int dst_set = 0, intfc_set = 0;
964 u32 inner_fib_id = (u32)~0;
965 u32 classify_table_index = (u32)~0;
966 u32 new_tunnel_index;
972 /* Get a line of input. */
973 if (! unformat_user (input, unformat_line_input, line_input))
976 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
978 if (unformat (line_input, "dst %U",
979 unformat_ethernet_address, &dst))
981 else if (unformat (line_input, "adj %U/%d",
982 unformat_ip4_address, &intfc, &mask_width))
984 else if (unformat (line_input, "tx-intfc %U",
985 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
987 else if (unformat (line_input, "classify-table-index %d",
988 &classify_table_index))
990 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
992 else if (unformat (line_input, "l2-only"))
994 else if (unformat (line_input, "del"))
997 return clib_error_return (0, "unknown input '%U'",
998 format_unformat_error, line_input);
1001 if (classify_table_index == ~0)
1002 return clib_error_return (0, "missing classify_table_index");
1005 return clib_error_return (0, "missing tx-intfc");
1008 return clib_error_return (0, "missing: dst <ethernet-address>");
1011 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1014 rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
1015 inner_fib_id, tx_sw_if_index,
1016 0 /* tunnel sw_if_index */,
1017 classify_table_index,
1024 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), new_tunnel_index);
1026 case VNET_API_ERROR_NO_SUCH_FIB:
1027 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1030 case VNET_API_ERROR_NO_SUCH_ENTRY:
1031 return clib_error_return (0, "tunnel not found\n");
1033 case VNET_API_ERROR_NO_SUCH_LABEL:
1035 * This happens when there's no MPLS label for the dst address
1036 * no need for two error messages.
1038 return clib_error_return (0, "no label for %U in fib %d",
1039 format_ip4_address, &intfc, inner_fib_id);
1043 return clib_error_return (0, "vnet_mpls_ethernet_add_del_policy_tunnel returned %d", rv);
1050 VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
1051 .path = "create mpls ethernet policy tunnel",
1053 "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
1054 " classify-table-index <nn>",
1055 .function = create_mpls_ethernet_policy_tunnel_command_fn,
1058 static clib_error_t *
1059 mpls_interface_enable_disable (vlib_main_t * vm,
1060 unformat_input_t * input,
1061 vlib_cli_command_t * cmd)
1063 vnet_main_t * vnm = vnet_get_main();
1064 clib_error_t * error = 0;
1065 u32 sw_if_index, enable;
1069 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1071 error = clib_error_return (0, "unknown interface `%U'",
1072 format_unformat_error, input);
1076 if (unformat (input, "enable"))
1078 else if (unformat (input, "disable"))
1082 error = clib_error_return (0, "expected 'enable' or 'disable'",
1083 format_unformat_error, input);
1087 mpls_sw_interface_enable_disable(&mpls_main, sw_if_index, enable);
1093 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
1094 .path = "set interface mpls",
1095 .function = mpls_interface_enable_disable,
1096 .short_help = "Enable/Disable an interface for MPLS forwarding",