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