FIB: encode the label stack in the FIB path during table dump
[vpp.git] / src / vnet / fib / fib_path_ext.c
index 08293bc..209b627 100644 (file)
@@ -24,6 +24,9 @@
 #include <vnet/fib/fib_path_list.h>
 #include <vnet/fib/fib_internal.h>
 
+const char *fib_path_ext_adj_flags_names[] = FIB_PATH_EXT_ADJ_ATTR_NAMES;
+const char *fib_path_ext_mpls_flags_names[] = FIB_PATH_EXT_MPLS_ATTR_NAMES;
+
 u8 *
 format_fib_path_ext (u8 * s, va_list * args)
 {
@@ -32,13 +35,52 @@ format_fib_path_ext (u8 * s, va_list * args)
 
     path_ext = va_arg (*args, fib_path_ext_t *);
 
-    s = format(s, "path:%d labels:",
-              path_ext->fpe_path_index);
-    for (ii = 0; ii < vec_len(path_ext->fpe_path.frp_label_stack); ii++)
+    s = format(s, "path:%d ", path_ext->fpe_path_index);
+
+    switch (path_ext->fpe_type)
     {
-       s = format(s, "%U ",
-                  format_mpls_unicast_label,
-                  path_ext->fpe_path.frp_label_stack[ii]);
+    case FIB_PATH_EXT_MPLS: {
+        fib_path_ext_mpls_attr_t attr;
+
+        if (path_ext->fpe_mpls_flags)
+        {
+            s = format(s, "mpls-flags:[");
+
+            FOR_EACH_PATH_EXT_MPLS_ATTR(attr)
+            {
+                if ((1<<attr) & path_ext->fpe_mpls_flags) {
+                    s = format(s, "%s", fib_path_ext_mpls_flags_names[attr]);
+                }
+            }
+            s = format(s, "]");
+        }
+        s = format(s, " labels:[");
+        for (ii = 0; ii < vec_len(path_ext->fpe_path.frp_label_stack); ii++)
+        {
+            s = format(s, "[%U]",
+                       format_fib_mpls_label,
+                       &path_ext->fpe_path.frp_label_stack[ii]);
+        }
+        s = format(s, "]");
+        break;
+    }
+    case FIB_PATH_EXT_ADJ: {
+        fib_path_ext_adj_attr_t attr;
+
+        if (path_ext->fpe_adj_flags)
+        {
+            s = format(s, "adj-flags:[");
+            FOR_EACH_PATH_EXT_ADJ_ATTR(attr)
+            {
+                if ((1<<attr) & path_ext->fpe_adj_flags)
+                {
+                    s = format(s, "%s", fib_path_ext_adj_flags_names[attr]);
+                }
+            }
+            s = format(s, "]");
+        }
+        break;
+    }
     }
     return (s);
 }
@@ -50,7 +92,7 @@ fib_path_ext_cmp (fib_path_ext_t *path_ext,
     return (fib_route_path_cmp(&path_ext->fpe_path, rpath));
 }
 
-static int
+static fib_path_list_walk_rc_t
 fib_path_ext_match (fib_node_index_t pl_index,
                    fib_node_index_t path_index,
                    void *ctx)
@@ -61,10 +103,9 @@ fib_path_ext_match (fib_node_index_t pl_index,
                                   &path_ext->fpe_path))
     {
        path_ext->fpe_path_index = path_index;
-       return (0);
+       return (FIB_PATH_LIST_WALK_STOP);
     }
-    // keep going
-    return (1);
+    return (FIB_PATH_LIST_WALK_CONTINUE);
 }
 
 void
@@ -80,25 +121,44 @@ fib_path_ext_resolve (fib_path_ext_t *path_ext,
                       path_ext);
 }
 
