ACL plugin enable macip for ip4/ip6 traffic
[vpp.git] / src / plugins / acl / acl.c
index 645c6c9..04a6686 100644 (file)
@@ -71,6 +71,7 @@ _(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list)     \
 _(ACL_DUMP, acl_dump)  \
 _(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump) \
 _(MACIP_ACL_ADD, macip_acl_add) \
+_(MACIP_ACL_ADD_REPLACE, macip_acl_add_replace) \
 _(MACIP_ACL_DEL, macip_acl_del) \
 _(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del) \
 _(MACIP_ACL_DUMP, macip_acl_dump) \
@@ -90,7 +91,7 @@ static void *
 acl_set_heap(acl_main_t *am)
 {
   if (0 == am->acl_mheap) {
-    am->acl_mheap = mheap_alloc (0 /* use VM */ , 2 << 29);
+    am->acl_mheap = mheap_alloc (0 /* use VM */ , am->acl_mheap_size);
     mheap_t *h = mheap_header (am->acl_mheap);
     h->flags |= MHEAP_FLAG_THREAD_SAFE;
   }
@@ -258,13 +259,13 @@ acl_del_list (u32 acl_list_index)
     }
 
   if (acl_list_index < vec_len(am->input_sw_if_index_vec_by_acl)) {
-    if (vec_len(am->input_sw_if_index_vec_by_acl[acl_list_index]) > 0) {
+    if (vec_len(pool_elt_at_index(am->input_sw_if_index_vec_by_acl, acl_list_index)) > 0) {
       /* ACL is applied somewhere inbound. Refuse to delete */
       return -1;
     }
   }
   if (acl_list_index < vec_len(am->output_sw_if_index_vec_by_acl)) {
-    if (vec_len(am->output_sw_if_index_vec_by_acl[acl_list_index]) > 0) {
+    if (vec_len(pool_elt_at_index(am->output_sw_if_index_vec_by_acl, acl_list_index)) > 0) {
       /* ACL is applied somewhere outbound. Refuse to delete */
       return -1;
     }
@@ -306,7 +307,7 @@ acl_del_list (u32 acl_list_index)
 
   hash_acl_delete(am, acl_list_index);
   /* now we can delete the ACL itself */
-  a = &am->acls[acl_list_index];
+  a = pool_elt_at_index (am->acls, acl_list_index);
   if (a->rules)
     vec_free (a->rules);
 
@@ -893,7 +894,6 @@ acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
 {
   int rv = -1;
   acl_main_t *am = &acl_main;
-  void *oldheap = acl_set_heap(am);
   if (is_add)
     {
       rv =
@@ -909,7 +909,6 @@ acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
       rv =
        acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index);
     }
-  clib_mem_set_heap (oldheap);
   return rv;
 }
 
@@ -949,8 +948,22 @@ macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
 static int
 match_type_metric (macip_match_type_t * m)
 {
-  /* FIXME: count the ones in the MAC mask as well, check how well this heuristic works in real life */
-  return m->prefix_len + m->is_ipv6 + 10 * m->count;
+   unsigned int mac_bits_set = 0;
+   unsigned int mac_byte;
+   int i;
+   for (i=0; i<6; i++)
+     {
+       mac_byte = m->mac_mask[i];
+       for (; mac_byte; mac_byte >>= 1)
+         mac_bits_set += mac_byte & 1;
+     }
+   /*
+    * Attempt to place the more specific and the more used rules on top.
+    * There are obvious caveat corner cases to this, but they do not
+    * seem to be sensible in real world (e.g. specific IPv4 with wildcard MAC
+    * going with a wildcard IPv4 with a specific MAC).
+    */
+   return m->prefix_len + mac_bits_set + m->is_ipv6 + 10 * m->count;
 }
 
 static int
@@ -975,7 +988,7 @@ macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
 {
   macip_match_type_t *mvec = NULL;
   macip_match_type_t *mt;
-  macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
+  macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
   int i;
   u32 match_type_index;
   u32 last_table;
@@ -994,7 +1007,7 @@ macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
          match_type_index = vec_len (mvec);
          vec_validate (mvec, match_type_index);
          memcpy (mvec[match_type_index].mac_mask,
-                 a->rules[match_type_index].src_mac_mask, 6);
+                 a->rules[i].src_mac_mask, 6);
          mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
          mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
          mvec[match_type_index].table_index = ~0;
@@ -1060,8 +1073,8 @@ macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
                                1);
     last_table = mt->table_index;
   }
