#include "public_inlines.h"
acl_main_t acl_main;
+acl_main_t *p_acl_main = &acl_main;
#define REPLY_MSG_ID_BASE am->msg_id_base
#include <vlibapi/api_helper_macros.h>
{
if (0 == am->acl_mheap)
{
+ if (0 == am->acl_mheap_size)
+ {
+ vlib_thread_main_t *tm = vlib_get_thread_main ();
+ u64 per_worker_slack = 1000000LL;
+ u64 per_worker_size =
+ per_worker_slack +
+ ((u64) am->fa_conn_table_max_entries) * sizeof (fa_session_t);
+ u64 per_worker_size_with_slack = per_worker_slack + per_worker_size;
+ u64 main_slack = 2000000LL;
+ u64 bihash_size = (u64) am->fa_conn_table_hash_memory_size;
+
+ am->acl_mheap_size =
+ per_worker_size_with_slack * tm->n_vlib_mains + bihash_size +
+ main_slack;
+ }
+ u64 max_possible = ((uword) ~ 0);
+ if (am->acl_mheap_size > max_possible)
+ {
+ clib_warning ("ACL heap size requested: %lld, max possible %lld",
+ am->acl_mheap_size, max_possible);
+ }
am->acl_mheap = mheap_alloc (0 /* use VM */ , am->acl_mheap_size);
+ if (0 == am->acl_mheap)
+ {
+ clib_error
+ ("ACL plugin failed to allocate main heap of %U bytes, abort",
+ format_memory_size, am->acl_mheap_size);
+ }
mheap_t *h = mheap_header (am->acl_mheap);
h->flags |= MHEAP_FLAG_THREAD_SAFE;
}
return oldheap;
}
+void *
+acl_plugin_set_heap ()
+{
+ acl_main_t *am = &acl_main;
+ return acl_set_heap (am);
+}
+
void
acl_plugin_acl_set_validate_heap (acl_main_t * am, int on)
{
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[],
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);
(*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;
+ }
}
/*
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);
- ASSERT (lc_index >= 0);
(*pinout_lc_index_by_sw_if_index)[sw_if_index] = lc_index;
}
acl_plugin_set_acl_vec_for_context (lc_index, vec_acl_list_index);
return rv;
}
-
-/* No check for validity of sw_if_index - the callers were supposed to validate */
+/* No check that sw_if_index denotes a valid interface - the callers
+ * were supposed to validate.
+ *
+ * That said, if sw_if_index corresponds to an interface that exists at all,
+ * this function must return errors accordingly if the ACL is not applied.
+ */
static int
macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
u32 macip_acl_index;
macip_acl_list_t *a;
+ /* The vector is too short - MACIP ACL is not applied */
+ if (sw_if_index >= vec_len (am->macip_acl_by_sw_if_index))
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+
macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
/* No point in deleting MACIP ACL which is not applied */
if (~0 == macip_acl_index)
return VNET_API_ERROR_NO_SUCH_ENTRY;
- void *oldheap = acl_set_heap (am);
- vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
- vec_validate_init_empty (am->sw_if_index_vec_by_macip_acl, macip_acl_index,
- ~0);
- clib_mem_set_heap (oldheap);
a = pool_elt_at_index (am->macip_acls, macip_acl_index);
/* remove the classifier tables off the interface L2 ACL */
rv =
a->out_l2_table_index, 0);
/* Unset the MACIP ACL index */
am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
- am->sw_if_index_vec_by_macip_acl[macip_acl_index] = ~0;
+ /* macip_acl_interface_add_acl did a vec_add1() to this previously, so [sw_if_index] should be valid */
+ u32 index = vec_search (am->sw_if_index_vec_by_macip_acl[macip_acl_index],
+ sw_if_index);
+ if (index != ~0)
+ vec_del1 (am->sw_if_index_vec_by_macip_acl[macip_acl_index], index);
return rv;
}
void *oldheap = acl_set_heap (am);
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);
- vec_validate_init_empty (am->sw_if_index_vec_by_macip_acl, macip_acl_index,
- ~0);
+ vec_validate (am->sw_if_index_vec_by_macip_acl, macip_acl_index);
+ vec_add1 (am->sw_if_index_vec_by_macip_acl[macip_acl_index], sw_if_index);
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;
- am->sw_if_index_vec_by_macip_acl[macip_acl_index] = sw_if_index;
/* Apply the classifier tables for L2 ACLs */
rv =
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))
macip_acl_print (am, i);
if (i < vec_len (am->sw_if_index_vec_by_macip_acl))
{
- vlib_cli_output (vm, " applied on sw_if_index: %d\n",
- vec_elt (am->sw_if_index_vec_by_macip_acl, i));
+ vlib_cli_output (vm, " applied on sw_if_index(s): %U\n",
+ format_vec32,
+ vec_elt (am->sw_if_index_vec_by_macip_acl, i),
+ "%d");
}
}
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))
{
?
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);
}
));
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 *
clib_error_t *error = 0;
u32 acl_index = ~0;
- u32 sw_if_index = ~0;
+ u32 lc_index = ~0;
int show_acl_hash_info = 0;
int show_applied_info = 0;
int show_mask_type = 0;
else if (unformat (input, "applied"))
{
show_applied_info = 1;
- unformat (input, "sw_if_index %u", &sw_if_index);
+ unformat (input, "lc_index %u", &lc_index);
}
else if (unformat (input, "mask"))
{
if (show_acl_hash_info)
acl_plugin_show_tables_acl_hash_info (acl_index);
if (show_applied_info)
- acl_plugin_show_tables_applied_info (sw_if_index);
+ acl_plugin_show_tables_applied_info (lc_index);
if (show_bihash)
acl_plugin_show_tables_bihash (show_bihash_verbose);
VLIB_CLI_COMMAND (aclplugin_show_tables_command, static) = {
.path = "show acl-plugin tables",
- .short_help = "show acl-plugin tables [ acl [index N] | applied [ sw_if_index N ] | mask | hash [verbose N] ]",
+ .short_help = "show acl-plugin tables [ acl [index N] | applied [ lc_index N ] | mask | hash [verbose N] ]",
.function = acl_show_aclplugin_tables_fn,
};
u32 conn_table_hash_buckets;
u32 conn_table_hash_memory_size;
u32 conn_table_max_entries;
- u32 main_heap_size;
- u32 hash_heap_size;
+ uword main_heap_size;
+ 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)
{
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))
+ else
+ if (unformat
+ (input, "main heap size %U", unformat_memory_size,
+ &main_heap_size))
am->acl_mheap_size = main_heap_size;
- else if (unformat (input, "hash lookup heap size %d", &hash_heap_size))
+ else
+ if (unformat
+ (input, "hash lookup heap size %U", unformat_memory_size,
+ &hash_heap_size))
am->hash_lookup_mheap_size = hash_heap_size;
else if (unformat (input, "hash lookup hash buckets %d",
&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 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);
acl_setup_fa_nodes ();
- am->acl_mheap_size = ACL_FA_DEFAULT_HEAP_SIZE;
+ am->acl_mheap_size = 0; /* auto size when initializing */
am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE;
am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
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);
{
/* use the new fancy hash-based matching */
am->use_hash_acl_matching = 1;
- am->interface_acl_user_id =
- acl_plugin_register_user_module ("interface ACL", "sw_if_index",
- "is_input");
+ am->interface_acl_user_id = ~0; /* defer till the first use */
return error;
}