-void
+static void
 fib_path_ext_init (fib_path_ext_t *path_ext,
                   fib_node_index_t path_list_index,
+                   fib_path_ext_type_t ext_type,
                   const fib_route_path_t *rpath)
 {
     path_ext->fpe_path = *rpath;
     path_ext->fpe_path_index = FIB_NODE_INDEX_INVALID;
+    path_ext->fpe_adj_flags = FIB_PATH_EXT_ADJ_FLAG_NONE;
+    path_ext->fpe_type = ext_type;
 
     fib_path_ext_resolve(path_ext, path_list_index);
 }
 
 /**
  * @brief Return true if the label stack is implicit null
+ * imp-null and pop equate to the same this as this level -
+ * the label is coming off.
  */
 static int
 fib_path_ext_is_imp_null (fib_path_ext_t *path_ext)
 {
     return ((1 == vec_len(path_ext->fpe_label_stack)) &&
-           (MPLS_IETF_IMPLICIT_NULL_LABEL == path_ext->fpe_label_stack[0]));
+           ((MPLS_IETF_IMPLICIT_NULL_LABEL == path_ext->fpe_label_stack[0].fml_value) ||
+             (MPLS_LABEL_POP == path_ext->fpe_label_stack[0].fml_value)));
+}
+
+mpls_label_dpo_flags_t
+fib_path_ext_mpls_flags_to_mpls_label (fib_path_ext_mpls_flags_t fpe_flags)
+{
+    mpls_label_dpo_flags_t ml_flags = MPLS_LABEL_DPO_FLAG_NONE;
+
+    if (fpe_flags &FIB_PATH_EXT_MPLS_FLAG_NO_IP_TTL_DECR)
+    {
+        ml_flags |= MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
+    }
+
+    return (ml_flags);
 }
 
 load_balance_path_t *
@@ -163,6 +223,9 @@ fib_path_ext_stack (fib_path_ext_t *path_ext,
     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
         parent_fct = child_fct;
        break;
+    case FIB_FORW_CHAIN_TYPE_ETHERNET:
+        parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
+       break;
     default:
         return (nhs);
        break;
@@ -205,27 +268,217 @@ fib_path_ext_stack (fib_path_ext_t *path_ext,
              * we pickup the correct MPLS imposition nodes to do
              * ip[46] processing.
              */
+            dpo_id_t parent = DPO_INVALID;
             dpo_proto_t chain_proto;
             mpls_eos_bit_t eos;
-            index_t mldi;
 
             eos = (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS ?
                    MPLS_NON_EOS :
                    MPLS_EOS);
             chain_proto = fib_forw_chain_type_to_dpo_proto(child_fct);
 
-            mldi = mpls_label_dpo_create(path_ext->fpe_label_stack,
-                                         eos, 255, 0,
-                                         chain_proto,
-                                         &nh->path_dpo);
+            dpo_copy(&parent, &nh->path_dpo);
+            mpls_label_dpo_create(path_ext->fpe_label_stack,
+                                  eos,
+                                  chain_proto,
+                                  fib_path_ext_mpls_flags_to_mpls_label(
+                                      path_ext->fpe_mpls_flags),
+                                  &parent,
+                                  &nh->path_dpo);
 
-           dpo_set(&nh->path_dpo,
-                   DPO_MPLS_LABEL,
-                    chain_proto,
-                    mldi);
+           dpo_reset(&parent);
        }
+        else if (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_EOS)
+        {
+            /*
+             * MPLS EOS packets using an imp-null. Insert the disposition.
+             */
+            fib_path_stack_mpls_disp(nh->path_index,
+                                     fib_forw_chain_type_to_dpo_proto(parent_fct),
+                                     path_ext->fpe_label_stack[0].fml_mode,
+                                     &nh->path_dpo);
+        }
     }
     dpo_reset(&via_dpo);
 
     return (nhs);
 }
