LCOV - code coverage report
Current view: top level - plugins/map - map.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 179 598 29.9 %
Date: 2023-07-05 22:20:52 Functions: 43 61 70.5 %

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

Generated by: LCOV version 1.14