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