/* * Copyright (c) 2018 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <vnet/ipsec/ipsec.h> #include <vnet/ipsec/ipsec_sa.h> #include <vnet/ipsec/ipsec_output.h> static clib_error_t * test_ipsec_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { u64 seq_num; u32 sa_id; sa_id = ~0; seq_num = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "sa %d", &sa_id)) ; else if (unformat (input, "seq 0x%llx", &seq_num)) ; else break; } if (~0 != sa_id) { ipsec_sa_t *sa; u32 sa_index; sa_index = ipsec_sa_find_and_lock (sa_id); sa = ipsec_sa_get (sa_index); sa->seq = seq_num & 0xffffffff; sa->seq_hi = seq_num >> 32; ipsec_sa_unlock (sa_index); } else { return clib_error_return (0, "unknown SA `%U'", format_unformat_error, input); } return (NULL); } static clib_error_t * test_ipsec_spd_outbound_perf_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) { clib_error_t *err = 0; ipsec_crypto_alg_t crypto_alg = IPSEC_CRYPTO_ALG_AES_GCM_128; ipsec_integ_alg_t integ_alg = IPSEC_INTEG_ALG_NONE; ipsec_protocol_t proto = IPSEC_PROTOCOL_ESP; ipsec_sa_flags_t sa_flags = IPSEC_SA_FLAG_NONE; ipsec_key_t ck = { 0 }; u8 key_data[] = { 31, 32, 33, 34, 35, 36, 37, 38, 39, 30, 31, 32, 33, 34, 35, 36 }; ipsec_mk_key (&ck, key_data, 16); ipsec_key_t ik = { 0 }; u32 sa_id = 123456, spi = 654321, salt = 1234, sai; u16 udp_src = IPSEC_UDP_PORT_NONE, udp_dst = IPSEC_UDP_PORT_NONE; tunnel_t tun = {}; /* SPD policy */ ipsec_main_t *im = &ipsec_main; ipsec_policy_t *p0 = NULL; ipsec_spd_t *spd0; uword *pp; u32 stat_index, spd_idx, spd_id = 1; int is_add = 1; int rv; ipsec_policy_t *p_vec = NULL; u64 i; u64 flows = 100; u64 t_add_0 = 0; u64 t_add_1 = 0; u64 t_add = 0; u64 t_look_0 = 0; u64 t_look_1 = 0; u64 t_look = 0; u8 flow_cache_enabled = im->output_flow_cache_flag; u32 count_cached = 0; u32 count_slow_path = 0; u32 seed = random_default_seed (); u32 *rand_val = NULL; u32 ip4_start; #define BURST_MAX_SIZE 256 ipsec_policy_t *policies[BURST_MAX_SIZE]; ipsec4_spd_5tuple_t ip4_5tuples[BURST_MAX_SIZE]; u32 burst_size = 10; int burst_enabled = 0; u64 t0 = clib_cpu_time_now (); u64 t1 = 0; u32 k = 0, m; u64 burst_counter = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "flows %d", &flows)) ; else if (unformat (input, "burst %d", &burst_size)) { if (burst_size == 0) burst_enabled = 0; else { burst_enabled = 1; burst_size = clib_min (burst_size, BURST_MAX_SIZE); } } else break; } vlib_cli_output (vm, "Create env:"); /* creating a new SA */ rv = ipsec_sa_add_and_lock (sa_id, spi, proto, crypto_alg, &ck, integ_alg, &ik, sa_flags, clib_host_to_net_u32 (salt), udp_src, udp_dst, &tun, &sai); if (rv) { err = clib_error_return (0, "create sa failure"); goto done; } else vlib_cli_output (vm, "\tAdd a new SA"); /* creating a new SPD */ rv = ipsec_add_del_spd (vm, spd_id, is_add); if (rv) { err = clib_error_return (0, "create spd failure"); goto done; } else vlib_cli_output (vm, "\tAdd a new SPD"); /* vector for spd_policy */ vec_validate (p_vec, flows + 1); vec_validate (rand_val, flows + 1); /* fill spd policy */ for (i = 0; i < flows; i++) { rand_val[i] = random_u32 (&seed) % flows; p_vec[i].type = IPSEC_SPD_POLICY_IP4_OUTBOUND; p_vec[i].priority = flows - i; p_vec[i].policy = IPSEC_POLICY_ACTION_PROTECT; p_vec[i].id = spd_id; p_vec[i].sa_id = sa_id; p_vec[i].protocol = IP_PROTOCOL_UDP; p_vec[i].lport.start = 1; p_vec[i].lport.stop = 1; p_vec[i].rport.start = 1; p_vec[i].rport.stop = 1; /* address: 1.0.0.0 as u32 */ ip4_start = 16777216; p_vec[i].laddr.start.ip4.data_u32 = clib_host_to_net_u32 (ip4_start + i * 32); p_vec[i].laddr.stop.ip4.data_u32 = clib_host_to_net_u32 (ip4_start + i * 32); p_vec[i].raddr.start.ip4.data_u32 = clib_host_to_net_u32 (ip4_start + i * 32); p_vec[i].raddr.stop.ip4.data_u32 = clib_host_to_net_u32 (ip4_start + i * 32); } vlib_cli_output (vm, "Add SPD Policy"); t_add_0 = clib_cpu_time_now (); for (i = 0; i < flows; i++) { rv = ipsec_add_del_policy (vm, &p_vec[i], is_add, &stat_index); if (rv) { clib_warning ("No add SPD Policy: %u", stat_index); err = clib_error_return (0, "add SPD Policy failure"); goto done; } } t_add_1 = clib_cpu_time_now (); pp = hash_get (im->spd_index_by_spd_id, spd_id); spd_idx = pp[0]; spd0 = pool_elt_at_index (im->spds, spd_idx); vlib_cli_output (vm, "Lookup SPD Policy"); u64 j = 0; u64 n_lookup = 1000 * 1000; t_look_0 = clib_cpu_time_now (); for (i = 0; i < n_lookup; i++) { if (flows == j) j = 0; p0 = NULL; if (flow_cache_enabled) { p0 = ipsec4_out_spd_find_flow_cache_entry ( im, 0, clib_net_to_host_u32 (ip4_start + ((flows - 1) - rand_val[j]) * 32), clib_net_to_host_u32 (ip4_start + ((flows - 1) - rand_val[j]) * 32), clib_net_to_host_u16 (1), clib_net_to_host_u16 (1)); if (p0) count_cached++; } if (p0 == NULL) { if (burst_enabled) { u32 src_addr = (ip4_start + ((flows - 1) - rand_val[j]) * 32); u32 dst_addr = (ip4_start + ((flows - 1) - rand_val[j]) * 32); ipsec4_spd_5tuple_t ip4_5tuple = { .ip4_addr = { (ip4_address_t) src_addr, (ip4_address_t) dst_addr }, .port = { 1, 1 }, .proto = IP_PROTOCOL_UDP }; if (k == burst_size) { k = 0; clib_memset (policies, 0, burst_size * sizeof (ipsec_policy_t *)); burst_counter += ipsec_output_policy_match_n ( spd0, ip4_5tuples, policies, burst_size, flow_cache_enabled); for (m = 0; m < burst_size; m++) { ASSERT (policies[m] != 0); } } clib_memcpy (ip4_5tuples + k, &ip4_5tuple, sizeof (ipsec4_spd_5tuple_t)); k++; } else { p0 = ipsec_output_policy_match ( spd0, IP_PROTOCOL_UDP, (ip4_start + ((flows - 1) - rand_val[j]) * 32), (ip4_start + ((flows - 1) - rand_val[j]) * 32), 1, 1, flow_cache_enabled); } count_slow_path++; } j++; if (!burst_enabled) ASSERT (p0 != 0); } if (burst_enabled && k > 0) { clib_memset (policies, 0, k * sizeof (ipsec_policy_t *)); burst_counter += ipsec_output_policy_match_n ( spd0, ip4_5tuples, policies, k, flow_cache_enabled); for (m = 0; m < k; m++) { ASSERT (policies[m] != 0); } } t_look_1 = clib_cpu_time_now (); t_add = (t_add_1 - t_add_0); t_look = (t_look_1 - t_look_0); vlib_cli_output (vm, "Results Outbound:"); vlib_cli_output (vm, "Time to add %u flows: \t\t%12.10f s", flows, (t_add / vm->clib_time.clocks_per_second)); vlib_cli_output (vm, "Average time to add 1 flow: \t\t%12.10f s", ((t_add / flows) / vm->clib_time.clocks_per_second)); vlib_cli_output (vm, "Time to lookup %u flows: \t\t%12.10f s", flows, (t_look / vm->clib_time.clocks_per_second)); vlib_cli_output (vm, "Average time to lookup 1 flow: \t\t%12.10f s", ((t_look / n_lookup) / vm->clib_time.clocks_per_second)); vlib_cli_output (vm, " "); vlib_cli_output (vm, "Cycle CPU to add %u flows: \t\t%32lu cycles", flows, t_add); vlib_cli_output (vm, "Average cycle CPU to add 1 flow: \t%32lu cycles", t_add / flows); vlib_cli_output (vm, "Cycle CPU to lookup %u flows: \t%32lu cycles", flows, t_look); vlib_cli_output (vm, "Average cycle CPU to lookup 1 flow: \t%32lu cycles", t_look / n_lookup); if (count_slow_path || count_cached) vlib_cli_output ( vm, "flow cache hit rate: \t\t%12.10f\n cached: \t%d\n slow_path: \t%d", ((float) count_cached) / ((float) count_cached + count_slow_path), count_cached, count_slow_path); if (burst_enabled) vlib_cli_output (vm, "Total number of packets matched in bursts: \t\t%d\n", burst_counter); done: vlib_cli_output (vm, "Cleaning:"); /* delete SPD policy */ is_add = 0; for (i = 0; i < flows; i++) { rv = ipsec_add_del_policy (vm, &p_vec[i], is_add, &stat_index); if (rv) { clib_warning ("No delete SPD Policy: %u", i); err = clib_error_return (0, "delete SPD Policy failure"); } } vlib_cli_output (vm, "\tDelete all SPD Policy"); /* delete SPD */ rv = ipsec_add_del_spd (vm, spd_id, is_add); if (rv) { err = clib_error_return (0, "delete spd failure"); } else vlib_cli_output (vm, "\tDelete SPD"); /* delete SA */ rv = ipsec_sa_unlock_id (sa_id); if (rv) { err = clib_error_return (0, "delete sa failure"); } else vlib_cli_output (vm, "\tDelete SA"); t1 = clib_cpu_time_now (); vlib_cli_output (vm, "Time for test: \t%12.10f s", ((t1 - t0) / vm->clib_time.clocks_per_second)); vec_free (p_vec); vlib_cli_output (vm, "End"); return (err); } VLIB_CLI_COMMAND (test_ipsec_spd_perf_command, static) = { .path = "test ipsec_spd_outbound_perf", .short_help = "test ipsec_spd_outbound_perf flows <n_flows>", .function = test_ipsec_spd_outbound_perf_command_fn, }; /* *INDENT-OFF* */ VLIB_CLI_COMMAND (test_ipsec_command, static) = { .path = "test ipsec", .short_help = "test ipsec sa <ID> seq-num <VALUE>", .function = test_ipsec_command_fn, }; /* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */