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