55fd031b9b9a395373605b7b7a6a3c15bf637c63
[vpp.git] / src / plugins / unittest / ipsec_test.c
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 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   sa_id = ~0;
28   seq_num = 0;
29
30   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
31     {
32       if (unformat (input, "sa %d", &sa_id))
33         ;
34       else if (unformat (input, "seq 0x%llx", &seq_num))
35         ;
36       else
37         break;
38     }
39
40   if (~0 != sa_id)
41     {
42       ipsec_sa_t *sa;
43       u32 sa_index;
44
45       sa_index = ipsec_sa_find_and_lock (sa_id);
46       sa = ipsec_sa_get (sa_index);
47
48       sa->seq = seq_num & 0xffffffff;
49       sa->seq_hi = seq_num >> 32;
50
51       ipsec_sa_unlock (sa_index);
52     }
53   else
54     {
55       return clib_error_return (0, "unknown SA `%U'",
56                                 format_unformat_error, input);
57     }
58
59   return (NULL);
60 }
61
62 static clib_error_t *
63 test_ipsec_spd_outbound_perf_command_fn (vlib_main_t *vm,
64                                          unformat_input_t *input,
65                                          vlib_cli_command_t *cmd)
66 {
67   clib_error_t *err = 0;
68   ipsec_crypto_alg_t crypto_alg = IPSEC_CRYPTO_ALG_AES_GCM_128;
69   ipsec_integ_alg_t integ_alg = IPSEC_INTEG_ALG_NONE;
70   ipsec_protocol_t proto = IPSEC_PROTOCOL_ESP;
71   ipsec_sa_flags_t sa_flags = IPSEC_SA_FLAG_NONE;
72   ipsec_key_t ck = { 0 };
73   u8 key_data[] = { 31, 32, 33, 34, 35, 36, 37, 38,
74                     39, 30, 31, 32, 33, 34, 35, 36 };
75   ipsec_mk_key (&ck, key_data, 16);
76   ipsec_key_t ik = { 0 };
77   u32 sa_id = 123456, spi = 654321, salt = 1234, sai;
78   u16 udp_src = IPSEC_UDP_PORT_NONE, udp_dst = IPSEC_UDP_PORT_NONE;
79   tunnel_t tun = {};
80
81   /* SPD policy */
82   ipsec_main_t *im = &ipsec_main;
83   ipsec_policy_t *p0 = NULL;
84   ipsec_spd_t *spd0;
85   uword *pp;
86   u32 stat_index, spd_idx, spd_id = 1;
87   int is_add = 1;
88   int rv;
89   ipsec_policy_t *p_vec = NULL;
90   u64 i;
91   u64 flows = 100;
92
93   u64 t_add_0 = 0;
94   u64 t_add_1 = 0;
95   u64 t_add = 0;
96   u64 t_look_0 = 0;
97   u64 t_look_1 = 0;
98   u64 t_look = 0;
99   u8 flow_cache_enabled = im->output_flow_cache_flag;
100   u32 count_cached = 0;
101   u32 count_slow_path = 0;
102   u32 seed = random_default_seed ();
103   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   u32 burst_size = 10;
109   int burst_enabled = 0;
110   u64 t0 = clib_cpu_time_now ();
111   u64 t1 = 0;
112   u32 k = 0, m;
113   u64 burst_counter = 0;
114
115   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
116     {
117       if (unformat (input, "flows %d", &flows))
118         ;
119       else if (unformat (input, "burst %d", &burst_size))
120         {
121           if (burst_size == 0)
122             burst_enabled = 0;
123           else
124             {
125               burst_enabled = 1;
126               burst_size = clib_min (burst_size, BURST_MAX_SIZE);
127             }
128         }
129       else
130         break;
131     }
132
133   vlib_cli_output (vm, "Create env:");
134   /* creating a new SA */
135   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   if (rv)
139     {
140       err = clib_error_return (0, "create sa failure");
141       goto done;
142     }
143   else
144     vlib_cli_output (vm, "\tAdd a new SA");
145
146   /* creating a new SPD */
147   rv = ipsec_add_del_spd (vm, spd_id, is_add);
148   if (rv)
149     {
150       err = clib_error_return (0, "create spd failure");
151       goto done;
152     }
153   else
154     vlib_cli_output (vm, "\tAdd a new SPD");
155
156   /* vector for spd_policy */
157   vec_validate (p_vec, flows + 1);
158   vec_validate (rand_val, flows + 1);
159
160   /* fill spd policy */
161   for (i = 0; i < flows; i++)
162     {
163       rand_val[i] = random_u32 (&seed) % flows;
164
165       p_vec[i].type = IPSEC_SPD_POLICY_IP4_OUTBOUND;
166       p_vec[i].priority = flows - i;
167       p_vec[i].policy = IPSEC_POLICY_ACTION_PROTECT;
168       p_vec[i].id = spd_id;
169       p_vec[i].sa_id = sa_id;
170       p_vec[i].protocol = IP_PROTOCOL_UDP;
171       p_vec[i].lport.start = 1;
172       p_vec[i].lport.stop = 1;
173       p_vec[i].rport.start = 1;
174       p_vec[i].rport.stop = 1;
175       /* address: 1.0.0.0 as u32 */
176       ip4_start = 16777216;
177       p_vec[i].laddr.start.ip4.data_u32 =
178         clib_host_to_net_u32 (ip4_start + i * 32);
179       p_vec[i].laddr.stop.ip4.data_u32 =
180         clib_host_to_net_u32 (ip4_start + i * 32);
181       p_vec[i].raddr.start.ip4.data_u32 =
182         clib_host_to_net_u32 (ip4_start + i * 32);
183       p_vec[i].raddr.stop.ip4.data_u32 =
184         clib_host_to_net_u32 (ip4_start + i * 32);
185     }
186
187   vlib_cli_output (vm, "Add SPD Policy");
188   t_add_0 = clib_cpu_time_now ();
189   for (i = 0; i < flows; i++)
190     {
191       rv = ipsec_add_del_policy (vm, &p_vec[i], is_add, &stat_index);
192       if (rv)
193         {
194           clib_warning ("No add SPD Policy: %u", stat_index);
195           err = clib_error_return (0, "add SPD Policy failure");
196           goto done;
197         }
198     }
199   t_add_1 = clib_cpu_time_now ();
200
201   pp = hash_get (im->spd_index_by_spd_id, spd_id);
202   spd_idx = pp[0];
203   spd0 = pool_elt_at_index (im->spds, spd_idx);
204
205   vlib_cli_output (vm, "Lookup SPD Policy");
206   u64 j = 0;
207   u64 n_lookup = 1000 * 1000;
208   t_look_0 = clib_cpu_time_now ();
209   for (i = 0; i < n_lookup; i++)
210     {
211       if (flows == j)
212         j = 0;
213
214       p0 = NULL;
215       if (flow_cache_enabled)
216         {
217           p0 = ipsec4_out_spd_find_flow_cache_entry (
218             im, 0,
219             clib_net_to_host_u32 (ip4_start +
220                                   ((flows - 1) - rand_val[j]) * 32),
221             clib_net_to_host_u32 (ip4_start +
222                                   ((flows - 1) - rand_val[j]) * 32),
223             clib_net_to_host_u16 (1), clib_net_to_host_u16 (1));
224           if (p0)
225             count_cached++;
226         }
227       if (p0 == NULL)
228         {
229           if (burst_enabled)
230             {
231               u32 src_addr = (ip4_start + ((flows - 1) - rand_val[j]) * 32);
232               u32 dst_addr = (ip4_start + ((flows - 1) - rand_val[j]) * 32);
233               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               if (k == burst_size)
241                 {
242                   k = 0;
243                   clib_memset (policies, 0,
244                                burst_size * sizeof (ipsec_policy_t *));
245                   burst_counter += ipsec_output_policy_match_n (
246                     spd0, ip4_5tuples, policies, burst_size,
247                     flow_cache_enabled);
248                   for (m = 0; m < burst_size; m++)
249                     {
250                       ASSERT (policies[m] != 0);
251                     }
252                 }
253
254               clib_memcpy (ip4_5tuples + k, &ip4_5tuple,
255                            sizeof (ipsec4_spd_5tuple_t));
256               k++;
257             }
258           else
259             {
260
261               p0 = ipsec_output_policy_match (
262                 spd0, IP_PROTOCOL_UDP,
263                 (ip4_start + ((flows - 1) - rand_val[j]) * 32),
264                 (ip4_start + ((flows - 1) - rand_val[j]) * 32), 1, 1,
265                 flow_cache_enabled);
266             }
267
268           count_slow_path++;
269         }
270       j++;
271       if (!burst_enabled)
272         ASSERT (p0 != 0);
273     }
274
275   if (burst_enabled && k > 0)
276     {
277       clib_memset (policies, 0, k * sizeof (ipsec_policy_t *));
278       burst_counter += ipsec_output_policy_match_n (
279         spd0, ip4_5tuples, policies, k, flow_cache_enabled);
280       for (m = 0; m < k; m++)
281         {
282           ASSERT (policies[m] != 0);
283         }
284     }
285   t_look_1 = clib_cpu_time_now ();
286
287   t_add = (t_add_1 - t_add_0);
288   t_look = (t_look_1 - t_look_0);
289
290   vlib_cli_output (vm, "Results Outbound:");
291   vlib_cli_output (vm, "Time to add %u flows: \t\t%12.10f s", flows,
292                    (t_add / vm->clib_time.clocks_per_second));
293   vlib_cli_output (vm, "Average time to add 1 flow: \t\t%12.10f s",
294                    ((t_add / flows) / vm->clib_time.clocks_per_second));
295   vlib_cli_output (vm, "Time to lookup %u flows: \t\t%12.10f s", flows,
296                    (t_look / vm->clib_time.clocks_per_second));
297   vlib_cli_output (vm, "Average time to lookup 1 flow: \t\t%12.10f s",
298                    ((t_look / n_lookup) / vm->clib_time.clocks_per_second));
299
300   vlib_cli_output (vm, " ");
301
302   vlib_cli_output (vm, "Cycle CPU to add %u flows: \t\t%32lu cycles", flows,
303                    t_add);
304   vlib_cli_output (vm, "Average cycle CPU to add 1 flow: \t%32lu cycles",
305                    t_add / flows);
306   vlib_cli_output (vm, "Cycle CPU to lookup %u flows: \t%32lu cycles", flows,
307                    t_look);
308   vlib_cli_output (vm, "Average cycle CPU to lookup 1 flow: \t%32lu cycles",
309                    t_look / n_lookup);
310
311   if (count_slow_path || count_cached)
312     vlib_cli_output (
313       vm, "flow cache hit rate: \t\t%12.10f\n cached: \t%d\n slow_path: \t%d",
314       ((float) count_cached) / ((float) count_cached + count_slow_path),
315       count_cached, count_slow_path);
316
317   if (burst_enabled)
318     vlib_cli_output (vm, "Total number of packets matched in bursts: \t\t%d\n",
319                      burst_counter);
320
321 done:
322   vlib_cli_output (vm, "Cleaning:");
323   /* delete SPD policy */
324   is_add = 0;
325   for (i = 0; i < flows; i++)
326     {
327       rv = ipsec_add_del_policy (vm, &p_vec[i], is_add, &stat_index);
328       if (rv)
329         {
330           clib_warning ("No delete SPD Policy: %u", i);
331           err = clib_error_return (0, "delete SPD Policy failure");
332         }
333     }
334   vlib_cli_output (vm, "\tDelete all SPD Policy");
335
336   /* delete SPD */
337   rv = ipsec_add_del_spd (vm, spd_id, is_add);
338   if (rv)
339     {
340       err = clib_error_return (0, "delete spd failure");
341     }
342   else
343     vlib_cli_output (vm, "\tDelete SPD");
344
345   /* delete SA */
346   rv = ipsec_sa_unlock_id (sa_id);
347   if (rv)
348     {
349       err = clib_error_return (0, "delete sa failure");
350     }
351   else
352     vlib_cli_output (vm, "\tDelete SA");
353
354   t1 = clib_cpu_time_now ();
355   vlib_cli_output (vm, "Time for test: \t%12.10f s",
356                    ((t1 - t0) / vm->clib_time.clocks_per_second));
357
358   vec_free (p_vec);
359   vlib_cli_output (vm, "End");
360
361   return (err);
362 }
363
364 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 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  */