+ if ((eh < 256) && (value < 2))
+ {
+ am->fa_ipv6_known_eh_bitmap =
+ clib_bitmap_set (am->fa_ipv6_known_eh_bitmap, eh, value);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+static clib_error_t *
+acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
+{
+ acl_main_t *am = &acl_main;
+ if (0 == am->acl_mheap)
+ {
+ /* ACL heap is not initialized, so definitely nothing to do. */
+ return 0;
+ }
+ if (0 == is_add)
+ {
+ vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
+ ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX,
+ sw_if_index);
+ /* also unapply any ACLs in case the users did not do so. */
+ macip_acl_interface_del_acl (am, sw_if_index);
+ acl_interface_reset_inout_acls (sw_if_index, 0);
+ acl_interface_reset_inout_acls (sw_if_index, 1);
+ }
+ return 0;
+}
+
+VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
+
+
+
+static clib_error_t *
+acl_set_aclplugin_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ clib_error_t *error = 0;
+ u32 timeout = 0;
+ u32 val = 0;
+ u32 eh_val = 0;
+ uword memory_size = 0;
+ acl_main_t *am = &acl_main;
+
+ if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val))
+ {
+ if (!acl_set_skip_ipv6_eh (eh_val, val))
+ {
+ error = clib_error_return (0, "expecting eh=0..255, value=0..1");
+ }
+ goto done;
+ }
+ if (unformat (input, "use-hash-acl-matching %u", &val))
+ {
+ am->use_hash_acl_matching = (val != 0);
+ goto done;
+ }
+ if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
+ {
+ am->l4_match_nonfirst_fragment = (val != 0);
+ goto done;
+ }
+ if (unformat (input, "heap"))
+ {
+ if (unformat (input, "main"))
+ {
+ if (unformat (input, "validate %u", &val))
+ acl_plugin_acl_set_validate_heap (am, val);
+ else if (unformat (input, "trace %u", &val))
+ acl_plugin_acl_set_trace_heap (am, val);
+ goto done;
+ }
+ else if (unformat (input, "hash"))
+ {
+ if (unformat (input, "validate %u", &val))
+ acl_plugin_hash_acl_set_validate_heap (am, val);
+ else if (unformat (input, "trace %u", &val))
+ acl_plugin_hash_acl_set_trace_heap (am, val);
+ goto done;
+ }
+ goto done;
+ }
+ if (unformat (input, "session"))
+ {
+ if (unformat (input, "table"))
+ {
+ /* The commands here are for tuning/testing. No user-serviceable parts inside */
+ if (unformat (input, "max-entries"))
+ {
+ if (!unformat (input, "%u", &val))
+ {
+ error = clib_error_return (0,
+ "expecting maximum number of entries, got `%U`",
+ format_unformat_error, input);
+ goto done;
+ }
+ else
+ {
+ acl_set_session_max_entries (val);
+ goto done;
+ }
+ }
+ if (unformat (input, "hash-table-buckets"))
+ {
+ if (!unformat (input, "%u", &val))
+ {
+ error = clib_error_return (0,
+ "expecting maximum number of hash table buckets, got `%U`",
+ format_unformat_error, input);
+ goto done;
+ }
+ else
+ {
+ am->fa_conn_table_hash_num_buckets = val;
+ goto done;
+ }
+ }
+ if (unformat (input, "hash-table-memory"))
+ {
+ if (!unformat (input, "%U", unformat_memory_size, &memory_size))
+ {
+ error = clib_error_return (0,
+ "expecting maximum amount of hash table memory, got `%U`",
+ format_unformat_error, input);
+ goto done;
+ }
+ else
+ {
+ am->fa_conn_table_hash_memory_size = memory_size;
+ goto done;
+ }
+ }
+ if (unformat (input, "event-trace"))
+ {
+ if (!unformat (input, "%u", &val))
+ {
+ error = clib_error_return (0,
+ "expecting trace level, got `%U`",
+ format_unformat_error, input);
+ goto done;
+ }
+ else
+ {
+ am->trace_sessions = val;
+ goto done;
+ }
+ }
+ goto done;
+ }
+ if (unformat (input, "timeout"))
+ {
+ if (unformat (input, "udp"))
+ {
+ if (unformat (input, "idle"))
+ {
+ if (!unformat (input, "%u", &timeout))
+ {
+ error = clib_error_return (0,
+ "expecting timeout value in seconds, got `%U`",
+ format_unformat_error,
+ input);
+ goto done;
+ }
+ else
+ {
+ acl_set_timeout_sec (ACL_TIMEOUT_UDP_IDLE, timeout);
+ goto done;
+ }
+ }
+ }
+ if (unformat (input, "tcp"))
+ {
+ if (unformat (input, "idle"))
+ {
+ if (!unformat (input, "%u", &timeout))
+ {
+ error = clib_error_return (0,
+ "expecting timeout value in seconds, got `%U`",
+ format_unformat_error,
+ input);
+ goto done;
+ }
+ else
+ {
+ acl_set_timeout_sec (ACL_TIMEOUT_TCP_IDLE, timeout);
+ goto done;
+ }
+ }
+ if (unformat (input, "transient"))
+ {
+ if (!unformat (input, "%u", &timeout))
+ {
+ error = clib_error_return (0,
+ "expecting timeout value in seconds, got `%U`",
+ format_unformat_error,
+ input);
+ goto done;
+ }
+ else
+ {
+ acl_set_timeout_sec (ACL_TIMEOUT_TCP_TRANSIENT,
+ timeout);
+ goto done;
+ }
+ }
+ }
+ goto done;
+ }
+ }
+done:
+ return error;
+}
+
+static u8 *
+my_format_mac_address (u8 * s, va_list * args)
+{
+ u8 *a = va_arg (*args, u8 *);
+ return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
+ a[0], a[1], a[2], a[3], a[4], a[5]);
+}
+
+static inline u8 *
+my_macip_acl_rule_t_pretty_format (u8 * out, va_list * args)
+{
+ macip_acl_rule_t *a = va_arg (*args, macip_acl_rule_t *);
+
+ out = format (out, "%s action %d ip %U/%d mac %U mask %U",
+ a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit,
+ format_ip46_address, &a->src_ip_addr,
+ a->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
+ a->src_prefixlen,
+ my_format_mac_address, a->src_mac,
+ my_format_mac_address, a->src_mac_mask);
+ return (out);
+}
+
+static void
+macip_acl_print (acl_main_t * am, u32 macip_acl_index)
+{
+ vlib_main_t *vm = am->vlib_main;
+ int i;
+
+ /* Don't attempt to show the ACLs that do not exist */
+ if (pool_is_free_index (am->macip_acls, macip_acl_index))
+ return;
+
+ /* Don't try to print someone else's memory */
+ if (macip_acl_index > vec_len (am->macip_acls))
+ return;
+
+ macip_acl_list_t *a = vec_elt_at_index (am->macip_acls, macip_acl_index);
+ int free_pool_slot = pool_is_free_index (am->macip_acls, macip_acl_index);
+
+ vlib_cli_output (vm,
+ "MACIP acl_index: %d, count: %d (true len %d) tag {%s} is free pool slot: %d\n",
+ macip_acl_index, a->count, vec_len (a->rules), a->tag,
+ free_pool_slot);
+ vlib_cli_output (vm,
+ " ip4_table_index %d, ip6_table_index %d, l2_table_index %d\n",
+ a->ip4_table_index, a->ip6_table_index, a->l2_table_index);
+ vlib_cli_output (vm,
+ " out_ip4_table_index %d, out_ip6_table_index %d, out_l2_table_index %d\n",
+ a->out_ip4_table_index, a->out_ip6_table_index,
+ a->out_l2_table_index);
+ for (i = 0; i < vec_len (a->rules); i++)
+ vlib_cli_output (vm, " rule %d: %U\n", i,
+ my_macip_acl_rule_t_pretty_format,
+ vec_elt_at_index (a->rules, i));
+
+}
+
+static clib_error_t *
+acl_show_aclplugin_macip_acl_fn (vlib_main_t * vm,
+ unformat_input_t *
+ input, vlib_cli_command_t * cmd)
+{
+ clib_error_t *error = 0;
+ acl_main_t *am = &acl_main;
+ int i;
+ for (i = 0; i < vec_len (am->macip_acls); i++)
+ macip_acl_print (am, i);
+ return error;
+}
+
+static clib_error_t *
+acl_show_aclplugin_macip_interface_fn (vlib_main_t * vm,
+ unformat_input_t *
+ input, vlib_cli_command_t * cmd)
+{
+ clib_error_t *error = 0;
+ acl_main_t *am = &acl_main;
+ int i;
+ for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
+ {
+ vlib_cli_output (vm, " sw_if_index %d: %d\n", i,
+ vec_elt (am->macip_acl_by_sw_if_index, i));
+ }
+ return error;
+}
+
+#define PRINT_AND_RESET(vm, out0) do { vlib_cli_output(vm, "%v", out0); vec_reset_length(out0); } while(0)
+static void
+acl_print_acl (vlib_main_t * vm, acl_main_t * am, int acl_index)
+{
+ acl_rule_t *r;
+ u8 *out0 = format (0, "acl-index %u count %u tag {%s}\n", acl_index,
+ am->acls[acl_index].count, am->acls[acl_index].tag);
+ int j;
+ PRINT_AND_RESET (vm, out0);
+ for (j = 0; j < am->acls[acl_index].count; j++)
+ {
+ r = &am->acls[acl_index].rules[j];
+ out0 = format (out0, " %4d: %s ", j, r->is_ipv6 ? "ipv6" : "ipv4");
+ out0 = format_acl_action (out0, r->is_permit);
+ out0 = format (out0, " src %U/%d", format_ip46_address, &r->src,
+ r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
+ r->src_prefixlen);
+ out0 =
+ format (out0, " dst %U/%d", format_ip46_address, &r->dst,
+ r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4, r->dst_prefixlen);
+ out0 = format (out0, " proto %d", r->proto);
+ out0 = format (out0, " sport %d", r->src_port_or_type_first);
+ if (r->src_port_or_type_first != r->src_port_or_type_last)
+ {
+ out0 = format (out0, "-%d", r->src_port_or_type_last);
+ }
+ out0 = format (out0, " dport %d", r->dst_port_or_code_first);
+ if (r->dst_port_or_code_first != r->dst_port_or_code_last)
+ {
+ out0 = format (out0, "-%d", r->dst_port_or_code_last);
+ }
+ if (r->tcp_flags_mask || r->tcp_flags_value)
+ {
+ out0 =
+ format (out0, " tcpflags %d mask %d", r->tcp_flags_value,
+ r->tcp_flags_mask);
+ }
+ out0 = format (out0, "\n");
+ PRINT_AND_RESET (vm, out0);
+ }
+}
+
+#undef PRINT_AND_RESET
+
+static void
+acl_plugin_show_acl (acl_main_t * am, u32 acl_index)
+{
+ u32 i;
+ vlib_main_t *vm = am->vlib_main;
+
+ for (i = 0; i < vec_len (am->acls); i++)
+ {
+ if (acl_is_not_defined (am, i))
+ {
+ /* don't attempt to show the ACLs that do not exist */
+ continue;
+ }
+ if ((acl_index != ~0) && (acl_index != i))
+ {
+ continue;
+ }
+ acl_print_acl (vm, am, i);
+
+ if (i < vec_len (am->input_sw_if_index_vec_by_acl))
+ {
+ vlib_cli_output (vm, " applied inbound on sw_if_index: %U\n",
+ format_vec32, am->input_sw_if_index_vec_by_acl[i],
+ "%d");
+ }
+ if (i < vec_len (am->output_sw_if_index_vec_by_acl))
+ {
+ vlib_cli_output (vm, " applied outbound on sw_if_index: %U\n",
+ format_vec32, am->output_sw_if_index_vec_by_acl[i],
+ "%d");
+ }
+ }
+}
+
+static clib_error_t *
+acl_show_aclplugin_acl_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ clib_error_t *error = 0;
+ acl_main_t *am = &acl_main;
+
+ u32 acl_index = ~0;
+ (void) unformat (input, "index %u", &acl_index);
+
+ acl_plugin_show_acl (am, acl_index);
+ return error;
+}
+
+static void
+acl_plugin_show_interface (acl_main_t * am, u32 sw_if_index, int show_acl)
+{
+ vlib_main_t *vm = am->vlib_main;
+ u32 swi;
+ u32 *pj;
+ for (swi = 0; (swi < vec_len (am->input_acl_vec_by_sw_if_index)) ||
+ (swi < vec_len (am->output_acl_vec_by_sw_if_index)); swi++)
+ {
+ /* if we need a particular interface, skip all the others */
+ if ((sw_if_index != ~0) && (sw_if_index != swi))
+ continue;
+
+ vlib_cli_output (vm, "sw_if_index %d:\n", swi);
+
+ if (intf_has_etype_whitelist (am, swi, 1))
+ {
+ vlib_cli_output (vm, " input etype whitelist: %U", format_vec16,
+ am->input_etype_whitelist_by_sw_if_index[swi],
+ "%04x");
+ }
+ if (intf_has_etype_whitelist (am, swi, 0))
+ {
+ vlib_cli_output (vm, " output etype whitelist: %U", format_vec16,
+ am->output_etype_whitelist_by_sw_if_index[swi],
+ "%04x");
+ }
+
+ if ((swi < vec_len (am->input_acl_vec_by_sw_if_index)) &&
+ (vec_len (am->input_acl_vec_by_sw_if_index[swi]) > 0))
+ {
+ vlib_cli_output (vm, " input acl(s): %U", format_vec32,
+ am->input_acl_vec_by_sw_if_index[swi], "%d");
+ if (show_acl)
+ {
+ vlib_cli_output (vm, "\n");
+ vec_foreach (pj, am->input_acl_vec_by_sw_if_index[swi])
+ {
+ acl_print_acl (vm, am, *pj);
+ }
+ vlib_cli_output (vm, "\n");
+ }
+ }
+
+ if ((swi < vec_len (am->output_acl_vec_by_sw_if_index)) &&
+ (vec_len (am->output_acl_vec_by_sw_if_index[swi]) > 0))
+ {
+ vlib_cli_output (vm, " output acl(s): %U", format_vec32,
+ am->output_acl_vec_by_sw_if_index[swi], "%d");
+ if (show_acl)
+ {
+ vlib_cli_output (vm, "\n");
+ vec_foreach (pj, am->output_acl_vec_by_sw_if_index[swi])
+ {
+ acl_print_acl (vm, am, *pj);
+ }
+ vlib_cli_output (vm, "\n");
+ }
+ }
+ }
+
+}
+
+
+static clib_error_t *
+acl_show_aclplugin_decode_5tuple_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ clib_error_t *error = 0;
+ u64 five_tuple[6] = { 0, 0, 0, 0, 0, 0 };
+
+ if (unformat
+ (input, "%llx %llx %llx %llx %llx %llx", &five_tuple[0], &five_tuple[1],
+ &five_tuple[2], &five_tuple[3], &five_tuple[4], &five_tuple[5]))
+ vlib_cli_output (vm, "5-tuple structure decode: %U\n\n",
+ format_acl_plugin_5tuple, five_tuple);
+ else
+ error = clib_error_return (0, "expecting 6 hex integers");
+ return error;
+}
+
+
+static clib_error_t *
+acl_show_aclplugin_interface_fn (vlib_main_t * vm,
+ unformat_input_t *
+ input, vlib_cli_command_t * cmd)
+{
+ clib_error_t *error = 0;
+ acl_main_t *am = &acl_main;
+
+ u32 sw_if_index = ~0;
+ (void) unformat (input, "sw_if_index %u", &sw_if_index);
+ int show_acl = unformat (input, "acl");
+
+ acl_plugin_show_interface (am, sw_if_index, show_acl);
+ return error;
+}
+
+static clib_error_t *
+acl_show_aclplugin_memory_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ clib_error_t *error = 0;
+ acl_main_t *am = &acl_main;
+
+ vlib_cli_output (vm, "ACL plugin main heap statistics:\n");
+ if (am->acl_mheap)
+ {
+ vlib_cli_output (vm, " %U\n", format_mheap, am->acl_mheap, 1);
+ }
+ else
+ {
+ vlib_cli_output (vm, " Not initialized\n");
+ }
+ vlib_cli_output (vm, "ACL hash lookup support heap statistics:\n");
+ if (am->hash_lookup_mheap)
+ {
+ vlib_cli_output (vm, " %U\n", format_mheap, am->hash_lookup_mheap, 1);
+ }
+ else
+ {
+ vlib_cli_output (vm, " Not initialized\n");
+ }
+ return error;
+}
+
+static void
+acl_plugin_show_sessions (acl_main_t * am,
+ u32 show_session_thread_id,
+ u32 show_session_session_index)
+{
+ vlib_main_t *vm = am->vlib_main;
+ u16 wk;
+ vnet_interface_main_t *im = &am->vnet_main->interface_main;
+ vnet_sw_interface_t *swif;
+
+ {
+ u64 n_adds = am->fa_session_total_adds;
+ u64 n_dels = am->fa_session_total_dels;
+ vlib_cli_output (vm, "Sessions total: add %lu - del %lu = %lu", n_adds,
+ n_dels, n_adds - n_dels);
+ }
+ vlib_cli_output (vm, "\n\nPer-thread data:");
+ for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
+ {
+ acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
+ vlib_cli_output (vm, "Thread #%d:", wk);
+ if (show_session_thread_id == wk
+ && show_session_session_index < pool_len (pw->fa_sessions_pool))
+ {
+ vlib_cli_output (vm, " session index %u:",
+ show_session_session_index);
+ fa_session_t *sess =
+ pw->fa_sessions_pool + show_session_session_index;
+ u64 *m = (u64 *) & sess->info;
+ vlib_cli_output (vm,
+ " info: %016llx %016llx %016llx %016llx %016llx %016llx",
+ m[0], m[1], m[2], m[3], m[4], m[5]);
+ vlib_cli_output (vm, " sw_if_index: %u", sess->sw_if_index);
+ vlib_cli_output (vm, " tcp_flags_seen: %x",
+ sess->tcp_flags_seen.as_u16);
+ vlib_cli_output (vm, " last active time: %lu",
+ sess->last_active_time);
+ vlib_cli_output (vm, " thread index: %u", sess->thread_index);
+ vlib_cli_output (vm, " link enqueue time: %lu",
+ sess->link_enqueue_time);
+ vlib_cli_output (vm, " link next index: %u",
+ sess->link_next_idx);
+ vlib_cli_output (vm, " link prev index: %u",
+ sess->link_prev_idx);
+ vlib_cli_output (vm, " link list id: %u", sess->link_list_id);
+ }
+ vlib_cli_output (vm, " connection add/del stats:", wk);
+ pool_foreach (swif, im->sw_interfaces, (
+ {
+ u32 sw_if_index =
+ swif->sw_if_index;
+ u64 n_adds =
+ sw_if_index <
+ vec_len
+ (pw->fa_session_adds_by_sw_if_index)
+ ?
+ pw->fa_session_adds_by_sw_if_index
+ [sw_if_index] : 0;
+ u64 n_dels =
+ sw_if_index <
+ vec_len
+ (pw->fa_session_dels_by_sw_if_index)
+ ?
+ pw->fa_session_dels_by_sw_if_index
+ [sw_if_index] : 0;
+ vlib_cli_output (vm,
+ " sw_if_index %d: add %lu - del %lu = %lu",
+ sw_if_index,
+ n_adds,
+ n_dels,
+ n_adds -
+ n_dels);
+ }
+ ));
+
+ vlib_cli_output (vm, " connection timeout type lists:", wk);
+ u8 tt = 0;
+ for (tt = 0; tt < ACL_N_TIMEOUTS; tt++)
+ {
+ u32 head_session_index = pw->fa_conn_list_head[tt];
+ vlib_cli_output (vm, " fa_conn_list_head[%d]: %d", tt,
+ head_session_index);
+ if (~0 != head_session_index)
+ {
+ fa_session_t *sess = pw->fa_sessions_pool + head_session_index;
+ vlib_cli_output (vm, " last active time: %lu",
+ sess->last_active_time);
+ vlib_cli_output (vm, " link enqueue time: %lu",
+ sess->link_enqueue_time);
+ }
+ }