A Protocol Independent Hierarchical FIB (VPP-352)
[vpp.git] / vnet / vnet / classify / vnet_classify.c
index 7f7138a..7716fc9 100644 (file)
@@ -16,7 +16,9 @@
 #include <vnet/classify/input_acl.h>
 #include <vnet/ip/ip.h>
 #include <vnet/api_errno.h>     /* for API error numbers */
-#include <vnet/l2/l2_classify.h> /* for L2_CLASSIFY_NEXT_xxx */
+#include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */
+
+vnet_classify_main_t vnet_classify_main;
 
 #if VALIDATION_SCAFFOLDING
 /* Validation scaffolding */
@@ -64,6 +66,43 @@ void mv (vnet_classify_table_t * t) { }
 void rogue (vnet_classify_table_t * t) { }
 #endif
 
+void vnet_classify_register_unformat_l2_next_index_fn (unformat_function_t * fn)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+
+  vec_add1 (cm->unformat_l2_next_index_fns, fn);
+}
+
+void vnet_classify_register_unformat_ip_next_index_fn (unformat_function_t * fn)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+
+  vec_add1 (cm->unformat_ip_next_index_fns, fn);
+}
+
+void 
+vnet_classify_register_unformat_acl_next_index_fn (unformat_function_t * fn)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+
+  vec_add1 (cm->unformat_acl_next_index_fns, fn);
+}
+
+void
+vnet_classify_register_unformat_policer_next_index_fn (unformat_function_t * fn)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+
+  vec_add1 (cm->unformat_policer_next_index_fns, fn);
+}
+
+void vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+
+  vec_add1 (cm->unformat_opaque_index_fns, fn);
+}
+
 vnet_classify_table_t * 
 vnet_classify_new_table (vnet_classify_main_t *cm,
                          u8 * mask, u32 nbuckets, u32 memory_size,
@@ -79,7 +118,7 @@ vnet_classify_new_table (vnet_classify_main_t *cm,
   memset(t, 0, sizeof (*t));
   
   vec_validate_aligned (t->mask, match_n_vectors - 1, sizeof(u32x4));
-  memcpy (t->mask, mask, match_n_vectors * sizeof (u32x4));
+  clib_memcpy (t->mask, mask, match_n_vectors * sizeof (u32x4));
 
   t->next_table_index = ~0;
   t->nbuckets = nbuckets;
@@ -261,7 +300,7 @@ static inline void make_working_copy
     {
 #define _(size)                                         \
     case size:                                          \
-      memcpy (working_copy, v,                          \
+      clib_memcpy (working_copy, v,                          \
               sizeof (vnet_classify_entry_##size##_t)   \
               * (1<<b->log2_pages)                      \
               * (t->entries_per_page));                 \
@@ -317,7 +356,7 @@ split_and_rehash (vnet_classify_table_t * t,
                   
                   if (vnet_classify_entry_is_free (new_v))
                     {
-                      memcpy (new_v, v, sizeof (vnet_classify_entry_t) 
+                      clib_memcpy (new_v, v, sizeof (vnet_classify_entry_t) 
                               + (t->match_n_vectors * sizeof (u32x4)));
                       new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
                       goto doublebreak;
@@ -374,7 +413,7 @@ int vnet_classify_add_del (vnet_classify_table_t * t,
         }
 
       v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */);
-      memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
+      clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
               t->match_n_vectors * sizeof (u32x4));
       v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
 
@@ -405,7 +444,7 @@ int vnet_classify_add_del (vnet_classify_table_t * t,
 
           if (!memcmp (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
             {
-              memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
+              clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
                       t->match_n_vectors * sizeof(u32x4));
               v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
 
@@ -421,7 +460,7 @@ int vnet_classify_add_del (vnet_classify_table_t * t,
 
           if (vnet_classify_entry_is_free (v))
             {
-              memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
+              clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
                       t->match_n_vectors * sizeof(u32x4));
               v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
               CLIB_MEMORY_BARRIER();
@@ -482,7 +521,7 @@ int vnet_classify_add_del (vnet_classify_table_t * t,
 
       if (vnet_classify_entry_is_free (new_v))
         {
-          memcpy (new_v, add_v, sizeof (vnet_classify_entry_t) +
+          clib_memcpy (new_v, add_v, sizeof (vnet_classify_entry_t) +
                   t->match_n_vectors * sizeof(u32x4));
           new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
           goto expand_ok;
@@ -941,8 +980,11 @@ uword unformat_classify_mask (unformat_input_t * input, va_list * args)
           if (l2 == 0)
             vec_validate (l2, 13);
           mask = l2;
-          vec_append (mask, l3);
-          vec_free (l3);
+          if (l3)
+            {
+              vec_append (mask, l3);
+              vec_free (l3);
+            }
         }
 
       /* Scan forward looking for the first significant mask octet */
@@ -981,22 +1023,73 @@ uword unformat_classify_mask (unformat_input_t * input, va_list * args)
   return 0;
 }
 
-#define foreach_l2_next                         \
+#define foreach_l2_input_next                   \
 _(drop, DROP)                                   \
 _(ethernet, ETHERNET_INPUT)                     \
 _(ip4, IP4_INPUT)                               \
 _(ip6, IP6_INPUT)                              \
 _(li, LI)
 
-uword unformat_l2_next_index (unformat_input_t * input, va_list * args)
+uword unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
 {
+  vnet_classify_main_t * cm = &vnet_classify_main;
   u32 * miss_next_indexp = va_arg (*args, u32 *);
   u32 next_index = 0;
   u32 tmp;
+  int i;
   
+  /* First try registered unformat fns, allowing override... */
+  for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
+    {
+      if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
+        {
+          next_index = tmp;
+          goto out;
+        }
+    }
+
 #define _(n,N) \
-  if (unformat (input, #n)) { next_index = L2_CLASSIFY_NEXT_##N; goto out;}
-  foreach_l2_next;
+  if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
+  foreach_l2_input_next;
+#undef _
+  
+  if (unformat (input, "%d", &tmp))
+    { 
+      next_index = tmp; 
+      goto out; 
+    }
+  
+  return 0;
+
+ out:
+  *miss_next_indexp = next_index;
+  return 1;
+}
+
+#define foreach_l2_output_next                   \
+_(drop, DROP)
+
+uword unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+  u32 * miss_next_indexp = va_arg (*args, u32 *);
+  u32 next_index = 0;
+  u32 tmp;
+  int i;
+  
+  /* First try registered unformat fns, allowing override... */
+  for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
+    {
+      if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
+        {
+          next_index = tmp;
+          goto out;
+        }
+    }
+
+#define _(n,N) \
+  if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
+  foreach_l2_output_next;
 #undef _
   
   if (unformat (input, "%d", &tmp))
@@ -1013,17 +1106,27 @@ uword unformat_l2_next_index (unformat_input_t * input, va_list * args)
 }
 
 #define foreach_ip_next                         \
-_(miss, MISS)                                   \
 _(drop, DROP)                                   \
-_(local, LOCAL)                                 \
 _(rewrite, REWRITE)
 
 uword unformat_ip_next_index (unformat_input_t * input, va_list * args)
 {
   u32 * miss_next_indexp = va_arg (*args, u32 *);
+  vnet_classify_main_t * cm = &vnet_classify_main;
   u32 next_index = 0;
   u32 tmp;
+  int i;
   
+  /* First try registered unformat fns, allowing override... */
+  for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
+    {
+      if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
+        {
+          next_index = tmp;
+          goto out;
+        }
+    }
+
 #define _(n,N) \
   if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
   foreach_ip_next;
@@ -1047,9 +1150,21 @@ _(deny, DENY)
 
 uword unformat_acl_next_index (unformat_input_t * input, va_list * args)
 {
-  u32 * miss_next_indexp = va_arg (*args, u32 *);
+  u32 * next_indexp = va_arg (*args, u32 *);
+  vnet_classify_main_t * cm = &vnet_classify_main;
   u32 next_index = 0;
   u32 tmp;
+  int i;
+
+  /* First try registered unformat fns, allowing override... */
+  for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
+    {
+      if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
+        {
+          next_index = tmp;
+          goto out;
+        }
+    }
 
 #define _(n,N) \
   if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
@@ -1070,7 +1185,38 @@ uword unformat_acl_next_index (unformat_input_t * input, va_list * args)
   return 0;
 
  out:
-  *miss_next_indexp = next_index;
+  *next_indexp = next_index;
+  return 1;
+}
+
+uword unformat_policer_next_index (unformat_input_t * input, va_list * args)
+{
+  u32 * next_indexp = va_arg (*args, u32 *);
+  vnet_classify_main_t * cm = &vnet_classify_main;
+  u32 next_index = 0;
+  u32 tmp;
+  int i;
+
+  /* First try registered unformat fns, allowing override... */
+  for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
+    {
+      if (unformat (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
+        {
+          next_index = tmp;
+          goto out;
+        }
+    }
+
+  if (unformat (input, "%d", &tmp))
+    {
+      next_index = tmp;
+      goto out;
+    }
+
+  return 0;
+
+ out:
+  *next_indexp = next_index;
   return 1;
 }
 
@@ -1116,7 +1262,10 @@ classify_table_command_fn (vlib_main_t * vm,
     else if (unformat (input, "miss-next %U", unformat_ip_next_index,
                        &miss_next_index))
       ;
-    else if (unformat (input, "l2-miss-next %U", unformat_l2_next_index,
+    else if (unformat (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
+                       &miss_next_index))
+        ;
+    else if (unformat (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
                        &miss_next_index))
       ;
     else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
@@ -1397,10 +1546,10 @@ uword unformat_ip6_match (unformat_input_t * input, va_list * args)
   ip = (ip6_header_t *) match;
   
   if (src)
-    memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
+    clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
 
   if (dst)
-    memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
+    clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
   
   if (proto)
     ip->protocol = proto_val;
@@ -1517,10 +1666,10 @@ uword unformat_l2_match (unformat_input_t * input, va_list * args)
   vec_validate_aligned (match, len-1, sizeof(u32x4));
 
   if (dst)
-    memcpy (match, dst_val, 6);
+    clib_memcpy (match, dst_val, 6);
 
   if (src)
-    memcpy (match + 6, src_val, 6);
+    clib_memcpy (match + 6, src_val, 6);
   
   if (tag2)
     {
@@ -1609,8 +1758,11 @@ uword unformat_classify_match (unformat_input_t * input, va_list * args)
           if (l2 == 0)
             vec_validate_aligned (l2, 13, sizeof(u32x4));
           match = l2;
-          vec_append_aligned (match, l3, sizeof(u32x4));
-          vec_free (l3);
+          if (l3)
+            {
+              vec_append_aligned (match, l3, sizeof(u32x4));
+              vec_free (l3);
+            }
         }
 
       /* Make sure the vector is big enough even if key is all 0's */
@@ -1656,7 +1808,7 @@ int vnet_classify_add_del_session (vnet_classify_main_t * cm,
   e->flags = 0;
 
   /* Copy key data, honoring skip_n_vectors */
-  memcpy (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
+  clib_memcpy (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
           t->match_n_vectors * sizeof (u32x4));
 
   /* Clear don't-care bits; likely when dynamically creating sessions */
@@ -1678,10 +1830,10 @@ classify_session_command_fn (vlib_main_t * vm,
   int is_add = 1;
   u32 table_index = ~0;
   u32 hit_next_index = ~0;
-  u32 opaque_index = ~0;
+  u64 opaque_index = ~0;
   u8 * match = 0;
   i32 advance = 0;
-  int rv;
+  int i, rv;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) 
     {
@@ -1690,13 +1842,19 @@ classify_session_command_fn (vlib_main_t * vm,
       else if (unformat (input, "hit-next %U", unformat_ip_next_index,
                          &hit_next_index))
         ;
-      else if (unformat (input, "l2-hit-next %U", unformat_l2_next_index,
+      else if (unformat (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
+                         &hit_next_index))
+        ;
+      else if (unformat (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
                          &hit_next_index))
         ;
       else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
                          &hit_next_index))
         ;
-      else if (unformat (input, "opaque-index %d", &opaque_index))
+      else if (unformat (input, "policer-hit-next %U",
+                         unformat_policer_next_index, &hit_next_index))
+        ;
+      else if (unformat (input, "opaque-index %lld", &opaque_index))
         ;
       else if (unformat (input, "match %U", unformat_classify_match,
                          cm, &match, table_index))
@@ -1706,7 +1864,18 @@ classify_session_command_fn (vlib_main_t * vm,
       else if (unformat (input, "table-index %d", &table_index))
         ;
       else
-        break;
+        {
+          /* Try registered opaque-index unformat fns */
+          for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
+            {
+              if (unformat (input, "%U", cm->unformat_opaque_index_fns[i], 
+                            &opaque_index))
+                goto found_opaque;
+            }
+          break;
+        }
+    found_opaque:
+      ;
     }
 
   if (table_index == ~0)
@@ -1735,11 +1904,144 @@ classify_session_command_fn (vlib_main_t * vm,
 VLIB_CLI_COMMAND (classify_session_command, static) = {
     .path = "classify session",
     .short_help = 
-    "classify session [hit-next|l2-hit-next|acl-hit-next <next_index>]"
+    "classify session [hit-next|l2-hit-next|acl-hit-next <next_index>|"
+    "policer-hit-next <policer_name>]"
     "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]",
     .function = classify_session_command_fn,
 };
 
+static uword 
+unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
+{
+  u64 * opaquep = va_arg (*args, u64 *);
+  u32 sw_if_index;
+
+  if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
+                vnet_get_main(), &sw_if_index))
+    {
+      *opaquep = sw_if_index;
+      return 1;
+    }
+  return 0;
+}
+
+static uword 
+unformat_ip_next_node (unformat_input_t * input, va_list * args)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+  u32 * next_indexp = va_arg (*args, u32 *);
+  u32 node_index;
+  u32 next_index, rv;
+
+  if (unformat (input, "node %U", unformat_vlib_node,
+                cm->vlib_main, &node_index))
+    {
+      rv = next_index = vlib_node_add_next 
+        (cm->vlib_main, ip4_classify_node.index, node_index);
+      next_index = vlib_node_add_next 
+        (cm->vlib_main, ip6_classify_node.index, node_index);
+      ASSERT(rv == next_index);
+
+      *next_indexp = next_index;
+      return 1;
+    }
+  return 0;
+}
+
+static uword 
+unformat_acl_next_node (unformat_input_t * input, va_list * args)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+  u32 * next_indexp = va_arg (*args, u32 *);
+  u32 node_index;
+  u32 next_index, rv;
+
+  if (unformat (input, "node %U", unformat_vlib_node,
+                cm->vlib_main, &node_index))
+    {
+      rv = next_index = vlib_node_add_next 
+        (cm->vlib_main, ip4_inacl_node.index, node_index);
+      next_index = vlib_node_add_next 
+        (cm->vlib_main, ip6_inacl_node.index, node_index);
+      ASSERT(rv == next_index);
+
+      *next_indexp = next_index;
+      return 1;
+    }
+  return 0;
+}
+
+static uword 
+unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+  u32 * next_indexp = va_arg (*args, u32 *);
+  u32 node_index;
+  u32 next_index;
+
+  if (unformat (input, "input-node %U", unformat_vlib_node,
+                cm->vlib_main, &node_index))
+    {
+      next_index = vlib_node_add_next 
+        (cm->vlib_main, l2_input_classify_node.index, node_index);
+
+      *next_indexp = next_index;
+      return 1;
+    }
+  return 0;
+}
+
+static uword 
+unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+  u32 * next_indexp = va_arg (*args, u32 *);
+  u32 node_index;
+  u32 next_index;
+
+  if (unformat (input, "output-node %U", unformat_vlib_node,
+                cm->vlib_main, &node_index))
+    {
+      next_index = vlib_node_add_next 
+        (cm->vlib_main, l2_output_classify_node.index, node_index);
+
+      *next_indexp = next_index;
+      return 1;
+    }
+  return 0;
+}
+
+static clib_error_t * 
+vnet_classify_init (vlib_main_t * vm)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+
+  cm->vlib_main = vm;
+  cm->vnet_main = vnet_get_main();
+
+  vnet_classify_register_unformat_opaque_index_fn 
+    (unformat_opaque_sw_if_index);
+
+  vnet_classify_register_unformat_ip_next_index_fn
+    (unformat_ip_next_node);
+
+  vnet_classify_register_unformat_l2_next_index_fn
+    (unformat_l2_input_next_node);
+
+  vnet_classify_register_unformat_l2_next_index_fn
+    (unformat_l2_input_next_node);
+
+  vnet_classify_register_unformat_l2_next_index_fn
+    (unformat_l2_output_next_node);
+
+  vnet_classify_register_unformat_acl_next_index_fn
+    (unformat_acl_next_node);
+
+  return 0;
+}
+
+VLIB_INIT_FUNCTION (vnet_classify_init);
+
 #define TEST_CODE 1
 
 #if TEST_CODE > 0
@@ -1817,7 +2119,7 @@ test_classify_command_fn (vlib_main_t * vm,
                                        memory_size,
                                        0 /* skip */,
                                        3 /* vectors to match */);
-          t->miss_next_index = IP_LOOKUP_NEXT_LOCAL;
+          t->miss_next_index = IP_LOOKUP_NEXT_DROP;
           vlib_cli_output (vm, "Create table %d", t - cm->tables);
         }