-  a->ip4_table_index = ~0;
-  a->ip6_table_index = ~0;
+  a->ip4_table_index = last_table;
+  a->ip6_table_index = last_table;
   a->l2_table_index = last_table;
 
   /* Populate the classifier tables with rules from the MACIP ACL */
@@ -1116,7 +1129,7 @@ static void
 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
 {
   vnet_classify_main_t *cm = &vnet_classify_main;
-  macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
+  macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
 
   if (a->ip4_table_index != ~0)
     {
@@ -1144,6 +1157,18 @@ macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
   macip_acl_rule_t *r;
   macip_acl_rule_t *acl_new_rules = 0;
   int i;
+
+  if (*acl_list_index != ~0)
+    {
+      /* They supplied some number, let's see if this MACIP ACL exists */
+      if (pool_is_free_index (am->macip_acls, *acl_list_index))
+  {
+    /* tried to replace a non-existent ACL, no point doing anything */
+          clib_warning("acl-plugin-error: Trying to replace nonexistent MACIP ACL %d (tag %s)", *acl_list_index, tag);
+    return -1;
+  }
+    }
+
   if (0 == count) {
     clib_warning("acl-plugin-warning: Trying to create empty MACIP ACL (tag %s)", tag);
   }
@@ -1166,11 +1191,23 @@ macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
       r->src_prefixlen = rules[i].src_ip_prefix_len;
     }
 
-  /* Get ACL index */
-  pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
-  memset (a, 0, sizeof (*a));
-  /* Will return the newly allocated ACL index */
-  *acl_list_index = a - am->macip_acls;
+  if (~0 == *acl_list_index)
+    {
+      /* Get ACL index */
+      pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
+      memset (a, 0, sizeof (*a));
+      /* Will return the newly allocated ACL index */
+      *acl_list_index = a - am->macip_acls;
+    }
+  else
+    {
+      a = pool_elt_at_index (am->macip_acls, *acl_list_index);
+      if (a->rules)
+        {
+          vec_free (a->rules);
+        }
+      macip_destroy_classify_tables (am, *acl_list_index);
+    }
 
   a->rules = acl_new_rules;
   a->count = count;
@@ -1198,7 +1235,7 @@ macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
   /* No point in deleting MACIP ACL which is not applied */
   if (~0 == macip_acl_index)
     return -1;
-  a = &am->macip_acls[macip_acl_index];
+  a = pool_elt_at_index (am->macip_acls, macip_acl_index);
   /* remove the classifier tables off the interface L2 ACL */
   rv =
     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
@@ -1221,13 +1258,13 @@ macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
       return -1;
     }
   void *oldheap = acl_set_heap(am);
-  a = &am->macip_acls[macip_acl_index];
+  a = pool_elt_at_index (am->macip_acls, macip_acl_index);
   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
+  clib_mem_set_heap (oldheap);
   /* If there already a MACIP ACL applied, unapply it */
   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
     macip_acl_interface_del_acl(am, sw_if_index);
   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
-  clib_mem_set_heap (oldheap);
 
   /* Apply the classifier tables for L2 ACLs */
   rv =
@@ -1240,7 +1277,6 @@ static int
 macip_acl_del_list (u32 acl_list_index)
 {
   acl_main_t *am = &acl_main;
-  void *oldheap = acl_set_heap(am);
   macip_acl_list_t *a;
   int i;
   if (pool_is_free_index (am->macip_acls, acl_list_index))
@@ -1257,11 +1293,12 @@ macip_acl_del_list (u32 acl_list_index)
        }
     }
 
+  void *oldheap = acl_set_heap(am);
   /* Now that classifier tables are detached, clean them up */
   macip_destroy_classify_tables (am, acl_list_index);
 
   /* now we can delete the ACL itself */
