A Protocol Independent Hierarchical FIB (VPP-352)
[vpp.git] / vnet / vnet / mpls / mpls.c
similarity index 74%
rename from vnet/vnet/mpls-gre/mpls.c
rename to vnet/vnet/mpls/mpls.c
index d914b4c..be5e882 100644 (file)
  */
 
 #include <vnet/vnet.h>
-#include <vnet/mpls-gre/mpls.h>
+#include <vnet/mpls/mpls.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/mpls_fib.h>
+
+const static char* mpls_eos_bit_names[] = MPLS_EOS_BITS;
 
 mpls_main_t mpls_main;
 
+u8 * format_mpls_unicast_label (u8 * s, va_list * args)
+{
+  mpls_label_t label = va_arg (*args, mpls_label_t);
+
+  switch (label) {
+  case MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL:
+      s = format (s, "%s", MPLS_IETF_IPV4_EXPLICIT_NULL_STRING);
+      break;
+  case MPLS_IETF_ROUTER_ALERT_LABEL:
+      s = format (s, "%s", MPLS_IETF_ROUTER_ALERT_STRING);
+      break;
+  case MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL:
+      s = format (s, "%s", MPLS_IETF_IPV6_EXPLICIT_NULL_STRING);
+      break;
+  case MPLS_IETF_IMPLICIT_NULL_LABEL:
+      s = format (s, "%s", MPLS_IETF_IMPLICIT_NULL_STRING);
+      break;
+  case MPLS_IETF_ELI_LABEL:
+      s = format (s, "%s", MPLS_IETF_ELI_STRING);
+      break;
+  case MPLS_IETF_GAL_LABEL:
+      s = format (s, "%s", MPLS_IETF_GAL_STRING);
+      break;
+  default:
+      s = format (s, "%d", label);
+      break;
+  }
+  return s;
+}
+
+uword unformat_mpls_unicast_label (unformat_input_t * input, va_list * args)
+{
+  mpls_label_t *label = va_arg (*args, mpls_label_t*);
+  
+  if (unformat (input, MPLS_IETF_IPV4_EXPLICIT_NULL_STRING))
+      *label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
+  else if (unformat (input, MPLS_IETF_IPV6_EXPLICIT_NULL_STRING))
+      *label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
+  else if (unformat (input, MPLS_IETF_ROUTER_ALERT_STRING))
+      *label = MPLS_IETF_ROUTER_ALERT_LABEL;
+  else if (unformat (input, MPLS_IETF_IMPLICIT_NULL_STRING))
+      *label = MPLS_IETF_IMPLICIT_NULL_LABEL;
+  else if (unformat (input, "%d", label))
+      ;
+
+  return (1);
+}
+
+u8 * format_mpls_eos_bit (u8 * s, va_list * args)
+{
+  mpls_eos_bit_t eb = va_arg (*args, mpls_eos_bit_t);
+
+  ASSERT(eb <= MPLS_EOS);
+
+  s = format(s, "%s", mpls_eos_bit_names[eb]);
+
+  return (s);
+}
+
+u8 * format_mpls_header (u8 * s, va_list * args)
+{
+  mpls_unicast_header_t hdr = va_arg (*args, mpls_unicast_header_t);
+
+  return (format(s, "[%U:%d:%d:%U]",
+                format_mpls_unicast_label, 
+                vnet_mpls_uc_get_label(hdr.label_exp_s_ttl),
+                vnet_mpls_uc_get_ttl(hdr.label_exp_s_ttl),
+                vnet_mpls_uc_get_exp(hdr.label_exp_s_ttl),
+                format_mpls_eos_bit,
+                vnet_mpls_uc_get_s(hdr.label_exp_s_ttl)));
+}
+
 u8 * format_mpls_gre_tx_trace (u8 * s, va_list * args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
@@ -203,8 +279,9 @@ int vnet_mpls_add_del_encap (ip4_address_t *dest, u32 fib_id,
           
           /* Reformat label into mpls_unicast_header_t */
           label_host_byte_order <<= 12;
-          if (i == vec_len(labels_host_byte_order) - 1)
-            label_host_byte_order |= 1<<8;            /* S=1 */
+         // FIXME NEOS AND EOS
+          //if (i == vec_len(labels_host_byte_order) - 1)
+          //  label_host_byte_order |= 1<<8;            /* S=1 */
           label_host_byte_order |= 0xff;            /* TTL=FF */
           label_net_byte_order = clib_host_to_net_u32 (label_host_byte_order);
           h.label_exp_s_ttl = label_net_byte_order;
@@ -385,7 +462,7 @@ int vnet_mpls_add_del_decap (u32 rx_fib_id,
   rx_fib_index = p[0];
 
   /* L3 decap => transform fib ID to fib index */
-  if (next_index == MPLS_INPUT_NEXT_IP4_INPUT)
+  if (next_index == MPLS_LOOKUP_NEXT_IP4_INPUT)
     {
       p = hash_get (im->fib_index_by_table_id, tx_fib_id);
       if (! p)
@@ -437,12 +514,12 @@ unformat_mpls_gre_input_next (unformat_input_t * input, va_list * args)
 
   if (unformat (input, "lookup"))
     {
-      *result = MPLS_INPUT_NEXT_IP4_INPUT;
+      *result = MPLS_LOOKUP_NEXT_IP4_INPUT;
       rv = 1;
     }
   else if (unformat (input, "output"))
     {
-      *result = MPLS_INPUT_NEXT_L2_OUTPUT;
+      *result = MPLS_LOOKUP_NEXT_L2_OUTPUT;
       rv = 1;
     }
   return rv;
@@ -614,10 +691,7 @@ show_mpls_fib_command_fn (vlib_main_t * vm,
   show_mpls_fib_t *records = 0;
   show_mpls_fib_t *s;
   mpls_main_t * mm = &mpls_main;
-  ip4_main_t * im = &ip4_main;
-  ip4_fib_t * rx_fib, * tx_fib;
-  u32 tx_table_id;
-  char *swif_tag;
+  ip4_fib_t * rx_fib;
 
   hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest, 
   ({
@@ -630,7 +704,6 @@ show_mpls_fib_command_fn (vlib_main_t * vm,
   if (!vec_len(records))
     {
       vlib_cli_output (vm, "MPLS encap table empty");
-      goto decap_table;
     }
   /* sort output by dst address within fib */
   vec_sort_with_function (records, mpls_dest_cmp);
@@ -639,65 +712,174 @@ show_mpls_fib_command_fn (vlib_main_t * vm,
   vlib_cli_output (vm, "%=6s%=16s%=16s", "Table", "Dest address", "Labels");
   vec_foreach (s, records)
     {
-      rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
+      rx_fib = ip4_fib_get (s->fib_index);
       vlib_cli_output (vm, "%=6d%=16U%=16U", rx_fib->table_id, 
                        format_ip4_address, &s->dest,
                        format_mpls_encap_index, mm, s->entry_index);
     }
 
- decap_table:
-  vec_reset_length(records);
+  vec_free(records);
+  return 0;
+}
 
-  hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label, 
-  ({
-    vec_add2 (records, s, 1);
-    s->fib_index = (u32)(key>>32);
-    s->entry_index = (u32) value;
-    s->label = ((u32) key)>>12;
-    s->s_bit = (key & (1<<8)) != 0;
-  }));
-  
-  if (!vec_len(records))
-    {
-      vlib_cli_output (vm, "MPLS decap table empty");
-      goto out;
-    }
+VLIB_CLI_COMMAND (show_mpls_fib_command, static) = {
+    .path = "show mpls encap",
+    .short_help = "show mpls encap",
+    .function = show_mpls_fib_command_fn,
+};
 
-  vec_sort_with_function (records, mpls_label_cmp);
+static clib_error_t *
+vnet_mpls_local_label (vlib_main_t * vm,
+                       unformat_input_t * input,
+                       vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, * line_input = &_line_input;
+  fib_route_path_t *rpaths = NULL, rpath;
+  clib_error_t * error = 0;
+  u32 table_id, is_del, is_ip;
+  fib_prefix_t pfx;
+  mpls_label_t local_label;
+  mpls_eos_bit_t eos;
+
+  is_ip = 0;
+  table_id = 0;
+  eos = MPLS_EOS;
+
+   /* Get a line of input. */
+  if (! unformat_user (input, unformat_line_input, line_input))
+    return 0;
 
-  vlib_cli_output (vm, "MPLS decap table");
-  vlib_cli_output (vm, "%=10s%=15s%=6s%=6s", "RX Table", "TX Table/Intfc", 
-                   "Label", "S-bit");
-  vec_foreach (s, records)
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-      mpls_decap_t * d;
-      d = pool_elt_at_index (mm->decaps, s->entry_index);
-      if (d->next_index == MPLS_INPUT_NEXT_IP4_INPUT)
-        {
-          tx_fib = vec_elt_at_index (im->fibs, d->tx_fib_index);
-          tx_table_id = tx_fib->table_id;
-          swif_tag = "     ";
-        }
+      memset(&rpath, 0, sizeof(rpath));
+      memset(&pfx, 0, sizeof(pfx));
+
+      if (unformat (line_input, "table %d", &table_id))
+       ;
+      else if (unformat (line_input, "del"))
+       is_del = 1;
+      else if (unformat (line_input, "add"))
+       is_del = 0;
+      else if (unformat (line_input, "eos"))
+       eos = MPLS_EOS;
+      else if (unformat (line_input, "non-eos"))
+       eos = MPLS_NON_EOS;
+      else if (unformat (line_input, "%U/%d",
+                        unformat_ip4_address,
+                        &pfx.fp_addr.ip4,
+                        &pfx.fp_len))
+      {
+         pfx.fp_proto = FIB_PROTOCOL_IP4;
+          is_ip = 1;
+      }
+      else if (unformat (line_input, "%U/%d",
+                        unformat_ip6_address,
+                        &pfx.fp_addr.ip6,
+                        &pfx.fp_len))
+      {
+         pfx.fp_proto = FIB_PROTOCOL_IP6;
+          is_ip = 1;
+      }
+      else if (unformat (line_input, "%d", &local_label))
+       ;
+      else if (unformat (line_input,
+                        "ip4-lookup-in-table %d",
+                        &rpath.frp_fib_index))
+      {
+         rpath.frp_label = MPLS_LABEL_INVALID;
+          rpath.frp_proto = FIB_PROTOCOL_IP4;
+          rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
+         vec_add1(rpaths, rpath);
+      }
+      else if (unformat (line_input,
+                        "ip6-lookup-in-table %d",
+                        &rpath.frp_fib_index))
+      {
+         rpath.frp_label = MPLS_LABEL_INVALID;
+          rpath.frp_proto = FIB_PROTOCOL_IP6;
+          rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
+         vec_add1(rpaths, rpath);
+      }
+      else if (unformat (line_input,
+                        "mpls-lookup-in-table %d",
+                        &rpath.frp_fib_index))
+      {
+         rpath.frp_label = MPLS_LABEL_INVALID;
+          rpath.frp_proto = FIB_PROTOCOL_IP4;
+          rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
+         vec_add1(rpaths, rpath);
+      }
       else
-        {
-          tx_table_id = d->tx_fib_index;
-          swif_tag = "(i)  ";
-        }
-      rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
+      {
+          error = clib_error_return (0, "unkown input: %U",
+                                     format_unformat_error, input);
+          goto done;
+      }
 
-      vlib_cli_output (vm, "%=10d%=10d%=5s%=6d%=6d", rx_fib->table_id, 
-                       tx_table_id, swif_tag, s->label, s->s_bit);
     }
 
- out:
-  vec_free(records);
-  return 0;
+  if (is_ip)
+  {
+      u32 fib_index = fib_table_find(pfx.fp_proto, table_id);
+
+      if (FIB_NODE_INDEX_INVALID == fib_index)
+      {
+          error = clib_error_return (0, "%U table-id %d does not exist",
+                                     format_fib_protocol, pfx.fp_proto, table_id);
+          goto done;
+      }
+
+      if (is_del)
+      {
+          fib_table_entry_local_label_remove(fib_index, &pfx, local_label);
+      }
+      else
+      {
+          fib_table_entry_local_label_add(fib_index, &pfx, local_label);
+      }
+  }
+  else
+  {
+      fib_node_index_t lfe, fib_index;
+      fib_prefix_t prefix = {
+         .fp_proto = FIB_PROTOCOL_MPLS,
+         .fp_label = local_label,
+         .fp_eos = eos,
+      };
+
+      fib_index = mpls_fib_index_from_table_id(table_id);
+
+      if (FIB_NODE_INDEX_INVALID == fib_index)
+      {
+          error = clib_error_return (0, "MPLS table-id %d does not exist",
+                                     table_id);
+          goto done;
+      }
+
+      lfe = fib_table_entry_path_add2(fib_index,
+                                     &prefix,
+                                     FIB_SOURCE_CLI,
+                                     FIB_ENTRY_FLAG_NONE,
+                                     rpaths);
+
+      if (FIB_NODE_INDEX_INVALID == lfe)
+      {
+          error = clib_error_return (0, "Failed to create %U-%U in MPLS table-id %d",
+                                     format_mpls_unicast_label, local_label,
+                                     format_mpls_eos_bit, eos,
+                                     table_id);
+          goto done;
+      }
+  }
+
+done:
+  return error;
 }
 
-VLIB_CLI_COMMAND (show_mpls_fib_command, static) = {
-    .path = "show mpls fib",
-    .short_help = "show mpls fib",
-    .function = show_mpls_fib_command_fn,
+VLIB_CLI_COMMAND (mpls_local_label_command, static) = {
+  .path = "mpls local-label",
+  .function = vnet_mpls_local_label,
+  .short_help = "Create/Delete MPL local labels",
 };
 
 int mpls_fib_reset_labels (u32 fib_id)
@@ -764,7 +946,6 @@ static clib_error_t * mpls_init (vlib_main_t * vm)
   mpls_main_t * mm = &mpls_main;
   clib_error_t * error;
 
-  memset (mm, 0, sizeof (mm[0]));
   mm->vlib_main = vm;
   mm->vnet_main = vnet_get_main();