ipsec: add per-SA error counters
[vpp.git] / src / vnet / ipsec / ipsec_format.c
1 /*
2  * decap.c : IPSec tunnel support
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21 #include <vnet/interface.h>
22 #include <vnet/fib/fib_table.h>
23
24 #include <vnet/ipsec/ipsec.h>
25 #include <vnet/ipsec/ipsec_tun.h>
26 #include <vnet/ipsec/ipsec_itf.h>
27
28 u8 *
29 format_ipsec_policy_action (u8 * s, va_list * args)
30 {
31   u32 i = va_arg (*args, u32);
32   char *t = 0;
33
34   switch (i)
35     {
36 #define _(v,f,str) case IPSEC_POLICY_ACTION_##f: t = str; break;
37       foreach_ipsec_policy_action
38 #undef _
39     default:
40       s = format (s, "unknown");
41     }
42   s = format (s, "%s", t);
43   return s;
44 }
45
46 u8 *
47 format_ipsec_policy_type (u8 * s, va_list * args)
48 {
49   u32 i = va_arg (*args, u32);
50   char *t = 0;
51
52   switch (i)
53     {
54 #define _(f,str) case IPSEC_SPD_POLICY_##f: t = str; break;
55       foreach_ipsec_spd_policy_type
56 #undef _
57     default:
58       s = format (s, "unknown");
59     }
60   s = format (s, "%s", t);
61   return s;
62 }
63
64 uword
65 unformat_ipsec_policy_action (unformat_input_t * input, va_list * args)
66 {
67   u32 *r = va_arg (*args, u32 *);
68
69   if (0);
70 #define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_POLICY_ACTION_##f;
71   foreach_ipsec_policy_action
72 #undef _
73     else
74     return 0;
75   return 1;
76 }
77
78 u8 *
79 format_ipsec_crypto_alg (u8 * s, va_list * args)
80 {
81   u32 i = va_arg (*args, u32);
82   u8 *t = 0;
83
84   switch (i)
85     {
86 #define _(v,f,str) case IPSEC_CRYPTO_ALG_##f: t = (u8 *) str; break;
87       foreach_ipsec_crypto_alg
88 #undef _
89     default:
90       s = format (s, "unknown");
91     }
92   s = format (s, "%s", t);
93   return s;
94 }
95
96 uword
97 unformat_ipsec_crypto_alg (unformat_input_t * input, va_list * args)
98 {
99   ipsec_crypto_alg_t *r = va_arg (*args, ipsec_crypto_alg_t *);
100
101   if (0);
102 #define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_CRYPTO_ALG_##f;
103   foreach_ipsec_crypto_alg
104 #undef _
105     else
106     return 0;
107   return 1;
108 }
109
110 u8 *
111 format_ipsec_integ_alg (u8 * s, va_list * args)
112 {
113   u32 i = va_arg (*args, u32);
114   u8 *t = 0;
115
116   switch (i)
117     {
118 #define _(v,f,str) case IPSEC_INTEG_ALG_##f: t = (u8 *) str; break;
119       foreach_ipsec_integ_alg
120 #undef _
121     default:
122       s = format (s, "unknown");
123     }
124   s = format (s, "%s", t);
125   return s;
126 }
127
128 uword
129 unformat_ipsec_integ_alg (unformat_input_t * input, va_list * args)
130 {
131   ipsec_integ_alg_t *r = va_arg (*args, ipsec_integ_alg_t *);
132
133   if (0);
134 #define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_INTEG_ALG_##f;
135   foreach_ipsec_integ_alg
136 #undef _
137     else
138     return 0;
139   return 1;
140 }
141
142 u8 *
143 format_ipsec_replay_window (u8 * s, va_list * args)
144 {
145   u64 w = va_arg (*args, u64);
146   u8 i;
147
148   for (i = 0; i < 64; i++)
149     {
150       s = format (s, "%u", w & (1ULL << i) ? 1 : 0);
151     }
152
153   return s;
154 }
155
156 static u8 *
157 format_ipsec_policy_with_suffix (u8 *s, va_list *args, u8 *suffix)
158 {
159   u32 pi = va_arg (*args, u32);
160   ip46_type_t ip_type = IP46_TYPE_IP4;
161   ipsec_main_t *im = &ipsec_main;
162   ipsec_policy_t *p;
163   vlib_counter_t counts;
164
165   p = pool_elt_at_index (im->policies, pi);
166
167   s = format (s, "  [%d] priority %d action %U type %U protocol ",
168               pi, p->priority,
169               format_ipsec_policy_action, p->policy,
170               format_ipsec_policy_type, p->type);
171   if (p->protocol != IPSEC_POLICY_PROTOCOL_ANY)
172     {
173       s = format (s, "%U", format_ip_protocol, p->protocol);
174     }
175   else
176     {
177       s = format (s, "any");
178     }
179   if (p->policy == IPSEC_POLICY_ACTION_PROTECT)
180     {
181       s = format (s, " sa %u", p->sa_id);
182     }
183   if (suffix)
184     s = format (s, " %s", suffix);
185
186   if (p->is_ipv6)
187     {
188       ip_type = IP46_TYPE_IP6;
189     }
190
191   s = format (s, "\n     local addr range %U - %U port range %u - %u",
192               format_ip46_address, &p->laddr.start, ip_type,
193               format_ip46_address, &p->laddr.stop, ip_type,
194               p->lport.start, p->lport.stop);
195   s = format (s, "\n     remote addr range %U - %U port range %u - %u",
196               format_ip46_address, &p->raddr.start, ip_type,
197               format_ip46_address, &p->raddr.stop, ip_type,
198               p->rport.start, p->rport.stop);
199
200   vlib_get_combined_counter (&ipsec_spd_policy_counters, pi, &counts);
201   s = format (s, "\n     packets %u bytes %u", counts.packets, counts.bytes);
202
203   return (s);
204 }
205
206 u8 *
207 format_ipsec_policy (u8 *s, va_list *args)
208 {
209   return format_ipsec_policy_with_suffix (s, args, 0);
210 }
211
212 u8 *
213 format_ipsec_fp_policy (u8 *s, va_list *args)
214 {
215   return format_ipsec_policy_with_suffix (s, args, (u8 *) "<fast-path>");
216 }
217
218 /**
219  * @brief Context when walking the fp bihash  table. We need to filter
220  * only those policies that are of given type as we walk the table.
221  */
222 typedef struct ipsec_spd_policy_ctx_t_
223 {
224   u32 *policies;
225   ipsec_spd_policy_type_t t;
226 } ipsec_fp_walk_ctx_t;
227
228 static int
229 ipsec_fp_table_walk_ip4_cb (clib_bihash_kv_16_8_t *kvp, void *arg)
230 {
231   ipsec_fp_walk_ctx_t *ctx = (ipsec_fp_walk_ctx_t *) arg;
232   ipsec_main_t *im = &ipsec_main;
233   ipsec_policy_t *p;
234
235   ipsec_fp_lookup_value_t *val = (ipsec_fp_lookup_value_t *) &kvp->value;
236
237   u32 *policy_id;
238
239   vec_foreach (policy_id, val->fp_policies_ids)
240     {
241       p = pool_elt_at_index (im->policies, *policy_id);
242       if (p->type == ctx->t)
243         vec_add1 (ctx->policies, *policy_id);
244     }
245
246   return BIHASH_WALK_CONTINUE;
247 }
248
249 static int
250 ipsec_fp_table_walk_ip6_cb (clib_bihash_kv_40_8_t *kvp, void *arg)
251 {
252   ipsec_fp_walk_ctx_t *ctx = (ipsec_fp_walk_ctx_t *) arg;
253   ipsec_main_t *im = &ipsec_main;
254   ipsec_policy_t *p;
255
256   ipsec_fp_lookup_value_t *val = (ipsec_fp_lookup_value_t *) &kvp->value;
257
258   u32 *policy_id;
259
260   vec_foreach (policy_id, val->fp_policies_ids)
261     {
262       p = pool_elt_at_index (im->policies, *policy_id);
263       if (p->type == ctx->t)
264         vec_add1 (ctx->policies, *policy_id);
265     }
266
267   return BIHASH_WALK_CONTINUE;
268 }
269
270 u8 *
271 format_ipsec_fp_policies (u8 *s, va_list *args)
272 {
273   ipsec_main_t *im = &ipsec_main;
274   ipsec_spd_t *spd = va_arg (*args, ipsec_spd_t *);
275   ipsec_spd_policy_type_t t = va_arg (*args, ipsec_spd_policy_type_t);
276   u32 *i;
277   ipsec_fp_walk_ctx_t ctx = {
278     .policies = 0,
279     .t = t,
280   };
281
282   u32 ip4_in_lookup_hash_idx = spd->fp_spd.ip4_in_lookup_hash_idx;
283   u32 ip4_out_lookup_hash_idx = spd->fp_spd.ip4_out_lookup_hash_idx;
284   u32 ip6_in_lookup_hash_idx = spd->fp_spd.ip6_in_lookup_hash_idx;
285   u32 ip6_out_lookup_hash_idx = spd->fp_spd.ip6_out_lookup_hash_idx;
286
287   switch (t)
288     {
289     case IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT:
290     case IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS:
291     case IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD:
292       if (INDEX_INVALID != ip4_in_lookup_hash_idx)
293         {
294           clib_bihash_16_8_t *bihash_table = pool_elt_at_index (
295             im->fp_ip4_lookup_hashes_pool, ip4_in_lookup_hash_idx);
296
297           clib_bihash_foreach_key_value_pair_16_8 (
298             bihash_table, ipsec_fp_table_walk_ip4_cb, &ctx);
299         }
300
301       break;
302
303     case IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT:
304     case IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS:
305     case IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD:
306       if (INDEX_INVALID != ip6_in_lookup_hash_idx)
307         {
308           clib_bihash_40_8_t *bihash_table = pool_elt_at_index (
309             im->fp_ip6_lookup_hashes_pool, ip6_in_lookup_hash_idx);
310
311           clib_bihash_foreach_key_value_pair_40_8 (
312             bihash_table, ipsec_fp_table_walk_ip6_cb, &ctx);
313         }
314
315       break;
316     case IPSEC_SPD_POLICY_IP4_OUTBOUND:
317       if (INDEX_INVALID != ip4_out_lookup_hash_idx)
318         {
319           clib_bihash_16_8_t *bihash_table = pool_elt_at_index (
320             im->fp_ip4_lookup_hashes_pool, ip4_out_lookup_hash_idx);
321
322           clib_bihash_foreach_key_value_pair_16_8 (
323             bihash_table, ipsec_fp_table_walk_ip4_cb, &ctx);
324         }
325
326       break;
327     case IPSEC_SPD_POLICY_IP6_OUTBOUND:
328       if (INDEX_INVALID != ip6_out_lookup_hash_idx)
329         {
330           clib_bihash_40_8_t *bihash_table = pool_elt_at_index (
331             im->fp_ip6_lookup_hashes_pool, ip6_out_lookup_hash_idx);
332
333           clib_bihash_foreach_key_value_pair_40_8 (
334             bihash_table, ipsec_fp_table_walk_ip6_cb, &ctx);
335         }
336
337       break;
338     default:
339       break;
340     }
341
342   vec_foreach (i, ctx.policies)
343     {
344       s = format (s, "\n %U", format_ipsec_fp_policy, *i);
345     }
346
347   vec_free (ctx.policies);
348
349   return s;
350 }
351
352 u8 *
353 format_ipsec_spd (u8 * s, va_list * args)
354 {
355   u32 si = va_arg (*args, u32);
356   ipsec_main_t *im = &ipsec_main;
357   ipsec_spd_t *spd;
358   u32 *i;
359
360   if (pool_is_free_index (im->spds, si))
361     {
362       s = format (s, "No such SPD index: %d", si);
363       goto done;
364     }
365
366   spd = pool_elt_at_index (im->spds, si);
367
368   s = format (s, "spd %u", spd->id);
369
370 #define _(v, n)                                                               \
371   s = format (s, "\n %s:", n);                                                \
372   vec_foreach (i, spd->policies[IPSEC_SPD_POLICY_##v])                        \
373     {                                                                         \
374       s = format (s, "\n %U", format_ipsec_policy, *i);                       \
375     }                                                                         \
376   s = format (s, "\n %U", format_ipsec_fp_policies, spd, IPSEC_SPD_POLICY_##v);
377   foreach_ipsec_spd_policy_type;
378 #undef _
379
380 done:
381   return (s);
382 }
383
384 u8 *
385 format_ipsec_out_spd_flow_cache (u8 *s, va_list *args)
386 {
387   ipsec_main_t *im = &ipsec_main;
388
389   s = format (s, "\nipv4-outbound-spd-flow-cache-entries: %u",
390               im->ipsec4_out_spd_flow_cache_entries);
391
392   return (s);
393 }
394
395 u8 *
396 format_ipsec_in_spd_flow_cache (u8 *s, va_list *args)
397 {
398   ipsec_main_t *im = &ipsec_main;
399
400   s = format (s, "\nipv4-inbound-spd-flow-cache-entries: %u",
401               im->ipsec4_in_spd_flow_cache_entries);
402
403   return (s);
404 }
405
406 u8 *
407 format_ipsec_key (u8 * s, va_list * args)
408 {
409   ipsec_key_t *key = va_arg (*args, ipsec_key_t *);
410
411   return (format (s, "%U", format_hex_bytes, key->data, key->len));
412 }
413
414 uword
415 unformat_ipsec_key (unformat_input_t * input, va_list * args)
416 {
417   ipsec_key_t *key = va_arg (*args, ipsec_key_t *);
418   u8 *data;
419
420   if (unformat (input, "%U", unformat_hex_string, &data))
421     {
422       ipsec_mk_key (key, data, vec_len (data));
423       vec_free (data);
424     }
425   else
426     return 0;
427   return 1;
428 }
429
430 u8 *
431 format_ipsec_sa_flags (u8 * s, va_list * args)
432 {
433   ipsec_sa_flags_t flags = va_arg (*args, int);
434
435 #define _(v, f, str) if (flags & IPSEC_SA_FLAG_##f) s = format(s, "%s ", str);
436   foreach_ipsec_sa_flags
437 #undef _
438     return (s);
439 }
440
441 u8 *
442 format_ipsec_sa (u8 * s, va_list * args)
443 {
444   u32 sai = va_arg (*args, u32);
445   ipsec_format_flags_t flags = va_arg (*args, ipsec_format_flags_t);
446   vlib_counter_t counts;
447   counter_t errors;
448   ipsec_sa_t *sa;
449
450   if (pool_is_free_index (ipsec_sa_pool, sai))
451     {
452       s = format (s, "No such SA index: %d", sai);
453       goto done;
454     }
455
456   sa = ipsec_sa_get (sai);
457
458   s = format (s, "[%d] sa %u (0x%x) spi %u (0x%08x) protocol:%s flags:[%U]",
459               sai, sa->id, sa->id, sa->spi, sa->spi,
460               sa->protocol ? "esp" : "ah", format_ipsec_sa_flags, sa->flags);
461
462   if (!(flags & IPSEC_FORMAT_DETAIL))
463     goto done;
464
465   s = format (s, "\n   locks %d", sa->node.fn_locks);
466   s = format (s, "\n   salt 0x%x", clib_net_to_host_u32 (sa->salt));
467   s = format (s, "\n   thread-index:%d", sa->thread_index);
468   s = format (s, "\n   seq %u seq-hi %u", sa->seq, sa->seq_hi);
469   s = format (s, "\n   window %U", format_ipsec_replay_window,
470               sa->replay_window);
471   s = format (s, "\n   crypto alg %U",
472               format_ipsec_crypto_alg, sa->crypto_alg);
473   if (sa->crypto_alg && (flags & IPSEC_FORMAT_INSECURE))
474     s = format (s, " key %U", format_ipsec_key, &sa->crypto_key);
475   else
476     s = format (s, " key [redacted]");
477   s = format (s, "\n   integrity alg %U",
478               format_ipsec_integ_alg, sa->integ_alg);
479   if (sa->integ_alg && (flags & IPSEC_FORMAT_INSECURE))
480     s = format (s, " key %U", format_ipsec_key, &sa->integ_key);
481   else
482     s = format (s, " key [redacted]");
483   s = format (s, "\n   UDP:[src:%d dst:%d]",
484               clib_host_to_net_u16 (sa->udp_hdr.src_port),
485               clib_host_to_net_u16 (sa->udp_hdr.dst_port));
486
487   vlib_get_combined_counter (&ipsec_sa_counters, sai, &counts);
488   s = format (s, "\n   tx/rx:[packets:%Ld bytes:%Ld]", counts.packets,
489               counts.bytes);
490   s = format (s, "\n   SA errors:");
491 #define _(index, val, err, desc)                                              \
492   errors = vlib_get_simple_counter (&ipsec_sa_err_counters[index], sai);      \
493   s = format (s, "\n   " #desc ":[packets:%Ld]", errors);
494   foreach_ipsec_sa_err
495 #undef _
496
497     if (ipsec_sa_is_set_IS_TUNNEL (sa)) s =
498       format (s, "\n%U", format_tunnel, &sa->tunnel, 3);
499
500 done:
501   return (s);
502 }
503
504 u8 *
505 format_ipsec_tun_protect_index (u8 * s, va_list * args)
506 {
507   u32 itpi = va_arg (*args, index_t);
508   ipsec_tun_protect_t *itp;
509
510   if (pool_is_free_index (ipsec_tun_protect_pool, itpi))
511     return (format (s, "No such tunnel index: %d", itpi));
512
513   itp = pool_elt_at_index (ipsec_tun_protect_pool, itpi);
514
515   return (format (s, "%U", format_ipsec_tun_protect, itp));
516 }
517
518 u8 *
519 format_ipsec_tun_protect_flags (u8 * s, va_list * args)
520 {
521   ipsec_protect_flags_t flags = va_arg (*args, int);
522
523   if (IPSEC_PROTECT_NONE == flags)
524     s = format (s, "none");
525 #define _(a,b,c)                                \
526   else if (flags & IPSEC_PROTECT_##a)           \
527     s = format (s, "%s", c);                    \
528   foreach_ipsec_protect_flags
529 #undef _
530
531   return (s);
532 }
533
534 u8 *
535 format_ipsec_tun_protect (u8 * s, va_list * args)
536 {
537   ipsec_tun_protect_t *itp = va_arg (*args, ipsec_tun_protect_t *);
538   u32 sai;
539
540   s = format (s, "%U flags:[%U]", format_vnet_sw_if_index_name,
541               vnet_get_main (), itp->itp_sw_if_index,
542               format_ipsec_tun_protect_flags, itp->itp_flags);
543   if (!ip_address_is_zero (itp->itp_key))
544     s = format (s, ": %U", format_ip_address, itp->itp_key);
545   s = format (s, "\n output-sa:");
546   s = format (s, "\n  %U", format_ipsec_sa, itp->itp_out_sa,
547               IPSEC_FORMAT_BRIEF);
548
549   s = format (s, "\n input-sa:");
550   /* *INDENT-OFF* */
551   FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
552   ({
553   s = format (s, "\n  %U", format_ipsec_sa, sai, IPSEC_FORMAT_BRIEF);
554   }));
555   /* *INDENT-ON* */
556
557   return (s);
558 }
559
560 u8 *
561 format_ipsec4_tunnel_kv (u8 * s, va_list * args)
562 {
563   ipsec4_tunnel_kv_t *kv = va_arg (*args, ipsec4_tunnel_kv_t *);
564   ip4_address_t ip;
565   u32 spi;
566
567   ipsec4_tunnel_extract_key (kv, &ip, &spi);
568
569   s = format (s, "remote:%U spi:%u (0x%08x) sa:%d tun:%d",
570               format_ip4_address, &ip,
571               clib_net_to_host_u32 (spi),
572               clib_net_to_host_u32 (spi),
573               kv->value.sa_index, kv->value.tun_index);
574
575   return (s);
576 }
577
578 u8 *
579 format_ipsec6_tunnel_kv (u8 * s, va_list * args)
580 {
581   ipsec6_tunnel_kv_t *kv = va_arg (*args, ipsec6_tunnel_kv_t *);
582
583   s = format (s, "remote:%U spi:%u (0x%08x) sa:%d tun:%d",
584               format_ip6_address, &kv->key.remote_ip,
585               clib_net_to_host_u32 (kv->key.spi),
586               clib_net_to_host_u32 (kv->key.spi),
587               kv->value.sa_index, kv->value.tun_index);
588
589   return (s);
590 }
591
592 u8 *
593 format_ipsec_itf (u8 * s, va_list * a)
594 {
595   index_t ii = va_arg (*a, index_t);
596   ipsec_itf_t *itf;
597
598   itf = ipsec_itf_get (ii);
599   s = format (s, "[%d] %U %U",
600               ii, format_vnet_sw_if_index_name, vnet_get_main (),
601               itf->ii_sw_if_index, format_tunnel_mode, itf->ii_mode);
602
603   return (s);
604 }
605
606 /*
607  * fd.io coding-style-patch-verification: ON
608  *
609  * Local Variables:
610  * eval: (c-set-style "gnu")
611  * End:
612  */