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-gre/mpls.h>
23 static uword mpls_gre_set_rewrite (vnet_main_t * vnm,
28 uword max_rewrite_bytes)
31 * Conundrum: packets from tun/tap destined for the tunnel
32 * actually have this rewrite applied. Transit packets do not.
33 * To make the two cases equivalent, don't generate a
34 * rewrite here, build the entire header in the fast path.
39 /* manually added to the interface output node */
40 #define MPLS_GRE_OUTPUT_NEXT_POST_REWRITE 1
43 mpls_gre_interface_tx (vlib_main_t * vm,
44 vlib_node_runtime_t * node,
47 mpls_main_t * gm = &mpls_main;
48 vnet_main_t * vnm = gm->vnet_main;
50 u32 * from, * to_next, n_left_from, n_left_to_next;
52 /* Vector of buffer / pkt indices we're supposed to process */
53 from = vlib_frame_vector_args (frame);
55 /* Number of buffers / pkts */
56 n_left_from = frame->n_vectors;
58 /* Speculatively send the first buffer to the last disposition we used */
59 next_index = node->cached_next_index;
61 while (n_left_from > 0)
63 /* set up to enqueue to our disposition with index = next_index */
64 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
67 * As long as we have enough pkts left to process two pkts
68 * and prefetch two pkts...
70 while (n_left_from >= 4 && n_left_to_next >= 2)
72 vlib_buffer_t * b0, * b1;
73 u32 bi0, next0, bi1, next1;
74 mpls_gre_tunnel_t * t0, * t1;
75 u32 sw_if_index0, sw_if_index1;
76 vnet_hw_interface_t * hi0, * hi1;
79 /* Prefetch the next iteration */
81 vlib_buffer_t * p2, * p3;
83 p2 = vlib_get_buffer (vm, from[2]);
84 p3 = vlib_get_buffer (vm, from[3]);
86 vlib_prefetch_buffer_header (p2, LOAD);
87 vlib_prefetch_buffer_header (p3, LOAD);
90 * Prefetch packet data. We expect to overwrite
91 * the inbound L2 header with an ip header and a
92 * gre header. Might want to prefetch the last line
93 * of rewrite space as well; need profile data
95 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
96 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
99 /* Pick up the next two buffer indices */
103 /* Speculatively enqueue them where we sent the last buffer */
111 b0 = vlib_get_buffer (vm, bi0);
112 b1 = vlib_get_buffer (vm, bi1);
114 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
115 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
118 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
119 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
121 /* hw_instance = tunnel pool index */
122 t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance);
123 t1 = pool_elt_at_index (gm->gre_tunnels, hi1->hw_instance);
125 /* Apply rewrite - $$$$$ fixme don't use memcpy */
126 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
127 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
129 dst0 = vlib_buffer_get_current (b0);
130 dst1 = vlib_buffer_get_current (b1);
132 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
133 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
135 /* Fix TX fib indices */
136 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
137 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->outer_fib_index;
139 /* mpls-post-rewrite takes it from here... */
140 next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
141 next1 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
143 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
145 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
147 tr->tunnel_id = t0 - gm->gre_tunnels;
148 tr->length = b0->current_length;
149 tr->src.as_u32 = t0->tunnel_src.as_u32;
150 tr->dst.as_u32 = t0->tunnel_dst.as_u32;
152 tr->mpls_encap_index = t0->encap_index;
154 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
156 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
158 tr->tunnel_id = t1 - gm->gre_tunnels;
159 tr->length = b1->current_length;
160 tr->src.as_u32 = t1->tunnel_src.as_u32;
161 tr->dst.as_u32 = t1->tunnel_dst.as_u32;
163 tr->mpls_encap_index = t1->encap_index;
166 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
167 to_next, n_left_to_next,
168 bi0, bi1, next0, next1);
171 while (n_left_from > 0 && n_left_to_next > 0)
175 mpls_gre_tunnel_t * t0;
177 vnet_hw_interface_t * hi0;
187 b0 = vlib_get_buffer (vm, bi0);
189 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
191 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
193 t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance);
195 /* Apply rewrite - $$$$$ fixme don't use memcpy */
196 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
198 dst0 = vlib_buffer_get_current (b0);
200 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
202 /* Fix the TX fib index */
203 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
205 /* mpls-post-rewrite takes it from here... */
206 next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
208 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
210 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
212 tr->tunnel_id = t0 - gm->gre_tunnels;
213 tr->length = b0->current_length;
214 tr->src.as_u32 = t0->tunnel_src.as_u32;
215 tr->dst.as_u32 = t0->tunnel_dst.as_u32;
217 tr->mpls_encap_index = t0->encap_index;
220 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
221 to_next, n_left_to_next,
225 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
228 vlib_node_increment_counter (vm, gre_input_node.index,
229 GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
231 return frame->n_vectors;
234 static u8 * format_mpls_gre_tunnel_name (u8 * s, va_list * args)
236 u32 dev_instance = va_arg (*args, u32);
237 return format (s, "mpls-gre%d", dev_instance);
240 static u8 * format_mpls_gre_device (u8 * s, va_list * args)
242 u32 dev_instance = va_arg (*args, u32);
243 CLIB_UNUSED (int verbose) = va_arg (*args, int);
245 s = format (s, "MPLS-GRE tunnel: id %d\n", dev_instance);
249 VNET_DEVICE_CLASS (mpls_gre_device_class) = {
250 .name = "MPLS-GRE tunnel device",
251 .format_device_name = format_mpls_gre_tunnel_name,
252 .format_device = format_mpls_gre_device,
253 .format_tx_trace = format_mpls_gre_tx_trace,
254 .tx_function = mpls_gre_interface_tx,
255 .no_flatten_output_chains = 1,
258 .admin_up_down_function = 0;
262 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_gre_device_class,
263 mpls_gre_interface_tx)
265 VNET_HW_INTERFACE_CLASS (mpls_gre_hw_interface_class) = {
267 .format_header = format_mpls_gre_header_with_length,
269 .unformat_header = unformat_mpls_gre_header,
271 .set_rewrite = mpls_gre_set_rewrite,
275 static uword mpls_eth_set_rewrite (vnet_main_t * vnm,
280 uword max_rewrite_bytes)
283 * Conundrum: packets from tun/tap destined for the tunnel
284 * actually have this rewrite applied. Transit packets do not.
285 * To make the two cases equivalent, don't generate a
286 * rewrite here, build the entire header in the fast path.
291 /* manually added to the interface output node */
292 #define MPLS_ETH_OUTPUT_NEXT_OUTPUT 1
295 mpls_eth_interface_tx (vlib_main_t * vm,
296 vlib_node_runtime_t * node,
297 vlib_frame_t * frame)
299 mpls_main_t * gm = &mpls_main;
300 vnet_main_t * vnm = gm->vnet_main;
302 u32 * from, * to_next, n_left_from, n_left_to_next;
304 /* Vector of buffer / pkt indices we're supposed to process */
305 from = vlib_frame_vector_args (frame);
307 /* Number of buffers / pkts */
308 n_left_from = frame->n_vectors;
310 /* Speculatively send the first buffer to the last disposition we used */
311 next_index = node->cached_next_index;
313 while (n_left_from > 0)
315 /* set up to enqueue to our disposition with index = next_index */
316 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
319 * As long as we have enough pkts left to process two pkts
320 * and prefetch two pkts...
322 while (n_left_from >= 4 && n_left_to_next >= 2)
324 vlib_buffer_t * b0, * b1;
325 u32 bi0, next0, bi1, next1;
326 mpls_eth_tunnel_t * t0, * t1;
327 u32 sw_if_index0, sw_if_index1;
328 vnet_hw_interface_t * hi0, * hi1;
331 /* Prefetch the next iteration */
333 vlib_buffer_t * p2, * p3;
335 p2 = vlib_get_buffer (vm, from[2]);
336 p3 = vlib_get_buffer (vm, from[3]);
338 vlib_prefetch_buffer_header (p2, LOAD);
339 vlib_prefetch_buffer_header (p3, LOAD);
342 * Prefetch packet data. We expect to overwrite
343 * the inbound L2 header with an ip header and a
344 * gre header. Might want to prefetch the last line
345 * of rewrite space as well; need profile data
347 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
348 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
351 /* Pick up the next two buffer indices */
355 /* Speculatively enqueue them where we sent the last buffer */
363 b0 = vlib_get_buffer (vm, bi0);
364 b1 = vlib_get_buffer (vm, bi1);
366 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
367 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
370 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
371 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
373 /* hw_instance = tunnel pool index */
374 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
375 t1 = pool_elt_at_index (gm->eth_tunnels, hi1->hw_instance);
377 /* Apply rewrite - $$$$$ fixme don't use memcpy */
378 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
379 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
381 dst0 = vlib_buffer_get_current (b0);
382 dst1 = vlib_buffer_get_current (b1);
384 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
385 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
387 /* Fix TX fib indices */
388 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
389 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->tx_sw_if_index;
391 /* mpls-post-rewrite takes it from here... */
392 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
393 next1 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
395 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
397 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
400 tr->tunnel_id = t0 - gm->eth_tunnels;
401 tr->tx_sw_if_index = t0->tx_sw_if_index;
402 tr->mpls_encap_index = t0->encap_index;
403 tr->length = b0->current_length;
404 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
405 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
407 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
409 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
412 tr->tunnel_id = t1 - gm->eth_tunnels;
413 tr->tx_sw_if_index = t1->tx_sw_if_index;
414 tr->mpls_encap_index = t1->encap_index;
415 tr->length = b1->current_length;
416 hi1 = vnet_get_sup_hw_interface (vnm, t1->tx_sw_if_index);
417 clib_memcpy (tr->dst, hi1->hw_address, sizeof (tr->dst));
420 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
421 to_next, n_left_to_next,
422 bi0, bi1, next0, next1);
424 while (n_left_from > 0 && n_left_to_next > 0)
428 mpls_eth_tunnel_t * t0;
430 vnet_hw_interface_t * hi0;
440 b0 = vlib_get_buffer (vm, bi0);
442 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
444 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
446 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
448 /* Apply rewrite - $$$$$ fixme don't use memcpy */
449 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
451 dst0 = vlib_buffer_get_current (b0);
453 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
455 /* Fix the TX interface */
456 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
458 /* Send the packet */
459 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
461 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
463 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
466 tr->tunnel_id = t0 - gm->eth_tunnels;
467 tr->tx_sw_if_index = t0->tx_sw_if_index;
468 tr->mpls_encap_index = t0->encap_index;
469 tr->length = b0->current_length;
470 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
471 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
474 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
475 to_next, n_left_to_next,
479 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
482 vlib_node_increment_counter (vm, mpls_input_node.index,
483 MPLS_ERROR_PKTS_ENCAP, frame->n_vectors);
485 return frame->n_vectors;
488 static u8 * format_mpls_eth_tunnel_name (u8 * s, va_list * args)
490 u32 dev_instance = va_arg (*args, u32);
491 return format (s, "mpls-eth%d", dev_instance);
494 static u8 * format_mpls_eth_device (u8 * s, va_list * args)
496 u32 dev_instance = va_arg (*args, u32);
497 CLIB_UNUSED (int verbose) = va_arg (*args, int);
499 s = format (s, "MPLS-ETH tunnel: id %d\n", dev_instance);
503 VNET_DEVICE_CLASS (mpls_eth_device_class) = {
504 .name = "MPLS-ETH tunnel device",
505 .format_device_name = format_mpls_eth_tunnel_name,
506 .format_device = format_mpls_eth_device,
507 .format_tx_trace = format_mpls_eth_tx_trace,
508 .tx_function = mpls_eth_interface_tx,
509 .no_flatten_output_chains = 1,
512 .admin_up_down_function = 0;
516 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_eth_device_class,
517 mpls_eth_interface_tx)
519 VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = {
521 .format_header = format_mpls_eth_header_with_length,
523 .unformat_header = unformat_mpls_eth_header,
525 .set_rewrite = mpls_eth_set_rewrite,
528 #define foreach_mpls_post_rewrite_next \
529 _ (IP4_LOOKUP, "ip4-lookup")
532 #define _(s,n) MPLS_POST_REWRITE_NEXT_##s,
533 foreach_mpls_post_rewrite_next
535 MPLS_POST_REWRITE_N_NEXT,
536 } mpls_post_rewrite_next_t;
540 mpls_post_rewrite (vlib_main_t * vm,
541 vlib_node_runtime_t * node,
542 vlib_frame_t * from_frame)
544 u32 n_left_from, next_index, * from, * to_next;
545 u16 old_l0 = 0, old_l1 = 0;
547 from = vlib_frame_vector_args (from_frame);
548 n_left_from = from_frame->n_vectors;
550 next_index = node->cached_next_index;
552 while (n_left_from > 0)
556 vlib_get_next_frame (vm, node, next_index,
557 to_next, n_left_to_next);
559 while (n_left_from >= 4 && n_left_to_next >= 2)
562 vlib_buffer_t * b0, * b1;
563 ip4_header_t * ip0, * ip1;
564 u32 next0 = MPLS_POST_REWRITE_NEXT_IP4_LOOKUP;
565 u32 next1 = MPLS_POST_REWRITE_NEXT_IP4_LOOKUP;
567 ip_csum_t sum0, sum1;
569 /* Prefetch next iteration. */
571 vlib_buffer_t * p2, * p3;
573 p2 = vlib_get_buffer (vm, from[2]);
574 p3 = vlib_get_buffer (vm, from[3]);
576 vlib_prefetch_buffer_header (p2, LOAD);
577 vlib_prefetch_buffer_header (p3, LOAD);
579 CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
580 CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
593 b0 = vlib_get_buffer (vm, bi0);
594 b1 = vlib_get_buffer (vm, bi1);
595 ip0 = vlib_buffer_get_current (b0);
596 ip1 = vlib_buffer_get_current (b1);
598 /* Note: the tunnel rewrite sets up sw_if_index[VLIB_TX] */
600 /* set the GRE (outer) ip packet length, fix the bloody checksum */
601 sum0 = ip0->checksum;
602 sum1 = ip1->checksum;
604 /* old_l0, old_l1 always 0, see the rewrite setup */
606 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
608 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
610 sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
611 length /* changed member */);
612 sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
613 length /* changed member */);
614 ip0->checksum = ip_csum_fold (sum0);
615 ip1->checksum = ip_csum_fold (sum1);
616 ip0->length = new_l0;
617 ip1->length = new_l1;
619 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
620 to_next, n_left_to_next,
621 bi0, bi1, next0, next1);
624 while (n_left_from > 0 && n_left_to_next > 0)
629 u32 next0 = MPLS_POST_REWRITE_NEXT_IP4_LOOKUP;
640 b0 = vlib_get_buffer (vm, bi0);
641 ip0 = vlib_buffer_get_current (b0);
643 /* Note: the tunnel rewrite sets up sw_if_index[VLIB_TX] */
645 /* set the GRE (outer) ip packet length, fix the bloody checksum */
646 sum0 = ip0->checksum;
647 /* old_l0 always 0, see the rewrite setup */
649 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
651 sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
652 length /* changed member */);
653 ip0->checksum = ip_csum_fold (sum0);
654 ip0->length = new_l0;
656 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
657 to_next, n_left_to_next,
661 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
663 vlib_node_increment_counter (vm, mpls_input_node.index,
664 MPLS_ERROR_PKTS_ENCAP, from_frame->n_vectors);
665 return from_frame->n_vectors;
668 VLIB_REGISTER_NODE (mpls_post_rewrite_node) = {
669 .function = mpls_post_rewrite,
670 .name = "mpls-post-rewrite",
671 /* Takes a vector of packets. */
672 .vector_size = sizeof (u32),
674 .runtime_data_bytes = 0,
676 .n_next_nodes = MPLS_POST_REWRITE_N_NEXT,
678 #define _(s,n) [MPLS_POST_REWRITE_NEXT_##s] = n,
679 foreach_mpls_post_rewrite_next
684 VLIB_NODE_FUNCTION_MULTIARCH (mpls_post_rewrite_node, mpls_post_rewrite)
686 static u8 * mpls_gre_rewrite (mpls_main_t *mm, mpls_gre_tunnel_t * t)
689 ip4_gre_and_mpls_header_t * h0;
690 u8 * rewrite_data = 0;
692 mpls_unicast_header_t *lp0;
695 /* look up the encap label stack using the RX FIB */
696 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index, t->tunnel_dst.as_u32);
700 clib_warning ("no label for inner fib index %d, dst %U",
701 t->inner_fib_index, format_ip4_address,
706 vec_validate (rewrite_data, sizeof (*h0)
707 + sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
708 memset (rewrite_data, 0, sizeof (*h0));
710 h0 = (ip4_gre_and_mpls_header_t *) rewrite_data;
711 /* Copy the encap label stack */
713 for (i = 0; i < vec_len(e->labels); i++)
714 lp0[i] = e->labels[i];
716 h0->gre.protocol = clib_host_to_net_u16(GRE_PROTOCOL_mpls_unicast);
717 ip0->ip_version_and_header_length = 0x45;
719 ip0->protocol = IP_PROTOCOL_GRE;
720 /* $$$ fixup ip4 header length and checksum after-the-fact */
721 ip0->src_address.as_u32 = t->tunnel_src.as_u32;
722 ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
723 ip0->checksum = ip4_header_checksum (ip0);
725 return (rewrite_data);
728 int vnet_mpls_gre_add_del_tunnel (ip4_address_t *src,
730 ip4_address_t *intfc,
732 u32 inner_fib_id, u32 outer_fib_id,
733 u32 * tunnel_sw_if_index,
737 ip4_main_t * im = &ip4_main;
738 ip_lookup_main_t * lm = &im->lookup_main;
739 mpls_main_t * mm = &mpls_main;
740 vnet_main_t * vnm = vnet_get_main();
742 mpls_gre_tunnel_t *tp;
743 int need_route_add_del = 1;
744 u32 inner_fib_index = 0;
745 u32 outer_fib_index = 0;
749 int found_tunnel = 0;
750 mpls_encap_t * e = 0;
751 u32 hw_if_index = ~0;
752 vnet_hw_interface_t * hi;
758 /* No questions, no answers */
759 if (tunnel_sw_if_index == 0)
760 tunnel_sw_if_index = &dummy;
762 *tunnel_sw_if_index = ~0;
764 if (inner_fib_id != (u32)~0)
768 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
770 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
771 inner_fib_index = p[0];
774 if (outer_fib_id != 0)
778 p = hash_get (im->fib_index_by_table_id, outer_fib_id);
780 return VNET_API_ERROR_NO_SUCH_FIB;
781 outer_fib_index = p[0];
784 /* suppress duplicate mpls interface generation. */
785 pool_foreach (tp, mm->gre_tunnels,
788 * If we have a tunnel which matches (src, dst, intfc/mask)
789 * AND the expected route is in the FIB, it's a dup
791 if (!memcmp (&tp->tunnel_src, src, sizeof (*src))
792 && !memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
793 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
794 && tp->inner_fib_index == inner_fib_index)
796 ip4_fib_t * fib = vec_elt_at_index (im->fibs, inner_fib_index);
797 uword * hash = fib->adj_index_by_dst_address[mask_width];
798 uword key = intfc->as_u32 & im->fib_masks[mask_width];
799 uword *p = hash_get (hash, key);
805 /* A dup, and the route is in the fib. Done */
810 /* Reinstall the route (and other stuff) */
811 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
814 return VNET_API_ERROR_NO_SUCH_LABEL;
820 /* Delete, the route is already gone? */
822 need_route_add_del = 0;
829 /* Delete, and we can't find the tunnel */
830 if (is_add == 0 && found_tunnel == 0)
831 return VNET_API_ERROR_NO_SUCH_ENTRY;
833 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, dst->as_u32);
835 return VNET_API_ERROR_NO_SUCH_LABEL;
837 pool_get(mm->gre_tunnels, tp);
838 memset (tp, 0, sizeof (*tp));
840 if (vec_len (mm->free_gre_sw_if_indices) > 0)
843 mm->free_gre_sw_if_indices[vec_len(mm->free_gre_sw_if_indices)-1];
844 _vec_len (mm->free_gre_sw_if_indices) -= 1;
845 hi = vnet_get_hw_interface (vnm, hw_if_index);
846 hi->dev_instance = tp - mm->gre_tunnels;
847 hi->hw_instance = tp - mm->gre_tunnels;
851 hw_if_index = vnet_register_interface
852 (vnm, mpls_gre_device_class.index, tp - mm->gre_tunnels,
853 mpls_gre_hw_interface_class.index,
854 tp - mm->gre_tunnels);
855 hi = vnet_get_hw_interface (vnm, hw_if_index);
857 /* ... to make the IP and L2 x-connect cases identical */
858 slot = vlib_node_add_named_next_with_slot
859 (vnm->vlib_main, hi->tx_node_index,
860 "mpls-post-rewrite", MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
862 ASSERT (slot == MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
865 *tunnel_sw_if_index = hi->sw_if_index;
866 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
867 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
869 tp->hw_if_index = hw_if_index;
872 tp->tunnel_src.as_u32 = src->as_u32;
873 tp->tunnel_dst.as_u32 = dst->as_u32;
874 tp->intfc_address.as_u32 = intfc->as_u32;
875 tp->mask_width = mask_width;
876 tp->inner_fib_index = inner_fib_index;
877 tp->outer_fib_index = outer_fib_index;
878 tp->encap_index = e - mm->encaps;
879 tp->l2_only = l2_only;
881 /* Create the adjacency and add to v4 fib */
882 memset(&adj, 0, sizeof (adj));
883 adj.explicit_fib_index = ~0;
884 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
886 rewrite_data = mpls_gre_rewrite (mm, tp);
887 if (rewrite_data == 0)
889 if (*tunnel_sw_if_index != ~0)
891 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
892 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
894 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
896 pool_put (mm->gre_tunnels, tp);
897 return VNET_API_ERROR_NO_SUCH_LABEL;
900 /* Save a copy of the rewrite data for L2 x-connect */
901 vec_free (tp->rewrite_data);
903 tp->rewrite_data = rewrite_data;
905 vnet_rewrite_for_tunnel
907 outer_fib_index /* tx_sw_if_index, aka outer fib ID */,
908 ip4_rewrite_node.index,
909 mpls_post_rewrite_node.index,
911 rewrite_data, vec_len(rewrite_data));
914 ip_add_adjacency (lm, &adj, 1 /* one adj */,
919 if (need_route_add_del && !l2_only)
922 ip4_add_del_route_next_hop (im,
926 &zero /* no next hop */,
927 (u32)~0 /* next_hop_sw_if_index */,
930 tp->inner_fib_index);
933 ip4_add_del_route_args_t a;
934 memset (&a, 0, sizeof (a));
936 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
937 a.table_index_or_table_id = tp->inner_fib_index;
938 a.dst_address = tp->intfc_address;
939 a.dst_address_length = tp->mask_width;
942 ip4_add_del_route (im, &a);
943 ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
944 IP4_ROUTE_FLAG_FIB_INDEX);
948 if (is_add == 0 && found_tunnel)
950 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
951 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
953 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
954 vec_free (tp->rewrite_data);
955 pool_put (mm->gre_tunnels, tp);
962 * Remove all mpls tunnels in the specified fib
964 int vnet_mpls_gre_delete_fib_tunnels (u32 fib_id)
966 ip4_main_t * im = &ip4_main;
967 mpls_main_t * mm = &mpls_main;
968 vnet_main_t * vnm = mm->vnet_main;
969 mpls_gre_tunnel_t *tp;
972 u32 * tunnels_to_delete = 0;
973 vnet_hw_interface_t * hi;
977 p = hash_get (im->fib_index_by_table_id, fib_id);
979 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
982 pool_foreach (tp, mm->gre_tunnels,
984 if (tp->inner_fib_index == fib_index)
985 vec_add1 (tunnels_to_delete, tp - mm->gre_tunnels);
988 fib = vec_elt_at_index (im->fibs, fib_index);
990 for (i = 0; i < vec_len(tunnels_to_delete); i++) {
991 tp = pool_elt_at_index (mm->gre_tunnels, tunnels_to_delete[i]);
992 uword * hash = fib->adj_index_by_dst_address[tp->mask_width];
993 uword key = tp->intfc_address.as_u32 & im->fib_masks[tp->mask_width];
994 uword *p = hash_get (hash, key);
995 ip4_add_del_route_args_t a;
997 /* Delete, the route if not already gone */
998 if (p && !tp->l2_only)
1000 memset (&a, 0, sizeof (a));
1001 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
1002 a.table_index_or_table_id = tp->inner_fib_index;
1003 a.dst_address = tp->intfc_address;
1004 a.dst_address_length = tp->mask_width;
1006 ip4_add_del_route (im, &a);
1007 ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
1008 IP4_ROUTE_FLAG_FIB_INDEX);
1011 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1012 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1013 0 /* admin down */);
1014 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
1015 vec_free (tp->rewrite_data);
1016 pool_put (mm->gre_tunnels, tp);
1019 vec_free(tunnels_to_delete);
1024 static clib_error_t *
1025 create_mpls_gre_tunnel_command_fn (vlib_main_t * vm,
1026 unformat_input_t * input,
1027 vlib_cli_command_t * cmd)
1029 unformat_input_t _line_input, * line_input = &_line_input;
1030 ip4_address_t src, dst, intfc;
1031 int src_set = 0, dst_set = 0, intfc_set = 0;
1033 u32 inner_fib_id = (u32)~0;
1034 u32 outer_fib_id = 0;
1038 u32 tunnel_intfc_sw_if_index = ~0;
1040 /* Get a line of input. */
1041 if (! unformat_user (input, unformat_line_input, line_input))
1044 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1046 if (unformat (line_input, "src %U",
1047 unformat_ip4_address, &src))
1049 else if (unformat (line_input, "dst %U",
1050 unformat_ip4_address, &dst))
1052 else if (unformat (line_input, "intfc %U/%d",
1053 unformat_ip4_address, &intfc, &mask_width))
1055 else if (unformat (line_input, "inner-fib-id %d", &inner_fib_id))
1057 else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
1059 else if (unformat (line_input, "del"))
1061 else if (unformat (line_input, "l2-only"))
1064 return clib_error_return (0, "unknown input '%U'",
1065 format_unformat_error, line_input);
1069 return clib_error_return (0, "missing: src <ip-address>");
1072 return clib_error_return (0, "missing: dst <ip-address>");
1075 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1078 rv = vnet_mpls_gre_add_del_tunnel (&src, &dst, &intfc, mask_width,
1079 inner_fib_id, outer_fib_id,
1080 &tunnel_intfc_sw_if_index,
1087 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), tunnel_intfc_sw_if_index);
1090 case VNET_API_ERROR_NO_SUCH_INNER_FIB:
1091 return clib_error_return (0, "inner fib ID %d doesn't exist\n",
1093 case VNET_API_ERROR_NO_SUCH_FIB:
1094 return clib_error_return (0, "outer fib ID %d doesn't exist\n",
1097 case VNET_API_ERROR_NO_SUCH_ENTRY:
1098 return clib_error_return (0, "tunnel not found\n");
1100 case VNET_API_ERROR_NO_SUCH_LABEL:
1102 * This happens when there's no MPLS label for the dst address
1103 * no need for two error messages.
1108 return clib_error_return (0, "vnet_mpls_gre_add_del_tunnel returned %d",
1114 VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
1115 .path = "create mpls gre tunnel",
1117 "create mpls gre tunnel [del] src <addr> dst <addr> intfc <addr>/<mw>",
1118 .function = create_mpls_gre_tunnel_command_fn,
1121 u8 * format_mpls_encap_index (u8 * s, va_list * args)
1123 mpls_main_t * mm = va_arg (*args, mpls_main_t *);
1124 u32 entry_index = va_arg (*args, u32);
1128 e = pool_elt_at_index (mm->encaps, entry_index);
1130 for (i = 0; i < vec_len (e->labels); i++)
1132 (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
1133 (e->labels[i].label_exp_s_ttl)));
1138 u8 * format_mpls_gre_tunnel (u8 * s, va_list * args)
1140 mpls_gre_tunnel_t * t = va_arg (*args, mpls_gre_tunnel_t *);
1141 mpls_main_t * mm = &mpls_main;
1143 if (t->l2_only == 0)
1145 s = format (s, "[%d]: src %U, dst %U, adj %U/%d, labels %U\n",
1146 t - mm->gre_tunnels,
1147 format_ip4_address, &t->tunnel_src,
1148 format_ip4_address, &t->tunnel_dst,
1149 format_ip4_address, &t->intfc_address,
1151 format_mpls_encap_index, mm, t->encap_index);
1153 s = format (s, " inner fib index %d, outer fib index %d",
1154 t->inner_fib_index, t->outer_fib_index);
1158 s = format (s, "[%d]: src %U, dst %U, key %U, labels %U\n",
1159 t - mm->gre_tunnels,
1160 format_ip4_address, &t->tunnel_src,
1161 format_ip4_address, &t->tunnel_dst,
1162 format_ip4_address, &t->intfc_address,
1163 format_mpls_encap_index, mm, t->encap_index);
1165 s = format (s, " l2 interface %d, outer fib index %d",
1166 t->hw_if_index, t->outer_fib_index);
1172 u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
1174 mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
1175 mpls_main_t * mm = &mpls_main;
1177 s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
1178 t - mm->eth_tunnels,
1179 format_ethernet_address, &t->tunnel_dst,
1180 format_ip4_address, &t->intfc_address,
1182 format_mpls_encap_index, mm, t->encap_index);
1185 s = format (s, " tx on %U, rx fib index %d",
1186 format_vnet_sw_if_index_name, mm->vnet_main, t->tx_sw_if_index,
1187 t->inner_fib_index);
1192 static clib_error_t *
1193 show_mpls_tunnel_command_fn (vlib_main_t * vm,
1194 unformat_input_t * input,
1195 vlib_cli_command_t * cmd)
1197 mpls_main_t * mm = &mpls_main;
1198 mpls_gre_tunnel_t * gt;
1199 mpls_eth_tunnel_t * et;
1201 if (pool_elts (mm->gre_tunnels))
1203 vlib_cli_output (vm, "MPLS-GRE tunnels");
1204 pool_foreach (gt, mm->gre_tunnels,
1206 vlib_cli_output (vm, "%U", format_mpls_gre_tunnel, gt);
1210 vlib_cli_output (vm, "No MPLS-GRE tunnels");
1212 if (pool_elts (mm->eth_tunnels))
1214 vlib_cli_output (vm, "MPLS-Ethernet tunnels");
1215 pool_foreach (et, mm->eth_tunnels,
1217 vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
1221 vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
1226 VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
1227 .path = "show mpls tunnel",
1228 .short_help = "show mpls tunnel",
1229 .function = show_mpls_tunnel_command_fn,
1232 /* force inclusion from application's main.c */
1233 clib_error_t *mpls_interface_init (vlib_main_t *vm)
1235 clib_error_t * error;
1237 if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
1242 VLIB_INIT_FUNCTION(mpls_interface_init);
1245 static u8 * mpls_ethernet_rewrite (mpls_main_t *mm, mpls_eth_tunnel_t * t)
1247 u8 * rewrite_data = 0;
1249 mpls_unicast_header_t *lp0;
1252 /* look up the encap label stack using the RX FIB and adjacency address*/
1253 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index,
1254 t->intfc_address.as_u32);
1258 clib_warning ("no label for inner fib index %d, dst %U",
1259 t->inner_fib_index, format_ip4_address,
1264 vec_validate (rewrite_data,
1265 sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
1267 /* Copy the encap label stack */
1268 lp0 = (mpls_unicast_header_t *) rewrite_data;
1270 for (i = 0; i < vec_len(e->labels); i++)
1271 lp0[i] = e->labels[i];
1273 return (rewrite_data);
1276 int vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
1277 ip4_address_t *intfc,
1281 u32 * tunnel_sw_if_index,
1285 ip4_main_t * im = &ip4_main;
1286 ip_lookup_main_t * lm = &im->lookup_main;
1287 mpls_main_t * mm = &mpls_main;
1288 vnet_main_t * vnm = vnet_get_main();
1290 mpls_eth_tunnel_t *tp;
1291 int need_route_add_del = 1;
1292 u32 inner_fib_index = 0;
1296 int found_tunnel = 0;
1297 mpls_encap_t * e = 0;
1298 u32 hw_if_index = ~0;
1299 vnet_hw_interface_t * hi;
1305 if (tunnel_sw_if_index == 0)
1306 tunnel_sw_if_index = &dummy;
1308 *tunnel_sw_if_index = ~0;
1310 if (inner_fib_id != (u32)~0)
1314 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1316 return VNET_API_ERROR_NO_SUCH_FIB;
1317 inner_fib_index = p[0];
1320 /* suppress duplicate mpls interface generation. */
1321 pool_foreach (tp, mm->eth_tunnels,
1324 * If we have a tunnel which matches (src, dst, intfc/mask)
1325 * AND the expected route is in the FIB, it's a dup
1327 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1328 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1329 && tp->inner_fib_index == inner_fib_index)
1331 ip4_fib_t * fib = vec_elt_at_index (im->fibs, inner_fib_index);
1332 uword * hash = fib->adj_index_by_dst_address[mask_width];
1333 uword key = intfc->as_u32 & im->fib_masks[mask_width];
1334 uword *p = hash_get (hash, key);
1344 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
1347 return VNET_API_ERROR_NO_SUCH_LABEL;
1354 /* Delete, the route is already gone? */
1356 need_route_add_del = 0;
1363 /* Delete, and we can't find the tunnel */
1364 if (is_add == 0 && found_tunnel == 0)
1365 return VNET_API_ERROR_NO_SUCH_ENTRY;
1367 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
1369 return VNET_API_ERROR_NO_SUCH_LABEL;
1371 pool_get(mm->eth_tunnels, tp);
1372 memset (tp, 0, sizeof (*tp));
1374 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1377 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1378 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1379 hi = vnet_get_hw_interface (vnm, hw_if_index);
1380 hi->dev_instance = tp - mm->eth_tunnels;
1381 hi->hw_instance = tp - mm->eth_tunnels;
1385 hw_if_index = vnet_register_interface
1386 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1387 mpls_eth_hw_interface_class.index,
1388 tp - mm->eth_tunnels);
1389 hi = vnet_get_hw_interface (vnm, hw_if_index);
1391 /* ... to make the IP and L2 x-connect cases identical */
1392 slot = vlib_node_add_named_next_with_slot
1393 (vnm->vlib_main, hi->tx_node_index,
1394 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1396 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1399 *tunnel_sw_if_index = hi->sw_if_index;
1400 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1401 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1403 tp->hw_if_index = hw_if_index;
1406 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1407 tp->intfc_address.as_u32 = intfc->as_u32;
1408 tp->mask_width = mask_width;
1409 tp->inner_fib_index = inner_fib_index;
1410 tp->encap_index = e - mm->encaps;
1411 tp->tx_sw_if_index = tx_sw_if_index;
1412 tp->l2_only = l2_only;
1414 /* Create the adjacency and add to v4 fib */
1415 memset(&adj, 0, sizeof (adj));
1416 adj.explicit_fib_index = ~0;
1417 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1419 rewrite_data = mpls_ethernet_rewrite (mm, tp);
1420 if (rewrite_data == 0)
1422 if (*tunnel_sw_if_index != ~0)
1424 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1425 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1426 0 /* admin down */);
1427 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1430 pool_put (mm->eth_tunnels, tp);
1431 return VNET_API_ERROR_NO_SUCH_LABEL;
1434 vnet_rewrite_for_sw_interface
1436 VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1438 ip4_rewrite_node.index,
1440 &adj.rewrite_header,
1441 sizeof (adj.rewrite_data));
1444 * Prepend the (0,1,2) VLAN tag ethernet header
1445 * we just built to the mpls header stack
1447 vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
1448 clib_memcpy(rewrite_data,
1449 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1450 sizeof (adj.rewrite_data)),
1451 adj.rewrite_header.data_bytes);
1453 vnet_rewrite_set_data_internal (&adj.rewrite_header,
1454 sizeof(adj.rewrite_data),
1456 vec_len(rewrite_data));
1458 vec_free (tp->rewrite_data);
1460 tp->rewrite_data = rewrite_data;
1463 ip_add_adjacency (lm, &adj, 1 /* one adj */,
1468 if (need_route_add_del && !l2_only)
1471 ip4_add_del_route_next_hop (im,
1475 &zero /* no next hop */,
1476 (u32)~0 /* next_hop_sw_if_index */,
1479 tp->inner_fib_index);
1482 ip4_add_del_route_args_t a;
1483 memset (&a, 0, sizeof (a));
1485 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
1486 a.table_index_or_table_id = tp->inner_fib_index;
1487 a.dst_address = tp->intfc_address;
1488 a.dst_address_length = tp->mask_width;
1491 ip4_add_del_route (im, &a);
1492 ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
1493 IP4_ROUTE_FLAG_FIB_INDEX);
1496 if (is_add == 0 && found_tunnel)
1498 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1499 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1500 0 /* admin down */);
1501 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1502 vec_free (tp->rewrite_data);
1503 pool_put (mm->eth_tunnels, tp);
1509 static clib_error_t *
1510 create_mpls_ethernet_tunnel_command_fn (vlib_main_t * vm,
1511 unformat_input_t * input,
1512 vlib_cli_command_t * cmd)
1514 unformat_input_t _line_input, * line_input = &_line_input;
1515 vnet_main_t * vnm = vnet_get_main();
1516 ip4_address_t intfc;
1519 int dst_set = 0, intfc_set = 0;
1521 u32 inner_fib_id = (u32)~0;
1526 u32 sw_if_index = ~0;
1528 /* Get a line of input. */
1529 if (! unformat_user (input, unformat_line_input, line_input))
1532 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1534 if (unformat (line_input, "dst %U",
1535 unformat_ethernet_address, &dst))
1537 else if (unformat (line_input, "adj %U/%d",
1538 unformat_ip4_address, &intfc, &mask_width))
1540 else if (unformat (line_input, "tx-intfc %U",
1541 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1543 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1545 else if (unformat (line_input, "l2-only"))
1547 else if (unformat (line_input, "del"))
1550 return clib_error_return (0, "unknown input '%U'",
1551 format_unformat_error, line_input);
1555 return clib_error_return (0, "missing tx-intfc");
1558 return clib_error_return (0, "missing: dst <ethernet-address>");
1561 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1564 rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
1565 inner_fib_id, tx_sw_if_index,
1573 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
1575 case VNET_API_ERROR_NO_SUCH_FIB:
1576 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1579 case VNET_API_ERROR_NO_SUCH_ENTRY:
1580 return clib_error_return (0, "tunnel not found\n");
1582 case VNET_API_ERROR_NO_SUCH_LABEL:
1584 * This happens when there's no MPLS label for the dst address
1585 * no need for two error messages.
1587 return clib_error_return (0, "no label for %U in fib %d",
1588 format_ip4_address, &intfc, inner_fib_id);
1592 return clib_error_return (0, "vnet_mpls_ethernet_add_del_tunnel returned %d", rv);
1599 VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
1600 .path = "create mpls ethernet tunnel",
1602 "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
1603 .function = create_mpls_ethernet_tunnel_command_fn,
1607 int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
1609 u32 policy_tunnel_index)
1611 mpls_eth_tunnel_t * t;
1613 u8 * rewrite_data = 0;
1615 mpls_unicast_header_t *lp;
1618 if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
1619 return VNET_API_ERROR_NO_SUCH_ENTRY;
1621 t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
1623 memset (&adj, 0, sizeof (adj));
1625 /* Build L2 encap */
1626 vnet_rewrite_for_sw_interface
1628 VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1630 mpls_policy_encap_node.index,
1632 &adj.rewrite_header,
1633 sizeof (adj.rewrite_data));
1635 vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
1637 clib_memcpy(rewrite_data,
1638 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1639 sizeof (adj.rewrite_data)),
1640 adj.rewrite_header.data_bytes);
1642 /* Append the label stack */
1644 vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
1646 lp = (mpls_unicast_header_t *) label_start;
1648 for (i = 0; i < vec_len(e->labels); i++)
1649 lp[i] = e->labels[i];
1651 /* Remember the rewrite data */
1652 e->rewrite = rewrite_data;
1653 e->output_next_index = adj.rewrite_header.next_index;
1658 int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
1659 ip4_address_t *intfc,
1663 u32 * tunnel_sw_if_index,
1664 u32 classify_table_index,
1665 u32 * new_tunnel_index,
1669 ip4_main_t * im = &ip4_main;
1670 ip_lookup_main_t * lm = &im->lookup_main;
1671 mpls_main_t * mm = &mpls_main;
1672 vnet_main_t * vnm = vnet_get_main();
1674 mpls_eth_tunnel_t *tp;
1675 int need_route_add_del = 1;
1676 u32 inner_fib_index = 0;
1679 int found_tunnel = 0;
1680 mpls_encap_t * e = 0;
1681 u32 hw_if_index = ~0;
1682 vnet_hw_interface_t * hi;
1688 if (tunnel_sw_if_index == 0)
1689 tunnel_sw_if_index = &dummy;
1691 *tunnel_sw_if_index = ~0;
1693 if (inner_fib_id != (u32)~0)
1697 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1699 return VNET_API_ERROR_NO_SUCH_FIB;
1700 inner_fib_index = p[0];
1703 /* suppress duplicate mpls interface generation. */
1704 pool_foreach (tp, mm->eth_tunnels,
1707 * If we have a tunnel which matches (src, dst, intfc/mask)
1708 * AND the expected route is in the FIB, it's a dup
1710 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1711 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1712 && tp->inner_fib_index == inner_fib_index)
1714 ip4_fib_t * fib = vec_elt_at_index (im->fibs, inner_fib_index);
1715 uword * hash = fib->adj_index_by_dst_address[mask_width];
1716 uword key = intfc->as_u32 & im->fib_masks[mask_width];
1717 uword *p = hash_get (hash, key);
1732 /* Delete, the route is already gone? */
1734 need_route_add_del = 0;
1741 /* Delete, and we can't find the tunnel */
1742 if (is_add == 0 && found_tunnel == 0)
1743 return VNET_API_ERROR_NO_SUCH_ENTRY;
1745 pool_get(mm->eth_tunnels, tp);
1746 memset (tp, 0, sizeof (*tp));
1748 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1751 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1752 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1753 hi = vnet_get_hw_interface (vnm, hw_if_index);
1754 hi->dev_instance = tp - mm->eth_tunnels;
1755 hi->hw_instance = tp - mm->eth_tunnels;
1759 hw_if_index = vnet_register_interface
1760 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1761 mpls_eth_hw_interface_class.index,
1762 tp - mm->eth_tunnels);
1763 hi = vnet_get_hw_interface (vnm, hw_if_index);
1765 /* ... to make the IP and L2 x-connect cases identical */
1766 slot = vlib_node_add_named_next_with_slot
1767 (vnm->vlib_main, hi->tx_node_index,
1768 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1770 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1773 *tunnel_sw_if_index = hi->sw_if_index;
1774 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1775 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1777 tp->hw_if_index = hw_if_index;
1780 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1781 tp->intfc_address.as_u32 = intfc->as_u32;
1782 tp->mask_width = mask_width;
1783 tp->inner_fib_index = inner_fib_index;
1784 tp->encap_index = e - mm->encaps;
1785 tp->tx_sw_if_index = tx_sw_if_index;
1786 tp->l2_only = l2_only;
1788 if (new_tunnel_index)
1789 *new_tunnel_index = tp - mm->eth_tunnels;
1791 /* Create the classify adjacency and add to v4 fib */
1792 memset(&adj, 0, sizeof (adj));
1793 adj.explicit_fib_index = ~0;
1794 adj.lookup_next_index = IP_LOOKUP_NEXT_CLASSIFY;
1795 adj.classify.table_index = classify_table_index;
1798 ip_add_adjacency (lm, &adj, 1 /* one adj */,
1803 if (need_route_add_del && !l2_only)
1806 ip4_add_del_route_next_hop (im,
1810 &zero /* no next hop */,
1811 (u32)~0 /* next_hop_sw_if_index */,
1814 tp->inner_fib_index);
1817 ip4_add_del_route_args_t a;
1818 memset (&a, 0, sizeof (a));
1820 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
1821 a.table_index_or_table_id = tp->inner_fib_index;
1822 a.dst_address = tp->intfc_address;
1823 a.dst_address_length = tp->mask_width;
1826 ip4_add_del_route (im, &a);
1827 ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
1828 IP4_ROUTE_FLAG_FIB_INDEX);
1831 if (is_add == 0 && found_tunnel)
1833 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1834 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1835 0 /* admin down */);
1836 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1837 pool_put (mm->eth_tunnels, tp);
1843 static clib_error_t *
1844 create_mpls_ethernet_policy_tunnel_command_fn (vlib_main_t * vm,
1845 unformat_input_t * input,
1846 vlib_cli_command_t * cmd)
1848 unformat_input_t _line_input, * line_input = &_line_input;
1849 vnet_main_t * vnm = vnet_get_main();
1850 ip4_address_t intfc;
1853 int dst_set = 0, intfc_set = 0;
1855 u32 inner_fib_id = (u32)~0;
1856 u32 classify_table_index = (u32)~0;
1857 u32 new_tunnel_index;
1863 /* Get a line of input. */
1864 if (! unformat_user (input, unformat_line_input, line_input))
1867 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1869 if (unformat (line_input, "dst %U",
1870 unformat_ethernet_address, &dst))
1872 else if (unformat (line_input, "adj %U/%d",
1873 unformat_ip4_address, &intfc, &mask_width))
1875 else if (unformat (line_input, "tx-intfc %U",
1876 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1878 else if (unformat (line_input, "classify-table-index %d",
1879 &classify_table_index))
1881 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1883 else if (unformat (line_input, "l2-only"))
1885 else if (unformat (line_input, "del"))
1888 return clib_error_return (0, "unknown input '%U'",
1889 format_unformat_error, line_input);
1892 if (classify_table_index == ~0)
1893 return clib_error_return (0, "missing classify_table_index");
1896 return clib_error_return (0, "missing tx-intfc");
1899 return clib_error_return (0, "missing: dst <ethernet-address>");
1902 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1905 rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
1906 inner_fib_id, tx_sw_if_index,
1907 0 /* tunnel sw_if_index */,
1908 classify_table_index,
1915 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), new_tunnel_index);
1917 case VNET_API_ERROR_NO_SUCH_FIB:
1918 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1921 case VNET_API_ERROR_NO_SUCH_ENTRY:
1922 return clib_error_return (0, "tunnel not found\n");
1924 case VNET_API_ERROR_NO_SUCH_LABEL:
1926 * This happens when there's no MPLS label for the dst address
1927 * no need for two error messages.
1929 return clib_error_return (0, "no label for %U in fib %d",
1930 format_ip4_address, &intfc, inner_fib_id);
1934 return clib_error_return (0, "vnet_mpls_ethernet_add_del_policy_tunnel returned %d", rv);
1941 VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
1942 .path = "create mpls ethernet policy tunnel",
1944 "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
1945 " classify-table-index <nn>",
1946 .function = create_mpls_ethernet_policy_tunnel_command_fn,