-  a = &am->macip_acls[acl_list_index];
+  a = pool_elt_at_index (am->macip_acls, acl_list_index);
   if (a->rules)
     {
       vec_free (a->rules);
@@ -1277,7 +1314,6 @@ macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
                                 u32 acl_list_index)
 {
   acl_main_t *am = &acl_main;
-  void *oldheap = acl_set_heap(am);
   int rv = -1;
   if (is_add)
     {
@@ -1287,7 +1323,6 @@ macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
     {
       rv = macip_acl_interface_del_acl (am, sw_if_index);
     }
-  clib_mem_set_heap (oldheap);
   return rv;
 }
 
@@ -1500,10 +1535,10 @@ vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
     {
       acl_index = ntohl (mp->acl_index);
       if (!pool_is_free_index (am->acls, acl_index))
-       {
-         acl = &am->acls[acl_index];
-         send_acl_details (am, q, acl, mp->context);
-       }
+       {
+         acl = pool_elt_at_index (am->acls, acl_index);
+         send_acl_details (am, q, acl, mp->context);
+       }
     }
 
   if (rv == -1)
@@ -1619,6 +1654,30 @@ vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
   /* *INDENT-ON* */
 }
 
+static void
+vl_api_macip_acl_add_replace_t_handler (vl_api_macip_acl_add_replace_t * mp)
+{
+  vl_api_macip_acl_add_replace_reply_t *rmp;
+  acl_main_t *am = &acl_main;
+  int rv;
+  u32 acl_list_index = ntohl (mp->acl_index);
+  u32 acl_count = ntohl (mp->count);
+  u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
+
+  if (verify_message_len(mp, expected_len, "macip_acl_add_replace")) {
+      rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
+  } else {
+      rv = VNET_API_ERROR_INVALID_VALUE;
+  }
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLACE_REPLY,
+  ({
+    rmp->acl_index = htonl(acl_list_index);
+  }));
+  /* *INDENT-ON* */
+}
+
 static void
 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
 {
@@ -1730,10 +1789,10 @@ vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
     {
       u32 acl_index = ntohl (mp->acl_index);
       if (!pool_is_free_index (am->macip_acls, acl_index))
-       {
-         acl = &am->macip_acls[acl_index];
-         send_macip_acl_details (am, q, acl, mp->context);
-       }
+       {
+         acl = pool_elt_at_index (am->macip_acls, acl_index);
+         send_macip_acl_details (am, q, acl, mp->context);
+       }
     }
 }
 
@@ -2242,6 +2301,7 @@ acl_show_aclplugin_fn (vlib_main_t * vm,
        out0 = format(out0, "  interrupt is pending: %d\n", pw->interrupt_is_pending);
        out0 = format(out0, "  interrupt is needed: %d\n", pw->interrupt_is_needed);
        out0 = format(out0, "  interrupt is unwanted: %d\n", pw->interrupt_is_unwanted);
+       out0 = format(out0, "  interrupt generation: %d\n", pw->interrupt_generation);
       }
       out0 = format(out0, "\n\nConn cleaner thread counters:\n");
 #define _(cnt, desc) out0 = format(out0, "             %20lu: %s\n", am->cnt, desc);
@@ -2249,6 +2309,7 @@ acl_show_aclplugin_fn (vlib_main_t * vm,
 #undef _
       vec_terminate_c_string(out0);
       vlib_cli_output(vm, "\n\n%s\n\n", out0);
+      vlib_cli_output(vm, "Interrupt generation: %d\n", am->fa_interrupt_generation);
       vlib_cli_output(vm, "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
               am->fa_min_deleted_sessions_per_interval, am->fa_max_deleted_sessions_per_interval,
               am->fa_cleaner_wait_time_increment * 1000.0, ((f64)am->fa_current_cleaner_timer_wait_interval) * 1000.0/(f64)vm->clib_time.clocks_per_second);
@@ -2419,6 +2480,8 @@ acl_show_aclplugin_fn (vlib_main_t * vm,
           }
           hash_acl_info_t *ha = &am->hash_acl_infos[i];
           out0 = format(out0, "acl-index %u bitmask-ready layout\n", i);
+          out0 = format(out0, "  applied  inbound on sw_if_index list: %U\n", format_vec32, ha->inbound_sw_if_index_list, "%d");
+          out0 = format(out0, "  applied outbound on sw_if_index list: %U\n", format_vec32, ha->outbound_sw_if_index_list, "%d");
           out0 = format(out0, "  mask type index bitmap: %U\n", format_bitmap_hex, ha->mask_type_index_bitmap);
           for(j=0; j<vec_len(ha->rules); j++) {
             hash_ace_info_t *pa = &ha->rules[j];
@@ -2456,9 +2519,9 @@ acl_show_aclplugin_fn (vlib_main_t * vm,
             out0 = format(out0, "  input lookup applied entries:\n");
             for(j=0; j<vec_len(am->input_hash_entry_vec_by_sw_if_index[swi]); j++) {
               applied_hash_ace_entry_t *pae = &am->input_hash_entry_vec_by_sw_if_index[swi][j];
-              out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d\n",
+              out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d hitcount %lld\n",
                                        j, pae->acl_index, pae->ace_index, pae->action, pae->hash_ace_info_index,
-                                       pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index);
+                                       pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index, pae->hitcount);
             }
           }
 
