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 mpls_gre_fixup (vlib_main_t *vm,
507 ip0 = vlib_buffer_get_current (b0);
509 /* Fixup the checksum and len fields in the GRE tunnel encap
510 * that was applied at the midchain node */
511 ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
512 ip0->checksum = ip4_header_checksum (ip0);
515 static u8 * mpls_gre_rewrite (mpls_main_t *mm, mpls_gre_tunnel_t * t)
518 ip4_gre_and_mpls_header_t * h0;
519 u8 * rewrite_data = 0;
521 mpls_unicast_header_t *lp0;
524 /* look up the encap label stack using the RX FIB */
525 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index, t->tunnel_dst.as_u32);
529 clib_warning ("no label for inner fib index %d, dst %U",
530 t->inner_fib_index, format_ip4_address,
535 vec_validate (rewrite_data, sizeof (*h0)
536 + sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
537 memset (rewrite_data, 0, sizeof (*h0));
539 h0 = (ip4_gre_and_mpls_header_t *) rewrite_data;
540 /* Copy the encap label stack */
542 for (i = 0; i < vec_len(e->labels); i++)
543 lp0[i] = e->labels[i];
545 h0->gre.protocol = clib_host_to_net_u16(GRE_PROTOCOL_mpls_unicast);
546 ip0->ip_version_and_header_length = 0x45;
548 ip0->protocol = IP_PROTOCOL_GRE;
549 /* $$$ fixup ip4 header length and checksum after-the-fact */
550 ip0->src_address.as_u32 = t->tunnel_src.as_u32;
551 ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
552 ip0->checksum = ip4_header_checksum (ip0);
554 return (rewrite_data);
558 mpls_sw_interface_is_enabled (u32 sw_if_index)
560 mpls_main_t * mm = &mpls_main;
562 if (vec_len(mm->mpls_enabled_by_sw_if_index) < sw_if_index)
565 return (mm->mpls_enabled_by_sw_if_index[sw_if_index]);
569 mpls_sw_interface_enable_disable (mpls_main_t * mm,
573 vlib_main_t * vm = vlib_get_main();
574 ip_config_main_t * cm = &mm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
575 vnet_config_main_t * vcm = &cm->config_main;
576 u32 lookup_feature_index;
577 fib_node_index_t lfib_index;
580 vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
583 * enable/disable only on the 1<->0 transition
587 if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
590 lfib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS,
591 MPLS_FIB_DEFAULT_TABLE_ID);
592 vec_validate(mm->fib_index_by_sw_if_index, 0);
593 mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
597 ASSERT(mm->mpls_enabled_by_sw_if_index[sw_if_index] > 0);
598 if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
601 fib_table_unlock(mm->fib_index_by_sw_if_index[sw_if_index],
605 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
606 ci = cm->config_index_by_sw_if_index[sw_if_index];
608 lookup_feature_index = mm->mpls_rx_feature_lookup;
611 ci = vnet_config_add_feature (vm, vcm,
613 lookup_feature_index,
615 /* # bytes of config data */ 0);
617 ci = vnet_config_del_feature (vm, vcm, ci,
618 lookup_feature_index,
620 /* # bytes of config data */ 0);
622 cm->config_index_by_sw_if_index[sw_if_index] = ci;
625 static mpls_gre_tunnel_t *
626 mpls_gre_tunnel_from_fib_node (fib_node_t *node)
629 ASSERT(FIB_NODE_TYPE_MPLS_GRE_TUNNEL == node->fn_type);
631 return ((mpls_gre_tunnel_t*)node);
635 * mpls_gre_tunnel_stack
637 * 'stack' (resolve the recursion for) the tunnel's midchain adjacency
640 mpls_gre_tunnel_stack (mpls_gre_tunnel_t *mgt)
643 * find the adjacency that is contributed by the FIB entry
644 * that this tunnel resovles via, and use it as the next adj
647 adj_nbr_midchain_stack(mgt->adj_index,
648 fib_entry_contribute_ip_forwarding(mgt->fei));
652 * Function definition to backwalk a FIB node
654 static fib_node_back_walk_rc_t
655 mpls_gre_tunnel_back_walk (fib_node_t *node,
656 fib_node_back_walk_ctx_t *ctx)
658 mpls_gre_tunnel_stack(mpls_gre_tunnel_from_fib_node(node));
660 return (FIB_NODE_BACK_WALK_CONTINUE);
664 * Function definition to get a FIB node from its index
667 mpls_gre_tunnel_fib_node_get (fib_node_index_t index)
669 mpls_gre_tunnel_t * mgt;
673 mgt = pool_elt_at_index(mm->gre_tunnels, index);
675 return (&mgt->mgt_node);
679 * Function definition to inform the FIB node that its last lock has gone.
682 mpls_gre_tunnel_last_lock_gone (fib_node_t *node)
685 * The MPLS GRE tunnel is a root of the graph. As such
686 * it never has children and thus is never locked.
692 * Virtual function table registered by MPLS GRE tunnels
693 * for participation in the FIB object graph.
695 const static fib_node_vft_t mpls_gre_vft = {
696 .fnv_get = mpls_gre_tunnel_fib_node_get,
697 .fnv_last_lock = mpls_gre_tunnel_last_lock_gone,
698 .fnv_back_walk = mpls_gre_tunnel_back_walk,
701 static mpls_gre_tunnel_t *
702 mpls_gre_tunnel_find (ip4_address_t *src,
704 ip4_address_t *intfc,
707 mpls_main_t * mm = &mpls_main;
708 mpls_gre_tunnel_t *tp;
709 int found_tunnel = 0;
711 /* suppress duplicate mpls interface generation. */
712 pool_foreach (tp, mm->gre_tunnels,
715 * If we have a tunnel which matches (src, dst, intfc/mask)
716 * AND the expected route is in the FIB, it's a dup
718 if (!memcmp (&tp->tunnel_src, src, sizeof (*src))
719 && !memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
720 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
721 && tp->inner_fib_index == inner_fib_index)
736 int mpls_gre_tunnel_add (ip4_address_t *src,
738 ip4_address_t *intfc,
742 u32 * tunnel_sw_if_index,
745 mpls_main_t * mm = &mpls_main;
746 gre_main_t * gm = &gre_main;
747 vnet_main_t * vnm = vnet_get_main();
748 mpls_gre_tunnel_t *tp;
751 mpls_encap_t * e = 0;
752 u32 hw_if_index = ~0;
753 vnet_hw_interface_t * hi;
755 const ip46_address_t zero_nh = {
759 tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index);
763 return VNET_API_ERROR_NO_SUCH_ENTRY;
765 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, dst->as_u32);
767 return VNET_API_ERROR_NO_SUCH_LABEL;
769 pool_get(mm->gre_tunnels, tp);
770 memset (tp, 0, sizeof (*tp));
771 fib_node_init(&tp->mgt_node,
772 FIB_NODE_TYPE_MPLS_GRE_TUNNEL);
774 if (vec_len (mm->free_gre_sw_if_indices) > 0)
777 mm->free_gre_sw_if_indices[vec_len(mm->free_gre_sw_if_indices)-1];
778 _vec_len (mm->free_gre_sw_if_indices) -= 1;
779 hi = vnet_get_hw_interface (vnm, hw_if_index);
780 hi->dev_instance = tp - mm->gre_tunnels;
781 hi->hw_instance = tp - mm->gre_tunnels;
785 hw_if_index = vnet_register_interface
786 (vnm, mpls_gre_device_class.index, tp - mm->gre_tunnels,
787 mpls_gre_hw_interface_class.index,
788 tp - mm->gre_tunnels);
789 hi = vnet_get_hw_interface (vnm, hw_if_index);
791 /* ... to make the IP and L2 x-connect cases identical */
792 slot = vlib_node_add_named_next_with_slot
793 (vnm->vlib_main, hi->tx_node_index,
794 "mpls-post-rewrite", MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
796 ASSERT (slot == MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
799 *tunnel_sw_if_index = hi->sw_if_index;
800 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
801 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
802 vec_validate(ip4_main.fib_index_by_sw_if_index, *tunnel_sw_if_index);
803 ip4_main.fib_index_by_sw_if_index[*tunnel_sw_if_index] = outer_fib_index;
805 tp->hw_if_index = hw_if_index;
807 /* bind the MPLS and IPv4 FIBs to the interface and enable */
808 vec_validate(mm->fib_index_by_sw_if_index, hi->sw_if_index);
809 mm->fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index;
810 mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 1);
811 ip4_main.fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index;
812 ip4_sw_interface_enable_disable(hi->sw_if_index, 1);
814 tp->tunnel_src.as_u32 = src->as_u32;
815 tp->tunnel_dst.as_u32 = dst->as_u32;
816 tp->intfc_address.as_u32 = intfc->as_u32;
817 tp->mask_width = mask_width;
818 tp->inner_fib_index = inner_fib_index;
819 tp->outer_fib_index = outer_fib_index;
820 tp->encap_index = e - mm->encaps;
821 tp->l2_only = l2_only;
823 /* Add the tunnel to the hash table of all GRE tunnels */
824 u64 key = (u64)src->as_u32 << 32 | (u64)dst->as_u32;
826 ASSERT(NULL == hash_get (gm->tunnel_by_key, key));
827 hash_set (gm->tunnel_by_key, key, tp - mm->gre_tunnels);
829 /* Create the adjacency and add to v4 fib */
830 memset(&adj, 0, sizeof (adj));
831 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
833 rewrite_data = mpls_gre_rewrite (mm, tp);
834 if (rewrite_data == 0)
836 if (*tunnel_sw_if_index != ~0)
838 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
839 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
841 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
843 pool_put (mm->gre_tunnels, tp);
844 return VNET_API_ERROR_NO_SUCH_LABEL;
847 /* Save a copy of the rewrite data for L2 x-connect */
848 vec_free (tp->rewrite_data);
850 tp->rewrite_data = rewrite_data;
855 * source the FIB entry for the tunnel's destination
856 * and become a child thereof. The tunnel will then get poked
857 * when the forwarding for the entry updates, and the tunnel can
858 * re-stack accordingly
860 const fib_prefix_t tun_dst_pfx = {
862 .fp_proto = FIB_PROTOCOL_IP4,
868 tp->fei = fib_table_entry_special_add(outer_fib_index,
873 tp->sibling_index = fib_entry_child_add(tp->fei,
874 FIB_NODE_TYPE_MPLS_GRE_TUNNEL,
875 tp - mm->gre_tunnels);
878 * create and update the midchain adj this tunnel sources.
879 * This is the adj the route we add below will resolve to.
881 tp->adj_index = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
886 adj_nbr_midchain_update_rewrite(tp->adj_index,
888 ADJ_MIDCHAIN_FLAG_NONE,
890 mpls_gre_tunnel_stack(tp);
893 * Update the route for the tunnel's subnet to point through the tunnel
895 const fib_prefix_t tun_sub_net_pfx = {
896 .fp_len = tp->mask_width,
897 .fp_proto = FIB_PROTOCOL_IP4,
899 .ip4 = tp->intfc_address,
903 fib_table_entry_update_one_path(inner_fib_index,
905 FIB_SOURCE_INTERFACE,
906 (FIB_ENTRY_FLAG_CONNECTED |
907 FIB_ENTRY_FLAG_ATTACHED),
911 ~0, // invalid fib index
914 FIB_ROUTE_PATH_FLAG_NONE);
921 mpls_gre_tunnel_del (ip4_address_t *src,
923 ip4_address_t *intfc,
927 u32 * tunnel_sw_if_index,
930 mpls_main_t * mm = &mpls_main;
931 vnet_main_t * vnm = vnet_get_main();
932 gre_main_t * gm = &gre_main;
933 mpls_gre_tunnel_t *tp;
934 vnet_hw_interface_t * hi;
936 tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index);
938 /* Delete, and we can't find the tunnel */
940 return VNET_API_ERROR_NO_SUCH_ENTRY;
942 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
947 * unsource the FIB entry for the tunnel's destination
949 const fib_prefix_t tun_dst_pfx = {
951 .fp_proto = FIB_PROTOCOL_IP4,
957 fib_entry_child_remove(tp->fei,
959 fib_table_entry_special_remove(outer_fib_index,
962 tp->fei = FIB_NODE_INDEX_INVALID;
963 adj_unlock(tp->adj_index);
966 * unsource the route for the tunnel's subnet
968 const fib_prefix_t tun_sub_net_pfx = {
969 .fp_len = tp->mask_width,
970 .fp_proto = FIB_PROTOCOL_IP4,
972 .ip4 = tp->intfc_address,
976 fib_table_entry_delete(inner_fib_index,
978 FIB_SOURCE_INTERFACE);
981 u64 key = ((u64)tp->tunnel_src.as_u32 << 32 |
982 (u64)tp->tunnel_src.as_u32);
984 hash_unset (gm->tunnel_by_key, key);
985 mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 0);
986 ip4_sw_interface_enable_disable(hi->sw_if_index, 0);
988 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
990 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
991 vec_free (tp->rewrite_data);
992 fib_node_deinit(&tp->mgt_node);
993 pool_put (mm->gre_tunnels, tp);
999 vnet_mpls_gre_add_del_tunnel (ip4_address_t *src,
1001 ip4_address_t *intfc,
1003 u32 inner_fib_id, u32 outer_fib_id,
1004 u32 * tunnel_sw_if_index,
1008 u32 inner_fib_index = 0;
1009 u32 outer_fib_index = 0;
1011 ip4_main_t * im = &ip4_main;
1013 /* No questions, no answers */
1014 if (NULL == tunnel_sw_if_index)
1015 tunnel_sw_if_index = &dummy;
1017 *tunnel_sw_if_index = ~0;
1019 if (inner_fib_id != (u32)~0)
1023 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1025 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
1026 inner_fib_index = p[0];
1029 if (outer_fib_id != 0)
1033 p = hash_get (im->fib_index_by_table_id, outer_fib_id);
1035 return VNET_API_ERROR_NO_SUCH_FIB;
1036 outer_fib_index = p[0];
1041 return (mpls_gre_tunnel_add(src,dst,intfc, mask_width,
1049 return (mpls_gre_tunnel_del(src,dst,intfc, mask_width,
1058 * Remove all mpls tunnels in the specified fib
1060 int vnet_mpls_gre_delete_fib_tunnels (u32 fib_id)
1062 mpls_main_t * mm = &mpls_main;
1063 vnet_main_t * vnm = mm->vnet_main;
1064 mpls_gre_tunnel_t *tp;
1066 u32 * tunnels_to_delete = 0;
1067 vnet_hw_interface_t * hi;
1070 fib_index = ip4_fib_index_from_table_id(fib_id);
1071 if (~0 == fib_index)
1072 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
1074 pool_foreach (tp, mm->gre_tunnels,
1076 if (tp->inner_fib_index == fib_index)
1077 vec_add1 (tunnels_to_delete, tp - mm->gre_tunnels);
1080 for (i = 0; i < vec_len(tunnels_to_delete); i++) {
1081 tp = pool_elt_at_index (mm->gre_tunnels, tunnels_to_delete[i]);
1083 /* Delete, the route if not already gone */
1084 if (FIB_NODE_INDEX_INVALID != tp->fei && !tp->l2_only)
1086 const fib_prefix_t tun_dst_pfx = {
1088 .fp_proto = FIB_PROTOCOL_IP4,
1090 .ip4 = tp->tunnel_dst,
1094 fib_entry_child_remove(tp->fei,
1096 fib_table_entry_special_remove(tp->outer_fib_index,
1099 tp->fei = FIB_NODE_INDEX_INVALID;
1100 adj_unlock(tp->adj_index);
1102 const fib_prefix_t tun_sub_net_pfx = {
1103 .fp_len = tp->mask_width,
1104 .fp_proto = FIB_PROTOCOL_IP4,
1106 .ip4 = tp->intfc_address,
1110 fib_table_entry_delete(tp->inner_fib_index,
1112 FIB_SOURCE_INTERFACE);
1115 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1116 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1117 0 /* admin down */);
1118 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
1119 vec_free (tp->rewrite_data);
1120 pool_put (mm->gre_tunnels, tp);
1123 vec_free(tunnels_to_delete);
1128 static clib_error_t *
1129 create_mpls_gre_tunnel_command_fn (vlib_main_t * vm,
1130 unformat_input_t * input,
1131 vlib_cli_command_t * cmd)
1133 unformat_input_t _line_input, * line_input = &_line_input;
1134 ip4_address_t src, dst, intfc;
1135 int src_set = 0, dst_set = 0, intfc_set = 0;
1137 u32 inner_fib_id = (u32)~0;
1138 u32 outer_fib_id = 0;
1142 u32 tunnel_intfc_sw_if_index = ~0;
1144 /* Get a line of input. */
1145 if (! unformat_user (input, unformat_line_input, line_input))
1148 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1150 if (unformat (line_input, "src %U",
1151 unformat_ip4_address, &src))
1153 else if (unformat (line_input, "dst %U",
1154 unformat_ip4_address, &dst))
1156 else if (unformat (line_input, "intfc %U/%d",
1157 unformat_ip4_address, &intfc, &mask_width))
1159 else if (unformat (line_input, "inner-fib-id %d", &inner_fib_id))
1161 else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
1163 else if (unformat (line_input, "del"))
1165 else if (unformat (line_input, "l2-only"))
1168 return clib_error_return (0, "unknown input '%U'",
1169 format_unformat_error, line_input);
1173 return clib_error_return (0, "missing: src <ip-address>");
1176 return clib_error_return (0, "missing: dst <ip-address>");
1179 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1182 rv = vnet_mpls_gre_add_del_tunnel (&src, &dst, &intfc, mask_width,
1183 inner_fib_id, outer_fib_id,
1184 &tunnel_intfc_sw_if_index,
1191 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), tunnel_intfc_sw_if_index);
1194 case VNET_API_ERROR_NO_SUCH_INNER_FIB:
1195 return clib_error_return (0, "inner fib ID %d doesn't exist\n",
1197 case VNET_API_ERROR_NO_SUCH_FIB:
1198 return clib_error_return (0, "outer fib ID %d doesn't exist\n",
1201 case VNET_API_ERROR_NO_SUCH_ENTRY:
1202 return clib_error_return (0, "tunnel not found\n");
1204 case VNET_API_ERROR_NO_SUCH_LABEL:
1206 * This happens when there's no MPLS label for the dst address
1207 * no need for two error messages.
1212 return clib_error_return (0, "vnet_mpls_gre_add_del_tunnel returned %d",
1218 VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
1219 .path = "create mpls gre tunnel",
1221 "create mpls gre tunnel [del] src <addr> dst <addr> intfc <addr>/<mw>",
1222 .function = create_mpls_gre_tunnel_command_fn,
1225 u8 * format_mpls_encap_index (u8 * s, va_list * args)
1227 mpls_main_t * mm = va_arg (*args, mpls_main_t *);
1228 u32 entry_index = va_arg (*args, u32);
1232 e = pool_elt_at_index (mm->encaps, entry_index);
1234 for (i = 0; i < vec_len (e->labels); i++)
1236 (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
1237 (e->labels[i].label_exp_s_ttl)));
1242 u8 * format_mpls_gre_tunnel (u8 * s, va_list * args)
1244 mpls_gre_tunnel_t * t = va_arg (*args, mpls_gre_tunnel_t *);
1245 mpls_main_t * mm = &mpls_main;
1247 if (t->l2_only == 0)
1249 s = format (s, "[%d]: src %U, dst %U, adj %U/%d, labels %U\n",
1250 t - mm->gre_tunnels,
1251 format_ip4_address, &t->tunnel_src,
1252 format_ip4_address, &t->tunnel_dst,
1253 format_ip4_address, &t->intfc_address,
1255 format_mpls_encap_index, mm, t->encap_index);
1257 s = format (s, " inner fib index %d, outer fib index %d",
1258 t->inner_fib_index, t->outer_fib_index);
1262 s = format (s, "[%d]: src %U, dst %U, key %U, labels %U\n",
1263 t - mm->gre_tunnels,
1264 format_ip4_address, &t->tunnel_src,
1265 format_ip4_address, &t->tunnel_dst,
1266 format_ip4_address, &t->intfc_address,
1267 format_mpls_encap_index, mm, t->encap_index);
1269 s = format (s, " l2 interface %d, outer fib index %d",
1270 t->hw_if_index, t->outer_fib_index);
1276 u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
1278 mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
1279 mpls_main_t * mm = &mpls_main;
1281 s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
1282 t - mm->eth_tunnels,
1283 format_ethernet_address, &t->tunnel_dst,
1284 format_ip4_address, &t->intfc_address,
1286 format_mpls_encap_index, mm, t->encap_index);
1289 s = format (s, " tx on %U, rx fib index %d",
1290 format_vnet_sw_if_index_name, mm->vnet_main, t->tx_sw_if_index,
1291 t->inner_fib_index);
1296 static clib_error_t *
1297 show_mpls_tunnel_command_fn (vlib_main_t * vm,
1298 unformat_input_t * input,
1299 vlib_cli_command_t * cmd)
1301 mpls_main_t * mm = &mpls_main;
1302 mpls_gre_tunnel_t * gt;
1303 mpls_eth_tunnel_t * et;
1305 if (pool_elts (mm->gre_tunnels))
1307 vlib_cli_output (vm, "MPLS-GRE tunnels");
1308 pool_foreach (gt, mm->gre_tunnels,
1310 vlib_cli_output (vm, "%U", format_mpls_gre_tunnel, gt);
1314 vlib_cli_output (vm, "No MPLS-GRE tunnels");
1316 if (pool_elts (mm->eth_tunnels))
1318 vlib_cli_output (vm, "MPLS-Ethernet tunnels");
1319 pool_foreach (et, mm->eth_tunnels,
1321 vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
1325 vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
1330 VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
1331 .path = "show mpls tunnel",
1332 .short_help = "show mpls tunnel",
1333 .function = show_mpls_tunnel_command_fn,
1337 /* force inclusion from application's main.c */
1338 clib_error_t *mpls_interface_init (vlib_main_t *vm)
1340 clib_error_t * error;
1342 fib_node_register_type(FIB_NODE_TYPE_MPLS_GRE_TUNNEL,
1345 if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
1350 VLIB_INIT_FUNCTION(mpls_interface_init);
1353 static u8 * mpls_ethernet_rewrite (mpls_main_t *mm, mpls_eth_tunnel_t * t)
1355 u8 * rewrite_data = 0;
1357 mpls_unicast_header_t *lp0;
1360 /* look up the encap label stack using the RX FIB and adjacency address*/
1361 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index,
1362 t->intfc_address.as_u32);
1366 clib_warning ("no label for inner fib index %d, dst %U",
1367 t->inner_fib_index, format_ip4_address,
1372 vec_validate (rewrite_data,
1373 sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
1375 /* Copy the encap label stack */
1376 lp0 = (mpls_unicast_header_t *) rewrite_data;
1378 for (i = 0; i < vec_len(e->labels); i++)
1379 lp0[i] = e->labels[i];
1381 return (rewrite_data);
1384 int vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
1385 ip4_address_t *intfc,
1389 u32 * tunnel_sw_if_index,
1393 ip4_main_t * im = &ip4_main;
1394 ip_lookup_main_t * lm = &im->lookup_main;
1395 mpls_main_t * mm = &mpls_main;
1396 vnet_main_t * vnm = vnet_get_main();
1397 mpls_eth_tunnel_t *tp;
1398 u32 inner_fib_index = 0;
1402 int found_tunnel = 0;
1403 mpls_encap_t * e = 0;
1404 u32 hw_if_index = ~0;
1405 vnet_hw_interface_t * hi;
1409 if (tunnel_sw_if_index == 0)
1410 tunnel_sw_if_index = &dummy;
1412 *tunnel_sw_if_index = ~0;
1414 if (inner_fib_id != (u32)~0)
1418 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1420 return VNET_API_ERROR_NO_SUCH_FIB;
1421 inner_fib_index = p[0];
1424 /* suppress duplicate mpls interface generation. */
1425 pool_foreach (tp, mm->eth_tunnels,
1428 * If we have a tunnel which matches (src, dst, intfc/mask)
1429 * AND the expected route is in the FIB, it's a dup
1431 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1432 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1433 && tp->inner_fib_index == inner_fib_index
1434 && FIB_NODE_INDEX_INVALID != tp->fei)
1444 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
1447 return VNET_API_ERROR_NO_SUCH_LABEL;
1461 /* Delete, and we can't find the tunnel */
1462 if (is_add == 0 && found_tunnel == 0)
1463 return VNET_API_ERROR_NO_SUCH_ENTRY;
1465 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
1467 return VNET_API_ERROR_NO_SUCH_LABEL;
1469 pool_get(mm->eth_tunnels, tp);
1470 memset (tp, 0, sizeof (*tp));
1472 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1475 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1476 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1477 hi = vnet_get_hw_interface (vnm, hw_if_index);
1478 hi->dev_instance = tp - mm->eth_tunnels;
1479 hi->hw_instance = tp - mm->eth_tunnels;
1483 hw_if_index = vnet_register_interface
1484 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1485 mpls_eth_hw_interface_class.index,
1486 tp - mm->eth_tunnels);
1487 hi = vnet_get_hw_interface (vnm, hw_if_index);
1489 /* ... to make the IP and L2 x-connect cases identical */
1490 slot = vlib_node_add_named_next_with_slot
1491 (vnm->vlib_main, hi->tx_node_index,
1492 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1494 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1497 *tunnel_sw_if_index = hi->sw_if_index;
1498 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1499 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1501 tp->hw_if_index = hw_if_index;
1504 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1505 tp->intfc_address.as_u32 = intfc->as_u32;
1506 tp->mask_width = mask_width;
1507 tp->inner_fib_index = inner_fib_index;
1508 tp->encap_index = e - mm->encaps;
1509 tp->tx_sw_if_index = tx_sw_if_index;
1510 tp->l2_only = l2_only;
1512 /* Create the adjacency and add to v4 fib */
1513 memset(&adj, 0, sizeof (adj));
1514 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1516 rewrite_data = mpls_ethernet_rewrite (mm, tp);
1517 if (rewrite_data == 0)
1519 if (*tunnel_sw_if_index != ~0)
1521 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1522 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1523 0 /* admin down */);
1524 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1527 pool_put (mm->eth_tunnels, tp);
1528 return VNET_API_ERROR_NO_SUCH_LABEL;
1531 vnet_rewrite_for_sw_interface
1535 ip4_rewrite_node.index,
1537 &adj.rewrite_header,
1538 sizeof (adj.rewrite_data));
1541 * Prepend the (0,1,2) VLAN tag ethernet header
1542 * we just built to the mpls header stack
1544 vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
1545 clib_memcpy(rewrite_data,
1546 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1547 sizeof (adj.rewrite_data)),
1548 adj.rewrite_header.data_bytes);
1550 vnet_rewrite_set_data_internal (&adj.rewrite_header,
1551 sizeof(adj.rewrite_data),
1553 vec_len(rewrite_data));
1555 vec_free (tp->rewrite_data);
1557 tp->rewrite_data = rewrite_data;
1560 ip_add_adjacency (lm, &adj, 1 /* one adj */,
1567 const fib_prefix_t pfx = {
1569 .ip4 = tp->intfc_address,
1571 .fp_len = tp->mask_width,
1572 .fp_proto = FIB_PROTOCOL_IP4,
1575 tp->fei = fib_table_entry_special_add(tp->inner_fib_index,
1578 FIB_ENTRY_FLAG_NONE,
1582 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
1583 tp->fei = FIB_NODE_INDEX_INVALID;
1586 if (is_add == 0 && found_tunnel)
1588 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1589 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1590 0 /* admin down */);
1591 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1592 vec_free (tp->rewrite_data);
1593 pool_put (mm->eth_tunnels, tp);
1599 static clib_error_t *
1600 create_mpls_ethernet_tunnel_command_fn (vlib_main_t * vm,
1601 unformat_input_t * input,
1602 vlib_cli_command_t * cmd)
1604 unformat_input_t _line_input, * line_input = &_line_input;
1605 vnet_main_t * vnm = vnet_get_main();
1606 ip4_address_t intfc;
1609 int dst_set = 0, intfc_set = 0;
1611 u32 inner_fib_id = (u32)~0;
1616 u32 sw_if_index = ~0;
1618 /* Get a line of input. */
1619 if (! unformat_user (input, unformat_line_input, line_input))
1622 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1624 if (unformat (line_input, "dst %U",
1625 unformat_ethernet_address, &dst))
1627 else if (unformat (line_input, "adj %U/%d",
1628 unformat_ip4_address, &intfc, &mask_width))
1630 else if (unformat (line_input, "tx-intfc %U",
1631 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1633 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1635 else if (unformat (line_input, "l2-only"))
1637 else if (unformat (line_input, "del"))
1640 return clib_error_return (0, "unknown input '%U'",
1641 format_unformat_error, line_input);
1645 return clib_error_return (0, "missing tx-intfc");
1648 return clib_error_return (0, "missing: dst <ethernet-address>");
1651 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1654 rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
1655 inner_fib_id, tx_sw_if_index,
1663 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
1665 case VNET_API_ERROR_NO_SUCH_FIB:
1666 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1669 case VNET_API_ERROR_NO_SUCH_ENTRY:
1670 return clib_error_return (0, "tunnel not found\n");
1672 case VNET_API_ERROR_NO_SUCH_LABEL:
1674 * This happens when there's no MPLS label for the dst address
1675 * no need for two error messages.
1677 return clib_error_return (0, "no label for %U in fib %d",
1678 format_ip4_address, &intfc, inner_fib_id);
1682 return clib_error_return (0, "vnet_mpls_ethernet_add_del_tunnel returned %d", rv);
1689 VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
1690 .path = "create mpls ethernet tunnel",
1692 "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
1693 .function = create_mpls_ethernet_tunnel_command_fn,
1697 int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
1699 u32 policy_tunnel_index)
1701 mpls_eth_tunnel_t * t;
1703 u8 * rewrite_data = 0;
1705 mpls_unicast_header_t *lp;
1708 if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
1709 return VNET_API_ERROR_NO_SUCH_ENTRY;
1711 t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
1713 memset (&adj, 0, sizeof (adj));
1715 /* Build L2 encap */
1716 vnet_rewrite_for_sw_interface
1720 mpls_policy_encap_node.index,
1722 &adj.rewrite_header,
1723 sizeof (adj.rewrite_data));
1725 vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
1727 clib_memcpy(rewrite_data,
1728 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1729 sizeof (adj.rewrite_data)),
1730 adj.rewrite_header.data_bytes);
1732 /* Append the label stack */
1734 vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
1736 lp = (mpls_unicast_header_t *) label_start;
1738 for (i = 0; i < vec_len(e->labels); i++)
1739 lp[i] = e->labels[i];
1741 /* Remember the rewrite data */
1742 e->rewrite = rewrite_data;
1743 e->output_next_index = adj.rewrite_header.next_index;
1748 int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
1749 ip4_address_t *intfc,
1753 u32 * tunnel_sw_if_index,
1754 u32 classify_table_index,
1755 u32 * new_tunnel_index,
1759 ip4_main_t * im = &ip4_main;
1760 mpls_main_t * mm = &mpls_main;
1761 vnet_main_t * vnm = vnet_get_main();
1762 mpls_eth_tunnel_t *tp;
1763 u32 inner_fib_index = 0;
1764 int found_tunnel = 0;
1765 mpls_encap_t * e = 0;
1766 u32 hw_if_index = ~0;
1767 vnet_hw_interface_t * hi;
1771 if (tunnel_sw_if_index == 0)
1772 tunnel_sw_if_index = &dummy;
1774 *tunnel_sw_if_index = ~0;
1776 if (inner_fib_id != (u32)~0)
1780 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1782 return VNET_API_ERROR_NO_SUCH_FIB;
1783 inner_fib_index = p[0];
1786 /* suppress duplicate mpls interface generation. */
1787 pool_foreach (tp, mm->eth_tunnels,
1790 * If we have a tunnel which matches (src, dst, intfc/mask)
1791 * AND the expected route is in the FIB, it's a dup
1793 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1794 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1795 && tp->inner_fib_index == inner_fib_index
1796 && FIB_NODE_INDEX_INVALID != tp->fei)
1818 /* Delete, and we can't find the tunnel */
1819 if (is_add == 0 && found_tunnel == 0)
1820 return VNET_API_ERROR_NO_SUCH_ENTRY;
1822 pool_get(mm->eth_tunnels, tp);
1823 memset (tp, 0, sizeof (*tp));
1825 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1828 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1829 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1830 hi = vnet_get_hw_interface (vnm, hw_if_index);
1831 hi->dev_instance = tp - mm->eth_tunnels;
1832 hi->hw_instance = tp - mm->eth_tunnels;
1836 hw_if_index = vnet_register_interface
1837 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1838 mpls_eth_hw_interface_class.index,
1839 tp - mm->eth_tunnels);
1840 hi = vnet_get_hw_interface (vnm, hw_if_index);
1842 /* ... to make the IP and L2 x-connect cases identical */
1843 slot = vlib_node_add_named_next_with_slot
1844 (vnm->vlib_main, hi->tx_node_index,
1845 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1847 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1850 *tunnel_sw_if_index = hi->sw_if_index;
1851 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1852 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1854 tp->hw_if_index = hw_if_index;
1857 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1858 tp->intfc_address.as_u32 = intfc->as_u32;
1859 tp->mask_width = mask_width;
1860 tp->inner_fib_index = inner_fib_index;
1861 tp->encap_index = e - mm->encaps;
1862 tp->tx_sw_if_index = tx_sw_if_index;
1863 tp->l2_only = l2_only;
1864 tp->fei = FIB_NODE_INDEX_INVALID;
1866 if (new_tunnel_index)
1867 *new_tunnel_index = tp - mm->eth_tunnels;
1873 const fib_prefix_t pfx = {
1875 .ip4 = tp->intfc_address,
1877 .fp_len = tp->mask_width,
1878 .fp_proto = FIB_PROTOCOL_IP4,
1880 dpo_id_t dpo = DPO_NULL;
1887 classify_dpo_create(FIB_PROTOCOL_IP4,
1888 classify_table_index));
1890 tp->fei = fib_table_entry_special_dpo_add(tp->inner_fib_index,
1893 FIB_ENTRY_FLAG_EXCLUSIVE,
1899 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
1900 tp->fei = FIB_NODE_INDEX_INVALID;
1903 if (is_add == 0 && found_tunnel)
1905 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1906 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1907 0 /* admin down */);
1908 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1909 pool_put (mm->eth_tunnels, tp);
1915 static clib_error_t *
1916 create_mpls_ethernet_policy_tunnel_command_fn (vlib_main_t * vm,
1917 unformat_input_t * input,
1918 vlib_cli_command_t * cmd)
1920 unformat_input_t _line_input, * line_input = &_line_input;
1921 vnet_main_t * vnm = vnet_get_main();
1922 ip4_address_t intfc;
1925 int dst_set = 0, intfc_set = 0;
1927 u32 inner_fib_id = (u32)~0;
1928 u32 classify_table_index = (u32)~0;
1929 u32 new_tunnel_index;
1935 /* Get a line of input. */
1936 if (! unformat_user (input, unformat_line_input, line_input))
1939 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1941 if (unformat (line_input, "dst %U",
1942 unformat_ethernet_address, &dst))
1944 else if (unformat (line_input, "adj %U/%d",
1945 unformat_ip4_address, &intfc, &mask_width))
1947 else if (unformat (line_input, "tx-intfc %U",
1948 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1950 else if (unformat (line_input, "classify-table-index %d",
1951 &classify_table_index))
1953 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1955 else if (unformat (line_input, "l2-only"))
1957 else if (unformat (line_input, "del"))
1960 return clib_error_return (0, "unknown input '%U'",
1961 format_unformat_error, line_input);
1964 if (classify_table_index == ~0)
1965 return clib_error_return (0, "missing classify_table_index");
1968 return clib_error_return (0, "missing tx-intfc");
1971 return clib_error_return (0, "missing: dst <ethernet-address>");
1974 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1977 rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
1978 inner_fib_id, tx_sw_if_index,
1979 0 /* tunnel sw_if_index */,
1980 classify_table_index,
1987 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), new_tunnel_index);
1989 case VNET_API_ERROR_NO_SUCH_FIB:
1990 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1993 case VNET_API_ERROR_NO_SUCH_ENTRY:
1994 return clib_error_return (0, "tunnel not found\n");
1996 case VNET_API_ERROR_NO_SUCH_LABEL:
1998 * This happens when there's no MPLS label for the dst address
1999 * no need for two error messages.
2001 return clib_error_return (0, "no label for %U in fib %d",
2002 format_ip4_address, &intfc, inner_fib_id);
2006 return clib_error_return (0, "vnet_mpls_ethernet_add_del_policy_tunnel returned %d", rv);
2013 VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
2014 .path = "create mpls ethernet policy tunnel",
2016 "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
2017 " classify-table-index <nn>",
2018 .function = create_mpls_ethernet_policy_tunnel_command_fn,
2021 static clib_error_t *
2022 mpls_interface_enable_disable (vlib_main_t * vm,
2023 unformat_input_t * input,
2024 vlib_cli_command_t * cmd)
2026 vnet_main_t * vnm = vnet_get_main();
2027 clib_error_t * error = 0;
2028 u32 sw_if_index, enable;
2032 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
2034 error = clib_error_return (0, "unknown interface `%U'",
2035 format_unformat_error, input);
2039 if (unformat (input, "enable"))
2041 else if (unformat (input, "disable"))
2045 error = clib_error_return (0, "expected 'enable' or 'disable'",
2046 format_unformat_error, input);
2050 mpls_sw_interface_enable_disable(&mpls_main, sw_if_index, enable);
2056 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
2057 .path = "set interface mpls",
2058 .function = mpls_interface_enable_disable,
2059 .short_help = "Enable/Disable an interface for MPLS forwarding",