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