ACL-plugin add "replace" semantics for adding a new MacIP acl
[vpp.git] / src / plugins / acl / acl.c
index 645c6c9..611efbb 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) \
@@ -949,8 +950,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
@@ -994,7 +1009,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;
@@ -1144,6 +1159,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 +1193,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 = &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;
@@ -1619,6 +1658,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)
 {
@@ -2242,6 +2305,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 +2313,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 +2484,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 +2523,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 +2538,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);
             }
           }