acl-plugin: implement an optional session reclassification when ACL is (re-)applied
[vpp.git] / src / plugins / acl / acl.c
index 7c2572d..90b369e 100644 (file)
@@ -305,6 +305,45 @@ warning_acl_print_acl (vlib_main_t * vm, acl_main_t * am, int acl_index)
   acl_print_acl_x (print_clib_warning_and_reset, vm, am, acl_index);
 }
 
+static void
+increment_policy_epoch (acl_main_t * am, u32 sw_if_index, int is_input)
+{
+
+  u32 **ppolicy_epoch_by_swi =
+    is_input ? &am->input_policy_epoch_by_sw_if_index :
+    &am->output_policy_epoch_by_sw_if_index;
+  vec_validate (*ppolicy_epoch_by_swi, sw_if_index);
+
+  u32 *p_epoch = vec_elt_at_index ((*ppolicy_epoch_by_swi), sw_if_index);
+  *p_epoch =
+    ((1 + *p_epoch) & FA_POLICY_EPOCH_MASK) +
+    (is_input * FA_POLICY_EPOCH_IS_INPUT);
+}
+
+static void
+try_increment_acl_policy_epoch (acl_main_t * am, u32 acl_num, int is_input)
+{
+  u32 ***p_swi_vec_by_acl = is_input ? &am->input_sw_if_index_vec_by_acl
+    : &am->output_sw_if_index_vec_by_acl;
+  if (acl_num < vec_len (*p_swi_vec_by_acl))
+    {
+      u32 *p_swi;
+      vec_foreach (p_swi, (*p_swi_vec_by_acl)[acl_num])
+      {
+       increment_policy_epoch (am, *p_swi, is_input);
+      }
+
+    }
+}
+
+static void
+policy_notify_acl_change (acl_main_t * am, u32 acl_num)
+{
+  try_increment_acl_policy_epoch (am, acl_num, 0);
+  try_increment_acl_policy_epoch (am, acl_num, 1);
+}
+
+
 
 static int
 acl_add_list (u32 count, vl_api_acl_rule_t rules[],
@@ -392,6 +431,12 @@ acl_add_list (u32 count, vl_api_acl_rule_t rules[],
   memcpy (a->tag, tag, sizeof (a->tag));
   if (am->trace_acl > 255)
     warning_acl_print_acl (am->vlib_main, am, *acl_list_index);
+  if (am->reclassify_sessions)
+    {
+      /* a change in an ACLs if they are applied may mean a new policy epoch */
+      policy_notify_acl_change (am, *acl_list_index);
+    }
+
   /* notify the lookup contexts about the ACL changes */
   acl_plugin_lookup_context_notify_acl_change (*acl_list_index);
   clib_mem_set_heap (oldheap);
@@ -1268,12 +1313,20 @@ acl_interface_set_inout_acl_list (acl_main_t * am, u32 sw_if_index,
   (*pinout_acl_vec_by_sw_if_index)[sw_if_index] =
     vec_dup (vec_acl_list_index);
 
-  /* if no commonalities between the ACL# - then we should definitely clear the sessions */
-  if (may_clear_sessions && *may_clear_sessions
-      && !clib_bitmap_is_zero (change_acl_bitmap))
+  if (am->reclassify_sessions)
+    {
+      /* re-applying ACLs means a new policy epoch */
+      increment_policy_epoch (am, sw_if_index, is_input);
+    }
+  else
     {
-      acl_clear_sessions (am, sw_if_index);
-      *may_clear_sessions = 0;
+      /* if no commonalities between the ACL# - then we should definitely clear the sessions */
+      if (may_clear_sessions && *may_clear_sessions
+         && !clib_bitmap_is_zero (change_acl_bitmap))
+       {
+         acl_clear_sessions (am, sw_if_index);
+         *may_clear_sessions = 0;
+       }
     }
 
   /*
@@ -3202,6 +3255,11 @@ acl_set_aclplugin_fn (vlib_main_t * vm,
       am->l4_match_nonfirst_fragment = (val != 0);
       goto done;
     }
+  if (unformat (input, "reclassify-sessions %u", &val))
+    {
+      am->reclassify_sessions = (val != 0);
+      goto done;
+    }
   if (unformat (input, "event-trace"))
     {
       if (!unformat (input, "%u", &val))
@@ -3571,6 +3629,15 @@ acl_plugin_show_interface (acl_main_t * am, u32 sw_if_index, int show_acl,
        continue;
 
       vlib_cli_output (vm, "sw_if_index %d:\n", swi);
+      if (swi < vec_len (am->input_policy_epoch_by_sw_if_index))
+       vlib_cli_output (vm, "   input policy epoch: %x\n",
+                        vec_elt (am->input_policy_epoch_by_sw_if_index,
+                                 swi));
+      if (swi < vec_len (am->output_policy_epoch_by_sw_if_index))
+       vlib_cli_output (vm, "   output policy epoch: %x\n",
+                        vec_elt (am->output_policy_epoch_by_sw_if_index,
+                                 swi));
+
 
       if (intf_has_etype_whitelist (am, swi, 1))
        {
@@ -3761,13 +3828,21 @@ acl_plugin_show_sessions (acl_main_t * am,
                                               ?
                                               pw->fa_session_dels_by_sw_if_index
                                               [sw_if_index] : 0;
+                                              u64 n_epoch_changes =
+                                              sw_if_index <
+                                              vec_len
+                                              (pw->fa_session_epoch_change_by_sw_if_index)
+                                              ?
+                                              pw->fa_session_epoch_change_by_sw_if_index
+                                              [sw_if_index] : 0;
                                               vlib_cli_output (vm,
-                                                               "    sw_if_index %d: add %lu - del %lu = %lu",
+                                                               "    sw_if_index %d: add %lu - del %lu = %lu; epoch chg: %lu",
                                                                sw_if_index,
                                                                n_adds,
                                                                n_dels,
                                                                n_adds -
-                                                               n_dels);
+                                                               n_dels,
+                                                               n_epoch_changes);
                                               }
                    ));
 
@@ -3829,6 +3904,7 @@ acl_plugin_show_sessions (acl_main_t * am,
                   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);
+  vlib_cli_output (vm, "Reclassify sessions: %d", am->reclassify_sessions);
 }
 
 static clib_error_t *
@@ -4007,6 +4083,7 @@ acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
   uword hash_heap_size;
   u32 hash_lookup_hash_buckets;
   u32 hash_lookup_hash_memory;
+  u32 reclassify_sessions;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
@@ -4035,6 +4112,10 @@ acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
       else if (unformat (input, "hash lookup hash memory %d",
                         &hash_lookup_hash_memory))
        am->hash_lookup_hash_memory = hash_lookup_hash_memory;
+      else if (unformat (input, "reclassify sessions %d",
+                        &reclassify_sessions))
+       am->reclassify_sessions = reclassify_sessions;
+
       else
        return clib_error_return (0, "unknown input '%U'",
                                  format_unformat_error, input);
@@ -4086,6 +4167,7 @@ acl_init (vlib_main_t * vm)
   am->fa_conn_table_hash_memory_size =
     ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
+  am->reclassify_sessions = 0;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
   vec_validate (am->per_worker_data, tm->n_vlib_mains - 1);
   {