FD.io VPP  v18.01.2-1-g9b554f3
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 
27 
28 /*
29  * This code supports the following MAP modes:
30  *
31  * Algorithmic Shared IPv4 address (ea_bits_len > 0):
32  * ea_bits_len + ip4_prefix > 32
33  * psid_length > 0, ip6_prefix < 64, ip4_prefix <= 32
34  * Algorithmic Full IPv4 address (ea_bits_len > 0):
35  * ea_bits_len + ip4_prefix = 32
36  * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
37  * Algorithmic IPv4 prefix (ea_bits_len > 0):
38  * ea_bits_len + ip4_prefix < 32
39  * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
40  *
41  * Independent Shared IPv4 address (ea_bits_len = 0):
42  * ip4_prefix = 32
43  * psid_length > 0
44  * Rule IPv6 address = 128, Rule PSID Set
45  * Independent Full IPv4 address (ea_bits_len = 0):
46  * ip4_prefix = 32
47  * psid_length = 0, ip6_prefix = 128
48  * Independent IPv4 prefix (ea_bits_len = 0):
49  * ip4_prefix < 32
50  * psid_length = 0, ip6_prefix = 128
51  *
52  */
53 
54 /*
55  * This code supports MAP-T:
56  *
57  * With DMR prefix length equal to 96.
58  *
59  */
60 
61 
62 
63 int
65  u8 ip4_prefix_len,
66  ip6_address_t * ip6_prefix,
67  u8 ip6_prefix_len,
68  ip6_address_t * ip6_src,
69  u8 ip6_src_len,
70  u8 ea_bits_len,
71  u8 psid_offset,
72  u8 psid_length, u32 * map_domain_index, u16 mtu, u8 flags)
73 {
74  u8 suffix_len, suffix_shift;
75  map_main_t *mm = &map_main;
76  dpo_id_t dpo_v4 = DPO_INVALID;
77  dpo_id_t dpo_v6 = DPO_INVALID;
78  map_domain_t *d;
79 
80  /* Sanity check on the src prefix length */
81  if (flags & MAP_DOMAIN_TRANSLATION)
82  {
83  if (ip6_src_len != 96)
84  {
85  clib_warning ("MAP-T only supports ip6_src_len = 96 for now.");
86  return -1;
87  }
88  }
89  else
90  {
91  if (ip6_src_len != 128)
92  {
94  ("MAP-E requires a BR address, not a prefix (ip6_src_len should "
95  "be 128).");
96  return -1;
97  }
98  }
99 
100  /* How many, and which bits to grab from the IPv4 DA */
101  if (ip4_prefix_len + ea_bits_len < 32)
102  {
103  flags |= MAP_DOMAIN_PREFIX;
104  suffix_shift = 32 - ip4_prefix_len - ea_bits_len;
105  suffix_len = ea_bits_len;
106  }
107  else
108  {
109  suffix_shift = 0;
110  suffix_len = 32 - ip4_prefix_len;
111  }
112 
113  /* EA bits must be within the first 64 bits */
114  if (ea_bits_len > 0 && ((ip6_prefix_len + ea_bits_len) > 64 ||
115  ip6_prefix_len + suffix_len + psid_length > 64))
116  {
118  ("Embedded Address bits must be within the first 64 bits of "
119  "the IPv6 prefix");
120  return -1;
121  }
122 
123  /* Get domain index */
125  memset (d, 0, sizeof (*d));
126  *map_domain_index = d - mm->domains;
127 
128  /* Init domain struct */
129  d->ip4_prefix.as_u32 = ip4_prefix->as_u32;
130  d->ip4_prefix_len = ip4_prefix_len;
131  d->ip6_prefix = *ip6_prefix;
132  d->ip6_prefix_len = ip6_prefix_len;
133  d->ip6_src = *ip6_src;
134  d->ip6_src_len = ip6_src_len;
135  d->ea_bits_len = ea_bits_len;
136  d->psid_offset = psid_offset;
137  d->psid_length = psid_length;
138  d->mtu = mtu;
139  d->flags = flags;
140  d->suffix_shift = suffix_shift;
141  d->suffix_mask = (1 << suffix_len) - 1;
142 
143  d->psid_shift = 16 - psid_length - psid_offset;
144  d->psid_mask = (1 << d->psid_length) - 1;
145  d->ea_shift = 64 - ip6_prefix_len - suffix_len - d->psid_length;
146 
147  /* MAP data-plane object */
148  if (d->flags & MAP_DOMAIN_TRANSLATION)
149  map_t_dpo_create (DPO_PROTO_IP4, *map_domain_index, &dpo_v4);
150  else
151  map_dpo_create (DPO_PROTO_IP4, *map_domain_index, &dpo_v4);
152 
153  /* Create ip4 route */
154  fib_prefix_t pfx = {
156  .fp_len = d->ip4_prefix_len,
157  .fp_addr = {
158  .ip4 = d->ip4_prefix,
159  }
160  ,
161  };
164  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
165  dpo_reset (&dpo_v4);
166 
167  /*
168  * construct a DPO to use the v6 domain
169  */
170  if (d->flags & MAP_DOMAIN_TRANSLATION)
171  map_t_dpo_create (DPO_PROTO_IP6, *map_domain_index, &dpo_v6);
172  else
173  map_dpo_create (DPO_PROTO_IP6, *map_domain_index, &dpo_v6);
174 
175  /*
176  * Multiple MAP domains may share same source IPv6 TEP. Which is just dandy.
177  * We are not tracking the sharing. So a v4 lookup to find the correct
178  * domain post decap/trnaslate is always done
179  *
180  * Create ip6 route. This is a reference counted add. If the prefix
181  * already exists and is MAP sourced, it is now MAP source n+1 times
182  * and will need to be removed n+1 times.
183  */
184  fib_prefix_t pfx6 = {
186  .fp_len = d->ip6_src_len,
187  .fp_addr.ip6 = d->ip6_src,
188  };
189 
192  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v6);
193  dpo_reset (&dpo_v6);
194 
195  /* Validate packet/byte counters */
197  int i;
198  for (i = 0; i < vec_len (mm->simple_domain_counters); i++)
199  {
201  *map_domain_index);
203  *map_domain_index);
204  }
205  for (i = 0; i < vec_len (mm->domain_counters); i++)
206  {
208  *map_domain_index);
209  vlib_zero_combined_counter (&mm->domain_counters[i], *map_domain_index);
210  }
212 
213  return 0;
214 }
215 
216 /*
217  * map_delete_domain
218  */
219 int
220 map_delete_domain (u32 map_domain_index)
221 {
222  map_main_t *mm = &map_main;
223  map_domain_t *d;
224 
225  if (pool_is_free_index (mm->domains, map_domain_index))
226  {
227  clib_warning ("MAP domain delete: domain does not exist: %d",
228  map_domain_index);
229  return -1;
230  }
231 
232  d = pool_elt_at_index (mm->domains, map_domain_index);
233 
234  fib_prefix_t pfx = {
236  .fp_len = d->ip4_prefix_len,
237  .fp_addr = {
238  .ip4 = d->ip4_prefix,
239  }
240  ,
241  };
243 
244  fib_prefix_t pfx6 = {
246  .fp_len = d->ip6_src_len,
247  .fp_addr = {
248  .ip6 = d->ip6_src,
249  }
250  ,
251  };
253 
254  /* Deleting rules */
255  if (d->rules)
256  clib_mem_free (d->rules);
257 
258  pool_put (mm->domains, d);
259 
260  return 0;
261 }
262 
263 int
264 map_add_del_psid (u32 map_domain_index, u16 psid, ip6_address_t * tep,
265  u8 is_add)
266 {
267  map_domain_t *d;
268  map_main_t *mm = &map_main;
269 
270  if (pool_is_free_index (mm->domains, map_domain_index))
271  {
272  clib_warning ("MAP rule: domain does not exist: %d", map_domain_index);
273  return -1;
274  }
275  d = pool_elt_at_index (mm->domains, map_domain_index);
276 
277  /* Rules are only used in 1:1 independent case */
278  if (d->ea_bits_len > 0)
279  return (-1);
280 
281  if (!d->rules)
282  {
283  u32 l = (0x1 << d->psid_length) * sizeof (ip6_address_t);
285  if (!d->rules)
286  return -1;
287  memset (d->rules, 0, l);
288  }
289 
290  if (psid >= (0x1 << d->psid_length))
291  {
292  clib_warning ("MAP rule: PSID outside bounds: %d [%d]", psid,
293  0x1 << d->psid_length);
294  return -1;
295  }
296 
297  if (is_add)
298  {
299  d->rules[psid] = *tep;
300  }
301  else
302  {
303  memset (&d->rules[psid], 0, sizeof (ip6_address_t));
304  }
305  return 0;
306 }
307 
308 #ifdef MAP_SKIP_IP6_LOOKUP
309 /**
310  * Pre-resolvd per-protocol global next-hops
311  */
313 
314 static void
316 {
319 }
320 
321 static u8 *
322 format_map_pre_resolve (u8 * s, va_list * ap)
323 {
324  map_main_pre_resolved_t *pr = va_arg (*ap, map_main_pre_resolved_t *);
325 
326  if (FIB_NODE_INDEX_INVALID != pr->fei)
327  {
328  fib_prefix_t pfx;
329 
330  fib_entry_get_prefix (pr->fei, &pfx);
331 
332  return (format (s, "%U (%u)",
334  pr->dpo.dpoi_index));
335  }
336  else
337  {
338  return (format (s, "un-set"));
339  }
340 }
341 
342 
343 /**
344  * Function definition to inform the FIB node that its last lock has gone.
345  */
346 static void
348 {
349  /*
350  * The MAP is a root of the graph. As such
351  * it never has children and thus is never locked.
352  */
353  ASSERT (0);
354 }
355 
358 {
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 {
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
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 
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 
1313  if (map_main.ip4_reass_conf_buffers >
1314  map_main.ip4_reass_conf_pool_size *
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 
1366  if (map_main.ip6_reass_conf_buffers >
1367  map_main.ip6_reass_conf_pool_size *
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;
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 {
1546  if (map_main.ip4_reass_buffered_counter >= map_main.ip4_reass_conf_buffers)
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;
1554  map_main.ip4_reass_buffered_counter++;
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;
1592  map_main.ip6_reass_buffered_counter--;
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;
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 
1730  if (map_main.ip6_reass_buffered_counter >= map_main.ip6_reass_conf_buffers)
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;
1780  map_main.ip6_reass_buffered_counter++;
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 =
2244  *mm->ip4_reass_lock = 0;
2249  mm->ip4_reass_ht_log2len =
2254 
2255  /* IP6 virtual reassembly */
2256  mm->ip6_reass_hash_table = 0;
2257  mm->ip6_reass_pool = 0;
2258  mm->ip6_reass_lock =
2260  *mm->ip6_reass_lock = 0;
2265  mm->ip6_reass_ht_log2len =
2270 
2271 #ifdef MAP_SKIP_IP6_LOOKUP
2273 #endif
2275 
2276  return 0;
2277 }
2278 
2280 
2281 /*
2282  * fd.io coding-style-patch-verification: ON
2283  *
2284  * Local Variables:
2285  * eval: (c-set-style "gnu")
2286  * End:
2287  */
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:432
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:181
#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:117
u32 ip4_reass_conf_buffers
Definition: map.h:258
u32 error_heap_index
Definition: node.h:278
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:220
#define MAP_IP6_REASS_BUFFERS_DEFAULT
Definition: map.h:66
map_domain_flags_e flags
Definition: map.h:88
map_main_t map_main
Definition: map.c:26
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:47
#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
#define pool_alloc(P, N)
Allocate N more free elements to pool (unspecified alignment).
Definition: pool.h:324
u16 bucket_next
Definition: map.h:185
void fib_node_init(fib_node_t *node, fib_node_type_t type)
Definition: fib_node.c:185
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:503
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:1546
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:224
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:459
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:514
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:258
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:518
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:415
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:225
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:60
#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:82
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:93
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:438
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:172
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:237
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:264
Definition: fib_entry.h:238
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:166
Definition: fib_entry.h:242
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:459
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:195
vlib_error_main_t error_main
Definition: main.h:138
static map_main_pre_resolved_t * map_from_fib_node(fib_node_t *node)
Definition: map.c:357
#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:341
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:271
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:64
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
fib_node_type_t fn_type
The node&#39;s type.
Definition: fib_node.h:290
An node in the FIB graph.
Definition: fib_node.h:286
#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:188
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:352
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
vlib_main_t * vm
Definition: buffer.c:283
vec_header_t h
Definition: buffer.c:282
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:336
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:64
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:89
fib_node_get_t fnv_get
Definition: fib_node.h:274
u16 forwarded
Definition: map.h:131
#define clib_memcpy(a, b, c)
Definition: string.h:75
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:29
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:268
static void map_pre_resolve_init(map_main_pre_resolved_t *pr)
Definition: map.c:315
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:199
#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
long ctx[MAX_CONNS]
Definition: main.c:122
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:179
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 u8 * format_map_pre_resolve(u8 *s, va_list *ap)
Definition: map.c:322
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:182
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:30
#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:193
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:51
#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:273
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:120
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:59
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:347
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:228
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:83
u8 ip_version_and_header_length
Definition: ip4_packet.h:132
u16 fifo_prev
Definition: map.h:136
u32 flags
Definition: vhost-user.h:77
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:128