api: autogenerate api trace print/endian
[vpp.git] / src / plugins / acl / acl.c
index 56a1bfa..dc9caa6 100644 (file)
@@ -86,7 +86,8 @@ _(MACIP_ACL_INTERFACE_GET, macip_acl_interface_get) \
 _(MACIP_ACL_INTERFACE_LIST_DUMP, macip_acl_interface_list_dump) \
 _(ACL_INTERFACE_SET_ETYPE_WHITELIST, acl_interface_set_etype_whitelist) \
 _(ACL_INTERFACE_ETYPE_WHITELIST_DUMP, acl_interface_etype_whitelist_dump) \
-_(ACL_PLUGIN_GET_CONN_TABLE_MAX_ENTRIES,acl_plugin_get_conn_table_max_entries)
+_(ACL_PLUGIN_GET_CONN_TABLE_MAX_ENTRIES,acl_plugin_get_conn_table_max_entries) \
+_(ACL_STATS_INTF_COUNTERS_ENABLE, acl_stats_intf_counters_enable)
 
 
 /* *INDENT-OFF* */
@@ -373,6 +374,82 @@ policy_notify_acl_change (acl_main_t * am, u32 acl_num)
 }
 
 
+static void
+validate_and_reset_acl_counters (acl_main_t * am, u32 acl_index)
+{
+  int i;
+  /* counters are set as vectors [acl#] pointing to vectors of [acl rule] */
+  acl_plugin_counter_lock (am);
+
+  int old_len = vec_len (am->combined_acl_counters);
+
+  vec_validate (am->combined_acl_counters, acl_index);
+
+  for (i = old_len; i < vec_len (am->combined_acl_counters); i++)
+    {
+      am->combined_acl_counters[i].name = 0;
+      /* filled in once only */
+      am->combined_acl_counters[i].stat_segment_name = (void *)
+       format (0, "/acl/%d/matches%c", i, 0);
+      i32 rule_count = vec_len (am->acls[i].rules);
+      /* Validate one extra so we always have at least one counter for an ACL */
+      vlib_validate_combined_counter (&am->combined_acl_counters[i],
+                                     rule_count);
+      vlib_clear_combined_counters (&am->combined_acl_counters[i]);
+    }
+
+  /* (re)validate for the actual ACL that is getting added/updated */
+  i32 rule_count = vec_len (am->acls[acl_index].rules);
+  /* Validate one extra so we always have at least one counter for an ACL */
+  vlib_validate_combined_counter (&am->combined_acl_counters[acl_index],
+                                 rule_count);
+  vlib_clear_combined_counters (&am->combined_acl_counters[acl_index]);
+  acl_plugin_counter_unlock (am);
+}
+
+static int
+acl_api_ip4_invalid_prefix (void *ip4_pref_raw, u8 ip4_prefix_len)
+{
+  ip4_address_t ip4_addr;
+  ip4_address_t ip4_mask;
+  ip4_address_t ip4_masked_addr;
+
+  memcpy (&ip4_addr, ip4_pref_raw, sizeof (ip4_addr));
+  ip4_preflen_to_mask (ip4_prefix_len, &ip4_mask);
+  ip4_masked_addr.as_u32 = ip4_addr.as_u32 & ip4_mask.as_u32;
+  int ret = (ip4_masked_addr.as_u32 != ip4_addr.as_u32);
+  if (ret)
+    {
+      clib_warning
+       ("inconsistent addr %U for prefix len %d; (%U when masked)",
+        format_ip4_address, ip4_pref_raw, ip4_prefix_len, format_ip4_address,
+        &ip4_masked_addr);
+    }
+  return ret;
+}
+
+static int
+acl_api_ip6_invalid_prefix (void *ip6_pref_raw, u8 ip6_prefix_len)
+{
+  ip6_address_t ip6_addr;
+  ip6_address_t ip6_mask;
+  ip6_address_t ip6_masked_addr;
+
+  memcpy (&ip6_addr, ip6_pref_raw, sizeof (ip6_addr));
+  ip6_preflen_to_mask (ip6_prefix_len, &ip6_mask);
+  ip6_masked_addr.as_u64[0] = ip6_addr.as_u64[0] & ip6_mask.as_u64[0];
+  ip6_masked_addr.as_u64[1] = ip6_addr.as_u64[1] & ip6_mask.as_u64[1];
+  int ret = ((ip6_masked_addr.as_u64[0] != ip6_addr.as_u64[0])
+            || (ip6_masked_addr.as_u64[1] != ip6_addr.as_u64[1]));
+  if (ret)
+    {
+      clib_warning
+       ("inconsistent addr %U for prefix len %d; (%U when masked)",
+        format_ip6_address, ip6_pref_raw, ip6_prefix_len, format_ip6_address,
+        &ip6_masked_addr);
+    }
+  return ret;
+}
 
 static int
 acl_add_list (u32 count, vl_api_acl_rule_t rules[],
@@ -388,6 +465,43 @@ acl_add_list (u32 count, vl_api_acl_rule_t rules[],
     clib_warning ("API dbg: acl_add_list index %d tag %s", *acl_list_index,
                  tag);
 
+  /* check if what they request is consistent */
+  for (i = 0; i < count; i++)
+    {
+      if (rules[i].is_ipv6)
+       {
+         if (rules[i].src_ip_prefix_len > 128)
+           return VNET_API_ERROR_INVALID_VALUE;
+         if (rules[i].dst_ip_prefix_len > 128)
+           return VNET_API_ERROR_INVALID_VALUE;
+         if (acl_api_ip6_invalid_prefix
+             (&rules[i].src_ip_addr, rules[i].src_ip_prefix_len))
+           return VNET_API_ERROR_INVALID_SRC_ADDRESS;
+         if (acl_api_ip6_invalid_prefix
+             (&rules[i].dst_ip_addr, rules[i].dst_ip_prefix_len))
+           return VNET_API_ERROR_INVALID_DST_ADDRESS;
+       }
+      else
+       {
+         if (rules[i].src_ip_prefix_len > 32)
+           return VNET_API_ERROR_INVALID_VALUE;
+         if (rules[i].dst_ip_prefix_len > 32)
+           return VNET_API_ERROR_INVALID_VALUE;
+         if (acl_api_ip4_invalid_prefix
+             (&rules[i].src_ip_addr, rules[i].src_ip_prefix_len))
+           return VNET_API_ERROR_INVALID_SRC_ADDRESS;
+         if (acl_api_ip4_invalid_prefix
+             (&rules[i].dst_ip_addr, rules[i].dst_ip_prefix_len))
+           return VNET_API_ERROR_INVALID_DST_ADDRESS;
+       }
+      if (ntohs (rules[i].srcport_or_icmptype_first) >
+         ntohs (rules[i].srcport_or_icmptype_last))
+       return VNET_API_ERROR_INVALID_VALUE_2;
+      if (ntohs (rules[i].dstport_or_icmpcode_first) >
+         ntohs (rules[i].dstport_or_icmpcode_last))
+       return VNET_API_ERROR_INVALID_VALUE_2;
+    }
+
   if (*acl_list_index != ~0)
     {
       /* They supplied some number, let's see if this ACL exists */
@@ -465,6 +579,11 @@ acl_add_list (u32 count, vl_api_acl_rule_t rules[],
       policy_notify_acl_change (am, *acl_list_index);
     }
 
+  /* stats segment expects global heap, so restore it temporarily */
+  clib_mem_set_heap (oldheap);
+  validate_and_reset_acl_counters (am, *acl_list_index);
+  oldheap = acl_set_heap (am);
+
   /* notify the lookup contexts about the ACL changes */
   acl_plugin_lookup_context_notify_acl_change (*acl_list_index);
   clib_mem_set_heap (oldheap);
@@ -661,6 +780,16 @@ acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index,
   return rv;
 }
 
+static int
+acl_stats_intf_counters_enable_disable (acl_main_t * am, int enable_disable)
+{
+  int rv = 0;
+
+  am->interface_acl_counters_enabled = enable_disable;
+
+  return rv;
+}
+
 static int
 acl_interface_inout_enable_disable (acl_main_t * am, u32 sw_if_index,
                                    int is_input, int enable_disable)
@@ -789,10 +918,6 @@ acl_interface_set_inout_acl_list (acl_main_t * am, u32 sw_if_index,
       u32 lc_index = (*pinout_lc_index_by_sw_if_index)[sw_if_index];
       if (~0 == lc_index)
        {
-         if (~0 == am->interface_acl_user_id)
-           am->interface_acl_user_id =
-             acl_plugin.register_user_module ("interface ACL", "sw_if_index",
-                                              "is_input");
          lc_index =
            acl_plugin.get_lookup_context_index (am->interface_acl_user_id,
                                                 sw_if_index, is_input);
@@ -1897,6 +2022,21 @@ vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
 }
 
+
+static void
+  vl_api_acl_stats_intf_counters_enable_t_handler
+  (vl_api_acl_stats_intf_counters_enable_t * mp)
+{
+  acl_main_t *am = &acl_main;
+  vl_api_acl_stats_intf_counters_enable_reply_t *rmp;
+  int rv;
+
+  rv = acl_stats_intf_counters_enable_disable (am, mp->enable);
+
+  REPLY_MACRO (VL_API_ACL_DEL_REPLY);
+}
+
+
 static void
 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
 {
@@ -3394,6 +3534,8 @@ acl_show_aclplugin_tables_fn (vlib_main_t * vm,
       show_applied_info = 1;
       show_bihash = 1;
     }
+  vlib_cli_output (vm, "Stats counters enabled for interface ACLs: %d",
+                  acl_main.interface_acl_counters_enabled);
   if (show_mask_type)
     acl_plugin_show_tables_mask_type ();
   if (show_acl_hash_info)
@@ -3659,7 +3801,13 @@ acl_init (vlib_main_t * vm)
   /* Set the default threshold */
   am->tuple_merge_split_threshold = TM_SPLIT_THRESHOLD;
 
-  am->interface_acl_user_id = ~0;      /* defer till the first use */
+  am->interface_acl_user_id =
+    acl_plugin.register_user_module ("interface ACL", "sw_if_index",
+                                    "is_input");
+
+  am->acl_counter_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
+                                                CLIB_CACHE_LINE_BYTES);
+  am->acl_counter_lock[0] = 0; /* should be no need */
 
   return error;
 }