2 * interface.c: mpls interfaces
4 * Copyright (c) 2012 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/vnet.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/gre/gre.h>
21 #include <vnet/mpls/mpls.h>
22 #include <vnet/fib/ip4_fib.h>
23 #include <vnet/adj/adj_midchain.h>
24 #include <vnet/dpo/classify_dpo.h>
26 static uword mpls_gre_set_rewrite (vnet_main_t * vnm,
31 uword max_rewrite_bytes)
34 * Conundrum: packets from tun/tap destined for the tunnel
35 * actually have this rewrite applied. Transit packets do not.
36 * To make the two cases equivalent, don't generate a
37 * rewrite here, build the entire header in the fast path.
42 /* manually added to the interface output node */
43 #define MPLS_GRE_OUTPUT_NEXT_POST_REWRITE 1
46 mpls_gre_interface_tx (vlib_main_t * vm,
47 vlib_node_runtime_t * node,
50 mpls_main_t * gm = &mpls_main;
51 vnet_main_t * vnm = gm->vnet_main;
53 u32 * from, * to_next, n_left_from, n_left_to_next;
55 /* Vector of buffer / pkt indices we're supposed to process */
56 from = vlib_frame_vector_args (frame);
58 /* Number of buffers / pkts */
59 n_left_from = frame->n_vectors;
61 /* Speculatively send the first buffer to the last disposition we used */
62 next_index = node->cached_next_index;
64 while (n_left_from > 0)
66 /* set up to enqueue to our disposition with index = next_index */
67 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
70 * As long as we have enough pkts left to process two pkts
71 * and prefetch two pkts...
73 while (n_left_from >= 4 && n_left_to_next >= 2)
75 vlib_buffer_t * b0, * b1;
76 u32 bi0, next0, bi1, next1;
77 mpls_gre_tunnel_t * t0, * t1;
78 u32 sw_if_index0, sw_if_index1;
79 vnet_hw_interface_t * hi0, * hi1;
82 /* Prefetch the next iteration */
84 vlib_buffer_t * p2, * p3;
86 p2 = vlib_get_buffer (vm, from[2]);
87 p3 = vlib_get_buffer (vm, from[3]);
89 vlib_prefetch_buffer_header (p2, LOAD);
90 vlib_prefetch_buffer_header (p3, LOAD);
93 * Prefetch packet data. We expect to overwrite
94 * the inbound L2 header with an ip header and a
95 * gre header. Might want to prefetch the last line
96 * of rewrite space as well; need profile data
98 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
99 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
102 /* Pick up the next two buffer indices */
106 /* Speculatively enqueue them where we sent the last buffer */
114 b0 = vlib_get_buffer (vm, bi0);
115 b1 = vlib_get_buffer (vm, bi1);
117 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
118 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
121 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
122 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
124 /* hw_instance = tunnel pool index */
125 t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance);
126 t1 = pool_elt_at_index (gm->gre_tunnels, hi1->hw_instance);
128 /* Apply rewrite - $$$$$ fixme don't use memcpy */
129 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
130 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
132 dst0 = vlib_buffer_get_current (b0);
133 dst1 = vlib_buffer_get_current (b1);
135 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
136 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
138 /* Fix TX fib indices */
139 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
140 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->outer_fib_index;
142 /* mpls-post-rewrite takes it from here... */
143 next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
144 next1 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
146 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
148 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
150 tr->tunnel_id = t0 - gm->gre_tunnels;
151 tr->length = b0->current_length;
152 tr->src.as_u32 = t0->tunnel_src.as_u32;
153 tr->dst.as_u32 = t0->tunnel_dst.as_u32;
155 tr->mpls_encap_index = t0->encap_index;
157 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
159 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
161 tr->tunnel_id = t1 - gm->gre_tunnels;
162 tr->length = b1->current_length;
163 tr->src.as_u32 = t1->tunnel_src.as_u32;
164 tr->dst.as_u32 = t1->tunnel_dst.as_u32;
166 tr->mpls_encap_index = t1->encap_index;
169 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
170 to_next, n_left_to_next,
171 bi0, bi1, next0, next1);
174 while (n_left_from > 0 && n_left_to_next > 0)
178 mpls_gre_tunnel_t * t0;
180 vnet_hw_interface_t * hi0;
190 b0 = vlib_get_buffer (vm, bi0);
192 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
194 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
196 t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance);
198 /* Apply rewrite - $$$$$ fixme don't use memcpy */
199 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
201 dst0 = vlib_buffer_get_current (b0);
203 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
205 /* Fix the TX fib index */
206 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
208 /* mpls-post-rewrite takes it from here... */
209 next0 = MPLS_GRE_OUTPUT_NEXT_POST_REWRITE;
211 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
213 mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
215 tr->tunnel_id = t0 - gm->gre_tunnels;
216 tr->length = b0->current_length;
217 tr->src.as_u32 = t0->tunnel_src.as_u32;
218 tr->dst.as_u32 = t0->tunnel_dst.as_u32;
220 tr->mpls_encap_index = t0->encap_index;
223 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
224 to_next, n_left_to_next,
228 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
231 vlib_node_increment_counter (vm, gre_input_node.index,
232 GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
234 return frame->n_vectors;
237 static u8 * format_mpls_gre_tunnel_name (u8 * s, va_list * args)
239 u32 dev_instance = va_arg (*args, u32);
240 return format (s, "mpls-gre%d", dev_instance);
243 static u8 * format_mpls_gre_device (u8 * s, va_list * args)
245 u32 dev_instance = va_arg (*args, u32);
246 CLIB_UNUSED (int verbose) = va_arg (*args, int);
248 s = format (s, "MPLS-GRE tunnel: id %d\n", dev_instance);
252 VNET_DEVICE_CLASS (mpls_gre_device_class) = {
253 .name = "MPLS-GRE tunnel device",
254 .format_device_name = format_mpls_gre_tunnel_name,
255 .format_device = format_mpls_gre_device,
256 .format_tx_trace = format_mpls_gre_tx_trace,
257 .tx_function = mpls_gre_interface_tx,
258 .no_flatten_output_chains = 1,
261 .admin_up_down_function = 0;
265 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_gre_device_class,
266 mpls_gre_interface_tx)
268 VNET_HW_INTERFACE_CLASS (mpls_gre_hw_interface_class) = {
270 .format_header = format_mpls_gre_header_with_length,
272 .unformat_header = unformat_mpls_gre_header,
274 .set_rewrite = mpls_gre_set_rewrite,
278 static uword mpls_eth_set_rewrite (vnet_main_t * vnm,
283 uword max_rewrite_bytes)
286 * Conundrum: packets from tun/tap destined for the tunnel
287 * actually have this rewrite applied. Transit packets do not.
288 * To make the two cases equivalent, don't generate a
289 * rewrite here, build the entire header in the fast path.
294 /* manually added to the interface output node */
295 #define MPLS_ETH_OUTPUT_NEXT_OUTPUT 1
298 mpls_eth_interface_tx (vlib_main_t * vm,
299 vlib_node_runtime_t * node,
300 vlib_frame_t * frame)
302 mpls_main_t * gm = &mpls_main;
303 vnet_main_t * vnm = gm->vnet_main;
305 u32 * from, * to_next, n_left_from, n_left_to_next;
307 /* Vector of buffer / pkt indices we're supposed to process */
308 from = vlib_frame_vector_args (frame);
310 /* Number of buffers / pkts */
311 n_left_from = frame->n_vectors;
313 /* Speculatively send the first buffer to the last disposition we used */
314 next_index = node->cached_next_index;
316 while (n_left_from > 0)
318 /* set up to enqueue to our disposition with index = next_index */
319 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
322 * As long as we have enough pkts left to process two pkts
323 * and prefetch two pkts...
325 while (n_left_from >= 4 && n_left_to_next >= 2)
327 vlib_buffer_t * b0, * b1;
328 u32 bi0, next0, bi1, next1;
329 mpls_eth_tunnel_t * t0, * t1;
330 u32 sw_if_index0, sw_if_index1;
331 vnet_hw_interface_t * hi0, * hi1;
334 /* Prefetch the next iteration */
336 vlib_buffer_t * p2, * p3;
338 p2 = vlib_get_buffer (vm, from[2]);
339 p3 = vlib_get_buffer (vm, from[3]);
341 vlib_prefetch_buffer_header (p2, LOAD);
342 vlib_prefetch_buffer_header (p3, LOAD);
345 * Prefetch packet data. We expect to overwrite
346 * the inbound L2 header with an ip header and a
347 * gre header. Might want to prefetch the last line
348 * of rewrite space as well; need profile data
350 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
351 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
354 /* Pick up the next two buffer indices */
358 /* Speculatively enqueue them where we sent the last buffer */
366 b0 = vlib_get_buffer (vm, bi0);
367 b1 = vlib_get_buffer (vm, bi1);
369 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
370 sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
373 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
374 hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
376 /* hw_instance = tunnel pool index */
377 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
378 t1 = pool_elt_at_index (gm->eth_tunnels, hi1->hw_instance);
380 /* Apply rewrite - $$$$$ fixme don't use memcpy */
381 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
382 vlib_buffer_advance (b1, -(word)vec_len(t1->rewrite_data));
384 dst0 = vlib_buffer_get_current (b0);
385 dst1 = vlib_buffer_get_current (b1);
387 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
388 clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
390 /* Fix TX fib indices */
391 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
392 vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->tx_sw_if_index;
394 /* mpls-post-rewrite takes it from here... */
395 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
396 next1 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
398 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
400 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
403 tr->tunnel_id = t0 - gm->eth_tunnels;
404 tr->tx_sw_if_index = t0->tx_sw_if_index;
405 tr->mpls_encap_index = t0->encap_index;
406 tr->length = b0->current_length;
407 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
408 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
410 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
412 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
415 tr->tunnel_id = t1 - gm->eth_tunnels;
416 tr->tx_sw_if_index = t1->tx_sw_if_index;
417 tr->mpls_encap_index = t1->encap_index;
418 tr->length = b1->current_length;
419 hi1 = vnet_get_sup_hw_interface (vnm, t1->tx_sw_if_index);
420 clib_memcpy (tr->dst, hi1->hw_address, sizeof (tr->dst));
423 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
424 to_next, n_left_to_next,
425 bi0, bi1, next0, next1);
427 while (n_left_from > 0 && n_left_to_next > 0)
431 mpls_eth_tunnel_t * t0;
433 vnet_hw_interface_t * hi0;
443 b0 = vlib_get_buffer (vm, bi0);
445 sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
447 hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
449 t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
451 /* Apply rewrite - $$$$$ fixme don't use memcpy */
452 vlib_buffer_advance (b0, -(word)vec_len(t0->rewrite_data));
454 dst0 = vlib_buffer_get_current (b0);
456 clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
458 /* Fix the TX interface */
459 vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
461 /* Send the packet */
462 next0 = MPLS_ETH_OUTPUT_NEXT_OUTPUT;
464 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
466 mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
469 tr->tunnel_id = t0 - gm->eth_tunnels;
470 tr->tx_sw_if_index = t0->tx_sw_if_index;
471 tr->mpls_encap_index = t0->encap_index;
472 tr->length = b0->current_length;
473 hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
474 clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
477 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
478 to_next, n_left_to_next,
482 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
485 vlib_node_increment_counter (vm, mpls_input_node.index,
486 MPLS_ERROR_PKTS_ENCAP, frame->n_vectors);
488 return frame->n_vectors;
491 static u8 * format_mpls_eth_tunnel_name (u8 * s, va_list * args)
493 u32 dev_instance = va_arg (*args, u32);
494 return format (s, "mpls-eth%d", dev_instance);
497 static u8 * format_mpls_eth_device (u8 * s, va_list * args)
499 u32 dev_instance = va_arg (*args, u32);
500 CLIB_UNUSED (int verbose) = va_arg (*args, int);
502 s = format (s, "MPLS-ETH tunnel: id %d\n", dev_instance);
506 VNET_DEVICE_CLASS (mpls_eth_device_class) = {
507 .name = "MPLS-ETH tunnel device",
508 .format_device_name = format_mpls_eth_tunnel_name,
509 .format_device = format_mpls_eth_device,
510 .format_tx_trace = format_mpls_eth_tx_trace,
511 .tx_function = mpls_eth_interface_tx,
512 .no_flatten_output_chains = 1,
515 .admin_up_down_function = 0;
519 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (mpls_eth_device_class,
520 mpls_eth_interface_tx)
522 VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = {
524 .format_header = format_mpls_eth_header_with_length,
526 .unformat_header = unformat_mpls_eth_header,
528 .set_rewrite = mpls_eth_set_rewrite,
532 * A conversion of DPO next object tpyes to VLIB graph next nodes from
533 * the mpls_post_rewrite node
535 static const int dpo_next_2_mpls_post_rewrite[DPO_LAST] = {
536 [DPO_LOAD_BALANCE] = IP_LOOKUP_NEXT_LOAD_BALANCE,
540 mpls_post_rewrite (vlib_main_t * vm,
541 vlib_node_runtime_t * node,
542 vlib_frame_t * from_frame)
544 ip4_main_t * im = &ip4_main;
545 ip_lookup_main_t * lm = &im->lookup_main;
546 u32 n_left_from, next_index, * from, * to_next;
547 u16 old_l0 = 0; //, old_l1 = 0;
549 from = vlib_frame_vector_args (from_frame);
550 n_left_from = from_frame->n_vectors;
552 next_index = node->cached_next_index;
554 while (n_left_from > 0)
558 vlib_get_next_frame (vm, node, next_index,
559 to_next, n_left_to_next);
561 /* while (n_left_from >= 4 && n_left_to_next >= 2) */
564 /* vlib_buffer_t * b0, * b1; */
565 /* ip4_header_t * ip0, * ip1; */
568 /* u16 new_l0, new_l1, adj_index0, adj_index1; */
569 /* ip_csum_t sum0, sum1; */
570 /* ip_adjacency_t *adj0, *adj1; */
572 /* /\* Prefetch next iteration. *\/ */
574 /* vlib_buffer_t * p2, * p3; */
576 /* p2 = vlib_get_buffer (vm, from[2]); */
577 /* p3 = vlib_get_buffer (vm, from[3]); */
579 /* vlib_prefetch_buffer_header (p2, LOAD); */
580 /* vlib_prefetch_buffer_header (p3, LOAD); */
582 /* CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); */
583 /* CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); */
588 /* to_next[0] = bi0; */
589 /* to_next[1] = bi1; */
592 /* n_left_to_next -= 2; */
593 /* n_left_from -= 2; */
596 /* b0 = vlib_get_buffer (vm, bi0); */
597 /* b1 = vlib_get_buffer (vm, bi1); */
598 /* ip0 = vlib_buffer_get_current (b0); */
599 /* ip1 = vlib_buffer_get_current (b1); */
601 /* /\* Note: the tunnel rewrite sets up sw_if_index[VLIB_TX] *\/ */
603 /* /\* set the GRE (outer) ip packet length, fix the bloody checksum *\/ */
604 /* sum0 = ip0->checksum; */
605 /* sum1 = ip1->checksum; */
607 /* /\* old_l0, old_l1 always 0, see the rewrite setup *\/ */
609 /* clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); */
611 /* clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1)); */
613 /* sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, */
614 /* length /\* changed member *\/); */
615 /* sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t, */
616 /* length /\* changed member *\/); */
617 /* ip0->checksum = ip_csum_fold (sum0); */
618 /* ip1->checksum = ip_csum_fold (sum1); */
619 /* ip0->length = new_l0; */
620 /* ip1->length = new_l1; */
622 /* /\* replace the TX adj in the packet with the next in the chain *\/ */
623 /* adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX]; */
624 /* adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX]; */
626 /* adj0 = ip_get_adjacency (lm, adj_index0); */
627 /* adj1 = ip_get_adjacency (lm, adj_index1); */
629 /* ASSERT(adj0->sub_type.midchain.adj_index != ADJ_INDEX_INVALID); */
630 /* ASSERT(adj1->sub_type.midchain.adj_index != ADJ_INDEX_INVALID); */
632 /* adj_index0 = adj0->sub_type.midchain.adj_index; */
633 /* adj_index1 = adj1->sub_type.midchain.adj_index; */
635 /* vnet_buffer (b0)->ip.adj_index[VLIB_TX] = adj_index0; */
636 /* vnet_buffer (b1)->ip.adj_index[VLIB_TX] = adj_index1; */
638 /* /\* get the next adj in the chain to determine the next graph node *\/ */
639 /* adj0 = ip_get_adjacency (lm, adj_index0); */
640 /* adj1 = ip_get_adjacency (lm, adj_index1); */
642 /* next0 = adj0->lookup_next_index; */
643 /* next1 = adj1->lookup_next_index; */
645 /* vlib_validate_buffer_enqueue_x2 (vm, node, next_index, */
646 /* to_next, n_left_to_next, */
647 /* bi0, bi1, next0, next1); */
650 while (n_left_from > 0 && n_left_to_next > 0)
652 ip_adjacency_t * adj0;
657 u16 new_l0, adj_index0;
667 b0 = vlib_get_buffer (vm, bi0);
668 ip0 = vlib_buffer_get_current (b0);
670 /* Note: the tunnel rewrite sets up sw_if_index[VLIB_TX] */
672 /* set the GRE (outer) ip packet length, fix the bloody checksum */
673 sum0 = ip0->checksum;
674 /* old_l0 always 0, see the rewrite setup */
676 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
678 sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
679 length /* changed member */);
680 ip0->checksum = ip_csum_fold (sum0);
681 ip0->length = new_l0;
683 /* replace the TX adj in the packet with the next in the chain */
684 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
688 adj0 = ip_get_adjacency (lm, adj_index0);
689 ASSERT(adj0->sub_type.midchain.next_dpo.dpoi_index != ADJ_INDEX_INVALID);
690 adj_index0 = adj0->sub_type.midchain.next_dpo.dpoi_index;
691 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = adj_index0;
693 /* get the next adj in the chain to determine the next graph node */
695 next0 = 0; //adj0->sub_type.midchain.next_dpo.dpoi_next;
697 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
698 to_next, n_left_to_next,
702 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
704 vlib_node_increment_counter (vm, mpls_input_node.index,
705 MPLS_ERROR_PKTS_ENCAP, from_frame->n_vectors);
706 return from_frame->n_vectors;
709 VLIB_REGISTER_NODE (mpls_post_rewrite_node) = {
710 .function = mpls_post_rewrite,
711 .name = "mpls-post-rewrite",
712 /* Takes a vector of packets. */
713 .vector_size = sizeof (u32),
715 .runtime_data_bytes = 0,
717 .n_next_nodes = IP_LOOKUP_N_NEXT,
718 .next_nodes = IP4_LOOKUP_NEXT_NODES,
721 VLIB_NODE_FUNCTION_MULTIARCH (mpls_post_rewrite_node, mpls_post_rewrite)
723 static u8 * mpls_gre_rewrite (mpls_main_t *mm, mpls_gre_tunnel_t * t)
726 ip4_gre_and_mpls_header_t * h0;
727 u8 * rewrite_data = 0;
729 mpls_unicast_header_t *lp0;
732 /* look up the encap label stack using the RX FIB */
733 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index, t->tunnel_dst.as_u32);
737 clib_warning ("no label for inner fib index %d, dst %U",
738 t->inner_fib_index, format_ip4_address,
743 vec_validate (rewrite_data, sizeof (*h0)
744 + sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
745 memset (rewrite_data, 0, sizeof (*h0));
747 h0 = (ip4_gre_and_mpls_header_t *) rewrite_data;
748 /* Copy the encap label stack */
750 for (i = 0; i < vec_len(e->labels); i++)
751 lp0[i] = e->labels[i];
753 h0->gre.protocol = clib_host_to_net_u16(GRE_PROTOCOL_mpls_unicast);
754 ip0->ip_version_and_header_length = 0x45;
756 ip0->protocol = IP_PROTOCOL_GRE;
757 /* $$$ fixup ip4 header length and checksum after-the-fact */
758 ip0->src_address.as_u32 = t->tunnel_src.as_u32;
759 ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
760 ip0->checksum = ip4_header_checksum (ip0);
762 return (rewrite_data);
766 mpls_sw_interface_is_enabled (u32 sw_if_index)
768 mpls_main_t * mm = &mpls_main;
770 if (vec_len(mm->mpls_enabled_by_sw_if_index) < sw_if_index)
773 return (mm->mpls_enabled_by_sw_if_index[sw_if_index]);
777 mpls_sw_interface_enable_disable (mpls_main_t * mm,
781 mpls_interface_state_change_callback_t *callback;
782 vlib_main_t * vm = vlib_get_main();
783 ip_config_main_t * cm = &mm->rx_config_mains;
784 vnet_config_main_t * vcm = &cm->config_main;
785 u32 lookup_feature_index;
786 fib_node_index_t lfib_index;
789 vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
792 * enable/disable only on the 1<->0 transition
796 if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
799 lfib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS,
800 MPLS_FIB_DEFAULT_TABLE_ID);
801 vec_validate(mm->fib_index_by_sw_if_index, 0);
802 mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
806 ASSERT(mm->mpls_enabled_by_sw_if_index[sw_if_index] > 0);
807 if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
810 fib_table_unlock(mm->fib_index_by_sw_if_index[sw_if_index],
814 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
815 ci = cm->config_index_by_sw_if_index[sw_if_index];
817 lookup_feature_index = mm->mpls_rx_feature_lookup;
820 ci = vnet_config_add_feature (vm, vcm,
822 lookup_feature_index,
824 /* # bytes of config data */ 0);
826 ci = vnet_config_del_feature (vm, vcm, ci,
827 lookup_feature_index,
829 /* # bytes of config data */ 0);
831 cm->config_index_by_sw_if_index[sw_if_index] = ci;
834 * notify all interested clients of the change of state.
836 vec_foreach(callback, mm->mpls_interface_state_change_callbacks)
838 (*callback)(sw_if_index, is_enable);
842 static mpls_gre_tunnel_t *
843 mpls_gre_tunnel_from_fib_node (fib_node_t *node)
846 ASSERT(FIB_NODE_TYPE_MPLS_GRE_TUNNEL == node->fn_type);
848 return ((mpls_gre_tunnel_t*)node);
852 * mpls_gre_tunnel_stack
854 * 'stack' (resolve the recursion for) the tunnel's midchain adjacency
857 mpls_gre_tunnel_stack (mpls_gre_tunnel_t *mgt)
860 * find the adjacency that is contributed by the FIB entry
861 * that this tunnel resovles via, and use it as the next adj
864 adj_nbr_midchain_stack(mgt->adj_index,
865 fib_entry_contribute_ip_forwarding(mgt->fei));
869 * Function definition to backwalk a FIB node
871 static fib_node_back_walk_rc_t
872 mpls_gre_tunnel_back_walk (fib_node_t *node,
873 fib_node_back_walk_ctx_t *ctx)
875 mpls_gre_tunnel_stack(mpls_gre_tunnel_from_fib_node(node));
877 return (FIB_NODE_BACK_WALK_CONTINUE);
881 * Function definition to get a FIB node from its index
884 mpls_gre_tunnel_fib_node_get (fib_node_index_t index)
886 mpls_gre_tunnel_t * mgt;
890 mgt = pool_elt_at_index(mm->gre_tunnels, index);
892 return (&mgt->mgt_node);
896 * Function definition to inform the FIB node that its last lock has gone.
899 mpls_gre_tunnel_last_lock_gone (fib_node_t *node)
902 * The MPLS GRE tunnel is a root of the graph. As such
903 * it never has children and thus is never locked.
909 * Virtual function table registered by MPLS GRE tunnels
910 * for participation in the FIB object graph.
912 const static fib_node_vft_t mpls_gre_vft = {
913 .fnv_get = mpls_gre_tunnel_fib_node_get,
914 .fnv_last_lock = mpls_gre_tunnel_last_lock_gone,
915 .fnv_back_walk = mpls_gre_tunnel_back_walk,
918 static mpls_gre_tunnel_t *
919 mpls_gre_tunnel_find (ip4_address_t *src,
921 ip4_address_t *intfc,
924 mpls_main_t * mm = &mpls_main;
925 mpls_gre_tunnel_t *tp;
926 int found_tunnel = 0;
928 /* suppress duplicate mpls interface generation. */
929 pool_foreach (tp, mm->gre_tunnels,
932 * If we have a tunnel which matches (src, dst, intfc/mask)
933 * AND the expected route is in the FIB, it's a dup
935 if (!memcmp (&tp->tunnel_src, src, sizeof (*src))
936 && !memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
937 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
938 && tp->inner_fib_index == inner_fib_index)
953 int mpls_gre_tunnel_add (ip4_address_t *src,
955 ip4_address_t *intfc,
959 u32 * tunnel_sw_if_index,
962 mpls_main_t * mm = &mpls_main;
963 gre_main_t * gm = &gre_main;
964 vnet_main_t * vnm = vnet_get_main();
965 mpls_gre_tunnel_t *tp;
968 mpls_encap_t * e = 0;
969 u32 hw_if_index = ~0;
970 vnet_hw_interface_t * hi;
972 const ip46_address_t zero_nh = {
976 tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index);
980 return VNET_API_ERROR_NO_SUCH_ENTRY;
982 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, dst->as_u32);
984 return VNET_API_ERROR_NO_SUCH_LABEL;
986 pool_get(mm->gre_tunnels, tp);
987 memset (tp, 0, sizeof (*tp));
988 fib_node_init(&tp->mgt_node,
989 FIB_NODE_TYPE_MPLS_GRE_TUNNEL);
991 if (vec_len (mm->free_gre_sw_if_indices) > 0)
994 mm->free_gre_sw_if_indices[vec_len(mm->free_gre_sw_if_indices)-1];
995 _vec_len (mm->free_gre_sw_if_indices) -= 1;
996 hi = vnet_get_hw_interface (vnm, hw_if_index);
997 hi->dev_instance = tp - mm->gre_tunnels;
998 hi->hw_instance = tp - mm->gre_tunnels;
1002 hw_if_index = vnet_register_interface
1003 (vnm, mpls_gre_device_class.index, tp - mm->gre_tunnels,
1004 mpls_gre_hw_interface_class.index,
1005 tp - mm->gre_tunnels);
1006 hi = vnet_get_hw_interface (vnm, hw_if_index);
1008 /* ... to make the IP and L2 x-connect cases identical */
1009 slot = vlib_node_add_named_next_with_slot
1010 (vnm->vlib_main, hi->tx_node_index,
1011 "mpls-post-rewrite", MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
1013 ASSERT (slot == MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
1016 *tunnel_sw_if_index = hi->sw_if_index;
1017 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1018 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1019 vec_validate(ip4_main.fib_index_by_sw_if_index, *tunnel_sw_if_index);
1020 ip4_main.fib_index_by_sw_if_index[*tunnel_sw_if_index] = outer_fib_index;
1022 tp->hw_if_index = hw_if_index;
1024 /* bind the MPLS and IPv4 FIBs to the interface and enable */
1025 vec_validate(mm->fib_index_by_sw_if_index, hi->sw_if_index);
1026 mm->fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index;
1027 mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 1);
1028 ip4_main.fib_index_by_sw_if_index[hi->sw_if_index] = inner_fib_index;
1029 ip4_sw_interface_enable_disable(hi->sw_if_index, 1);
1031 tp->tunnel_src.as_u32 = src->as_u32;
1032 tp->tunnel_dst.as_u32 = dst->as_u32;
1033 tp->intfc_address.as_u32 = intfc->as_u32;
1034 tp->mask_width = mask_width;
1035 tp->inner_fib_index = inner_fib_index;
1036 tp->outer_fib_index = outer_fib_index;
1037 tp->encap_index = e - mm->encaps;
1038 tp->l2_only = l2_only;
1040 /* Add the tunnel to the hash table of all GRE tunnels */
1041 u64 key = (u64)src->as_u32 << 32 | (u64)dst->as_u32;
1043 ASSERT(NULL == hash_get (gm->tunnel_by_key, key));
1044 hash_set (gm->tunnel_by_key, key, tp - mm->gre_tunnels);
1046 /* Create the adjacency and add to v4 fib */
1047 memset(&adj, 0, sizeof (adj));
1048 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1050 rewrite_data = mpls_gre_rewrite (mm, tp);
1051 if (rewrite_data == 0)
1053 if (*tunnel_sw_if_index != ~0)
1055 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1056 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1057 0 /* admin down */);
1058 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
1060 pool_put (mm->gre_tunnels, tp);
1061 return VNET_API_ERROR_NO_SUCH_LABEL;
1064 /* Save a copy of the rewrite data for L2 x-connect */
1065 vec_free (tp->rewrite_data);
1067 tp->rewrite_data = rewrite_data;
1072 * source the FIB entry for the tunnel's destination
1073 * and become a child thereof. The tunnel will then get poked
1074 * when the forwarding for the entry updates, and the tunnel can
1075 * re-stack accordingly
1077 const fib_prefix_t tun_dst_pfx = {
1079 .fp_proto = FIB_PROTOCOL_IP4,
1085 tp->fei = fib_table_entry_special_add(outer_fib_index,
1088 FIB_ENTRY_FLAG_NONE,
1090 tp->sibling_index = fib_entry_child_add(tp->fei,
1091 FIB_NODE_TYPE_MPLS_GRE_TUNNEL,
1092 tp - mm->gre_tunnels);
1095 * create and update the midchain adj this tunnel sources.
1096 * This is the adj the route we add below will resolve to.
1098 tp->adj_index = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1103 adj_nbr_midchain_update_rewrite(tp->adj_index,
1104 mpls_post_rewrite_node.index,
1106 mpls_gre_tunnel_stack(tp);
1109 * Update the route for the tunnel's subnet to point through the tunnel
1111 const fib_prefix_t tun_sub_net_pfx = {
1112 .fp_len = tp->mask_width,
1113 .fp_proto = FIB_PROTOCOL_IP4,
1115 .ip4 = tp->intfc_address,
1119 fib_table_entry_update_one_path(inner_fib_index,
1121 FIB_SOURCE_INTERFACE,
1122 (FIB_ENTRY_FLAG_CONNECTED |
1123 FIB_ENTRY_FLAG_ATTACHED),
1127 ~0, // invalid fib index
1130 FIB_ROUTE_PATH_FLAG_NONE);
1137 mpls_gre_tunnel_del (ip4_address_t *src,
1139 ip4_address_t *intfc,
1141 u32 inner_fib_index,
1142 u32 outer_fib_index,
1143 u32 * tunnel_sw_if_index,
1146 mpls_main_t * mm = &mpls_main;
1147 vnet_main_t * vnm = vnet_get_main();
1148 gre_main_t * gm = &gre_main;
1149 mpls_gre_tunnel_t *tp;
1150 vnet_hw_interface_t * hi;
1152 tp = mpls_gre_tunnel_find(src,dst,intfc,inner_fib_index);
1154 /* Delete, and we can't find the tunnel */
1156 return VNET_API_ERROR_NO_SUCH_ENTRY;
1158 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1163 * unsource the FIB entry for the tunnel's destination
1165 const fib_prefix_t tun_dst_pfx = {
1167 .fp_proto = FIB_PROTOCOL_IP4,
1173 fib_entry_child_remove(tp->fei,
1175 fib_table_entry_special_remove(outer_fib_index,
1178 tp->fei = FIB_NODE_INDEX_INVALID;
1179 adj_unlock(tp->adj_index);
1182 * unsource the route for the tunnel's subnet
1184 const fib_prefix_t tun_sub_net_pfx = {
1185 .fp_len = tp->mask_width,
1186 .fp_proto = FIB_PROTOCOL_IP4,
1188 .ip4 = tp->intfc_address,
1192 fib_table_entry_delete(inner_fib_index,
1194 FIB_SOURCE_INTERFACE);
1197 u64 key = ((u64)tp->tunnel_src.as_u32 << 32 |
1198 (u64)tp->tunnel_src.as_u32);
1200 hash_unset (gm->tunnel_by_key, key);
1201 mpls_sw_interface_enable_disable(mm, hi->sw_if_index, 0);
1202 ip4_sw_interface_enable_disable(hi->sw_if_index, 0);
1204 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1205 0 /* admin down */);
1206 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
1207 vec_free (tp->rewrite_data);
1208 fib_node_deinit(&tp->mgt_node);
1209 pool_put (mm->gre_tunnels, tp);
1215 vnet_mpls_gre_add_del_tunnel (ip4_address_t *src,
1217 ip4_address_t *intfc,
1219 u32 inner_fib_id, u32 outer_fib_id,
1220 u32 * tunnel_sw_if_index,
1224 u32 inner_fib_index = 0;
1225 u32 outer_fib_index = 0;
1227 ip4_main_t * im = &ip4_main;
1229 /* No questions, no answers */
1230 if (NULL == tunnel_sw_if_index)
1231 tunnel_sw_if_index = &dummy;
1233 *tunnel_sw_if_index = ~0;
1235 if (inner_fib_id != (u32)~0)
1239 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1241 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
1242 inner_fib_index = p[0];
1245 if (outer_fib_id != 0)
1249 p = hash_get (im->fib_index_by_table_id, outer_fib_id);
1251 return VNET_API_ERROR_NO_SUCH_FIB;
1252 outer_fib_index = p[0];
1257 return (mpls_gre_tunnel_add(src,dst,intfc, mask_width,
1265 return (mpls_gre_tunnel_del(src,dst,intfc, mask_width,
1274 * Remove all mpls tunnels in the specified fib
1276 int vnet_mpls_gre_delete_fib_tunnels (u32 fib_id)
1278 mpls_main_t * mm = &mpls_main;
1279 vnet_main_t * vnm = mm->vnet_main;
1280 mpls_gre_tunnel_t *tp;
1282 u32 * tunnels_to_delete = 0;
1283 vnet_hw_interface_t * hi;
1286 fib_index = ip4_fib_index_from_table_id(fib_id);
1287 if (~0 == fib_index)
1288 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
1290 pool_foreach (tp, mm->gre_tunnels,
1292 if (tp->inner_fib_index == fib_index)
1293 vec_add1 (tunnels_to_delete, tp - mm->gre_tunnels);
1296 for (i = 0; i < vec_len(tunnels_to_delete); i++) {
1297 tp = pool_elt_at_index (mm->gre_tunnels, tunnels_to_delete[i]);
1299 /* Delete, the route if not already gone */
1300 if (FIB_NODE_INDEX_INVALID != tp->fei && !tp->l2_only)
1302 const fib_prefix_t tun_dst_pfx = {
1304 .fp_proto = FIB_PROTOCOL_IP4,
1306 .ip4 = tp->tunnel_dst,
1310 fib_entry_child_remove(tp->fei,
1312 fib_table_entry_special_remove(tp->outer_fib_index,
1315 tp->fei = FIB_NODE_INDEX_INVALID;
1316 adj_unlock(tp->adj_index);
1318 const fib_prefix_t tun_sub_net_pfx = {
1319 .fp_len = tp->mask_width,
1320 .fp_proto = FIB_PROTOCOL_IP4,
1322 .ip4 = tp->intfc_address,
1326 fib_table_entry_delete(tp->inner_fib_index,
1328 FIB_SOURCE_INTERFACE);
1331 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1332 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1333 0 /* admin down */);
1334 vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
1335 vec_free (tp->rewrite_data);
1336 pool_put (mm->gre_tunnels, tp);
1339 vec_free(tunnels_to_delete);
1344 static clib_error_t *
1345 create_mpls_gre_tunnel_command_fn (vlib_main_t * vm,
1346 unformat_input_t * input,
1347 vlib_cli_command_t * cmd)
1349 unformat_input_t _line_input, * line_input = &_line_input;
1350 ip4_address_t src, dst, intfc;
1351 int src_set = 0, dst_set = 0, intfc_set = 0;
1353 u32 inner_fib_id = (u32)~0;
1354 u32 outer_fib_id = 0;
1358 u32 tunnel_intfc_sw_if_index = ~0;
1360 /* Get a line of input. */
1361 if (! unformat_user (input, unformat_line_input, line_input))
1364 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1366 if (unformat (line_input, "src %U",
1367 unformat_ip4_address, &src))
1369 else if (unformat (line_input, "dst %U",
1370 unformat_ip4_address, &dst))
1372 else if (unformat (line_input, "intfc %U/%d",
1373 unformat_ip4_address, &intfc, &mask_width))
1375 else if (unformat (line_input, "inner-fib-id %d", &inner_fib_id))
1377 else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
1379 else if (unformat (line_input, "del"))
1381 else if (unformat (line_input, "l2-only"))
1384 return clib_error_return (0, "unknown input '%U'",
1385 format_unformat_error, line_input);
1389 return clib_error_return (0, "missing: src <ip-address>");
1392 return clib_error_return (0, "missing: dst <ip-address>");
1395 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1398 rv = vnet_mpls_gre_add_del_tunnel (&src, &dst, &intfc, mask_width,
1399 inner_fib_id, outer_fib_id,
1400 &tunnel_intfc_sw_if_index,
1407 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), tunnel_intfc_sw_if_index);
1410 case VNET_API_ERROR_NO_SUCH_INNER_FIB:
1411 return clib_error_return (0, "inner fib ID %d doesn't exist\n",
1413 case VNET_API_ERROR_NO_SUCH_FIB:
1414 return clib_error_return (0, "outer fib ID %d doesn't exist\n",
1417 case VNET_API_ERROR_NO_SUCH_ENTRY:
1418 return clib_error_return (0, "tunnel not found\n");
1420 case VNET_API_ERROR_NO_SUCH_LABEL:
1422 * This happens when there's no MPLS label for the dst address
1423 * no need for two error messages.
1428 return clib_error_return (0, "vnet_mpls_gre_add_del_tunnel returned %d",
1434 VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
1435 .path = "create mpls gre tunnel",
1437 "create mpls gre tunnel [del] src <addr> dst <addr> intfc <addr>/<mw>",
1438 .function = create_mpls_gre_tunnel_command_fn,
1441 u8 * format_mpls_encap_index (u8 * s, va_list * args)
1443 mpls_main_t * mm = va_arg (*args, mpls_main_t *);
1444 u32 entry_index = va_arg (*args, u32);
1448 e = pool_elt_at_index (mm->encaps, entry_index);
1450 for (i = 0; i < vec_len (e->labels); i++)
1452 (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
1453 (e->labels[i].label_exp_s_ttl)));
1458 u8 * format_mpls_gre_tunnel (u8 * s, va_list * args)
1460 mpls_gre_tunnel_t * t = va_arg (*args, mpls_gre_tunnel_t *);
1461 mpls_main_t * mm = &mpls_main;
1463 if (t->l2_only == 0)
1465 s = format (s, "[%d]: src %U, dst %U, adj %U/%d, labels %U\n",
1466 t - mm->gre_tunnels,
1467 format_ip4_address, &t->tunnel_src,
1468 format_ip4_address, &t->tunnel_dst,
1469 format_ip4_address, &t->intfc_address,
1471 format_mpls_encap_index, mm, t->encap_index);
1473 s = format (s, " inner fib index %d, outer fib index %d",
1474 t->inner_fib_index, t->outer_fib_index);
1478 s = format (s, "[%d]: src %U, dst %U, key %U, labels %U\n",
1479 t - mm->gre_tunnels,
1480 format_ip4_address, &t->tunnel_src,
1481 format_ip4_address, &t->tunnel_dst,
1482 format_ip4_address, &t->intfc_address,
1483 format_mpls_encap_index, mm, t->encap_index);
1485 s = format (s, " l2 interface %d, outer fib index %d",
1486 t->hw_if_index, t->outer_fib_index);
1492 u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
1494 mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
1495 mpls_main_t * mm = &mpls_main;
1497 s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
1498 t - mm->eth_tunnels,
1499 format_ethernet_address, &t->tunnel_dst,
1500 format_ip4_address, &t->intfc_address,
1502 format_mpls_encap_index, mm, t->encap_index);
1505 s = format (s, " tx on %U, rx fib index %d",
1506 format_vnet_sw_if_index_name, mm->vnet_main, t->tx_sw_if_index,
1507 t->inner_fib_index);
1512 static clib_error_t *
1513 show_mpls_tunnel_command_fn (vlib_main_t * vm,
1514 unformat_input_t * input,
1515 vlib_cli_command_t * cmd)
1517 mpls_main_t * mm = &mpls_main;
1518 mpls_gre_tunnel_t * gt;
1519 mpls_eth_tunnel_t * et;
1521 if (pool_elts (mm->gre_tunnels))
1523 vlib_cli_output (vm, "MPLS-GRE tunnels");
1524 pool_foreach (gt, mm->gre_tunnels,
1526 vlib_cli_output (vm, "%U", format_mpls_gre_tunnel, gt);
1530 vlib_cli_output (vm, "No MPLS-GRE tunnels");
1532 if (pool_elts (mm->eth_tunnels))
1534 vlib_cli_output (vm, "MPLS-Ethernet tunnels");
1535 pool_foreach (et, mm->eth_tunnels,
1537 vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
1541 vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
1546 VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
1547 .path = "show mpls tunnel",
1548 .short_help = "show mpls tunnel",
1549 .function = show_mpls_tunnel_command_fn,
1553 /* force inclusion from application's main.c */
1554 clib_error_t *mpls_interface_init (vlib_main_t *vm)
1556 clib_error_t * error;
1558 fib_node_register_type(FIB_NODE_TYPE_MPLS_GRE_TUNNEL,
1561 if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
1566 VLIB_INIT_FUNCTION(mpls_interface_init);
1569 static u8 * mpls_ethernet_rewrite (mpls_main_t *mm, mpls_eth_tunnel_t * t)
1571 u8 * rewrite_data = 0;
1573 mpls_unicast_header_t *lp0;
1576 /* look up the encap label stack using the RX FIB and adjacency address*/
1577 e = mpls_encap_by_fib_and_dest (mm, t->inner_fib_index,
1578 t->intfc_address.as_u32);
1582 clib_warning ("no label for inner fib index %d, dst %U",
1583 t->inner_fib_index, format_ip4_address,
1588 vec_validate (rewrite_data,
1589 sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
1591 /* Copy the encap label stack */
1592 lp0 = (mpls_unicast_header_t *) rewrite_data;
1594 for (i = 0; i < vec_len(e->labels); i++)
1595 lp0[i] = e->labels[i];
1597 return (rewrite_data);
1600 int vnet_mpls_ethernet_add_del_tunnel (u8 *dst,
1601 ip4_address_t *intfc,
1605 u32 * tunnel_sw_if_index,
1609 ip4_main_t * im = &ip4_main;
1610 ip_lookup_main_t * lm = &im->lookup_main;
1611 mpls_main_t * mm = &mpls_main;
1612 vnet_main_t * vnm = vnet_get_main();
1613 mpls_eth_tunnel_t *tp;
1614 u32 inner_fib_index = 0;
1618 int found_tunnel = 0;
1619 mpls_encap_t * e = 0;
1620 u32 hw_if_index = ~0;
1621 vnet_hw_interface_t * hi;
1625 if (tunnel_sw_if_index == 0)
1626 tunnel_sw_if_index = &dummy;
1628 *tunnel_sw_if_index = ~0;
1630 if (inner_fib_id != (u32)~0)
1634 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1636 return VNET_API_ERROR_NO_SUCH_FIB;
1637 inner_fib_index = p[0];
1640 /* suppress duplicate mpls interface generation. */
1641 pool_foreach (tp, mm->eth_tunnels,
1644 * If we have a tunnel which matches (src, dst, intfc/mask)
1645 * AND the expected route is in the FIB, it's a dup
1647 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1648 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1649 && tp->inner_fib_index == inner_fib_index
1650 && FIB_NODE_INDEX_INVALID != tp->fei)
1660 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
1663 return VNET_API_ERROR_NO_SUCH_LABEL;
1677 /* Delete, and we can't find the tunnel */
1678 if (is_add == 0 && found_tunnel == 0)
1679 return VNET_API_ERROR_NO_SUCH_ENTRY;
1681 e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
1683 return VNET_API_ERROR_NO_SUCH_LABEL;
1685 pool_get(mm->eth_tunnels, tp);
1686 memset (tp, 0, sizeof (*tp));
1688 if (vec_len (mm->free_eth_sw_if_indices) > 0)
1691 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1692 _vec_len (mm->free_eth_sw_if_indices) -= 1;
1693 hi = vnet_get_hw_interface (vnm, hw_if_index);
1694 hi->dev_instance = tp - mm->eth_tunnels;
1695 hi->hw_instance = tp - mm->eth_tunnels;
1699 hw_if_index = vnet_register_interface
1700 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1701 mpls_eth_hw_interface_class.index,
1702 tp - mm->eth_tunnels);
1703 hi = vnet_get_hw_interface (vnm, hw_if_index);
1705 /* ... to make the IP and L2 x-connect cases identical */
1706 slot = vlib_node_add_named_next_with_slot
1707 (vnm->vlib_main, hi->tx_node_index,
1708 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1710 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1713 *tunnel_sw_if_index = hi->sw_if_index;
1714 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1715 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1717 tp->hw_if_index = hw_if_index;
1720 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1721 tp->intfc_address.as_u32 = intfc->as_u32;
1722 tp->mask_width = mask_width;
1723 tp->inner_fib_index = inner_fib_index;
1724 tp->encap_index = e - mm->encaps;
1725 tp->tx_sw_if_index = tx_sw_if_index;
1726 tp->l2_only = l2_only;
1728 /* Create the adjacency and add to v4 fib */
1729 memset(&adj, 0, sizeof (adj));
1730 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1732 rewrite_data = mpls_ethernet_rewrite (mm, tp);
1733 if (rewrite_data == 0)
1735 if (*tunnel_sw_if_index != ~0)
1737 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1738 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1739 0 /* admin down */);
1740 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1743 pool_put (mm->eth_tunnels, tp);
1744 return VNET_API_ERROR_NO_SUCH_LABEL;
1747 vnet_rewrite_for_sw_interface
1749 VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1751 ip4_rewrite_node.index,
1753 &adj.rewrite_header,
1754 sizeof (adj.rewrite_data));
1757 * Prepend the (0,1,2) VLAN tag ethernet header
1758 * we just built to the mpls header stack
1760 vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
1761 clib_memcpy(rewrite_data,
1762 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1763 sizeof (adj.rewrite_data)),
1764 adj.rewrite_header.data_bytes);
1766 vnet_rewrite_set_data_internal (&adj.rewrite_header,
1767 sizeof(adj.rewrite_data),
1769 vec_len(rewrite_data));
1771 vec_free (tp->rewrite_data);
1773 tp->rewrite_data = rewrite_data;
1776 ip_add_adjacency (lm, &adj, 1 /* one adj */,
1783 const fib_prefix_t pfx = {
1785 .ip4 = tp->intfc_address,
1787 .fp_len = tp->mask_width,
1788 .fp_proto = FIB_PROTOCOL_IP4,
1791 tp->fei = fib_table_entry_special_add(tp->inner_fib_index,
1794 FIB_ENTRY_FLAG_NONE,
1798 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
1799 tp->fei = FIB_NODE_INDEX_INVALID;
1802 if (is_add == 0 && found_tunnel)
1804 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1805 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1806 0 /* admin down */);
1807 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1808 vec_free (tp->rewrite_data);
1809 pool_put (mm->eth_tunnels, tp);
1815 static clib_error_t *
1816 create_mpls_ethernet_tunnel_command_fn (vlib_main_t * vm,
1817 unformat_input_t * input,
1818 vlib_cli_command_t * cmd)
1820 unformat_input_t _line_input, * line_input = &_line_input;
1821 vnet_main_t * vnm = vnet_get_main();
1822 ip4_address_t intfc;
1825 int dst_set = 0, intfc_set = 0;
1827 u32 inner_fib_id = (u32)~0;
1832 u32 sw_if_index = ~0;
1834 /* Get a line of input. */
1835 if (! unformat_user (input, unformat_line_input, line_input))
1838 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1840 if (unformat (line_input, "dst %U",
1841 unformat_ethernet_address, &dst))
1843 else if (unformat (line_input, "adj %U/%d",
1844 unformat_ip4_address, &intfc, &mask_width))
1846 else if (unformat (line_input, "tx-intfc %U",
1847 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1849 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1851 else if (unformat (line_input, "l2-only"))
1853 else if (unformat (line_input, "del"))
1856 return clib_error_return (0, "unknown input '%U'",
1857 format_unformat_error, line_input);
1861 return clib_error_return (0, "missing tx-intfc");
1864 return clib_error_return (0, "missing: dst <ethernet-address>");
1867 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1870 rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
1871 inner_fib_id, tx_sw_if_index,
1879 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
1881 case VNET_API_ERROR_NO_SUCH_FIB:
1882 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1885 case VNET_API_ERROR_NO_SUCH_ENTRY:
1886 return clib_error_return (0, "tunnel not found\n");
1888 case VNET_API_ERROR_NO_SUCH_LABEL:
1890 * This happens when there's no MPLS label for the dst address
1891 * no need for two error messages.
1893 return clib_error_return (0, "no label for %U in fib %d",
1894 format_ip4_address, &intfc, inner_fib_id);
1898 return clib_error_return (0, "vnet_mpls_ethernet_add_del_tunnel returned %d", rv);
1905 VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
1906 .path = "create mpls ethernet tunnel",
1908 "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
1909 .function = create_mpls_ethernet_tunnel_command_fn,
1913 int vnet_mpls_policy_tunnel_add_rewrite (mpls_main_t * mm,
1915 u32 policy_tunnel_index)
1917 mpls_eth_tunnel_t * t;
1919 u8 * rewrite_data = 0;
1921 mpls_unicast_header_t *lp;
1924 if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
1925 return VNET_API_ERROR_NO_SUCH_ENTRY;
1927 t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
1929 memset (&adj, 0, sizeof (adj));
1931 /* Build L2 encap */
1932 vnet_rewrite_for_sw_interface
1934 VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1936 mpls_policy_encap_node.index,
1938 &adj.rewrite_header,
1939 sizeof (adj.rewrite_data));
1941 vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
1943 clib_memcpy(rewrite_data,
1944 vnet_rewrite_get_data_internal(&adj.rewrite_header,
1945 sizeof (adj.rewrite_data)),
1946 adj.rewrite_header.data_bytes);
1948 /* Append the label stack */
1950 vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
1952 lp = (mpls_unicast_header_t *) label_start;
1954 for (i = 0; i < vec_len(e->labels); i++)
1955 lp[i] = e->labels[i];
1957 /* Remember the rewrite data */
1958 e->rewrite = rewrite_data;
1959 e->output_next_index = adj.rewrite_header.next_index;
1964 int vnet_mpls_ethernet_add_del_policy_tunnel (u8 *dst,
1965 ip4_address_t *intfc,
1969 u32 * tunnel_sw_if_index,
1970 u32 classify_table_index,
1971 u32 * new_tunnel_index,
1975 ip4_main_t * im = &ip4_main;
1976 mpls_main_t * mm = &mpls_main;
1977 vnet_main_t * vnm = vnet_get_main();
1978 mpls_eth_tunnel_t *tp;
1979 u32 inner_fib_index = 0;
1980 int found_tunnel = 0;
1981 mpls_encap_t * e = 0;
1982 u32 hw_if_index = ~0;
1983 vnet_hw_interface_t * hi;
1987 if (tunnel_sw_if_index == 0)
1988 tunnel_sw_if_index = &dummy;
1990 *tunnel_sw_if_index = ~0;
1992 if (inner_fib_id != (u32)~0)
1996 p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1998 return VNET_API_ERROR_NO_SUCH_FIB;
1999 inner_fib_index = p[0];
2002 /* suppress duplicate mpls interface generation. */
2003 pool_foreach (tp, mm->eth_tunnels,
2006 * If we have a tunnel which matches (src, dst, intfc/mask)
2007 * AND the expected route is in the FIB, it's a dup
2009 if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
2010 && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
2011 && tp->inner_fib_index == inner_fib_index
2012 && FIB_NODE_INDEX_INVALID != tp->fei)
2034 /* Delete, and we can't find the tunnel */
2035 if (is_add == 0 && found_tunnel == 0)
2036 return VNET_API_ERROR_NO_SUCH_ENTRY;
2038 pool_get(mm->eth_tunnels, tp);
2039 memset (tp, 0, sizeof (*tp));
2041 if (vec_len (mm->free_eth_sw_if_indices) > 0)
2044 mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
2045 _vec_len (mm->free_eth_sw_if_indices) -= 1;
2046 hi = vnet_get_hw_interface (vnm, hw_if_index);
2047 hi->dev_instance = tp - mm->eth_tunnels;
2048 hi->hw_instance = tp - mm->eth_tunnels;
2052 hw_if_index = vnet_register_interface
2053 (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
2054 mpls_eth_hw_interface_class.index,
2055 tp - mm->eth_tunnels);
2056 hi = vnet_get_hw_interface (vnm, hw_if_index);
2058 /* ... to make the IP and L2 x-connect cases identical */
2059 slot = vlib_node_add_named_next_with_slot
2060 (vnm->vlib_main, hi->tx_node_index,
2061 "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
2063 ASSERT (slot == MPLS_ETH_OUTPUT_NEXT_OUTPUT);
2066 *tunnel_sw_if_index = hi->sw_if_index;
2067 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
2068 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
2070 tp->hw_if_index = hw_if_index;
2073 clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
2074 tp->intfc_address.as_u32 = intfc->as_u32;
2075 tp->mask_width = mask_width;
2076 tp->inner_fib_index = inner_fib_index;
2077 tp->encap_index = e - mm->encaps;
2078 tp->tx_sw_if_index = tx_sw_if_index;
2079 tp->l2_only = l2_only;
2080 tp->fei = FIB_NODE_INDEX_INVALID;
2082 if (new_tunnel_index)
2083 *new_tunnel_index = tp - mm->eth_tunnels;
2089 const fib_prefix_t pfx = {
2091 .ip4 = tp->intfc_address,
2093 .fp_len = tp->mask_width,
2094 .fp_proto = FIB_PROTOCOL_IP4,
2096 dpo_id_t dpo = DPO_NULL;
2103 classify_dpo_create(FIB_PROTOCOL_IP4,
2104 classify_table_index));
2106 tp->fei = fib_table_entry_special_dpo_add(tp->inner_fib_index,
2109 FIB_ENTRY_FLAG_EXCLUSIVE,
2115 fib_table_entry_delete(tp->inner_fib_index, &pfx, FIB_SOURCE_API);
2116 tp->fei = FIB_NODE_INDEX_INVALID;
2119 if (is_add == 0 && found_tunnel)
2121 hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
2122 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
2123 0 /* admin down */);
2124 vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
2125 pool_put (mm->eth_tunnels, tp);
2131 static clib_error_t *
2132 create_mpls_ethernet_policy_tunnel_command_fn (vlib_main_t * vm,
2133 unformat_input_t * input,
2134 vlib_cli_command_t * cmd)
2136 unformat_input_t _line_input, * line_input = &_line_input;
2137 vnet_main_t * vnm = vnet_get_main();
2138 ip4_address_t intfc;
2141 int dst_set = 0, intfc_set = 0;
2143 u32 inner_fib_id = (u32)~0;
2144 u32 classify_table_index = (u32)~0;
2145 u32 new_tunnel_index;
2151 /* Get a line of input. */
2152 if (! unformat_user (input, unformat_line_input, line_input))
2155 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2157 if (unformat (line_input, "dst %U",
2158 unformat_ethernet_address, &dst))
2160 else if (unformat (line_input, "adj %U/%d",
2161 unformat_ip4_address, &intfc, &mask_width))
2163 else if (unformat (line_input, "tx-intfc %U",
2164 unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
2166 else if (unformat (line_input, "classify-table-index %d",
2167 &classify_table_index))
2169 else if (unformat (line_input, "fib-id %d", &inner_fib_id))
2171 else if (unformat (line_input, "l2-only"))
2173 else if (unformat (line_input, "del"))
2176 return clib_error_return (0, "unknown input '%U'",
2177 format_unformat_error, line_input);
2180 if (classify_table_index == ~0)
2181 return clib_error_return (0, "missing classify_table_index");
2184 return clib_error_return (0, "missing tx-intfc");
2187 return clib_error_return (0, "missing: dst <ethernet-address>");
2190 return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
2193 rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
2194 inner_fib_id, tx_sw_if_index,
2195 0 /* tunnel sw_if_index */,
2196 classify_table_index,
2203 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), new_tunnel_index);
2205 case VNET_API_ERROR_NO_SUCH_FIB:
2206 return clib_error_return (0, "rx fib ID %d doesn't exist\n",
2209 case VNET_API_ERROR_NO_SUCH_ENTRY:
2210 return clib_error_return (0, "tunnel not found\n");
2212 case VNET_API_ERROR_NO_SUCH_LABEL:
2214 * This happens when there's no MPLS label for the dst address
2215 * no need for two error messages.
2217 return clib_error_return (0, "no label for %U in fib %d",
2218 format_ip4_address, &intfc, inner_fib_id);
2222 return clib_error_return (0, "vnet_mpls_ethernet_add_del_policy_tunnel returned %d", rv);
2229 VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
2230 .path = "create mpls ethernet policy tunnel",
2232 "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
2233 " classify-table-index <nn>",
2234 .function = create_mpls_ethernet_policy_tunnel_command_fn,
2237 static clib_error_t *
2238 mpls_interface_enable_disable (vlib_main_t * vm,
2239 unformat_input_t * input,
2240 vlib_cli_command_t * cmd)
2242 vnet_main_t * vnm = vnet_get_main();
2243 clib_error_t * error = 0;
2244 u32 sw_if_index, enable;
2248 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
2250 error = clib_error_return (0, "unknown interface `%U'",
2251 format_unformat_error, input);
2255 if (unformat (input, "enable"))
2257 else if (unformat (input, "disable"))
2261 error = clib_error_return (0, "expected 'enable' or 'disable'",
2262 format_unformat_error, input);
2266 mpls_sw_interface_enable_disable(&mpls_main, sw_if_index, enable);
2272 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
2273 .path = "set interface mpls",
2274 .function = mpls_interface_enable_disable,
2275 .short_help = "Enable/Disable an interface for MPLS forwarding",