1/*
2 * map.c : MAP support
3 *
4 * Copyright (c) 2015 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <vnet/fib/fib_table.h>
19#include <vnet/fib/fib_entry_track.h>
20#include <vnet/fib/ip6_fib.h>
21#include <vnet/adj/adj.h>
22#include <vppinfra/crc32.h>
23#include <vnet/plugin/plugin.h>
24#include <vpp/app/version.h>
25#include "map.h"
26
27map_main_t map_main;
28
29/*
30 * This code supports the following MAP modes:
31 *
32 * Algorithmic Shared IPv4 address (ea_bits_len > 0):
33 *   ea_bits_len + ip4_prefix > 32
34 *   psid_length > 0, ip6_prefix < 64, ip4_prefix <= 32
35 * Algorithmic Full IPv4 address (ea_bits_len > 0):
36 *   ea_bits_len + ip4_prefix = 32
37 *   psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
38 * Algorithmic IPv4 prefix (ea_bits_len > 0):
39 *   ea_bits_len + ip4_prefix < 32
40 *   psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
41 *
42 * Independent Shared IPv4 address (ea_bits_len = 0):
43 *   ip4_prefix = 32
44 *   psid_length > 0
45 *   Rule IPv6 address = 128, Rule PSID Set
46 * Independent Full IPv4 address (ea_bits_len = 0):
47 *   ip4_prefix = 32
48 *   psid_length = 0, ip6_prefix = 128
49 * Independent IPv4 prefix (ea_bits_len = 0):
50 *   ip4_prefix < 32
51 *   psid_length = 0, ip6_prefix = 128
52 *
53 */
54
55/*
56 * This code supports MAP-T:
57 *
58 * With a DMR prefix length of 64 or 96 (RFC6052).
59 *
60 */
61
62
63/*
64 * Save user-assigned MAP domain names ("tags") in a vector of
65 * extra domain information.
66 */
67static void
68map_save_extras (u32 map_domain_index, u8 * tag)
69{
70  map_main_t *mm = &map_main;
71  map_domain_extra_t *de;
72
73  if (map_domain_index == ~0)
74    return;
75
76  vec_validate (mm->domain_extras, map_domain_index);
77  de = vec_elt_at_index (mm->domain_extras, map_domain_index);
78  clib_memset (de, 0, sizeof (*de));
79
80  if (!tag)
81    return;
82
83  vec_validate_init_c_string (de->tag, tag, strlen ((char *) tag));
84}
85
86
87static void
88map_free_extras (u32 map_domain_index)
89{
90  map_main_t *mm = &map_main;
91  map_domain_extra_t *de;
92
93  if (map_domain_index == ~0)
94    return;
95
96  if (map_domain_index >= vec_len (mm->domain_extras))
97    return;
98
99  de = vec_elt_at_index (mm->domain_extras, map_domain_index);
100  vec_free (de->tag);
101}
102
103
104int
105map_create_domain (ip4_address_t * ip4_prefix,
106		   u8 ip4_prefix_len,
107		   ip6_address_t * ip6_prefix,
108		   u8 ip6_prefix_len,
109		   ip6_address_t * ip6_src,
110		   u8 ip6_src_len,
111		   u8 ea_bits_len,
112		   u8 psid_offset,
113		   u8 psid_length,
114		   u32 * map_domain_index, u16 mtu, u8 flags, u8 * tag)
115{
116  u8 suffix_len, suffix_shift;
117  map_main_t *mm = &map_main;
118  map_domain_t *d;
119
120  /* How many, and which bits to grab from the IPv4 DA */
121  if (ip4_prefix_len + ea_bits_len < 32)
122    {
123      flags |= MAP_DOMAIN_PREFIX;
124      suffix_shift = 32 - ip4_prefix_len - ea_bits_len;
125      suffix_len = ea_bits_len;
126    }
127  else
128    {
129      suffix_shift = 0;
130      suffix_len = 32 - ip4_prefix_len;
131    }
132
133  /* EA bits must be within the first 64 bits */
134  if (ea_bits_len > 0 && ((ip6_prefix_len + ea_bits_len) > 64 ||
135			  ip6_prefix_len + suffix_len + psid_length > 64))
136    {
137      clib_warning
138	("Embedded Address bits must be within the first 64 bits of "
139	 "the IPv6 prefix");
140      return -1;
141    }
142
143  /* Get domain index */
144  pool_get_aligned (mm->domains, d, CLIB_CACHE_LINE_BYTES);
145  clib_memset (d, 0, sizeof (*d));
146  *map_domain_index = d - mm->domains;
147
148  /* Init domain struct */
149  d->ip4_prefix.as_u32 = ip4_prefix->as_u32;
150  d->ip4_prefix_len = ip4_prefix_len;
151  d->ip6_prefix = *ip6_prefix;
152  d->ip6_prefix_len = ip6_prefix_len;
153  d->ip6_src = *ip6_src;
154  d->ip6_src_len = ip6_src_len;
155  d->ea_bits_len = ea_bits_len;
156  d->psid_offset = psid_offset;
157  d->psid_length = psid_length;
158  d->mtu = mtu;
159  d->flags = flags;
160  d->suffix_shift = suffix_shift;
161  d->suffix_mask = (1 << suffix_len) - 1;
162
163  d->psid_shift = 16 - psid_length - psid_offset;
164  d->psid_mask = (1 << d->psid_length) - 1;
165  d->ea_shift = 64 - ip6_prefix_len - suffix_len - d->psid_length;
166
167  /* Save a user-assigned MAP domain name if provided. */
168  if (tag)
169    map_save_extras (*map_domain_index, tag);
170
171  /* MAP longest match lookup table (input feature / FIB) */
172  mm->ip4_prefix_tbl->add (mm->ip4_prefix_tbl, &d->ip4_prefix,
173			   d->ip4_prefix_len, *map_domain_index);
174
175  /* Really needed? Or always use FIB? */
176  mm->ip6_src_prefix_tbl->add (mm->ip6_src_prefix_tbl, &d->ip6_src,
177			       d->ip6_src_len, *map_domain_index);
178
179  /* Validate packet/byte counters */
180  map_domain_counter_lock (mm);
181  int i;
182  for (i = 0; i < vec_len (mm->simple_domain_counters); i++)
183    {
184      vlib_validate_simple_counter (&mm->simple_domain_counters[i],
185				    *map_domain_index);
186      vlib_zero_simple_counter (&mm->simple_domain_counters[i],
187				*map_domain_index);
188    }
189  for (i = 0; i < vec_len (mm->domain_counters); i++)
190    {
191      vlib_validate_combined_counter (&mm->domain_counters[i],
192				      *map_domain_index);
193      vlib_zero_combined_counter (&mm->domain_counters[i], *map_domain_index);
194    }
195  map_domain_counter_unlock (mm);
196
197  return 0;
198}
199
200/*
201 * map_delete_domain
202 */
203int
204map_delete_domain (u32 map_domain_index)
205{
206  map_main_t *mm = &map_main;
207  map_domain_t *d;
208
209  if (pool_is_free_index (mm->domains, map_domain_index))
210    {
211      clib_warning ("MAP domain delete: domain does not exist: %d",
212		    map_domain_index);
213      return -1;
214    }
215
216  d = pool_elt_at_index (mm->domains, map_domain_index);
217  mm->ip4_prefix_tbl->delete (mm->ip4_prefix_tbl, &d->ip4_prefix,
218			      d->ip4_prefix_len);
219  mm->ip6_src_prefix_tbl->delete (mm->ip6_src_prefix_tbl, &d->ip6_src,
220				  d->ip6_src_len);
221
222  /* Release user-assigned MAP domain name. */
223  map_free_extras (map_domain_index);
224
225  /* Deleting rules */
226  if (d->rules)
227    clib_mem_free (d->rules);
228
229  pool_put (mm->domains, d);
230
231  return 0;
232}
233
234int
235map_add_del_psid (u32 map_domain_index, u16 psid, ip6_address_t * tep,
236		  bool is_add)
237{
238  map_domain_t *d;
239  map_main_t *mm = &map_main;
240
241  if (pool_is_free_index (mm->domains, map_domain_index))
242    {
243      clib_warning ("MAP rule: domain does not exist: %d", map_domain_index);
244      return -1;
245    }
246  d = pool_elt_at_index (mm->domains, map_domain_index);
247
248  /* Rules are only used in 1:1 independent case */
249  if (d->ea_bits_len > 0)
250    return (-1);
251
252  if (!d->rules)
253    {
254      u32 l = (0x1 << d->psid_length) * sizeof (ip6_address_t);
255      d->rules = clib_mem_alloc_aligned (l, CLIB_CACHE_LINE_BYTES);
256      if (!d->rules)
257	return -1;
258      clib_memset (d->rules, 0, l);
259    }
260
261  if (psid >= (0x1 << d->psid_length))
262    {
263      clib_warning ("MAP rule: PSID outside bounds: %d [%d]", psid,
264		    0x1 << d->psid_length);
265      return -1;
266    }
267
268  if (is_add)
269    {
270      d->rules[psid] = *tep;
271    }
272  else
273    {
274      clib_memset (&d->rules[psid], 0, sizeof (ip6_address_t));
275    }
276  return 0;
277}
278
279#ifdef MAP_SKIP_IP6_LOOKUP
280/**
281 * Pre-resolved per-protocol global next-hops
282 */
283map_main_pre_resolved_t pre_resolved[FIB_PROTOCOL_MAX];
284
285static void
286map_pre_resolve_init (map_main_pre_resolved_t * pr)
287{
288  pr->fei = FIB_NODE_INDEX_INVALID;
289  fib_node_init (&pr->node, FIB_NODE_TYPE_MAP_E);
290}
291
292static u8 *
293format_map_pre_resolve (u8 * s, va_list * ap)
294{
295  map_main_pre_resolved_t *pr = va_arg (*ap, map_main_pre_resolved_t *);
296
297  if (FIB_NODE_INDEX_INVALID != pr->fei)
298    {
299      const fib_prefix_t *pfx;
300
301      pfx = fib_entry_get_prefix (pr->fei);
302
303      return (format (s, "%U (%u)",
304		      format_ip46_address, &pfx->fp_addr, IP46_TYPE_ANY,
305		      pr->dpo.dpoi_index));
306    }
307  else
308    {
309      return (format (s, "un-set"));
310    }
311}
312
313
314/**
315 * Function definition to inform the FIB node that its last lock has gone.
316 */
317static void
318map_last_lock_gone (fib_node_t * node)
319{
320  /*
321   * The MAP is a root of the graph. As such
322   * it never has children and thus is never locked.
323   */
324  ASSERT (0);
325}
326
327static map_main_pre_resolved_t *
328map_from_fib_node (fib_node_t * node)
329{
330  ASSERT (FIB_NODE_TYPE_MAP_E == node->fn_type);
331  return ((map_main_pre_resolved_t *)
332	  (((char *) node) -
333	   STRUCT_OFFSET_OF (map_main_pre_resolved_t, node)));
334}
335
336static void
337map_stack (map_main_pre_resolved_t * pr)
338{
339  const dpo_id_t *dpo;
340
341  dpo = fib_entry_contribute_ip_forwarding (pr->fei);
342
343  dpo_copy (&pr->dpo, dpo);
344}
345
346/**
347 * Function definition to backwalk a FIB node
348 */
349static fib_node_back_walk_rc_t
350map_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
351{
352  map_stack (map_from_fib_node (node));
353
354  return (FIB_NODE_BACK_WALK_CONTINUE);
355}
356
357/**
358 * Function definition to get a FIB node from its index
359 */
360static fib_node_t *
361map_fib_node_get (fib_node_index_t index)
362{
363  return (&pre_resolved[index].node);
364}
365
366/*
367 * Virtual function table registered by MPLS GRE tunnels
368 * for participation in the FIB object graph.
369 */
370const static fib_node_vft_t map_vft = {
371  .fnv_get = map_fib_node_get,
372  .fnv_last_lock = map_last_lock_gone,
373  .fnv_back_walk = map_back_walk,
374};
375
376static void
377map_fib_resolve (map_main_pre_resolved_t * pr,
378		 fib_protocol_t proto, u8 len, const ip46_address_t * addr)
379{
380  fib_prefix_t pfx = {
381    .fp_proto = proto,
382    .fp_len = len,
383    .fp_addr = *addr,
384  };
385
386  pr->fei = fib_entry_track (0,	// default fib
387			     &pfx, FIB_NODE_TYPE_MAP_E, proto, &pr->sibling);
388  map_stack (pr);
389}
390
391static void
392map_fib_unresolve (map_main_pre_resolved_t * pr,
393		   fib_protocol_t proto, u8 len, const ip46_address_t * addr)
394{
395  if (pr->fei != FIB_NODE_INDEX_INVALID)
396    {
397      fib_entry_untrack (pr->fei, pr->sibling);
398
399      dpo_reset (&pr->dpo);
400
401      pr->fei = FIB_NODE_INDEX_INVALID;
402      pr->sibling = FIB_NODE_INDEX_INVALID;
403    }
404}
405
406void
407map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6, bool is_del)
408{
409  if (ip6 && (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0))
410    {
411      ip46_address_t addr = {
412	.ip6 = *ip6,
413      };
414      if (is_del)
415	map_fib_unresolve (&pre_resolved[FIB_PROTOCOL_IP6],
416			   FIB_PROTOCOL_IP6, 128, &addr);
417      else
418	map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP6],
419			 FIB_PROTOCOL_IP6, 128, &addr);
420    }
421  if (ip4 && (ip4->as_u32 != 0))
422    {
423      ip46_address_t addr = {
424	.ip4 = *ip4,
425      };
426      if (is_del)
427	map_fib_unresolve (&pre_resolved[FIB_PROTOCOL_IP4],
428			   FIB_PROTOCOL_IP4, 32, &addr);
429      else
430	map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP4],
431			 FIB_PROTOCOL_IP4, 32, &addr);
432    }
433}
434#endif
435
436static clib_error_t *
437map_security_check_command_fn (vlib_main_t * vm,
438			       unformat_input_t * input,
439			       vlib_cli_command_t * cmd)
440{
441  unformat_input_t _line_input, *line_input = &_line_input;
442  clib_error_t *error = NULL;
443  bool enable = false;
444  bool check_frag = false;
445  bool saw_enable = false;
446  bool saw_frag = false;
447
448  /* Get a line of input. */
449  if (!unformat_user (input, unformat_line_input, line_input))
450    return 0;
451
452  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
453    {
454      if (unformat (line_input, "enable"))
455	{
456	  enable = true;
457	  saw_enable = true;
458	}
459      else if (unformat (line_input, "disable"))
460	{
461	  enable = false;
462	  saw_enable = true;
463	}
464      else if (unformat (line_input, "fragments on"))
465	{
466	  check_frag = true;
467	  saw_frag = true;
468	}
469      else if (unformat (line_input, "fragments off"))
470	{
471	  check_frag = false;
472	  saw_frag = true;
473	}
474      else
475	{
476	  error = clib_error_return (0, "unknown input `%U'",
477				     format_unformat_error, line_input);
478	  goto done;
479	}
480    }
481
482  if (!saw_enable)
483    {
484      error = clib_error_return (0,
485				 "Must specify enable 'enable' or 'disable'");
486      goto done;
487    }
488
489  if (!saw_frag)
490    {
491      error = clib_error_return (0, "Must specify fragments 'on' or 'off'");
492      goto done;
493    }
494
495  map_param_set_security_check (enable, check_frag);
496
497done:
498  unformat_free (line_input);
499
500  return error;
501}
502
503
504static clib_error_t *
505map_add_domain_command_fn (vlib_main_t * vm,
506			   unformat_input_t * input, vlib_cli_command_t * cmd)
507{
508  unformat_input_t _line_input, *line_input = &_line_input;
509  ip4_address_t ip4_prefix;
510  ip6_address_t ip6_prefix;
511  ip6_address_t ip6_src;
512  u32 ip6_prefix_len = 0, ip4_prefix_len = 0, map_domain_index, ip6_src_len;
513  u32 num_m_args = 0;
514  /* Optional arguments */
515  u32 ea_bits_len = 0, psid_offset = 0, psid_length = 0;
516  u32 mtu = 0;
517  u8 flags = 0;
518  u8 *tag = 0;
519  ip6_src_len = 128;
520  clib_error_t *error = NULL;
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, "tag %s", &tag))
555	;
556      else
557	{
558	  error = clib_error_return (0, "unknown input `%U'",
559				     format_unformat_error, line_input);
560	  goto done;
561	}
562    }
563
564  if (num_m_args < 3)
565    {
566      error = clib_error_return (0, "mandatory argument(s) missing");
567      goto done;
568    }
569
570  map_create_domain (&ip4_prefix, ip4_prefix_len,
571		     &ip6_prefix, ip6_prefix_len, &ip6_src, ip6_src_len,
572		     ea_bits_len, psid_offset, psid_length, &map_domain_index,
573		     mtu, flags, tag);
574
575done:
576  vec_free (tag);
577  unformat_free (line_input);
578
579  return error;
580}
581
582static clib_error_t *
583map_del_domain_command_fn (vlib_main_t * vm,
584			   unformat_input_t * input, vlib_cli_command_t * cmd)
585{
586  unformat_input_t _line_input, *line_input = &_line_input;
587  u32 num_m_args = 0;
588  u32 map_domain_index;
589  clib_error_t *error = NULL;
590
591  /* Get a line of input. */
592  if (!unformat_user (input, unformat_line_input, line_input))
593    return 0;
594
595  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
596    {
597      if (unformat (line_input, "index %d", &map_domain_index))
598	num_m_args++;
599      else
600	{
601	  error = clib_error_return (0, "unknown input `%U'",
602				     format_unformat_error, line_input);
603	  goto done;
604	}
605    }
606
607  if (num_m_args != 1)
608    {
609      error = clib_error_return (0, "mandatory argument(s) missing");
610      goto done;
611    }
612
613  map_delete_domain (map_domain_index);
614
615done:
616  unformat_free (line_input);
617
618  return error;
619}
620
621static clib_error_t *
622map_add_rule_command_fn (vlib_main_t * vm,
623			 unformat_input_t * input, vlib_cli_command_t * cmd)
624{
625  unformat_input_t _line_input, *line_input = &_line_input;
626  ip6_address_t tep;
627  u32 num_m_args = 0;
628  u32 psid = 0, map_domain_index;
629  clib_error_t *error = NULL;
630
631  /* Get a line of input. */
632  if (!unformat_user (input, unformat_line_input, line_input))
633    return 0;
634
635  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
636    {
637      if (unformat (line_input, "index %d", &map_domain_index))
638	num_m_args++;
639      else if (unformat (line_input, "psid %d", &psid))
640	num_m_args++;
641      else
642	if (unformat (line_input, "ip6-dst %U", unformat_ip6_address, &tep))
643	num_m_args++;
644      else
645	{
646	  error = clib_error_return (0, "unknown input `%U'",
647				     format_unformat_error, line_input);
648	  goto done;
649	}
650    }
651
652  if (num_m_args != 3)
653    {
654      error = clib_error_return (0, "mandatory argument(s) missing");
655      goto done;
656    }
657
658  if (map_add_del_psid (map_domain_index, psid, &tep, 1) != 0)
659    {
660      error = clib_error_return (0, "Failing to add Mapping Rule");
661      goto done;
662    }
663
664done:
665  unformat_free (line_input);
666
667  return error;
668}
669
670#if MAP_SKIP_IP6_LOOKUP
671static clib_error_t *
672map_pre_resolve_command_fn (vlib_main_t * vm,
673			    unformat_input_t * input,
674			    vlib_cli_command_t * cmd)
675{
676  unformat_input_t _line_input, *line_input = &_line_input;
677  ip4_address_t ip4nh, *p_v4 = NULL;
678  ip6_address_t ip6nh, *p_v6 = NULL;
679  clib_error_t *error = NULL;
680  bool is_del = false;
681
682  clib_memset (&ip4nh, 0, sizeof (ip4nh));
683  clib_memset (&ip6nh, 0, sizeof (ip6nh));
684
685  /* Get a line of input. */
686  if (!unformat_user (input, unformat_line_input, line_input))
687    return 0;
688
689  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
690    {
691      if (unformat (line_input, "ip4-nh %U", unformat_ip4_address, &ip4nh))
692	p_v4 = &ip4nh;
693      else
694	if (unformat (line_input, "ip6-nh %U", unformat_ip6_address, &ip6nh))
695	p_v6 = &ip6nh;
696      else if (unformat (line_input, "del"))
697	is_del = true;
698      else
699	{
700	  error = clib_error_return (0, "unknown input `%U'",
701				     format_unformat_error, line_input);
702	  goto done;
703	}
704    }
705
706  map_pre_resolve (p_v4, p_v6, is_del);
707
708done:
709  unformat_free (line_input);
710
711  return error;
712}
713#endif
714
715static clib_error_t *
716map_icmp_relay_source_address_command_fn (vlib_main_t * vm,
717					  unformat_input_t * input,
718					  vlib_cli_command_t * cmd)
719{
720  unformat_input_t _line_input, *line_input = &_line_input;
721  ip4_address_t icmp_src_address;
722  ip4_address_t *p_icmp_addr = 0;
723  map_main_t *mm = &map_main;
724  clib_error_t *error = NULL;
725
726  mm->icmp4_src_address.as_u32 = 0;
727
728  /* Get a line of input. */
729  if (!unformat_user (input, unformat_line_input, line_input))
730    return 0;
731
732  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
733    {
734      if (unformat
735	  (line_input, "%U", unformat_ip4_address, &icmp_src_address))
736	{
737	  mm->icmp4_src_address = icmp_src_address;
738	  p_icmp_addr = &icmp_src_address;
739	}
740      else
741	{
742	  error = clib_error_return (0, "unknown input `%U'",
743				     format_unformat_error, line_input);
744	  goto done;
745	}
746    }
747
748  map_param_set_icmp (p_icmp_addr);
749
750done:
751  unformat_free (line_input);
752
753  return error;
754}
755
756static clib_error_t *
757map_icmp_unreachables_command_fn (vlib_main_t * vm,
758				  unformat_input_t * input,
759				  vlib_cli_command_t * cmd)
760{
761  unformat_input_t _line_input, *line_input = &_line_input;
762  int num_m_args = 0;
763  clib_error_t *error = NULL;
764  bool enabled = false;
765
766  /* Get a line of input. */
767  if (!unformat_user (input, unformat_line_input, line_input))
768    return 0;
769
770  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
771    {
772      num_m_args++;
773      if (unformat (line_input, "on"))
774	enabled = true;
775      else if (unformat (line_input, "off"))
776	enabled = false;
777      else
778	{
779	  error = clib_error_return (0, "unknown input `%U'",
780				     format_unformat_error, line_input);
781	  goto done;
782	}
783    }
784
785
786  if (num_m_args != 1)
787    error = clib_error_return (0, "mandatory argument(s) missing");
788
789
790  map_param_set_icmp6 (enabled);
791
792done:
793  unformat_free (line_input);
794
795  return error;
796}
797
798
799static clib_error_t *
800map_fragment_command_fn (vlib_main_t * vm,
801			 unformat_input_t * input, vlib_cli_command_t * cmd)
802{
803  unformat_input_t _line_input, *line_input = &_line_input;
804  clib_error_t *error = NULL;
805  bool frag_inner = false;
806  bool frag_ignore_df = false;
807  bool saw_in_out = false;
808  bool saw_df = false;
809
810  /* Get a line of input. */
811  if (!unformat_user (input, unformat_line_input, line_input))
812    return 0;
813
814  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
815    {
816      if (unformat (line_input, "inner"))
817	{
818	  frag_inner = true;
819	  saw_in_out = true;
820	}
821      else if (unformat (line_input, "outer"))
822	{
823	  frag_inner = false;
824	  saw_in_out = true;
825	}
826      else if (unformat (line_input, "ignore-df"))
827	{
828	  frag_ignore_df = true;
829	  saw_df = true;
830	}
831      else if (unformat (line_input, "honor-df"))
832	{
833	  frag_ignore_df = false;
834	  saw_df = true;
835	}
836      else
837	{
838	  error = clib_error_return (0, "unknown input `%U'",
839				     format_unformat_error, line_input);
840	  goto done;
841	}
842    }
843
844  if (!saw_in_out)
845    {
846      error = clib_error_return (0, "Must specify 'inner' or 'outer'");
847      goto done;
848    }
849
850  if (!saw_df)
851    {
852      error = clib_error_return (0, "Must specify 'ignore-df' or 'honor-df'");
853      goto done;
854    }
855
856  map_param_set_fragmentation (frag_inner, frag_ignore_df);
857
858done:
859  unformat_free (line_input);
860
861  return error;
862}
863
864static clib_error_t *
865map_traffic_class_command_fn (vlib_main_t * vm,
866			      unformat_input_t * input,
867			      vlib_cli_command_t * cmd)
868{
869  unformat_input_t _line_input, *line_input = &_line_input;
870  u32 tc = 0;
871  clib_error_t *error = NULL;
872  bool tc_copy = false;
873
874
875  /* Get a line of input. */
876  if (!unformat_user (input, unformat_line_input, line_input))
877    return 0;
878
879  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
880    {
881      if (unformat (line_input, "copy"))
882	tc_copy = true;
883      else if (unformat (line_input, "%x", &tc))
884	tc = tc & 0xff;
885      else
886	{
887	  error = clib_error_return (0, "unknown input `%U'",
888				     format_unformat_error, line_input);
889	  goto done;
890	}
891    }
892
893  map_param_set_traffic_class (tc_copy, tc);
894
895done:
896  unformat_free (line_input);
897
898  return error;
899}
900
901static char *
902map_flags_to_string (u32 flags)
903{
904  if (flags & MAP_DOMAIN_PREFIX)
905    return "prefix";
906  return "";
907}
908
909static u8 *
910format_map_domain (u8 * s, va_list * args)
911{
912  map_domain_t *d = va_arg (*args, map_domain_t *);
913  bool counters = va_arg (*args, int);
914  map_main_t *mm = &map_main;
915  ip6_address_t ip6_prefix;
916  u32 map_domain_index = d - mm->domains;
917  map_domain_extra_t *de = 0;
918
919  if (d->rules)
920    clib_memset (&ip6_prefix, 0, sizeof (ip6_prefix));
921  else
922    ip6_prefix = d->ip6_prefix;
923
924  if (map_domain_index < vec_len (mm->domain_extras))
925    de = vec_elt_at_index (mm->domain_extras, map_domain_index);
926
927  s = format (s,
928	      "[%d] tag {%s} ip4-pfx %U/%d ip6-pfx %U/%d ip6-src %U/%d "
929	      "ea-bits-len %d psid-offset %d psid-len %d mtu %d %s",
930	      map_domain_index, (de && de->tag) ? de->tag : (u8 *) "[no-tag]",
931	      format_ip4_address, &d->ip4_prefix, d->ip4_prefix_len,
932	      format_ip6_address, &ip6_prefix, d->ip6_prefix_len,
933	      format_ip6_address, &d->ip6_src, d->ip6_src_len,
934	      d->ea_bits_len, d->psid_offset, d->psid_length, d->mtu,
935	      map_flags_to_string (d->flags));
936
937  if (counters)
938    {
939      map_domain_counter_lock (mm);
940      vlib_counter_t v;
941      vlib_get_combined_counter (&mm->domain_counters[MAP_DOMAIN_COUNTER_TX],
942				 map_domain_index, &v);
943      s = format (s, "  TX: %lld/%lld", v.packets, v.bytes);
944      vlib_get_combined_counter (&mm->domain_counters[MAP_DOMAIN_COUNTER_RX],
945				 map_domain_index, &v);
946      s = format (s, "  RX: %lld/%lld", v.packets, v.bytes);
947      map_domain_counter_unlock (mm);
948    }
949  s = format (s, "\n");
950
951  if (d->rules)
952    {
953      int i;
954      ip6_address_t dst;
955      for (i = 0; i < (0x1 << d->psid_length); i++)
956	{
957	  dst = d->rules[i];
958	  if (dst.as_u64[0] == 0 && dst.as_u64[1] == 0)
959	    continue;
960	  s = format (s,
961		      " rule psid: %d ip6-dst %U\n", i, format_ip6_address,
962		      &dst);
963	}
964    }
965  return s;
966}
967
968static clib_error_t *
969show_map_domain_command_fn (vlib_main_t * vm, unformat_input_t * input,
970			    vlib_cli_command_t * cmd)
971{
972  unformat_input_t _line_input, *line_input = &_line_input;
973  map_main_t *mm = &map_main;
974  map_domain_t *d;
975  bool counters = false;
976  u32 map_domain_index = ~0;
977  clib_error_t *error = NULL;
978
979  /* Get a line of input. */
980  if (!unformat_user (input, unformat_line_input, line_input))
981    {
982      /* *INDENT-OFF* */
983      pool_foreach(d, mm->domains,
984	({vlib_cli_output(vm, "%U", format_map_domain, d, counters);}));
985      /* *INDENT-ON* */
986      return 0;
987    }
988
989  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
990    {
991      if (unformat (line_input, "counters"))
992	counters = true;
993      else if (unformat (line_input, "index %d", &map_domain_index))
994	;
995      else
996	{
997	  error = clib_error_return (0, "unknown input `%U'",
998				     format_unformat_error, line_input);
999	  goto done;
1000	}
1001    }
1002
1003  if (pool_elts (mm->domains) == 0)
1004    {
1005      vlib_cli_output (vm, "No MAP domains are configured...");
1006      goto done;
1007    }
1008
1009  if (map_domain_index == ~0)
1010    {
1011      /* *INDENT-OFF* */
1012      pool_foreach(d, mm->domains,
1013	({vlib_cli_output(vm, "%U", format_map_domain, d, counters);}));
1014      /* *INDENT-ON* */
1015    }
1016  else
1017    {
1018      if (pool_is_free_index (mm->domains, map_domain_index))
1019	{
1020	  error = clib_error_return (0, "MAP domain does not exists %d",
1021				     map_domain_index);
1022	  goto done;
1023	}
1024
1025      d = pool_elt_at_index (mm->domains, map_domain_index);
1026      vlib_cli_output (vm, "%U", format_map_domain, d, counters);
1027    }
1028
1029done:
1030  unformat_free (line_input);
1031
1032  return error;
1033}
1034
1035u64
1036map_error_counter_get (u32 node_index, map_error_t map_error)
1037{
1038  vlib_main_t *vm = vlib_get_main ();
1039  vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, node_index);
1040  vlib_error_main_t *em = &vm->error_main;
1041  vlib_error_t e = error_node->errors[map_error];
1042  vlib_node_t *n = vlib_get_node (vm, node_index);
1043  u32 ci;
1044
1045  ci = vlib_error_get_code (&vm->node_main, e);
1046  ASSERT (ci < n->n_errors);
1047  ci += n->error_heap_index;
1048
1049  return (em->counters[ci]);
1050}
1051
1052static clib_error_t *
1053show_map_stats_command_fn (vlib_main_t * vm, unformat_input_t * input,
1054			   vlib_cli_command_t * cmd)
1055{
1056  map_main_t *mm = &map_main;
1057  map_domain_t *d;
1058  int domains = 0, rules = 0, domaincount = 0, rulecount = 0;
1059  if (pool_elts (mm->domains) == 0)
1060    {
1061      vlib_cli_output (vm, "No MAP domains are configured...");
1062      return 0;
1063    }
1064
1065  /* *INDENT-OFF* */
1066  pool_foreach(d, mm->domains, ({
1067    if (d->rules) {
1068      rulecount+= 0x1 << d->psid_length;
1069      rules += sizeof(ip6_address_t) * 0x1 << d->psid_length;
1070    }
1071    domains += sizeof(*d);
1072    domaincount++;
1073  }));
1074  /* *INDENT-ON* */
1075
1076  vlib_cli_output (vm, "MAP domains structure: %d\n", sizeof (map_domain_t));
1077  vlib_cli_output (vm, "MAP domains: %d (%d bytes)\n", domaincount, domains);
1078  vlib_cli_output (vm, "MAP rules: %d (%d bytes)\n", rulecount, rules);
1079  vlib_cli_output (vm, "Total: %d bytes)\n", rules + domains);
1080
1081#if MAP_SKIP_IP6_LOOKUP
1082  vlib_cli_output (vm,
1083		   "MAP pre-resolve: IP6 next-hop: %U, IP4 next-hop: %U\n",
1084		   format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP6],
1085		   format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP4]);
1086
1087#endif
1088
1089  if (mm->tc_copy)
1090    vlib_cli_output (vm, "MAP traffic-class: copy");
1091  else
1092    vlib_cli_output (vm, "MAP traffic-class: %x", mm->tc);
1093
1094  if (mm->tcp_mss)
1095    vlib_cli_output (vm, "MAP TCP MSS clamping: %u", mm->tcp_mss);
1096
1097  vlib_cli_output (vm,
1098		   "MAP IPv6 inbound security check: %s, fragmented packet security check: %s",
1099		   mm->sec_check ? "enabled" : "disabled",
1100		   mm->sec_check_frag ? "enabled" : "disabled");
1101
1102  vlib_cli_output (vm, "ICMP-relay IPv4 source address: %U\n",
1103		   format_ip4_address, &mm->icmp4_src_address);
1104  vlib_cli_output (vm, "ICMP6 unreachables sent for unmatched packets: %s\n",
1105		   mm->icmp6_enabled ? "enabled" : "disabled");
1106  vlib_cli_output (vm, "Inner fragmentation: %s\n",
1107		   mm->frag_inner ? "enabled" : "disabled");
1108  vlib_cli_output (vm, "Fragment packets regardless of DF flag: %s\n",
1109		   mm->frag_ignore_df ? "enabled" : "disabled");
1110
1111  /*
1112   * Counters
1113   */
1114  vlib_combined_counter_main_t *cm = mm->domain_counters;
1115  u64 total_pkts[MAP_N_DOMAIN_COUNTER];
1116  u64 total_bytes[MAP_N_DOMAIN_COUNTER];
1117  int which, i;
1118  vlib_counter_t v;
1119
1120  clib_memset (total_pkts, 0, sizeof (total_pkts));
1121  clib_memset (total_bytes, 0, sizeof (total_bytes));
1122
1123  map_domain_counter_lock (mm);
1124  vec_foreach (cm, mm->domain_counters)
1125  {
1126    which = cm - mm->domain_counters;
1127
1128    for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
1129      {
1130	vlib_get_combined_counter (cm, i, &v);
1131	total_pkts[which] += v.packets;
1132	total_bytes[which] += v.bytes;
1133      }
1134  }
1135  map_domain_counter_unlock (mm);
1136
1137  vlib_cli_output (vm, "Encapsulated packets: %lld bytes: %lld\n",
1138		   total_pkts[MAP_DOMAIN_COUNTER_TX],
1139		   total_bytes[MAP_DOMAIN_COUNTER_TX]);
1140  vlib_cli_output (vm, "Decapsulated packets: %lld bytes: %lld\n",
1141		   total_pkts[MAP_DOMAIN_COUNTER_RX],
1142		   total_bytes[MAP_DOMAIN_COUNTER_RX]);
1143
1144  vlib_cli_output (vm, "ICMP relayed packets: %d\n",
1145		   vlib_get_simple_counter (&mm->icmp_relayed, 0));
1146
1147  return 0;
1148}
1149
1150static clib_error_t *
1151map_if_command_fn (vlib_main_t * vm,
1152		   unformat_input_t * input, vlib_cli_command_t * cmd)
1153{
1154  unformat_input_t _line_input, *line_input = &_line_input;
1155  clib_error_t *error = NULL;
1156  bool is_enable = true, is_translation = false;
1157  vnet_main_t *vnm = vnet_get_main ();
1158  u32 sw_if_index = ~0;
1159
1160  /* Get a line of input. */
1161  if (!unformat_user (input, unformat_line_input, line_input))
1162    return 0;
1163
1164  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1165    {
1166      if (unformat
1167	  (line_input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1168	;
1169      else if (unformat (line_input, "del"))
1170	is_enable = false;
1171      else if (unformat (line_input, "map-t"))
1172	is_translation = true;
1173      else
1174	{
1175	  error = clib_error_return (0, "unknown input `%U'",
1176				     format_unformat_error, line_input);
1177	  goto done;
1178	}
1179    }
1180
1181done:
1182  unformat_free (line_input);
1183
1184  if (sw_if_index == ~0)
1185    {
1186      error = clib_error_return (0, "unknown interface");
1187      return error;
1188    }
1189
1190  int rv = map_if_enable_disable (is_enable, sw_if_index, is_translation);
1191  if (rv)
1192    {
1193      error = clib_error_return (0, "failure enabling MAP on interface");
1194    }
1195
1196  return error;
1197}
1198
1199
1200/*
1201 * packet trace format function
1202 */
1203u8 *
1204format_map_trace (u8 * s, va_list * args)
1205{
1206  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1207  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1208  map_trace_t *t = va_arg (*args, map_trace_t *);
1209  u32 map_domain_index = t->map_domain_index;
1210  u16 port = t->port;
1211
1212  s =
1213    format (s, "MAP domain index: %d L4 port: %u", map_domain_index,
1214	    clib_net_to_host_u16 (port));
1215
1216  return s;
1217}
1218
1219static clib_error_t *
1220map_tcp_mss_command_fn (vlib_main_t * vm,
1221			unformat_input_t * input, vlib_cli_command_t * cmd)
1222{
1223  unformat_input_t _line_input, *line_input = &_line_input;
1224  clib_error_t *error = NULL;
1225  u32 tcp_mss = 0;
1226
1227  /* Get a line of input. */
1228  if (!unformat_user (input, unformat_line_input, line_input))
1229    return 0;
1230
1231  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1232    {
1233      if (unformat (line_input, "%u", &tcp_mss))
1234	;
1235      else
1236	{
1237	  error = clib_error_return (0, "unknown input `%U'",
1238				     format_unformat_error, line_input);
1239	  goto done;
1240	}
1241    }
1242
1243  if (tcp_mss >= (0x1 << 16))
1244    {
1245      error = clib_error_return (0, "invalid value `%u'", tcp_mss);
1246      goto done;
1247    }
1248
1249  map_param_set_tcp (tcp_mss);
1250
1251done:
1252  unformat_free (line_input);
1253
1254  return error;
1255}
1256
1257
1258/* *INDENT-OFF* */
1259
1260/*?
1261 * Set or copy the IP TOS/Traffic Class field
1262 *
1263 * @cliexpar
1264 * @cliexstart{map params traffic-class}
1265 *
1266 * This command is used to set the traffic-class field in translated
1267 * or encapsulated packets. If copy is specifed (the default) then the
1268 * traffic-class/TOS field is copied from the original packet to the
1269 * translated / encapsulating header.
1270 * @cliexend
1271 ?*/
1272VLIB_CLI_COMMAND(map_traffic_class_command, static) = {
1273  .path = "map params traffic-class",
1274  .short_help = "map params traffic-class {0x0-0xff | copy}",
1275  .function = map_traffic_class_command_fn,
1276};
1277
1278/*?
1279 * TCP MSS clamping
1280 *
1281 * @cliexpar
1282 * @cliexstart{map params tcp-mss}
1283 *
1284 * This command is used to set the TCP MSS in translated
1285 * or encapsulated packets.
1286 * @cliexend
1287 ?*/
1288VLIB_CLI_COMMAND(map_tcp_mss_command, static) = {
1289  .path = "map params tcp-mss",
1290  .short_help = "map params tcp-mss <value>",
1291  .function = map_tcp_mss_command_fn,
1292};
1293
1294/*?
1295 * Bypass IP4/IP6 lookup
1296 *
1297 * @cliexpar
1298 * @cliexstart{map params pre-resolve}
1299 *
1300 * Bypass a second FIB lookup of the translated or encapsulated
1301 * packet, and forward the packet directly to the specified
1302 * next-hop. This optimization trades forwarding flexibility for
1303 * performance.
1304 * @cliexend
1305 ?*/
1306VLIB_CLI_COMMAND(map_pre_resolve_command, static) = {
1307  .path = "map params pre-resolve",
1308  .short_help = " map params pre-resolve {ip4-nh <address>} "
1309                "| {ip6-nh <address>}",
1310  .function = map_pre_resolve_command_fn,
1311};
1312
1313/*?
1314 * Enable or disable the MAP-E inbound security check
1315 * Specifiy if the inbound security check should be done on fragments
1316 *
1317 * @cliexpar
1318 * @cliexstart{map params security-check}
1319 *
1320 * By default, a decapsulated packet's IPv4 source address will be
1321 * verified against the outer header's IPv6 source address. Disabling
1322 * this feature will allow IPv4 source address spoofing.
1323 *
1324 * Typically the inbound on-decapsulation security check is only done
1325 * on the first packet. The packet that contains the L4
1326 * information. While a security check on every fragment is possible,
1327 * it has a cost. State must be created on the first fragment.
1328 * @cliexend
1329 ?*/
1330VLIB_CLI_COMMAND(map_security_check_command, static) = {
1331  .path = "map params security-check",
1332  .short_help = "map params security-check enable|disable fragments on|off",
1333  .function = map_security_check_command_fn,
1334};
1335
1336
1337/*?
1338 * Specifiy the IPv4 source address used for relayed ICMP error messages
1339 *
1340 * @cliexpar
1341 * @cliexstart{map params icmp source-address}
1342 *
1343 * This command specifies which IPv4 source address (must be local to
1344 * the system), that is used for relayed received IPv6 ICMP error
1345 * messages.
1346 * @cliexend
1347 ?*/
1348VLIB_CLI_COMMAND(map_icmp_relay_source_address_command, static) = {
1349  .path = "map params icmp source-address",
1350  .short_help = "map params icmp source-address <ip4-address>",
1351  .function = map_icmp_relay_source_address_command_fn,
1352};
1353
1354/*?
1355 * Send IPv6 ICMP unreachables
1356 *
1357 * @cliexpar
1358 * @cliexstart{map params icmp6 unreachables}
1359 *
1360 * Send IPv6 ICMP unreachable messages back if security check fails or
1361 * no MAP domain exists.
1362 * @cliexend
1363 ?*/
1364VLIB_CLI_COMMAND(map_icmp_unreachables_command, static) = {
1365  .path = "map params icmp6 unreachables",
1366  .short_help = "map params icmp6 unreachables {on|off}",
1367  .function = map_icmp_unreachables_command_fn,
1368};
1369
1370/*?
1371 * Configure MAP fragmentation behaviour
1372 *
1373 * @cliexpar
1374 * @cliexstart{map params fragment}
1375 *
1376 * Allows fragmentation of the IPv4 packet even if the DF bit is
1377 * set. The choice between inner or outer fragmentation of tunnel
1378 * packets is complicated. The benefit of inner fragmentation is that
1379 * the ultimate endpoint must reassemble, instead of the tunnel
1380 * endpoint.
1381 * @cliexend
1382 ?*/
1383VLIB_CLI_COMMAND(map_fragment_command, static) = {
1384  .path = "map params fragment",
1385  .short_help = "map params fragment inner|outer ignore-df|honor-df",
1386  .function = map_fragment_command_fn,
1387};
1388
1389
1390/*?
1391 * Add MAP domain
1392 *
1393 * @cliexpar
1394 * @cliexstart{map add domain}
1395 * @cliexend
1396 ?*/
1397VLIB_CLI_COMMAND(map_add_domain_command, static) = {
1398  .path = "map add domain",
1399  .short_help = "map add domain [tag <tag>] ip4-pfx <ip4-pfx> "
1400      "ip6-pfx <ip6-pfx> "
1401      "ip6-src <ip6-pfx> ea-bits-len <n> psid-offset <n> psid-len <n> "
1402      "[map-t] [mtu <mtu>]",
1403  .function = map_add_domain_command_fn,
1404};
1405
1406/*?
1407 * Add MAP rule to a domain
1408 *
1409 * @cliexpar
1410 * @cliexstart{map add rule}
1411 * @cliexend
1412 ?*/
1413VLIB_CLI_COMMAND(map_add_rule_command, static) = {
1414  .path = "map add rule",
1415  .short_help = "map add rule index <domain> psid <psid> ip6-dst <ip6-addr>",
1416  .function = map_add_rule_command_fn,
1417};
1418
1419/*?
1420 * Delete MAP domain
1421 *
1422 * @cliexpar
1423 * @cliexstart{map del domain}
1424 * @cliexend
1425 ?*/
1426VLIB_CLI_COMMAND(map_del_command, static) = {
1427  .path = "map del domain",
1428  .short_help = "map del domain index <domain>",
1429  .function = map_del_domain_command_fn,
1430};
1431
1432/*?
1433 * Show MAP domains
1434 *
1435 * @cliexpar
1436 * @cliexstart{show map domain}
1437 * @cliexend
1438 ?*/
1439VLIB_CLI_COMMAND(show_map_domain_command, static) = {
1440  .path = "show map domain",
1441  .short_help = "show map domain index <n> [counters]",
1442  .function = show_map_domain_command_fn,
1443};
1444
1445/*?
1446 * Show MAP statistics
1447 *
1448 * @cliexpar
1449 * @cliexstart{show map stats}
1450 * @cliexend
1451 ?*/
1452VLIB_CLI_COMMAND(show_map_stats_command, static) = {
1453  .path = "show map stats",
1454  .short_help = "show map stats",
1455  .function = show_map_stats_command_fn,
1456};
1457
1458/*?
1459 * Enable MAP processing on interface (input feature)
1460 *
1461 ?*/
1462VLIB_CLI_COMMAND(map_if_command, static) = {
1463  .path = "map interface",
1464  .short_help = "map interface <interface-name> [map-t] [del]",
1465  .function = map_if_command_fn,
1466};
1467
1468VLIB_PLUGIN_REGISTER() = {
1469  .version = VPP_BUILD_VER,
1470  .description = "Mapping of Address and Port (MAP)",
1471};
1472
1473/* *INDENT-ON* */
1474
1475/*
1476 * map_init
1477 */
1478clib_error_t *
1479map_init (vlib_main_t * vm)
1480{
1481  map_main_t *mm = &map_main;
1482  clib_error_t *error = 0;
1483
1484  memset (mm, 0, sizeof (*mm));
1485
1486  mm->vnet_main = vnet_get_main ();
1487  mm->vlib_main = vm;
1488
1489#ifdef MAP_SKIP_IP6_LOOKUP
1490  fib_protocol_t proto;
1491
1492  FOR_EACH_FIB_PROTOCOL (proto)
1493  {
1494    map_pre_resolve_init (&pre_resolved[proto]);
1495  }
1496#endif
1497
1498  /* traffic class */
1499  mm->tc = 0;
1500  mm->tc_copy = true;
1501
1502  /* Inbound security check */
1503  mm->sec_check = true;
1504  mm->sec_check_frag = false;
1505
1506  /* ICMP6 Type 1, Code 5 for security check failure */
1507  mm->icmp6_enabled = false;
1508
1509  /* Inner or outer fragmentation */
1510  mm->frag_inner = false;
1511  mm->frag_ignore_df = false;
1512
1513  vec_validate (mm->domain_counters, MAP_N_DOMAIN_COUNTER - 1);
1514  mm->domain_counters[MAP_DOMAIN_COUNTER_RX].name = "/map/rx";
1515  mm->domain_counters[MAP_DOMAIN_COUNTER_TX].name = "/map/tx";
1516
1517  vlib_validate_simple_counter (&mm->icmp_relayed, 0);
1518  vlib_zero_simple_counter (&mm->icmp_relayed, 0);
1519  mm->icmp_relayed.stat_segment_name = "/map/icmp-relayed";
1520
1521  /* IP6 virtual reassembly */
1522
1523#ifdef MAP_SKIP_IP6_LOOKUP
1524  fib_node_register_type (FIB_NODE_TYPE_MAP_E, &map_vft);
1525#endif
1526
1527  /* LPM lookup tables */
1528  mm->ip4_prefix_tbl = lpm_table_init (LPM_TYPE_KEY32);
1529  mm->ip6_prefix_tbl = lpm_table_init (LPM_TYPE_KEY128);
1530  mm->ip6_src_prefix_tbl = lpm_table_init (LPM_TYPE_KEY128);
1531
1532  mm->bm_trans_enabled_by_sw_if = 0;
1533  mm->bm_encap_enabled_by_sw_if = 0;
1534
1535  error = map_plugin_api_hookup (vm);
1536
1537  return error;
1538}
1539
1540VLIB_INIT_FUNCTION (map_init);
1541
1542/*
1543 * fd.io coding-style-patch-verification: ON
1544 *
1545 * Local Variables:
1546 * eval: (c-set-style "gnu")
1547 * End:
1548 */
1549