Add extern to *_main global variable declarations in header files.
[vpp.git] / src / vnet / map / map.c
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 map_main_t map_main;
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
64 map_create_domain (ip4_address_t * ip4_prefix,
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         {
93           clib_warning
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     {
117       clib_warning
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 */
124   pool_get_aligned (mm->domains, d, CLIB_CACHE_LINE_BYTES);
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 = {
155     .fp_proto = FIB_PROTOCOL_IP4,
156     .fp_len = d->ip4_prefix_len,
157     .fp_addr = {
158                 .ip4 = d->ip4_prefix,
159                 }
160     ,
161   };
162   fib_table_entry_special_dpo_add (0, &pfx,
163                                    FIB_SOURCE_MAP,
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 = {
185     .fp_proto = FIB_PROTOCOL_IP6,
186     .fp_len = d->ip6_src_len,
187     .fp_addr.ip6 = d->ip6_src,
188   };
189
190   fib_table_entry_special_dpo_add (0, &pfx6,
191                                    FIB_SOURCE_MAP,
192                                    FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v6);
193   dpo_reset (&dpo_v6);
194
195   /* Validate packet/byte counters */
196   map_domain_counter_lock (mm);
197   int i;
198   for (i = 0; i < vec_len (mm->simple_domain_counters); i++)
199     {
200       vlib_validate_simple_counter (&mm->simple_domain_counters[i],
201                                     *map_domain_index);
202       vlib_zero_simple_counter (&mm->simple_domain_counters[i],
203                                 *map_domain_index);
204     }
205   for (i = 0; i < vec_len (mm->domain_counters); i++)
206     {
207       vlib_validate_combined_counter (&mm->domain_counters[i],
208                                       *map_domain_index);
209       vlib_zero_combined_counter (&mm->domain_counters[i], *map_domain_index);
210     }
211   map_domain_counter_unlock (mm);
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 = {
235     .fp_proto = FIB_PROTOCOL_IP4,
236     .fp_len = d->ip4_prefix_len,
237     .fp_addr = {
238                 .ip4 = d->ip4_prefix,
239                 }
240     ,
241   };
242   fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_MAP);
243
244   fib_prefix_t pfx6 = {
245     .fp_proto = FIB_PROTOCOL_IP6,
246     .fp_len = d->ip6_src_len,
247     .fp_addr = {
248                 .ip6 = d->ip6_src,
249                 }
250     ,
251   };
252   fib_table_entry_special_remove (0, &pfx6, FIB_SOURCE_MAP);
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);
284       d->rules = clib_mem_alloc_aligned (l, CLIB_CACHE_LINE_BYTES);
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  */
312 map_main_pre_resolved_t pre_resolved[FIB_PROTOCOL_MAX];
313
314 static void
315 map_pre_resolve_init (map_main_pre_resolved_t * pr)
316 {
317   pr->fei = FIB_NODE_INDEX_INVALID;
318   fib_node_init (&pr->node, FIB_NODE_TYPE_MAP_E);
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)",
333                       format_ip46_address, &pfx.fp_addr, IP46_TYPE_ANY,
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
347 map_last_lock_gone (fib_node_t * node)
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
356 static map_main_pre_resolved_t *
357 map_from_fib_node (fib_node_t * node)
358 {
359 #if (CLIB_DEBUG > 0)
360   ASSERT (FIB_NODE_TYPE_MAP_E == node->fn_type);
361 #endif
362   return ((map_main_pre_resolved_t *)
363           (((char *) node) -
364            STRUCT_OFFSET_OF (map_main_pre_resolved_t, node)));
365 }
366
367 static void
368 map_stack (map_main_pre_resolved_t * pr)
369 {
370   const dpo_id_t *dpo;
371
372   dpo = fib_entry_contribute_ip_forwarding (pr->fei);
373
374   dpo_copy (&pr->dpo, dpo);
375 }
376
377 /**
378  * Function definition to backwalk a FIB node
379  */
380 static fib_node_back_walk_rc_t
381 map_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
382 {
383   map_stack (map_from_fib_node (node));
384
385   return (FIB_NODE_BACK_WALK_CONTINUE);
386 }
387
388 /**
389  * Function definition to get a FIB node from its index
390  */
391 static fib_node_t *
392 map_fib_node_get (fib_node_index_t index)
393 {
394   return (&pre_resolved[index].node);
395 }
396
397 /*
398  * Virtual function table registered by MPLS GRE tunnels
399  * for participation in the FIB object graph.
400  */
401 const static fib_node_vft_t map_vft = {
402   .fnv_get = map_fib_node_get,
403   .fnv_last_lock = map_last_lock_gone,
404   .fnv_back_walk = map_back_walk,
405 };
406
407 static void
408 map_fib_resolve (map_main_pre_resolved_t * pr,
409                  fib_protocol_t proto, u8 len, const ip46_address_t * addr)
410 {
411   fib_prefix_t pfx = {
412     .fp_proto = proto,
413     .fp_len = len,
414     .fp_addr = *addr,
415   };
416
417   pr->fei = fib_table_entry_special_add (0,     // default fib
418                                          &pfx,
419                                          FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE);
420   pr->sibling = fib_entry_child_add (pr->fei, FIB_NODE_TYPE_MAP_E, proto);
421   map_stack (pr);
422 }
423
424 static void
425 map_fib_unresolve (map_main_pre_resolved_t * pr,
426                    fib_protocol_t proto, u8 len, const ip46_address_t * addr)
427 {
428   fib_prefix_t pfx = {
429     .fp_proto = proto,
430     .fp_len = len,
431     .fp_addr = *addr,
432   };
433
434   fib_entry_child_remove (pr->fei, pr->sibling);
435
436   fib_table_entry_special_remove (0,    // default fib
437                                   &pfx, FIB_SOURCE_RR);
438   dpo_reset (&pr->dpo);
439
440   pr->fei = FIB_NODE_INDEX_INVALID;
441   pr->sibling = FIB_NODE_INDEX_INVALID;
442 }
443
444 static void
445 map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6, int is_del)
446 {
447   if (ip6 && (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0))
448     {
449       ip46_address_t addr = {
450         .ip6 = *ip6,
451       };
452       if (is_del)
453         map_fib_unresolve (&pre_resolved[FIB_PROTOCOL_IP6],
454                            FIB_PROTOCOL_IP6, 128, &addr);
455       else
456         map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP6],
457                          FIB_PROTOCOL_IP6, 128, &addr);
458     }
459   if (ip4 && (ip4->as_u32 != 0))
460     {
461       ip46_address_t addr = {
462         .ip4 = *ip4,
463       };
464       if (is_del)
465         map_fib_unresolve (&pre_resolved[FIB_PROTOCOL_IP4],
466                            FIB_PROTOCOL_IP4, 32, &addr);
467       else
468         map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP4],
469                          FIB_PROTOCOL_IP4, 32, &addr);
470     }
471 }
472 #endif
473
474 static clib_error_t *
475 map_security_check_command_fn (vlib_main_t * vm,
476                                unformat_input_t * input,
477                                vlib_cli_command_t * cmd)
478 {
479   unformat_input_t _line_input, *line_input = &_line_input;
480   map_main_t *mm = &map_main;
481   clib_error_t *error = NULL;
482
483   /* Get a line of input. */
484   if (!unformat_user (input, unformat_line_input, line_input))
485     return 0;
486
487   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
488     {
489       if (unformat (line_input, "off"))
490         mm->sec_check = false;
491       else if (unformat (line_input, "on"))
492         mm->sec_check = true;
493       else
494         {
495           error = clib_error_return (0, "unknown input `%U'",
496                                      format_unformat_error, line_input);
497           goto done;
498         }
499     }
500
501 done:
502   unformat_free (line_input);
503
504   return error;
505 }
506
507 static clib_error_t *
508 map_security_check_frag_command_fn (vlib_main_t * vm,
509                                     unformat_input_t * input,
510                                     vlib_cli_command_t * cmd)
511 {
512   unformat_input_t _line_input, *line_input = &_line_input;
513   map_main_t *mm = &map_main;
514   clib_error_t *error = NULL;
515
516   /* Get a line of input. */
517   if (!unformat_user (input, unformat_line_input, line_input))
518     return 0;
519
520   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
521     {
522       if (unformat (line_input, "off"))
523         mm->sec_check_frag = false;
524       else if (unformat (line_input, "on"))
525         mm->sec_check_frag = true;
526       else
527         {
528           error = clib_error_return (0, "unknown input `%U'",
529                                      format_unformat_error, line_input);
530           goto done;
531         }
532     }
533
534 done:
535   unformat_free (line_input);
536
537   return error;
538 }
539
540 static clib_error_t *
541 map_add_domain_command_fn (vlib_main_t * vm,
542                            unformat_input_t * input, vlib_cli_command_t * cmd)
543 {
544   unformat_input_t _line_input, *line_input = &_line_input;
545   ip4_address_t ip4_prefix;
546   ip6_address_t ip6_prefix;
547   ip6_address_t ip6_src;
548   u32 ip6_prefix_len = 0, ip4_prefix_len = 0, map_domain_index, ip6_src_len;
549   u32 num_m_args = 0;
550   /* Optional arguments */
551   u32 ea_bits_len = 0, psid_offset = 0, psid_length = 0;
552   u32 mtu = 0;
553   u8 flags = 0;
554   ip6_src_len = 128;
555   clib_error_t *error = NULL;
556
557   /* Get a line of input. */
558   if (!unformat_user (input, unformat_line_input, line_input))
559     return 0;
560
561   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
562     {
563       if (unformat
564           (line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix,
565            &ip4_prefix_len))
566         num_m_args++;
567       else
568         if (unformat
569             (line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix,
570              &ip6_prefix_len))
571         num_m_args++;
572       else
573         if (unformat
574             (line_input, "ip6-src %U/%d", unformat_ip6_address, &ip6_src,
575              &ip6_src_len))
576         num_m_args++;
577       else
578         if (unformat
579             (line_input, "ip6-src %U", unformat_ip6_address, &ip6_src))
580         num_m_args++;
581       else if (unformat (line_input, "ea-bits-len %d", &ea_bits_len))
582         num_m_args++;
583       else if (unformat (line_input, "psid-offset %d", &psid_offset))
584         num_m_args++;
585       else if (unformat (line_input, "psid-len %d", &psid_length))
586         num_m_args++;
587       else if (unformat (line_input, "mtu %d", &mtu))
588         num_m_args++;
589       else if (unformat (line_input, "map-t"))
590         flags |= MAP_DOMAIN_TRANSLATION;
591       else
592         {
593           error = clib_error_return (0, "unknown input `%U'",
594                                      format_unformat_error, line_input);
595           goto done;
596         }
597     }
598
599   if (num_m_args < 3)
600     {
601       error = clib_error_return (0, "mandatory argument(s) missing");
602       goto done;
603     }
604
605   map_create_domain (&ip4_prefix, ip4_prefix_len,
606                      &ip6_prefix, ip6_prefix_len, &ip6_src, ip6_src_len,
607                      ea_bits_len, psid_offset, psid_length, &map_domain_index,
608                      mtu, flags);
609
610 done:
611   unformat_free (line_input);
612
613   return error;
614 }
615
616 static clib_error_t *
617 map_del_domain_command_fn (vlib_main_t * vm,
618                            unformat_input_t * input, vlib_cli_command_t * cmd)
619 {
620   unformat_input_t _line_input, *line_input = &_line_input;
621   u32 num_m_args = 0;
622   u32 map_domain_index;
623   clib_error_t *error = NULL;
624
625   /* Get a line of input. */
626   if (!unformat_user (input, unformat_line_input, line_input))
627     return 0;
628
629   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
630     {
631       if (unformat (line_input, "index %d", &map_domain_index))
632         num_m_args++;
633       else
634         {
635           error = clib_error_return (0, "unknown input `%U'",
636                                      format_unformat_error, line_input);
637           goto done;
638         }
639     }
640
641   if (num_m_args != 1)
642     {
643       error = clib_error_return (0, "mandatory argument(s) missing");
644       goto done;
645     }
646
647   map_delete_domain (map_domain_index);
648
649 done:
650   unformat_free (line_input);
651
652   return error;
653 }
654
655 static clib_error_t *
656 map_add_rule_command_fn (vlib_main_t * vm,
657                          unformat_input_t * input, vlib_cli_command_t * cmd)
658 {
659   unformat_input_t _line_input, *line_input = &_line_input;
660   ip6_address_t tep;
661   u32 num_m_args = 0;
662   u32 psid = 0, map_domain_index;
663   clib_error_t *error = NULL;
664
665   /* Get a line of input. */
666   if (!unformat_user (input, unformat_line_input, line_input))
667     return 0;
668
669   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
670     {
671       if (unformat (line_input, "index %d", &map_domain_index))
672         num_m_args++;
673       else if (unformat (line_input, "psid %d", &psid))
674         num_m_args++;
675       else
676         if (unformat (line_input, "ip6-dst %U", unformat_ip6_address, &tep))
677         num_m_args++;
678       else
679         {
680           error = clib_error_return (0, "unknown input `%U'",
681                                      format_unformat_error, line_input);
682           goto done;
683         }
684     }
685
686   if (num_m_args != 3)
687     {
688       error = clib_error_return (0, "mandatory argument(s) missing");
689       goto done;
690     }
691
692   if (map_add_del_psid (map_domain_index, psid, &tep, 1) != 0)
693     {
694       error = clib_error_return (0, "Failing to add Mapping Rule");
695       goto done;
696     }
697
698 done:
699   unformat_free (line_input);
700
701   return error;
702 }
703
704 #if MAP_SKIP_IP6_LOOKUP
705 static clib_error_t *
706 map_pre_resolve_command_fn (vlib_main_t * vm,
707                             unformat_input_t * input,
708                             vlib_cli_command_t * cmd)
709 {
710   unformat_input_t _line_input, *line_input = &_line_input;
711   ip4_address_t ip4nh, *p_v4 = NULL;
712   ip6_address_t ip6nh, *p_v6 = NULL;
713   clib_error_t *error = NULL;
714   int is_del = 0;
715
716   memset (&ip4nh, 0, sizeof (ip4nh));
717   memset (&ip6nh, 0, sizeof (ip6nh));
718
719   /* Get a line of input. */
720   if (!unformat_user (input, unformat_line_input, line_input))
721     return 0;
722
723   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
724     {
725       if (unformat (line_input, "ip4-nh %U", unformat_ip4_address, &ip4nh))
726         p_v4 = &ip4nh;
727       else
728         if (unformat (line_input, "ip6-nh %U", unformat_ip6_address, &ip6nh))
729         p_v6 = &ip6nh;
730       else if (unformat (line_input, "del"))
731         is_del = 1;
732       else
733         {
734           error = clib_error_return (0, "unknown input `%U'",
735                                      format_unformat_error, line_input);
736           goto done;
737         }
738     }
739
740   map_pre_resolve (p_v4, p_v6, is_del);
741
742 done:
743   unformat_free (line_input);
744
745   return error;
746 }
747 #endif
748
749 static clib_error_t *
750 map_icmp_relay_source_address_command_fn (vlib_main_t * vm,
751                                           unformat_input_t * input,
752                                           vlib_cli_command_t * cmd)
753 {
754   unformat_input_t _line_input, *line_input = &_line_input;
755   ip4_address_t icmp_src_address;
756   map_main_t *mm = &map_main;
757   clib_error_t *error = NULL;
758
759   mm->icmp4_src_address.as_u32 = 0;
760
761   /* Get a line of input. */
762   if (!unformat_user (input, unformat_line_input, line_input))
763     return 0;
764
765   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
766     {
767       if (unformat
768           (line_input, "%U", unformat_ip4_address, &icmp_src_address))
769         mm->icmp4_src_address = icmp_src_address;
770       else
771         {
772           error = clib_error_return (0, "unknown input `%U'",
773                                      format_unformat_error, line_input);
774           goto done;
775         }
776     }
777
778 done:
779   unformat_free (line_input);
780
781   return error;
782 }
783
784 static clib_error_t *
785 map_icmp_unreachables_command_fn (vlib_main_t * vm,
786                                   unformat_input_t * input,
787                                   vlib_cli_command_t * cmd)
788 {
789   unformat_input_t _line_input, *line_input = &_line_input;
790   map_main_t *mm = &map_main;
791   int num_m_args = 0;
792   clib_error_t *error = NULL;
793
794   /* Get a line of input. */
795   if (!unformat_user (input, unformat_line_input, line_input))
796     return 0;
797
798   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
799     {
800       num_m_args++;
801       if (unformat (line_input, "on"))
802         mm->icmp6_enabled = true;
803       else if (unformat (line_input, "off"))
804         mm->icmp6_enabled = false;
805       else
806         {
807           error = clib_error_return (0, "unknown input `%U'",
808                                      format_unformat_error, line_input);
809           goto done;
810         }
811     }
812
813
814   if (num_m_args != 1)
815     error = clib_error_return (0, "mandatory argument(s) missing");
816
817 done:
818   unformat_free (line_input);
819
820   return error;
821 }
822
823 static clib_error_t *
824 map_fragment_command_fn (vlib_main_t * vm,
825                          unformat_input_t * input, vlib_cli_command_t * cmd)
826 {
827   unformat_input_t _line_input, *line_input = &_line_input;
828   map_main_t *mm = &map_main;
829   clib_error_t *error = NULL;
830
831   /* Get a line of input. */
832   if (!unformat_user (input, unformat_line_input, line_input))
833     return 0;
834
835   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
836     {
837       if (unformat (line_input, "inner"))
838         mm->frag_inner = true;
839       else if (unformat (line_input, "outer"))
840         mm->frag_inner = false;
841       else
842         {
843           error = clib_error_return (0, "unknown input `%U'",
844                                      format_unformat_error, line_input);
845           goto done;
846         }
847     }
848
849 done:
850   unformat_free (line_input);
851
852   return error;
853 }
854
855 static clib_error_t *
856 map_fragment_df_command_fn (vlib_main_t * vm,
857                             unformat_input_t * input,
858                             vlib_cli_command_t * cmd)
859 {
860   unformat_input_t _line_input, *line_input = &_line_input;
861   map_main_t *mm = &map_main;
862   clib_error_t *error = NULL;
863
864   /* Get a line of input. */
865   if (!unformat_user (input, unformat_line_input, line_input))
866     return 0;
867
868   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
869     {
870       if (unformat (line_input, "on"))
871         mm->frag_ignore_df = true;
872       else if (unformat (line_input, "off"))
873         mm->frag_ignore_df = false;
874       else
875         {
876           error = clib_error_return (0, "unknown input `%U'",
877                                      format_unformat_error, line_input);
878           goto done;
879         }
880     }
881
882 done:
883   unformat_free (line_input);
884
885   return error;
886 }
887
888 static clib_error_t *
889 map_traffic_class_command_fn (vlib_main_t * vm,
890                               unformat_input_t * input,
891                               vlib_cli_command_t * cmd)
892 {
893   unformat_input_t _line_input, *line_input = &_line_input;
894   map_main_t *mm = &map_main;
895   u32 tc = 0;
896   clib_error_t *error = NULL;
897
898   mm->tc_copy = false;
899
900   /* Get a line of input. */
901   if (!unformat_user (input, unformat_line_input, line_input))
902     return 0;
903
904   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
905     {
906       if (unformat (line_input, "copy"))
907         mm->tc_copy = true;
908       else if (unformat (line_input, "%x", &tc))
909         mm->tc = tc & 0xff;
910       else
911         {
912           error = clib_error_return (0, "unknown input `%U'",
913                                      format_unformat_error, line_input);
914           goto done;
915         }
916     }
917
918 done:
919   unformat_free (line_input);
920
921   return error;
922 }
923
924 static u8 *
925 format_map_domain (u8 * s, va_list * args)
926 {
927   map_domain_t *d = va_arg (*args, map_domain_t *);
928   bool counters = va_arg (*args, int);
929   map_main_t *mm = &map_main;
930   ip6_address_t ip6_prefix;
931
932   if (d->rules)
933     memset (&ip6_prefix, 0, sizeof (ip6_prefix));
934   else
935     ip6_prefix = d->ip6_prefix;
936
937   s = format (s,
938               "[%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",
939               d - mm->domains,
940               format_ip4_address, &d->ip4_prefix, d->ip4_prefix_len,
941               format_ip6_address, &ip6_prefix, d->ip6_prefix_len,
942               format_ip6_address, &d->ip6_src, d->ip6_src_len,
943               d->ea_bits_len, d->psid_offset, d->psid_length, d->mtu,
944               (d->flags & MAP_DOMAIN_TRANSLATION) ? "map-t" : "");
945
946   if (counters)
947     {
948       map_domain_counter_lock (mm);
949       vlib_counter_t v;
950       vlib_get_combined_counter (&mm->domain_counters[MAP_DOMAIN_COUNTER_TX],
951                                  d - mm->domains, &v);
952       s = format (s, "  TX: %lld/%lld", v.packets, v.bytes);
953       vlib_get_combined_counter (&mm->domain_counters[MAP_DOMAIN_COUNTER_RX],
954                                  d - mm->domains, &v);
955       s = format (s, "  RX: %lld/%lld", v.packets, v.bytes);
956       map_domain_counter_unlock (mm);
957     }
958   s = format (s, "\n");
959
960   if (d->rules)
961     {
962       int i;
963       ip6_address_t dst;
964       for (i = 0; i < (0x1 << d->psid_length); i++)
965         {
966           dst = d->rules[i];
967           if (dst.as_u64[0] == 0 && dst.as_u64[1] == 0)
968             continue;
969           s = format (s,
970                       " rule psid: %d ip6-dst %U\n", i, format_ip6_address,
971                       &dst);
972         }
973     }
974   return s;
975 }
976
977 static u8 *
978 format_map_ip4_reass (u8 * s, va_list * args)
979 {
980   map_main_t *mm = &map_main;
981   map_ip4_reass_t *r = va_arg (*args, map_ip4_reass_t *);
982   map_ip4_reass_key_t *k = &r->key;
983   f64 now = vlib_time_now (mm->vlib_main);
984   f64 lifetime = (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000);
985   f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
986   s = format (s,
987               "ip4-reass src=%U  dst=%U  protocol=%d  identifier=%d  port=%d  lifetime=%.3lf\n",
988               format_ip4_address, &k->src.as_u8, format_ip4_address,
989               &k->dst.as_u8, k->protocol,
990               clib_net_to_host_u16 (k->fragment_id),
991               (r->port >= 0) ? clib_net_to_host_u16 (r->port) : -1, dt);
992   return s;
993 }
994
995 static u8 *
996 format_map_ip6_reass (u8 * s, va_list * args)
997 {
998   map_main_t *mm = &map_main;
999   map_ip6_reass_t *r = va_arg (*args, map_ip6_reass_t *);
1000   map_ip6_reass_key_t *k = &r->key;
1001   f64 now = vlib_time_now (mm->vlib_main);
1002   f64 lifetime = (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000);
1003   f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
1004   s = format (s,
1005               "ip6-reass src=%U  dst=%U  protocol=%d  identifier=%d  lifetime=%.3lf\n",
1006               format_ip6_address, &k->src.as_u8, format_ip6_address,
1007               &k->dst.as_u8, k->protocol,
1008               clib_net_to_host_u32 (k->fragment_id), dt);
1009   return s;
1010 }
1011
1012 static clib_error_t *
1013 show_map_domain_command_fn (vlib_main_t * vm, unformat_input_t * input,
1014                             vlib_cli_command_t * cmd)
1015 {
1016   unformat_input_t _line_input, *line_input = &_line_input;
1017   map_main_t *mm = &map_main;
1018   map_domain_t *d;
1019   bool counters = false;
1020   u32 map_domain_index = ~0;
1021   clib_error_t *error = NULL;
1022
1023   /* Get a line of input. */
1024   if (!unformat_user (input, unformat_line_input, line_input))
1025     return 0;
1026
1027   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1028     {
1029       if (unformat (line_input, "counters"))
1030         counters = true;
1031       else if (unformat (line_input, "index %d", &map_domain_index))
1032         ;
1033       else
1034         {
1035           error = clib_error_return (0, "unknown input `%U'",
1036                                      format_unformat_error, line_input);
1037           goto done;
1038         }
1039     }
1040
1041   if (pool_elts (mm->domains) == 0)
1042     vlib_cli_output (vm, "No MAP domains are configured...");
1043
1044   if (map_domain_index == ~0)
1045     {
1046     /* *INDENT-OFF* */
1047     pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_map_domain, d, counters);}));
1048     /* *INDENT-ON* */
1049     }
1050   else
1051     {
1052       if (pool_is_free_index (mm->domains, map_domain_index))
1053         {
1054           error = clib_error_return (0, "MAP domain does not exists %d",
1055                                      map_domain_index);
1056           goto done;
1057         }
1058
1059       d = pool_elt_at_index (mm->domains, map_domain_index);
1060       vlib_cli_output (vm, "%U", format_map_domain, d, counters);
1061     }
1062
1063 done:
1064   unformat_free (line_input);
1065
1066   return error;
1067 }
1068
1069 static clib_error_t *
1070 show_map_fragments_command_fn (vlib_main_t * vm, unformat_input_t * input,
1071                                vlib_cli_command_t * cmd)
1072 {
1073   map_main_t *mm = &map_main;
1074   map_ip4_reass_t *f4;
1075   map_ip6_reass_t *f6;
1076
1077   /* *INDENT-OFF* */
1078   pool_foreach(f4, mm->ip4_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip4_reass, f4);}));
1079   /* *INDENT-ON* */
1080   /* *INDENT-OFF* */
1081   pool_foreach(f6, mm->ip6_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip6_reass, f6);}));
1082   /* *INDENT-ON* */
1083   return (0);
1084 }
1085
1086 u64
1087 map_error_counter_get (u32 node_index, map_error_t map_error)
1088 {
1089   vlib_main_t *vm = vlib_get_main ();
1090   vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, node_index);
1091   vlib_error_main_t *em = &vm->error_main;
1092   vlib_error_t e = error_node->errors[map_error];
1093   vlib_node_t *n = vlib_get_node (vm, node_index);
1094   u32 ci;
1095
1096   ci = vlib_error_get_code (e);
1097   ASSERT (ci < n->n_errors);
1098   ci += n->error_heap_index;
1099
1100   return (em->counters[ci]);
1101 }
1102
1103 static clib_error_t *
1104 show_map_stats_command_fn (vlib_main_t * vm, unformat_input_t * input,
1105                            vlib_cli_command_t * cmd)
1106 {
1107   map_main_t *mm = &map_main;
1108   map_domain_t *d;
1109   int domains = 0, rules = 0, domaincount = 0, rulecount = 0;
1110   if (pool_elts (mm->domains) == 0)
1111     {
1112       vlib_cli_output (vm, "No MAP domains are configured...");
1113       return 0;
1114     }
1115
1116   /* *INDENT-OFF* */
1117   pool_foreach(d, mm->domains, ({
1118     if (d->rules) {
1119       rulecount+= 0x1 << d->psid_length;
1120       rules += sizeof(ip6_address_t) * 0x1 << d->psid_length;
1121     }
1122     domains += sizeof(*d);
1123     domaincount++;
1124   }));
1125   /* *INDENT-ON* */
1126
1127   vlib_cli_output (vm, "MAP domains structure: %d\n", sizeof (map_domain_t));
1128   vlib_cli_output (vm, "MAP domains: %d (%d bytes)\n", domaincount, domains);
1129   vlib_cli_output (vm, "MAP rules: %d (%d bytes)\n", rulecount, rules);
1130   vlib_cli_output (vm, "Total: %d bytes)\n", rules + domains);
1131
1132 #if MAP_SKIP_IP6_LOOKUP
1133   vlib_cli_output (vm,
1134                    "MAP pre-resolve: IP6 next-hop: %U, IP4 next-hop: %U\n",
1135                    format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP6],
1136                    format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP4]);
1137
1138 #endif
1139
1140   if (mm->tc_copy)
1141     vlib_cli_output (vm, "MAP traffic-class: copy");
1142   else
1143     vlib_cli_output (vm, "MAP traffic-class: %x", mm->tc);
1144
1145   vlib_cli_output (vm,
1146                    "MAP IPv6 inbound security check: %s, fragmented packet security check: %s",
1147                    mm->sec_check ? "enabled" : "disabled",
1148                    mm->sec_check_frag ? "enabled" : "disabled");
1149
1150   vlib_cli_output (vm, "ICMP-relay IPv4 source address: %U\n",
1151                    format_ip4_address, &mm->icmp4_src_address);
1152   vlib_cli_output (vm, "ICMP6 unreachables sent for unmatched packets: %s\n",
1153                    mm->icmp6_enabled ? "enabled" : "disabled");
1154   vlib_cli_output (vm, "Inner fragmentation: %s\n",
1155                    mm->frag_inner ? "enabled" : "disabled");
1156   vlib_cli_output (vm, "Fragment packets regardless of DF flag: %s\n",
1157                    mm->frag_ignore_df ? "enabled" : "disabled");
1158
1159   /*
1160    * Counters
1161    */
1162   vlib_combined_counter_main_t *cm = mm->domain_counters;
1163   u64 total_pkts[MAP_N_DOMAIN_COUNTER];
1164   u64 total_bytes[MAP_N_DOMAIN_COUNTER];
1165   int which, i;
1166   vlib_counter_t v;
1167
1168   memset (total_pkts, 0, sizeof (total_pkts));
1169   memset (total_bytes, 0, sizeof (total_bytes));
1170
1171   map_domain_counter_lock (mm);
1172   vec_foreach (cm, mm->domain_counters)
1173   {
1174     which = cm - mm->domain_counters;
1175
1176     for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
1177       {
1178         vlib_get_combined_counter (cm, i, &v);
1179         total_pkts[which] += v.packets;
1180         total_bytes[which] += v.bytes;
1181       }
1182   }
1183   map_domain_counter_unlock (mm);
1184
1185   vlib_cli_output (vm, "Encapsulated packets: %lld bytes: %lld\n",
1186                    total_pkts[MAP_DOMAIN_COUNTER_TX],
1187                    total_bytes[MAP_DOMAIN_COUNTER_TX]);
1188   vlib_cli_output (vm, "Decapsulated packets: %lld bytes: %lld\n",
1189                    total_pkts[MAP_DOMAIN_COUNTER_RX],
1190                    total_bytes[MAP_DOMAIN_COUNTER_RX]);
1191
1192   vlib_cli_output (vm, "ICMP relayed packets: %d\n",
1193                    vlib_get_simple_counter (&mm->icmp_relayed, 0));
1194
1195   return 0;
1196 }
1197
1198 static clib_error_t *
1199 map_params_reass_command_fn (vlib_main_t * vm, unformat_input_t * input,
1200                              vlib_cli_command_t * cmd)
1201 {
1202   unformat_input_t _line_input, *line_input = &_line_input;
1203   u32 lifetime = ~0;
1204   f64 ht_ratio = (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1);
1205   u32 pool_size = ~0;
1206   u64 buffers = ~(0ull);
1207   u8 ip4 = 0, ip6 = 0;
1208
1209   if (!unformat_user (input, unformat_line_input, line_input))
1210     return 0;
1211
1212   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1213     {
1214       if (unformat (line_input, "lifetime %u", &lifetime))
1215         ;
1216       else if (unformat (line_input, "ht-ratio %lf", &ht_ratio))
1217         ;
1218       else if (unformat (line_input, "pool-size %u", &pool_size))
1219         ;
1220       else if (unformat (line_input, "buffers %llu", &buffers))
1221         ;
1222       else if (unformat (line_input, "ip4"))
1223         ip4 = 1;
1224       else if (unformat (line_input, "ip6"))
1225         ip6 = 1;
1226       else
1227         {
1228           unformat_free (line_input);
1229           return clib_error_return (0, "invalid input");
1230         }
1231     }
1232   unformat_free (line_input);
1233
1234   if (!ip4 && !ip6)
1235     return clib_error_return (0, "must specify ip4 and/or ip6");
1236
1237   if (ip4)
1238     {
1239       if (pool_size != ~0 && pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1240         return clib_error_return (0, "invalid ip4-reass pool-size ( > %d)",
1241                                   MAP_IP4_REASS_CONF_POOL_SIZE_MAX);
1242       if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1243           && ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1244         return clib_error_return (0, "invalid ip4-reass ht-ratio ( > %d)",
1245                                   MAP_IP4_REASS_CONF_HT_RATIO_MAX);
1246       if (lifetime != ~0 && lifetime > MAP_IP4_REASS_CONF_LIFETIME_MAX)
1247         return clib_error_return (0, "invalid ip4-reass lifetime ( > %d)",
1248                                   MAP_IP4_REASS_CONF_LIFETIME_MAX);
1249       if (buffers != ~(0ull) && buffers > MAP_IP4_REASS_CONF_BUFFERS_MAX)
1250         return clib_error_return (0, "invalid ip4-reass buffers ( > %ld)",
1251                                   MAP_IP4_REASS_CONF_BUFFERS_MAX);
1252     }
1253
1254   if (ip6)
1255     {
1256       if (pool_size != ~0 && pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1257         return clib_error_return (0, "invalid ip6-reass pool-size ( > %d)",
1258                                   MAP_IP6_REASS_CONF_POOL_SIZE_MAX);
1259       if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1260           && ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1261         return clib_error_return (0, "invalid ip6-reass ht-log2len ( > %d)",
1262                                   MAP_IP6_REASS_CONF_HT_RATIO_MAX);
1263       if (lifetime != ~0 && lifetime > MAP_IP6_REASS_CONF_LIFETIME_MAX)
1264         return clib_error_return (0, "invalid ip6-reass lifetime ( > %d)",
1265                                   MAP_IP6_REASS_CONF_LIFETIME_MAX);
1266       if (buffers != ~(0ull) && buffers > MAP_IP6_REASS_CONF_BUFFERS_MAX)
1267         return clib_error_return (0, "invalid ip6-reass buffers ( > %ld)",
1268                                   MAP_IP6_REASS_CONF_BUFFERS_MAX);
1269     }
1270
1271   if (ip4)
1272     {
1273       u32 reass = 0, packets = 0;
1274       if (pool_size != ~0)
1275         {
1276           if (map_ip4_reass_conf_pool_size (pool_size, &reass, &packets))
1277             {
1278               vlib_cli_output (vm, "Could not set ip4-reass pool-size");
1279             }
1280           else
1281             {
1282               vlib_cli_output (vm,
1283                                "Setting ip4-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1284                                reass, packets);
1285             }
1286         }
1287       if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1288         {
1289           if (map_ip4_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1290             {
1291               vlib_cli_output (vm, "Could not set ip4-reass ht-log2len");
1292             }
1293           else
1294             {
1295               vlib_cli_output (vm,
1296                                "Setting ip4-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1297                                reass, packets);
1298             }
1299         }
1300       if (lifetime != ~0)
1301         {
1302           if (map_ip4_reass_conf_lifetime (lifetime))
1303             vlib_cli_output (vm, "Could not set ip4-reass lifetime");
1304           else
1305             vlib_cli_output (vm, "Setting ip4-reass lifetime");
1306         }
1307       if (buffers != ~(0ull))
1308         {
1309           if (map_ip4_reass_conf_buffers (buffers))
1310             vlib_cli_output (vm, "Could not set ip4-reass buffers");
1311           else
1312             vlib_cli_output (vm, "Setting ip4-reass buffers");
1313         }
1314
1315       if (map_main.ip4_reass_conf_buffers >
1316           map_main.ip4_reass_conf_pool_size *
1317           MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY)
1318         {
1319           vlib_cli_output (vm,
1320                            "Note: 'ip4-reass buffers' > pool-size * max-fragments-per-reassembly.");
1321         }
1322     }
1323
1324   if (ip6)
1325     {
1326       u32 reass = 0, packets = 0;
1327       if (pool_size != ~0)
1328         {
1329           if (map_ip6_reass_conf_pool_size (pool_size, &reass, &packets))
1330             {
1331               vlib_cli_output (vm, "Could not set ip6-reass pool-size");
1332             }
1333           else
1334             {
1335               vlib_cli_output (vm,
1336                                "Setting ip6-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1337                                reass, packets);
1338             }
1339         }
1340       if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1341         {
1342           if (map_ip6_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1343             {
1344               vlib_cli_output (vm, "Could not set ip6-reass ht-log2len");
1345             }
1346           else
1347             {
1348               vlib_cli_output (vm,
1349                                "Setting ip6-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1350                                reass, packets);
1351             }
1352         }
1353       if (lifetime != ~0)
1354         {
1355           if (map_ip6_reass_conf_lifetime (lifetime))
1356             vlib_cli_output (vm, "Could not set ip6-reass lifetime");
1357           else
1358             vlib_cli_output (vm, "Setting ip6-reass lifetime");
1359         }
1360       if (buffers != ~(0ull))
1361         {
1362           if (map_ip6_reass_conf_buffers (buffers))
1363             vlib_cli_output (vm, "Could not set ip6-reass buffers");
1364           else
1365             vlib_cli_output (vm, "Setting ip6-reass buffers");
1366         }
1367
1368       if (map_main.ip6_reass_conf_buffers >
1369           map_main.ip6_reass_conf_pool_size *
1370           MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY)
1371         {
1372           vlib_cli_output (vm,
1373                            "Note: 'ip6-reass buffers' > pool-size * max-fragments-per-reassembly.");
1374         }
1375     }
1376
1377   return 0;
1378 }
1379
1380
1381 /*
1382  * packet trace format function
1383  */
1384 u8 *
1385 format_map_trace (u8 * s, va_list * args)
1386 {
1387   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1388   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1389   map_trace_t *t = va_arg (*args, map_trace_t *);
1390   u32 map_domain_index = t->map_domain_index;
1391   u16 port = t->port;
1392
1393   s =
1394     format (s, "MAP domain index: %d L4 port: %u", map_domain_index,
1395             clib_net_to_host_u16 (port));
1396
1397   return s;
1398 }
1399
1400 static_always_inline map_ip4_reass_t *
1401 map_ip4_reass_lookup (map_ip4_reass_key_t * k, u32 bucket, f64 now)
1402 {
1403   map_main_t *mm = &map_main;
1404   u32 ri = mm->ip4_reass_hash_table[bucket];
1405   while (ri != MAP_REASS_INDEX_NONE)
1406     {
1407       map_ip4_reass_t *r = pool_elt_at_index (mm->ip4_reass_pool, ri);
1408       if (r->key.as_u64[0] == k->as_u64[0] &&
1409           r->key.as_u64[1] == k->as_u64[1] &&
1410           now < r->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000))
1411         {
1412           return r;
1413         }
1414       ri = r->bucket_next;
1415     }
1416   return NULL;
1417 }
1418
1419 #define map_ip4_reass_pool_index(r) (r - map_main.ip4_reass_pool)
1420
1421 void
1422 map_ip4_reass_free (map_ip4_reass_t * r, u32 ** pi_to_drop)
1423 {
1424   map_main_t *mm = &map_main;
1425   map_ip4_reass_get_fragments (r, pi_to_drop);
1426
1427   // Unlink in hash bucket
1428   map_ip4_reass_t *r2 = NULL;
1429   u32 r2i = mm->ip4_reass_hash_table[r->bucket];
1430   while (r2i != map_ip4_reass_pool_index (r))
1431     {
1432       ASSERT (r2i != MAP_REASS_INDEX_NONE);
1433       r2 = pool_elt_at_index (mm->ip4_reass_pool, r2i);
1434       r2i = r2->bucket_next;
1435     }
1436   if (r2)
1437     {
1438       r2->bucket_next = r->bucket_next;
1439     }
1440   else
1441     {
1442       mm->ip4_reass_hash_table[r->bucket] = r->bucket_next;
1443     }
1444
1445   // Unlink in list
1446   if (r->fifo_next == map_ip4_reass_pool_index (r))
1447     {
1448       mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
1449     }
1450   else
1451     {
1452       if (mm->ip4_reass_fifo_last == map_ip4_reass_pool_index (r))
1453         mm->ip4_reass_fifo_last = r->fifo_prev;
1454       pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next =
1455         r->fifo_next;
1456       pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev =
1457         r->fifo_prev;
1458     }
1459
1460   pool_put (mm->ip4_reass_pool, r);
1461   mm->ip4_reass_allocated--;
1462 }
1463
1464 map_ip4_reass_t *
1465 map_ip4_reass_get (u32 src, u32 dst, u16 fragment_id,
1466                    u8 protocol, u32 ** pi_to_drop)
1467 {
1468   map_ip4_reass_t *r;
1469   map_main_t *mm = &map_main;
1470   map_ip4_reass_key_t k = {.src.data_u32 = src,
1471     .dst.data_u32 = dst,
1472     .fragment_id = fragment_id,
1473     .protocol = protocol
1474   };
1475
1476   u32 h = 0;
1477 #ifdef clib_crc32c_uses_intrinsics
1478   h = clib_crc32c ((u8 *) k.as_u32, 16);
1479 #else
1480   u64 tmp = k.as_u32[0] ^ k.as_u32[1] ^ k.as_u32[2] ^ k.as_u32[3];
1481   h = clib_xxhash (tmp);
1482 #endif
1483   h = h >> (32 - mm->ip4_reass_ht_log2len);
1484
1485   f64 now = vlib_time_now (mm->vlib_main);
1486
1487   //Cache garbage collection
1488   while (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
1489     {
1490       map_ip4_reass_t *last =
1491         pool_elt_at_index (mm->ip4_reass_pool, mm->ip4_reass_fifo_last);
1492       if (last->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000) < now)
1493         map_ip4_reass_free (last, pi_to_drop);
1494       else
1495         break;
1496     }
1497
1498   if ((r = map_ip4_reass_lookup (&k, h, now)))
1499     return r;
1500
1501   if (mm->ip4_reass_allocated >= mm->ip4_reass_conf_pool_size)
1502     return NULL;
1503
1504   pool_get (mm->ip4_reass_pool, r);
1505   mm->ip4_reass_allocated++;
1506   int i;
1507   for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1508     r->fragments[i] = ~0;
1509
1510   u32 ri = map_ip4_reass_pool_index (r);
1511
1512   //Link in new bucket
1513   r->bucket = h;
1514   r->bucket_next = mm->ip4_reass_hash_table[h];
1515   mm->ip4_reass_hash_table[h] = ri;
1516
1517   //Link in fifo
1518   if (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
1519     {
1520       r->fifo_next =
1521         pool_elt_at_index (mm->ip4_reass_pool,
1522                            mm->ip4_reass_fifo_last)->fifo_next;
1523       r->fifo_prev = mm->ip4_reass_fifo_last;
1524       pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next = ri;
1525       pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev = ri;
1526     }
1527   else
1528     {
1529       r->fifo_next = r->fifo_prev = ri;
1530       mm->ip4_reass_fifo_last = ri;
1531     }
1532
1533   //Set other fields
1534   r->ts = now;
1535   r->key = k;
1536   r->port = -1;
1537 #ifdef MAP_IP4_REASS_COUNT_BYTES
1538   r->expected_total = 0xffff;
1539   r->forwarded = 0;
1540 #endif
1541
1542   return r;
1543 }
1544
1545 int
1546 map_ip4_reass_add_fragment (map_ip4_reass_t * r, u32 pi)
1547 {
1548   if (map_main.ip4_reass_buffered_counter >= map_main.ip4_reass_conf_buffers)
1549     return -1;
1550
1551   int i;
1552   for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1553     if (r->fragments[i] == ~0)
1554       {
1555         r->fragments[i] = pi;
1556         map_main.ip4_reass_buffered_counter++;
1557         return 0;
1558       }
1559   return -1;
1560 }
1561
1562 static_always_inline map_ip6_reass_t *
1563 map_ip6_reass_lookup (map_ip6_reass_key_t * k, u32 bucket, f64 now)
1564 {
1565   map_main_t *mm = &map_main;
1566   u32 ri = mm->ip6_reass_hash_table[bucket];
1567   while (ri != MAP_REASS_INDEX_NONE)
1568     {
1569       map_ip6_reass_t *r = pool_elt_at_index (mm->ip6_reass_pool, ri);
1570       if (now < r->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) &&
1571           r->key.as_u64[0] == k->as_u64[0] &&
1572           r->key.as_u64[1] == k->as_u64[1] &&
1573           r->key.as_u64[2] == k->as_u64[2] &&
1574           r->key.as_u64[3] == k->as_u64[3] &&
1575           r->key.as_u64[4] == k->as_u64[4])
1576         return r;
1577       ri = r->bucket_next;
1578     }
1579   return NULL;
1580 }
1581
1582 #define map_ip6_reass_pool_index(r) (r - map_main.ip6_reass_pool)
1583
1584 void
1585 map_ip6_reass_free (map_ip6_reass_t * r, u32 ** pi_to_drop)
1586 {
1587   map_main_t *mm = &map_main;
1588   int i;
1589   for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1590     if (r->fragments[i].pi != ~0)
1591       {
1592         vec_add1 (*pi_to_drop, r->fragments[i].pi);
1593         r->fragments[i].pi = ~0;
1594         map_main.ip6_reass_buffered_counter--;
1595       }
1596
1597   // Unlink in hash bucket
1598   map_ip6_reass_t *r2 = NULL;
1599   u32 r2i = mm->ip6_reass_hash_table[r->bucket];
1600   while (r2i != map_ip6_reass_pool_index (r))
1601     {
1602       ASSERT (r2i != MAP_REASS_INDEX_NONE);
1603       r2 = pool_elt_at_index (mm->ip6_reass_pool, r2i);
1604       r2i = r2->bucket_next;
1605     }
1606   if (r2)
1607     {
1608       r2->bucket_next = r->bucket_next;
1609     }
1610   else
1611     {
1612       mm->ip6_reass_hash_table[r->bucket] = r->bucket_next;
1613     }
1614
1615   // Unlink in list
1616   if (r->fifo_next == map_ip6_reass_pool_index (r))
1617     {
1618       //Single element in the list, list is now empty
1619       mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
1620     }
1621   else
1622     {
1623       if (mm->ip6_reass_fifo_last == map_ip6_reass_pool_index (r))      //First element
1624         mm->ip6_reass_fifo_last = r->fifo_prev;
1625       pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next =
1626         r->fifo_next;
1627       pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev =
1628         r->fifo_prev;
1629     }
1630
1631   // Free from pool if necessary
1632   pool_put (mm->ip6_reass_pool, r);
1633   mm->ip6_reass_allocated--;
1634 }
1635
1636 map_ip6_reass_t *
1637 map_ip6_reass_get (ip6_address_t * src, ip6_address_t * dst, u32 fragment_id,
1638                    u8 protocol, u32 ** pi_to_drop)
1639 {
1640   map_ip6_reass_t *r;
1641   map_main_t *mm = &map_main;
1642   map_ip6_reass_key_t k = {
1643     .src = *src,
1644     .dst = *dst,
1645     .fragment_id = fragment_id,
1646     .protocol = protocol
1647   };
1648
1649   u32 h = 0;
1650   int i;
1651
1652 #ifdef clib_crc32c_uses_intrinsics
1653   h = clib_crc32c ((u8 *) k.as_u32, 40);
1654 #else
1655   u64 tmp =
1656     k.as_u64[0] ^ k.as_u64[1] ^ k.as_u64[2] ^ k.as_u64[3] ^ k.as_u64[4];
1657   h = clib_xxhash (tmp);
1658 #endif
1659
1660   h = h >> (32 - mm->ip6_reass_ht_log2len);
1661
1662   f64 now = vlib_time_now (mm->vlib_main);
1663
1664   //Cache garbage collection
1665   while (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
1666     {
1667       map_ip6_reass_t *last =
1668         pool_elt_at_index (mm->ip6_reass_pool, mm->ip6_reass_fifo_last);
1669       if (last->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) < now)
1670         map_ip6_reass_free (last, pi_to_drop);
1671       else
1672         break;
1673     }
1674
1675   if ((r = map_ip6_reass_lookup (&k, h, now)))
1676     return r;
1677
1678   if (mm->ip6_reass_allocated >= mm->ip6_reass_conf_pool_size)
1679     return NULL;
1680
1681   pool_get (mm->ip6_reass_pool, r);
1682   mm->ip6_reass_allocated++;
1683   for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1684     {
1685       r->fragments[i].pi = ~0;
1686       r->fragments[i].next_data_len = 0;
1687       r->fragments[i].next_data_offset = 0;
1688     }
1689
1690   u32 ri = map_ip6_reass_pool_index (r);
1691
1692   //Link in new bucket
1693   r->bucket = h;
1694   r->bucket_next = mm->ip6_reass_hash_table[h];
1695   mm->ip6_reass_hash_table[h] = ri;
1696
1697   //Link in fifo
1698   if (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
1699     {
1700       r->fifo_next =
1701         pool_elt_at_index (mm->ip6_reass_pool,
1702                            mm->ip6_reass_fifo_last)->fifo_next;
1703       r->fifo_prev = mm->ip6_reass_fifo_last;
1704       pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next = ri;
1705       pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev = ri;
1706     }
1707   else
1708     {
1709       r->fifo_next = r->fifo_prev = ri;
1710       mm->ip6_reass_fifo_last = ri;
1711     }
1712
1713   //Set other fields
1714   r->ts = now;
1715   r->key = k;
1716   r->ip4_header.ip_version_and_header_length = 0;
1717 #ifdef MAP_IP6_REASS_COUNT_BYTES
1718   r->expected_total = 0xffff;
1719   r->forwarded = 0;
1720 #endif
1721   return r;
1722 }
1723
1724 int
1725 map_ip6_reass_add_fragment (map_ip6_reass_t * r, u32 pi,
1726                             u16 data_offset, u16 next_data_offset,
1727                             u8 * data_start, u16 data_len)
1728 {
1729   map_ip6_fragment_t *f = NULL, *prev_f = NULL;
1730   u16 copied_len = (data_len > 20) ? 20 : data_len;
1731
1732   if (map_main.ip6_reass_buffered_counter >= map_main.ip6_reass_conf_buffers)
1733     return -1;
1734
1735   //Lookup for fragments for the current buffer
1736   //and the one before that
1737   int i;
1738   for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1739     {
1740       if (data_offset && r->fragments[i].next_data_offset == data_offset)
1741         {
1742           prev_f = &r->fragments[i];    // This is buffer for previous packet
1743         }
1744       else if (r->fragments[i].next_data_offset == next_data_offset)
1745         {
1746           f = &r->fragments[i]; // This is a buffer for the current packet
1747         }
1748       else if (r->fragments[i].next_data_offset == 0)
1749         {                       //Available
1750           if (f == NULL)
1751             f = &r->fragments[i];
1752           else if (prev_f == NULL)
1753             prev_f = &r->fragments[i];
1754         }
1755     }
1756
1757   if (!f || f->pi != ~0)
1758     return -1;
1759
1760   if (data_offset)
1761     {
1762       if (!prev_f)
1763         return -1;
1764
1765       clib_memcpy (prev_f->next_data, data_start, copied_len);
1766       prev_f->next_data_len = copied_len;
1767       prev_f->next_data_offset = data_offset;
1768     }
1769   else
1770     {
1771       if (((ip4_header_t *) data_start)->ip_version_and_header_length != 0x45)
1772         return -1;
1773
1774       if (r->ip4_header.ip_version_and_header_length == 0)
1775         clib_memcpy (&r->ip4_header, data_start, sizeof (ip4_header_t));
1776     }
1777
1778   if (data_len > 20)
1779     {
1780       f->next_data_offset = next_data_offset;
1781       f->pi = pi;
1782       map_main.ip6_reass_buffered_counter++;
1783     }
1784   return 0;
1785 }
1786
1787 void
1788 map_ip4_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1789 {
1790   map_main_t *mm = &map_main;
1791   int i;
1792
1793   if (dropped_packets)
1794     *dropped_packets = mm->ip4_reass_buffered_counter;
1795   if (trashed_reass)
1796     *trashed_reass = mm->ip4_reass_allocated;
1797   if (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
1798     {
1799       u16 ri = mm->ip4_reass_fifo_last;
1800       do
1801         {
1802           map_ip4_reass_t *r = pool_elt_at_index (mm->ip4_reass_pool, ri);
1803           for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1804             if (r->fragments[i] != ~0)
1805               map_ip4_drop_pi (r->fragments[i]);
1806
1807           ri = r->fifo_next;
1808           pool_put (mm->ip4_reass_pool, r);
1809         }
1810       while (ri != mm->ip4_reass_fifo_last);
1811     }
1812
1813   vec_free (mm->ip4_reass_hash_table);
1814   vec_resize (mm->ip4_reass_hash_table, 1 << mm->ip4_reass_ht_log2len);
1815   for (i = 0; i < (1 << mm->ip4_reass_ht_log2len); i++)
1816     mm->ip4_reass_hash_table[i] = MAP_REASS_INDEX_NONE;
1817   pool_free (mm->ip4_reass_pool);
1818   pool_alloc (mm->ip4_reass_pool, mm->ip4_reass_conf_pool_size);
1819
1820   mm->ip4_reass_allocated = 0;
1821   mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
1822   mm->ip4_reass_buffered_counter = 0;
1823 }
1824
1825 u8
1826 map_get_ht_log2len (f32 ht_ratio, u16 pool_size)
1827 {
1828   u32 desired_size = (u32) (pool_size * ht_ratio);
1829   u8 i;
1830   for (i = 1; i < 31; i++)
1831     if ((1 << i) >= desired_size)
1832       return i;
1833   return 4;
1834 }
1835
1836 int
1837 map_ip4_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1838                              u32 * dropped_packets)
1839 {
1840   map_main_t *mm = &map_main;
1841   if (ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1842     return -1;
1843
1844   map_ip4_reass_lock ();
1845   mm->ip4_reass_conf_ht_ratio = ht_ratio;
1846   mm->ip4_reass_ht_log2len =
1847     map_get_ht_log2len (ht_ratio, mm->ip4_reass_conf_pool_size);
1848   map_ip4_reass_reinit (trashed_reass, dropped_packets);
1849   map_ip4_reass_unlock ();
1850   return 0;
1851 }
1852
1853 int
1854 map_ip4_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1855                               u32 * dropped_packets)
1856 {
1857   map_main_t *mm = &map_main;
1858   if (pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1859     return -1;
1860
1861   map_ip4_reass_lock ();
1862   mm->ip4_reass_conf_pool_size = pool_size;
1863   map_ip4_reass_reinit (trashed_reass, dropped_packets);
1864   map_ip4_reass_unlock ();
1865   return 0;
1866 }
1867
1868 int
1869 map_ip4_reass_conf_lifetime (u16 lifetime_ms)
1870 {
1871   map_main.ip4_reass_conf_lifetime_ms = lifetime_ms;
1872   return 0;
1873 }
1874
1875 int
1876 map_ip4_reass_conf_buffers (u32 buffers)
1877 {
1878   map_main.ip4_reass_conf_buffers = buffers;
1879   return 0;
1880 }
1881
1882 void
1883 map_ip6_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1884 {
1885   map_main_t *mm = &map_main;
1886   if (dropped_packets)
1887     *dropped_packets = mm->ip6_reass_buffered_counter;
1888   if (trashed_reass)
1889     *trashed_reass = mm->ip6_reass_allocated;
1890   int i;
1891   if (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
1892     {
1893       u16 ri = mm->ip6_reass_fifo_last;
1894       do
1895         {
1896           map_ip6_reass_t *r = pool_elt_at_index (mm->ip6_reass_pool, ri);
1897           for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1898             if (r->fragments[i].pi != ~0)
1899               map_ip6_drop_pi (r->fragments[i].pi);
1900
1901           ri = r->fifo_next;
1902           pool_put (mm->ip6_reass_pool, r);
1903         }
1904       while (ri != mm->ip6_reass_fifo_last);
1905       mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
1906     }
1907
1908   vec_free (mm->ip6_reass_hash_table);
1909   vec_resize (mm->ip6_reass_hash_table, 1 << mm->ip6_reass_ht_log2len);
1910   for (i = 0; i < (1 << mm->ip6_reass_ht_log2len); i++)
1911     mm->ip6_reass_hash_table[i] = MAP_REASS_INDEX_NONE;
1912   pool_free (mm->ip6_reass_pool);
1913   pool_alloc (mm->ip6_reass_pool, mm->ip4_reass_conf_pool_size);
1914
1915   mm->ip6_reass_allocated = 0;
1916   mm->ip6_reass_buffered_counter = 0;
1917 }
1918
1919 int
1920 map_ip6_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1921                              u32 * dropped_packets)
1922 {
1923   map_main_t *mm = &map_main;
1924   if (ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1925     return -1;
1926
1927   map_ip6_reass_lock ();
1928   mm->ip6_reass_conf_ht_ratio = ht_ratio;
1929   mm->ip6_reass_ht_log2len =
1930     map_get_ht_log2len (ht_ratio, mm->ip6_reass_conf_pool_size);
1931   map_ip6_reass_reinit (trashed_reass, dropped_packets);
1932   map_ip6_reass_unlock ();
1933   return 0;
1934 }
1935
1936 int
1937 map_ip6_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1938                               u32 * dropped_packets)
1939 {
1940   map_main_t *mm = &map_main;
1941   if (pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1942     return -1;
1943
1944   map_ip6_reass_lock ();
1945   mm->ip6_reass_conf_pool_size = pool_size;
1946   map_ip6_reass_reinit (trashed_reass, dropped_packets);
1947   map_ip6_reass_unlock ();
1948   return 0;
1949 }
1950
1951 int
1952 map_ip6_reass_conf_lifetime (u16 lifetime_ms)
1953 {
1954   map_main.ip6_reass_conf_lifetime_ms = lifetime_ms;
1955   return 0;
1956 }
1957
1958 int
1959 map_ip6_reass_conf_buffers (u32 buffers)
1960 {
1961   map_main.ip6_reass_conf_buffers = buffers;
1962   return 0;
1963 }
1964
1965 /* *INDENT-OFF* */
1966
1967 /*?
1968  * Configure MAP reassembly behaviour
1969  *
1970  * @cliexpar
1971  * @cliexstart{map params reassembly}
1972  * @cliexend
1973  ?*/
1974 VLIB_CLI_COMMAND(map_ip4_reass_lifetime_command, static) = {
1975   .path = "map params reassembly",
1976   .short_help = "map params reassembly [ip4 | ip6] [lifetime <lifetime-ms>] "
1977                 "[pool-size <pool-size>] [buffers <buffers>] "
1978                 "[ht-ratio <ht-ratio>]",
1979   .function = map_params_reass_command_fn,
1980 };
1981
1982 /*?
1983  * Set or copy the IP TOS/Traffic Class field
1984  *
1985  * @cliexpar
1986  * @cliexstart{map params traffic-class}
1987  *
1988  * This command is used to set the traffic-class field in translated
1989  * or encapsulated packets. If copy is specifed (the default) then the
1990  * traffic-class/TOS field is copied from the original packet to the
1991  * translated / encapsulating header.
1992  * @cliexend
1993  ?*/
1994 VLIB_CLI_COMMAND(map_traffic_class_command, static) = {
1995   .path = "map params traffic-class",
1996   .short_help = "map params traffic-class {0x0-0xff | copy}",
1997   .function = map_traffic_class_command_fn,
1998 };
1999
2000 /*?
2001  * Bypass IP4/IP6 lookup
2002  *
2003  * @cliexpar
2004  * @cliexstart{map params pre-resolve}
2005  *
2006  * Bypass a second FIB lookup of the translated or encapsulated
2007  * packet, and forward the packet directly to the specified
2008  * next-hop. This optimization trades forwarding flexibility for
2009  * performance.
2010  * @cliexend
2011  ?*/
2012 VLIB_CLI_COMMAND(map_pre_resolve_command, static) = {
2013   .path = "map params pre-resolve",
2014   .short_help = " map params pre-resolve {ip4-nh <address>} "
2015                 "| {ip6-nh <address>}",
2016   .function = map_pre_resolve_command_fn,
2017 };
2018
2019 /*?
2020  * Enable or disable the MAP-E inbound security check
2021  *
2022  * @cliexpar
2023  * @cliexstart{map params security-check}
2024  *
2025  * By default, a decapsulated packet's IPv4 source address will be
2026  * verified against the outer header's IPv6 source address. Disabling
2027  * this feature will allow IPv4 source address spoofing.
2028  * @cliexend
2029  ?*/
2030 VLIB_CLI_COMMAND(map_security_check_command, static) = {
2031   .path = "map params security-check",
2032   .short_help = "map params security-check on|off",
2033   .function = map_security_check_command_fn,
2034 };
2035
2036 /*?
2037  * Specifiy the IPv4 source address used for relayed ICMP error messages
2038  *
2039  * @cliexpar
2040  * @cliexstart{map params icmp source-address}
2041  *
2042  * This command specifies which IPv4 source address (must be local to
2043  * the system), that is used for relayed received IPv6 ICMP error
2044  * messages.
2045  * @cliexend
2046  ?*/
2047 VLIB_CLI_COMMAND(map_icmp_relay_source_address_command, static) = {
2048   .path = "map params icmp source-address",
2049   .short_help = "map params icmp source-address <ip4-address>",
2050   .function = map_icmp_relay_source_address_command_fn,
2051 };
2052
2053 /*?
2054  * Send IPv6 ICMP unreachables
2055  *
2056  * @cliexpar
2057  * @cliexstart{map params icmp6 unreachables}
2058  *
2059  * Send IPv6 ICMP unreachable messages back if security check fails or
2060  * no MAP domain exists.
2061  * @cliexend
2062  ?*/
2063 VLIB_CLI_COMMAND(map_icmp_unreachables_command, static) = {
2064   .path = "map params icmp6 unreachables",
2065   .short_help = "map params icmp6 unreachables {on|off}",
2066   .function = map_icmp_unreachables_command_fn,
2067 };
2068
2069 /*?
2070  * Configure MAP fragmentation behaviour
2071  *
2072  * @cliexpar
2073  * @cliexstart{map params fragment}
2074  * @cliexend
2075  ?*/
2076 VLIB_CLI_COMMAND(map_fragment_command, static) = {
2077   .path = "map params fragment",
2078   .short_help = "map params fragment inner|outer",
2079   .function = map_fragment_command_fn,
2080 };
2081
2082 /*?
2083  * Ignore the IPv4 Don't fragment bit
2084  *
2085  * @cliexpar
2086  * @cliexstart{map params fragment ignore-df}
2087  *
2088  * Allows fragmentation of the IPv4 packet even if the DF bit is
2089  * set. The choice between inner or outer fragmentation of tunnel
2090  * packets is complicated. The benefit of inner fragmentation is that
2091  * the ultimate endpoint must reassemble, instead of the tunnel
2092  * endpoint.
2093  * @cliexend
2094  ?*/
2095 VLIB_CLI_COMMAND(map_fragment_df_command, static) = {
2096   .path = "map params fragment ignore-df",
2097   .short_help = "map params fragment ignore-df on|off",
2098   .function = map_fragment_df_command_fn,
2099 };
2100
2101 /*?
2102  * Specifiy if the inbound security check should be done on fragments
2103  *
2104  * @cliexpar
2105  * @cliexstart{map params security-check fragments}
2106  *
2107  * Typically the inbound on-decapsulation security check is only done
2108  * on the first packet. The packet that contains the L4
2109  * information. While a security check on every fragment is possible,
2110  * it has a cost. State must be created on the first fragment.
2111  * @cliexend
2112  ?*/
2113 VLIB_CLI_COMMAND(map_security_check_frag_command, static) = {
2114   .path = "map params security-check fragments",
2115   .short_help = "map params security-check fragments on|off",
2116   .function = map_security_check_frag_command_fn,
2117 };
2118
2119 /*?
2120  * Add MAP domain
2121  *
2122  * @cliexpar
2123  * @cliexstart{map add domain}
2124  * @cliexend
2125  ?*/
2126 VLIB_CLI_COMMAND(map_add_domain_command, static) = {
2127   .path = "map add domain",
2128   .short_help = "map add domain ip4-pfx <ip4-pfx> ip6-pfx <ip6-pfx> "
2129       "ip6-src <ip6-pfx> ea-bits-len <n> psid-offset <n> psid-len <n> "
2130       "[map-t] [mtu <mtu>]",
2131   .function = map_add_domain_command_fn,
2132 };
2133
2134 /*?
2135  * Add MAP rule to a domain
2136  *
2137  * @cliexpar
2138  * @cliexstart{map add rule}
2139  * @cliexend
2140  ?*/
2141 VLIB_CLI_COMMAND(map_add_rule_command, static) = {
2142   .path = "map add rule",
2143   .short_help = "map add rule index <domain> psid <psid> ip6-dst <ip6-addr>",
2144   .function = map_add_rule_command_fn,
2145 };
2146
2147 /*?
2148  * Delete MAP domain
2149  *
2150  * @cliexpar
2151  * @cliexstart{map del domain}
2152  * @cliexend
2153  ?*/
2154 VLIB_CLI_COMMAND(map_del_command, static) = {
2155   .path = "map del domain",
2156   .short_help = "map del domain index <domain>",
2157   .function = map_del_domain_command_fn,
2158 };
2159
2160 /*?
2161  * Show MAP domains
2162  *
2163  * @cliexpar
2164  * @cliexstart{show map domain}
2165  * @cliexend
2166  ?*/
2167 VLIB_CLI_COMMAND(show_map_domain_command, static) = {
2168   .path = "show map domain",
2169   .short_help = "show map domain index <n> [counters]",
2170   .function = show_map_domain_command_fn,
2171 };
2172
2173 /*?
2174  * Show MAP statistics
2175  *
2176  * @cliexpar
2177  * @cliexstart{show map stats}
2178  * @cliexend
2179  ?*/
2180 VLIB_CLI_COMMAND(show_map_stats_command, static) = {
2181   .path = "show map stats",
2182   .short_help = "show map stats",
2183   .function = show_map_stats_command_fn,
2184 };
2185
2186 /*?
2187  * Show MAP fragmentation information
2188  *
2189  * @cliexpar
2190  * @cliexstart{show map fragments}
2191  * @cliexend
2192  ?*/
2193 VLIB_CLI_COMMAND(show_map_fragments_command, static) = {
2194   .path = "show map fragments",
2195   .short_help = "show map fragments",
2196   .function = show_map_fragments_command_fn,
2197 };
2198 /* *INDENT-ON* */
2199
2200 /*
2201  * map_init
2202  */
2203 clib_error_t *
2204 map_init (vlib_main_t * vm)
2205 {
2206   map_main_t *mm = &map_main;
2207   mm->vnet_main = vnet_get_main ();
2208   mm->vlib_main = vm;
2209
2210 #ifdef MAP_SKIP_IP6_LOOKUP
2211   fib_protocol_t proto;
2212
2213   FOR_EACH_FIB_PROTOCOL (proto)
2214   {
2215     map_pre_resolve_init (&pre_resolved[proto]);
2216   }
2217 #endif
2218
2219   /* traffic class */
2220   mm->tc = 0;
2221   mm->tc_copy = true;
2222
2223   /* Inbound security check */
2224   mm->sec_check = true;
2225   mm->sec_check_frag = false;
2226
2227   /* ICMP6 Type 1, Code 5 for security check failure */
2228   mm->icmp6_enabled = false;
2229
2230   /* Inner or outer fragmentation */
2231   mm->frag_inner = false;
2232   mm->frag_ignore_df = false;
2233
2234   vec_validate (mm->domain_counters, MAP_N_DOMAIN_COUNTER - 1);
2235   mm->domain_counters[MAP_DOMAIN_COUNTER_RX].name = "rx";
2236   mm->domain_counters[MAP_DOMAIN_COUNTER_TX].name = "tx";
2237
2238   vlib_validate_simple_counter (&mm->icmp_relayed, 0);
2239   vlib_zero_simple_counter (&mm->icmp_relayed, 0);
2240
2241   /* IP4 virtual reassembly */
2242   mm->ip4_reass_hash_table = 0;
2243   mm->ip4_reass_pool = 0;
2244   mm->ip4_reass_lock =
2245     clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
2246   *mm->ip4_reass_lock = 0;
2247   mm->ip4_reass_conf_ht_ratio = MAP_IP4_REASS_HT_RATIO_DEFAULT;
2248   mm->ip4_reass_conf_lifetime_ms = MAP_IP4_REASS_LIFETIME_DEFAULT;
2249   mm->ip4_reass_conf_pool_size = MAP_IP4_REASS_POOL_SIZE_DEFAULT;
2250   mm->ip4_reass_conf_buffers = MAP_IP4_REASS_BUFFERS_DEFAULT;
2251   mm->ip4_reass_ht_log2len =
2252     map_get_ht_log2len (mm->ip4_reass_conf_ht_ratio,
2253                         mm->ip4_reass_conf_pool_size);
2254   mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
2255   map_ip4_reass_reinit (NULL, NULL);
2256
2257   /* IP6 virtual reassembly */
2258   mm->ip6_reass_hash_table = 0;
2259   mm->ip6_reass_pool = 0;
2260   mm->ip6_reass_lock =
2261     clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
2262   *mm->ip6_reass_lock = 0;
2263   mm->ip6_reass_conf_ht_ratio = MAP_IP6_REASS_HT_RATIO_DEFAULT;
2264   mm->ip6_reass_conf_lifetime_ms = MAP_IP6_REASS_LIFETIME_DEFAULT;
2265   mm->ip6_reass_conf_pool_size = MAP_IP6_REASS_POOL_SIZE_DEFAULT;
2266   mm->ip6_reass_conf_buffers = MAP_IP6_REASS_BUFFERS_DEFAULT;
2267   mm->ip6_reass_ht_log2len =
2268     map_get_ht_log2len (mm->ip6_reass_conf_ht_ratio,
2269                         mm->ip6_reass_conf_pool_size);
2270   mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
2271   map_ip6_reass_reinit (NULL, NULL);
2272
2273 #ifdef MAP_SKIP_IP6_LOOKUP
2274   fib_node_register_type (FIB_NODE_TYPE_MAP_E, &map_vft);
2275 #endif
2276   map_dpo_module_init ();
2277
2278   return 0;
2279 }
2280
2281 VLIB_INIT_FUNCTION (map_init);
2282
2283 /*
2284  * fd.io coding-style-patch-verification: ON
2285  *
2286  * Local Variables:
2287  * eval: (c-set-style "gnu")
2288  * End:
2289  */