+
+fib_path_ext_t *
+fib_path_ext_list_find (const fib_path_ext_list_t *list,
+                        fib_path_ext_type_t ext_type,
+                        const fib_route_path_t *rpath)
+{
+    fib_path_ext_t *path_ext;
+
+    vec_foreach(path_ext, list->fpel_exts)
+    {
+        if ((path_ext->fpe_type == ext_type) &&
+            !fib_path_ext_cmp(path_ext, rpath) )
+        {
+            return (path_ext);
+        }
+    }
+    return (NULL);
+}
+
+fib_path_ext_t *
+fib_path_ext_list_find_by_path_index (const fib_path_ext_list_t *list,
+                                      fib_node_index_t path_index)
+{
+    fib_path_ext_t *path_ext;
+
+    if (NULL != list)
+    {
+        vec_foreach(path_ext, list->fpel_exts)
+        {
+            if (path_ext->fpe_path_index == path_index)
+            {
+                return (path_ext);
+            }
+        }
+    }
+    return (NULL);
+}
+
+
+fib_path_ext_t *
+fib_path_ext_list_push_back (fib_path_ext_list_t *list,
+                             fib_node_index_t path_list_index,
+                             fib_path_ext_type_t ext_type,
+                             const fib_route_path_t *rpath)
+{
+    fib_path_ext_t *path_ext;
+
+    path_ext = fib_path_ext_list_find(list, ext_type, rpath);
+
+    if (NULL == path_ext)
+    {
+        vec_add2(list->fpel_exts, path_ext, 1);
+        fib_path_ext_init(path_ext, path_list_index, ext_type, rpath);
+    }
+
+    return (path_ext);
+}
+
+/*
+ * insert, sorted, a path extension to the entry's list.
+ * It's not strictly necessary to sort the path extensions, since each
+ * extension has the path index to which it resolves. However, by being
+ * sorted the load-balance produced has a deterministic order, not an order
+ * based on the sequence of extension additions. this is a considerable benefit.
+ */
+fib_path_ext_t *
+fib_path_ext_list_insert (fib_path_ext_list_t *list,
+                          fib_node_index_t path_list_index,
+                          fib_path_ext_type_t ext_type,
+                          const fib_route_path_t *rpath)
+{
+    fib_path_ext_t new_path_ext, *path_ext;
+    int i = 0;
+
+    if (0 == fib_path_ext_list_length(list))
+    {
+        return (fib_path_ext_list_push_back(list, path_list_index,
+                                            ext_type, rpath));
+    }
+
+    fib_path_ext_init(&new_path_ext, path_list_index, ext_type, rpath);
+
+    vec_foreach(path_ext, list->fpel_exts)
+    {
+        int res = fib_path_ext_cmp(path_ext, rpath);
+
+        if (0 == res)
+        {
+            /*
+             * don't add duplicate extensions. modify instead
+             */
+            vec_free(path_ext->fpe_label_stack);
+            *path_ext = new_path_ext;
+            goto done;
+        }
+        else if (res < 0)
+        {
+            i++;
+        }
+        else
+        {
+            break;
+        }
+    }
+    vec_insert_elts(list->fpel_exts, &new_path_ext, 1, i);
+done:
+    return (&(list->fpel_exts[i]));
+}
+
+void
+fib_path_ext_list_resolve (fib_path_ext_list_t *list,
+                           fib_node_index_t path_list_index)
+{
+    fib_path_ext_t *path_ext;
+
+    vec_foreach(path_ext, list->fpel_exts)
+    {
+        fib_path_ext_resolve(path_ext, path_list_index);
+    };
+}
+
+void
+fib_path_ext_list_remove (fib_path_ext_list_t *list,
+                          fib_path_ext_type_t ext_type,
+                          const fib_route_path_t *rpath)
+{
+    fib_path_ext_t *path_ext;
+
+    path_ext = fib_path_ext_list_find(list, ext_type, rpath);
+
+    if (NULL != path_ext)
+    {
+        /*
+         * delete the element moving the remaining elements down 1 position.
+         * this preserves the sorted order.
+         */
+        vec_free(path_ext->fpe_label_stack);
+        vec_delete(list->fpel_exts, 1, (path_ext - list->fpel_exts));
+    }
+}
+
+void
+fib_path_ext_list_flush (fib_path_ext_list_t *list)
+{
+    fib_path_ext_t *path_ext;
+
+    vec_foreach(path_ext, list->fpel_exts)
+    {
+        vec_free(path_ext->fpe_label_stack);
+    };
+    vec_free(list->fpel_exts);
+    list->fpel_exts = NULL;
+}
+
+u8*
+format_fib_path_ext_list (u8 * s, va_list * args)
+{
+    fib_path_ext_list_t *list;
+    fib_path_ext_t *path_ext;
+
+    list = va_arg (*args, fib_path_ext_list_t *);
+
+    if (fib_path_ext_list_length(list))
+    {
+        s = format(s, "    Extensions:");
+        vec_foreach(path_ext, list->fpel_exts)
+        {
+            s = format(s, "\n     %U", format_fib_path_ext, path_ext);
+        };
+    }
+
+    return (s);
+}
+
+int
+fib_path_ext_list_length (const fib_path_ext_list_t *list)
+{
+    return (vec_len(list->fpel_exts));
+}