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