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/gre/gre.h>
21 #include <vnet/mpls/mpls.h>
22 #include <vnet/fib/ip4_fib.h>
23 #include <vnet/adj/adj_midchain.h>
24 #include <vnet/dpo/classify_dpo.h>
26 /* manually added to the interface output node */
27 #define MPLS_GRE_OUTPUT_NEXT_POST_REWRITE 1
30 mpls_gre_interface_tx (vlib_main_t * vm,
31 vlib_node_runtime_t * node,
34 mpls_main_t * gm = &mpls_main;
35 vnet_main_t * vnm = gm->vnet_main;
37 u32 * from, * to_next, n_left_from, n_left_to_next;
39 /* Vector of buffer / pkt indices we're supposed to process */
40 from = vlib_frame_vector_args (frame);
42 /* Number of buffers / pkts */
43 n_left_from = frame->n_vectors;
45 /* Speculatively send the first buffer to the last disposition we used */
46 next_index = node->cached_next_index;
48 while (n_left_from > 0)
50 /* set up to enqueue to our disposition with index = next_index */
51 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
54 * As long as we have enough pkts left to process two pkts
55 * and prefetch two pkts...
57 while (n_left_from >= 4 && n_left_to_next >= 2)
59 vlib_buffer_t * b0, * b1;
60 u32 bi0, next0, bi1, next1;
61 mpls_gre_tunnel_t * t0, * t1;
62 u32 sw_if_index0, sw_if_index1;
63 vnet_hw_interface_t * hi0, * hi1;
66 /* Prefetch the next iteration */
68 vlib_buffer_t * p2, * p3;
70 p2 = vlib_get_buffer (vm, from[2]);
71 p3 = vlib_get_buffer (vm, from[3]);
73 vlib_prefetch_buffer_header (p2, LOAD);
74 vlib_prefetch_buffer_header (p3, LOAD);
77 * Prefetch packet data. We expect to overwrite
78 * the inbound L2 header with an ip header and a
79 * gre header. Might want to prefetch the last line
80 * of rewrite space as well; need profile data
82 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
83 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
86 /* Pick up the next two buffer indices */
90 /* Speculatively enqueue them where we sent the last buffer */
98 b0 = vlib_get_buffer (vm, bi0);
99 b1 = vlib_get_buffer (vm, bi1);
101 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
102 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
105 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
106 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
108 /* hw_instance = tunnel pool index */
109 t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance);
110 t1 = pool_elt_at_index (gm->gre_tunnels, hi1->hw_instance);
112 /* Apply rewrite - $$$$$ fixme don't use memcpy */
113 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
114 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
116 dst0 = vlib_buffer_get_current (b0);
117 dst1 = vlib_buffer_get_current (b1);
119 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
120 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
122 /* Fix TX fib indices */
123 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
124 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->outer_fib_index;
126 /* mpls-post-rewrite takes it from here... */
127 next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
128 next1 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
130 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
132 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
134 tr->tunnel_id = t0 - gm->gre_tunnels;
135 tr->length = b0->current_length;
136 tr->src.as_u32 = t0->tunnel_src.as_u32;
137 tr->dst.as_u32 = t0->tunnel_dst.as_u32;
139 tr->mpls_encap_index = t0->encap_index;
141 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
143 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
145 tr->tunnel_id = t1 - gm->gre_tunnels;
146 tr->length = b1->current_length;
147 tr->src.as_u32 = t1->tunnel_src.as_u32;
148 tr->dst.as_u32 = t1->tunnel_dst.as_u32;
150 tr->mpls_encap_index = t1->encap_index;
153 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
154 to_next, n_left_to_next,
155 bi0, bi1, next0, next1);
158 while (n_left_from > 0 && n_left_to_next > 0)
162 mpls_gre_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->gre_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 fib index */
190 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
192 /* mpls-post-rewrite takes it from here... */
193 next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
195 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
197 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
199 tr->tunnel_id = t0 - gm->gre_tunnels;
200 tr->length = b0->current_length;
201 tr->src.as_u32 = t0->tunnel_src.as_u32;
202 tr->dst.as_u32 = t0->tunnel_dst.as_u32;
204 tr->mpls_encap_index = t0->encap_index;
207 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
208 to_next, n_left_to_next,
212 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
215 vlib_node_increment_counter (vm, gre_input_node.index,
216 GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
218 return frame->n_vectors;
221 static u8 * format_mpls_gre_tunnel_name (u8 * s, va_list * args)
223 u32 dev_instance = va_arg (*args, u32);
224 return format (s, "mpls-gre%d", dev_instance);
227 static u8 * format_mpls_gre_device (u8 * s, va_list * args)
229 u32 dev_instance = va_arg (*args, u32);
230 CLIB_UNUSED (int verbose) = va_arg (*args, int);
232 s = format (s, "MPLS-GRE tunnel: id %d\n", dev_instance);
236 VNET_DEVICE_CLASS (mpls_gre_device_class) = {
237 .name = "MPLS-GRE tunnel device",
238 .format_device_name = format_mpls_gre_tunnel_name,
239 .format_device = format_mpls_gre_device,
240 .format_tx_trace = format_mpls_gre_tx_trace,
241 .tx_function = mpls_gre_interface_tx,
242 .no_flatten_output_chains = 1,
245 .admin_up_down_function = 0;
249 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_gre_device_class,
250 mpls_gre_interface_tx)
252 VNET_HW_INTERFACE_CLASS (mpls_gre_hw_interface_class) = {
254 .format_header = format_mpls_gre_header_with_length,
256 .unformat_header = unformat_mpls_gre_header,
258 .build_rewrite = default_build_rewrite,
259 .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
262 /* manually added to the interface output node */
263 #define MPLS_ETH_OUTPUT_NEXT_OUTPUT 1
266 mpls_eth_interface_tx (vlib_main_t * vm,
267 vlib_node_runtime_t * node,
268 vlib_frame_t * frame)
270 mpls_main_t * gm = &mpls_main;
271 vnet_main_t * vnm = gm->vnet_main;
273 u32 * from, * to_next, n_left_from, n_left_to_next;
275 /* Vector of buffer / pkt indices we're supposed to process */
276 from = vlib_frame_vector_args (frame);
278 /* Number of buffers / pkts */
279 n_left_from = frame->n_vectors;
281 /* Speculatively send the first buffer to the last disposition we used */
282 next_index = node->cached_next_index;
284 while (n_left_from > 0)
286 /* set up to enqueue to our disposition with index = next_index */
287 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
290 * As long as we have enough pkts left to process two pkts
291 * and prefetch two pkts...
293 while (n_left_from >= 4 && n_left_to_next >= 2)
295 vlib_buffer_t * b0, * b1;
296 u32 bi0, next0, bi1, next1;
297 mpls_eth_tunnel_t * t0, * t1;
298 u32 sw_if_index0, sw_if_index1;
299 vnet_hw_interface_t * hi0, * hi1;
302 /* Prefetch the next iteration */
304 vlib_buffer_t * p2, * p3;
306 p2 = vlib_get_buffer (vm, from[2]);
307 p3 = vlib_get_buffer (vm, from[3]);
309 vlib_prefetch_buffer_header (p2, LOAD);
310 vlib_prefetch_buffer_header (p3, LOAD);
313 * Prefetch packet data. We expect to overwrite
314 * the inbound L2 header with an ip header and a
315 * gre header. Might want to prefetch the last line
316 * of rewrite space as well; need profile data
318 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
319 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
322 /* Pick up the next two buffer indices */
326 /* Speculatively enqueue them where we sent the last buffer */
334 b0 = vlib_get_buffer (vm, bi0);
335 b1 = vlib_get_buffer (vm, bi1);
337 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
338 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
341 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
342 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
344 /* hw_instance = tunnel pool index */
345 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
346 t1 = pool_elt_at_index (gm->eth_tunnels, hi1->hw_instance);
348 /* Apply rewrite - $$$$$ fixme don't use memcpy */
349 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
350 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
352 dst0 = vlib_buffer_get_current (b0);
353 dst1 = vlib_buffer_get_current (b1);
355 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
356 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
358 /* Fix TX fib indices */
359 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
360 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->tx_sw_if_index;
362 /* mpls-post-rewrite takes it from here... */
363 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
364 next1 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
366 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
368 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
371 tr->tunnel_id = t0 - gm->eth_tunnels;
372 tr->tx_sw_if_index = t0->tx_sw_if_index;
373 tr->mpls_encap_index = t0->encap_index;
374 tr->length = b0->current_length;
375 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
376 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
378 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
380 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
383 tr->tunnel_id = t1 - gm->eth_tunnels;
384 tr->tx_sw_if_index = t1->tx_sw_if_index;
385 tr->mpls_encap_index = t1->encap_index;
386 tr->length = b1->current_length;
387 hi1 = vnet_get_sup_hw_interface (vnm, t1->tx_sw_if_index);
388 clib_memcpy (tr->dst, hi1->hw_address, sizeof (tr->dst));
391 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
392 to_next, n_left_to_next,
393 bi0, bi1, next0, next1);
395 while (n_left_from > 0 && n_left_to_next > 0)
399 mpls_eth_tunnel_t * t0;
401 vnet_hw_interface_t * hi0;
411 b0 = vlib_get_buffer (vm, bi0);
413 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
415 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
417 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
419 /* Apply rewrite - $$$$$ fixme don't use memcpy */
420 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
422 dst0 = vlib_buffer_get_current (b0);
424 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
426 /* Fix the TX interface */
427 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
429 /* Send the packet */
430 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
432 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
434 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
437 tr->tunnel_id = t0 - gm->eth_tunnels;
438 tr->tx_sw_if_index = t0->tx_sw_if_index;
439 tr->mpls_encap_index = t0->encap_index;
440 tr->length = b0->current_length;
441 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
442 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
445 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
446 to_next, n_left_to_next,
450 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
453 vlib_node_increment_counter (vm, mpls_input_node.index,
454 MPLS_ERROR_PKTS_ENCAP, frame->n_vectors);
456 return frame->n_vectors;
459 static u8 * format_mpls_eth_tunnel_name (u8 * s, va_list * args)
461 u32 dev_instance = va_arg (*args, u32);
462 return format (s, "mpls-eth%d", dev_instance);
465 static u8 * format_mpls_eth_device (u8 * s, va_list * args)
467 u32 dev_instance = va_arg (*args, u32);
468 CLIB_UNUSED (int verbose) = va_arg (*args, int);
470 s = format (s, "MPLS-ETH tunnel: id %d\n", dev_instance);
474 VNET_DEVICE_CLASS (mpls_eth_device_class) = {
475 .name = "MPLS-ETH tunnel device",
476 .format_device_name = format_mpls_eth_tunnel_name,
477 .format_device = format_mpls_eth_device,
478 .format_tx_trace = format_mpls_eth_tx_trace,
479 .tx_function = mpls_eth_interface_tx,
480 .no_flatten_output_chains = 1,
483 .admin_up_down_function = 0;
487 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_eth_device_class,
488 mpls_eth_interface_tx)
490 VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = {
492 .format_header = format_mpls_eth_header_with_length,
494 .unformat_header = unformat_mpls_eth_header,
496 .build_rewrite = default_build_rewrite,
497 .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
501 * A conversion of DPO next object tpyes to VLIB graph next nodes from
502 * the mpls_post_rewrite node
504 static const int dpo_next_2_mpls_post_rewrite[DPO_LAST] = {
505 [DPO_LOAD_BALANCE] = IP_LOOKUP_NEXT_LOAD_BALANCE,
509 mpls_gre_fixup (vlib_main_t *vm,
515 ip0 = vlib_buffer_get_current (b0);
517 /* Fixup the checksum and len fields in the GRE tunnel encap
518 * that was applied at the midchain node */
519 ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
520 ip0->checksum = ip4_header_checksum (ip0);
523 static u8 * mpls_gre_rewrite (mpls_main_t *mm, mpls_gre_tunnel_t * t)
526 ip4_gre_and_mpls_header_t * h0;
527 u8 * rewrite_data = 0;
529 mpls_unicast_header_t *lp0;
532 /* look up the encap label stack using the RX FIB */
533 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index, t->tunnel_dst.as_u32);
537 clib_warning ("no label for inner fib index %d, dst %U",
538 t->inner_fib_index, format_ip4_address,
543 vec_validate (rewrite_data, sizeof (*h0)
544 + sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
545 memset (rewrite_data, 0, sizeof (*h0));
547 h0 = (ip4_gre_and_mpls_header_t *) rewrite_data;
548 /* Copy the encap label stack */
550 for (i = 0; i < vec_len(e->labels); i++)
551 lp0[i] = e->labels[i];
553 h0->gre.protocol = clib_host_to_net_u16(GRE_PROTOCOL_mpls_unicast);
554 ip0->ip_version_and_header_length = 0x45;
556 ip0->protocol = IP_PROTOCOL_GRE;
557 /* $$$ fixup ip4 header length and checksum after-the-fact */
558 ip0->src_address.as_u32 = t->tunnel_src.as_u32;
559 ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
560 ip0->checksum = ip4_header_checksum (ip0);
562 return (rewrite_data);
566 mpls_sw_interface_is_enabled (u32 sw_if_index)
568 mpls_main_t * mm = &mpls_main;
570 if (vec_len(mm->mpls_enabled_by_sw_if_index) < sw_if_index)
573 return (mm->mpls_enabled_by_sw_if_index[sw_if_index]);
577 mpls_sw_interface_enable_disable (mpls_main_t * mm,
581 vlib_main_t * vm = vlib_get_main();
582 ip_config_main_t * cm = &mm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
583 vnet_config_main_t * vcm = &cm->config_main;
584 u32 lookup_feature_index;
585 fib_node_index_t lfib_index;
588 vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
591 * enable/disable only on the 1<->0 transition
595 if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
598 lfib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS,
599 MPLS_FIB_DEFAULT_TABLE_ID);
600 vec_validate(mm->fib_index_by_sw_if_index, 0);
601 mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
605 ASSERT(mm->mpls_enabled_by_sw_if_index[sw_if_index] > 0);
606 if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
609 fib_table_unlock(mm->fib_index_by_sw_if_index[sw_if_index],
613 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
614 ci = cm->config_index_by_sw_if_index[sw_if_index];
616 lookup_feature_index = mm->mpls_rx_feature_lookup;
619 ci = vnet_config_add_feature (vm, vcm,
621 lookup_feature_index,
623 /* # bytes of config data */ 0);
625 ci = vnet_config_del_feature (vm, vcm, ci,
626 lookup_feature_index,
628 /* # bytes of config data */ 0);
630 cm->config_index_by_sw_if_index[sw_if_index] = ci;
633 static mpls_gre_tunnel_t *
634 mpls_gre_tunnel_from_fib_node (fib_node_t *node)
637 ASSERT(FIB_NODE_TYPE_MPLS_GRE_TUNNEL == node->fn_type);
639 return ((mpls_gre_tunnel_t*)node);
643 * mpls_gre_tunnel_stack
645 * 'stack' (resolve the recursion for) the tunnel's midchain adjacency
648 mpls_gre_tunnel_stack (mpls_gre_tunnel_t *mgt)
651 * find the adjacency that is contributed by the FIB entry
652 * that this tunnel resovles via, and use it as the next adj
655 adj_nbr_midchain_stack(mgt->adj_index,
656 fib_entry_contribute_ip_forwarding(mgt->fei));
660 * Function definition to backwalk a FIB node
662 static fib_node_back_walk_rc_t
663 mpls_gre_tunnel_back_walk (fib_node_t *node,
664 fib_node_back_walk_ctx_t *ctx)
666 mpls_gre_tunnel_stack(mpls_gre_tunnel_from_fib_node(node));
668 return (FIB_NODE_BACK_WALK_CONTINUE);
672 * Function definition to get a FIB node from its index
675 mpls_gre_tunnel_fib_node_get (fib_node_index_t index)
677 mpls_gre_tunnel_t * mgt;
681 mgt = pool_elt_at_index(mm->gre_tunnels, index);
683 return (&mgt->mgt_node);
687 * Function definition to inform the FIB node that its last lock has gone.
690 mpls_gre_tunnel_last_lock_gone (fib_node_t *node)
693 * The MPLS GRE tunnel is a root of the graph. As such
694 * it never has children and thus is never locked.
700 * Virtual function table registered by MPLS GRE tunnels
701 * for participation in the FIB object graph.
703 const static fib_node_vft_t mpls_gre_vft = {
704 .fnv_get = mpls_gre_tunnel_fib_node_get,
705 .fnv_last_lock = mpls_gre_tunnel_last_lock_gone,
706 .fnv_back_walk = mpls_gre_tunnel_back_walk,
709 static mpls_gre_tunnel_t *
710 mpls_gre_tunnel_find (ip4_address_t *src,
712 ip4_address_t *intfc,
715 mpls_main_t * mm = &mpls_main;
716 mpls_gre_tunnel_t *tp;
717 int found_tunnel = 0;
719 /* suppress duplicate mpls interface generation. */
720 pool_foreach (tp, mm->gre_tunnels,
723 * If we have a tunnel which matches (src, dst, intfc/mask)
724 * AND the expected route is in the FIB, it's a dup
726 if (!memcmp (&tp->tunnel_src, src, sizeof (*src))
727 && !memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
728 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
729 && tp->inner_fib_index == inner_fib_index)
744 int mpls_gre_tunnel_add (ip4_address_t *src,
746 ip4_address_t *intfc,
750 u32 * tunnel_sw_if_index,
753 mpls_main_t * mm = &mpls_main;
754 gre_main_t * gm = &gre_main;
755 vnet_main_t * vnm = vnet_get_main();
756 mpls_gre_tunnel_t *tp;
759 mpls_encap_t * e = 0;
760 u32 hw_if_index = ~0;
761 vnet_hw_interface_t * hi;
763 const ip46_address_t zero_nh = {
767 tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index);
771 return VNET_API_ERROR_NO_SUCH_ENTRY;
773 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, dst->as_u32);
775 return VNET_API_ERROR_NO_SUCH_LABEL;
777 pool_get(mm->gre_tunnels, tp);
778 memset (tp, 0, sizeof (*tp));
779 fib_node_init(&tp->mgt_node,
780 FIB_NODE_TYPE_MPLS_GRE_TUNNEL);
782 if (vec_len (mm->free_gre_sw_if_indices) > 0)
785 mm->free_gre_sw_if_indices[vec_len(mm->free_gre_sw_if_indices)-1];
786 _vec_len (mm->free_gre_sw_if_indices) -= 1;
787 hi = vnet_get_hw_interface (vnm, hw_if_index);
788 hi->dev_instance = tp - mm->gre_tunnels;
789 hi->hw_instance = tp - mm->gre_tunnels;
793 hw_if_index = vnet_register_interface
794 (vnm, mpls_gre_device_class.index, tp - mm->gre_tunnels,
795 mpls_gre_hw_interface_class.index,
796 tp - mm->gre_tunnels);
797 hi = vnet_get_hw_interface (vnm, hw_if_index);
799 /* ... to make the IP and L2 x-connect cases identical */
800 slot = vlib_node_add_named_next_with_slot
801 (vnm->vlib_main, hi->tx_node_index,
802 "mpls-post-rewrite", MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
804 ASSERT (slot == MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
807 *tunnel_sw_if_index = hi->sw_if_index;
808 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
809 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
810 vec_validate(ip4_main.fib_index_by_sw_if_index, *tunnel_sw_if_index);
811 ip4_main.fib_index_by_sw_if_index[*tunnel_sw_if_index] = outer_fib_index;
813 tp->hw_if_index = hw_if_index;
815 /* bind the MPLS and IPv4 FIBs to the interface and enable */
816 vec_validate(mm->fib_index_by_sw_if_index, hi->sw_if_index);
817 mm->fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index;
818 mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 1);
819 ip4_main.fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index;
820 ip4_sw_interface_enable_disable(hi->sw_if_index, 1);
822 tp->tunnel_src.as_u32 = src->as_u32;
823 tp->tunnel_dst.as_u32 = dst->as_u32;
824 tp->intfc_address.as_u32 = intfc->as_u32;
825 tp->mask_width = mask_width;
826 tp->inner_fib_index = inner_fib_index;
827 tp->outer_fib_index = outer_fib_index;
828 tp->encap_index = e - mm->encaps;
829 tp->l2_only = l2_only;
831 /* Add the tunnel to the hash table of all GRE tunnels */
832 u64 key = (u64)src->as_u32 << 32 | (u64)dst->as_u32;
834 ASSERT(NULL == hash_get (gm->tunnel_by_key, key));
835 hash_set (gm->tunnel_by_key, key, tp - mm->gre_tunnels);
837 /* Create the adjacency and add to v4 fib */
838 memset(&adj, 0, sizeof (adj));
839 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
841 rewrite_data = mpls_gre_rewrite (mm, tp);
842 if (rewrite_data == 0)
844 if (*tunnel_sw_if_index != ~0)
846 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
847 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
849 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
851 pool_put (mm->gre_tunnels, tp);
852 return VNET_API_ERROR_NO_SUCH_LABEL;
855 /* Save a copy of the rewrite data for L2 x-connect */
856 vec_free (tp->rewrite_data);
858 tp->rewrite_data = rewrite_data;
863 * source the FIB entry for the tunnel's destination
864 * and become a child thereof. The tunnel will then get poked
865 * when the forwarding for the entry updates, and the tunnel can
866 * re-stack accordingly
868 const fib_prefix_t tun_dst_pfx = {
870 .fp_proto = FIB_PROTOCOL_IP4,
876 tp->fei = fib_table_entry_special_add(outer_fib_index,
881 tp->sibling_index = fib_entry_child_add(tp->fei,
882 FIB_NODE_TYPE_MPLS_GRE_TUNNEL,
883 tp - mm->gre_tunnels);
886 * create and update the midchain adj this tunnel sources.
887 * This is the adj the route we add below will resolve to.
889 tp->adj_index = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
894 adj_nbr_midchain_update_rewrite(tp->adj_index,
896 ADJ_MIDCHAIN_FLAG_NONE,
898 mpls_gre_tunnel_stack(tp);
901 * Update the route for the tunnel's subnet to point through the tunnel
903 const fib_prefix_t tun_sub_net_pfx = {
904 .fp_len = tp->mask_width,
905 .fp_proto = FIB_PROTOCOL_IP4,
907 .ip4 = tp->intfc_address,
911 fib_table_entry_update_one_path(inner_fib_index,
913 FIB_SOURCE_INTERFACE,
914 (FIB_ENTRY_FLAG_CONNECTED |
915 FIB_ENTRY_FLAG_ATTACHED),
919 ~0, // invalid fib index
922 FIB_ROUTE_PATH_FLAG_NONE);
929 mpls_gre_tunnel_del (ip4_address_t *src,
931 ip4_address_t *intfc,
935 u32 * tunnel_sw_if_index,
938 mpls_main_t * mm = &mpls_main;
939 vnet_main_t * vnm = vnet_get_main();
940 gre_main_t * gm = &gre_main;
941 mpls_gre_tunnel_t *tp;
942 vnet_hw_interface_t * hi;
944 tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index);
946 /* Delete, and we can't find the tunnel */
948 return VNET_API_ERROR_NO_SUCH_ENTRY;
950 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
955 * unsource the FIB entry for the tunnel's destination
957 const fib_prefix_t tun_dst_pfx = {
959 .fp_proto = FIB_PROTOCOL_IP4,
965 fib_entry_child_remove(tp->fei,
967 fib_table_entry_special_remove(outer_fib_index,
970 tp->fei = FIB_NODE_INDEX_INVALID;
971 adj_unlock(tp->adj_index);
974 * unsource the route for the tunnel's subnet
976 const fib_prefix_t tun_sub_net_pfx = {
977 .fp_len = tp->mask_width,
978 .fp_proto = FIB_PROTOCOL_IP4,
980 .ip4 = tp->intfc_address,
984 fib_table_entry_delete(inner_fib_index,
986 FIB_SOURCE_INTERFACE);
989 u64 key = ((u64)tp->tunnel_src.as_u32 << 32 |
990 (u64)tp->tunnel_src.as_u32);
992 hash_unset (gm->tunnel_by_key, key);
993 mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 0);
994 ip4_sw_interface_enable_disable(hi->sw_if_index, 0);
996 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
998 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
999 vec_free (tp->rewrite_data);
1000 fib_node_deinit(&tp->mgt_node);
1001 pool_put (mm->gre_tunnels, tp);
1007 vnet_mpls_gre_add_del_tunnel (ip4_address_t *src,
1009 ip4_address_t *intfc,
1011 u32 inner_fib_id, u32 outer_fib_id,
1012 u32 * tunnel_sw_if_index,
1016 u32 inner_fib_index = 0;
1017 u32 outer_fib_index = 0;
1019 ip4_main_t * im = &ip4_main;
1021 /* No questions, no answers */
1022 if (NULL == tunnel_sw_if_index)
1023 tunnel_sw_if_index = &dummy;
1025 *tunnel_sw_if_index = ~0;
1027 if (inner_fib_id != (u32)~0)
1031 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1033 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
1034 inner_fib_index = p[0];
1037 if (outer_fib_id != 0)
1041 p = hash_get (im->fib_index_by_table_id, outer_fib_id);
1043 return VNET_API_ERROR_NO_SUCH_FIB;
1044 outer_fib_index = p[0];
1049 return (mpls_gre_tunnel_add(src,dst,intfc, mask_width,
1057 return (mpls_gre_tunnel_del(src,dst,intfc, mask_width,
1066 * Remove all mpls tunnels in the specified fib
1068 int vnet_mpls_gre_delete_fib_tunnels (u32 fib_id)
1070 mpls_main_t * mm = &mpls_main;
1071 vnet_main_t * vnm = mm->vnet_main;
1072 mpls_gre_tunnel_t *tp;
1074 u32 * tunnels_to_delete = 0;
1075 vnet_hw_interface_t * hi;
1078 fib_index = ip4_fib_index_from_table_id(fib_id);
1079 if (~0 == fib_index)
1080 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
1082 pool_foreach (tp, mm->gre_tunnels,
1084 if (tp->inner_fib_index == fib_index)
1085 vec_add1 (tunnels_to_delete, tp - mm->gre_tunnels);
1088 for (i = 0; i < vec_len(tunnels_to_delete); i++) {
1089 tp = pool_elt_at_index (mm->gre_tunnels, tunnels_to_delete[i]);
1091 /* Delete, the route if not already gone */
1092 if (FIB_NODE_INDEX_INVALID != tp->fei && !tp->l2_only)
1094 const fib_prefix_t tun_dst_pfx = {
1096 .fp_proto = FIB_PROTOCOL_IP4,
1098 .ip4 = tp->tunnel_dst,
1102 fib_entry_child_remove(tp->fei,
1104 fib_table_entry_special_remove(tp->outer_fib_index,
1107 tp->fei = FIB_NODE_INDEX_INVALID;
1108 adj_unlock(tp->adj_index);
1110 const fib_prefix_t tun_sub_net_pfx = {
1111 .fp_len = tp->mask_width,
1112 .fp_proto = FIB_PROTOCOL_IP4,
1114 .ip4 = tp->intfc_address,
1118 fib_table_entry_delete(tp->inner_fib_index,
1120 FIB_SOURCE_INTERFACE);
1123 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1124 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1125 0 /* admin down */);
1126 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
1127 vec_free (tp->rewrite_data);
1128 pool_put (mm->gre_tunnels, tp);
1131 vec_free(tunnels_to_delete);
1136 static clib_error_t *
1137 create_mpls_gre_tunnel_command_fn (vlib_main_t * vm,
1138 unformat_input_t * input,
1139 vlib_cli_command_t * cmd)
1141 unformat_input_t _line_input, * line_input = &_line_input;
1142 ip4_address_t src, dst, intfc;
1143 int src_set = 0, dst_set = 0, intfc_set = 0;
1145 u32 inner_fib_id = (u32)~0;
1146 u32 outer_fib_id = 0;
1150 u32 tunnel_intfc_sw_if_index = ~0;
1152 /* Get a line of input. */
1153 if (! unformat_user (input, unformat_line_input, line_input))
1156 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1158 if (unformat (line_input, "src %U",
1159 unformat_ip4_address, &src))
1161 else if (unformat (line_input, "dst %U",
1162 unformat_ip4_address, &dst))
1164 else if (unformat (line_input, "intfc %U/%d",
1165 unformat_ip4_address, &intfc, &mask_width))
1167 else if (unformat (line_input, "inner-fib-id %d", &inner_fib_id))
1169 else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
1171 else if (unformat (line_input, "del"))
1173 else if (unformat (line_input, "l2-only"))
1176 return clib_error_return (0, "unknown input '%U'",
1177 format_unformat_error, line_input);
1181 return clib_error_return (0, "missing: src <ip-address>");
1184 return clib_error_return (0, "missing: dst <ip-address>");
1187 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1190 rv = vnet_mpls_gre_add_del_tunnel (&src, &dst, &intfc, mask_width,
1191 inner_fib_id, outer_fib_id,
1192 &tunnel_intfc_sw_if_index,
1199 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), tunnel_intfc_sw_if_index);
1202 case VNET_API_ERROR_NO_SUCH_INNER_FIB:
1203 return clib_error_return (0, "inner fib ID %d doesn't exist\n",
1205 case VNET_API_ERROR_NO_SUCH_FIB:
1206 return clib_error_return (0, "outer fib ID %d doesn't exist\n",
1209 case VNET_API_ERROR_NO_SUCH_ENTRY:
1210 return clib_error_return (0, "tunnel not found\n");
1212 case VNET_API_ERROR_NO_SUCH_LABEL:
1214 * This happens when there's no MPLS label for the dst address
1215 * no need for two error messages.
1220 return clib_error_return (0, "vnet_mpls_gre_add_del_tunnel returned %d",
1226 VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
1227 .path = "create mpls gre tunnel",
1229 "create mpls gre tunnel [del] src <addr> dst <addr> intfc <addr>/<mw>",
1230 .function = create_mpls_gre_tunnel_command_fn,
1233 u8 * format_mpls_encap_index (u8 * s, va_list * args)
1235 mpls_main_t * mm = va_arg (*args, mpls_main_t *);
1236 u32 entry_index = va_arg (*args, u32);
1240 e = pool_elt_at_index (mm->encaps, entry_index);
1242 for (i = 0; i < vec_len (e->labels); i++)
1244 (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
1245 (e->labels[i].label_exp_s_ttl)));
1250 u8 * format_mpls_gre_tunnel (u8 * s, va_list * args)
1252 mpls_gre_tunnel_t * t = va_arg (*args, mpls_gre_tunnel_t *);
1253 mpls_main_t * mm = &mpls_main;
1255 if (t->l2_only == 0)
1257 s = format (s, "[%d]: src %U, dst %U, adj %U/%d, labels %U\n",
1258 t - mm->gre_tunnels,
1259 format_ip4_address, &t->tunnel_src,
1260 format_ip4_address, &t->tunnel_dst,
1261 format_ip4_address, &t->intfc_address,
1263 format_mpls_encap_index, mm, t->encap_index);
1265 s = format (s, " inner fib index %d, outer fib index %d",
1266 t->inner_fib_index, t->outer_fib_index);
1270 s = format (s, "[%d]: src %U, dst %U, key %U, labels %U\n",
1271 t - mm->gre_tunnels,
1272 format_ip4_address, &t->tunnel_src,
1273 format_ip4_address, &t->tunnel_dst,
1274 format_ip4_address, &t->intfc_address,
1275 format_mpls_encap_index, mm, t->encap_index);
1277 s = format (s, " l2 interface %d, outer fib index %d",
1278 t->hw_if_index, t->outer_fib_index);
1284 u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
1286 mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
1287 mpls_main_t * mm = &mpls_main;
1289 s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
1290 t - mm->eth_tunnels,
1291 format_ethernet_address, &t->tunnel_dst,
1292 format_ip4_address, &t->intfc_address,
1294 format_mpls_encap_index, mm, t->encap_index);
1297 s = format (s, " tx on %U, rx fib index %d",
1298 format_vnet_sw_if_index_name, mm->vnet_main, t->tx_sw_if_index,
1299 t->inner_fib_index);
1304 static clib_error_t *
1305 show_mpls_tunnel_command_fn (vlib_main_t * vm,
1306 unformat_input_t * input,
1307 vlib_cli_command_t * cmd)
1309 mpls_main_t * mm = &mpls_main;
1310 mpls_gre_tunnel_t * gt;
1311 mpls_eth_tunnel_t * et;
1313 if (pool_elts (mm->gre_tunnels))
1315 vlib_cli_output (vm, "MPLS-GRE tunnels");
1316 pool_foreach (gt, mm->gre_tunnels,
1318 vlib_cli_output (vm, "%U", format_mpls_gre_tunnel, gt);
1322 vlib_cli_output (vm, "No MPLS-GRE tunnels");
1324 if (pool_elts (mm->eth_tunnels))
1326 vlib_cli_output (vm, "MPLS-Ethernet tunnels");
1327 pool_foreach (et, mm->eth_tunnels,
1329 vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
1333 vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
1338 VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
1339 .path = "show mpls tunnel",
1340 .short_help = "show mpls tunnel",
1341 .function = show_mpls_tunnel_command_fn,
1345 /* force inclusion from application's main.c */
1346 clib_error_t *mpls_interface_init (vlib_main_t *vm)
1348 clib_error_t * error;
1350 fib_node_register_type(FIB_NODE_TYPE_MPLS_GRE_TUNNEL,
1353 if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
1358 VLIB_INIT_FUNCTION(mpls_interface_init);
1361 static u8 * mpls_ethernet_rewrite (mpls_main_t *mm, mpls_eth_tunnel_t * t)
1363 u8 * rewrite_data = 0;
1365 mpls_unicast_header_t *lp0;
1368 /* look up the encap label stack using the RX FIB and adjacency address*/
1369 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index,
1370 t->intfc_address.as_u32);
1374 clib_warning ("no label for inner fib index %d, dst %U",
1375 t->inner_fib_index, format_ip4_address,
1380 vec_validate (rewrite_data,
1381 sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
1383 /* Copy the encap label stack */
1384 lp0 = (mpls_unicast_header_t *) rewrite_data;
1386 for (i = 0; i < vec_len(e->labels); i++)
1387 lp0[i] = e->labels[i];
1389 return (rewrite_data);
1392 int vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
1393 ip4_address_t *intfc,
1397 u32 * tunnel_sw_if_index,
1401 ip4_main_t * im = &ip4_main;
1402 ip_lookup_main_t * lm = &im->lookup_main;
1403 mpls_main_t * mm = &mpls_main;
1404 vnet_main_t * vnm = vnet_get_main();
1405 mpls_eth_tunnel_t *tp;
1406 u32 inner_fib_index = 0;
1410 int found_tunnel = 0;
1411 mpls_encap_t * e = 0;
1412 u32 hw_if_index = ~0;
1413 vnet_hw_interface_t * hi;
1417 if (tunnel_sw_if_index == 0)
1418 tunnel_sw_if_index = &dummy;
1420 *tunnel_sw_if_index = ~0;
1422 if (inner_fib_id != (u32)~0)
1426 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1428 return VNET_API_ERROR_NO_SUCH_FIB;
1429 inner_fib_index = p[0];
1432 /* suppress duplicate mpls interface generation. */
1433 pool_foreach (tp, mm->eth_tunnels,
1436 * If we have a tunnel which matches (src, dst, intfc/mask)
1437 * AND the expected route is in the FIB, it's a dup
1439 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1440 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1441 && tp->inner_fib_index == inner_fib_index
1442 && FIB_NODE_INDEX_INVALID != tp->fei)
1452 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
1455 return VNET_API_ERROR_NO_SUCH_LABEL;
1469 /* Delete, and we can't find the tunnel */
1470 if (is_add == 0 && found_tunnel == 0)
1471 return VNET_API_ERROR_NO_SUCH_ENTRY;
1473 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
1475 return VNET_API_ERROR_NO_SUCH_LABEL;
1477 pool_get(mm->eth_tunnels, tp);
1478 memset (tp, 0, sizeof (*tp));
1480 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1483 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1484 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1485 hi = vnet_get_hw_interface (vnm, hw_if_index);
1486 hi->dev_instance = tp - mm->eth_tunnels;
1487 hi->hw_instance = tp - mm->eth_tunnels;
1491 hw_if_index = vnet_register_interface
1492 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1493 mpls_eth_hw_interface_class.index,
1494 tp - mm->eth_tunnels);
1495 hi = vnet_get_hw_interface (vnm, hw_if_index);
1497 /* ... to make the IP and L2 x-connect cases identical */
1498 slot = vlib_node_add_named_next_with_slot
1499 (vnm->vlib_main, hi->tx_node_index,
1500 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1502 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1505 *tunnel_sw_if_index = hi->sw_if_index;
1506 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1507 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1509 tp->hw_if_index = hw_if_index;
1512 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1513 tp->intfc_address.as_u32 = intfc->as_u32;
1514 tp->mask_width = mask_width;
1515 tp->inner_fib_index = inner_fib_index;
1516 tp->encap_index = e - mm->encaps;
1517 tp->tx_sw_if_index = tx_sw_if_index;
1518 tp->l2_only = l2_only;
1520 /* Create the adjacency and add to v4 fib */
1521 memset(&adj, 0, sizeof (adj));
1522 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1524 rewrite_data = mpls_ethernet_rewrite (mm, tp);
1525 if (rewrite_data == 0)
1527 if (*tunnel_sw_if_index != ~0)
1529 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1530 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1531 0 /* admin down */);
1532 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1535 pool_put (mm->eth_tunnels, tp);
1536 return VNET_API_ERROR_NO_SUCH_LABEL;
1539 vnet_rewrite_for_sw_interface
1543 ip4_rewrite_node.index,
1545 &adj.rewrite_header,
1546 sizeof (adj.rewrite_data));
1549 * Prepend the (0,1,2) VLAN tag ethernet header
1550 * we just built to the mpls header stack
1552 vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
1553 clib_memcpy(rewrite_data,
1554 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1555 sizeof (adj.rewrite_data)),
1556 adj.rewrite_header.data_bytes);
1558 vnet_rewrite_set_data_internal (&adj.rewrite_header,
1559 sizeof(adj.rewrite_data),
1561 vec_len(rewrite_data));
1563 vec_free (tp->rewrite_data);
1565 tp->rewrite_data = rewrite_data;
1568 ip_add_adjacency (lm, &adj, 1 /* one adj */,
1575 const fib_prefix_t pfx = {
1577 .ip4 = tp->intfc_address,
1579 .fp_len = tp->mask_width,
1580 .fp_proto = FIB_PROTOCOL_IP4,
1583 tp->fei = fib_table_entry_special_add(tp->inner_fib_index,
1586 FIB_ENTRY_FLAG_NONE,
1590 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
1591 tp->fei = FIB_NODE_INDEX_INVALID;
1594 if (is_add == 0 && found_tunnel)
1596 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1597 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1598 0 /* admin down */);
1599 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1600 vec_free (tp->rewrite_data);
1601 pool_put (mm->eth_tunnels, tp);
1607 static clib_error_t *
1608 create_mpls_ethernet_tunnel_command_fn (vlib_main_t * vm,
1609 unformat_input_t * input,
1610 vlib_cli_command_t * cmd)
1612 unformat_input_t _line_input, * line_input = &_line_input;
1613 vnet_main_t * vnm = vnet_get_main();
1614 ip4_address_t intfc;
1617 int dst_set = 0, intfc_set = 0;
1619 u32 inner_fib_id = (u32)~0;
1624 u32 sw_if_index = ~0;
1626 /* Get a line of input. */
1627 if (! unformat_user (input, unformat_line_input, line_input))
1630 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1632 if (unformat (line_input, "dst %U",
1633 unformat_ethernet_address, &dst))
1635 else if (unformat (line_input, "adj %U/%d",
1636 unformat_ip4_address, &intfc, &mask_width))
1638 else if (unformat (line_input, "tx-intfc %U",
1639 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1641 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1643 else if (unformat (line_input, "l2-only"))
1645 else if (unformat (line_input, "del"))
1648 return clib_error_return (0, "unknown input '%U'",
1649 format_unformat_error, line_input);
1653 return clib_error_return (0, "missing tx-intfc");
1656 return clib_error_return (0, "missing: dst <ethernet-address>");
1659 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1662 rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
1663 inner_fib_id, tx_sw_if_index,
1671 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
1673 case VNET_API_ERROR_NO_SUCH_FIB:
1674 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1677 case VNET_API_ERROR_NO_SUCH_ENTRY:
1678 return clib_error_return (0, "tunnel not found\n");
1680 case VNET_API_ERROR_NO_SUCH_LABEL:
1682 * This happens when there's no MPLS label for the dst address
1683 * no need for two error messages.
1685 return clib_error_return (0, "no label for %U in fib %d",
1686 format_ip4_address, &intfc, inner_fib_id);
1690 return clib_error_return (0, "vnet_mpls_ethernet_add_del_tunnel returned %d", rv);
1697 VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
1698 .path = "create mpls ethernet tunnel",
1700 "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
1701 .function = create_mpls_ethernet_tunnel_command_fn,
1705 int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
1707 u32 policy_tunnel_index)
1709 mpls_eth_tunnel_t * t;
1711 u8 * rewrite_data = 0;
1713 mpls_unicast_header_t *lp;
1716 if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
1717 return VNET_API_ERROR_NO_SUCH_ENTRY;
1719 t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
1721 memset (&adj, 0, sizeof (adj));
1723 /* Build L2 encap */
1724 vnet_rewrite_for_sw_interface
1728 mpls_policy_encap_node.index,
1730 &adj.rewrite_header,
1731 sizeof (adj.rewrite_data));
1733 vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
1735 clib_memcpy(rewrite_data,
1736 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1737 sizeof (adj.rewrite_data)),
1738 adj.rewrite_header.data_bytes);
1740 /* Append the label stack */
1742 vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
1744 lp = (mpls_unicast_header_t *) label_start;
1746 for (i = 0; i < vec_len(e->labels); i++)
1747 lp[i] = e->labels[i];
1749 /* Remember the rewrite data */
1750 e->rewrite = rewrite_data;
1751 e->output_next_index = adj.rewrite_header.next_index;
1756 int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
1757 ip4_address_t *intfc,
1761 u32 * tunnel_sw_if_index,
1762 u32 classify_table_index,
1763 u32 * new_tunnel_index,
1767 ip4_main_t * im = &ip4_main;
1768 mpls_main_t * mm = &mpls_main;
1769 vnet_main_t * vnm = vnet_get_main();
1770 mpls_eth_tunnel_t *tp;
1771 u32 inner_fib_index = 0;
1772 int found_tunnel = 0;
1773 mpls_encap_t * e = 0;
1774 u32 hw_if_index = ~0;
1775 vnet_hw_interface_t * hi;
1779 if (tunnel_sw_if_index == 0)
1780 tunnel_sw_if_index = &dummy;
1782 *tunnel_sw_if_index = ~0;
1784 if (inner_fib_id != (u32)~0)
1788 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1790 return VNET_API_ERROR_NO_SUCH_FIB;
1791 inner_fib_index = p[0];
1794 /* suppress duplicate mpls interface generation. */
1795 pool_foreach (tp, mm->eth_tunnels,
1798 * If we have a tunnel which matches (src, dst, intfc/mask)
1799 * AND the expected route is in the FIB, it's a dup
1801 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1802 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1803 && tp->inner_fib_index == inner_fib_index
1804 && FIB_NODE_INDEX_INVALID != tp->fei)
1826 /* Delete, and we can't find the tunnel */
1827 if (is_add == 0 && found_tunnel == 0)
1828 return VNET_API_ERROR_NO_SUCH_ENTRY;
1830 pool_get(mm->eth_tunnels, tp);
1831 memset (tp, 0, sizeof (*tp));
1833 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1836 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1837 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1838 hi = vnet_get_hw_interface (vnm, hw_if_index);
1839 hi->dev_instance = tp - mm->eth_tunnels;
1840 hi->hw_instance = tp - mm->eth_tunnels;
1844 hw_if_index = vnet_register_interface
1845 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1846 mpls_eth_hw_interface_class.index,
1847 tp - mm->eth_tunnels);
1848 hi = vnet_get_hw_interface (vnm, hw_if_index);
1850 /* ... to make the IP and L2 x-connect cases identical */
1851 slot = vlib_node_add_named_next_with_slot
1852 (vnm->vlib_main, hi->tx_node_index,
1853 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1855 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1858 *tunnel_sw_if_index = hi->sw_if_index;
1859 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1860 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1862 tp->hw_if_index = hw_if_index;
1865 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1866 tp->intfc_address.as_u32 = intfc->as_u32;
1867 tp->mask_width = mask_width;
1868 tp->inner_fib_index = inner_fib_index;
1869 tp->encap_index = e - mm->encaps;
1870 tp->tx_sw_if_index = tx_sw_if_index;
1871 tp->l2_only = l2_only;
1872 tp->fei = FIB_NODE_INDEX_INVALID;
1874 if (new_tunnel_index)
1875 *new_tunnel_index = tp - mm->eth_tunnels;
1881 const fib_prefix_t pfx = {
1883 .ip4 = tp->intfc_address,
1885 .fp_len = tp->mask_width,
1886 .fp_proto = FIB_PROTOCOL_IP4,
1888 dpo_id_t dpo = DPO_NULL;
1895 classify_dpo_create(FIB_PROTOCOL_IP4,
1896 classify_table_index));
1898 tp->fei = fib_table_entry_special_dpo_add(tp->inner_fib_index,
1901 FIB_ENTRY_FLAG_EXCLUSIVE,
1907 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
1908 tp->fei = FIB_NODE_INDEX_INVALID;
1911 if (is_add == 0 && found_tunnel)
1913 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1914 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1915 0 /* admin down */);
1916 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1917 pool_put (mm->eth_tunnels, tp);
1923 static clib_error_t *
1924 create_mpls_ethernet_policy_tunnel_command_fn (vlib_main_t * vm,
1925 unformat_input_t * input,
1926 vlib_cli_command_t * cmd)
1928 unformat_input_t _line_input, * line_input = &_line_input;
1929 vnet_main_t * vnm = vnet_get_main();
1930 ip4_address_t intfc;
1933 int dst_set = 0, intfc_set = 0;
1935 u32 inner_fib_id = (u32)~0;
1936 u32 classify_table_index = (u32)~0;
1937 u32 new_tunnel_index;
1943 /* Get a line of input. */
1944 if (! unformat_user (input, unformat_line_input, line_input))
1947 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1949 if (unformat (line_input, "dst %U",
1950 unformat_ethernet_address, &dst))
1952 else if (unformat (line_input, "adj %U/%d",
1953 unformat_ip4_address, &intfc, &mask_width))
1955 else if (unformat (line_input, "tx-intfc %U",
1956 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1958 else if (unformat (line_input, "classify-table-index %d",
1959 &classify_table_index))
1961 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1963 else if (unformat (line_input, "l2-only"))
1965 else if (unformat (line_input, "del"))
1968 return clib_error_return (0, "unknown input '%U'",
1969 format_unformat_error, line_input);
1972 if (classify_table_index == ~0)
1973 return clib_error_return (0, "missing classify_table_index");
1976 return clib_error_return (0, "missing tx-intfc");
1979 return clib_error_return (0, "missing: dst <ethernet-address>");
1982 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1985 rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
1986 inner_fib_id, tx_sw_if_index,
1987 0 /* tunnel sw_if_index */,
1988 classify_table_index,
1995 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), new_tunnel_index);
1997 case VNET_API_ERROR_NO_SUCH_FIB:
1998 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
2001 case VNET_API_ERROR_NO_SUCH_ENTRY:
2002 return clib_error_return (0, "tunnel not found\n");
2004 case VNET_API_ERROR_NO_SUCH_LABEL:
2006 * This happens when there's no MPLS label for the dst address
2007 * no need for two error messages.
2009 return clib_error_return (0, "no label for %U in fib %d",
2010 format_ip4_address, &intfc, inner_fib_id);
2014 return clib_error_return (0, "vnet_mpls_ethernet_add_del_policy_tunnel returned %d", rv);
2021 VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
2022 .path = "create mpls ethernet policy tunnel",
2024 "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
2025 " classify-table-index <nn>",
2026 .function = create_mpls_ethernet_policy_tunnel_command_fn,
2029 static clib_error_t *
2030 mpls_interface_enable_disable (vlib_main_t * vm,
2031 unformat_input_t * input,
2032 vlib_cli_command_t * cmd)
2034 vnet_main_t * vnm = vnet_get_main();
2035 clib_error_t * error = 0;
2036 u32 sw_if_index, enable;
2040 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
2042 error = clib_error_return (0, "unknown interface `%U'",
2043 format_unformat_error, input);
2047 if (unformat (input, "enable"))
2049 else if (unformat (input, "disable"))
2053 error = clib_error_return (0, "expected 'enable' or 'disable'",
2054 format_unformat_error, input);
2058 mpls_sw_interface_enable_disable(&mpls_main, sw_if_index, enable);
2064 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
2065 .path = "set interface mpls",
2066 .function = mpls_interface_enable_disable,
2067 .short_help = "Enable/Disable an interface for MPLS forwarding",