FD.io VPP  v17.07.01-10-g3be13f0
Vector Packet Processing
map.c
Go to the documentation of this file.
1 /*
2  * map.c : MAP 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/fib/fib_table.h>
19 #include <vnet/fib/ip6_fib.h>
20 #include <vnet/adj/adj.h>
21 #include <vnet/map/map_dpo.h>
22 #include <vppinfra/crc32.h>
23 
24 #include "map.h"
25 
26 /*
27  * This code supports the following MAP modes:
28  *
29  * Algorithmic Shared IPv4 address (ea_bits_len > 0):
30  * ea_bits_len + ip4_prefix > 32
31  * psid_length > 0, ip6_prefix < 64, ip4_prefix <= 32
32  * Algorithmic Full IPv4 address (ea_bits_len > 0):
33  * ea_bits_len + ip4_prefix = 32
34  * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
35  * Algorithmic IPv4 prefix (ea_bits_len > 0):
36  * ea_bits_len + ip4_prefix < 32
37  * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
38  *
39  * Independent Shared IPv4 address (ea_bits_len = 0):
40  * ip4_prefix = 32
41  * psid_length > 0
42  * Rule IPv6 address = 128, Rule PSID Set
43  * Independent Full IPv4 address (ea_bits_len = 0):
44  * ip4_prefix = 32
45  * psid_length = 0, ip6_prefix = 128
46  * Independent IPv4 prefix (ea_bits_len = 0):
47  * ip4_prefix < 32
48  * psid_length = 0, ip6_prefix = 128
49  *
50  */
51 
52 /*
53  * This code supports MAP-T:
54  *
55  * With DMR prefix length equal to 96.
56  *
57  */
58 
59 
60 
61 int
63  u8 ip4_prefix_len,
64  ip6_address_t * ip6_prefix,
65  u8 ip6_prefix_len,
66  ip6_address_t * ip6_src,
67  u8 ip6_src_len,
68  u8 ea_bits_len,
69  u8 psid_offset,
70  u8 psid_length, u32 * map_domain_index, u16 mtu, u8 flags)
71 {
72  u8 suffix_len, suffix_shift;
73  map_main_t *mm = &map_main;
74  dpo_id_t dpo_v4 = DPO_INVALID;
75  dpo_id_t dpo_v6 = DPO_INVALID;
76  map_domain_t *d;
77 
78  /* Sanity check on the src prefix length */
79  if (flags & MAP_DOMAIN_TRANSLATION)
80  {
81  if (ip6_src_len != 96)
82  {
83  clib_warning ("MAP-T only supports ip6_src_len = 96 for now.");
84  return -1;
85  }
86  }
87  else
88  {
89  if (ip6_src_len != 128)
90  {
92  ("MAP-E requires a BR address, not a prefix (ip6_src_len should "
93  "be 128).");
94  return -1;
95  }
96  }
97 
98  /* How many, and which bits to grab from the IPv4 DA */
99  if (ip4_prefix_len + ea_bits_len < 32)
100  {
101  flags |= MAP_DOMAIN_PREFIX;
102  suffix_shift = 32 - ip4_prefix_len - ea_bits_len;
103  suffix_len = ea_bits_len;
104  }
105  else
106  {
107  suffix_shift = 0;
108  suffix_len = 32 - ip4_prefix_len;
109  }
110 
111  /* EA bits must be within the first 64 bits */
112  if (ea_bits_len > 0 && ((ip6_prefix_len + ea_bits_len) > 64 ||
113  ip6_prefix_len + suffix_len + psid_length > 64))
114  {
116  ("Embedded Address bits must be within the first 64 bits of "
117  "the IPv6 prefix");
118  return -1;
119  }
120 
121  /* Get domain index */
123  memset (d, 0, sizeof (*d));
124  *map_domain_index = d - mm->domains;
125 
126  /* Init domain struct */
127  d->ip4_prefix.as_u32 = ip4_prefix->as_u32;
128  d->ip4_prefix_len = ip4_prefix_len;
129  d->ip6_prefix = *ip6_prefix;
130  d->ip6_prefix_len = ip6_prefix_len;
131  d->ip6_src = *ip6_src;
132  d->ip6_src_len = ip6_src_len;
133  d->ea_bits_len = ea_bits_len;
134  d->psid_offset = psid_offset;
135  d->psid_length = psid_length;
136  d->mtu = mtu;
137  d->flags = flags;
138  d->suffix_shift = suffix_shift;
139  d->suffix_mask = (1 << suffix_len) - 1;
140 
141  d->psid_shift = 16 - psid_length - psid_offset;
142  d->psid_mask = (1 << d->psid_length) - 1;
143  d->ea_shift = 64 - ip6_prefix_len - suffix_len - d->psid_length;
144 
145  /* MAP data-plane object */
146  if (d->flags & MAP_DOMAIN_TRANSLATION)
147  map_t_dpo_create (DPO_PROTO_IP4, *map_domain_index, &dpo_v4);
148  else
149  map_dpo_create (DPO_PROTO_IP4, *map_domain_index, &dpo_v4);
150 
151  /* Create ip4 route */
152  fib_prefix_t pfx = {
154  .fp_len = d->ip4_prefix_len,
155  .fp_addr = {
156  .ip4 = d->ip4_prefix,
157  }
158  ,
159  };
162  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
163  dpo_reset (&dpo_v4);
164 
165  /*
166  * construct a DPO to use the v6 domain
167  */
168  if (d->flags & MAP_DOMAIN_TRANSLATION)
169  map_t_dpo_create (DPO_PROTO_IP6, *map_domain_index, &dpo_v6);
170  else
171  map_dpo_create (DPO_PROTO_IP6, *map_domain_index, &dpo_v6);
172 
173  /*
174  * Multiple MAP domains may share same source IPv6 TEP. Which is just dandy.
175  * We are not tracking the sharing. So a v4 lookup to find the correct
176  * domain post decap/trnaslate is always done
177  *
178  * Create ip6 route. This is a reference counted add. If the prefix
179  * already exists and is MAP sourced, it is now MAP source n+1 times
180  * and will need to be removed n+1 times.
181  */
182  fib_prefix_t pfx6 = {
184  .fp_len = d->ip6_src_len,
185  .fp_addr.ip6 = d->ip6_src,
186  };
187 
190  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v6);
191  dpo_reset (&dpo_v6);
192 
193  /* Validate packet/byte counters */
195  int i;
196  for (i = 0; i < vec_len (mm->simple_domain_counters); i++)
197  {
199  *map_domain_index);
201  *map_domain_index);
202  }
203  for (i = 0; i < vec_len (mm->domain_counters); i++)
204  {
206  *map_domain_index);
207  vlib_zero_combined_counter (&mm->domain_counters[i], *map_domain_index);
208  }
210 
211  return 0;
212 }
213 
214 /*
215  * map_delete_domain
216  */
217 int
218 map_delete_domain (u32 map_domain_index)
219 {
220  map_main_t *mm = &map_main;
221  map_domain_t *d;
222 
223  if (pool_is_free_index (mm->domains, map_domain_index))
224  {
225  clib_warning ("MAP domain delete: domain does not exist: %d",
226  map_domain_index);
227  return -1;
228  }
229 
230  d = pool_elt_at_index (mm->domains, map_domain_index);
231 
232  fib_prefix_t pfx = {
234  .fp_len = d->ip4_prefix_len,
235  .fp_addr = {
236  .ip4 = d->ip4_prefix,
237  }
238  ,
239  };
241 
242  fib_prefix_t pfx6 = {
244  .fp_len = d->ip6_src_len,
245  .fp_addr = {
246  .ip6 = d->ip6_src,
247  }
248  ,
249  };
251 
252  /* Deleting rules */
253  if (d->rules)
254  clib_mem_free (d->rules);
255 
256  pool_put (mm->domains, d);
257 
258  return 0;
259 }
260 
261 int
262 map_add_del_psid (u32 map_domain_index, u16 psid, ip6_address_t * tep,
263  u8 is_add)
264 {
265  map_domain_t *d;
266  map_main_t *mm = &map_main;
267 
268  if (pool_is_free_index (mm->domains, map_domain_index))
269  {
270  clib_warning ("MAP rule: domain does not exist: %d", map_domain_index);
271  return -1;
272  }
273  d = pool_elt_at_index (mm->domains, map_domain_index);
274 
275  /* Rules are only used in 1:1 independent case */
276  if (d->ea_bits_len > 0)
277  return (-1);
278 
279  if (!d->rules)
280  {
281  u32 l = (0x1 << d->psid_length) * sizeof (ip6_address_t);
283  if (!d->rules)
284  return -1;
285  memset (d->rules, 0, l);
286  }
287 
288  if (psid >= (0x1 << d->psid_length))
289  {
290  clib_warning ("MAP rule: PSID outside bounds: %d [%d]", psid,
291  0x1 << d->psid_length);
292  return -1;
293  }
294 
295  if (is_add)
296  {
297  d->rules[psid] = *tep;
298  }
299  else
300  {
301  memset (&d->rules[psid], 0, sizeof (ip6_address_t));
302  }
303  return 0;
304 }
305 
306 #ifdef MAP_SKIP_IP6_LOOKUP
307 /**
308  * Pre-resolvd per-protocol global next-hops
309  */
311 
312 static void
314 {
317 }
318 
319 static u8 *
320 format_map_pre_resolve (u8 * s, va_list ap)
321 {
323 
324  if (FIB_NODE_INDEX_INVALID != pr->fei)
325  {
326  fib_prefix_t pfx;
327 
328  fib_entry_get_prefix (pr->fei, &pfx);
329 
330  return (format (s, "%U (%u)",
332  pr->dpo.dpoi_index));
333  }
334  else
335  {
336  return (format (s, "un-set"));
337  }
338 }
339 
340 
341 /**
342  * Function definition to inform the FIB node that its last lock has gone.
343  */
344 static void
346 {
347  /*
348  * The MAP is a root of the graph. As such
349  * it never has children and thus is never locked.
350  */
351  ASSERT (0);
352 }
353 
356 {
357 #if (CLIB_DEBUG > 0)
359 #endif
360  return ((map_main_pre_resolved_t *)
361  (((char *) node) -
363 }
364 
365 static void
367 {
368  const dpo_id_t *dpo;
369 
371 
372  dpo_copy (&pr->dpo, dpo);
373 }
374 
375 /**
376  * Function definition to backwalk a FIB node
377  */
380 {
381  map_stack (map_from_fib_node (node));
382 
384 }
385 
386 /**
387  * Function definition to get a FIB node from its index
388  */
389 static fib_node_t *
391 {
392  return (&pre_resolved[index].node);
393 }
394 
395 /*
396  * Virtual function table registered by MPLS GRE tunnels
397  * for participation in the FIB object graph.
398  */
399 const static fib_node_vft_t map_vft = {
401  .fnv_last_lock = map_last_lock_gone,
402  .fnv_back_walk = map_back_walk,
403 };
404 
405 static void
407  fib_protocol_t proto, u8 len, const ip46_address_t * addr)
408 {
409  fib_prefix_t pfx = {
410  .fp_proto = proto,
411  .fp_len = len,
412  .fp_addr = *addr,
413  };
414 
415  pr->fei = fib_table_entry_special_add (0, // default fib
416  &pfx,
419  map_stack (pr);
420 }
421 
422 static void
424  fib_protocol_t proto, u8 len, const ip46_address_t * addr)
425 {
426  fib_prefix_t pfx = {
427  .fp_proto = proto,
428  .fp_len = len,
429  .fp_addr = *addr,
430  };
431 
433 
434  fib_table_entry_special_remove (0, // default fib
435  &pfx, FIB_SOURCE_RR);
436  dpo_reset (&pr->dpo);
437 
440 }
441 
442 static void
443 map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6, int is_del)
444 {
445  if (ip6 && (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0))
446  {
447  ip46_address_t addr = {
448  .ip6 = *ip6,
449  };
450  if (is_del)
451  map_fib_unresolve (&pre_resolved[FIB_PROTOCOL_IP6],
452  FIB_PROTOCOL_IP6, 128, &addr);
453  else
454  map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP6],
455  FIB_PROTOCOL_IP6, 128, &addr);
456  }
457  if (ip4 && (ip4->as_u32 != 0))
458  {
459  ip46_address_t addr = {
460  .ip4 = *ip4,
461  };
462  if (is_del)
463  map_fib_unresolve (&pre_resolved[FIB_PROTOCOL_IP4],
464  FIB_PROTOCOL_IP4, 32, &addr);
465  else
466  map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP4],
467  FIB_PROTOCOL_IP4, 32, &addr);
468  }
469 }
470 #endif
471 
472 static clib_error_t *
474  unformat_input_t * input,
475  vlib_cli_command_t * cmd)
476 {
477  unformat_input_t _line_input, *line_input = &_line_input;
478  map_main_t *mm = &map_main;
479  clib_error_t *error = NULL;
480 
481  /* Get a line of input. */
482  if (!unformat_user (input, unformat_line_input, line_input))
483  return 0;
484 
485  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
486  {
487  if (unformat (line_input, "off"))
488  mm->sec_check = false;
489  else if (unformat (line_input, "on"))
490  mm->sec_check = true;
491  else
492  {
493  error = clib_error_return (0, "unknown input `%U'",
494  format_unformat_error, line_input);
495  goto done;
496  }
497  }
498 
499 done:
500  unformat_free (line_input);
501 
502  return error;
503 }
504 
505 static clib_error_t *
507  unformat_input_t * input,
508  vlib_cli_command_t * cmd)
509 {
510  unformat_input_t _line_input, *line_input = &_line_input;
511  map_main_t *mm = &map_main;
512  clib_error_t *error = NULL;
513 
514  /* Get a line of input. */
515  if (!unformat_user (input, unformat_line_input, line_input))
516  return 0;
517 
518  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
519  {
520  if (unformat (line_input, "off"))
521  mm->sec_check_frag = false;
522  else if (unformat (line_input, "on"))
523  mm->sec_check_frag = true;
524  else
525  {
526  error = clib_error_return (0, "unknown input `%U'",
527  format_unformat_error, line_input);
528  goto done;
529  }
530  }
531 
532 done:
533  unformat_free (line_input);
534 
535  return error;
536 }
537 
538 static clib_error_t *
540  unformat_input_t * input, vlib_cli_command_t * cmd)
541 {
542  unformat_input_t _line_input, *line_input = &_line_input;
543  ip4_address_t ip4_prefix;
544  ip6_address_t ip6_prefix;
545  ip6_address_t ip6_src;
546  u32 ip6_prefix_len = 0, ip4_prefix_len = 0, map_domain_index, ip6_src_len;
547  u32 num_m_args = 0;
548  /* Optional arguments */
549  u32 ea_bits_len = 0, psid_offset = 0, psid_length = 0;
550  u32 mtu = 0;
551  u8 flags = 0;
552  ip6_src_len = 128;
553  clib_error_t *error = NULL;
554 
555  /* Get a line of input. */
556  if (!unformat_user (input, unformat_line_input, line_input))
557  return 0;
558 
559  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
560  {
561  if (unformat
562  (line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix,
563  &ip4_prefix_len))
564  num_m_args++;
565  else
566  if (unformat
567  (line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix,
568  &ip6_prefix_len))
569  num_m_args++;
570  else
571  if (unformat
572  (line_input, "ip6-src %U/%d", unformat_ip6_address, &ip6_src,
573  &ip6_src_len))
574  num_m_args++;
575  else
576  if (unformat
577  (line_input, "ip6-src %U", unformat_ip6_address, &ip6_src))
578  num_m_args++;
579  else if (unformat (line_input, "ea-bits-len %d", &ea_bits_len))
580  num_m_args++;
581  else if (unformat (line_input, "psid-offset %d", &psid_offset))
582  num_m_args++;
583  else if (unformat (line_input, "psid-len %d", &psid_length))
584  num_m_args++;
585  else if (unformat (line_input, "mtu %d", &mtu))
586  num_m_args++;
587  else if (unformat (line_input, "map-t"))
588  flags |= MAP_DOMAIN_TRANSLATION;
589  else
590  {
591  error = clib_error_return (0, "unknown input `%U'",
592  format_unformat_error, line_input);
593  goto done;
594  }
595  }
596 
597  if (num_m_args < 3)
598  {
599  error = clib_error_return (0, "mandatory argument(s) missing");
600  goto done;
601  }
602 
603  map_create_domain (&ip4_prefix, ip4_prefix_len,
604  &ip6_prefix, ip6_prefix_len, &ip6_src, ip6_src_len,
605  ea_bits_len, psid_offset, psid_length, &map_domain_index,
606  mtu, flags);
607 
608 done:
609  unformat_free (line_input);
610 
611  return error;
612 }
613 
614 static clib_error_t *
616  unformat_input_t * input, vlib_cli_command_t * cmd)
617 {
618  unformat_input_t _line_input, *line_input = &_line_input;
619  u32 num_m_args = 0;
620  u32 map_domain_index;
621  clib_error_t *error = NULL;
622 
623  /* Get a line of input. */
624  if (!unformat_user (input, unformat_line_input, line_input))
625  return 0;
626 
627  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
628  {
629  if (unformat (line_input, "index %d", &map_domain_index))
630  num_m_args++;
631  else
632  {
633  error = clib_error_return (0, "unknown input `%U'",
634  format_unformat_error, line_input);
635  goto done;
636  }
637  }
638 
639  if (num_m_args != 1)
640  {
641  error = clib_error_return (0, "mandatory argument(s) missing");
642  goto done;
643  }
644 
645  map_delete_domain (map_domain_index);
646 
647 done:
648  unformat_free (line_input);
649 
650  return error;
651 }
652 
653 static clib_error_t *
655  unformat_input_t * input, vlib_cli_command_t * cmd)
656 {
657  unformat_input_t _line_input, *line_input = &_line_input;
658  ip6_address_t tep;
659  u32 num_m_args = 0;
660  u32 psid = 0, map_domain_index;
661  clib_error_t *error = NULL;
662 
663  /* Get a line of input. */
664  if (!unformat_user (input, unformat_line_input, line_input))
665  return 0;
666 
667  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
668  {
669  if (unformat (line_input, "index %d", &map_domain_index))
670  num_m_args++;
671  else if (unformat (line_input, "psid %d", &psid))
672  num_m_args++;
673  else
674  if (unformat (line_input, "ip6-dst %U", unformat_ip6_address, &tep))
675  num_m_args++;
676  else
677  {
678  error = clib_error_return (0, "unknown input `%U'",
679  format_unformat_error, line_input);
680  goto done;
681  }
682  }
683 
684  if (num_m_args != 3)
685  {
686  error = clib_error_return (0, "mandatory argument(s) missing");
687  goto done;
688  }
689 
690  if (map_add_del_psid (map_domain_index, psid, &tep, 1) != 0)
691  {
692  error = clib_error_return (0, "Failing to add Mapping Rule");
693  goto done;
694  }
695 
696 done:
697  unformat_free (line_input);
698 
699  return error;
700 }
701 
702 #if MAP_SKIP_IP6_LOOKUP
703 static clib_error_t *
705  unformat_input_t * input,
706  vlib_cli_command_t * cmd)
707 {
708  unformat_input_t _line_input, *line_input = &_line_input;
709  ip4_address_t ip4nh, *p_v4 = NULL;
710  ip6_address_t ip6nh, *p_v6 = NULL;
711  clib_error_t *error = NULL;
712  int is_del = 0;
713 
714  memset (&ip4nh, 0, sizeof (ip4nh));
715  memset (&ip6nh, 0, sizeof (ip6nh));
716 
717  /* Get a line of input. */
718  if (!unformat_user (input, unformat_line_input, line_input))
719  return 0;
720 
721  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
722  {
723  if (unformat (line_input, "ip4-nh %U", unformat_ip4_address, &ip4nh))
724  p_v4 = &ip4nh;
725  else
726  if (unformat (line_input, "ip6-nh %U", unformat_ip6_address, &ip6nh))
727  p_v6 = &ip6nh;
728  else if (unformat (line_input, "del"))
729  is_del = 1;
730  else
731  {
732  error = clib_error_return (0, "unknown input `%U'",
733  format_unformat_error, line_input);
734  goto done;
735  }
736  }
737 
738  map_pre_resolve (p_v4, p_v6, is_del);
739 
740 done:
741  unformat_free (line_input);
742 
743  return error;
744 }
745 #endif
746 
747 static clib_error_t *
749  unformat_input_t * input,
750  vlib_cli_command_t * cmd)
751 {
752  unformat_input_t _line_input, *line_input = &_line_input;
753  ip4_address_t icmp_src_address;
754  map_main_t *mm = &map_main;
755  clib_error_t *error = NULL;
756 
757  mm->icmp4_src_address.as_u32 = 0;
758 
759  /* Get a line of input. */
760  if (!unformat_user (input, unformat_line_input, line_input))
761  return 0;
762 
763  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
764  {
765  if (unformat
766  (line_input, "%U", unformat_ip4_address, &icmp_src_address))
767  mm->icmp4_src_address = icmp_src_address;
768  else
769  {
770  error = clib_error_return (0, "unknown input `%U'",
771  format_unformat_error, line_input);
772  goto done;
773  }
774  }
775 
776 done:
777  unformat_free (line_input);
778 
779  return error;
780 }
781 
782 static clib_error_t *
784  unformat_input_t * input,
785  vlib_cli_command_t * cmd)
786 {
787  unformat_input_t _line_input, *line_input = &_line_input;
788  map_main_t *mm = &map_main;
789  int num_m_args = 0;
790  clib_error_t *error = NULL;
791 
792  /* Get a line of input. */
793  if (!unformat_user (input, unformat_line_input, line_input))
794  return 0;
795 
796  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
797  {
798  num_m_args++;
799  if (unformat (line_input, "on"))
800  mm->icmp6_enabled = true;
801  else if (unformat (line_input, "off"))
802  mm->icmp6_enabled = false;
803  else
804  {
805  error = clib_error_return (0, "unknown input `%U'",
806  format_unformat_error, line_input);
807  goto done;
808  }
809  }
810 
811 
812  if (num_m_args != 1)
813  error = clib_error_return (0, "mandatory argument(s) missing");
814 
815 done:
816  unformat_free (line_input);
817 
818  return error;
819 }
820 
821 static clib_error_t *
823  unformat_input_t * input, vlib_cli_command_t * cmd)
824 {
825  unformat_input_t _line_input, *line_input = &_line_input;
826  map_main_t *mm = &map_main;
827  clib_error_t *error = NULL;
828 
829  /* Get a line of input. */
830  if (!unformat_user (input, unformat_line_input, line_input))
831  return 0;
832 
833  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
834  {
835  if (unformat (line_input, "inner"))
836  mm->frag_inner = true;
837  else if (unformat (line_input, "outer"))
838  mm->frag_inner = false;
839  else
840  {
841  error = clib_error_return (0, "unknown input `%U'",
842  format_unformat_error, line_input);
843  goto done;
844  }
845  }
846 
847 done:
848  unformat_free (line_input);
849 
850  return error;
851 }
852 
853 static clib_error_t *
855  unformat_input_t * input,
856  vlib_cli_command_t * cmd)
857 {
858  unformat_input_t _line_input, *line_input = &_line_input;
859  map_main_t *mm = &map_main;
860  clib_error_t *error = NULL;
861 
862  /* Get a line of input. */
863  if (!unformat_user (input, unformat_line_input, line_input))
864  return 0;
865 
866  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
867  {
868  if (unformat (line_input, "on"))
869  mm->frag_ignore_df = true;
870  else if (unformat (line_input, "off"))
871  mm->frag_ignore_df = false;
872  else
873  {
874  error = clib_error_return (0, "unknown input `%U'",
875  format_unformat_error, line_input);
876  goto done;
877  }
878  }
879 
880 done:
881  unformat_free (line_input);
882 
883  return error;
884 }
885 
886 static clib_error_t *
888  unformat_input_t * input,
889  vlib_cli_command_t * cmd)
890 {
891  unformat_input_t _line_input, *line_input = &_line_input;
892  map_main_t *mm = &map_main;
893  u32 tc = 0;
894  clib_error_t *error = NULL;
895 
896  mm->tc_copy = false;
897 
898  /* Get a line of input. */
899  if (!unformat_user (input, unformat_line_input, line_input))
900  return 0;
901 
902  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
903  {
904  if (unformat (line_input, "copy"))
905  mm->tc_copy = true;
906  else if (unformat (line_input, "%x", &tc))
907  mm->tc = tc & 0xff;
908  else
909  {
910  error = clib_error_return (0, "unknown input `%U'",
911  format_unformat_error, line_input);
912  goto done;
913  }
914  }
915 
916 done:
917  unformat_free (line_input);
918 
919  return error;
920 }
921 
922 static u8 *
923 format_map_domain (u8 * s, va_list * args)
924 {
925  map_domain_t *d = va_arg (*args, map_domain_t *);
926  bool counters = va_arg (*args, int);
927  map_main_t *mm = &map_main;
928  ip6_address_t ip6_prefix;
929 
930  if (d->rules)
931  memset (&ip6_prefix, 0, sizeof (ip6_prefix));
932  else
933  ip6_prefix = d->ip6_prefix;
934 
935  s = format (s,
936  "[%d] ip4-pfx %U/%d ip6-pfx %U/%d ip6-src %U/%d ea_bits_len %d psid-offset %d psid-len %d mtu %d %s",
937  d - mm->domains,
939  format_ip6_address, &ip6_prefix, d->ip6_prefix_len,
941  d->ea_bits_len, d->psid_offset, d->psid_length, d->mtu,
942  (d->flags & MAP_DOMAIN_TRANSLATION) ? "map-t" : "");
943 
944  if (counters)
945  {
949  d - mm->domains, &v);
950  s = format (s, " TX: %lld/%lld", v.packets, v.bytes);
952  d - mm->domains, &v);
953  s = format (s, " RX: %lld/%lld", v.packets, v.bytes);
955  }
956  s = format (s, "\n");
957 
958  if (d->rules)
959  {
960  int i;
961  ip6_address_t dst;
962  for (i = 0; i < (0x1 << d->psid_length); i++)
963  {
964  dst = d->rules[i];
965  if (dst.as_u64[0] == 0 && dst.as_u64[1] == 0)
966  continue;
967  s = format (s,
968  " rule psid: %d ip6-dst %U\n", i, format_ip6_address,
969  &dst);
970  }
971  }
972  return s;
973 }
974 
975 static u8 *
976 format_map_ip4_reass (u8 * s, va_list * args)
977 {
978  map_main_t *mm = &map_main;
979  map_ip4_reass_t *r = va_arg (*args, map_ip4_reass_t *);
980  map_ip4_reass_key_t *k = &r->key;
981  f64 now = vlib_time_now (mm->vlib_main);
982  f64 lifetime = (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000);
983  f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
984  s = format (s,
985  "ip4-reass src=%U dst=%U protocol=%d identifier=%d port=%d lifetime=%.3lf\n",
986  format_ip4_address, &k->src.as_u8, format_ip4_address,
987  &k->dst.as_u8, k->protocol,
988  clib_net_to_host_u16 (k->fragment_id),
989  (r->port >= 0) ? clib_net_to_host_u16 (r->port) : -1, dt);
990  return s;
991 }
992 
993 static u8 *
994 format_map_ip6_reass (u8 * s, va_list * args)
995 {
996  map_main_t *mm = &map_main;
997  map_ip6_reass_t *r = va_arg (*args, map_ip6_reass_t *);
998  map_ip6_reass_key_t *k = &r->key;
999  f64 now = vlib_time_now (mm->vlib_main);
1000  f64 lifetime = (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000);
1001  f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
1002  s = format (s,
1003  "ip6-reass src=%U dst=%U protocol=%d identifier=%d lifetime=%.3lf\n",
1004  format_ip6_address, &k->src.as_u8, format_ip6_address,
1005  &k->dst.as_u8, k->protocol,
1006  clib_net_to_host_u32 (k->fragment_id), dt);
1007  return s;
1008 }
1009 
1010 static clib_error_t *
1012  vlib_cli_command_t * cmd)
1013 {
1014  unformat_input_t _line_input, *line_input = &_line_input;
1015  map_main_t *mm = &map_main;
1016  map_domain_t *d;
1017  bool counters = false;
1018  u32 map_domain_index = ~0;
1019  clib_error_t *error = NULL;
1020 
1021  /* Get a line of input. */
1022  if (!unformat_user (input, unformat_line_input, line_input))
1023  return 0;
1024 
1025  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1026  {
1027  if (unformat (line_input, "counters"))
1028  counters = true;
1029  else if (unformat (line_input, "index %d", &map_domain_index))
1030  ;
1031  else
1032  {
1033  error = clib_error_return (0, "unknown input `%U'",
1034  format_unformat_error, line_input);
1035  goto done;
1036  }
1037  }
1038 
1039  if (pool_elts (mm->domains) == 0)
1040  vlib_cli_output (vm, "No MAP domains are configured...");
1041 
1042  if (map_domain_index == ~0)
1043  {
1044  /* *INDENT-OFF* */
1045  pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_map_domain, d, counters);}));
1046  /* *INDENT-ON* */
1047  }
1048  else
1049  {
1050  if (pool_is_free_index (mm->domains, map_domain_index))
1051  {
1052  error = clib_error_return (0, "MAP domain does not exists %d",
1053  map_domain_index);
1054  goto done;
1055  }
1056 
1057  d = pool_elt_at_index (mm->domains, map_domain_index);
1058  vlib_cli_output (vm, "%U", format_map_domain, d, counters);
1059  }
1060 
1061 done:
1062  unformat_free (line_input);
1063 
1064  return error;
1065 }
1066 
1067 static clib_error_t *
1069  vlib_cli_command_t * cmd)
1070 {
1071  map_main_t *mm = &map_main;
1072  map_ip4_reass_t *f4;
1073  map_ip6_reass_t *f6;
1074 
1075  /* *INDENT-OFF* */
1076  pool_foreach(f4, mm->ip4_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip4_reass, f4);}));
1077  /* *INDENT-ON* */
1078  /* *INDENT-OFF* */
1079  pool_foreach(f6, mm->ip6_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip6_reass, f6);}));
1080  /* *INDENT-ON* */
1081  return (0);
1082 }
1083 
1084 u64
1085 map_error_counter_get (u32 node_index, map_error_t map_error)
1086 {
1087  vlib_main_t *vm = vlib_get_main ();
1088  vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, node_index);
1089  vlib_error_main_t *em = &vm->error_main;
1090  vlib_error_t e = error_node->errors[map_error];
1091  vlib_node_t *n = vlib_get_node (vm, node_index);
1092  u32 ci;
1093 
1094  ci = vlib_error_get_code (e);
1095  ASSERT (ci < n->n_errors);
1096  ci += n->error_heap_index;
1097 
1098  return (em->counters[ci]);
1099 }
1100 
1101 static clib_error_t *
1103  vlib_cli_command_t * cmd)
1104 {
1105  map_main_t *mm = &map_main;
1106  map_domain_t *d;
1107  int domains = 0, rules = 0, domaincount = 0, rulecount = 0;
1108  if (pool_elts (mm->domains) == 0)
1109  {
1110  vlib_cli_output (vm, "No MAP domains are configured...");
1111  return 0;
1112  }
1113 
1114  /* *INDENT-OFF* */
1115  pool_foreach(d, mm->domains, ({
1116  if (d->rules) {
1117  rulecount+= 0x1 << d->psid_length;
1118  rules += sizeof(ip6_address_t) * 0x1 << d->psid_length;
1119  }
1120  domains += sizeof(*d);
1121  domaincount++;
1122  }));
1123  /* *INDENT-ON* */
1124 
1125  vlib_cli_output (vm, "MAP domains structure: %d\n", sizeof (map_domain_t));
1126  vlib_cli_output (vm, "MAP domains: %d (%d bytes)\n", domaincount, domains);
1127  vlib_cli_output (vm, "MAP rules: %d (%d bytes)\n", rulecount, rules);
1128  vlib_cli_output (vm, "Total: %d bytes)\n", rules + domains);
1129 
1130 #if MAP_SKIP_IP6_LOOKUP
1131  vlib_cli_output (vm,
1132  "MAP pre-resolve: IP6 next-hop: %U, IP4 next-hop: %U\n",
1133  format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP6],
1134  format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP4]);
1135 
1136 #endif
1137 
1138  if (mm->tc_copy)
1139  vlib_cli_output (vm, "MAP traffic-class: copy");
1140  else
1141  vlib_cli_output (vm, "MAP traffic-class: %x", mm->tc);
1142 
1143  vlib_cli_output (vm,
1144  "MAP IPv6 inbound security check: %s, fragmented packet security check: %s",
1145  mm->sec_check ? "enabled" : "disabled",
1146  mm->sec_check_frag ? "enabled" : "disabled");
1147 
1148  vlib_cli_output (vm, "ICMP-relay IPv4 source address: %U\n",
1149  format_ip4_address, &mm->icmp4_src_address);
1150  vlib_cli_output (vm, "ICMP6 unreachables sent for unmatched packets: %s\n",
1151  mm->icmp6_enabled ? "enabled" : "disabled");
1152  vlib_cli_output (vm, "Inner fragmentation: %s\n",
1153  mm->frag_inner ? "enabled" : "disabled");
1154  vlib_cli_output (vm, "Fragment packets regardless of DF flag: %s\n",
1155  mm->frag_ignore_df ? "enabled" : "disabled");
1156 
1157  /*
1158  * Counters
1159  */
1160  vlib_combined_counter_main_t *cm = mm->domain_counters;
1161  u64 total_pkts[MAP_N_DOMAIN_COUNTER];
1162  u64 total_bytes[MAP_N_DOMAIN_COUNTER];
1163  int which, i;
1164  vlib_counter_t v;
1165 
1166  memset (total_pkts, 0, sizeof (total_pkts));
1167  memset (total_bytes, 0, sizeof (total_bytes));
1168 
1170  vec_foreach (cm, mm->domain_counters)
1171  {
1172  which = cm - mm->domain_counters;
1173 
1174  for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
1175  {
1176  vlib_get_combined_counter (cm, i, &v);
1177  total_pkts[which] += v.packets;
1178  total_bytes[which] += v.bytes;
1179  }
1180  }
1182 
1183  vlib_cli_output (vm, "Encapsulated packets: %lld bytes: %lld\n",
1184  total_pkts[MAP_DOMAIN_COUNTER_TX],
1185  total_bytes[MAP_DOMAIN_COUNTER_TX]);
1186  vlib_cli_output (vm, "Decapsulated packets: %lld bytes: %lld\n",
1187  total_pkts[MAP_DOMAIN_COUNTER_RX],
1188  total_bytes[MAP_DOMAIN_COUNTER_RX]);
1189 
1190  vlib_cli_output (vm, "ICMP relayed packets: %d\n",
1191  vlib_get_simple_counter (&mm->icmp_relayed, 0));
1192 
1193  return 0;
1194 }
1195 
1196 static clib_error_t *
1198  vlib_cli_command_t * cmd)
1199 {
1200  unformat_input_t _line_input, *line_input = &_line_input;
1201  u32 lifetime = ~0;
1202  f64 ht_ratio = (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1);
1203  u32 pool_size = ~0;
1204  u64 buffers = ~(0ull);
1205  u8 ip4 = 0, ip6 = 0;
1206 
1207  if (!unformat_user (input, unformat_line_input, line_input))
1208  return 0;
1209 
1210  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1211  {
1212  if (unformat (line_input, "lifetime %u", &lifetime))
1213  ;
1214  else if (unformat (line_input, "ht-ratio %lf", &ht_ratio))
1215  ;
1216  else if (unformat (line_input, "pool-size %u", &pool_size))
1217  ;
1218  else if (unformat (line_input, "buffers %llu", &buffers))
1219  ;
1220  else if (unformat (line_input, "ip4"))
1221  ip4 = 1;
1222  else if (unformat (line_input, "ip6"))
1223  ip6 = 1;
1224  else
1225  {
1226  unformat_free (line_input);
1227  return clib_error_return (0, "invalid input");
1228  }
1229  }
1230  unformat_free (line_input);
1231 
1232  if (!ip4 && !ip6)
1233  return clib_error_return (0, "must specify ip4 and/or ip6");
1234 
1235  if (ip4)
1236  {
1237  if (pool_size != ~0 && pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1238  return clib_error_return (0, "invalid ip4-reass pool-size ( > %d)",
1240  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1241  && ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1242  return clib_error_return (0, "invalid ip4-reass ht-ratio ( > %d)",
1244  if (lifetime != ~0 && lifetime > MAP_IP4_REASS_CONF_LIFETIME_MAX)
1245  return clib_error_return (0, "invalid ip4-reass lifetime ( > %d)",
1247  if (buffers != ~(0ull) && buffers > MAP_IP4_REASS_CONF_BUFFERS_MAX)
1248  return clib_error_return (0, "invalid ip4-reass buffers ( > %ld)",
1250  }
1251 
1252  if (ip6)
1253  {
1254  if (pool_size != ~0 && pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1255  return clib_error_return (0, "invalid ip6-reass pool-size ( > %d)",
1257  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1258  && ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1259  return clib_error_return (0, "invalid ip6-reass ht-log2len ( > %d)",
1261  if (lifetime != ~0 && lifetime > MAP_IP6_REASS_CONF_LIFETIME_MAX)
1262  return clib_error_return (0, "invalid ip6-reass lifetime ( > %d)",
1264  if (buffers != ~(0ull) && buffers > MAP_IP6_REASS_CONF_BUFFERS_MAX)
1265  return clib_error_return (0, "invalid ip6-reass buffers ( > %ld)",
1267  }
1268 
1269  if (ip4)
1270  {
1271  u32 reass = 0, packets = 0;
1272  if (pool_size != ~0)
1273  {
1274  if (map_ip4_reass_conf_pool_size (pool_size, &reass, &packets))
1275  {
1276  vlib_cli_output (vm, "Could not set ip4-reass pool-size");
1277  }
1278  else
1279  {
1280  vlib_cli_output (vm,
1281  "Setting ip4-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1282  reass, packets);
1283  }
1284  }
1285  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1286  {
1287  if (map_ip4_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1288  {
1289  vlib_cli_output (vm, "Could not set ip4-reass ht-log2len");
1290  }
1291  else
1292  {
1293  vlib_cli_output (vm,
1294  "Setting ip4-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1295  reass, packets);
1296  }
1297  }
1298  if (lifetime != ~0)
1299  {
1300  if (map_ip4_reass_conf_lifetime (lifetime))
1301  vlib_cli_output (vm, "Could not set ip4-reass lifetime");
1302  else
1303  vlib_cli_output (vm, "Setting ip4-reass lifetime");
1304  }
1305  if (buffers != ~(0ull))
1306  {
1307  if (map_ip4_reass_conf_buffers (buffers))
1308  vlib_cli_output (vm, "Could not set ip4-reass buffers");
1309  else
1310  vlib_cli_output (vm, "Setting ip4-reass buffers");
1311  }
1312 
1316  {
1317  vlib_cli_output (vm,
1318  "Note: 'ip4-reass buffers' > pool-size * max-fragments-per-reassembly.");
1319  }
1320  }
1321 
1322  if (ip6)
1323  {
1324  u32 reass = 0, packets = 0;
1325  if (pool_size != ~0)
1326  {
1327  if (map_ip6_reass_conf_pool_size (pool_size, &reass, &packets))
1328  {
1329  vlib_cli_output (vm, "Could not set ip6-reass pool-size");
1330  }
1331  else
1332  {
1333  vlib_cli_output (vm,
1334  "Setting ip6-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1335  reass, packets);
1336  }
1337  }
1338  if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1339  {
1340  if (map_ip6_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1341  {
1342  vlib_cli_output (vm, "Could not set ip6-reass ht-log2len");
1343  }
1344  else
1345  {
1346  vlib_cli_output (vm,
1347  "Setting ip6-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1348  reass, packets);
1349  }
1350  }
1351  if (lifetime != ~0)
1352  {
1353  if (map_ip6_reass_conf_lifetime (lifetime))
1354  vlib_cli_output (vm, "Could not set ip6-reass lifetime");
1355  else
1356  vlib_cli_output (vm, "Setting ip6-reass lifetime");
1357  }
1358  if (buffers != ~(0ull))
1359  {
1360  if (map_ip6_reass_conf_buffers (buffers))
1361  vlib_cli_output (vm, "Could not set ip6-reass buffers");
1362  else
1363  vlib_cli_output (vm, "Setting ip6-reass buffers");
1364  }
1365 
1369  {
1370  vlib_cli_output (vm,
1371  "Note: 'ip6-reass buffers' > pool-size * max-fragments-per-reassembly.");
1372  }
1373  }
1374 
1375  return 0;
1376 }
1377 
1378 
1379 /*
1380  * packet trace format function
1381  */
1382 u8 *
1383 format_map_trace (u8 * s, va_list * args)
1384 {
1385  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1386  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1387  map_trace_t *t = va_arg (*args, map_trace_t *);
1388  u32 map_domain_index = t->map_domain_index;
1389  u16 port = t->port;
1390 
1391  s =
1392  format (s, "MAP domain index: %d L4 port: %u", map_domain_index,
1393  clib_net_to_host_u16 (port));
1394 
1395  return s;
1396 }
1397 
1400 {
1401  map_main_t *mm = &map_main;
1402  u32 ri = mm->ip4_reass_hash_table[bucket];
1403  while (ri != MAP_REASS_INDEX_NONE)
1404  {
1406  if (r->key.as_u64[0] == k->as_u64[0] &&
1407  r->key.as_u64[1] == k->as_u64[1] &&
1408  now < r->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000))
1409  {
1410  return r;
1411  }
1412  ri = r->bucket_next;
1413  }
1414  return NULL;
1415 }
1416 
1417 #define map_ip4_reass_pool_index(r) (r - map_main.ip4_reass_pool)
1418 
1419 void
1421 {
1422  map_main_t *mm = &map_main;
1423  map_ip4_reass_get_fragments (r, pi_to_drop);
1424 
1425  // Unlink in hash bucket
1426  map_ip4_reass_t *r2 = NULL;
1427  u32 r2i = mm->ip4_reass_hash_table[r->bucket];
1428  while (r2i != map_ip4_reass_pool_index (r))
1429  {
1430  ASSERT (r2i != MAP_REASS_INDEX_NONE);
1431  r2 = pool_elt_at_index (mm->ip4_reass_pool, r2i);
1432  r2i = r2->bucket_next;
1433  }
1434  if (r2)
1435  {
1436  r2->bucket_next = r->bucket_next;
1437  }
1438  else
1439  {
1441  }
1442 
1443  // Unlink in list
1444  if (r->fifo_next == map_ip4_reass_pool_index (r))
1445  {
1447  }
1448  else
1449  {
1451  mm->ip4_reass_fifo_last = r->fifo_prev;
1452  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next =
1453  r->fifo_next;
1454  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev =
1455  r->fifo_prev;
1456  }
1457 
1458  pool_put (mm->ip4_reass_pool, r);
1459  mm->ip4_reass_allocated--;
1460 }
1461 
1463 map_ip4_reass_get (u32 src, u32 dst, u16 fragment_id,
1464  u8 protocol, u32 ** pi_to_drop)
1465 {
1466  map_ip4_reass_t *r;
1467  map_main_t *mm = &map_main;
1468  map_ip4_reass_key_t k = {.src.data_u32 = src,
1469  .dst.data_u32 = dst,
1470  .fragment_id = fragment_id,
1471  .protocol = protocol
1472  };
1473 
1474  u32 h = 0;
1475 #ifdef clib_crc32c_uses_intrinsics
1476  h = clib_crc32c ((u8 *) k.as_u32, 16);
1477 #else
1478  u64 tmp = k.as_u32[0] ^ k.as_u32[1] ^ k.as_u32[2] ^ k.as_u32[3];
1479  h = clib_xxhash (tmp);
1480 #endif
1481  h = h >> (32 - mm->ip4_reass_ht_log2len);
1482 
1483  f64 now = vlib_time_now (mm->vlib_main);
1484 
1485  //Cache garbage collection
1487  {
1490  if (last->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000) < now)
1491  map_ip4_reass_free (last, pi_to_drop);
1492  else
1493  break;
1494  }
1495 
1496  if ((r = map_ip4_reass_lookup (&k, h, now)))
1497  return r;
1498 
1500  return NULL;
1501 
1502  pool_get (mm->ip4_reass_pool, r);
1503  mm->ip4_reass_allocated++;
1504  int i;
1505  for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1506  r->fragments[i] = ~0;
1507 
1508  u32 ri = map_ip4_reass_pool_index (r);
1509 
1510  //Link in new bucket
1511  r->bucket = h;
1512  r->bucket_next = mm->ip4_reass_hash_table[h];
1513  mm->ip4_reass_hash_table[h] = ri;
1514 
1515  //Link in fifo
1517  {
1518  r->fifo_next =
1520  mm->ip4_reass_fifo_last)->fifo_next;
1521  r->fifo_prev = mm->ip4_reass_fifo_last;
1522  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next = ri;
1523  pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev = ri;
1524  }
1525  else
1526  {
1527  r->fifo_next = r->fifo_prev = ri;
1528  mm->ip4_reass_fifo_last = ri;
1529  }
1530 
1531  //Set other fields
1532  r->ts = now;
1533  r->key = k;
1534  r->port = -1;
1535 #ifdef MAP_IP4_REASS_COUNT_BYTES
1536  r->expected_total = 0xffff;
1537  r->forwarded = 0;
1538 #endif
1539 
1540  return r;
1541 }
1542 
1543 int
1545 {
1547  return -1;
1548 
1549  int i;
1550  for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1551  if (r->fragments[i] == ~0)
1552  {
1553  r->fragments[i] = pi;
1555  return 0;
1556  }
1557  return -1;
1558 }
1559 
1562 {
1563  map_main_t *mm = &map_main;
1564  u32 ri = mm->ip6_reass_hash_table[bucket];
1565  while (ri != MAP_REASS_INDEX_NONE)
1566  {
1568  if (now < r->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) &&
1569  r->key.as_u64[0] == k->as_u64[0] &&
1570  r->key.as_u64[1] == k->as_u64[1] &&
1571  r->key.as_u64[2] == k->as_u64[2] &&
1572  r->key.as_u64[3] == k->as_u64[3] &&
1573  r->key.as_u64[4] == k->as_u64[4])
1574  return r;
1575  ri = r->bucket_next;
1576  }
1577  return NULL;
1578 }
1579 
1580 #define map_ip6_reass_pool_index(r) (r - map_main.ip6_reass_pool)
1581 
1582 void
1584 {
1585  map_main_t *mm = &map_main;
1586  int i;
1587  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1588  if (r->fragments[i].pi != ~0)
1589  {
1590  vec_add1 (*pi_to_drop, r->fragments[i].pi);
1591  r->fragments[i].pi = ~0;
1593  }
1594 
1595  // Unlink in hash bucket
1596  map_ip6_reass_t *r2 = NULL;
1597  u32 r2i = mm->ip6_reass_hash_table[r->bucket];
1598  while (r2i != map_ip6_reass_pool_index (r))
1599  {
1600  ASSERT (r2i != MAP_REASS_INDEX_NONE);
1601  r2 = pool_elt_at_index (mm->ip6_reass_pool, r2i);
1602  r2i = r2->bucket_next;
1603  }
1604  if (r2)
1605  {
1606  r2->bucket_next = r->bucket_next;
1607  }
1608  else
1609  {
1611  }
1612 
1613  // Unlink in list
1614  if (r->fifo_next == map_ip6_reass_pool_index (r))
1615  {
1616  //Single element in the list, list is now empty
1618  }
1619  else
1620  {
1621  if (mm->ip6_reass_fifo_last == map_ip6_reass_pool_index (r)) //First element
1622  mm->ip6_reass_fifo_last = r->fifo_prev;
1623  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next =
1624  r->fifo_next;
1625  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev =
1626  r->fifo_prev;
1627  }
1628 
1629  // Free from pool if necessary
1630  pool_put (mm->ip6_reass_pool, r);
1631  mm->ip6_reass_allocated--;
1632 }
1633 
1636  u8 protocol, u32 ** pi_to_drop)
1637 {
1638  map_ip6_reass_t *r;
1639  map_main_t *mm = &map_main;
1640  map_ip6_reass_key_t k = {
1641  .src = *src,
1642  .dst = *dst,
1643  .fragment_id = fragment_id,
1644  .protocol = protocol
1645  };
1646 
1647  u32 h = 0;
1648  int i;
1649 
1650 #ifdef clib_crc32c_uses_intrinsics
1651  h = clib_crc32c ((u8 *) k.as_u32, 40);
1652 #else
1653  u64 tmp =
1654  k.as_u64[0] ^ k.as_u64[1] ^ k.as_u64[2] ^ k.as_u64[3] ^ k.as_u64[4];
1655  h = clib_xxhash (tmp);
1656 #endif
1657 
1658  h = h >> (32 - mm->ip6_reass_ht_log2len);
1659 
1660  f64 now = vlib_time_now (mm->vlib_main);
1661 
1662  //Cache garbage collection
1664  {
1667  if (last->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) < now)
1668  map_ip6_reass_free (last, pi_to_drop);
1669  else
1670  break;
1671  }
1672 
1673  if ((r = map_ip6_reass_lookup (&k, h, now)))
1674  return r;
1675 
1677  return NULL;
1678 
1679  pool_get (mm->ip6_reass_pool, r);
1680  mm->ip6_reass_allocated++;
1681  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1682  {
1683  r->fragments[i].pi = ~0;
1684  r->fragments[i].next_data_len = 0;
1685  r->fragments[i].next_data_offset = 0;
1686  }
1687 
1688  u32 ri = map_ip6_reass_pool_index (r);
1689 
1690  //Link in new bucket
1691  r->bucket = h;
1692  r->bucket_next = mm->ip6_reass_hash_table[h];
1693  mm->ip6_reass_hash_table[h] = ri;
1694 
1695  //Link in fifo
1697  {
1698  r->fifo_next =
1700  mm->ip6_reass_fifo_last)->fifo_next;
1701  r->fifo_prev = mm->ip6_reass_fifo_last;
1702  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next = ri;
1703  pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev = ri;
1704  }
1705  else
1706  {
1707  r->fifo_next = r->fifo_prev = ri;
1708  mm->ip6_reass_fifo_last = ri;
1709  }
1710 
1711  //Set other fields
1712  r->ts = now;
1713  r->key = k;
1715 #ifdef MAP_IP6_REASS_COUNT_BYTES
1716  r->expected_total = 0xffff;
1717  r->forwarded = 0;
1718 #endif
1719  return r;
1720 }
1721 
1722 int
1724  u16 data_offset, u16 next_data_offset,
1725  u8 * data_start, u16 data_len)
1726 {
1727  map_ip6_fragment_t *f = NULL, *prev_f = NULL;
1728  u16 copied_len = (data_len > 20) ? 20 : data_len;
1729 
1731  return -1;
1732 
1733  //Lookup for fragments for the current buffer
1734  //and the one before that
1735  int i;
1736  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1737  {
1738  if (data_offset && r->fragments[i].next_data_offset == data_offset)
1739  {
1740  prev_f = &r->fragments[i]; // This is buffer for previous packet
1741  }
1742  else if (r->fragments[i].next_data_offset == next_data_offset)
1743  {
1744  f = &r->fragments[i]; // This is a buffer for the current packet
1745  }
1746  else if (r->fragments[i].next_data_offset == 0)
1747  { //Available
1748  if (f == NULL)
1749  f = &r->fragments[i];
1750  else if (prev_f == NULL)
1751  prev_f = &r->fragments[i];
1752  }
1753  }
1754 
1755  if (!f || f->pi != ~0)
1756  return -1;
1757 
1758  if (data_offset)
1759  {
1760  if (!prev_f)
1761  return -1;
1762 
1763  clib_memcpy (prev_f->next_data, data_start, copied_len);
1764  prev_f->next_data_len = copied_len;
1765  prev_f->next_data_offset = data_offset;
1766  }
1767  else
1768  {
1769  if (((ip4_header_t *) data_start)->ip_version_and_header_length != 0x45)
1770  return -1;
1771 
1773  clib_memcpy (&r->ip4_header, data_start, sizeof (ip4_header_t));
1774  }
1775 
1776  if (data_len > 20)
1777  {
1778  f->next_data_offset = next_data_offset;
1779  f->pi = pi;
1781  }
1782  return 0;
1783 }
1784 
1785 void
1786 map_ip4_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1787 {
1788  map_main_t *mm = &map_main;
1789  int i;
1790 
1791  if (dropped_packets)
1792  *dropped_packets = mm->ip4_reass_buffered_counter;
1793  if (trashed_reass)
1794  *trashed_reass = mm->ip4_reass_allocated;
1796  {
1797  u16 ri = mm->ip4_reass_fifo_last;
1798  do
1799  {
1801  for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1802  if (r->fragments[i] != ~0)
1803  map_ip4_drop_pi (r->fragments[i]);
1804 
1805  ri = r->fifo_next;
1806  pool_put (mm->ip4_reass_pool, r);
1807  }
1808  while (ri != mm->ip4_reass_fifo_last);
1809  }
1810 
1813  for (i = 0; i < (1 << mm->ip4_reass_ht_log2len); i++)
1815  pool_free (mm->ip4_reass_pool);
1817 
1818  mm->ip4_reass_allocated = 0;
1821 }
1822 
1823 u8
1824 map_get_ht_log2len (f32 ht_ratio, u16 pool_size)
1825 {
1826  u32 desired_size = (u32) (pool_size * ht_ratio);
1827  u8 i;
1828  for (i = 1; i < 31; i++)
1829  if ((1 << i) >= desired_size)
1830  return i;
1831  return 4;
1832 }
1833 
1834 int
1835 map_ip4_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1836  u32 * dropped_packets)
1837 {
1838  map_main_t *mm = &map_main;
1839  if (ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1840  return -1;
1841 
1842  map_ip4_reass_lock ();
1843  mm->ip4_reass_conf_ht_ratio = ht_ratio;
1844  mm->ip4_reass_ht_log2len =
1846  map_ip4_reass_reinit (trashed_reass, dropped_packets);
1848  return 0;
1849 }
1850 
1851 int
1852 map_ip4_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1853  u32 * dropped_packets)
1854 {
1855  map_main_t *mm = &map_main;
1856  if (pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1857  return -1;
1858 
1859  map_ip4_reass_lock ();
1860  mm->ip4_reass_conf_pool_size = pool_size;
1861  map_ip4_reass_reinit (trashed_reass, dropped_packets);
1863  return 0;
1864 }
1865 
1866 int
1868 {
1869  map_main.ip4_reass_conf_lifetime_ms = lifetime_ms;
1870  return 0;
1871 }
1872 
1873 int
1875 {
1876  map_main.ip4_reass_conf_buffers = buffers;
1877  return 0;
1878 }
1879 
1880 void
1881 map_ip6_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1882 {
1883  map_main_t *mm = &map_main;
1884  if (dropped_packets)
1885  *dropped_packets = mm->ip6_reass_buffered_counter;
1886  if (trashed_reass)
1887  *trashed_reass = mm->ip6_reass_allocated;
1888  int i;
1890  {
1891  u16 ri = mm->ip6_reass_fifo_last;
1892  do
1893  {
1895  for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1896  if (r->fragments[i].pi != ~0)
1897  map_ip6_drop_pi (r->fragments[i].pi);
1898 
1899  ri = r->fifo_next;
1900  pool_put (mm->ip6_reass_pool, r);
1901  }
1902  while (ri != mm->ip6_reass_fifo_last);
1904  }
1905 
1908  for (i = 0; i < (1 << mm->ip6_reass_ht_log2len); i++)
1910  pool_free (mm->ip6_reass_pool);
1912 
1913  mm->ip6_reass_allocated = 0;
1915 }
1916 
1917 int
1918 map_ip6_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1919  u32 * dropped_packets)
1920 {
1921  map_main_t *mm = &map_main;
1922  if (ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1923  return -1;
1924 
1925  map_ip6_reass_lock ();
1926  mm->ip6_reass_conf_ht_ratio = ht_ratio;
1927  mm->ip6_reass_ht_log2len =
1929  map_ip6_reass_reinit (trashed_reass, dropped_packets);
1931  return 0;
1932 }
1933 
1934 int
1935 map_ip6_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1936  u32 * dropped_packets)
1937 {
1938  map_main_t *mm = &map_main;
1939  if (pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1940  return -1;
1941 
1942  map_ip6_reass_lock ();
1943  mm->ip6_reass_conf_pool_size = pool_size;
1944  map_ip6_reass_reinit (trashed_reass, dropped_packets);
1946  return 0;
1947 }
1948 
1949 int
1951 {
1952  map_main.ip6_reass_conf_lifetime_ms = lifetime_ms;
1953  return 0;
1954 }
1955 
1956 int
1958 {
1959  map_main.ip6_reass_conf_buffers = buffers;
1960  return 0;
1961 }
1962 
1963 /* *INDENT-OFF* */
1964 
1965 /*?
1966  * Configure MAP reassembly behaviour
1967  *
1968  * @cliexpar
1969  * @cliexstart{map params reassembly}
1970  * @cliexend
1971  ?*/
1972 VLIB_CLI_COMMAND(map_ip4_reass_lifetime_command, static) = {
1973  .path = "map params reassembly",
1974  .short_help = "map params reassembly [ip4 | ip6] [lifetime <lifetime-ms>] "
1975  "[pool-size <pool-size>] [buffers <buffers>] "
1976  "[ht-ratio <ht-ratio>]",
1977  .function = map_params_reass_command_fn,
1978 };
1979 
1980 /*?
1981  * Set or copy the IP TOS/Traffic Class field
1982  *
1983  * @cliexpar
1984  * @cliexstart{map params traffic-class}
1985  *
1986  * This command is used to set the traffic-class field in translated
1987  * or encapsulated packets. If copy is specifed (the default) then the
1988  * traffic-class/TOS field is copied from the original packet to the
1989  * translated / encapsulating header.
1990  * @cliexend
1991  ?*/
1992 VLIB_CLI_COMMAND(map_traffic_class_command, static) = {
1993  .path = "map params traffic-class",
1994  .short_help = "map params traffic-class {0x0-0xff | copy}",
1995  .function = map_traffic_class_command_fn,
1996 };
1997 
1998 /*?
1999  * Bypass IP4/IP6 lookup
2000  *
2001  * @cliexpar
2002  * @cliexstart{map params pre-resolve}
2003  *
2004  * Bypass a second FIB lookup of the translated or encapsulated
2005  * packet, and forward the packet directly to the specified
2006  * next-hop. This optimization trades forwarding flexibility for
2007  * performance.
2008  * @cliexend
2009  ?*/
2010 VLIB_CLI_COMMAND(map_pre_resolve_command, static) = {
2011  .path = "map params pre-resolve",
2012  .short_help = " map params pre-resolve {ip4-nh <address>} "
2013  "| {ip6-nh <address>}",
2014  .function = map_pre_resolve_command_fn,
2015 };
2016 
2017 /*?
2018  * Enable or disable the MAP-E inbound security check
2019  *
2020  * @cliexpar
2021  * @cliexstart{map params security-check}
2022  *
2023  * By default, a decapsulated packet's IPv4 source address will be
2024  * verified against the outer header's IPv6 source address. Disabling
2025  * this feature will allow IPv4 source address spoofing.
2026  * @cliexend
2027  ?*/
2028 VLIB_CLI_COMMAND(map_security_check_command, static) = {
2029  .path = "map params security-check",
2030  .short_help = "map params security-check on|off",
2031  .function = map_security_check_command_fn,
2032 };
2033 
2034 /*?
2035  * Specifiy the IPv4 source address used for relayed ICMP error messages
2036  *
2037  * @cliexpar
2038  * @cliexstart{map params icmp source-address}
2039  *
2040  * This command specifies which IPv4 source address (must be local to
2041  * the system), that is used for relayed received IPv6 ICMP error
2042  * messages.
2043  * @cliexend
2044  ?*/
2045 VLIB_CLI_COMMAND(map_icmp_relay_source_address_command, static) = {
2046  .path = "map params icmp source-address",
2047  .short_help = "map params icmp source-address <ip4-address>",
2049 };
2050 
2051 /*?
2052  * Send IPv6 ICMP unreachables
2053  *
2054  * @cliexpar
2055  * @cliexstart{map params icmp6 unreachables}
2056  *
2057  * Send IPv6 ICMP unreachable messages back if security check fails or
2058  * no MAP domain exists.
2059  * @cliexend
2060  ?*/
2061 VLIB_CLI_COMMAND(map_icmp_unreachables_command, static) = {
2062  .path = "map params icmp6 unreachables",
2063  .short_help = "map params icmp6 unreachables {on|off}",
2065 };
2066 
2067 /*?
2068  * Configure MAP fragmentation behaviour
2069  *
2070  * @cliexpar
2071  * @cliexstart{map params fragment}
2072  * @cliexend
2073  ?*/
2074 VLIB_CLI_COMMAND(map_fragment_command, static) = {
2075  .path = "map params fragment",
2076  .short_help = "map params fragment inner|outer",
2077  .function = map_fragment_command_fn,
2078 };
2079 
2080 /*?
2081  * Ignore the IPv4 Don't fragment bit
2082  *
2083  * @cliexpar
2084  * @cliexstart{map params fragment ignore-df}
2085  *
2086  * Allows fragmentation of the IPv4 packet even if the DF bit is
2087  * set. The choice between inner or outer fragmentation of tunnel
2088  * packets is complicated. The benefit of inner fragmentation is that
2089  * the ultimate endpoint must reassemble, instead of the tunnel
2090  * endpoint.
2091  * @cliexend
2092  ?*/
2093 VLIB_CLI_COMMAND(map_fragment_df_command, static) = {
2094  .path = "map params fragment ignore-df",
2095  .short_help = "map params fragment ignore-df on|off",
2096  .function = map_fragment_df_command_fn,
2097 };
2098 
2099 /*?
2100  * Specifiy if the inbound security check should be done on fragments
2101  *
2102  * @cliexpar
2103  * @cliexstart{map params security-check fragments}
2104  *
2105  * Typically the inbound on-decapsulation security check is only done
2106  * on the first packet. The packet that contains the L4
2107  * information. While a security check on every fragment is possible,
2108  * it has a cost. State must be created on the first fragment.
2109  * @cliexend
2110  ?*/
2111 VLIB_CLI_COMMAND(map_security_check_frag_command, static) = {
2112  .path = "map params security-check fragments",
2113  .short_help = "map params security-check fragments on|off",
2115 };
2116 
2117 /*?
2118  * Add MAP domain
2119  *
2120  * @cliexpar
2121  * @cliexstart{map add domain}
2122  * @cliexend
2123  ?*/
2124 VLIB_CLI_COMMAND(map_add_domain_command, static) = {
2125  .path = "map add domain",
2126  .short_help = "map add domain ip4-pfx <ip4-pfx> ip6-pfx <ip6-pfx> "
2127  "ip6-src <ip6-pfx> ea-bits-len <n> psid-offset <n> psid-len <n> "
2128  "[map-t] [mtu <mtu>]",
2129  .function = map_add_domain_command_fn,
2130 };
2131 
2132 /*?
2133  * Add MAP rule to a domain
2134  *
2135  * @cliexpar
2136  * @cliexstart{map add rule}
2137  * @cliexend
2138  ?*/
2139 VLIB_CLI_COMMAND(map_add_rule_command, static) = {
2140  .path = "map add rule",
2141  .short_help = "map add rule index <domain> psid <psid> ip6-dst <ip6-addr>",
2142  .function = map_add_rule_command_fn,
2143 };
2144 
2145 /*?
2146  * Delete MAP domain
2147  *
2148  * @cliexpar
2149  * @cliexstart{map del domain}
2150  * @cliexend
2151  ?*/
2152 VLIB_CLI_COMMAND(map_del_command, static) = {
2153  .path = "map del domain",
2154  .short_help = "map del domain index <domain>",
2155  .function = map_del_domain_command_fn,
2156 };
2157 
2158 /*?
2159  * Show MAP domains
2160  *
2161  * @cliexpar
2162  * @cliexstart{show map domain}
2163  * @cliexend
2164  ?*/
2165 VLIB_CLI_COMMAND(show_map_domain_command, static) = {
2166  .path = "show map domain",
2167  .short_help = "show map domain index <n> [counters]",
2168  .function = show_map_domain_command_fn,
2169 };
2170 
2171 /*?
2172  * Show MAP statistics
2173  *
2174  * @cliexpar
2175  * @cliexstart{show map stats}
2176  * @cliexend
2177  ?*/
2178 VLIB_CLI_COMMAND(show_map_stats_command, static) = {
2179  .path = "show map stats",
2180  .short_help = "show map stats",
2181  .function = show_map_stats_command_fn,
2182 };
2183 
2184 /*?
2185  * Show MAP fragmentation information
2186  *
2187  * @cliexpar
2188  * @cliexstart{show map fragments}
2189  * @cliexend
2190  ?*/
2191 VLIB_CLI_COMMAND(show_map_fragments_command, static) = {
2192  .path = "show map fragments",
2193  .short_help = "show map fragments",
2194  .function = show_map_fragments_command_fn,
2195 };
2196 /* *INDENT-ON* */
2197 
2198 /*
2199  * map_init
2200  */
2201 clib_error_t *
2203 {
2204  map_main_t *mm = &map_main;
2205  mm->vnet_main = vnet_get_main ();
2206  mm->vlib_main = vm;
2207 
2208 #ifdef MAP_SKIP_IP6_LOOKUP
2209  fib_protocol_t proto;
2210 
2211  FOR_EACH_FIB_PROTOCOL (proto)
2212  {
2213  map_pre_resolve_init (&pre_resolved[proto]);
2214  }
2215 #endif
2216 
2217  /* traffic class */
2218  mm->tc = 0;
2219  mm->tc_copy = true;
2220 
2221  /* Inbound security check */
2222  mm->sec_check = true;
2223  mm->sec_check_frag = false;
2224 
2225  /* ICMP6 Type 1, Code 5 for security check failure */
2226  mm->icmp6_enabled = false;
2227 
2228  /* Inner or outer fragmentation */
2229  mm->frag_inner = false;
2230  mm->frag_ignore_df = false;
2231 
2235 
2238 
2239  /* IP4 virtual reassembly */
2240  mm->ip4_reass_hash_table = 0;
2241  mm->ip4_reass_pool = 0;
2242  mm->ip4_reass_lock =
2248  mm->ip4_reass_ht_log2len =
2253 
2254  /* IP6 virtual reassembly */
2255  mm->ip6_reass_hash_table = 0;
2256  mm->ip6_reass_pool = 0;
2257  mm->ip6_reass_lock =
2263  mm->ip6_reass_ht_log2len =
2268 
2269 #ifdef MAP_SKIP_IP6_LOOKUP
2271 #endif
2273 
2274  return 0;
2275 }
2276 
2278 
2279 /*
2280  * fd.io coding-style-patch-verification: ON
2281  *
2282  * Local Variables:
2283  * eval: (c-set-style "gnu")
2284  * End:
2285  */
u16 forwarded
Definition: map.h:182
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:169
#define map_ip4_reass_lock()
Definition: map.h:458
u8 psid_length
Definition: map.h:93
map_ip4_reass_t * ip4_reass_pool
Definition: map.h:261
Recursive resolution source.
Definition: fib_entry.h:109
u32 ip4_reass_conf_buffers
Definition: map.h:258
u32 error_heap_index
Definition: node.h:279
fib_node_t node
Linkage into the FIB graph.
Definition: map.h:201
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
static clib_error_t * map_fragment_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:822
#define CLIB_UNUSED(x)
Definition: clib.h:79
#define MAP_IP6_REASS_CONF_BUFFERS_MAX
Definition: map.h:510
u32 as_u32[4]
Definition: map.h:121
int map_delete_domain(u32 map_domain_index)
Definition: map.c:218
#define MAP_IP6_REASS_BUFFERS_DEFAULT
Definition: map.h:66
map_domain_flags_e flags
Definition: map.h:88
u16 fifo_prev
Definition: map.h:186
void vlib_validate_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
validate a combined counter
Definition: counter.c:89
static fib_node_t * map_fib_node_get(fib_node_index_t index)
Function definition to get a FIB node from its index.
Definition: map.c:390
u16 ip4_reass_allocated
Definition: map.h:263
volatile u32 * ip6_reass_lock
Definition: map.h:289
u8 ip4_reass_ht_log2len
Definition: map.h:262
u32 fragments[MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY]
Definition: map.h:138
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define MAP_IP6_REASS_LIFETIME_DEFAULT
Definition: map.h:63
static_always_inline map_ip6_reass_t * map_ip6_reass_lookup(map_ip6_reass_key_t *k, u32 bucket, f64 now)
Definition: map.c:1561
static u8 * format_map_pre_resolve(u8 *s, va_list ap)
Definition: map.c:320
#define pool_alloc(P, N)
Allocate N more free elements to pool (unspecified alignment).
Definition: pool.h:274
u16 bucket_next
Definition: map.h:185
void fib_node_init(fib_node_t *node, fib_node_type_t type)
Definition: fib_node.c:183
u32 fib_entry_child_add(fib_node_index_t fib_entry_index, fib_node_type_t child_type, fib_node_index_t child_index)
Definition: fib_entry.c:489
u64 as_u64[2]
Definition: ip6_packet.h:51
void fib_entry_get_prefix(fib_node_index_t fib_entry_index, fib_prefix_t *pfx)
Definition: fib_entry.c:1532
map_error_t
Definition: map.h:318
dpo_id_t dpo
The Load-balance object index to use to forward.
Definition: map.h:216
#define NULL
Definition: clib.h:55
static u8 * format_map_domain(u8 *s, va_list *args)
Definition: map.c:923
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:192
static clib_error_t * show_map_domain_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:1011
void map_ip4_reass_reinit(u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1786
static clib_error_t * map_security_check_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:473
u64 map_error_counter_get(u32 node_index, map_error_t map_error)
Definition: map.c:1085
enum fib_node_back_walk_rc_t_ fib_node_back_walk_rc_t
Return code from a back walk function.
const dpo_id_t * fib_entry_contribute_ip_forwarding(fib_node_index_t fib_entry_index)
Definition: fib_entry.c:445
static clib_error_t * map_fragment_df_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:854
vlib_main_t * vlib_main
Definition: map.h:248
u8 tc
Definition: map.h:236
static void map_fib_resolve(map_main_pre_resolved_t *pr, fib_protocol_t proto, u8 len, const ip46_address_t *addr)
Definition: map.c:406
static clib_error_t * show_map_fragments_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:1068
void fib_entry_child_remove(fib_node_index_t fib_entry_index, u32 sibling_index)
Definition: fib_entry.c:500
A pre-resolved next-hop.
Definition: map.h:196
void dpo_copy(dpo_id_t *dst, const dpo_id_t *src)
atomic copy a data-plane object.
Definition: dpo.c:235
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
static void map_domain_counter_unlock(map_main_t *mm)
Definition: map.h:541
Combined counter to hold both packets and byte differences.
Definition: counter.h:139
static u64 clib_xxhash(u64 key)
Definition: xxhash.h:58
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
format_function_t format_ip46_address
Definition: format.h:61
u32 suffix_mask
Definition: map.h:84
bool sec_check_frag
Definition: map.h:240
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:62
u32 ip4_reass_buffered_counter
Definition: map.h:269
static u8 * format_map_ip4_reass(u8 *s, va_list *args)
Definition: map.c:976
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:419
u16 ip4_reass_fifo_last
Definition: map.h:265
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
int map_ip6_reass_conf_ht_ratio(f32 ht_ratio, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1918
#define MAP_IP6_REASS_CONF_LIFETIME_MAX
Definition: map.h:508
u64 as_u64[5]
Definition: map.h:165
enum fib_protocol_t_ fib_protocol_t
Protocol Type.
map_ip6_reass_t * ip6_reass_pool
Definition: map.h:284
map_ip6_fragment_t fragments[MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY]
Definition: map.h:189
u16 port
Definition: map.h:329
void fib_node_register_type(fib_node_type_t type, const fib_node_vft_t *vft)
fib_node_register_type
Definition: fib_node.c:58
#define map_ip6_reass_unlock()
Definition: map.h:482
static void map_pre_resolve(ip4_address_t *ip4, ip6_address_t *ip6, int is_del)
Definition: map.c:443
float f32
Definition: types.h:143
IPv[46] Mapping.
Definition: fib_entry.h:74
void map_dpo_create(dpo_proto_t dproto, u32 domain_index, dpo_id_t *dpo)
A representation of a MAP DPO.
Definition: map_dpo.c:26
static counter_t vlib_get_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Get the value of a simple counter Scrapes the entire set of per-thread counters.
Definition: counter.h:97
format_function_t format_ip4_address
Definition: format.h:79
#define MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY
Definition: map.h:61
bool tc_copy
Definition: map.h:237
#define static_always_inline
Definition: clib.h:85
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:376
unformat_function_t unformat_ip4_address
Definition: format.h:76
static clib_error_t * map_pre_resolve_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:704
#define MAP_REASS_INDEX_NONE
Definition: map.h:107
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
map_ip4_reass_key_t key
Definition: map.h:127
static clib_error_t * map_icmp_unreachables_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:783
void fib_table_entry_special_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Remove a &#39;special&#39; entry from the FIB.
Definition: fib_table.c:390
u16 bucket
Definition: map.h:184
vlib_combined_counter_main_t * domain_counters
Definition: map.h:232
ip4_address_t icmp4_src_address
Definition: map.h:244
static clib_error_t * map_add_domain_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:539
Aggregrate type for a prefix.
Definition: fib_types.h:160
u16 fifo_next
Definition: map.h:137
#define clib_error_return(e, args...)
Definition: error.h:99
vlib_simple_counter_main_t icmp_relayed
Definition: map.h:245
int map_ip4_reass_add_fragment(map_ip4_reass_t *r, u32 pi)
Definition: map.c:1544
ip6_address_t * rules
Definition: map.h:83
unsigned long u64
Definition: types.h:89
u8 map_get_ht_log2len(f32 ht_ratio, u16 pool_size)
Definition: map.c:1824
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:241
u8 ea_bits_len
Definition: map.h:91
u8 ip6_prefix_len
Definition: map.h:89
#define MAP_IP4_REASS_CONF_LIFETIME_MAX
Definition: map.h:496
static_always_inline map_ip4_reass_t * map_ip4_reass_lookup(map_ip4_reass_key_t *k, u32 bucket, f64 now)
Definition: map.c:1399
u16 ip6_reass_allocated
Definition: map.h:286
int map_add_del_psid(u32 map_domain_index, u16 psid, ip6_address_t *tep, u8 is_add)
Definition: map.c:262
Definition: fib_entry.h:233
unformat_function_t unformat_line_input
Definition: format.h:281
#define MAP_IP6_REASS_CONF_POOL_SIZE_MAX
Definition: map.h:506
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:152
Definition: fib_entry.h:237
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:397
static void vlib_zero_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
Clear a combined counter Clears the set of per-thread counters.
Definition: counter.h:276
int map_ip6_reass_conf_buffers(u32 buffers)
Definition: map.c:1957
#define map_ip4_reass_pool_index(r)
Definition: map.c:1417
counter_t packets
packet counter
Definition: counter.h:141
static clib_error_t * map_add_rule_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:654
int map_ip4_reass_conf_lifetime(u16 lifetime_ms)
Definition: map.c:1867
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:183
vlib_error_main_t error_main
Definition: main.h:124
static map_main_pre_resolved_t * map_from_fib_node(fib_node_t *node)
Definition: map.c:355
#define MAP_IP4_REASS_BUFFERS_DEFAULT
Definition: map.h:59
#define MAP_IP4_REASS_CONF_HT_RATIO_MAX
Definition: map.h:492
static u8 * format_map_ip6_reass(u8 *s, va_list *args)
Definition: map.c:994
bool frag_ignore_df
Definition: map.h:272
volatile u32 * ip4_reass_lock
Definition: map.h:266
#define v
Definition: acl.c:320
u32 vlib_combined_counter_n_counters(const vlib_combined_counter_main_t *cm)
The number of counters (not the number of per-thread counters)
Definition: counter.c:100
struct _unformat_input_t unformat_input_t
u16 ip4_reass_conf_pool_size
Definition: map.h:256
map_domain_t * domains
Definition: map.h:228
u16 bucket
Definition: map.h:134
int map_ip4_reass_conf_buffers(u32 buffers)
Definition: map.c:1874
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:241
void map_t_dpo_create(dpo_proto_t dproto, u32 domain_index, dpo_id_t *dpo)
Definition: map_dpo.c:37
#define FOR_EACH_FIB_PROTOCOL(_item)
Definition: fib_types.h:57
void map_dpo_module_init(void)
Definition: map_dpo.c:126
int map_ip6_reass_conf_lifetime(u16 lifetime_ms)
Definition: map.c:1950
map_ip4_reass_t * map_ip4_reass_get(u32 src, u32 dst, u16 fragment_id, u8 protocol, u32 **pi_to_drop)
Definition: map.c:1463
int map_ip4_reass_conf_pool_size(u16 pool_size, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1852
u16 * ip6_reass_hash_table
Definition: map.h:287
u16 * ip4_reass_hash_table
Definition: map.h:264
u32 vlib_error_t
Definition: error.h:44
map_main_t map_main
Definition: map.h:332
fib_node_type_t fn_type
The node&#39;s type.
Definition: fib_node.h:284
An node in the FIB graph.
Definition: fib_node.h:279
#define MAP_IP4_REASS_HT_RATIO_DEFAULT
Definition: map.h:57
u8 ip6_src_len
Definition: map.h:90
u8 psid_shift
Definition: map.h:96
u16 expected_total
Definition: map.h:130
static u32 vlib_error_get_code(vlib_error_t e)
Definition: error.h:53
u8 suffix_shift
Definition: map.h:97
unformat_function_t unformat_ip6_address
Definition: format.h:94
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:169
void map_ip4_drop_pi(u32 pi)
Definition: ip6_map.c:664
u8 ip6_reass_ht_log2len
Definition: map.h:285
u16 ip6_reass_fifo_last
Definition: map.h:288
#define pool_free(p)
Free a pool.
Definition: pool.h:290
void map_ip4_reass_free(map_ip4_reass_t *r, u32 **pi_to_drop)
Definition: map.c:1420
fib_node_index_t fib_table_entry_special_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags)
Add a &#39;special&#39; entry to the FIB.
Definition: fib_table.c:371
u64 * counters
Definition: error.h:78
static clib_error_t * map_params_reass_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:1197
u16 ip6_reass_conf_pool_size
Definition: map.h:279
u8 next_data_len
Definition: map.h:173
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
ip4_address_t ip4_prefix
Definition: map.h:85
u16 next_data_offset
Definition: map.h:172
static_always_inline void map_ip4_reass_get_fragments(map_ip4_reass_t *r, u32 **pi)
Definition: map.h:462
format_function_t format_ip6_address
Definition: format.h:95
static void vlib_get_combined_counter(const vlib_combined_counter_main_t *cm, u32 index, vlib_counter_t *result)
Get the value of a combined counter, never called in the speed path Scrapes the entire set of per-thr...
Definition: counter.h:250
map_ip6_reass_t * map_ip6_reass_get(ip6_address_t *src, ip6_address_t *dst, u32 fragment_id, u8 protocol, u32 **pi_to_drop)
Definition: map.c:1635
#define MAP_IP6_REASS_POOL_SIZE_DEFAULT
Definition: map.h:65
u32 as_u32[10]
Definition: map.h:166
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
int map_create_domain(ip4_address_t *ip4_prefix, u8 ip4_prefix_len, ip6_address_t *ip6_prefix, u8 ip6_prefix_len, ip6_address_t *ip6_src, u8 ip6_src_len, u8 ea_bits_len, u8 psid_offset, u8 psid_length, u32 *map_domain_index, u16 mtu, u8 flags)
Definition: map.c:62
u8 psid_offset
Definition: map.h:92
static clib_error_t * map_icmp_relay_source_address_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:748
#define clib_warning(format, args...)
Definition: error.h:59
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:88
fib_node_get_t fnv_get
Definition: fib_node.h:267
u16 forwarded
Definition: map.h:131
#define clib_memcpy(a, b, c)
Definition: string.h:69
bool icmp6_enabled
Definition: map.h:241
u32 sibling
This object sibling index on the FIB entry&#39;s child dependency list.
Definition: map.h:211
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
map_ip6_reass_key_t key
Definition: map.h:178
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:238
static void map_pre_resolve_init(map_main_pre_resolved_t *pr)
Definition: map.c:313
ip6_address_t ip6_src
Definition: map.h:81
int map_ip4_reass_conf_ht_ratio(f32 ht_ratio, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1835
static clib_error_t * map_del_domain_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:615
static void map_domain_counter_lock(map_main_t *mm)
Definition: map.h:534
f32 ip4_reass_conf_ht_ratio
Definition: map.h:255
Context passed between object during a back walk.
Definition: fib_node.h:192
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Add a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the FI...
Definition: fib_table.c:290
void vlib_validate_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
validate a simple counter
Definition: counter.c:78
int map_ip6_reass_conf_pool_size(u16 pool_size, u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1935
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
bool sec_check
Definition: map.h:239
bool frag_inner
Definition: map.h:271
u16 psid_mask
Definition: map.h:86
void map_ip6_reass_reinit(u32 *trashed_reass, u32 *dropped_packets)
Definition: map.c:1881
static void clib_mem_free(void *p)
Definition: mem.h:176
ip4_header_t ip4_header
Definition: map.h:188
#define map_ip4_reass_unlock()
Definition: map.h:459
static void vlib_zero_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Clear a simple counter Clears the set of per-thread u16 counters, and the u64 counter.
Definition: counter.h:123
u8 * format_map_trace(u8 *s, va_list *args)
Definition: map.c:1383
#define MAP_IP6_REASS_HT_RATIO_DEFAULT
Definition: map.h:64
u8 ea_shift
Definition: map.h:98
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
ip6_address_t ip6_prefix
Definition: map.h:82
f32 ip6_reass_conf_ht_ratio
Definition: map.h:278
static clib_error_t * map_traffic_class_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:887
counter_t bytes
byte counter
Definition: counter.h:142
vnet_main_t * vnet_main
Definition: map.h:249
unsigned short u16
Definition: types.h:57
u16 mtu
Definition: map.h:87
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:168
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:29
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
u16 ip6_reass_conf_lifetime_ms
Definition: map.h:280
unsigned char u8
Definition: types.h:56
fib_node_index_t fei
The FIB entry index of the next-hop.
Definition: map.h:206
#define map_ip6_reass_lock()
Definition: map.h:481
i32 port
Definition: map.h:133
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
#define MAP_IP4_REASS_POOL_SIZE_DEFAULT
Definition: map.h:58
#define MAP_IP6_REASS_CONF_HT_RATIO_MAX
Definition: map.h:504
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:179
char * name
The counter collection&#39;s name.
Definition: counter.h:185
A collection of combined counters.
Definition: counter.h:180
#define MAP_IP4_REASS_LIFETIME_DEFAULT
IP4 reassembly logic: One virtually reassembled flow requires a map_ip4_reass_t structure in order to...
Definition: map.h:56
u16 bucket_next
Definition: map.h:135
#define FIB_PROTOCOL_MAX
Definition outside of enum so it does not need to be included in non-defaulted switch statements...
Definition: fib_types.h:50
#define MAP_IP4_REASS_CONF_POOL_SIZE_MAX
Definition: map.h:494
u8 ip4_prefix_len
Definition: map.h:101
A FIB graph nodes virtual function table.
Definition: fib_node.h:266
void map_ip6_reass_free(map_ip6_reass_t *r, u32 **pi_to_drop)
Definition: map.c:1583
vlib_simple_counter_main_t * simple_domain_counters
Definition: map.h:231
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:117
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static fib_node_back_walk_rc_t map_back_walk(fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
Function definition to backwalk a FIB node.
Definition: map.c:379
#define MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY
Definition: map.h:68
static void map_stack(map_main_pre_resolved_t *pr)
Definition: map.c:366
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:58
static void map_last_lock_gone(fib_node_t *node)
Function definition to inform the FIB node that its last lock has gone.
Definition: map.c:345
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:205
u16 ip4_reass_conf_lifetime_ms
Definition: map.h:257
#define vec_foreach(var, vec)
Vector iterator.
static clib_error_t * map_security_check_frag_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:506
u32 map_domain_index
Definition: map.h:328
#define MAP_IP4_REASS_CONF_BUFFERS_MAX
Definition: map.h:498
u64 as_u64[2]
Definition: map.h:120
vhost_vring_addr_t addr
Definition: vhost-user.h:82
u8 ip_version_and_header_length
Definition: ip4_packet.h:132
u16 fifo_prev
Definition: map.h:136
u32 flags
Definition: vhost-user.h:76
u32 ip6_reass_buffered_counter
Definition: map.h:292
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
int map_ip6_reass_add_fragment(map_ip6_reass_t *r, u32 pi, u16 data_offset, u16 next_data_offset, u8 *data_start, u16 data_len)
Definition: map.c:1723
u16 expected_total
Definition: map.h:181
clib_error_t * map_init(vlib_main_t *vm)
Definition: map.c:2202
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
static void map_fib_unresolve(map_main_pre_resolved_t *pr, fib_protocol_t proto, u8 len, const ip46_address_t *addr)
Definition: map.c:423
u16 fifo_next
Definition: map.h:187
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static clib_error_t * show_map_stats_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: map.c:1102
void map_ip6_drop_pi(u32 pi)
Definition: ip6_map.c:655
#define map_ip6_reass_pool_index(r)
Definition: map.c:1580
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
u32 ip6_reass_conf_buffers
Definition: map.h:281
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109