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 static uword mpls_gre_set_rewrite (vnet_main_t * vnm,
31 uword max_rewrite_bytes)
34 * Conundrum: packets from tun/tap destined for the tunnel
35 * actually have this rewrite applied. Transit packets do not.
36 * To make the two cases equivalent, don't generate a
37 * rewrite here, build the entire header in the fast path.
42 /* manually added to the interface output node */
43 #define MPLS_GRE_OUTPUT_NEXT_POST_REWRITE 1
46 mpls_gre_interface_tx (vlib_main_t * vm,
47 vlib_node_runtime_t * node,
50 mpls_main_t * gm = &mpls_main;
51 vnet_main_t * vnm = gm->vnet_main;
53 u32 * from, * to_next, n_left_from, n_left_to_next;
55 /* Vector of buffer / pkt indices we're supposed to process */
56 from = vlib_frame_vector_args (frame);
58 /* Number of buffers / pkts */
59 n_left_from = frame->n_vectors;
61 /* Speculatively send the first buffer to the last disposition we used */
62 next_index = node->cached_next_index;
64 while (n_left_from > 0)
66 /* set up to enqueue to our disposition with index = next_index */
67 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
70 * As long as we have enough pkts left to process two pkts
71 * and prefetch two pkts...
73 while (n_left_from >= 4 && n_left_to_next >= 2)
75 vlib_buffer_t * b0, * b1;
76 u32 bi0, next0, bi1, next1;
77 mpls_gre_tunnel_t * t0, * t1;
78 u32 sw_if_index0, sw_if_index1;
79 vnet_hw_interface_t * hi0, * hi1;
82 /* Prefetch the next iteration */
84 vlib_buffer_t * p2, * p3;
86 p2 = vlib_get_buffer (vm, from[2]);
87 p3 = vlib_get_buffer (vm, from[3]);
89 vlib_prefetch_buffer_header (p2, LOAD);
90 vlib_prefetch_buffer_header (p3, LOAD);
93 * Prefetch packet data. We expect to overwrite
94 * the inbound L2 header with an ip header and a
95 * gre header. Might want to prefetch the last line
96 * of rewrite space as well; need profile data
98 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
99 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
102 /* Pick up the next two buffer indices */
106 /* Speculatively enqueue them where we sent the last buffer */
114 b0 = vlib_get_buffer (vm, bi0);
115 b1 = vlib_get_buffer (vm, bi1);
117 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
118 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
121 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
122 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
124 /* hw_instance = tunnel pool index */
125 t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance);
126 t1 = pool_elt_at_index (gm->gre_tunnels, hi1->hw_instance);
128 /* Apply rewrite - $$$$$ fixme don't use memcpy */
129 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
130 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
132 dst0 = vlib_buffer_get_current (b0);
133 dst1 = vlib_buffer_get_current (b1);
135 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
136 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
138 /* Fix TX fib indices */
139 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
140 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->outer_fib_index;
142 /* mpls-post-rewrite takes it from here... */
143 next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
144 next1 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
146 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
148 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
150 tr->tunnel_id = t0 - gm->gre_tunnels;
151 tr->length = b0->current_length;
152 tr->src.as_u32 = t0->tunnel_src.as_u32;
153 tr->dst.as_u32 = t0->tunnel_dst.as_u32;
155 tr->mpls_encap_index = t0->encap_index;
157 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
159 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
161 tr->tunnel_id = t1 - gm->gre_tunnels;
162 tr->length = b1->current_length;
163 tr->src.as_u32 = t1->tunnel_src.as_u32;
164 tr->dst.as_u32 = t1->tunnel_dst.as_u32;
166 tr->mpls_encap_index = t1->encap_index;
169 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
170 to_next, n_left_to_next,
171 bi0, bi1, next0, next1);
174 while (n_left_from > 0 && n_left_to_next > 0)
178 mpls_gre_tunnel_t * t0;
180 vnet_hw_interface_t * hi0;
190 b0 = vlib_get_buffer (vm, bi0);
192 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
194 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
196 t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance);
198 /* Apply rewrite - $$$$$ fixme don't use memcpy */
199 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
201 dst0 = vlib_buffer_get_current (b0);
203 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
205 /* Fix the TX fib index */
206 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
208 /* mpls-post-rewrite takes it from here... */
209 next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
211 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
213 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
215 tr->tunnel_id = t0 - gm->gre_tunnels;
216 tr->length = b0->current_length;
217 tr->src.as_u32 = t0->tunnel_src.as_u32;
218 tr->dst.as_u32 = t0->tunnel_dst.as_u32;
220 tr->mpls_encap_index = t0->encap_index;
223 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
224 to_next, n_left_to_next,
228 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
231 vlib_node_increment_counter (vm, gre_input_node.index,
232 GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
234 return frame->n_vectors;
237 static u8 * format_mpls_gre_tunnel_name (u8 * s, va_list * args)
239 u32 dev_instance = va_arg (*args, u32);
240 return format (s, "mpls-gre%d", dev_instance);
243 static u8 * format_mpls_gre_device (u8 * s, va_list * args)
245 u32 dev_instance = va_arg (*args, u32);
246 CLIB_UNUSED (int verbose) = va_arg (*args, int);
248 s = format (s, "MPLS-GRE tunnel: id %d\n", dev_instance);
252 VNET_DEVICE_CLASS (mpls_gre_device_class) = {
253 .name = "MPLS-GRE tunnel device",
254 .format_device_name = format_mpls_gre_tunnel_name,
255 .format_device = format_mpls_gre_device,
256 .format_tx_trace = format_mpls_gre_tx_trace,
257 .tx_function = mpls_gre_interface_tx,
258 .no_flatten_output_chains = 1,
261 .admin_up_down_function = 0;
265 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_gre_device_class,
266 mpls_gre_interface_tx)
268 VNET_HW_INTERFACE_CLASS (mpls_gre_hw_interface_class) = {
270 .format_header = format_mpls_gre_header_with_length,
272 .unformat_header = unformat_mpls_gre_header,
274 .set_rewrite = mpls_gre_set_rewrite,
278 static uword mpls_eth_set_rewrite (vnet_main_t * vnm,
283 uword max_rewrite_bytes)
286 * Conundrum: packets from tun/tap destined for the tunnel
287 * actually have this rewrite applied. Transit packets do not.
288 * To make the two cases equivalent, don't generate a
289 * rewrite here, build the entire header in the fast path.
294 /* manually added to the interface output node */
295 #define MPLS_ETH_OUTPUT_NEXT_OUTPUT 1
298 mpls_eth_interface_tx (vlib_main_t * vm,
299 vlib_node_runtime_t * node,
300 vlib_frame_t * frame)
302 mpls_main_t * gm = &mpls_main;
303 vnet_main_t * vnm = gm->vnet_main;
305 u32 * from, * to_next, n_left_from, n_left_to_next;
307 /* Vector of buffer / pkt indices we're supposed to process */
308 from = vlib_frame_vector_args (frame);
310 /* Number of buffers / pkts */
311 n_left_from = frame->n_vectors;
313 /* Speculatively send the first buffer to the last disposition we used */
314 next_index = node->cached_next_index;
316 while (n_left_from > 0)
318 /* set up to enqueue to our disposition with index = next_index */
319 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
322 * As long as we have enough pkts left to process two pkts
323 * and prefetch two pkts...
325 while (n_left_from >= 4 && n_left_to_next >= 2)
327 vlib_buffer_t * b0, * b1;
328 u32 bi0, next0, bi1, next1;
329 mpls_eth_tunnel_t * t0, * t1;
330 u32 sw_if_index0, sw_if_index1;
331 vnet_hw_interface_t * hi0, * hi1;
334 /* Prefetch the next iteration */
336 vlib_buffer_t * p2, * p3;
338 p2 = vlib_get_buffer (vm, from[2]);
339 p3 = vlib_get_buffer (vm, from[3]);
341 vlib_prefetch_buffer_header (p2, LOAD);
342 vlib_prefetch_buffer_header (p3, LOAD);
345 * Prefetch packet data. We expect to overwrite
346 * the inbound L2 header with an ip header and a
347 * gre header. Might want to prefetch the last line
348 * of rewrite space as well; need profile data
350 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
351 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
354 /* Pick up the next two buffer indices */
358 /* Speculatively enqueue them where we sent the last buffer */
366 b0 = vlib_get_buffer (vm, bi0);
367 b1 = vlib_get_buffer (vm, bi1);
369 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
370 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
373 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
374 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
376 /* hw_instance = tunnel pool index */
377 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
378 t1 = pool_elt_at_index (gm->eth_tunnels, hi1->hw_instance);
380 /* Apply rewrite - $$$$$ fixme don't use memcpy */
381 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
382 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
384 dst0 = vlib_buffer_get_current (b0);
385 dst1 = vlib_buffer_get_current (b1);
387 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
388 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
390 /* Fix TX fib indices */
391 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
392 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->tx_sw_if_index;
394 /* mpls-post-rewrite takes it from here... */
395 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
396 next1 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
398 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
400 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
403 tr->tunnel_id = t0 - gm->eth_tunnels;
404 tr->tx_sw_if_index = t0->tx_sw_if_index;
405 tr->mpls_encap_index = t0->encap_index;
406 tr->length = b0->current_length;
407 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
408 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
410 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
412 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
415 tr->tunnel_id = t1 - gm->eth_tunnels;
416 tr->tx_sw_if_index = t1->tx_sw_if_index;
417 tr->mpls_encap_index = t1->encap_index;
418 tr->length = b1->current_length;
419 hi1 = vnet_get_sup_hw_interface (vnm, t1->tx_sw_if_index);
420 clib_memcpy (tr->dst, hi1->hw_address, sizeof (tr->dst));
423 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
424 to_next, n_left_to_next,
425 bi0, bi1, next0, next1);
427 while (n_left_from > 0 && n_left_to_next > 0)
431 mpls_eth_tunnel_t * t0;
433 vnet_hw_interface_t * hi0;
443 b0 = vlib_get_buffer (vm, bi0);
445 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
447 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
449 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
451 /* Apply rewrite - $$$$$ fixme don't use memcpy */
452 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
454 dst0 = vlib_buffer_get_current (b0);
456 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
458 /* Fix the TX interface */
459 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
461 /* Send the packet */
462 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
464 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
466 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
469 tr->tunnel_id = t0 - gm->eth_tunnels;
470 tr->tx_sw_if_index = t0->tx_sw_if_index;
471 tr->mpls_encap_index = t0->encap_index;
472 tr->length = b0->current_length;
473 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
474 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
477 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
478 to_next, n_left_to_next,
482 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
485 vlib_node_increment_counter (vm, mpls_input_node.index,
486 MPLS_ERROR_PKTS_ENCAP, frame->n_vectors);
488 return frame->n_vectors;
491 static u8 * format_mpls_eth_tunnel_name (u8 * s, va_list * args)
493 u32 dev_instance = va_arg (*args, u32);
494 return format (s, "mpls-eth%d", dev_instance);
497 static u8 * format_mpls_eth_device (u8 * s, va_list * args)
499 u32 dev_instance = va_arg (*args, u32);
500 CLIB_UNUSED (int verbose) = va_arg (*args, int);
502 s = format (s, "MPLS-ETH tunnel: id %d\n", dev_instance);
506 VNET_DEVICE_CLASS (mpls_eth_device_class) = {
507 .name = "MPLS-ETH tunnel device",
508 .format_device_name = format_mpls_eth_tunnel_name,
509 .format_device = format_mpls_eth_device,
510 .format_tx_trace = format_mpls_eth_tx_trace,
511 .tx_function = mpls_eth_interface_tx,
512 .no_flatten_output_chains = 1,
515 .admin_up_down_function = 0;
519 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_eth_device_class,
520 mpls_eth_interface_tx)
522 VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = {
524 .format_header = format_mpls_eth_header_with_length,
526 .unformat_header = unformat_mpls_eth_header,
528 .set_rewrite = mpls_eth_set_rewrite,
532 * A conversion of DPO next object tpyes to VLIB graph next nodes from
533 * the mpls_post_rewrite node
535 static const int dpo_next_2_mpls_post_rewrite[DPO_LAST] = {
536 [DPO_LOAD_BALANCE] = IP_LOOKUP_NEXT_LOAD_BALANCE,
540 mpls_gre_fixup (vlib_main_t *vm,
546 ip0 = vlib_buffer_get_current (b0);
548 /* Fixup the checksum and len fields in the GRE tunnel encap
549 * that was applied at the midchain node */
550 ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
551 ip0->checksum = ip4_header_checksum (ip0);
554 static u8 * mpls_gre_rewrite (mpls_main_t *mm, mpls_gre_tunnel_t * t)
557 ip4_gre_and_mpls_header_t * h0;
558 u8 * rewrite_data = 0;
560 mpls_unicast_header_t *lp0;
563 /* look up the encap label stack using the RX FIB */
564 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index, t->tunnel_dst.as_u32);
568 clib_warning ("no label for inner fib index %d, dst %U",
569 t->inner_fib_index, format_ip4_address,
574 vec_validate (rewrite_data, sizeof (*h0)
575 + sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
576 memset (rewrite_data, 0, sizeof (*h0));
578 h0 = (ip4_gre_and_mpls_header_t *) rewrite_data;
579 /* Copy the encap label stack */
581 for (i = 0; i < vec_len(e->labels); i++)
582 lp0[i] = e->labels[i];
584 h0->gre.protocol = clib_host_to_net_u16(GRE_PROTOCOL_mpls_unicast);
585 ip0->ip_version_and_header_length = 0x45;
587 ip0->protocol = IP_PROTOCOL_GRE;
588 /* $$$ fixup ip4 header length and checksum after-the-fact */
589 ip0->src_address.as_u32 = t->tunnel_src.as_u32;
590 ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
591 ip0->checksum = ip4_header_checksum (ip0);
593 return (rewrite_data);
597 mpls_sw_interface_is_enabled (u32 sw_if_index)
599 mpls_main_t * mm = &mpls_main;
601 if (vec_len(mm->mpls_enabled_by_sw_if_index) < sw_if_index)
604 return (mm->mpls_enabled_by_sw_if_index[sw_if_index]);
608 mpls_sw_interface_enable_disable (mpls_main_t * mm,
612 mpls_interface_state_change_callback_t *callback;
613 vlib_main_t * vm = vlib_get_main();
614 ip_config_main_t * cm = &mm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
615 vnet_config_main_t * vcm = &cm->config_main;
616 u32 lookup_feature_index;
617 fib_node_index_t lfib_index;
620 vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
623 * enable/disable only on the 1<->0 transition
627 if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
630 lfib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS,
631 MPLS_FIB_DEFAULT_TABLE_ID);
632 vec_validate(mm->fib_index_by_sw_if_index, 0);
633 mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
637 ASSERT(mm->mpls_enabled_by_sw_if_index[sw_if_index] > 0);
638 if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
641 fib_table_unlock(mm->fib_index_by_sw_if_index[sw_if_index],
645 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
646 ci = cm->config_index_by_sw_if_index[sw_if_index];
648 lookup_feature_index = mm->mpls_rx_feature_lookup;
651 ci = vnet_config_add_feature (vm, vcm,
653 lookup_feature_index,
655 /* # bytes of config data */ 0);
657 ci = vnet_config_del_feature (vm, vcm, ci,
658 lookup_feature_index,
660 /* # bytes of config data */ 0);
662 cm->config_index_by_sw_if_index[sw_if_index] = ci;
665 * notify all interested clients of the change of state.
667 vec_foreach(callback, mm->mpls_interface_state_change_callbacks)
669 (*callback)(sw_if_index, is_enable);
673 static mpls_gre_tunnel_t *
674 mpls_gre_tunnel_from_fib_node (fib_node_t *node)
677 ASSERT(FIB_NODE_TYPE_MPLS_GRE_TUNNEL == node->fn_type);
679 return ((mpls_gre_tunnel_t*)node);
683 * mpls_gre_tunnel_stack
685 * 'stack' (resolve the recursion for) the tunnel's midchain adjacency
688 mpls_gre_tunnel_stack (mpls_gre_tunnel_t *mgt)
691 * find the adjacency that is contributed by the FIB entry
692 * that this tunnel resovles via, and use it as the next adj
695 adj_nbr_midchain_stack(mgt->adj_index,
696 fib_entry_contribute_ip_forwarding(mgt->fei));
700 * Function definition to backwalk a FIB node
702 static fib_node_back_walk_rc_t
703 mpls_gre_tunnel_back_walk (fib_node_t *node,
704 fib_node_back_walk_ctx_t *ctx)
706 mpls_gre_tunnel_stack(mpls_gre_tunnel_from_fib_node(node));
708 return (FIB_NODE_BACK_WALK_CONTINUE);
712 * Function definition to get a FIB node from its index
715 mpls_gre_tunnel_fib_node_get (fib_node_index_t index)
717 mpls_gre_tunnel_t * mgt;
721 mgt = pool_elt_at_index(mm->gre_tunnels, index);
723 return (&mgt->mgt_node);
727 * Function definition to inform the FIB node that its last lock has gone.
730 mpls_gre_tunnel_last_lock_gone (fib_node_t *node)
733 * The MPLS GRE tunnel is a root of the graph. As such
734 * it never has children and thus is never locked.
740 * Virtual function table registered by MPLS GRE tunnels
741 * for participation in the FIB object graph.
743 const static fib_node_vft_t mpls_gre_vft = {
744 .fnv_get = mpls_gre_tunnel_fib_node_get,
745 .fnv_last_lock = mpls_gre_tunnel_last_lock_gone,
746 .fnv_back_walk = mpls_gre_tunnel_back_walk,
749 static mpls_gre_tunnel_t *
750 mpls_gre_tunnel_find (ip4_address_t *src,
752 ip4_address_t *intfc,
755 mpls_main_t * mm = &mpls_main;
756 mpls_gre_tunnel_t *tp;
757 int found_tunnel = 0;
759 /* suppress duplicate mpls interface generation. */
760 pool_foreach (tp, mm->gre_tunnels,
763 * If we have a tunnel which matches (src, dst, intfc/mask)
764 * AND the expected route is in the FIB, it's a dup
766 if (!memcmp (&tp->tunnel_src, src, sizeof (*src))
767 && !memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
768 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
769 && tp->inner_fib_index == inner_fib_index)
784 int mpls_gre_tunnel_add (ip4_address_t *src,
786 ip4_address_t *intfc,
790 u32 * tunnel_sw_if_index,
793 mpls_main_t * mm = &mpls_main;
794 gre_main_t * gm = &gre_main;
795 vnet_main_t * vnm = vnet_get_main();
796 mpls_gre_tunnel_t *tp;
799 mpls_encap_t * e = 0;
800 u32 hw_if_index = ~0;
801 vnet_hw_interface_t * hi;
803 const ip46_address_t zero_nh = {
807 tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index);
811 return VNET_API_ERROR_NO_SUCH_ENTRY;
813 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, dst->as_u32);
815 return VNET_API_ERROR_NO_SUCH_LABEL;
817 pool_get(mm->gre_tunnels, tp);
818 memset (tp, 0, sizeof (*tp));
819 fib_node_init(&tp->mgt_node,
820 FIB_NODE_TYPE_MPLS_GRE_TUNNEL);
822 if (vec_len (mm->free_gre_sw_if_indices) > 0)
825 mm->free_gre_sw_if_indices[vec_len(mm->free_gre_sw_if_indices)-1];
826 _vec_len (mm->free_gre_sw_if_indices) -= 1;
827 hi = vnet_get_hw_interface (vnm, hw_if_index);
828 hi->dev_instance = tp - mm->gre_tunnels;
829 hi->hw_instance = tp - mm->gre_tunnels;
833 hw_if_index = vnet_register_interface
834 (vnm, mpls_gre_device_class.index, tp - mm->gre_tunnels,
835 mpls_gre_hw_interface_class.index,
836 tp - mm->gre_tunnels);
837 hi = vnet_get_hw_interface (vnm, hw_if_index);
839 /* ... to make the IP and L2 x-connect cases identical */
840 slot = vlib_node_add_named_next_with_slot
841 (vnm->vlib_main, hi->tx_node_index,
842 "mpls-post-rewrite", MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
844 ASSERT (slot == MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
847 *tunnel_sw_if_index = hi->sw_if_index;
848 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
849 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
850 vec_validate(ip4_main.fib_index_by_sw_if_index, *tunnel_sw_if_index);
851 ip4_main.fib_index_by_sw_if_index[*tunnel_sw_if_index] = outer_fib_index;
853 tp->hw_if_index = hw_if_index;
855 /* bind the MPLS and IPv4 FIBs to the interface and enable */
856 vec_validate(mm->fib_index_by_sw_if_index, hi->sw_if_index);
857 mm->fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index;
858 mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 1);
859 ip4_main.fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index;
860 ip4_sw_interface_enable_disable(hi->sw_if_index, 1);
862 tp->tunnel_src.as_u32 = src->as_u32;
863 tp->tunnel_dst.as_u32 = dst->as_u32;
864 tp->intfc_address.as_u32 = intfc->as_u32;
865 tp->mask_width = mask_width;
866 tp->inner_fib_index = inner_fib_index;
867 tp->outer_fib_index = outer_fib_index;
868 tp->encap_index = e - mm->encaps;
869 tp->l2_only = l2_only;
871 /* Add the tunnel to the hash table of all GRE tunnels */
872 u64 key = (u64)src->as_u32 << 32 | (u64)dst->as_u32;
874 ASSERT(NULL == hash_get (gm->tunnel_by_key, key));
875 hash_set (gm->tunnel_by_key, key, tp - mm->gre_tunnels);
877 /* Create the adjacency and add to v4 fib */
878 memset(&adj, 0, sizeof (adj));
879 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
881 rewrite_data = mpls_gre_rewrite (mm, tp);
882 if (rewrite_data == 0)
884 if (*tunnel_sw_if_index != ~0)
886 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
887 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
889 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
891 pool_put (mm->gre_tunnels, tp);
892 return VNET_API_ERROR_NO_SUCH_LABEL;
895 /* Save a copy of the rewrite data for L2 x-connect */
896 vec_free (tp->rewrite_data);
898 tp->rewrite_data = rewrite_data;
903 * source the FIB entry for the tunnel's destination
904 * and become a child thereof. The tunnel will then get poked
905 * when the forwarding for the entry updates, and the tunnel can
906 * re-stack accordingly
908 const fib_prefix_t tun_dst_pfx = {
910 .fp_proto = FIB_PROTOCOL_IP4,
916 tp->fei = fib_table_entry_special_add(outer_fib_index,
921 tp->sibling_index = fib_entry_child_add(tp->fei,
922 FIB_NODE_TYPE_MPLS_GRE_TUNNEL,
923 tp - mm->gre_tunnels);
926 * create and update the midchain adj this tunnel sources.
927 * This is the adj the route we add below will resolve to.
929 tp->adj_index = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
934 adj_nbr_midchain_update_rewrite(tp->adj_index,
936 ADJ_MIDCHAIN_FLAG_NONE,
938 mpls_gre_tunnel_stack(tp);
941 * Update the route for the tunnel's subnet to point through the tunnel
943 const fib_prefix_t tun_sub_net_pfx = {
944 .fp_len = tp->mask_width,
945 .fp_proto = FIB_PROTOCOL_IP4,
947 .ip4 = tp->intfc_address,
951 fib_table_entry_update_one_path(inner_fib_index,
953 FIB_SOURCE_INTERFACE,
954 (FIB_ENTRY_FLAG_CONNECTED |
955 FIB_ENTRY_FLAG_ATTACHED),
959 ~0, // invalid fib index
962 FIB_ROUTE_PATH_FLAG_NONE);
969 mpls_gre_tunnel_del (ip4_address_t *src,
971 ip4_address_t *intfc,
975 u32 * tunnel_sw_if_index,
978 mpls_main_t * mm = &mpls_main;
979 vnet_main_t * vnm = vnet_get_main();
980 gre_main_t * gm = &gre_main;
981 mpls_gre_tunnel_t *tp;
982 vnet_hw_interface_t * hi;
984 tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index);
986 /* Delete, and we can't find the tunnel */
988 return VNET_API_ERROR_NO_SUCH_ENTRY;
990 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
995 * unsource the FIB entry for the tunnel's destination
997 const fib_prefix_t tun_dst_pfx = {
999 .fp_proto = FIB_PROTOCOL_IP4,
1005 fib_entry_child_remove(tp->fei,
1007 fib_table_entry_special_remove(outer_fib_index,
1010 tp->fei = FIB_NODE_INDEX_INVALID;
1011 adj_unlock(tp->adj_index);
1014 * unsource the route for the tunnel's subnet
1016 const fib_prefix_t tun_sub_net_pfx = {
1017 .fp_len = tp->mask_width,
1018 .fp_proto = FIB_PROTOCOL_IP4,
1020 .ip4 = tp->intfc_address,
1024 fib_table_entry_delete(inner_fib_index,
1026 FIB_SOURCE_INTERFACE);
1029 u64 key = ((u64)tp->tunnel_src.as_u32 << 32 |
1030 (u64)tp->tunnel_src.as_u32);
1032 hash_unset (gm->tunnel_by_key, key);
1033 mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 0);
1034 ip4_sw_interface_enable_disable(hi->sw_if_index, 0);
1036 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1037 0 /* admin down */);
1038 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
1039 vec_free (tp->rewrite_data);
1040 fib_node_deinit(&tp->mgt_node);
1041 pool_put (mm->gre_tunnels, tp);
1047 vnet_mpls_gre_add_del_tunnel (ip4_address_t *src,
1049 ip4_address_t *intfc,
1051 u32 inner_fib_id, u32 outer_fib_id,
1052 u32 * tunnel_sw_if_index,
1056 u32 inner_fib_index = 0;
1057 u32 outer_fib_index = 0;
1059 ip4_main_t * im = &ip4_main;
1061 /* No questions, no answers */
1062 if (NULL == tunnel_sw_if_index)
1063 tunnel_sw_if_index = &dummy;
1065 *tunnel_sw_if_index = ~0;
1067 if (inner_fib_id != (u32)~0)
1071 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1073 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
1074 inner_fib_index = p[0];
1077 if (outer_fib_id != 0)
1081 p = hash_get (im->fib_index_by_table_id, outer_fib_id);
1083 return VNET_API_ERROR_NO_SUCH_FIB;
1084 outer_fib_index = p[0];
1089 return (mpls_gre_tunnel_add(src,dst,intfc, mask_width,
1097 return (mpls_gre_tunnel_del(src,dst,intfc, mask_width,
1106 * Remove all mpls tunnels in the specified fib
1108 int vnet_mpls_gre_delete_fib_tunnels (u32 fib_id)
1110 mpls_main_t * mm = &mpls_main;
1111 vnet_main_t * vnm = mm->vnet_main;
1112 mpls_gre_tunnel_t *tp;
1114 u32 * tunnels_to_delete = 0;
1115 vnet_hw_interface_t * hi;
1118 fib_index = ip4_fib_index_from_table_id(fib_id);
1119 if (~0 == fib_index)
1120 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
1122 pool_foreach (tp, mm->gre_tunnels,
1124 if (tp->inner_fib_index == fib_index)
1125 vec_add1 (tunnels_to_delete, tp - mm->gre_tunnels);
1128 for (i = 0; i < vec_len(tunnels_to_delete); i++) {
1129 tp = pool_elt_at_index (mm->gre_tunnels, tunnels_to_delete[i]);
1131 /* Delete, the route if not already gone */
1132 if (FIB_NODE_INDEX_INVALID != tp->fei && !tp->l2_only)
1134 const fib_prefix_t tun_dst_pfx = {
1136 .fp_proto = FIB_PROTOCOL_IP4,
1138 .ip4 = tp->tunnel_dst,
1142 fib_entry_child_remove(tp->fei,
1144 fib_table_entry_special_remove(tp->outer_fib_index,
1147 tp->fei = FIB_NODE_INDEX_INVALID;
1148 adj_unlock(tp->adj_index);
1150 const fib_prefix_t tun_sub_net_pfx = {
1151 .fp_len = tp->mask_width,
1152 .fp_proto = FIB_PROTOCOL_IP4,
1154 .ip4 = tp->intfc_address,
1158 fib_table_entry_delete(tp->inner_fib_index,
1160 FIB_SOURCE_INTERFACE);
1163 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1164 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1165 0 /* admin down */);
1166 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
1167 vec_free (tp->rewrite_data);
1168 pool_put (mm->gre_tunnels, tp);
1171 vec_free(tunnels_to_delete);
1176 static clib_error_t *
1177 create_mpls_gre_tunnel_command_fn (vlib_main_t * vm,
1178 unformat_input_t * input,
1179 vlib_cli_command_t * cmd)
1181 unformat_input_t _line_input, * line_input = &_line_input;
1182 ip4_address_t src, dst, intfc;
1183 int src_set = 0, dst_set = 0, intfc_set = 0;
1185 u32 inner_fib_id = (u32)~0;
1186 u32 outer_fib_id = 0;
1190 u32 tunnel_intfc_sw_if_index = ~0;
1192 /* Get a line of input. */
1193 if (! unformat_user (input, unformat_line_input, line_input))
1196 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1198 if (unformat (line_input, "src %U",
1199 unformat_ip4_address, &src))
1201 else if (unformat (line_input, "dst %U",
1202 unformat_ip4_address, &dst))
1204 else if (unformat (line_input, "intfc %U/%d",
1205 unformat_ip4_address, &intfc, &mask_width))
1207 else if (unformat (line_input, "inner-fib-id %d", &inner_fib_id))
1209 else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
1211 else if (unformat (line_input, "del"))
1213 else if (unformat (line_input, "l2-only"))
1216 return clib_error_return (0, "unknown input '%U'",
1217 format_unformat_error, line_input);
1221 return clib_error_return (0, "missing: src <ip-address>");
1224 return clib_error_return (0, "missing: dst <ip-address>");
1227 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1230 rv = vnet_mpls_gre_add_del_tunnel (&src, &dst, &intfc, mask_width,
1231 inner_fib_id, outer_fib_id,
1232 &tunnel_intfc_sw_if_index,
1239 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), tunnel_intfc_sw_if_index);
1242 case VNET_API_ERROR_NO_SUCH_INNER_FIB:
1243 return clib_error_return (0, "inner fib ID %d doesn't exist\n",
1245 case VNET_API_ERROR_NO_SUCH_FIB:
1246 return clib_error_return (0, "outer fib ID %d doesn't exist\n",
1249 case VNET_API_ERROR_NO_SUCH_ENTRY:
1250 return clib_error_return (0, "tunnel not found\n");
1252 case VNET_API_ERROR_NO_SUCH_LABEL:
1254 * This happens when there's no MPLS label for the dst address
1255 * no need for two error messages.
1260 return clib_error_return (0, "vnet_mpls_gre_add_del_tunnel returned %d",
1266 VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
1267 .path = "create mpls gre tunnel",
1269 "create mpls gre tunnel [del] src <addr> dst <addr> intfc <addr>/<mw>",
1270 .function = create_mpls_gre_tunnel_command_fn,
1273 u8 * format_mpls_encap_index (u8 * s, va_list * args)
1275 mpls_main_t * mm = va_arg (*args, mpls_main_t *);
1276 u32 entry_index = va_arg (*args, u32);
1280 e = pool_elt_at_index (mm->encaps, entry_index);
1282 for (i = 0; i < vec_len (e->labels); i++)
1284 (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
1285 (e->labels[i].label_exp_s_ttl)));
1290 u8 * format_mpls_gre_tunnel (u8 * s, va_list * args)
1292 mpls_gre_tunnel_t * t = va_arg (*args, mpls_gre_tunnel_t *);
1293 mpls_main_t * mm = &mpls_main;
1295 if (t->l2_only == 0)
1297 s = format (s, "[%d]: src %U, dst %U, adj %U/%d, labels %U\n",
1298 t - mm->gre_tunnels,
1299 format_ip4_address, &t->tunnel_src,
1300 format_ip4_address, &t->tunnel_dst,
1301 format_ip4_address, &t->intfc_address,
1303 format_mpls_encap_index, mm, t->encap_index);
1305 s = format (s, " inner fib index %d, outer fib index %d",
1306 t->inner_fib_index, t->outer_fib_index);
1310 s = format (s, "[%d]: src %U, dst %U, key %U, labels %U\n",
1311 t - mm->gre_tunnels,
1312 format_ip4_address, &t->tunnel_src,
1313 format_ip4_address, &t->tunnel_dst,
1314 format_ip4_address, &t->intfc_address,
1315 format_mpls_encap_index, mm, t->encap_index);
1317 s = format (s, " l2 interface %d, outer fib index %d",
1318 t->hw_if_index, t->outer_fib_index);
1324 u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
1326 mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
1327 mpls_main_t * mm = &mpls_main;
1329 s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
1330 t - mm->eth_tunnels,
1331 format_ethernet_address, &t->tunnel_dst,
1332 format_ip4_address, &t->intfc_address,
1334 format_mpls_encap_index, mm, t->encap_index);
1337 s = format (s, " tx on %U, rx fib index %d",
1338 format_vnet_sw_if_index_name, mm->vnet_main, t->tx_sw_if_index,
1339 t->inner_fib_index);
1344 static clib_error_t *
1345 show_mpls_tunnel_command_fn (vlib_main_t * vm,
1346 unformat_input_t * input,
1347 vlib_cli_command_t * cmd)
1349 mpls_main_t * mm = &mpls_main;
1350 mpls_gre_tunnel_t * gt;
1351 mpls_eth_tunnel_t * et;
1353 if (pool_elts (mm->gre_tunnels))
1355 vlib_cli_output (vm, "MPLS-GRE tunnels");
1356 pool_foreach (gt, mm->gre_tunnels,
1358 vlib_cli_output (vm, "%U", format_mpls_gre_tunnel, gt);
1362 vlib_cli_output (vm, "No MPLS-GRE tunnels");
1364 if (pool_elts (mm->eth_tunnels))
1366 vlib_cli_output (vm, "MPLS-Ethernet tunnels");
1367 pool_foreach (et, mm->eth_tunnels,
1369 vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
1373 vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
1378 VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
1379 .path = "show mpls tunnel",
1380 .short_help = "show mpls tunnel",
1381 .function = show_mpls_tunnel_command_fn,
1385 /* force inclusion from application's main.c */
1386 clib_error_t *mpls_interface_init (vlib_main_t *vm)
1388 clib_error_t * error;
1390 fib_node_register_type(FIB_NODE_TYPE_MPLS_GRE_TUNNEL,
1393 if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
1398 VLIB_INIT_FUNCTION(mpls_interface_init);
1401 static u8 * mpls_ethernet_rewrite (mpls_main_t *mm, mpls_eth_tunnel_t * t)
1403 u8 * rewrite_data = 0;
1405 mpls_unicast_header_t *lp0;
1408 /* look up the encap label stack using the RX FIB and adjacency address*/
1409 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index,
1410 t->intfc_address.as_u32);
1414 clib_warning ("no label for inner fib index %d, dst %U",
1415 t->inner_fib_index, format_ip4_address,
1420 vec_validate (rewrite_data,
1421 sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
1423 /* Copy the encap label stack */
1424 lp0 = (mpls_unicast_header_t *) rewrite_data;
1426 for (i = 0; i < vec_len(e->labels); i++)
1427 lp0[i] = e->labels[i];
1429 return (rewrite_data);
1432 int vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
1433 ip4_address_t *intfc,
1437 u32 * tunnel_sw_if_index,
1441 ip4_main_t * im = &ip4_main;
1442 ip_lookup_main_t * lm = &im->lookup_main;
1443 mpls_main_t * mm = &mpls_main;
1444 vnet_main_t * vnm = vnet_get_main();
1445 mpls_eth_tunnel_t *tp;
1446 u32 inner_fib_index = 0;
1450 int found_tunnel = 0;
1451 mpls_encap_t * e = 0;
1452 u32 hw_if_index = ~0;
1453 vnet_hw_interface_t * hi;
1457 if (tunnel_sw_if_index == 0)
1458 tunnel_sw_if_index = &dummy;
1460 *tunnel_sw_if_index = ~0;
1462 if (inner_fib_id != (u32)~0)
1466 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1468 return VNET_API_ERROR_NO_SUCH_FIB;
1469 inner_fib_index = p[0];
1472 /* suppress duplicate mpls interface generation. */
1473 pool_foreach (tp, mm->eth_tunnels,
1476 * If we have a tunnel which matches (src, dst, intfc/mask)
1477 * AND the expected route is in the FIB, it's a dup
1479 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1480 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1481 && tp->inner_fib_index == inner_fib_index
1482 && FIB_NODE_INDEX_INVALID != tp->fei)
1492 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
1495 return VNET_API_ERROR_NO_SUCH_LABEL;
1509 /* Delete, and we can't find the tunnel */
1510 if (is_add == 0 && found_tunnel == 0)
1511 return VNET_API_ERROR_NO_SUCH_ENTRY;
1513 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
1515 return VNET_API_ERROR_NO_SUCH_LABEL;
1517 pool_get(mm->eth_tunnels, tp);
1518 memset (tp, 0, sizeof (*tp));
1520 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1523 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1524 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1525 hi = vnet_get_hw_interface (vnm, hw_if_index);
1526 hi->dev_instance = tp - mm->eth_tunnels;
1527 hi->hw_instance = tp - mm->eth_tunnels;
1531 hw_if_index = vnet_register_interface
1532 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1533 mpls_eth_hw_interface_class.index,
1534 tp - mm->eth_tunnels);
1535 hi = vnet_get_hw_interface (vnm, hw_if_index);
1537 /* ... to make the IP and L2 x-connect cases identical */
1538 slot = vlib_node_add_named_next_with_slot
1539 (vnm->vlib_main, hi->tx_node_index,
1540 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1542 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1545 *tunnel_sw_if_index = hi->sw_if_index;
1546 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1547 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1549 tp->hw_if_index = hw_if_index;
1552 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1553 tp->intfc_address.as_u32 = intfc->as_u32;
1554 tp->mask_width = mask_width;
1555 tp->inner_fib_index = inner_fib_index;
1556 tp->encap_index = e - mm->encaps;
1557 tp->tx_sw_if_index = tx_sw_if_index;
1558 tp->l2_only = l2_only;
1560 /* Create the adjacency and add to v4 fib */
1561 memset(&adj, 0, sizeof (adj));
1562 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1564 rewrite_data = mpls_ethernet_rewrite (mm, tp);
1565 if (rewrite_data == 0)
1567 if (*tunnel_sw_if_index != ~0)
1569 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1570 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1571 0 /* admin down */);
1572 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1575 pool_put (mm->eth_tunnels, tp);
1576 return VNET_API_ERROR_NO_SUCH_LABEL;
1579 vnet_rewrite_for_sw_interface
1581 VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1583 ip4_rewrite_node.index,
1585 &adj.rewrite_header,
1586 sizeof (adj.rewrite_data));
1589 * Prepend the (0,1,2) VLAN tag ethernet header
1590 * we just built to the mpls header stack
1592 vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
1593 clib_memcpy(rewrite_data,
1594 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1595 sizeof (adj.rewrite_data)),
1596 adj.rewrite_header.data_bytes);
1598 vnet_rewrite_set_data_internal (&adj.rewrite_header,
1599 sizeof(adj.rewrite_data),
1601 vec_len(rewrite_data));
1603 vec_free (tp->rewrite_data);
1605 tp->rewrite_data = rewrite_data;
1608 ip_add_adjacency (lm, &adj, 1 /* one adj */,
1615 const fib_prefix_t pfx = {
1617 .ip4 = tp->intfc_address,
1619 .fp_len = tp->mask_width,
1620 .fp_proto = FIB_PROTOCOL_IP4,
1623 tp->fei = fib_table_entry_special_add(tp->inner_fib_index,
1626 FIB_ENTRY_FLAG_NONE,
1630 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
1631 tp->fei = FIB_NODE_INDEX_INVALID;
1634 if (is_add == 0 && found_tunnel)
1636 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1637 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1638 0 /* admin down */);
1639 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1640 vec_free (tp->rewrite_data);
1641 pool_put (mm->eth_tunnels, tp);
1647 static clib_error_t *
1648 create_mpls_ethernet_tunnel_command_fn (vlib_main_t * vm,
1649 unformat_input_t * input,
1650 vlib_cli_command_t * cmd)
1652 unformat_input_t _line_input, * line_input = &_line_input;
1653 vnet_main_t * vnm = vnet_get_main();
1654 ip4_address_t intfc;
1657 int dst_set = 0, intfc_set = 0;
1659 u32 inner_fib_id = (u32)~0;
1664 u32 sw_if_index = ~0;
1666 /* Get a line of input. */
1667 if (! unformat_user (input, unformat_line_input, line_input))
1670 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1672 if (unformat (line_input, "dst %U",
1673 unformat_ethernet_address, &dst))
1675 else if (unformat (line_input, "adj %U/%d",
1676 unformat_ip4_address, &intfc, &mask_width))
1678 else if (unformat (line_input, "tx-intfc %U",
1679 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1681 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1683 else if (unformat (line_input, "l2-only"))
1685 else if (unformat (line_input, "del"))
1688 return clib_error_return (0, "unknown input '%U'",
1689 format_unformat_error, line_input);
1693 return clib_error_return (0, "missing tx-intfc");
1696 return clib_error_return (0, "missing: dst <ethernet-address>");
1699 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1702 rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
1703 inner_fib_id, tx_sw_if_index,
1711 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
1713 case VNET_API_ERROR_NO_SUCH_FIB:
1714 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1717 case VNET_API_ERROR_NO_SUCH_ENTRY:
1718 return clib_error_return (0, "tunnel not found\n");
1720 case VNET_API_ERROR_NO_SUCH_LABEL:
1722 * This happens when there's no MPLS label for the dst address
1723 * no need for two error messages.
1725 return clib_error_return (0, "no label for %U in fib %d",
1726 format_ip4_address, &intfc, inner_fib_id);
1730 return clib_error_return (0, "vnet_mpls_ethernet_add_del_tunnel returned %d", rv);
1737 VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
1738 .path = "create mpls ethernet tunnel",
1740 "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
1741 .function = create_mpls_ethernet_tunnel_command_fn,
1745 int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
1747 u32 policy_tunnel_index)
1749 mpls_eth_tunnel_t * t;
1751 u8 * rewrite_data = 0;
1753 mpls_unicast_header_t *lp;
1756 if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
1757 return VNET_API_ERROR_NO_SUCH_ENTRY;
1759 t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
1761 memset (&adj, 0, sizeof (adj));
1763 /* Build L2 encap */
1764 vnet_rewrite_for_sw_interface
1766 VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1768 mpls_policy_encap_node.index,
1770 &adj.rewrite_header,
1771 sizeof (adj.rewrite_data));
1773 vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
1775 clib_memcpy(rewrite_data,
1776 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1777 sizeof (adj.rewrite_data)),
1778 adj.rewrite_header.data_bytes);
1780 /* Append the label stack */
1782 vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
1784 lp = (mpls_unicast_header_t *) label_start;
1786 for (i = 0; i < vec_len(e->labels); i++)
1787 lp[i] = e->labels[i];
1789 /* Remember the rewrite data */
1790 e->rewrite = rewrite_data;
1791 e->output_next_index = adj.rewrite_header.next_index;
1796 int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
1797 ip4_address_t *intfc,
1801 u32 * tunnel_sw_if_index,
1802 u32 classify_table_index,
1803 u32 * new_tunnel_index,
1807 ip4_main_t * im = &ip4_main;
1808 mpls_main_t * mm = &mpls_main;
1809 vnet_main_t * vnm = vnet_get_main();
1810 mpls_eth_tunnel_t *tp;
1811 u32 inner_fib_index = 0;
1812 int found_tunnel = 0;
1813 mpls_encap_t * e = 0;
1814 u32 hw_if_index = ~0;
1815 vnet_hw_interface_t * hi;
1819 if (tunnel_sw_if_index == 0)
1820 tunnel_sw_if_index = &dummy;
1822 *tunnel_sw_if_index = ~0;
1824 if (inner_fib_id != (u32)~0)
1828 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1830 return VNET_API_ERROR_NO_SUCH_FIB;
1831 inner_fib_index = p[0];
1834 /* suppress duplicate mpls interface generation. */
1835 pool_foreach (tp, mm->eth_tunnels,
1838 * If we have a tunnel which matches (src, dst, intfc/mask)
1839 * AND the expected route is in the FIB, it's a dup
1841 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1842 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1843 && tp->inner_fib_index == inner_fib_index
1844 && FIB_NODE_INDEX_INVALID != tp->fei)
1866 /* Delete, and we can't find the tunnel */
1867 if (is_add == 0 && found_tunnel == 0)
1868 return VNET_API_ERROR_NO_SUCH_ENTRY;
1870 pool_get(mm->eth_tunnels, tp);
1871 memset (tp, 0, sizeof (*tp));
1873 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1876 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1877 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1878 hi = vnet_get_hw_interface (vnm, hw_if_index);
1879 hi->dev_instance = tp - mm->eth_tunnels;
1880 hi->hw_instance = tp - mm->eth_tunnels;
1884 hw_if_index = vnet_register_interface
1885 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1886 mpls_eth_hw_interface_class.index,
1887 tp - mm->eth_tunnels);
1888 hi = vnet_get_hw_interface (vnm, hw_if_index);
1890 /* ... to make the IP and L2 x-connect cases identical */
1891 slot = vlib_node_add_named_next_with_slot
1892 (vnm->vlib_main, hi->tx_node_index,
1893 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1895 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1898 *tunnel_sw_if_index = hi->sw_if_index;
1899 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1900 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1902 tp->hw_if_index = hw_if_index;
1905 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1906 tp->intfc_address.as_u32 = intfc->as_u32;
1907 tp->mask_width = mask_width;
1908 tp->inner_fib_index = inner_fib_index;
1909 tp->encap_index = e - mm->encaps;
1910 tp->tx_sw_if_index = tx_sw_if_index;
1911 tp->l2_only = l2_only;
1912 tp->fei = FIB_NODE_INDEX_INVALID;
1914 if (new_tunnel_index)
1915 *new_tunnel_index = tp - mm->eth_tunnels;
1921 const fib_prefix_t pfx = {
1923 .ip4 = tp->intfc_address,
1925 .fp_len = tp->mask_width,
1926 .fp_proto = FIB_PROTOCOL_IP4,
1928 dpo_id_t dpo = DPO_NULL;
1935 classify_dpo_create(FIB_PROTOCOL_IP4,
1936 classify_table_index));
1938 tp->fei = fib_table_entry_special_dpo_add(tp->inner_fib_index,
1941 FIB_ENTRY_FLAG_EXCLUSIVE,
1947 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
1948 tp->fei = FIB_NODE_INDEX_INVALID;
1951 if (is_add == 0 && found_tunnel)
1953 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1954 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1955 0 /* admin down */);
1956 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1957 pool_put (mm->eth_tunnels, tp);
1963 static clib_error_t *
1964 create_mpls_ethernet_policy_tunnel_command_fn (vlib_main_t * vm,
1965 unformat_input_t * input,
1966 vlib_cli_command_t * cmd)
1968 unformat_input_t _line_input, * line_input = &_line_input;
1969 vnet_main_t * vnm = vnet_get_main();
1970 ip4_address_t intfc;
1973 int dst_set = 0, intfc_set = 0;
1975 u32 inner_fib_id = (u32)~0;
1976 u32 classify_table_index = (u32)~0;
1977 u32 new_tunnel_index;
1983 /* Get a line of input. */
1984 if (! unformat_user (input, unformat_line_input, line_input))
1987 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1989 if (unformat (line_input, "dst %U",
1990 unformat_ethernet_address, &dst))
1992 else if (unformat (line_input, "adj %U/%d",
1993 unformat_ip4_address, &intfc, &mask_width))
1995 else if (unformat (line_input, "tx-intfc %U",
1996 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1998 else if (unformat (line_input, "classify-table-index %d",
1999 &classify_table_index))
2001 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
2003 else if (unformat (line_input, "l2-only"))
2005 else if (unformat (line_input, "del"))
2008 return clib_error_return (0, "unknown input '%U'",
2009 format_unformat_error, line_input);
2012 if (classify_table_index == ~0)
2013 return clib_error_return (0, "missing classify_table_index");
2016 return clib_error_return (0, "missing tx-intfc");
2019 return clib_error_return (0, "missing: dst <ethernet-address>");
2022 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
2025 rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
2026 inner_fib_id, tx_sw_if_index,
2027 0 /* tunnel sw_if_index */,
2028 classify_table_index,
2035 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), new_tunnel_index);
2037 case VNET_API_ERROR_NO_SUCH_FIB:
2038 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
2041 case VNET_API_ERROR_NO_SUCH_ENTRY:
2042 return clib_error_return (0, "tunnel not found\n");
2044 case VNET_API_ERROR_NO_SUCH_LABEL:
2046 * This happens when there's no MPLS label for the dst address
2047 * no need for two error messages.
2049 return clib_error_return (0, "no label for %U in fib %d",
2050 format_ip4_address, &intfc, inner_fib_id);
2054 return clib_error_return (0, "vnet_mpls_ethernet_add_del_policy_tunnel returned %d", rv);
2061 VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
2062 .path = "create mpls ethernet policy tunnel",
2064 "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
2065 " classify-table-index <nn>",
2066 .function = create_mpls_ethernet_policy_tunnel_command_fn,
2069 static clib_error_t *
2070 mpls_interface_enable_disable (vlib_main_t * vm,
2071 unformat_input_t * input,
2072 vlib_cli_command_t * cmd)
2074 vnet_main_t * vnm = vnet_get_main();
2075 clib_error_t * error = 0;
2076 u32 sw_if_index, enable;
2080 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
2082 error = clib_error_return (0, "unknown interface `%U'",
2083 format_unformat_error, input);
2087 if (unformat (input, "enable"))
2089 else if (unformat (input, "disable"))
2093 error = clib_error_return (0, "expected 'enable' or 'disable'",
2094 format_unformat_error, input);
2098 mpls_sw_interface_enable_disable(&mpls_main, sw_if_index, enable);
2104 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
2105 .path = "set interface mpls",
2106 .function = mpls_interface_enable_disable,
2107 .short_help = "Enable/Disable an interface for MPLS forwarding",