@@ -2471,9 +2534,9 @@ acl_show_aclplugin_fn (vlib_main_t * vm,
             out0 = format(out0, "  output lookup applied entries:\n");
             for(j=0; j<vec_len(am->output_hash_entry_vec_by_sw_if_index[swi]); j++) {
               applied_hash_ace_entry_t *pae = &am->output_hash_entry_vec_by_sw_if_index[swi][j];
-              out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d\n",
+              out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d hitcount %lld\n",
                                        j, pae->acl_index, pae->ace_index, pae->action, pae->hash_ace_info_index,
-                                       pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index);
+                                       pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index, pae->hitcount);
             }
           }
 
@@ -2529,7 +2592,47 @@ VLIB_CLI_COMMAND (aclplugin_clear_command, static) = {
 };
 /* *INDENT-ON* */
 
-
+static clib_error_t *
+acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
+{
+  acl_main_t *am = &acl_main;
+  u32 conn_table_hash_buckets;
+  u32 conn_table_hash_memory_size;
+  u32 conn_table_max_entries;
+  u32 main_heap_size;
+  u32 hash_heap_size;
+  u32 hash_lookup_hash_buckets;
+  u32 hash_lookup_hash_memory;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "connection hash buckets %d", &conn_table_hash_buckets))
+        am->fa_conn_table_hash_num_buckets = conn_table_hash_buckets;
+      else if (unformat (input, "connection hash memory %d",
+                         &conn_table_hash_memory_size))
+        am->fa_conn_table_hash_memory_size = conn_table_hash_memory_size;
+      else if (unformat (input, "connection count max %d",
+                         &conn_table_max_entries))
+        am->fa_conn_table_max_entries = conn_table_max_entries;
+      else if (unformat (input, "main heap size %d",
+                         &main_heap_size))
+        am->acl_mheap_size = main_heap_size;
+      else if (unformat (input, "hash lookup heap size %d",
+                         &hash_heap_size))
+        am->hash_lookup_mheap_size = hash_heap_size;
+      else if (unformat (input, "hash lookup hash buckets %d",
+                         &hash_lookup_hash_buckets))
+        am->hash_lookup_hash_buckets = hash_lookup_hash_buckets;
+      else if (unformat (input, "hash lookup hash memory %d",
+                         &hash_lookup_hash_memory))
+        am->hash_lookup_hash_memory = hash_lookup_hash_memory;
+      else
+        return clib_error_return (0, "unknown input '%U'",
+                                  format_unformat_error, input);
+    }
+  return 0;
+}
+VLIB_CONFIG_FUNCTION (acl_plugin_config, "acl-plugin");
 
 static clib_error_t *
 acl_init (vlib_main_t * vm)
@@ -2555,6 +2658,12 @@ acl_init (vlib_main_t * vm)
 
   acl_setup_fa_nodes();
 
+  am->acl_mheap_size = ACL_FA_DEFAULT_HEAP_SIZE;
+  am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE;
+
+  am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
+  am->hash_lookup_hash_memory = ACL_PLUGIN_HASH_LOOKUP_HASH_MEMORY;
+
   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] = TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] = TCP_SESSION_IDLE_TIMEOUT_SEC;
   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] = UDP_SESSION_IDLE_TIMEOUT_SEC;