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/mpls-gre/mpls.h>
21 mpls_main_t mpls_main;
23 u8 * format_mpls_gre_tx_trace (u8 * s, va_list * args)
25 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
26 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
27 mpls_gre_tx_trace_t * t = va_arg (*args, mpls_gre_tx_trace_t *);
28 mpls_main_t * mm = &mpls_main;
31 s = format (s, "MPLS: lookup miss");
34 s = format (s, "MPLS: tunnel %d labels %U len %d src %U dst %U",
36 format_mpls_encap_index, mm, t->mpls_encap_index,
37 clib_net_to_host_u16 (t->length),
38 format_ip4_address, &t->src.as_u8,
39 format_ip4_address, &t->dst.as_u8);
44 u8 * format_mpls_eth_tx_trace (u8 * s, va_list * args)
46 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
47 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
48 mpls_eth_tx_trace_t * t = va_arg (*args, mpls_eth_tx_trace_t *);
49 mpls_main_t * mm = &mpls_main;
52 s = format (s, "MPLS: lookup miss");
55 s = format (s, "MPLS: tunnel %d labels %U len %d tx_sw_index %d dst %U",
57 format_mpls_encap_index, mm, t->mpls_encap_index,
58 clib_net_to_host_u16 (t->length),
60 format_ethernet_address, t->dst);
65 u8 * format_mpls_eth_header_with_length (u8 * s, va_list * args)
67 ethernet_header_t * h = va_arg (*args, ethernet_header_t *);
68 mpls_unicast_header_t * m = (mpls_unicast_header_t *)(h+1);
69 u32 max_header_bytes = va_arg (*args, u32);
72 header_bytes = sizeof (h[0]);
73 if (max_header_bytes != 0 && header_bytes > max_header_bytes)
74 return format (s, "ethernet header truncated");
77 (s, "ETHERNET-MPLS label %d",
78 vnet_mpls_uc_get_label (clib_net_to_host_u32 (m->label_exp_s_ttl)));
83 u8 * format_mpls_gre_header_with_length (u8 * s, va_list * args)
85 gre_header_t * h = va_arg (*args, gre_header_t *);
86 mpls_unicast_header_t * m = (mpls_unicast_header_t *)(h+1);
87 u32 max_header_bytes = va_arg (*args, u32);
90 header_bytes = sizeof (h[0]);
91 if (max_header_bytes != 0 && header_bytes > max_header_bytes)
92 return format (s, "gre header truncated");
95 (s, "GRE-MPLS label %d",
96 vnet_mpls_uc_get_label (clib_net_to_host_u32 (m->label_exp_s_ttl)));
101 u8 * format_mpls_gre_header (u8 * s, va_list * args)
103 gre_header_t * h = va_arg (*args, gre_header_t *);
104 return format (s, "%U", format_mpls_gre_header_with_length, h, 0);
108 unformat_mpls_gre_header (unformat_input_t * input, va_list * args)
110 u8 ** result = va_arg (*args, u8 **);
111 gre_header_t _g, * g = &_g;
112 mpls_unicast_header_t _h, * h = &_h;
113 u32 label, label_exp_s_ttl;
115 if (! unformat (input, "MPLS %d", &label))
118 g->protocol = clib_host_to_net_u16 (GRE_PROTOCOL_mpls_unicast);
120 label_exp_s_ttl = (label<<12) | (1<<8) /* s-bit */ | 0xFF;
121 h->label_exp_s_ttl = clib_host_to_net_u32 (label_exp_s_ttl);
123 /* Add gre, mpls headers to result. */
126 u32 g_n_bytes = sizeof (g[0]);
127 u32 h_n_bytes = sizeof (h[0]);
129 vec_add2 (*result, p, g_n_bytes);
130 clib_memcpy (p, g, g_n_bytes);
132 vec_add2 (*result, p, h_n_bytes);
133 clib_memcpy (p, h, h_n_bytes);
140 unformat_mpls_label_net_byte_order (unformat_input_t * input,
143 u32 * result = va_arg (*args, u32 *);
146 if (!unformat (input, "MPLS: label %d", &label))
149 label = (label<<12) | (1<<8) /* s-bit set */ | 0xFF /* ttl */;
151 *result = clib_host_to_net_u32 (label);
156 mpls_encap_by_fib_and_dest (mpls_main_t * mm, u32 rx_fib, u32 dst_address)
162 key = ((u64)rx_fib<<32) | ((u64) dst_address);
163 p = hash_get (mm->mpls_encap_by_fib_and_dest, key);
168 e = pool_elt_at_index (mm->encaps, p[0]);
172 int vnet_mpls_add_del_encap (ip4_address_t *dest, u32 fib_id,
173 u32 *labels_host_byte_order,
174 u32 policy_tunnel_index,
175 int no_dst_hash, u32 * indexp, int is_add)
177 mpls_main_t * mm = &mpls_main;
178 ip4_main_t * im = &ip4_main;
180 u32 label_net_byte_order, label_host_byte_order;
186 p = hash_get (im->fib_index_by_table_id, fib_id);
188 return VNET_API_ERROR_NO_SUCH_FIB;
192 key = ((u64)fib_index<<32) | ((u64) dest->as_u32);
196 pool_get (mm->encaps, e);
197 memset (e, 0, sizeof (*e));
199 for (i = 0; i < vec_len (labels_host_byte_order); i++)
201 mpls_unicast_header_t h;
202 label_host_byte_order = labels_host_byte_order[i];
204 /* Reformat label into mpls_unicast_header_t */
205 label_host_byte_order <<= 12;
206 if (i == vec_len(labels_host_byte_order) - 1)
207 label_host_byte_order |= 1<<8; /* S=1 */
208 label_host_byte_order |= 0xff; /* TTL=FF */
209 label_net_byte_order = clib_host_to_net_u32 (label_host_byte_order);
210 h.label_exp_s_ttl = label_net_byte_order;
211 vec_add1 (e->labels, h);
213 if (no_dst_hash == 0)
214 hash_set (mm->mpls_encap_by_fib_and_dest, key, e - mm->encaps);
216 *indexp = e - mm->encaps;
217 if (policy_tunnel_index != ~0)
218 return vnet_mpls_policy_tunnel_add_rewrite (mm, e, policy_tunnel_index);
222 p = hash_get (mm->mpls_encap_by_fib_and_dest, key);
224 return VNET_API_ERROR_NO_SUCH_LABEL;
226 e = pool_elt_at_index (mm->encaps, p[0]);
228 vec_free (e->labels);
229 vec_free (e->rewrite);
230 pool_put(mm->encaps, e);
232 if (no_dst_hash == 0)
233 hash_unset (mm->mpls_encap_by_fib_and_dest, key);
238 static clib_error_t *
239 mpls_add_encap_command_fn (vlib_main_t * vm,
240 unformat_input_t * input,
241 vlib_cli_command_t * cmd)
247 u32 policy_tunnel_index = ~0;
253 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
255 if (unformat (input, "fib %d", &fib_id))
257 else if (unformat (input, "dest %U", unformat_ip4_address, &dest))
259 else if (unformat (input, "no-dst-hash"))
261 else if (unformat (input, "label %d", &this_label))
262 vec_add1 (labels, this_label);
263 else if (unformat (input, "policy-tunnel %d", &policy_tunnel_index))
270 return clib_error_return (0, "fib-id missing");
272 return clib_error_return (0, "destination IP address missing");
273 if (vec_len (labels) == 0)
274 return clib_error_return (0, "label stack missing");
276 rv = vnet_mpls_add_del_encap (&dest, fib_id, labels,
278 no_dst_hash, 0 /* indexp */,
287 case VNET_API_ERROR_NO_SUCH_FIB:
288 return clib_error_return (0, "fib id %d unknown", fib_id);
291 return clib_error_return (0, "vnet_mpls_add_del_encap returned %d",
298 VLIB_CLI_COMMAND (mpls_add_encap_command, static) = {
299 .path = "mpls encap add",
301 "mpls encap add label <label> ... fib <id> dest <ip4-address>",
302 .function = mpls_add_encap_command_fn,
305 u8 * format_mpls_unicast_header_host_byte_order (u8 * s, va_list * args)
307 mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
308 u32 label = h->label_exp_s_ttl;
310 s = format (s, "label %d exp %d, s %d, ttl %d",
311 vnet_mpls_uc_get_label (label),
312 vnet_mpls_uc_get_exp (label),
313 vnet_mpls_uc_get_s (label),
314 vnet_mpls_uc_get_ttl (label));
318 u8 * format_mpls_unicast_header_net_byte_order (u8 * s, va_list * args)
320 mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
321 mpls_unicast_header_t h_host;
323 h_host.label_exp_s_ttl = clib_net_to_host_u32 (h->label_exp_s_ttl);
325 return format (s, "%U", format_mpls_unicast_header_host_byte_order,
329 static clib_error_t *
330 mpls_del_encap_command_fn (vlib_main_t * vm,
331 unformat_input_t * input,
332 vlib_cli_command_t * cmd)
338 if (unformat (input, "fib %d dest %U", &fib_id,
339 unformat_ip4_address, &dest))
341 rv = vnet_mpls_add_del_encap (&dest, fib_id, 0 /* labels */,
342 ~0 /* policy_tunnel_index */,
348 case VNET_API_ERROR_NO_SUCH_FIB:
349 return clib_error_return (0, "fib id %d unknown", fib_id);
350 case VNET_API_ERROR_NO_SUCH_ENTRY:
351 return clib_error_return (0, "dest %U not in fib %d",
352 format_ip4_address, &dest, fib_id);
359 return clib_error_return (0, "unknown input `%U'",
360 format_unformat_error, input);
363 VLIB_CLI_COMMAND (mpls_del_encap_command, static) = {
364 .path = "mpls encap delete",
365 .short_help = "mpls encap delete fib <id> dest <ip4-address>",
366 .function = mpls_del_encap_command_fn,
369 int vnet_mpls_add_del_decap (u32 rx_fib_id,
371 u32 label_host_byte_order,
372 int s_bit, int next_index, int is_add)
374 mpls_main_t * mm = &mpls_main;
375 ip4_main_t * im = &ip4_main;
377 u32 rx_fib_index, tx_fib_index_or_output_swif_index;
381 p = hash_get (im->fib_index_by_table_id, rx_fib_id);
383 return VNET_API_ERROR_NO_SUCH_FIB;
387 /* L3 decap => transform fib ID to fib index */
388 if (next_index == MPLS_INPUT_NEXT_IP4_INPUT)
390 p = hash_get (im->fib_index_by_table_id, tx_fib_id);
392 return VNET_API_ERROR_NO_SUCH_INNER_FIB;
394 tx_fib_index_or_output_swif_index = p[0];
398 /* L2 decap, tx_fib_id is actually the output sw_if_index */
399 tx_fib_index_or_output_swif_index = tx_fib_id;
402 key = ((u64)rx_fib_index<<32) | ((u64) (label_host_byte_order<<12))
405 p = hash_get (mm->mpls_decap_by_rx_fib_and_label, key);
407 /* If deleting, or replacing an old entry */
408 if (is_add == 0 || p)
410 if (is_add == 0 && p == 0)
411 return VNET_API_ERROR_NO_SUCH_LABEL;
413 d = pool_elt_at_index (mm->decaps, p[0]);
414 hash_unset (mm->mpls_decap_by_rx_fib_and_label, key);
415 pool_put (mm->decaps, d);
416 /* Deleting, we're done... */
421 /* add decap entry... */
422 pool_get (mm->decaps, d);
423 memset (d, 0, sizeof (*d));
424 d->tx_fib_index = tx_fib_index_or_output_swif_index;
425 d->next_index = next_index;
427 hash_set (mm->mpls_decap_by_rx_fib_and_label, key, d - mm->decaps);
433 unformat_mpls_gre_input_next (unformat_input_t * input, va_list * args)
435 u32 * result = va_arg (*args, u32 *);
438 if (unformat (input, "lookup"))
440 *result = MPLS_INPUT_NEXT_IP4_INPUT;
443 else if (unformat (input, "output"))
445 *result = MPLS_INPUT_NEXT_L2_OUTPUT;
451 static clib_error_t *
452 mpls_add_decap_command_fn (vlib_main_t * vm,
453 unformat_input_t * input,
454 vlib_cli_command_t * cmd)
456 vnet_main_t * vnm = vnet_get_main();
458 u32 tx_fib_or_sw_if_index;
461 u32 next_index = 1; /* ip4_lookup, see node.c */
462 int tx_fib_id_set = 0;
466 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
468 if (unformat (input, "fib %d", &tx_fib_or_sw_if_index))
470 else if (unformat (input, "sw_if_index %d", &tx_fib_or_sw_if_index))
472 else if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
473 &tx_fib_or_sw_if_index))
475 else if (unformat (input, "rx-fib %d", &rx_fib_id))
477 else if (unformat (input, "label %d", &label))
479 else if (unformat (input, "s-bit-clear"))
481 else if (unformat (input, "next %U", unformat_mpls_gre_input_next,
488 if (tx_fib_id_set == 0)
489 return clib_error_return (0, "lookup FIB ID not set");
491 return clib_error_return (0, "missing label");
493 rv = vnet_mpls_add_del_decap (rx_fib_id, tx_fib_or_sw_if_index,
494 label, s_bit, next_index, 1 /* is_add */);
500 case VNET_API_ERROR_NO_SUCH_FIB:
501 return clib_error_return (0, "no such rx fib id %d", rx_fib_id);
503 case VNET_API_ERROR_NO_SUCH_INNER_FIB:
504 return clib_error_return (0, "no such tx fib / swif %d",
505 tx_fib_or_sw_if_index);
508 return clib_error_return (0, "vnet_mpls_add_del_decap returned %d",
514 VLIB_CLI_COMMAND (mpls_add_decap_command, static) = {
515 .path = "mpls decap add",
517 "mpls decap add fib <id> label <nn> [s-bit-clear] [next-index <nn>]",
518 .function = mpls_add_decap_command_fn,
521 static clib_error_t *
522 mpls_del_decap_command_fn (vlib_main_t * vm,
523 unformat_input_t * input,
524 vlib_cli_command_t * cmd)
533 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
535 if (unformat (input, "rx-fib %d", &rx_fib_id))
537 else if (unformat (input, "label %d", &label))
539 else if (unformat (input, "s-bit-clear"))
544 return clib_error_return (0, "label not set");
546 rv = vnet_mpls_add_del_decap (rx_fib_id,
547 tx_fib_id /* not interesting */,
549 0 /* next_index not interesting */,
556 case VNET_API_ERROR_NO_SUCH_FIB:
557 return clib_error_return (0, "no such rx fib id %d", rx_fib_id);
559 case VNET_API_ERROR_NO_SUCH_INNER_FIB:
560 return clib_error_return (0, "no such lookup fib id %d", tx_fib_id);
562 case VNET_API_ERROR_NO_SUCH_LABEL:
563 return clib_error_return (0, "no such label %d rx fib id %d",
567 return clib_error_return (0, "vnet_mpls_add_del_decap returned %d",
574 VLIB_CLI_COMMAND (mpls_del_decap_command, static) = {
575 .path = "mpls decap delete",
576 .short_help = "mpls decap delete label <label> rx-fib <id> [s-bit-clear]",
577 .function = mpls_del_decap_command_fn,
589 mpls_dest_cmp(void * a1, void * a2)
591 show_mpls_fib_t * r1 = a1;
592 show_mpls_fib_t * r2 = a2;
594 return clib_net_to_host_u32(r1->dest) - clib_net_to_host_u32(r2->dest);
598 mpls_fib_index_cmp(void * a1, void * a2)
600 show_mpls_fib_t * r1 = a1;
601 show_mpls_fib_t * r2 = a2;
603 return r1->fib_index - r2->fib_index;
607 mpls_label_cmp(void * a1, void * a2)
609 show_mpls_fib_t * r1 = a1;
610 show_mpls_fib_t * r2 = a2;
612 return r1->label - r2->label;
615 static clib_error_t *
616 show_mpls_fib_command_fn (vlib_main_t * vm,
617 unformat_input_t * input,
618 vlib_cli_command_t * cmd)
622 show_mpls_fib_t *records = 0;
624 mpls_main_t * mm = &mpls_main;
625 ip4_main_t * im = &ip4_main;
626 ip4_fib_t * rx_fib, * tx_fib;
630 hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest,
632 vec_add2 (records, s, 1);
633 s->fib_index = (u32)(key>>32);
634 s->dest = (u32)(key & 0xFFFFFFFF);
635 s->entry_index = (u32) value;
638 if (!vec_len(records))
640 vlib_cli_output (vm, "MPLS encap table empty");
643 /* sort output by dst address within fib */
644 vec_sort_with_function (records, mpls_dest_cmp);
645 vec_sort_with_function (records, mpls_fib_index_cmp);
646 vlib_cli_output (vm, "MPLS encap table");
647 vlib_cli_output (vm, "%=6s%=16s%=16s", "Table", "Dest address", "Labels");
648 vec_foreach (s, records)
650 rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
651 vlib_cli_output (vm, "%=6d%=16U%=16U", rx_fib->table_id,
652 format_ip4_address, &s->dest,
653 format_mpls_encap_index, mm, s->entry_index);
657 vec_reset_length(records);
659 hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label,
661 vec_add2 (records, s, 1);
662 s->fib_index = (u32)(key>>32);
663 s->entry_index = (u32) value;
664 s->label = ((u32) key)>>12;
665 s->s_bit = (key & (1<<8)) != 0;
668 if (!vec_len(records))
670 vlib_cli_output (vm, "MPLS decap table empty");
674 vec_sort_with_function (records, mpls_label_cmp);
676 vlib_cli_output (vm, "MPLS decap table");
677 vlib_cli_output (vm, "%=10s%=15s%=6s%=6s", "RX Table", "TX Table/Intfc",
679 vec_foreach (s, records)
682 d = pool_elt_at_index (mm->decaps, s->entry_index);
683 if (d->next_index == MPLS_INPUT_NEXT_IP4_INPUT)
685 tx_fib = vec_elt_at_index (im->fibs, d->tx_fib_index);
686 tx_table_id = tx_fib->table_id;
691 tx_table_id = d->tx_fib_index;
694 rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
696 vlib_cli_output (vm, "%=10d%=10d%=5s%=6d%=6d", rx_fib->table_id,
697 tx_table_id, swif_tag, s->label, s->s_bit);
705 VLIB_CLI_COMMAND (show_mpls_fib_command, static) = {
706 .path = "show mpls fib",
707 .short_help = "show mpls fib",
708 .function = show_mpls_fib_command_fn,
711 int mpls_fib_reset_labels (u32 fib_id)
715 show_mpls_fib_t *records = 0;
717 mpls_main_t * mm = &mpls_main;
718 ip4_main_t * im = &ip4_main;
722 p = hash_get (im->fib_index_by_table_id, fib_id);
724 return VNET_API_ERROR_NO_SUCH_FIB;
728 hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest,
730 if (fib_index == (u32)(key>>32)) {
731 vec_add2 (records, s, 1);
732 s->dest = (u32)(key & 0xFFFFFFFF);
733 s->entry_index = (u32) value;
737 vec_foreach (s, records)
739 key = ((u64)fib_index<<32) | ((u64) s->dest);
740 hash_unset (mm->mpls_encap_by_fib_and_dest, key);
741 pool_put_index (mm->encaps, s->entry_index);
744 vec_reset_length(records);
746 hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label,
748 if (fib_index == (u32) (key>>32)) {
749 vec_add2 (records, s, 1);
750 s->entry_index = value;
751 s->fib_index = fib_index;
752 s->s_bit = key & (1<<8);
753 s->dest = (u32)((key & 0xFFFFFFFF)>>12);
757 vec_foreach (s, records)
759 key = ((u64)fib_index <<32) | ((u64)(s->dest<<12)) |
762 hash_unset (mm->mpls_decap_by_rx_fib_and_label, key);
763 pool_put_index (mm->decaps, s->entry_index);
770 static clib_error_t * mpls_init (vlib_main_t * vm)
772 mpls_main_t * mm = &mpls_main;
773 clib_error_t * error;
775 memset (mm, 0, sizeof (mm[0]));
777 mm->vnet_main = vnet_get_main();
779 if ((error = vlib_call_init_function (vm, ip_main_init)))
782 mm->mpls_encap_by_fib_and_dest = hash_create (0, sizeof (uword));
783 mm->mpls_decap_by_rx_fib_and_label = hash_create (0, sizeof (uword));
785 return vlib_call_init_function (vm, mpls_input_init);
788 VLIB_INIT_FUNCTION (mpls_init);
790 mpls_main_t * mpls_get_main (vlib_main_t * vm)
792 vlib_call_init_function (vm, mpls_init);