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