Line data Source code
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 65258 : format_ipsec_policy_action (u8 * s, va_list * args)
30 : {
31 65258 : u32 i = va_arg (*args, u32);
32 65258 : char *t = 0;
33 :
34 65258 : switch (i)
35 : {
36 : #define _(v,f,str) case IPSEC_POLICY_ACTION_##f: t = str; break;
37 65258 : foreach_ipsec_policy_action
38 : #undef _
39 0 : default:
40 0 : s = format (s, "unknown");
41 : }
42 65258 : s = format (s, "%s", t);
43 65258 : return s;
44 : }
45 :
46 : u8 *
47 65258 : format_ipsec_policy_type (u8 * s, va_list * args)
48 : {
49 65258 : u32 i = va_arg (*args, u32);
50 65258 : char *t = 0;
51 :
52 65258 : switch (i)
53 : {
54 : #define _(f,str) case IPSEC_SPD_POLICY_##f: t = str; break;
55 65258 : foreach_ipsec_spd_policy_type
56 : #undef _
57 0 : default:
58 0 : s = format (s, "unknown");
59 : }
60 65258 : s = format (s, "%s", t);
61 65258 : return s;
62 : }
63 :
64 : uword
65 0 : unformat_ipsec_policy_action (unformat_input_t * input, va_list * args)
66 : {
67 0 : 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 0 : foreach_ipsec_policy_action
72 : #undef _
73 : else
74 0 : return 0;
75 0 : return 1;
76 : }
77 :
78 : u8 *
79 372765 : format_ipsec_crypto_alg (u8 * s, va_list * args)
80 : {
81 372765 : u32 i = va_arg (*args, u32);
82 372765 : u8 *t = 0;
83 :
84 372765 : switch (i)
85 : {
86 : #define _(v,f,str) case IPSEC_CRYPTO_ALG_##f: t = (u8 *) str; break;
87 372715 : foreach_ipsec_crypto_alg
88 : #undef _
89 50 : default:
90 50 : s = format (s, "unknown");
91 : }
92 372765 : s = format (s, "%s", t);
93 372765 : return s;
94 : }
95 :
96 : uword
97 0 : unformat_ipsec_crypto_alg (unformat_input_t * input, va_list * args)
98 : {
99 0 : 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 0 : foreach_ipsec_crypto_alg
104 : #undef _
105 : else
106 0 : return 0;
107 0 : return 1;
108 : }
109 :
110 : u8 *
111 380343 : format_ipsec_integ_alg (u8 * s, va_list * args)
112 : {
113 380343 : u32 i = va_arg (*args, u32);
114 380343 : u8 *t = 0;
115 :
116 380343 : switch (i)
117 : {
118 : #define _(v,f,str) case IPSEC_INTEG_ALG_##f: t = (u8 *) str; break;
119 380293 : foreach_ipsec_integ_alg
120 : #undef _
121 50 : default:
122 50 : s = format (s, "unknown");
123 : }
124 380343 : s = format (s, "%s", t);
125 380343 : return s;
126 : }
127 :
128 : uword
129 0 : unformat_ipsec_integ_alg (unformat_input_t * input, va_list * args)
130 : {
131 0 : 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 0 : foreach_ipsec_integ_alg
136 : #undef _
137 : else
138 0 : return 0;
139 0 : return 1;
140 : }
141 :
142 : u8 *
143 1419 : format_ipsec_replay_window (u8 * s, va_list * args)
144 : {
145 1419 : u64 w = va_arg (*args, u64);
146 : u8 i;
147 :
148 92235 : for (i = 0; i < 64; i++)
149 : {
150 90816 : s = format (s, "%u", w & (1ULL << i) ? 1 : 0);
151 : }
152 :
153 1419 : return s;
154 : }
155 :
156 : static u8 *
157 65258 : format_ipsec_policy_with_suffix (u8 *s, va_list *args, u8 *suffix)
158 : {
159 65258 : u32 pi = va_arg (*args, u32);
160 65258 : ip46_type_t ip_type = IP46_TYPE_IP4;
161 65258 : ipsec_main_t *im = &ipsec_main;
162 : ipsec_policy_t *p;
163 : vlib_counter_t counts;
164 :
165 65258 : p = pool_elt_at_index (im->policies, pi);
166 :
167 65258 : s = format (s, " [%d] priority %d action %U type %U protocol ",
168 : pi, p->priority,
169 65258 : format_ipsec_policy_action, p->policy,
170 65258 : format_ipsec_policy_type, p->type);
171 65258 : if (p->protocol != IPSEC_POLICY_PROTOCOL_ANY)
172 : {
173 26374 : s = format (s, "%U", format_ip_protocol, p->protocol);
174 : }
175 : else
176 : {
177 38884 : s = format (s, "any");
178 : }
179 65258 : if (p->policy == IPSEC_POLICY_ACTION_PROTECT)
180 : {
181 38884 : s = format (s, " sa %u", p->sa_id);
182 : }
183 65258 : if (suffix)
184 174 : s = format (s, " %s", suffix);
185 :
186 65258 : if (p->is_ipv6)
187 : {
188 32420 : ip_type = IP46_TYPE_IP6;
189 : }
190 :
191 65258 : 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 65258 : p->lport.start, p->lport.stop);
195 65258 : 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 65258 : p->rport.start, p->rport.stop);
199 :
200 65258 : vlib_get_combined_counter (&ipsec_spd_policy_counters, pi, &counts);
201 65258 : s = format (s, "\n packets %u bytes %u", counts.packets, counts.bytes);
202 :
203 65258 : return (s);
204 : }
205 :
206 : u8 *
207 65084 : format_ipsec_policy (u8 *s, va_list *args)
208 : {
209 65084 : return format_ipsec_policy_with_suffix (s, args, 0);
210 : }
211 :
212 : u8 *
213 174 : format_ipsec_fp_policy (u8 *s, va_list *args)
214 : {
215 174 : 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 218 : ipsec_fp_table_walk_ip4_cb (clib_bihash_kv_16_8_t *kvp, void *arg)
230 : {
231 218 : ipsec_fp_walk_ctx_t *ctx = (ipsec_fp_walk_ctx_t *) arg;
232 218 : ipsec_main_t *im = &ipsec_main;
233 : ipsec_policy_t *p;
234 :
235 218 : ipsec_fp_lookup_value_t *val = (ipsec_fp_lookup_value_t *) &kvp->value;
236 :
237 : u32 *policy_id;
238 :
239 462 : vec_foreach (policy_id, val->fp_policies_ids)
240 : {
241 244 : p = pool_elt_at_index (im->policies, *policy_id);
242 244 : if (p->type == ctx->t)
243 116 : vec_add1 (ctx->policies, *policy_id);
244 : }
245 :
246 218 : return BIHASH_WALK_CONTINUE;
247 : }
248 :
249 : static int
250 53 : ipsec_fp_table_walk_ip6_cb (clib_bihash_kv_40_8_t *kvp, void *arg)
251 : {
252 53 : ipsec_fp_walk_ctx_t *ctx = (ipsec_fp_walk_ctx_t *) arg;
253 53 : ipsec_main_t *im = &ipsec_main;
254 : ipsec_policy_t *p;
255 :
256 53 : ipsec_fp_lookup_value_t *val = (ipsec_fp_lookup_value_t *) &kvp->value;
257 :
258 : u32 *policy_id;
259 :
260 131 : vec_foreach (policy_id, val->fp_policies_ids)
261 : {
262 78 : p = pool_elt_at_index (im->policies, *policy_id);
263 78 : if (p->type == ctx->t)
264 58 : vec_add1 (ctx->policies, *policy_id);
265 : }
266 :
267 53 : return BIHASH_WALK_CONTINUE;
268 : }
269 :
270 : u8 *
271 53296 : format_ipsec_fp_policies (u8 *s, va_list *args)
272 : {
273 53296 : ipsec_main_t *im = &ipsec_main;
274 53296 : ipsec_spd_t *spd = va_arg (*args, ipsec_spd_t *);
275 53296 : ipsec_spd_policy_type_t t = va_arg (*args, ipsec_spd_policy_type_t);
276 : u32 *i;
277 53296 : ipsec_fp_walk_ctx_t ctx = {
278 : .policies = 0,
279 : .t = t,
280 : };
281 :
282 53296 : u32 ip4_in_lookup_hash_idx = spd->fp_spd.ip4_in_lookup_hash_idx;
283 53296 : u32 ip4_out_lookup_hash_idx = spd->fp_spd.ip4_out_lookup_hash_idx;
284 53296 : u32 ip6_in_lookup_hash_idx = spd->fp_spd.ip6_in_lookup_hash_idx;
285 53296 : u32 ip6_out_lookup_hash_idx = spd->fp_spd.ip6_out_lookup_hash_idx;
286 :
287 53296 : switch (t)
288 : {
289 19986 : case IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT:
290 : case IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS:
291 : case IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD:
292 19986 : if (INDEX_INVALID != ip4_in_lookup_hash_idx)
293 : {
294 90 : 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 90 : clib_bihash_foreach_key_value_pair_16_8 (
298 : bihash_table, ipsec_fp_table_walk_ip4_cb, &ctx);
299 : }
300 :
301 19986 : break;
302 :
303 19986 : case IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT:
304 : case IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS:
305 : case IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD:
306 19986 : if (INDEX_INVALID != ip6_in_lookup_hash_idx)
307 : {
308 12 : 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 12 : clib_bihash_foreach_key_value_pair_40_8 (
312 : bihash_table, ipsec_fp_table_walk_ip6_cb, &ctx);
313 : }
314 :
315 19986 : break;
316 6662 : case IPSEC_SPD_POLICY_IP4_OUTBOUND:
317 6662 : if (INDEX_INVALID != ip4_out_lookup_hash_idx)
318 : {
319 24 : 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 24 : clib_bihash_foreach_key_value_pair_16_8 (
323 : bihash_table, ipsec_fp_table_walk_ip4_cb, &ctx);
324 : }
325 :
326 6662 : break;
327 6662 : case IPSEC_SPD_POLICY_IP6_OUTBOUND:
328 6662 : if (INDEX_INVALID != ip6_out_lookup_hash_idx)
329 : {
330 21 : 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 21 : clib_bihash_foreach_key_value_pair_40_8 (
334 : bihash_table, ipsec_fp_table_walk_ip6_cb, &ctx);
335 : }
336 :
337 6662 : break;
338 0 : default:
339 0 : break;
340 : }
341 :
342 53470 : vec_foreach (i, ctx.policies)
343 : {
344 174 : s = format (s, "\n %U", format_ipsec_fp_policy, *i);
345 : }
346 :
347 53296 : vec_free (ctx.policies);
348 :
349 53296 : return s;
350 : }
351 :
352 : u8 *
353 6662 : format_ipsec_spd (u8 * s, va_list * args)
354 : {
355 6662 : u32 si = va_arg (*args, u32);
356 6662 : ipsec_main_t *im = &ipsec_main;
357 : ipsec_spd_t *spd;
358 : u32 *i;
359 :
360 6662 : if (pool_is_free_index (im->spds, si))
361 : {
362 0 : s = format (s, "No such SPD index: %d", si);
363 0 : goto done;
364 : }
365 :
366 6662 : spd = pool_elt_at_index (im->spds, si);
367 :
368 6662 : 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 71746 : foreach_ipsec_spd_policy_type;
378 : #undef _
379 :
380 6662 : done:
381 6662 : return (s);
382 : }
383 :
384 : u8 *
385 47 : format_ipsec_out_spd_flow_cache (u8 *s, va_list *args)
386 : {
387 47 : ipsec_main_t *im = &ipsec_main;
388 :
389 47 : s = format (s, "\nipv4-outbound-spd-flow-cache-entries: %u",
390 : im->ipsec4_out_spd_flow_cache_entries);
391 :
392 47 : return (s);
393 : }
394 :
395 : u8 *
396 51 : format_ipsec_in_spd_flow_cache (u8 *s, va_list *args)
397 : {
398 51 : ipsec_main_t *im = &ipsec_main;
399 :
400 51 : s = format (s, "\nipv4-inbound-spd-flow-cache-entries: %u",
401 : im->ipsec4_in_spd_flow_cache_entries);
402 :
403 51 : return (s);
404 : }
405 :
406 : u8 *
407 2297 : format_ipsec_key (u8 * s, va_list * args)
408 : {
409 2297 : ipsec_key_t *key = va_arg (*args, ipsec_key_t *);
410 :
411 2297 : return (format (s, "%U", format_hex_bytes, key->data, key->len));
412 : }
413 :
414 : uword
415 0 : unformat_ipsec_key (unformat_input_t * input, va_list * args)
416 : {
417 0 : ipsec_key_t *key = va_arg (*args, ipsec_key_t *);
418 : u8 *data;
419 :
420 0 : if (unformat (input, "%U", unformat_hex_string, &data))
421 : {
422 0 : ipsec_mk_key (key, data, vec_len (data));
423 0 : vec_free (data);
424 : }
425 : else
426 0 : return 0;
427 0 : return 1;
428 : }
429 :
430 : u8 *
431 35927 : format_ipsec_sa_flags (u8 * s, va_list * args)
432 : {
433 35927 : 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 35927 : foreach_ipsec_sa_flags
437 : #undef _
438 35927 : return (s);
439 : }
440 :
441 : u8 *
442 36009 : format_ipsec_sa (u8 * s, va_list * args)
443 : {
444 36009 : u32 sai = va_arg (*args, u32);
445 36009 : 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 36009 : if (pool_is_free_index (ipsec_sa_pool, sai))
451 : {
452 82 : s = format (s, "No such SA index: %d", sai);
453 82 : goto done;
454 : }
455 :
456 35927 : sa = ipsec_sa_get (sai);
457 :
458 35927 : 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 35927 : sa->protocol ? "esp" : "ah", format_ipsec_sa_flags, sa->flags);
461 :
462 35927 : if (!(flags & IPSEC_FORMAT_DETAIL))
463 34508 : goto done;
464 :
465 1419 : s = format (s, "\n locks %d", sa->node.fn_locks);
466 1419 : s = format (s, "\n salt 0x%x", clib_net_to_host_u32 (sa->salt));
467 1419 : s = format (s, "\n thread-index:%d", sa->thread_index);
468 1419 : s = format (s, "\n seq %u seq-hi %u", sa->seq, sa->seq_hi);
469 1419 : s = format (s, "\n window %U", format_ipsec_replay_window,
470 : sa->replay_window);
471 1419 : s = format (s, "\n crypto alg %U",
472 1419 : format_ipsec_crypto_alg, sa->crypto_alg);
473 1419 : if (sa->crypto_alg && (flags & IPSEC_FORMAT_INSECURE))
474 1350 : s = format (s, " key %U", format_ipsec_key, &sa->crypto_key);
475 : else
476 69 : s = format (s, " key [redacted]");
477 1419 : s = format (s, "\n integrity alg %U",
478 1419 : format_ipsec_integ_alg, sa->integ_alg);
479 1419 : if (sa->integ_alg && (flags & IPSEC_FORMAT_INSECURE))
480 947 : s = format (s, " key %U", format_ipsec_key, &sa->integ_key);
481 : else
482 472 : s = format (s, " key [redacted]");
483 1419 : s = format (s, "\n UDP:[src:%d dst:%d]",
484 1419 : clib_host_to_net_u16 (sa->udp_hdr.src_port),
485 1419 : clib_host_to_net_u16 (sa->udp_hdr.dst_port));
486 :
487 1419 : vlib_get_combined_counter (&ipsec_sa_counters, sai, &counts);
488 1419 : s = format (s, "\n tx/rx:[packets:%Ld bytes:%Ld]", counts.packets,
489 : counts.bytes);
490 1419 : 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 1419 : foreach_ipsec_sa_err
495 : #undef _
496 :
497 1419 : if (ipsec_sa_is_set_IS_TUNNEL (sa)) s =
498 615 : format (s, "\n%U", format_tunnel, &sa->tunnel, 3);
499 :
500 804 : done:
501 36009 : return (s);
502 : }
503 :
504 : u8 *
505 2106 : format_ipsec_tun_protect_index (u8 * s, va_list * args)
506 : {
507 2106 : u32 itpi = va_arg (*args, index_t);
508 : ipsec_tun_protect_t *itp;
509 :
510 2106 : if (pool_is_free_index (ipsec_tun_protect_pool, itpi))
511 0 : return (format (s, "No such tunnel index: %d", itpi));
512 :
513 2106 : itp = pool_elt_at_index (ipsec_tun_protect_pool, itpi);
514 :
515 2106 : return (format (s, "%U", format_ipsec_tun_protect, itp));
516 : }
517 :
518 : u8 *
519 2139 : format_ipsec_tun_protect_flags (u8 * s, va_list * args)
520 : {
521 2139 : ipsec_protect_flags_t flags = va_arg (*args, int);
522 :
523 2139 : if (IPSEC_PROTECT_NONE == flags)
524 1328 : 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 2139 : return (s);
532 : }
533 :
534 : u8 *
535 2139 : format_ipsec_tun_protect (u8 * s, va_list * args)
536 : {
537 2139 : ipsec_tun_protect_t *itp = va_arg (*args, ipsec_tun_protect_t *);
538 : u32 sai;
539 :
540 2139 : s = format (s, "%U flags:[%U]", format_vnet_sw_if_index_name,
541 : vnet_get_main (), itp->itp_sw_if_index,
542 2139 : format_ipsec_tun_protect_flags, itp->itp_flags);
543 2139 : if (!ip_address_is_zero (itp->itp_key))
544 1824 : s = format (s, ": %U", format_ip_address, itp->itp_key);
545 2139 : s = format (s, "\n output-sa:");
546 2139 : s = format (s, "\n %U", format_ipsec_sa, itp->itp_out_sa,
547 : IPSEC_FORMAT_BRIEF);
548 :
549 2139 : s = format (s, "\n input-sa:");
550 : /* *INDENT-OFF* */
551 4282 : 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 2139 : return (s);
558 : }
559 :
560 : u8 *
561 8556 : format_ipsec4_tunnel_kv (u8 * s, va_list * args)
562 : {
563 8556 : ipsec4_tunnel_kv_t *kv = va_arg (*args, ipsec4_tunnel_kv_t *);
564 : ip4_address_t ip;
565 : u32 spi;
566 :
567 8556 : ipsec4_tunnel_extract_key (kv, &ip, &spi);
568 :
569 8556 : 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 8556 : return (s);
576 : }
577 :
578 : u8 *
579 3304 : format_ipsec6_tunnel_kv (u8 * s, va_list * args)
580 : {
581 3304 : ipsec6_tunnel_kv_t *kv = va_arg (*args, ipsec6_tunnel_kv_t *);
582 :
583 3304 : 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 3304 : return (s);
590 : }
591 :
592 : u8 *
593 0 : format_ipsec_itf (u8 * s, va_list * a)
594 : {
595 0 : index_t ii = va_arg (*a, index_t);
596 : ipsec_itf_t *itf;
597 :
598 0 : itf = ipsec_itf_get (ii);
599 0 : s = format (s, "[%d] %U %U",
600 : ii, format_vnet_sw_if_index_name, vnet_get_main (),
601 0 : itf->ii_sw_if_index, format_tunnel_mode, itf->ii_mode);
602 :
603 0 : 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 : */
|