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 VNET_HW_INTERFACE_CLASS (mpls_gre_hw_interface_class) = {
264 .format_header = format_mpls_gre_header_with_length,
266 .unformat_header = unformat_mpls_gre_header,
268 .set_rewrite = mpls_gre_set_rewrite,
272 static uword mpls_eth_set_rewrite (vnet_main_t * vnm,
277 uword max_rewrite_bytes)
280 * Conundrum: packets from tun/tap destined for the tunnel
281 * actually have this rewrite applied. Transit packets do not.
282 * To make the two cases equivalent, don't generate a
283 * rewrite here, build the entire header in the fast path.
288 /* manually added to the interface output node */
289 #define MPLS_ETH_OUTPUT_NEXT_OUTPUT 1
292 mpls_eth_interface_tx (vlib_main_t * vm,
293 vlib_node_runtime_t * node,
294 vlib_frame_t * frame)
296 mpls_main_t * gm = &mpls_main;
297 vnet_main_t * vnm = gm->vnet_main;
299 u32 * from, * to_next, n_left_from, n_left_to_next;
301 /* Vector of buffer / pkt indices we're supposed to process */
302 from = vlib_frame_vector_args (frame);
304 /* Number of buffers / pkts */
305 n_left_from = frame->n_vectors;
307 /* Speculatively send the first buffer to the last disposition we used */
308 next_index = node->cached_next_index;
310 while (n_left_from > 0)
312 /* set up to enqueue to our disposition with index = next_index */
313 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
316 * As long as we have enough pkts left to process two pkts
317 * and prefetch two pkts...
319 while (n_left_from >= 4 && n_left_to_next >= 2)
321 vlib_buffer_t * b0, * b1;
322 u32 bi0, next0, bi1, next1;
323 mpls_eth_tunnel_t * t0, * t1;
324 u32 sw_if_index0, sw_if_index1;
325 vnet_hw_interface_t * hi0, * hi1;
328 /* Prefetch the next iteration */
330 vlib_buffer_t * p2, * p3;
332 p2 = vlib_get_buffer (vm, from[2]);
333 p3 = vlib_get_buffer (vm, from[3]);
335 vlib_prefetch_buffer_header (p2, LOAD);
336 vlib_prefetch_buffer_header (p3, LOAD);
339 * Prefetch packet data. We expect to overwrite
340 * the inbound L2 header with an ip header and a
341 * gre header. Might want to prefetch the last line
342 * of rewrite space as well; need profile data
344 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
345 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
348 /* Pick up the next two buffer indices */
352 /* Speculatively enqueue them where we sent the last buffer */
360 b0 = vlib_get_buffer (vm, bi0);
361 b1 = vlib_get_buffer (vm, bi1);
363 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
364 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
367 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
368 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
370 /* hw_instance = tunnel pool index */
371 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
372 t1 = pool_elt_at_index (gm->eth_tunnels, hi1->hw_instance);
374 /* Apply rewrite - $$$$$ fixme don't use memcpy */
375 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
376 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
378 dst0 = vlib_buffer_get_current (b0);
379 dst1 = vlib_buffer_get_current (b1);
381 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
382 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
384 /* Fix TX fib indices */
385 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
386 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->tx_sw_if_index;
388 /* mpls-post-rewrite takes it from here... */
389 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
390 next1 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
392 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
394 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
397 tr->tunnel_id = t0 - gm->eth_tunnels;
398 tr->tx_sw_if_index = t0->tx_sw_if_index;
399 tr->mpls_encap_index = t0->encap_index;
400 tr->length = b0->current_length;
401 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
402 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
404 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
406 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
409 tr->tunnel_id = t1 - gm->eth_tunnels;
410 tr->tx_sw_if_index = t1->tx_sw_if_index;
411 tr->mpls_encap_index = t1->encap_index;
412 tr->length = b0->current_length;
413 hi1 = vnet_get_sup_hw_interface (vnm, t1->tx_sw_if_index);
414 clib_memcpy (tr->dst, hi1->hw_address, sizeof (tr->dst));
417 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
418 to_next, n_left_to_next,
419 bi0, bi1, next0, next1);
421 while (n_left_from > 0 && n_left_to_next > 0)
425 mpls_eth_tunnel_t * t0;
427 vnet_hw_interface_t * hi0;
437 b0 = vlib_get_buffer (vm, bi0);
439 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
441 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
443 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
445 /* Apply rewrite - $$$$$ fixme don't use memcpy */
446 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
448 dst0 = vlib_buffer_get_current (b0);
450 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
452 /* Fix the TX interface */
453 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
455 /* Send the packet */
456 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
458 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
460 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
463 tr->tunnel_id = t0 - gm->eth_tunnels;
464 tr->tx_sw_if_index = t0->tx_sw_if_index;
465 tr->mpls_encap_index = t0->encap_index;
466 tr->length = b0->current_length;
467 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
468 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
471 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
472 to_next, n_left_to_next,
476 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
479 vlib_node_increment_counter (vm, mpls_input_node.index,
480 MPLS_ERROR_PKTS_ENCAP, frame->n_vectors);
482 return frame->n_vectors;
485 static u8 * format_mpls_eth_tunnel_name (u8 * s, va_list * args)
487 u32 dev_instance = va_arg (*args, u32);
488 return format (s, "mpls-eth%d", dev_instance);
491 static u8 * format_mpls_eth_device (u8 * s, va_list * args)
493 u32 dev_instance = va_arg (*args, u32);
494 CLIB_UNUSED (int verbose) = va_arg (*args, int);
496 s = format (s, "MPLS-ETH tunnel: id %d\n", dev_instance);
500 VNET_DEVICE_CLASS (mpls_eth_device_class) = {
501 .name = "MPLS-ETH tunnel device",
502 .format_device_name = format_mpls_eth_tunnel_name,
503 .format_device = format_mpls_eth_device,
504 .format_tx_trace = format_mpls_eth_tx_trace,
505 .tx_function = mpls_eth_interface_tx,
506 .no_flatten_output_chains = 1,
509 .admin_up_down_function = 0;
514 VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = {
516 .format_header = format_mpls_eth_header_with_length,
518 .unformat_header = unformat_mpls_eth_header,
520 .set_rewrite = mpls_eth_set_rewrite,
523 #define foreach_mpls_post_rewrite_next \
524 _ (IP4_LOOKUP, "ip4-lookup")
527 #define _(s,n) MPLS_POST_REWRITE_NEXT_##s,
528 foreach_mpls_post_rewrite_next
530 MPLS_POST_REWRITE_N_NEXT,
531 } mpls_post_rewrite_next_t;
535 mpls_post_rewrite (vlib_main_t * vm,
536 vlib_node_runtime_t * node,
537 vlib_frame_t * from_frame)
539 u32 n_left_from, next_index, * from, * to_next;
540 u16 old_l0 = 0, old_l1 = 0;
542 from = vlib_frame_vector_args (from_frame);
543 n_left_from = from_frame->n_vectors;
545 next_index = node->cached_next_index;
547 while (n_left_from > 0)
551 vlib_get_next_frame (vm, node, next_index,
552 to_next, n_left_to_next);
554 while (n_left_from >= 4 && n_left_to_next >= 2)
557 vlib_buffer_t * b0, * b1;
558 ip4_header_t * ip0, * ip1;
559 u32 next0 = MPLS_POST_REWRITE_NEXT_IP4_LOOKUP;
560 u32 next1 = MPLS_POST_REWRITE_NEXT_IP4_LOOKUP;
562 ip_csum_t sum0, sum1;
564 /* Prefetch next iteration. */
566 vlib_buffer_t * p2, * p3;
568 p2 = vlib_get_buffer (vm, from[2]);
569 p3 = vlib_get_buffer (vm, from[3]);
571 vlib_prefetch_buffer_header (p2, LOAD);
572 vlib_prefetch_buffer_header (p3, LOAD);
574 CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
575 CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
588 b0 = vlib_get_buffer (vm, bi0);
589 b1 = vlib_get_buffer (vm, bi1);
590 ip0 = vlib_buffer_get_current (b0);
591 ip1 = vlib_buffer_get_current (b1);
593 /* Note: the tunnel rewrite sets up sw_if_index[VLIB_TX] */
595 /* set the GRE (outer) ip packet length, fix the bloody checksum */
596 sum0 = ip0->checksum;
597 sum1 = ip1->checksum;
599 /* old_l0, old_l1 always 0, see the rewrite setup */
601 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
603 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
605 sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
606 length /* changed member */);
607 sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
608 length /* changed member */);
609 ip0->checksum = ip_csum_fold (sum0);
610 ip1->checksum = ip_csum_fold (sum1);
611 ip0->length = new_l0;
612 ip1->length = new_l1;
614 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
615 to_next, n_left_to_next,
616 bi0, bi1, next0, next1);
619 while (n_left_from > 0 && n_left_to_next > 0)
624 u32 next0 = MPLS_POST_REWRITE_NEXT_IP4_LOOKUP;
635 b0 = vlib_get_buffer (vm, bi0);
636 ip0 = vlib_buffer_get_current (b0);
638 /* Note: the tunnel rewrite sets up sw_if_index[VLIB_TX] */
640 /* set the GRE (outer) ip packet length, fix the bloody checksum */
641 sum0 = ip0->checksum;
642 /* old_l0 always 0, see the rewrite setup */
644 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
646 sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
647 length /* changed member */);
648 ip0->checksum = ip_csum_fold (sum0);
649 ip0->length = new_l0;
651 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
652 to_next, n_left_to_next,
656 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
658 vlib_node_increment_counter (vm, mpls_input_node.index,
659 MPLS_ERROR_PKTS_ENCAP, from_frame->n_vectors);
660 return from_frame->n_vectors;
663 VLIB_REGISTER_NODE (mpls_post_rewrite_node) = {
664 .function = mpls_post_rewrite,
665 .name = "mpls-post-rewrite",
666 /* Takes a vector of packets. */
667 .vector_size = sizeof (u32),
669 .runtime_data_bytes = 0,
671 .n_next_nodes = MPLS_POST_REWRITE_N_NEXT,
673 #define _(s,n) [MPLS_POST_REWRITE_NEXT_##s] = n,
674 foreach_mpls_post_rewrite_next
679 static u8 * mpls_gre_rewrite (mpls_main_t *mm, mpls_gre_tunnel_t * t)
682 ip4_gre_and_mpls_header_t * h0;
683 u8 * rewrite_data = 0;
685 mpls_unicast_header_t *lp0;
688 /* look up the encap label stack using the RX FIB */
689 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index, t->tunnel_dst.as_u32);
693 clib_warning ("no label for inner fib index %d, dst %U",
694 t->inner_fib_index, format_ip4_address,
699 vec_validate (rewrite_data, sizeof (*h0)
700 + sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
701 memset (rewrite_data, 0, sizeof (*h0));
703 h0 = (ip4_gre_and_mpls_header_t *) rewrite_data;
704 /* Copy the encap label stack */
706 for (i = 0; i < vec_len(e->labels); i++)
707 lp0[i] = e->labels[i];
709 h0->gre.protocol = clib_host_to_net_u16(GRE_PROTOCOL_mpls_unicast);
710 ip0->ip_version_and_header_length = 0x45;
712 ip0->protocol = IP_PROTOCOL_GRE;
713 /* $$$ fixup ip4 header length and checksum after-the-fact */
714 ip0->src_address.as_u32 = t->tunnel_src.as_u32;
715 ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
716 ip0->checksum = ip4_header_checksum (ip0);
718 return (rewrite_data);
721 int vnet_mpls_gre_add_del_tunnel (ip4_address_t *src,
723 ip4_address_t *intfc,
725 u32 inner_fib_id, u32 outer_fib_id,
726 u32 * tunnel_sw_if_index,
730 ip4_main_t * im = &ip4_main;
731 ip_lookup_main_t * lm = &im->lookup_main;
732 mpls_main_t * mm = &mpls_main;
733 vnet_main_t * vnm = vnet_get_main();
735 mpls_gre_tunnel_t *tp;
736 int need_route_add_del = 1;
737 u32 inner_fib_index = 0;
738 u32 outer_fib_index = 0;
742 int found_tunnel = 0;
743 mpls_encap_t * e = 0;
744 u32 hw_if_index = ~0;
745 vnet_hw_interface_t * hi;
751 /* No questions, no answers */
752 if (tunnel_sw_if_index == 0)
753 tunnel_sw_if_index = &dummy;
755 *tunnel_sw_if_index = ~0;
757 if (inner_fib_id != (u32)~0)
761 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
763 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
764 inner_fib_index = p[0];
767 if (outer_fib_id != 0)
771 p = hash_get (im->fib_index_by_table_id, outer_fib_id);
773 return VNET_API_ERROR_NO_SUCH_FIB;
774 outer_fib_index = p[0];
777 /* suppress duplicate mpls interface generation. */
778 pool_foreach (tp, mm->gre_tunnels,
781 * If we have a tunnel which matches (src, dst, intfc/mask)
782 * AND the expected route is in the FIB, it's a dup
784 if (!memcmp (&tp->tunnel_src, src, sizeof (*src))
785 && !memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
786 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
787 && tp->inner_fib_index == inner_fib_index)
789 ip4_fib_t * fib = vec_elt_at_index (im->fibs, inner_fib_index);
790 uword * hash = fib->adj_index_by_dst_address[mask_width];
791 uword key = intfc->as_u32 & im->fib_masks[mask_width];
792 uword *p = hash_get (hash, key);
798 /* A dup, and the route is in the fib. Done */
803 /* Reinstall the route (and other stuff) */
804 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
807 return VNET_API_ERROR_NO_SUCH_LABEL;
813 /* Delete, the route is already gone? */
815 need_route_add_del = 0;
822 /* Delete, and we can't find the tunnel */
823 if (is_add == 0 && found_tunnel == 0)
824 return VNET_API_ERROR_NO_SUCH_ENTRY;
826 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, dst->as_u32);
828 return VNET_API_ERROR_NO_SUCH_LABEL;
830 pool_get(mm->gre_tunnels, tp);
831 memset (tp, 0, sizeof (*tp));
833 if (vec_len (mm->free_gre_sw_if_indices) > 0)
836 mm->free_gre_sw_if_indices[vec_len(mm->free_gre_sw_if_indices)-1];
837 _vec_len (mm->free_gre_sw_if_indices) -= 1;
838 hi = vnet_get_hw_interface (vnm, hw_if_index);
839 hi->dev_instance = tp - mm->gre_tunnels;
840 hi->hw_instance = tp - mm->gre_tunnels;
844 hw_if_index = vnet_register_interface
845 (vnm, mpls_gre_device_class.index, tp - mm->gre_tunnels,
846 mpls_gre_hw_interface_class.index,
847 tp - mm->gre_tunnels);
848 hi = vnet_get_hw_interface (vnm, hw_if_index);
850 /* ... to make the IP and L2 x-connect cases identical */
851 slot = vlib_node_add_named_next_with_slot
852 (vnm->vlib_main, hi->tx_node_index,
853 "mpls-post-rewrite", MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
855 ASSERT (slot == MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
858 *tunnel_sw_if_index = hi->sw_if_index;
859 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
860 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
862 tp->hw_if_index = hw_if_index;
865 tp->tunnel_src.as_u32 = src->as_u32;
866 tp->tunnel_dst.as_u32 = dst->as_u32;
867 tp->intfc_address.as_u32 = intfc->as_u32;
868 tp->mask_width = mask_width;
869 tp->inner_fib_index = inner_fib_index;
870 tp->outer_fib_index = outer_fib_index;
871 tp->encap_index = e - mm->encaps;
872 tp->l2_only = l2_only;
874 /* Create the adjacency and add to v4 fib */
875 memset(&adj, 0, sizeof (adj));
876 adj.explicit_fib_index = ~0;
877 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
879 rewrite_data = mpls_gre_rewrite (mm, tp);
880 if (rewrite_data == 0)
882 if (*tunnel_sw_if_index != ~0)
884 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
885 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
887 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
889 pool_put (mm->gre_tunnels, tp);
890 return VNET_API_ERROR_NO_SUCH_LABEL;
893 /* Save a copy of the rewrite data for L2 x-connect */
894 vec_free (tp->rewrite_data);
896 tp->rewrite_data = rewrite_data;
898 vnet_rewrite_for_tunnel
900 outer_fib_index /* tx_sw_if_index, aka outer fib ID */,
901 ip4_rewrite_node.index,
902 mpls_post_rewrite_node.index,
904 rewrite_data, vec_len(rewrite_data));
907 ip_add_adjacency (lm, &adj, 1 /* one adj */,
912 if (need_route_add_del && !l2_only)
915 ip4_add_del_route_next_hop (im,
919 &zero /* no next hop */,
920 (u32)~0 /* next_hop_sw_if_index */,
923 tp->inner_fib_index);
926 ip4_add_del_route_args_t a;
927 memset (&a, 0, sizeof (a));
929 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
930 a.table_index_or_table_id = tp->inner_fib_index;
931 a.dst_address = tp->intfc_address;
932 a.dst_address_length = tp->mask_width;
935 ip4_add_del_route (im, &a);
936 ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
937 IP4_ROUTE_FLAG_FIB_INDEX);
941 if (is_add == 0 && found_tunnel)
943 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
944 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
946 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
947 vec_free (tp->rewrite_data);
948 pool_put (mm->gre_tunnels, tp);
955 * Remove all mpls tunnels in the specified fib
957 int vnet_mpls_gre_delete_fib_tunnels (u32 fib_id)
959 ip4_main_t * im = &ip4_main;
960 mpls_main_t * mm = &mpls_main;
961 vnet_main_t * vnm = mm->vnet_main;
962 mpls_gre_tunnel_t *tp;
965 u32 * tunnels_to_delete = 0;
966 vnet_hw_interface_t * hi;
970 p = hash_get (im->fib_index_by_table_id, fib_id);
972 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
975 pool_foreach (tp, mm->gre_tunnels,
977 if (tp->inner_fib_index == fib_index)
978 vec_add1 (tunnels_to_delete, tp - mm->gre_tunnels);
981 fib = vec_elt_at_index (im->fibs, fib_index);
983 for (i = 0; i < vec_len(tunnels_to_delete); i++) {
984 tp = pool_elt_at_index (mm->gre_tunnels, tunnels_to_delete[i]);
985 uword * hash = fib->adj_index_by_dst_address[tp->mask_width];
986 uword key = tp->intfc_address.as_u32 & im->fib_masks[tp->mask_width];
987 uword *p = hash_get (hash, key);
988 ip4_add_del_route_args_t a;
990 /* Delete, the route if not already gone */
991 if (p && !tp->l2_only)
993 memset (&a, 0, sizeof (a));
994 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
995 a.table_index_or_table_id = tp->inner_fib_index;
996 a.dst_address = tp->intfc_address;
997 a.dst_address_length = tp->mask_width;
999 ip4_add_del_route (im, &a);
1000 ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
1001 IP4_ROUTE_FLAG_FIB_INDEX);
1004 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1005 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1006 0 /* admin down */);
1007 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
1008 vec_free (tp->rewrite_data);
1009 pool_put (mm->gre_tunnels, tp);
1012 vec_free(tunnels_to_delete);
1017 static clib_error_t *
1018 create_mpls_gre_tunnel_command_fn (vlib_main_t * vm,
1019 unformat_input_t * input,
1020 vlib_cli_command_t * cmd)
1022 unformat_input_t _line_input, * line_input = &_line_input;
1023 ip4_address_t src, dst, intfc;
1024 int src_set = 0, dst_set = 0, intfc_set = 0;
1026 u32 inner_fib_id = (u32)~0;
1027 u32 outer_fib_id = 0;
1031 u32 tunnel_intfc_sw_if_index = ~0;
1033 /* Get a line of input. */
1034 if (! unformat_user (input, unformat_line_input, line_input))
1037 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1039 if (unformat (line_input, "src %U",
1040 unformat_ip4_address, &src))
1042 else if (unformat (line_input, "dst %U",
1043 unformat_ip4_address, &dst))
1045 else if (unformat (line_input, "intfc %U/%d",
1046 unformat_ip4_address, &intfc, &mask_width))
1048 else if (unformat (line_input, "inner-fib-id %d", &inner_fib_id))
1050 else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
1052 else if (unformat (line_input, "del"))
1054 else if (unformat (line_input, "l2-only"))
1057 return clib_error_return (0, "unknown input '%U'",
1058 format_unformat_error, line_input);
1062 return clib_error_return (0, "missing: src <ip-address>");
1065 return clib_error_return (0, "missing: dst <ip-address>");
1068 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1071 rv = vnet_mpls_gre_add_del_tunnel (&src, &dst, &intfc, mask_width,
1072 inner_fib_id, outer_fib_id,
1073 &tunnel_intfc_sw_if_index,
1081 case VNET_API_ERROR_NO_SUCH_INNER_FIB:
1082 return clib_error_return (0, "inner fib ID %d doesn't exist\n",
1084 case VNET_API_ERROR_NO_SUCH_FIB:
1085 return clib_error_return (0, "outer fib ID %d doesn't exist\n",
1088 case VNET_API_ERROR_NO_SUCH_ENTRY:
1089 return clib_error_return (0, "tunnel not found\n");
1091 case VNET_API_ERROR_NO_SUCH_LABEL:
1093 * This happens when there's no MPLS label for the dst address
1094 * no need for two error messages.
1099 return clib_error_return (0, "vnet_mpls_gre_add_del_tunnel returned %d",
1105 VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
1106 .path = "create mpls gre tunnel",
1108 "create mpls gre tunnel [del] src <addr> dst <addr> intfc <addr>/<mw>",
1109 .function = create_mpls_gre_tunnel_command_fn,
1112 u8 * format_mpls_encap_index (u8 * s, va_list * args)
1114 mpls_main_t * mm = va_arg (*args, mpls_main_t *);
1115 u32 entry_index = va_arg (*args, u32);
1119 e = pool_elt_at_index (mm->encaps, entry_index);
1121 for (i = 0; i < vec_len (e->labels); i++)
1123 (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
1124 (e->labels[i].label_exp_s_ttl)));
1129 u8 * format_mpls_gre_tunnel (u8 * s, va_list * args)
1131 mpls_gre_tunnel_t * t = va_arg (*args, mpls_gre_tunnel_t *);
1132 mpls_main_t * mm = &mpls_main;
1134 if (t->l2_only == 0)
1136 s = format (s, "[%d]: src %U, dst %U, adj %U/%d, labels %U\n",
1137 t - mm->gre_tunnels,
1138 format_ip4_address, &t->tunnel_src,
1139 format_ip4_address, &t->tunnel_dst,
1140 format_ip4_address, &t->intfc_address,
1142 format_mpls_encap_index, mm, t->encap_index);
1144 s = format (s, " inner fib index %d, outer fib index %d",
1145 t->inner_fib_index, t->outer_fib_index);
1149 s = format (s, "[%d]: src %U, dst %U, key %U, labels %U\n",
1150 t - mm->gre_tunnels,
1151 format_ip4_address, &t->tunnel_src,
1152 format_ip4_address, &t->tunnel_dst,
1153 format_ip4_address, &t->intfc_address,
1154 format_mpls_encap_index, mm, t->encap_index);
1156 s = format (s, " l2 interface %d, outer fib index %d",
1157 t->hw_if_index, t->outer_fib_index);
1163 u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
1165 mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
1166 mpls_main_t * mm = &mpls_main;
1168 s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
1169 t - mm->eth_tunnels,
1170 format_ethernet_address, &t->tunnel_dst,
1171 format_ip4_address, &t->intfc_address,
1173 format_mpls_encap_index, mm, t->encap_index);
1176 s = format (s, " tx on %U, rx fib index %d",
1177 format_vnet_sw_if_index_name, mm->vnet_main, t->tx_sw_if_index,
1178 t->inner_fib_index);
1183 static clib_error_t *
1184 show_mpls_tunnel_command_fn (vlib_main_t * vm,
1185 unformat_input_t * input,
1186 vlib_cli_command_t * cmd)
1188 mpls_main_t * mm = &mpls_main;
1189 mpls_gre_tunnel_t * gt;
1190 mpls_eth_tunnel_t * et;
1192 if (pool_elts (mm->gre_tunnels))
1194 vlib_cli_output (vm, "MPLS-GRE tunnels");
1195 pool_foreach (gt, mm->gre_tunnels,
1197 vlib_cli_output (vm, "%U", format_mpls_gre_tunnel, gt);
1201 vlib_cli_output (vm, "No MPLS-GRE tunnels");
1203 if (pool_elts (mm->eth_tunnels))
1205 vlib_cli_output (vm, "MPLS-Ethernet tunnels");
1206 pool_foreach (et, mm->eth_tunnels,
1208 vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
1212 vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
1217 VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
1218 .path = "show mpls tunnel",
1219 .short_help = "show mpls tunnel",
1220 .function = show_mpls_tunnel_command_fn,
1223 /* force inclusion from application's main.c */
1224 clib_error_t *mpls_interface_init (vlib_main_t *vm)
1226 clib_error_t * error;
1228 if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
1233 VLIB_INIT_FUNCTION(mpls_interface_init);
1236 static u8 * mpls_ethernet_rewrite (mpls_main_t *mm, mpls_eth_tunnel_t * t)
1238 u8 * rewrite_data = 0;
1240 mpls_unicast_header_t *lp0;
1243 /* look up the encap label stack using the RX FIB and adjacency address*/
1244 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index,
1245 t->intfc_address.as_u32);
1249 clib_warning ("no label for inner fib index %d, dst %U",
1250 t->inner_fib_index, format_ip4_address,
1255 vec_validate (rewrite_data,
1256 sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
1258 /* Copy the encap label stack */
1259 lp0 = (mpls_unicast_header_t *) rewrite_data;
1261 for (i = 0; i < vec_len(e->labels); i++)
1262 lp0[i] = e->labels[i];
1264 return (rewrite_data);
1267 int vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
1268 ip4_address_t *intfc,
1272 u32 * tunnel_sw_if_index,
1276 ip4_main_t * im = &ip4_main;
1277 ip_lookup_main_t * lm = &im->lookup_main;
1278 mpls_main_t * mm = &mpls_main;
1279 vnet_main_t * vnm = vnet_get_main();
1281 mpls_eth_tunnel_t *tp;
1282 int need_route_add_del = 1;
1283 u32 inner_fib_index = 0;
1287 int found_tunnel = 0;
1288 mpls_encap_t * e = 0;
1289 u32 hw_if_index = ~0;
1290 vnet_hw_interface_t * hi;
1296 if (tunnel_sw_if_index == 0)
1297 tunnel_sw_if_index = &dummy;
1299 *tunnel_sw_if_index = ~0;
1301 if (inner_fib_id != (u32)~0)
1305 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1307 return VNET_API_ERROR_NO_SUCH_FIB;
1308 inner_fib_index = p[0];
1311 /* suppress duplicate mpls interface generation. */
1312 pool_foreach (tp, mm->eth_tunnels,
1315 * If we have a tunnel which matches (src, dst, intfc/mask)
1316 * AND the expected route is in the FIB, it's a dup
1318 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1319 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1320 && tp->inner_fib_index == inner_fib_index)
1322 ip4_fib_t * fib = vec_elt_at_index (im->fibs, inner_fib_index);
1323 uword * hash = fib->adj_index_by_dst_address[mask_width];
1324 uword key = intfc->as_u32 & im->fib_masks[mask_width];
1325 uword *p = hash_get (hash, key);
1335 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
1338 return VNET_API_ERROR_NO_SUCH_LABEL;
1345 /* Delete, the route is already gone? */
1347 need_route_add_del = 0;
1354 /* Delete, and we can't find the tunnel */
1355 if (is_add == 0 && found_tunnel == 0)
1356 return VNET_API_ERROR_NO_SUCH_ENTRY;
1358 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
1360 return VNET_API_ERROR_NO_SUCH_LABEL;
1362 pool_get(mm->eth_tunnels, tp);
1363 memset (tp, 0, sizeof (*tp));
1365 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1368 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1369 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1370 hi = vnet_get_hw_interface (vnm, hw_if_index);
1371 hi->dev_instance = tp - mm->eth_tunnels;
1372 hi->hw_instance = tp - mm->eth_tunnels;
1376 hw_if_index = vnet_register_interface
1377 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1378 mpls_eth_hw_interface_class.index,
1379 tp - mm->eth_tunnels);
1380 hi = vnet_get_hw_interface (vnm, hw_if_index);
1382 /* ... to make the IP and L2 x-connect cases identical */
1383 slot = vlib_node_add_named_next_with_slot
1384 (vnm->vlib_main, hi->tx_node_index,
1385 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1387 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1390 *tunnel_sw_if_index = hi->sw_if_index;
1391 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1392 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1394 tp->hw_if_index = hw_if_index;
1397 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1398 tp->intfc_address.as_u32 = intfc->as_u32;
1399 tp->mask_width = mask_width;
1400 tp->inner_fib_index = inner_fib_index;
1401 tp->encap_index = e - mm->encaps;
1402 tp->tx_sw_if_index = tx_sw_if_index;
1403 tp->l2_only = l2_only;
1405 /* Create the adjacency and add to v4 fib */
1406 memset(&adj, 0, sizeof (adj));
1407 adj.explicit_fib_index = ~0;
1408 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1410 rewrite_data = mpls_ethernet_rewrite (mm, tp);
1411 if (rewrite_data == 0)
1413 if (*tunnel_sw_if_index != ~0)
1415 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1416 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1417 0 /* admin down */);
1418 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1421 pool_put (mm->eth_tunnels, tp);
1422 return VNET_API_ERROR_NO_SUCH_LABEL;
1425 vnet_rewrite_for_sw_interface
1427 VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1429 ip4_rewrite_node.index,
1431 &adj.rewrite_header,
1432 sizeof (adj.rewrite_data));
1435 * Prepend the (0,1,2) VLAN tag ethernet header
1436 * we just built to the mpls header stack
1438 vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
1439 clib_memcpy(rewrite_data,
1440 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1441 sizeof (adj.rewrite_data)),
1442 adj.rewrite_header.data_bytes);
1444 vnet_rewrite_set_data_internal (&adj.rewrite_header,
1445 sizeof(adj.rewrite_data),
1447 vec_len(rewrite_data));
1449 vec_free (tp->rewrite_data);
1451 tp->rewrite_data = rewrite_data;
1454 ip_add_adjacency (lm, &adj, 1 /* one adj */,
1459 if (need_route_add_del && !l2_only)
1462 ip4_add_del_route_next_hop (im,
1466 &zero /* no next hop */,
1467 (u32)~0 /* next_hop_sw_if_index */,
1470 tp->inner_fib_index);
1473 ip4_add_del_route_args_t a;
1474 memset (&a, 0, sizeof (a));
1476 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
1477 a.table_index_or_table_id = tp->inner_fib_index;
1478 a.dst_address = tp->intfc_address;
1479 a.dst_address_length = tp->mask_width;
1482 ip4_add_del_route (im, &a);
1483 ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
1484 IP4_ROUTE_FLAG_FIB_INDEX);
1487 if (is_add == 0 && found_tunnel)
1489 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1490 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1491 0 /* admin down */);
1492 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1493 vec_free (tp->rewrite_data);
1494 pool_put (mm->eth_tunnels, tp);
1500 static clib_error_t *
1501 create_mpls_ethernet_tunnel_command_fn (vlib_main_t * vm,
1502 unformat_input_t * input,
1503 vlib_cli_command_t * cmd)
1505 unformat_input_t _line_input, * line_input = &_line_input;
1506 vnet_main_t * vnm = vnet_get_main();
1507 ip4_address_t intfc;
1510 int dst_set = 0, intfc_set = 0;
1512 u32 inner_fib_id = (u32)~0;
1518 /* Get a line of input. */
1519 if (! unformat_user (input, unformat_line_input, line_input))
1522 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1524 if (unformat (line_input, "dst %U",
1525 unformat_ethernet_address, &dst))
1527 else if (unformat (line_input, "adj %U/%d",
1528 unformat_ip4_address, &intfc, &mask_width))
1530 else if (unformat (line_input, "tx-intfc %U",
1531 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1533 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1535 else if (unformat (line_input, "l2-only"))
1537 else if (unformat (line_input, "del"))
1540 return clib_error_return (0, "unknown input '%U'",
1541 format_unformat_error, line_input);
1545 return clib_error_return (0, "missing tx-intfc");
1548 return clib_error_return (0, "missing: dst <ethernet-address>");
1551 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1554 rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
1555 inner_fib_id, tx_sw_if_index,
1556 0 /* tunnel sw_if_index */,
1561 case VNET_API_ERROR_NO_SUCH_FIB:
1562 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1565 case VNET_API_ERROR_NO_SUCH_ENTRY:
1566 return clib_error_return (0, "tunnel not found\n");
1568 case VNET_API_ERROR_NO_SUCH_LABEL:
1570 * This happens when there's no MPLS label for the dst address
1571 * no need for two error messages.
1573 return clib_error_return (0, "no label for %U in fib %d",
1574 format_ip4_address, &intfc, inner_fib_id);
1584 VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
1585 .path = "create mpls ethernet tunnel",
1587 "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
1588 .function = create_mpls_ethernet_tunnel_command_fn,
1592 int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
1594 u32 policy_tunnel_index)
1596 mpls_eth_tunnel_t * t;
1598 u8 * rewrite_data = 0;
1600 mpls_unicast_header_t *lp;
1603 if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
1604 return VNET_API_ERROR_NO_SUCH_ENTRY;
1606 t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
1608 memset (&adj, 0, sizeof (adj));
1610 /* Build L2 encap */
1611 vnet_rewrite_for_sw_interface
1613 VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1615 mpls_policy_encap_node.index,
1617 &adj.rewrite_header,
1618 sizeof (adj.rewrite_data));
1620 vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
1622 clib_memcpy(rewrite_data,
1623 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1624 sizeof (adj.rewrite_data)),
1625 adj.rewrite_header.data_bytes);
1627 /* Append the label stack */
1629 vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
1631 lp = (mpls_unicast_header_t *) label_start;
1633 for (i = 0; i < vec_len(e->labels); i++)
1634 lp[i] = e->labels[i];
1636 /* Remember the rewrite data */
1637 e->rewrite = rewrite_data;
1638 e->output_next_index = adj.rewrite_header.next_index;
1643 int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
1644 ip4_address_t *intfc,
1648 u32 * tunnel_sw_if_index,
1649 u32 classify_table_index,
1650 u32 * new_tunnel_index,
1654 ip4_main_t * im = &ip4_main;
1655 ip_lookup_main_t * lm = &im->lookup_main;
1656 mpls_main_t * mm = &mpls_main;
1657 vnet_main_t * vnm = vnet_get_main();
1659 mpls_eth_tunnel_t *tp;
1660 int need_route_add_del = 1;
1661 u32 inner_fib_index = 0;
1664 int found_tunnel = 0;
1665 mpls_encap_t * e = 0;
1666 u32 hw_if_index = ~0;
1667 vnet_hw_interface_t * hi;
1673 if (tunnel_sw_if_index == 0)
1674 tunnel_sw_if_index = &dummy;
1676 *tunnel_sw_if_index = ~0;
1678 if (inner_fib_id != (u32)~0)
1682 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1684 return VNET_API_ERROR_NO_SUCH_FIB;
1685 inner_fib_index = p[0];
1688 /* suppress duplicate mpls interface generation. */
1689 pool_foreach (tp, mm->eth_tunnels,
1692 * If we have a tunnel which matches (src, dst, intfc/mask)
1693 * AND the expected route is in the FIB, it's a dup
1695 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1696 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1697 && tp->inner_fib_index == inner_fib_index)
1699 ip4_fib_t * fib = vec_elt_at_index (im->fibs, inner_fib_index);
1700 uword * hash = fib->adj_index_by_dst_address[mask_width];
1701 uword key = intfc->as_u32 & im->fib_masks[mask_width];
1702 uword *p = hash_get (hash, key);
1717 /* Delete, the route is already gone? */
1719 need_route_add_del = 0;
1726 /* Delete, and we can't find the tunnel */
1727 if (is_add == 0 && found_tunnel == 0)
1728 return VNET_API_ERROR_NO_SUCH_ENTRY;
1730 pool_get(mm->eth_tunnels, tp);
1731 memset (tp, 0, sizeof (*tp));
1733 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1736 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1737 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1738 hi = vnet_get_hw_interface (vnm, hw_if_index);
1739 hi->dev_instance = tp - mm->eth_tunnels;
1740 hi->hw_instance = tp - mm->eth_tunnels;
1744 hw_if_index = vnet_register_interface
1745 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1746 mpls_eth_hw_interface_class.index,
1747 tp - mm->eth_tunnels);
1748 hi = vnet_get_hw_interface (vnm, hw_if_index);
1750 /* ... to make the IP and L2 x-connect cases identical */
1751 slot = vlib_node_add_named_next_with_slot
1752 (vnm->vlib_main, hi->tx_node_index,
1753 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1755 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1758 *tunnel_sw_if_index = hi->sw_if_index;
1759 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1760 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1762 tp->hw_if_index = hw_if_index;
1765 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1766 tp->intfc_address.as_u32 = intfc->as_u32;
1767 tp->mask_width = mask_width;
1768 tp->inner_fib_index = inner_fib_index;
1769 tp->encap_index = e - mm->encaps;
1770 tp->tx_sw_if_index = tx_sw_if_index;
1771 tp->l2_only = l2_only;
1773 if (new_tunnel_index)
1774 *new_tunnel_index = tp - mm->eth_tunnels;
1776 /* Create the classify adjacency and add to v4 fib */
1777 memset(&adj, 0, sizeof (adj));
1778 adj.explicit_fib_index = ~0;
1779 adj.lookup_next_index = IP_LOOKUP_NEXT_CLASSIFY;
1780 adj.classify.table_index = classify_table_index;
1783 ip_add_adjacency (lm, &adj, 1 /* one adj */,
1788 if (need_route_add_del && !l2_only)
1791 ip4_add_del_route_next_hop (im,
1795 &zero /* no next hop */,
1796 (u32)~0 /* next_hop_sw_if_index */,
1799 tp->inner_fib_index);
1802 ip4_add_del_route_args_t a;
1803 memset (&a, 0, sizeof (a));
1805 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
1806 a.table_index_or_table_id = tp->inner_fib_index;
1807 a.dst_address = tp->intfc_address;
1808 a.dst_address_length = tp->mask_width;
1811 ip4_add_del_route (im, &a);
1812 ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
1813 IP4_ROUTE_FLAG_FIB_INDEX);
1816 if (is_add == 0 && found_tunnel)
1818 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1819 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1820 0 /* admin down */);
1821 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1822 pool_put (mm->eth_tunnels, tp);
1828 static clib_error_t *
1829 create_mpls_ethernet_policy_tunnel_command_fn (vlib_main_t * vm,
1830 unformat_input_t * input,
1831 vlib_cli_command_t * cmd)
1833 unformat_input_t _line_input, * line_input = &_line_input;
1834 vnet_main_t * vnm = vnet_get_main();
1835 ip4_address_t intfc;
1838 int dst_set = 0, intfc_set = 0;
1840 u32 inner_fib_id = (u32)~0;
1841 u32 classify_table_index = (u32)~0;
1842 u32 new_tunnel_index;
1848 /* Get a line of input. */
1849 if (! unformat_user (input, unformat_line_input, line_input))
1852 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1854 if (unformat (line_input, "dst %U",
1855 unformat_ethernet_address, &dst))
1857 else if (unformat (line_input, "adj %U/%d",
1858 unformat_ip4_address, &intfc, &mask_width))
1860 else if (unformat (line_input, "tx-intfc %U",
1861 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1863 else if (unformat (line_input, "classify-table-index %d",
1864 &classify_table_index))
1866 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1868 else if (unformat (line_input, "l2-only"))
1870 else if (unformat (line_input, "del"))
1873 return clib_error_return (0, "unknown input '%U'",
1874 format_unformat_error, line_input);
1877 if (classify_table_index == ~0)
1878 return clib_error_return (0, "missing classify_table_index");
1881 return clib_error_return (0, "missing tx-intfc");
1884 return clib_error_return (0, "missing: dst <ethernet-address>");
1887 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1890 rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
1891 inner_fib_id, tx_sw_if_index,
1892 0 /* tunnel sw_if_index */,
1893 classify_table_index,
1898 case VNET_API_ERROR_NO_SUCH_FIB:
1899 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1902 case VNET_API_ERROR_NO_SUCH_ENTRY:
1903 return clib_error_return (0, "tunnel not found\n");
1905 case VNET_API_ERROR_NO_SUCH_LABEL:
1907 * This happens when there's no MPLS label for the dst address
1908 * no need for two error messages.
1910 return clib_error_return (0, "no label for %U in fib %d",
1911 format_ip4_address, &intfc, inner_fib_id);
1919 vlib_cli_output (vm, "tunnel index %d", new_tunnel_index);
1924 VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
1925 .path = "create mpls ethernet policy tunnel",
1927 "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
1928 " classify-table-index <nn>",
1929 .function = create_mpls_ethernet_policy_tunnel_command_fn,