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