Coverty error: Incorrect expression (PW.ASSIGN_WHERE_COMPARE_MEANT)
[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         ;
1104       else if (unformat (line_input, "ht-ratio %lf", &ht_ratio))
1105         ;
1106       else if (unformat (line_input, "pool-size %u", &pool_size))
1107         ;
1108       else if (unformat (line_input, "buffers %llu", &buffers))
1109         ;
1110       else if (unformat (line_input, "ip4"))
1111         ip4 = 1;
1112       else if (unformat (line_input, "ip6"))
1113         ip6 = 1;
1114       else
1115         {
1116           unformat_free (line_input);
1117           return clib_error_return (0, "invalid input");
1118         }
1119     }
1120   unformat_free (line_input);
1121
1122   if (!ip4 && !ip6)
1123     return clib_error_return (0, "must specify ip4 and/or ip6");
1124
1125   if (ip4)
1126     {
1127       if (pool_size != ~0 && pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1128         return clib_error_return (0, "invalid ip4-reass pool-size ( > %d)",
1129                                   MAP_IP4_REASS_CONF_POOL_SIZE_MAX);
1130       if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1131           && ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1132         return clib_error_return (0, "invalid ip4-reass ht-ratio ( > %d)",
1133                                   MAP_IP4_REASS_CONF_HT_RATIO_MAX);
1134       if (lifetime != ~0 && lifetime > MAP_IP4_REASS_CONF_LIFETIME_MAX)
1135         return clib_error_return (0, "invalid ip4-reass lifetime ( > %d)",
1136                                   MAP_IP4_REASS_CONF_LIFETIME_MAX);
1137       if (buffers != ~(0ull) && buffers > MAP_IP4_REASS_CONF_BUFFERS_MAX)
1138         return clib_error_return (0, "invalid ip4-reass buffers ( > %ld)",
1139                                   MAP_IP4_REASS_CONF_BUFFERS_MAX);
1140     }
1141
1142   if (ip6)
1143     {
1144       if (pool_size != ~0 && pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1145         return clib_error_return (0, "invalid ip6-reass pool-size ( > %d)",
1146                                   MAP_IP6_REASS_CONF_POOL_SIZE_MAX);
1147       if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1148           && ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1149         return clib_error_return (0, "invalid ip6-reass ht-log2len ( > %d)",
1150                                   MAP_IP6_REASS_CONF_HT_RATIO_MAX);
1151       if (lifetime != ~0 && lifetime > MAP_IP6_REASS_CONF_LIFETIME_MAX)
1152         return clib_error_return (0, "invalid ip6-reass lifetime ( > %d)",
1153                                   MAP_IP6_REASS_CONF_LIFETIME_MAX);
1154       if (buffers != ~(0ull) && buffers > MAP_IP6_REASS_CONF_BUFFERS_MAX)
1155         return clib_error_return (0, "invalid ip6-reass buffers ( > %ld)",
1156                                   MAP_IP6_REASS_CONF_BUFFERS_MAX);
1157     }
1158
1159   if (ip4)
1160     {
1161       u32 reass = 0, packets = 0;
1162       if (pool_size != ~0)
1163         {
1164           if (map_ip4_reass_conf_pool_size (pool_size, &reass, &packets))
1165             {
1166               vlib_cli_output (vm, "Could not set ip4-reass pool-size");
1167             }
1168           else
1169             {
1170               vlib_cli_output (vm,
1171                                "Setting ip4-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1172                                reass, packets);
1173             }
1174         }
1175       if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1176         {
1177           if (map_ip4_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1178             {
1179               vlib_cli_output (vm, "Could not set ip4-reass ht-log2len");
1180             }
1181           else
1182             {
1183               vlib_cli_output (vm,
1184                                "Setting ip4-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1185                                reass, packets);
1186             }
1187         }
1188       if (lifetime != ~0)
1189         {
1190           if (map_ip4_reass_conf_lifetime (lifetime))
1191             vlib_cli_output (vm, "Could not set ip4-reass lifetime");
1192           else
1193             vlib_cli_output (vm, "Setting ip4-reass lifetime");
1194         }
1195       if (buffers != ~(0ull))
1196         {
1197           if (map_ip4_reass_conf_buffers (buffers))
1198             vlib_cli_output (vm, "Could not set ip4-reass buffers");
1199           else
1200             vlib_cli_output (vm, "Setting ip4-reass buffers");
1201         }
1202
1203       if (map_main.ip4_reass_conf_buffers >
1204           map_main.ip4_reass_conf_pool_size *
1205           MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY)
1206         {
1207           vlib_cli_output (vm,
1208                            "Note: 'ip4-reass buffers' > pool-size * max-fragments-per-reassembly.");
1209         }
1210     }
1211
1212   if (ip6)
1213     {
1214       u32 reass = 0, packets = 0;
1215       if (pool_size != ~0)
1216         {
1217           if (map_ip6_reass_conf_pool_size (pool_size, &reass, &packets))
1218             {
1219               vlib_cli_output (vm, "Could not set ip6-reass pool-size");
1220             }
1221           else
1222             {
1223               vlib_cli_output (vm,
1224                                "Setting ip6-reass pool-size (destroyed-reassembly=%u , dropped-fragments=%u)",
1225                                reass, packets);
1226             }
1227         }
1228       if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1))
1229         {
1230           if (map_ip6_reass_conf_ht_ratio (ht_ratio, &reass, &packets))
1231             {
1232               vlib_cli_output (vm, "Could not set ip6-reass ht-log2len");
1233             }
1234           else
1235             {
1236               vlib_cli_output (vm,
1237                                "Setting ip6-reass ht-log2len (destroyed-reassembly=%u , dropped-fragments=%u)",
1238                                reass, packets);
1239             }
1240         }
1241       if (lifetime != ~0)
1242         {
1243           if (map_ip6_reass_conf_lifetime (lifetime))
1244             vlib_cli_output (vm, "Could not set ip6-reass lifetime");
1245           else
1246             vlib_cli_output (vm, "Setting ip6-reass lifetime");
1247         }
1248       if (buffers != ~(0ull))
1249         {
1250           if (map_ip6_reass_conf_buffers (buffers))
1251             vlib_cli_output (vm, "Could not set ip6-reass buffers");
1252           else
1253             vlib_cli_output (vm, "Setting ip6-reass buffers");
1254         }
1255
1256       if (map_main.ip6_reass_conf_buffers >
1257           map_main.ip6_reass_conf_pool_size *
1258           MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY)
1259         {
1260           vlib_cli_output (vm,
1261                            "Note: 'ip6-reass buffers' > pool-size * max-fragments-per-reassembly.");
1262         }
1263     }
1264
1265   return 0;
1266 }
1267
1268
1269 /*
1270  * packet trace format function
1271  */
1272 u8 *
1273 format_map_trace (u8 * s, va_list * args)
1274 {
1275   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1276   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1277   map_trace_t *t = va_arg (*args, map_trace_t *);
1278   u32 map_domain_index = t->map_domain_index;
1279   u16 port = t->port;
1280
1281   s =
1282     format (s, "MAP domain index: %d L4 port: %u", map_domain_index,
1283             clib_net_to_host_u16 (port));
1284
1285   return s;
1286 }
1287
1288 static_always_inline map_ip4_reass_t *
1289 map_ip4_reass_lookup (map_ip4_reass_key_t * k, u32 bucket, f64 now)
1290 {
1291   map_main_t *mm = &map_main;
1292   u32 ri = mm->ip4_reass_hash_table[bucket];
1293   while (ri != MAP_REASS_INDEX_NONE)
1294     {
1295       map_ip4_reass_t *r = pool_elt_at_index (mm->ip4_reass_pool, ri);
1296       if (r->key.as_u64[0] == k->as_u64[0] &&
1297           r->key.as_u64[1] == k->as_u64[1] &&
1298           now < r->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000))
1299         {
1300           return r;
1301         }
1302       ri = r->bucket_next;
1303     }
1304   return NULL;
1305 }
1306
1307 #define map_ip4_reass_pool_index(r) (r - map_main.ip4_reass_pool)
1308
1309 void
1310 map_ip4_reass_free (map_ip4_reass_t * r, u32 ** pi_to_drop)
1311 {
1312   map_main_t *mm = &map_main;
1313   map_ip4_reass_get_fragments (r, pi_to_drop);
1314
1315   // Unlink in hash bucket
1316   map_ip4_reass_t *r2 = NULL;
1317   u32 r2i = mm->ip4_reass_hash_table[r->bucket];
1318   while (r2i != map_ip4_reass_pool_index (r))
1319     {
1320       ASSERT (r2i != MAP_REASS_INDEX_NONE);
1321       r2 = pool_elt_at_index (mm->ip4_reass_pool, r2i);
1322       r2i = r2->bucket_next;
1323     }
1324   if (r2)
1325     {
1326       r2->bucket_next = r->bucket_next;
1327     }
1328   else
1329     {
1330       mm->ip4_reass_hash_table[r->bucket] = r->bucket_next;
1331     }
1332
1333   // Unlink in list
1334   if (r->fifo_next == map_ip4_reass_pool_index (r))
1335     {
1336       mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
1337     }
1338   else
1339     {
1340       if (mm->ip4_reass_fifo_last == map_ip4_reass_pool_index (r))
1341         mm->ip4_reass_fifo_last = r->fifo_prev;
1342       pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next =
1343         r->fifo_next;
1344       pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev =
1345         r->fifo_prev;
1346     }
1347
1348   pool_put (mm->ip4_reass_pool, r);
1349   mm->ip4_reass_allocated--;
1350 }
1351
1352 map_ip4_reass_t *
1353 map_ip4_reass_get (u32 src, u32 dst, u16 fragment_id,
1354                    u8 protocol, u32 ** pi_to_drop)
1355 {
1356   map_ip4_reass_t *r;
1357   map_main_t *mm = &map_main;
1358   map_ip4_reass_key_t k = {.src.data_u32 = src,
1359     .dst.data_u32 = dst,
1360     .fragment_id = fragment_id,
1361     .protocol = protocol
1362   };
1363
1364   u32 h = 0;
1365   h = crc_u32 (k.as_u32[0], h);
1366   h = crc_u32 (k.as_u32[1], h);
1367   h = crc_u32 (k.as_u32[2], h);
1368   h = crc_u32 (k.as_u32[3], h);
1369   h = h >> (32 - mm->ip4_reass_ht_log2len);
1370
1371   f64 now = vlib_time_now (mm->vlib_main);
1372
1373   //Cache garbage collection
1374   while (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
1375     {
1376       map_ip4_reass_t *last =
1377         pool_elt_at_index (mm->ip4_reass_pool, mm->ip4_reass_fifo_last);
1378       if (last->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000) < now)
1379         map_ip4_reass_free (last, pi_to_drop);
1380       else
1381         break;
1382     }
1383
1384   if ((r = map_ip4_reass_lookup (&k, h, now)))
1385     return r;
1386
1387   if (mm->ip4_reass_allocated >= mm->ip4_reass_conf_pool_size)
1388     return NULL;
1389
1390   pool_get (mm->ip4_reass_pool, r);
1391   mm->ip4_reass_allocated++;
1392   int i;
1393   for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1394     r->fragments[i] = ~0;
1395
1396   u32 ri = map_ip4_reass_pool_index (r);
1397
1398   //Link in new bucket
1399   r->bucket = h;
1400   r->bucket_next = mm->ip4_reass_hash_table[h];
1401   mm->ip4_reass_hash_table[h] = ri;
1402
1403   //Link in fifo
1404   if (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
1405     {
1406       r->fifo_next =
1407         pool_elt_at_index (mm->ip4_reass_pool,
1408                            mm->ip4_reass_fifo_last)->fifo_next;
1409       r->fifo_prev = mm->ip4_reass_fifo_last;
1410       pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next = ri;
1411       pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev = ri;
1412     }
1413   else
1414     {
1415       r->fifo_next = r->fifo_prev = ri;
1416       mm->ip4_reass_fifo_last = ri;
1417     }
1418
1419   //Set other fields
1420   r->ts = now;
1421   r->key = k;
1422   r->port = -1;
1423 #ifdef MAP_IP4_REASS_COUNT_BYTES
1424   r->expected_total = 0xffff;
1425   r->forwarded = 0;
1426 #endif
1427
1428   return r;
1429 }
1430
1431 int
1432 map_ip4_reass_add_fragment (map_ip4_reass_t * r, u32 pi)
1433 {
1434   if (map_main.ip4_reass_buffered_counter >= map_main.ip4_reass_conf_buffers)
1435     return -1;
1436
1437   int i;
1438   for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1439     if (r->fragments[i] == ~0)
1440       {
1441         r->fragments[i] = pi;
1442         map_main.ip4_reass_buffered_counter++;
1443         return 0;
1444       }
1445   return -1;
1446 }
1447
1448 static_always_inline map_ip6_reass_t *
1449 map_ip6_reass_lookup (map_ip6_reass_key_t * k, u32 bucket, f64 now)
1450 {
1451   map_main_t *mm = &map_main;
1452   u32 ri = mm->ip6_reass_hash_table[bucket];
1453   while (ri != MAP_REASS_INDEX_NONE)
1454     {
1455       map_ip6_reass_t *r = pool_elt_at_index (mm->ip6_reass_pool, ri);
1456       if (now < r->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) &&
1457           r->key.as_u64[0] == k->as_u64[0] &&
1458           r->key.as_u64[1] == k->as_u64[1] &&
1459           r->key.as_u64[2] == k->as_u64[2] &&
1460           r->key.as_u64[3] == k->as_u64[3] &&
1461           r->key.as_u64[4] == k->as_u64[4])
1462         return r;
1463       ri = r->bucket_next;
1464     }
1465   return NULL;
1466 }
1467
1468 #define map_ip6_reass_pool_index(r) (r - map_main.ip6_reass_pool)
1469
1470 void
1471 map_ip6_reass_free (map_ip6_reass_t * r, u32 ** pi_to_drop)
1472 {
1473   map_main_t *mm = &map_main;
1474   int i;
1475   for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1476     if (r->fragments[i].pi != ~0)
1477       {
1478         vec_add1 (*pi_to_drop, r->fragments[i].pi);
1479         r->fragments[i].pi = ~0;
1480         map_main.ip6_reass_buffered_counter--;
1481       }
1482
1483   // Unlink in hash bucket
1484   map_ip6_reass_t *r2 = NULL;
1485   u32 r2i = mm->ip6_reass_hash_table[r->bucket];
1486   while (r2i != map_ip6_reass_pool_index (r))
1487     {
1488       ASSERT (r2i != MAP_REASS_INDEX_NONE);
1489       r2 = pool_elt_at_index (mm->ip6_reass_pool, r2i);
1490       r2i = r2->bucket_next;
1491     }
1492   if (r2)
1493     {
1494       r2->bucket_next = r->bucket_next;
1495     }
1496   else
1497     {
1498       mm->ip6_reass_hash_table[r->bucket] = r->bucket_next;
1499     }
1500
1501   // Unlink in list
1502   if (r->fifo_next == map_ip6_reass_pool_index (r))
1503     {
1504       //Single element in the list, list is now empty
1505       mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
1506     }
1507   else
1508     {
1509       if (mm->ip6_reass_fifo_last == map_ip6_reass_pool_index (r))      //First element
1510         mm->ip6_reass_fifo_last = r->fifo_prev;
1511       pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next =
1512         r->fifo_next;
1513       pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev =
1514         r->fifo_prev;
1515     }
1516
1517   // Free from pool if necessary
1518   pool_put (mm->ip6_reass_pool, r);
1519   mm->ip6_reass_allocated--;
1520 }
1521
1522 map_ip6_reass_t *
1523 map_ip6_reass_get (ip6_address_t * src, ip6_address_t * dst, u32 fragment_id,
1524                    u8 protocol, u32 ** pi_to_drop)
1525 {
1526   map_ip6_reass_t *r;
1527   map_main_t *mm = &map_main;
1528   map_ip6_reass_key_t k = {
1529     .src = *src,
1530     .dst = *dst,
1531     .fragment_id = fragment_id,
1532     .protocol = protocol
1533   };
1534
1535   u32 h = 0;
1536   int i;
1537   for (i = 0; i < 10; i++)
1538     h = crc_u32 (k.as_u32[i], h);
1539   h = h >> (32 - mm->ip6_reass_ht_log2len);
1540
1541   f64 now = vlib_time_now (mm->vlib_main);
1542
1543   //Cache garbage collection
1544   while (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
1545     {
1546       map_ip6_reass_t *last =
1547         pool_elt_at_index (mm->ip6_reass_pool, mm->ip6_reass_fifo_last);
1548       if (last->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) < now)
1549         map_ip6_reass_free (last, pi_to_drop);
1550       else
1551         break;
1552     }
1553
1554   if ((r = map_ip6_reass_lookup (&k, h, now)))
1555     return r;
1556
1557   if (mm->ip6_reass_allocated >= mm->ip6_reass_conf_pool_size)
1558     return NULL;
1559
1560   pool_get (mm->ip6_reass_pool, r);
1561   mm->ip6_reass_allocated++;
1562   for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1563     {
1564       r->fragments[i].pi = ~0;
1565       r->fragments[i].next_data_len = 0;
1566       r->fragments[i].next_data_offset = 0;
1567     }
1568
1569   u32 ri = map_ip6_reass_pool_index (r);
1570
1571   //Link in new bucket
1572   r->bucket = h;
1573   r->bucket_next = mm->ip6_reass_hash_table[h];
1574   mm->ip6_reass_hash_table[h] = ri;
1575
1576   //Link in fifo
1577   if (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
1578     {
1579       r->fifo_next =
1580         pool_elt_at_index (mm->ip6_reass_pool,
1581                            mm->ip6_reass_fifo_last)->fifo_next;
1582       r->fifo_prev = mm->ip6_reass_fifo_last;
1583       pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next = ri;
1584       pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev = ri;
1585     }
1586   else
1587     {
1588       r->fifo_next = r->fifo_prev = ri;
1589       mm->ip6_reass_fifo_last = ri;
1590     }
1591
1592   //Set other fields
1593   r->ts = now;
1594   r->key = k;
1595   r->ip4_header.ip_version_and_header_length = 0;
1596 #ifdef MAP_IP6_REASS_COUNT_BYTES
1597   r->expected_total = 0xffff;
1598   r->forwarded = 0;
1599 #endif
1600   return r;
1601 }
1602
1603 int
1604 map_ip6_reass_add_fragment (map_ip6_reass_t * r, u32 pi,
1605                             u16 data_offset, u16 next_data_offset,
1606                             u8 * data_start, u16 data_len)
1607 {
1608   map_ip6_fragment_t *f = NULL, *prev_f = NULL;
1609   u16 copied_len = (data_len > 20) ? 20 : data_len;
1610
1611   if (map_main.ip6_reass_buffered_counter >= map_main.ip6_reass_conf_buffers)
1612     return -1;
1613
1614   //Lookup for fragments for the current buffer
1615   //and the one before that
1616   int i;
1617   for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1618     {
1619       if (data_offset && r->fragments[i].next_data_offset == data_offset)
1620         {
1621           prev_f = &r->fragments[i];    // This is buffer for previous packet
1622         }
1623       else if (r->fragments[i].next_data_offset == next_data_offset)
1624         {
1625           f = &r->fragments[i]; // This is a buffer for the current packet
1626         }
1627       else if (r->fragments[i].next_data_offset == 0)
1628         {                       //Available
1629           if (f == NULL)
1630             f = &r->fragments[i];
1631           else if (prev_f == NULL)
1632             prev_f = &r->fragments[i];
1633         }
1634     }
1635
1636   if (!f || f->pi != ~0)
1637     return -1;
1638
1639   if (data_offset)
1640     {
1641       if (!prev_f)
1642         return -1;
1643
1644       clib_memcpy (prev_f->next_data, data_start, copied_len);
1645       prev_f->next_data_len = copied_len;
1646       prev_f->next_data_offset = data_offset;
1647     }
1648   else
1649     {
1650       if (((ip4_header_t *) data_start)->ip_version_and_header_length != 0x45)
1651         return -1;
1652
1653       if (r->ip4_header.ip_version_and_header_length == 0)
1654         clib_memcpy (&r->ip4_header, data_start, sizeof (ip4_header_t));
1655     }
1656
1657   if (data_len > 20)
1658     {
1659       f->next_data_offset = next_data_offset;
1660       f->pi = pi;
1661       map_main.ip6_reass_buffered_counter++;
1662     }
1663   return 0;
1664 }
1665
1666 void
1667 map_ip4_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1668 {
1669   map_main_t *mm = &map_main;
1670   int i;
1671
1672   if (dropped_packets)
1673     *dropped_packets = mm->ip4_reass_buffered_counter;
1674   if (trashed_reass)
1675     *trashed_reass = mm->ip4_reass_allocated;
1676   if (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
1677     {
1678       u16 ri = mm->ip4_reass_fifo_last;
1679       do
1680         {
1681           map_ip4_reass_t *r = pool_elt_at_index (mm->ip4_reass_pool, ri);
1682           for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1683             if (r->fragments[i] != ~0)
1684               map_ip4_drop_pi (r->fragments[i]);
1685
1686           ri = r->fifo_next;
1687           pool_put (mm->ip4_reass_pool, r);
1688         }
1689       while (ri != mm->ip4_reass_fifo_last);
1690     }
1691
1692   vec_free (mm->ip4_reass_hash_table);
1693   vec_resize (mm->ip4_reass_hash_table, 1 << mm->ip4_reass_ht_log2len);
1694   for (i = 0; i < (1 << mm->ip4_reass_ht_log2len); i++)
1695     mm->ip4_reass_hash_table[i] = MAP_REASS_INDEX_NONE;
1696   pool_free (mm->ip4_reass_pool);
1697   pool_alloc (mm->ip4_reass_pool, mm->ip4_reass_conf_pool_size);
1698
1699   mm->ip4_reass_allocated = 0;
1700   mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
1701   mm->ip4_reass_buffered_counter = 0;
1702 }
1703
1704 u8
1705 map_get_ht_log2len (f32 ht_ratio, u16 pool_size)
1706 {
1707   u32 desired_size = (u32) (pool_size * ht_ratio);
1708   u8 i;
1709   for (i = 1; i < 31; i++)
1710     if ((1 << i) >= desired_size)
1711       return i;
1712   return 4;
1713 }
1714
1715 int
1716 map_ip4_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1717                              u32 * dropped_packets)
1718 {
1719   map_main_t *mm = &map_main;
1720   if (ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1721     return -1;
1722
1723   map_ip4_reass_lock ();
1724   mm->ip4_reass_conf_ht_ratio = ht_ratio;
1725   mm->ip4_reass_ht_log2len =
1726     map_get_ht_log2len (ht_ratio, mm->ip4_reass_conf_pool_size);
1727   map_ip4_reass_reinit (trashed_reass, dropped_packets);
1728   map_ip4_reass_unlock ();
1729   return 0;
1730 }
1731
1732 int
1733 map_ip4_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1734                               u32 * dropped_packets)
1735 {
1736   map_main_t *mm = &map_main;
1737   if (pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1738     return -1;
1739
1740   map_ip4_reass_lock ();
1741   mm->ip4_reass_conf_pool_size = pool_size;
1742   map_ip4_reass_reinit (trashed_reass, dropped_packets);
1743   map_ip4_reass_unlock ();
1744   return 0;
1745 }
1746
1747 int
1748 map_ip4_reass_conf_lifetime (u16 lifetime_ms)
1749 {
1750   map_main.ip4_reass_conf_lifetime_ms = lifetime_ms;
1751   return 0;
1752 }
1753
1754 int
1755 map_ip4_reass_conf_buffers (u32 buffers)
1756 {
1757   map_main.ip4_reass_conf_buffers = buffers;
1758   return 0;
1759 }
1760
1761 void
1762 map_ip6_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1763 {
1764   map_main_t *mm = &map_main;
1765   if (dropped_packets)
1766     *dropped_packets = mm->ip6_reass_buffered_counter;
1767   if (trashed_reass)
1768     *trashed_reass = mm->ip6_reass_allocated;
1769   int i;
1770   if (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
1771     {
1772       u16 ri = mm->ip6_reass_fifo_last;
1773       do
1774         {
1775           map_ip6_reass_t *r = pool_elt_at_index (mm->ip6_reass_pool, ri);
1776           for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1777             if (r->fragments[i].pi != ~0)
1778               map_ip6_drop_pi (r->fragments[i].pi);
1779
1780           ri = r->fifo_next;
1781           pool_put (mm->ip6_reass_pool, r);
1782         }
1783       while (ri != mm->ip6_reass_fifo_last);
1784       mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
1785     }
1786
1787   vec_free (mm->ip6_reass_hash_table);
1788   vec_resize (mm->ip6_reass_hash_table, 1 << mm->ip6_reass_ht_log2len);
1789   for (i = 0; i < (1 << mm->ip6_reass_ht_log2len); i++)
1790     mm->ip6_reass_hash_table[i] = MAP_REASS_INDEX_NONE;
1791   pool_free (mm->ip6_reass_pool);
1792   pool_alloc (mm->ip6_reass_pool, mm->ip4_reass_conf_pool_size);
1793
1794   mm->ip6_reass_allocated = 0;
1795   mm->ip6_reass_buffered_counter = 0;
1796 }
1797
1798 int
1799 map_ip6_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1800                              u32 * dropped_packets)
1801 {
1802   map_main_t *mm = &map_main;
1803   if (ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1804     return -1;
1805
1806   map_ip6_reass_lock ();
1807   mm->ip6_reass_conf_ht_ratio = ht_ratio;
1808   mm->ip6_reass_ht_log2len =
1809     map_get_ht_log2len (ht_ratio, mm->ip6_reass_conf_pool_size);
1810   map_ip6_reass_reinit (trashed_reass, dropped_packets);
1811   map_ip6_reass_unlock ();
1812   return 0;
1813 }
1814
1815 int
1816 map_ip6_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1817                               u32 * dropped_packets)
1818 {
1819   map_main_t *mm = &map_main;
1820   if (pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1821     return -1;
1822
1823   map_ip6_reass_lock ();
1824   mm->ip6_reass_conf_pool_size = pool_size;
1825   map_ip6_reass_reinit (trashed_reass, dropped_packets);
1826   map_ip6_reass_unlock ();
1827   return 0;
1828 }
1829
1830 int
1831 map_ip6_reass_conf_lifetime (u16 lifetime_ms)
1832 {
1833   map_main.ip6_reass_conf_lifetime_ms = lifetime_ms;
1834   return 0;
1835 }
1836
1837 int
1838 map_ip6_reass_conf_buffers (u32 buffers)
1839 {
1840   map_main.ip6_reass_conf_buffers = buffers;
1841   return 0;
1842 }
1843
1844 /* *INDENT-OFF* */
1845 VLIB_CLI_COMMAND(map_ip4_reass_lifetime_command, static) = {
1846   .path = "map params reassembly",
1847   .short_help = "[ip4 | ip6] [lifetime <lifetime-ms>] [pool-size <pool-size>] [buffers <buffers>] [ht-ratio <ht-ratio>]",
1848   .function = map_params_reass_command_fn,
1849 };
1850 /* *INDENT-ON* */
1851
1852 /* *INDENT-OFF* */
1853 VLIB_CLI_COMMAND(map_traffic_class_command, static) = {
1854   .path = "map params traffic-class",
1855   .short_help = 
1856   "traffic-class {0x0-0xff | copy}",
1857   .function = map_traffic_class_command_fn,
1858 };
1859 /* *INDENT-ON* */
1860
1861 /* *INDENT-OFF* */
1862 VLIB_CLI_COMMAND(map_pre_resolve_command, static) = {
1863   .path = "map params pre-resolve",
1864   .short_help = 
1865   "pre-resolve {ip4-nh <address>} | {ip6-nh <address>}",
1866   .function = map_pre_resolve_command_fn,
1867 };
1868 /* *INDENT-ON* */
1869
1870 /* *INDENT-OFF* */
1871 VLIB_CLI_COMMAND(map_security_check_command, static) = {
1872   .path = "map params security-check",
1873   .short_help = 
1874   "security-check on|off",
1875   .function = map_security_check_command_fn,
1876 };
1877 /* *INDENT-ON* */
1878
1879 /* *INDENT-OFF* */
1880 VLIB_CLI_COMMAND(map_icmp_relay_source_address_command, static) = {
1881   .path = "map params icmp source-address",
1882    .short_help = "source-address <ip4-address>",
1883   .function = map_icmp_relay_source_address_command_fn,
1884 };
1885 /* *INDENT-ON* */
1886
1887 /* *INDENT-OFF* */
1888 VLIB_CLI_COMMAND(map_icmp_unreachables_command, static) = {
1889   .path = "map params icmp6 unreachables",
1890   .short_help = "unreachables {on|off}",
1891   .function = map_icmp_unreachables_command_fn,
1892 };
1893 /* *INDENT-ON* */
1894
1895 /* *INDENT-OFF* */
1896 VLIB_CLI_COMMAND(map_fragment_command, static) = {
1897   .path = "map params fragment",
1898   .short_help = "[inner|outer] [ignore-df [on|off]]",
1899   .function = map_fragment_command_fn,
1900 };
1901 /* *INDENT-ON* */
1902
1903 /* *INDENT-OFF* */
1904 VLIB_CLI_COMMAND(map_fragment_df_command, static) = {
1905   .path = "map params fragment ignore-df",
1906   .short_help = "on|off",
1907   .function = map_fragment_df_command_fn,
1908 };
1909 /* *INDENT-ON* */
1910
1911 /* *INDENT-OFF* */
1912 VLIB_CLI_COMMAND(map_security_check_frag_command, static) = {
1913   .path = "map params security-check fragments",
1914   .short_help = 
1915   "fragments on|off",
1916   .function = map_security_check_frag_command_fn,
1917 };
1918 /* *INDENT-ON* */
1919
1920 /* *INDENT-OFF* */
1921 VLIB_CLI_COMMAND(map_add_domain_command, static) = {
1922   .path = "map add domain",
1923   .short_help = 
1924   "map add domain ip4-pfx <ip4-pfx> ip6-pfx <ip6-pfx> ip6-src <ip6-pfx> "
1925       "ea-bits-len <n> psid-offset <n> psid-len <n> [map-t] [mtu <mtu>]",
1926   .function = map_add_domain_command_fn,
1927 };
1928 /* *INDENT-ON* */
1929
1930 /* *INDENT-OFF* */
1931 VLIB_CLI_COMMAND(map_add_rule_command, static) = {
1932   .path = "map add rule",
1933   .short_help = 
1934   "map add rule index <domain> psid <psid> ip6-dst <ip6-addr>",
1935   .function = map_add_rule_command_fn,
1936 };
1937 /* *INDENT-ON* */
1938
1939 /* *INDENT-OFF* */
1940 VLIB_CLI_COMMAND(map_del_command, static) = {
1941   .path = "map del domain",
1942   .short_help = 
1943   "map del domain index <domain>",
1944   .function = map_del_domain_command_fn,
1945 };
1946 /* *INDENT-ON* */
1947
1948 /* *INDENT-OFF* */
1949 VLIB_CLI_COMMAND(show_map_domain_command, static) = {
1950   .path = "show map domain",
1951   .function = show_map_domain_command_fn,
1952 };
1953 /* *INDENT-ON* */
1954
1955 /* *INDENT-OFF* */
1956 VLIB_CLI_COMMAND(show_map_stats_command, static) = {
1957   .path = "show map stats",
1958   .function = show_map_stats_command_fn,
1959 };
1960 /* *INDENT-ON* */
1961
1962 /* *INDENT-OFF* */
1963 VLIB_CLI_COMMAND(show_map_fragments_command, static) = {
1964   .path = "show map fragments",
1965   .function = show_map_fragments_command_fn,
1966 };
1967 /* *INDENT-ON* */
1968
1969 /*
1970  * map_init
1971  */
1972 clib_error_t *
1973 map_init (vlib_main_t * vm)
1974 {
1975   map_main_t *mm = &map_main;
1976   mm->vnet_main = vnet_get_main ();
1977   mm->vlib_main = vm;
1978
1979 #ifdef MAP_SKIP_IP6_LOOKUP
1980   memset (&mm->preresolve_ip4, 0, sizeof (mm->preresolve_ip4));
1981   memset (&mm->preresolve_ip6, 0, sizeof (mm->preresolve_ip6));
1982   mm->adj4_index = 0;
1983   mm->adj6_index = 0;
1984 #endif
1985
1986   /* traffic class */
1987   mm->tc = 0;
1988   mm->tc_copy = true;
1989
1990   /* Inbound security check */
1991   mm->sec_check = true;
1992   mm->sec_check_frag = false;
1993
1994   /* ICMP6 Type 1, Code 5 for security check failure */
1995   mm->icmp6_enabled = false;
1996
1997   /* Inner or outer fragmentation */
1998   mm->frag_inner = false;
1999   mm->frag_ignore_df = false;
2000
2001   vec_validate (mm->domain_counters, MAP_N_DOMAIN_COUNTER - 1);
2002   mm->domain_counters[MAP_DOMAIN_COUNTER_RX].name = "rx";
2003   mm->domain_counters[MAP_DOMAIN_COUNTER_TX].name = "tx";
2004
2005   vlib_validate_simple_counter (&mm->icmp_relayed, 0);
2006   vlib_zero_simple_counter (&mm->icmp_relayed, 0);
2007
2008   /* IP4 virtual reassembly */
2009   mm->ip4_reass_hash_table = 0;
2010   mm->ip4_reass_pool = 0;
2011   mm->ip4_reass_lock =
2012     clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
2013   mm->ip4_reass_conf_ht_ratio = MAP_IP4_REASS_HT_RATIO_DEFAULT;
2014   mm->ip4_reass_conf_lifetime_ms = MAP_IP4_REASS_LIFETIME_DEFAULT;
2015   mm->ip4_reass_conf_pool_size = MAP_IP4_REASS_POOL_SIZE_DEFAULT;
2016   mm->ip4_reass_conf_buffers = MAP_IP4_REASS_BUFFERS_DEFAULT;
2017   mm->ip4_reass_ht_log2len =
2018     map_get_ht_log2len (mm->ip4_reass_conf_ht_ratio,
2019                         mm->ip4_reass_conf_pool_size);
2020   mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
2021   map_ip4_reass_reinit (NULL, NULL);
2022
2023   /* IP6 virtual reassembly */
2024   mm->ip6_reass_hash_table = 0;
2025   mm->ip6_reass_pool = 0;
2026   mm->ip6_reass_lock =
2027     clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
2028   mm->ip6_reass_conf_ht_ratio = MAP_IP6_REASS_HT_RATIO_DEFAULT;
2029   mm->ip6_reass_conf_lifetime_ms = MAP_IP6_REASS_LIFETIME_DEFAULT;
2030   mm->ip6_reass_conf_pool_size = MAP_IP6_REASS_POOL_SIZE_DEFAULT;
2031   mm->ip6_reass_conf_buffers = MAP_IP6_REASS_BUFFERS_DEFAULT;
2032   mm->ip6_reass_ht_log2len =
2033     map_get_ht_log2len (mm->ip6_reass_conf_ht_ratio,
2034                         mm->ip6_reass_conf_pool_size);
2035   mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
2036   map_ip6_reass_reinit (NULL, NULL);
2037
2038   return 0;
2039 }
2040
2041 VLIB_INIT_FUNCTION (map_init);
2042
2043 /*
2044  * fd.io coding-style-patch-verification: ON
2045  *
2046  * Local Variables:
2047  * eval: (c-set-style "gnu")
2048  * End:
2049  */