Line data Source code
1 : /*
2 : * Copyright (c) 2018 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <vnet/ipsec/ipsec.h>
17 : #include <vnet/ipsec/ipsec_sa.h>
18 : #include <vnet/ipsec/ipsec_output.h>
19 :
20 : static clib_error_t *
21 158 : test_ipsec_command_fn (vlib_main_t * vm,
22 : unformat_input_t * input, vlib_cli_command_t * cmd)
23 : {
24 : u64 seq_num;
25 : u32 sa_id;
26 :
27 158 : sa_id = ~0;
28 158 : seq_num = 0;
29 :
30 474 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
31 : {
32 316 : if (unformat (input, "sa %d", &sa_id))
33 : ;
34 158 : else if (unformat (input, "seq 0x%llx", &seq_num))
35 : ;
36 : else
37 0 : break;
38 : }
39 :
40 158 : if (~0 != sa_id)
41 : {
42 : ipsec_sa_t *sa;
43 : u32 sa_index;
44 :
45 158 : sa_index = ipsec_sa_find_and_lock (sa_id);
46 158 : sa = ipsec_sa_get (sa_index);
47 :
48 158 : sa->seq = seq_num & 0xffffffff;
49 158 : sa->seq_hi = seq_num >> 32;
50 :
51 158 : ipsec_sa_unlock (sa_index);
52 : }
53 : else
54 : {
55 0 : return clib_error_return (0, "unknown SA `%U'",
56 : format_unformat_error, input);
57 : }
58 :
59 158 : return (NULL);
60 : }
61 :
62 : static clib_error_t *
63 0 : test_ipsec_spd_outbound_perf_command_fn (vlib_main_t *vm,
64 : unformat_input_t *input,
65 : vlib_cli_command_t *cmd)
66 : {
67 0 : clib_error_t *err = 0;
68 0 : ipsec_crypto_alg_t crypto_alg = IPSEC_CRYPTO_ALG_AES_GCM_128;
69 0 : ipsec_integ_alg_t integ_alg = IPSEC_INTEG_ALG_NONE;
70 0 : ipsec_protocol_t proto = IPSEC_PROTOCOL_ESP;
71 0 : ipsec_sa_flags_t sa_flags = IPSEC_SA_FLAG_NONE;
72 0 : ipsec_key_t ck = { 0 };
73 0 : u8 key_data[] = { 31, 32, 33, 34, 35, 36, 37, 38,
74 : 39, 30, 31, 32, 33, 34, 35, 36 };
75 0 : ipsec_mk_key (&ck, key_data, 16);
76 0 : ipsec_key_t ik = { 0 };
77 0 : u32 sa_id = 123456, spi = 654321, salt = 1234, sai;
78 0 : u16 udp_src = IPSEC_UDP_PORT_NONE, udp_dst = IPSEC_UDP_PORT_NONE;
79 0 : tunnel_t tun = {};
80 :
81 : /* SPD policy */
82 0 : ipsec_main_t *im = &ipsec_main;
83 0 : ipsec_policy_t *p0 = NULL;
84 : ipsec_spd_t *spd0;
85 : uword *pp;
86 0 : u32 stat_index, spd_idx, spd_id = 1;
87 0 : int is_add = 1;
88 : int rv;
89 0 : ipsec_policy_t *p_vec = NULL;
90 : u64 i;
91 0 : u64 flows = 100;
92 :
93 0 : u64 t_add_0 = 0;
94 0 : u64 t_add_1 = 0;
95 0 : u64 t_add = 0;
96 0 : u64 t_look_0 = 0;
97 0 : u64 t_look_1 = 0;
98 0 : u64 t_look = 0;
99 0 : u8 flow_cache_enabled = im->output_flow_cache_flag;
100 0 : u32 count_cached = 0;
101 0 : u32 count_slow_path = 0;
102 0 : u32 seed = random_default_seed ();
103 0 : u32 *rand_val = NULL;
104 : u32 ip4_start;
105 : #define BURST_MAX_SIZE 256
106 : ipsec_policy_t *policies[BURST_MAX_SIZE];
107 : ipsec4_spd_5tuple_t ip4_5tuples[BURST_MAX_SIZE];
108 0 : u32 burst_size = 10;
109 0 : int burst_enabled = 0;
110 0 : u64 t0 = clib_cpu_time_now ();
111 0 : u64 t1 = 0;
112 0 : u32 k = 0, m;
113 0 : u64 burst_counter = 0;
114 :
115 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
116 : {
117 0 : if (unformat (input, "flows %d", &flows))
118 : ;
119 0 : else if (unformat (input, "burst %d", &burst_size))
120 : {
121 0 : if (burst_size == 0)
122 0 : burst_enabled = 0;
123 : else
124 : {
125 0 : burst_enabled = 1;
126 0 : burst_size = clib_min (burst_size, BURST_MAX_SIZE);
127 : }
128 : }
129 : else
130 0 : break;
131 : }
132 :
133 0 : vlib_cli_output (vm, "Create env:");
134 : /* creating a new SA */
135 0 : rv = ipsec_sa_add_and_lock (sa_id, spi, proto, crypto_alg, &ck, integ_alg,
136 : &ik, sa_flags, clib_host_to_net_u32 (salt),
137 : udp_src, udp_dst, &tun, &sai);
138 0 : if (rv)
139 : {
140 0 : err = clib_error_return (0, "create sa failure");
141 0 : goto done;
142 : }
143 : else
144 0 : vlib_cli_output (vm, "\tAdd a new SA");
145 :
146 : /* creating a new SPD */
147 0 : rv = ipsec_add_del_spd (vm, spd_id, is_add);
148 0 : if (rv)
149 : {
150 0 : err = clib_error_return (0, "create spd failure");
151 0 : goto done;
152 : }
153 : else
154 0 : vlib_cli_output (vm, "\tAdd a new SPD");
155 :
156 : /* vector for spd_policy */
157 0 : vec_validate (p_vec, flows + 1);
158 0 : vec_validate (rand_val, flows + 1);
159 :
160 : /* fill spd policy */
161 0 : for (i = 0; i < flows; i++)
162 : {
163 0 : rand_val[i] = random_u32 (&seed) % flows;
164 :
165 0 : p_vec[i].type = IPSEC_SPD_POLICY_IP4_OUTBOUND;
166 0 : p_vec[i].priority = flows - i;
167 0 : p_vec[i].policy = IPSEC_POLICY_ACTION_PROTECT;
168 0 : p_vec[i].id = spd_id;
169 0 : p_vec[i].sa_id = sa_id;
170 0 : p_vec[i].protocol = IP_PROTOCOL_UDP;
171 0 : p_vec[i].lport.start = 1;
172 0 : p_vec[i].lport.stop = 1;
173 0 : p_vec[i].rport.start = 1;
174 0 : p_vec[i].rport.stop = 1;
175 : /* address: 1.0.0.0 as u32 */
176 0 : ip4_start = 16777216;
177 0 : p_vec[i].laddr.start.ip4.data_u32 =
178 0 : clib_host_to_net_u32 (ip4_start + i * 32);
179 0 : p_vec[i].laddr.stop.ip4.data_u32 =
180 0 : clib_host_to_net_u32 (ip4_start + i * 32);
181 0 : p_vec[i].raddr.start.ip4.data_u32 =
182 0 : clib_host_to_net_u32 (ip4_start + i * 32);
183 0 : p_vec[i].raddr.stop.ip4.data_u32 =
184 0 : clib_host_to_net_u32 (ip4_start + i * 32);
185 : }
186 :
187 0 : vlib_cli_output (vm, "Add SPD Policy");
188 0 : t_add_0 = clib_cpu_time_now ();
189 0 : for (i = 0; i < flows; i++)
190 : {
191 0 : rv = ipsec_add_del_policy (vm, &p_vec[i], is_add, &stat_index);
192 0 : if (rv)
193 : {
194 0 : clib_warning ("No add SPD Policy: %u", stat_index);
195 0 : err = clib_error_return (0, "add SPD Policy failure");
196 0 : goto done;
197 : }
198 : }
199 0 : t_add_1 = clib_cpu_time_now ();
200 :
201 0 : pp = hash_get (im->spd_index_by_spd_id, spd_id);
202 0 : spd_idx = pp[0];
203 0 : spd0 = pool_elt_at_index (im->spds, spd_idx);
204 :
205 0 : vlib_cli_output (vm, "Lookup SPD Policy");
206 0 : u64 j = 0;
207 0 : u64 n_lookup = 1000 * 1000;
208 0 : t_look_0 = clib_cpu_time_now ();
209 0 : for (i = 0; i < n_lookup; i++)
210 : {
211 0 : if (flows == j)
212 0 : j = 0;
213 :
214 0 : p0 = NULL;
215 0 : if (flow_cache_enabled)
216 : {
217 0 : p0 = ipsec4_out_spd_find_flow_cache_entry (
218 : im, 0,
219 : clib_net_to_host_u32 (ip4_start +
220 0 : ((flows - 1) - rand_val[j]) * 32),
221 : clib_net_to_host_u32 (ip4_start +
222 0 : ((flows - 1) - rand_val[j]) * 32),
223 0 : clib_net_to_host_u16 (1), clib_net_to_host_u16 (1));
224 0 : if (p0)
225 0 : count_cached++;
226 : }
227 0 : if (p0 == NULL)
228 : {
229 0 : if (burst_enabled)
230 : {
231 0 : u32 src_addr = (ip4_start + ((flows - 1) - rand_val[j]) * 32);
232 0 : u32 dst_addr = (ip4_start + ((flows - 1) - rand_val[j]) * 32);
233 0 : ipsec4_spd_5tuple_t ip4_5tuple = {
234 : .ip4_addr = { (ip4_address_t) src_addr,
235 : (ip4_address_t) dst_addr },
236 : .port = { 1, 1 },
237 : .proto = IP_PROTOCOL_UDP
238 : };
239 :
240 0 : if (k == burst_size)
241 : {
242 0 : k = 0;
243 0 : clib_memset (policies, 0,
244 : burst_size * sizeof (ipsec_policy_t *));
245 0 : burst_counter += ipsec_output_policy_match_n (
246 : spd0, ip4_5tuples, policies, burst_size,
247 : flow_cache_enabled);
248 0 : for (m = 0; m < burst_size; m++)
249 : {
250 0 : ASSERT (policies[m] != 0);
251 : }
252 : }
253 :
254 0 : clib_memcpy (ip4_5tuples + k, &ip4_5tuple,
255 : sizeof (ipsec4_spd_5tuple_t));
256 0 : k++;
257 : }
258 : else
259 : {
260 :
261 0 : p0 = ipsec_output_policy_match (
262 : spd0, IP_PROTOCOL_UDP,
263 0 : (ip4_start + ((flows - 1) - rand_val[j]) * 32),
264 0 : (ip4_start + ((flows - 1) - rand_val[j]) * 32), 1, 1,
265 : flow_cache_enabled);
266 : }
267 :
268 0 : count_slow_path++;
269 : }
270 0 : j++;
271 0 : if (!burst_enabled)
272 0 : ASSERT (p0 != 0);
273 : }
274 :
275 0 : if (burst_enabled && k > 0)
276 : {
277 0 : clib_memset (policies, 0, k * sizeof (ipsec_policy_t *));
278 0 : burst_counter += ipsec_output_policy_match_n (
279 : spd0, ip4_5tuples, policies, k, flow_cache_enabled);
280 0 : for (m = 0; m < k; m++)
281 : {
282 0 : ASSERT (policies[m] != 0);
283 : }
284 : }
285 0 : t_look_1 = clib_cpu_time_now ();
286 :
287 0 : t_add = (t_add_1 - t_add_0);
288 0 : t_look = (t_look_1 - t_look_0);
289 :
290 0 : vlib_cli_output (vm, "Results Outbound:");
291 0 : vlib_cli_output (vm, "Time to add %u flows: \t\t%12.10f s", flows,
292 0 : (t_add / vm->clib_time.clocks_per_second));
293 0 : vlib_cli_output (vm, "Average time to add 1 flow: \t\t%12.10f s",
294 0 : ((t_add / flows) / vm->clib_time.clocks_per_second));
295 0 : vlib_cli_output (vm, "Time to lookup %u flows: \t\t%12.10f s", flows,
296 0 : (t_look / vm->clib_time.clocks_per_second));
297 0 : vlib_cli_output (vm, "Average time to lookup 1 flow: \t\t%12.10f s",
298 0 : ((t_look / n_lookup) / vm->clib_time.clocks_per_second));
299 :
300 0 : vlib_cli_output (vm, " ");
301 :
302 0 : vlib_cli_output (vm, "Cycle CPU to add %u flows: \t\t%32lu cycles", flows,
303 : t_add);
304 0 : vlib_cli_output (vm, "Average cycle CPU to add 1 flow: \t%32lu cycles",
305 : t_add / flows);
306 0 : vlib_cli_output (vm, "Cycle CPU to lookup %u flows: \t%32lu cycles", flows,
307 : t_look);
308 0 : vlib_cli_output (vm, "Average cycle CPU to lookup 1 flow: \t%32lu cycles",
309 : t_look / n_lookup);
310 :
311 0 : if (count_slow_path || count_cached)
312 0 : vlib_cli_output (
313 : vm, "flow cache hit rate: \t\t%12.10f\n cached: \t%d\n slow_path: \t%d",
314 0 : ((float) count_cached) / ((float) count_cached + count_slow_path),
315 : count_cached, count_slow_path);
316 :
317 0 : if (burst_enabled)
318 0 : vlib_cli_output (vm, "Total number of packets matched in bursts: \t\t%d\n",
319 : burst_counter);
320 :
321 0 : done:
322 0 : vlib_cli_output (vm, "Cleaning:");
323 : /* delete SPD policy */
324 0 : is_add = 0;
325 0 : for (i = 0; i < flows; i++)
326 : {
327 0 : rv = ipsec_add_del_policy (vm, &p_vec[i], is_add, &stat_index);
328 0 : if (rv)
329 : {
330 0 : clib_warning ("No delete SPD Policy: %u", i);
331 0 : err = clib_error_return (0, "delete SPD Policy failure");
332 : }
333 : }
334 0 : vlib_cli_output (vm, "\tDelete all SPD Policy");
335 :
336 : /* delete SPD */
337 0 : rv = ipsec_add_del_spd (vm, spd_id, is_add);
338 0 : if (rv)
339 : {
340 0 : err = clib_error_return (0, "delete spd failure");
341 : }
342 : else
343 0 : vlib_cli_output (vm, "\tDelete SPD");
344 :
345 : /* delete SA */
346 0 : rv = ipsec_sa_unlock_id (sa_id);
347 0 : if (rv)
348 : {
349 0 : err = clib_error_return (0, "delete sa failure");
350 : }
351 : else
352 0 : vlib_cli_output (vm, "\tDelete SA");
353 :
354 0 : t1 = clib_cpu_time_now ();
355 0 : vlib_cli_output (vm, "Time for test: \t%12.10f s",
356 0 : ((t1 - t0) / vm->clib_time.clocks_per_second));
357 :
358 0 : vec_free (p_vec);
359 0 : vlib_cli_output (vm, "End");
360 :
361 0 : return (err);
362 : }
363 :
364 16239 : VLIB_CLI_COMMAND (test_ipsec_spd_perf_command, static) = {
365 : .path = "test ipsec_spd_outbound_perf",
366 : .short_help = "test ipsec_spd_outbound_perf flows <n_flows>",
367 : .function = test_ipsec_spd_outbound_perf_command_fn,
368 : };
369 :
370 : /* *INDENT-OFF* */
371 16239 : VLIB_CLI_COMMAND (test_ipsec_command, static) =
372 : {
373 : .path = "test ipsec",
374 : .short_help = "test ipsec sa <ID> seq-num <VALUE>",
375 : .function = test_ipsec_command_fn,
376 : };
377 : /* *INDENT-ON* */
378 :
379 : /*
380 : * fd.io coding-style-patch-verification: ON
381 : *
382 : * Local Variables:
383 : * eval: (c-set-style "gnu")
384 : * End:
385 : */
|