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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vnet/fib/fib_table.h>
19 #include <vnet/fib/ip6_fib.h>
20 #include <vnet/adj/adj.h>
21 #include <vppinfra/crc32.h>
22 #include <vnet/plugin/plugin.h>
23 #include <vpp/app/version.h>
29 * This code supports the following MAP modes:
31 * Algorithmic Shared IPv4 address (ea_bits_len > 0):
32 * ea_bits_len + ip4_prefix > 32
33 * psid_length > 0, ip6_prefix < 64, ip4_prefix <= 32
34 * Algorithmic Full IPv4 address (ea_bits_len > 0):
35 * ea_bits_len + ip4_prefix = 32
36 * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
37 * Algorithmic IPv4 prefix (ea_bits_len > 0):
38 * ea_bits_len + ip4_prefix < 32
39 * psid_length = 0, ip6_prefix < 64, ip4_prefix <= 32
41 * Independent Shared IPv4 address (ea_bits_len = 0):
44 * Rule IPv6 address = 128, Rule PSID Set
45 * Independent Full IPv4 address (ea_bits_len = 0):
47 * psid_length = 0, ip6_prefix = 128
48 * Independent IPv4 prefix (ea_bits_len = 0):
50 * psid_length = 0, ip6_prefix = 128
55 * This code supports MAP-T:
57 * With a DMR prefix length of 64 or 96 (RFC6052).
63 * Save usre-assigned MAP domain names ("tags") in a vector of
64 * extra domain information.
67 map_save_extras (u32 map_domain_index, char *tag)
69 map_main_t *mm = &map_main;
70 map_domain_extra_t *de;
73 if (map_domain_index == ~0)
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));
83 len = strlen (tag) + 1;
84 de->tag = clib_mem_alloc (len);
85 clib_memcpy (de->tag, tag, len);
90 map_free_extras (u32 map_domain_index)
92 map_main_t *mm = &map_main;
93 map_domain_extra_t *de;
96 if (map_domain_index == ~0)
99 de = vec_elt_at_index (mm->domain_extras, map_domain_index);
110 map_create_domain (ip4_address_t * ip4_prefix,
112 ip6_address_t * ip6_prefix,
114 ip6_address_t * ip6_src,
119 u32 * map_domain_index, u16 mtu, u8 flags, char *tag)
121 u8 suffix_len, suffix_shift;
122 map_main_t *mm = &map_main;
125 /* How many, and which bits to grab from the IPv4 DA */
126 if (ip4_prefix_len + ea_bits_len < 32)
128 flags |= MAP_DOMAIN_PREFIX;
129 suffix_shift = 32 - ip4_prefix_len - ea_bits_len;
130 suffix_len = ea_bits_len;
135 suffix_len = 32 - ip4_prefix_len;
138 /* EA bits must be within the first 64 bits */
139 if (ea_bits_len > 0 && ((ip6_prefix_len + ea_bits_len) > 64 ||
140 ip6_prefix_len + suffix_len + psid_length > 64))
143 ("Embedded Address bits must be within the first 64 bits of "
148 /* Get domain index */
149 pool_get_aligned (mm->domains, d, CLIB_CACHE_LINE_BYTES);
150 clib_memset (d, 0, sizeof (*d));
151 *map_domain_index = d - mm->domains;
153 /* Init domain struct */
154 d->ip4_prefix.as_u32 = ip4_prefix->as_u32;
155 d->ip4_prefix_len = ip4_prefix_len;
156 d->ip6_prefix = *ip6_prefix;
157 d->ip6_prefix_len = ip6_prefix_len;
158 d->ip6_src = *ip6_src;
159 d->ip6_src_len = ip6_src_len;
160 d->ea_bits_len = ea_bits_len;
161 d->psid_offset = psid_offset;
162 d->psid_length = psid_length;
165 d->suffix_shift = suffix_shift;
166 d->suffix_mask = (1 << suffix_len) - 1;
168 d->psid_shift = 16 - psid_length - psid_offset;
169 d->psid_mask = (1 << d->psid_length) - 1;
170 d->ea_shift = 64 - ip6_prefix_len - suffix_len - d->psid_length;
172 /* Save a user-assigned MAP domain name if provided. */
174 map_save_extras (*map_domain_index, tag);
176 /* MAP longest match lookup table (input feature / FIB) */
177 mm->ip4_prefix_tbl->add (mm->ip4_prefix_tbl, &d->ip4_prefix,
178 d->ip4_prefix_len, *map_domain_index);
180 /* Really needed? Or always use FIB? */
181 mm->ip6_src_prefix_tbl->add (mm->ip6_src_prefix_tbl, &d->ip6_src,
182 d->ip6_src_len, *map_domain_index);
184 /* Validate packet/byte counters */
185 map_domain_counter_lock (mm);
187 for (i = 0; i < vec_len (mm->simple_domain_counters); i++)
189 vlib_validate_simple_counter (&mm->simple_domain_counters[i],
191 vlib_zero_simple_counter (&mm->simple_domain_counters[i],
194 for (i = 0; i < vec_len (mm->domain_counters); i++)
196 vlib_validate_combined_counter (&mm->domain_counters[i],
198 vlib_zero_combined_counter (&mm->domain_counters[i], *map_domain_index);
200 map_domain_counter_unlock (mm);
209 map_delete_domain (u32 map_domain_index)
211 map_main_t *mm = &map_main;
214 if (pool_is_free_index (mm->domains, map_domain_index))
216 clib_warning ("MAP domain delete: domain does not exist: %d",
221 d = pool_elt_at_index (mm->domains, map_domain_index);
222 mm->ip4_prefix_tbl->delete (mm->ip4_prefix_tbl, &d->ip4_prefix,
224 mm->ip6_src_prefix_tbl->delete (mm->ip6_src_prefix_tbl, &d->ip6_src,
227 /* Release user-assigned MAP domain name. */
228 map_free_extras (map_domain_index);
232 clib_mem_free (d->rules);
234 pool_put (mm->domains, d);
240 map_add_del_psid (u32 map_domain_index, u16 psid, ip6_address_t * tep,
244 map_main_t *mm = &map_main;
246 if (pool_is_free_index (mm->domains, map_domain_index))
248 clib_warning ("MAP rule: domain does not exist: %d", map_domain_index);
251 d = pool_elt_at_index (mm->domains, map_domain_index);
253 /* Rules are only used in 1:1 independent case */
254 if (d->ea_bits_len > 0)
259 u32 l = (0x1 << d->psid_length) * sizeof (ip6_address_t);
260 d->rules = clib_mem_alloc_aligned (l, CLIB_CACHE_LINE_BYTES);
263 clib_memset (d->rules, 0, l);
266 if (psid >= (0x1 << d->psid_length))
268 clib_warning ("MAP rule: PSID outside bounds: %d [%d]", psid,
269 0x1 << d->psid_length);
275 d->rules[psid] = *tep;
279 clib_memset (&d->rules[psid], 0, sizeof (ip6_address_t));
284 #ifdef MAP_SKIP_IP6_LOOKUP
286 * Pre-resolved per-protocol global next-hops
288 map_main_pre_resolved_t pre_resolved[FIB_PROTOCOL_MAX];
291 map_pre_resolve_init (map_main_pre_resolved_t * pr)
293 pr->fei = FIB_NODE_INDEX_INVALID;
294 fib_node_init (&pr->node, FIB_NODE_TYPE_MAP_E);
298 format_map_pre_resolve (u8 * s, va_list * ap)
300 map_main_pre_resolved_t *pr = va_arg (*ap, map_main_pre_resolved_t *);
302 if (FIB_NODE_INDEX_INVALID != pr->fei)
304 const fib_prefix_t *pfx;
306 pfx = fib_entry_get_prefix (pr->fei);
308 return (format (s, "%U (%u)",
309 format_ip46_address, &pfx->fp_addr, IP46_TYPE_ANY,
310 pr->dpo.dpoi_index));
314 return (format (s, "un-set"));
320 * Function definition to inform the FIB node that its last lock has gone.
323 map_last_lock_gone (fib_node_t * node)
326 * The MAP is a root of the graph. As such
327 * it never has children and thus is never locked.
332 static map_main_pre_resolved_t *
333 map_from_fib_node (fib_node_t * node)
335 ASSERT (FIB_NODE_TYPE_MAP_E == node->fn_type);
336 return ((map_main_pre_resolved_t *)
338 STRUCT_OFFSET_OF (map_main_pre_resolved_t, node)));
342 map_stack (map_main_pre_resolved_t * pr)
346 dpo = fib_entry_contribute_ip_forwarding (pr->fei);
348 dpo_copy (&pr->dpo, dpo);
352 * Function definition to backwalk a FIB node
354 static fib_node_back_walk_rc_t
355 map_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
357 map_stack (map_from_fib_node (node));
359 return (FIB_NODE_BACK_WALK_CONTINUE);
363 * Function definition to get a FIB node from its index
366 map_fib_node_get (fib_node_index_t index)
368 return (&pre_resolved[index].node);
372 * Virtual function table registered by MPLS GRE tunnels
373 * for participation in the FIB object graph.
375 const static fib_node_vft_t map_vft = {
376 .fnv_get = map_fib_node_get,
377 .fnv_last_lock = map_last_lock_gone,
378 .fnv_back_walk = map_back_walk,
382 map_fib_resolve (map_main_pre_resolved_t * pr,
383 fib_protocol_t proto, u8 len, const ip46_address_t * addr)
391 pr->fei = fib_table_entry_special_add (0, // default fib
393 FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE);
394 pr->sibling = fib_entry_child_add (pr->fei, FIB_NODE_TYPE_MAP_E, proto);
399 map_fib_unresolve (map_main_pre_resolved_t * pr,
400 fib_protocol_t proto, u8 len, const ip46_address_t * addr)
408 if (pr->fei != FIB_NODE_INDEX_INVALID)
410 fib_entry_child_remove (pr->fei, pr->sibling);
412 fib_table_entry_special_remove (0, // default fib
413 &pfx, FIB_SOURCE_RR);
414 dpo_reset (&pr->dpo);
416 pr->fei = FIB_NODE_INDEX_INVALID;
417 pr->sibling = FIB_NODE_INDEX_INVALID;
422 map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6, bool is_del)
424 if (ip6 && (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0))
426 ip46_address_t addr = {
430 map_fib_unresolve (&pre_resolved[FIB_PROTOCOL_IP6],
431 FIB_PROTOCOL_IP6, 128, &addr);
433 map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP6],
434 FIB_PROTOCOL_IP6, 128, &addr);
436 if (ip4 && (ip4->as_u32 != 0))
438 ip46_address_t addr = {
442 map_fib_unresolve (&pre_resolved[FIB_PROTOCOL_IP4],
443 FIB_PROTOCOL_IP4, 32, &addr);
445 map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP4],
446 FIB_PROTOCOL_IP4, 32, &addr);
451 static clib_error_t *
452 map_security_check_command_fn (vlib_main_t * vm,
453 unformat_input_t * input,
454 vlib_cli_command_t * cmd)
456 unformat_input_t _line_input, *line_input = &_line_input;
457 clib_error_t *error = NULL;
459 bool check_frag = false;
460 bool saw_enable = false;
461 bool saw_frag = false;
463 /* Get a line of input. */
464 if (!unformat_user (input, unformat_line_input, line_input))
467 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
469 if (unformat (line_input, "enable"))
474 else if (unformat (line_input, "disable"))
479 else if (unformat (line_input, "fragments on"))
484 else if (unformat (line_input, "fragments off"))
491 error = clib_error_return (0, "unknown input `%U'",
492 format_unformat_error, line_input);
499 error = clib_error_return (0,
500 "Must specify enable 'enable' or 'disable'");
506 error = clib_error_return (0, "Must specify fragments 'on' or 'off'");
510 map_param_set_security_check (enable, check_frag);
513 unformat_free (line_input);
519 static clib_error_t *
520 map_add_domain_command_fn (vlib_main_t * vm,
521 unformat_input_t * input, vlib_cli_command_t * cmd)
523 unformat_input_t _line_input, *line_input = &_line_input;
524 ip4_address_t ip4_prefix;
525 ip6_address_t ip6_prefix;
526 ip6_address_t ip6_src;
527 u32 ip6_prefix_len = 0, ip4_prefix_len = 0, map_domain_index, ip6_src_len;
529 /* Optional arguments */
530 u32 ea_bits_len = 0, psid_offset = 0, psid_length = 0;
535 clib_error_t *error = NULL;
537 /* Get a line of input. */
538 if (!unformat_user (input, unformat_line_input, line_input))
541 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
544 (line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix,
549 (line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix,
554 (line_input, "ip6-src %U/%d", unformat_ip6_address, &ip6_src,
559 (line_input, "ip6-src %U", unformat_ip6_address, &ip6_src))
561 else if (unformat (line_input, "ea-bits-len %d", &ea_bits_len))
563 else if (unformat (line_input, "psid-offset %d", &psid_offset))
565 else if (unformat (line_input, "psid-len %d", &psid_length))
567 else if (unformat (line_input, "mtu %d", &mtu))
569 else if (unformat (line_input, "tag %s", &tag))
573 error = clib_error_return (0, "unknown input `%U'",
574 format_unformat_error, line_input);
581 error = clib_error_return (0, "mandatory argument(s) missing");
585 map_create_domain (&ip4_prefix, ip4_prefix_len,
586 &ip6_prefix, ip6_prefix_len, &ip6_src, ip6_src_len,
587 ea_bits_len, psid_offset, psid_length, &map_domain_index,
588 mtu, flags, (char *) tag);
591 unformat_free (line_input);
596 static clib_error_t *
597 map_del_domain_command_fn (vlib_main_t * vm,
598 unformat_input_t * input, vlib_cli_command_t * cmd)
600 unformat_input_t _line_input, *line_input = &_line_input;
602 u32 map_domain_index;
603 clib_error_t *error = NULL;
605 /* Get a line of input. */
606 if (!unformat_user (input, unformat_line_input, line_input))
609 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
611 if (unformat (line_input, "index %d", &map_domain_index))
615 error = clib_error_return (0, "unknown input `%U'",
616 format_unformat_error, line_input);
623 error = clib_error_return (0, "mandatory argument(s) missing");
627 map_delete_domain (map_domain_index);
630 unformat_free (line_input);
635 static clib_error_t *
636 map_add_rule_command_fn (vlib_main_t * vm,
637 unformat_input_t * input, vlib_cli_command_t * cmd)
639 unformat_input_t _line_input, *line_input = &_line_input;
642 u32 psid = 0, map_domain_index;
643 clib_error_t *error = NULL;
645 /* Get a line of input. */
646 if (!unformat_user (input, unformat_line_input, line_input))
649 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
651 if (unformat (line_input, "index %d", &map_domain_index))
653 else if (unformat (line_input, "psid %d", &psid))
656 if (unformat (line_input, "ip6-dst %U", unformat_ip6_address, &tep))
660 error = clib_error_return (0, "unknown input `%U'",
661 format_unformat_error, line_input);
668 error = clib_error_return (0, "mandatory argument(s) missing");
672 if (map_add_del_psid (map_domain_index, psid, &tep, 1) != 0)
674 error = clib_error_return (0, "Failing to add Mapping Rule");
679 unformat_free (line_input);
684 #if MAP_SKIP_IP6_LOOKUP
685 static clib_error_t *
686 map_pre_resolve_command_fn (vlib_main_t * vm,
687 unformat_input_t * input,
688 vlib_cli_command_t * cmd)
690 unformat_input_t _line_input, *line_input = &_line_input;
691 ip4_address_t ip4nh, *p_v4 = NULL;
692 ip6_address_t ip6nh, *p_v6 = NULL;
693 clib_error_t *error = NULL;
696 clib_memset (&ip4nh, 0, sizeof (ip4nh));
697 clib_memset (&ip6nh, 0, sizeof (ip6nh));
699 /* Get a line of input. */
700 if (!unformat_user (input, unformat_line_input, line_input))
703 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
705 if (unformat (line_input, "ip4-nh %U", unformat_ip4_address, &ip4nh))
708 if (unformat (line_input, "ip6-nh %U", unformat_ip6_address, &ip6nh))
710 else if (unformat (line_input, "del"))
714 error = clib_error_return (0, "unknown input `%U'",
715 format_unformat_error, line_input);
720 map_pre_resolve (p_v4, p_v6, is_del);
723 unformat_free (line_input);
729 static clib_error_t *
730 map_icmp_relay_source_address_command_fn (vlib_main_t * vm,
731 unformat_input_t * input,
732 vlib_cli_command_t * cmd)
734 unformat_input_t _line_input, *line_input = &_line_input;
735 ip4_address_t icmp_src_address;
736 ip4_address_t *p_icmp_addr = 0;
737 map_main_t *mm = &map_main;
738 clib_error_t *error = NULL;
740 mm->icmp4_src_address.as_u32 = 0;
742 /* Get a line of input. */
743 if (!unformat_user (input, unformat_line_input, line_input))
746 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
749 (line_input, "%U", unformat_ip4_address, &icmp_src_address))
751 mm->icmp4_src_address = icmp_src_address;
752 p_icmp_addr = &icmp_src_address;
756 error = clib_error_return (0, "unknown input `%U'",
757 format_unformat_error, line_input);
762 map_param_set_icmp (p_icmp_addr);
765 unformat_free (line_input);
770 static clib_error_t *
771 map_icmp_unreachables_command_fn (vlib_main_t * vm,
772 unformat_input_t * input,
773 vlib_cli_command_t * cmd)
775 unformat_input_t _line_input, *line_input = &_line_input;
777 clib_error_t *error = NULL;
778 bool enabled = false;
780 /* Get a line of input. */
781 if (!unformat_user (input, unformat_line_input, line_input))
784 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
787 if (unformat (line_input, "on"))
789 else if (unformat (line_input, "off"))
793 error = clib_error_return (0, "unknown input `%U'",
794 format_unformat_error, line_input);
801 error = clib_error_return (0, "mandatory argument(s) missing");
804 map_param_set_icmp6 (enabled);
807 unformat_free (line_input);
813 static clib_error_t *
814 map_fragment_command_fn (vlib_main_t * vm,
815 unformat_input_t * input, vlib_cli_command_t * cmd)
817 unformat_input_t _line_input, *line_input = &_line_input;
818 clib_error_t *error = NULL;
819 bool frag_inner = false;
820 bool frag_ignore_df = false;
821 bool saw_in_out = false;
824 /* Get a line of input. */
825 if (!unformat_user (input, unformat_line_input, line_input))
828 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
830 if (unformat (line_input, "inner"))
835 else if (unformat (line_input, "outer"))
840 else if (unformat (line_input, "ignore-df"))
842 frag_ignore_df = true;
845 else if (unformat (line_input, "honor-df"))
847 frag_ignore_df = false;
852 error = clib_error_return (0, "unknown input `%U'",
853 format_unformat_error, line_input);
860 error = clib_error_return (0, "Must specify 'inner' or 'outer'");
866 error = clib_error_return (0, "Must specify 'ignore-df' or 'honor-df'");
870 map_param_set_fragmentation (frag_inner, frag_ignore_df);
873 unformat_free (line_input);
878 static clib_error_t *
879 map_traffic_class_command_fn (vlib_main_t * vm,
880 unformat_input_t * input,
881 vlib_cli_command_t * cmd)
883 unformat_input_t _line_input, *line_input = &_line_input;
885 clib_error_t *error = NULL;
886 bool tc_copy = false;
889 /* Get a line of input. */
890 if (!unformat_user (input, unformat_line_input, line_input))
893 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
895 if (unformat (line_input, "copy"))
897 else if (unformat (line_input, "%x", &tc))
901 error = clib_error_return (0, "unknown input `%U'",
902 format_unformat_error, line_input);
907 map_param_set_traffic_class (tc_copy, tc);
910 unformat_free (line_input);
916 map_flags_to_string (u32 flags)
918 if (flags & MAP_DOMAIN_PREFIX)
924 format_map_domain (u8 * s, va_list * args)
926 map_domain_t *d = va_arg (*args, map_domain_t *);
927 bool counters = va_arg (*args, int);
928 map_main_t *mm = &map_main;
929 ip6_address_t ip6_prefix;
930 u32 map_domain_index = d - mm->domains;
931 map_domain_extra_t *de;
934 clib_memset (&ip6_prefix, 0, sizeof (ip6_prefix));
936 ip6_prefix = d->ip6_prefix;
938 de = vec_elt_at_index (mm->domain_extras, map_domain_index);
941 "[%d] tag {%s} ip4-pfx %U/%d ip6-pfx %U/%d ip6-src %U/%d "
942 "ea-bits-len %d psid-offset %d psid-len %d mtu %d %s",
943 map_domain_index, de->tag,
944 format_ip4_address, &d->ip4_prefix, d->ip4_prefix_len,
945 format_ip6_address, &ip6_prefix, d->ip6_prefix_len,
946 format_ip6_address, &d->ip6_src, d->ip6_src_len,
947 d->ea_bits_len, d->psid_offset, d->psid_length, d->mtu,
948 map_flags_to_string (d->flags));
952 map_domain_counter_lock (mm);
954 vlib_get_combined_counter (&mm->domain_counters[MAP_DOMAIN_COUNTER_TX],
955 map_domain_index, &v);
956 s = format (s, " TX: %lld/%lld", v.packets, v.bytes);
957 vlib_get_combined_counter (&mm->domain_counters[MAP_DOMAIN_COUNTER_RX],
958 map_domain_index, &v);
959 s = format (s, " RX: %lld/%lld", v.packets, v.bytes);
960 map_domain_counter_unlock (mm);
962 s = format (s, "\n");
968 for (i = 0; i < (0x1 << d->psid_length); i++)
971 if (dst.as_u64[0] == 0 && dst.as_u64[1] == 0)
974 " rule psid: %d ip6-dst %U\n", i, format_ip6_address,
982 format_map_ip4_reass (u8 * s, va_list * args)
984 map_main_t *mm = &map_main;
985 map_ip4_reass_t *r = va_arg (*args, map_ip4_reass_t *);
986 map_ip4_reass_key_t *k = &r->key;
987 f64 now = vlib_time_now (mm->vlib_main);
988 f64 lifetime = (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000);
989 f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
991 "ip4-reass src=%U dst=%U protocol=%d identifier=%d port=%d lifetime=%.3lf\n",
992 format_ip4_address, &k->src.as_u8, format_ip4_address,
993 &k->dst.as_u8, k->protocol,
994 clib_net_to_host_u16 (k->fragment_id),
995 (r->port >= 0) ? clib_net_to_host_u16 (r->port) : -1, dt);
1000 format_map_ip6_reass (u8 * s, va_list * args)
1002 map_main_t *mm = &map_main;
1003 map_ip6_reass_t *r = va_arg (*args, map_ip6_reass_t *);
1004 map_ip6_reass_key_t *k = &r->key;
1005 f64 now = vlib_time_now (mm->vlib_main);
1006 f64 lifetime = (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000);
1007 f64 dt = (r->ts + lifetime > now) ? (r->ts + lifetime - now) : -1;
1009 "ip6-reass src=%U dst=%U protocol=%d identifier=%d lifetime=%.3lf\n",
1010 format_ip6_address, &k->src.as_u8, format_ip6_address,
1011 &k->dst.as_u8, k->protocol,
1012 clib_net_to_host_u32 (k->fragment_id), dt);
1016 static clib_error_t *
1017 show_map_domain_command_fn (vlib_main_t * vm, unformat_input_t * input,
1018 vlib_cli_command_t * cmd)
1020 unformat_input_t _line_input, *line_input = &_line_input;
1021 map_main_t *mm = &map_main;
1023 bool counters = false;
1024 u32 map_domain_index = ~0;
1025 clib_error_t *error = NULL;
1027 /* Get a line of input. */
1028 if (!unformat_user (input, unformat_line_input, line_input))
1031 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1033 if (unformat (line_input, "counters"))
1035 else if (unformat (line_input, "index %d", &map_domain_index))
1039 error = clib_error_return (0, "unknown input `%U'",
1040 format_unformat_error, line_input);
1045 if (pool_elts (mm->domains) == 0)
1046 vlib_cli_output (vm, "No MAP domains are configured...");
1048 if (map_domain_index == ~0)
1051 pool_foreach(d, mm->domains,
1052 ({vlib_cli_output(vm, "%U", format_map_domain, d, counters);}));
1057 if (pool_is_free_index (mm->domains, map_domain_index))
1059 error = clib_error_return (0, "MAP domain does not exists %d",
1064 d = pool_elt_at_index (mm->domains, map_domain_index);
1065 vlib_cli_output (vm, "%U", format_map_domain, d, counters);
1069 unformat_free (line_input);
1074 static clib_error_t *
1075 show_map_fragments_command_fn (vlib_main_t * vm, unformat_input_t * input,
1076 vlib_cli_command_t * cmd)
1078 map_main_t *mm = &map_main;
1079 map_ip4_reass_t *f4;
1080 map_ip6_reass_t *f6;
1083 pool_foreach(f4, mm->ip4_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip4_reass, f4);}));
1086 pool_foreach(f6, mm->ip6_reass_pool, ({vlib_cli_output (vm, "%U", format_map_ip6_reass, f6);}));
1092 map_error_counter_get (u32 node_index, map_error_t map_error)
1094 vlib_main_t *vm = vlib_get_main ();
1095 vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, node_index);
1096 vlib_error_main_t *em = &vm->error_main;
1097 vlib_error_t e = error_node->errors[map_error];
1098 vlib_node_t *n = vlib_get_node (vm, node_index);
1101 ci = vlib_error_get_code (e);
1102 ASSERT (ci < n->n_errors);
1103 ci += n->error_heap_index;
1105 return (em->counters[ci]);
1108 static clib_error_t *
1109 show_map_stats_command_fn (vlib_main_t * vm, unformat_input_t * input,
1110 vlib_cli_command_t * cmd)
1112 map_main_t *mm = &map_main;
1114 int domains = 0, rules = 0, domaincount = 0, rulecount = 0;
1115 if (pool_elts (mm->domains) == 0)
1117 vlib_cli_output (vm, "No MAP domains are configured...");
1122 pool_foreach(d, mm->domains, ({
1124 rulecount+= 0x1 << d->psid_length;
1125 rules += sizeof(ip6_address_t) * 0x1 << d->psid_length;
1127 domains += sizeof(*d);
1132 vlib_cli_output (vm, "MAP domains structure: %d\n", sizeof (map_domain_t));
1133 vlib_cli_output (vm, "MAP domains: %d (%d bytes)\n", domaincount, domains);
1134 vlib_cli_output (vm, "MAP rules: %d (%d bytes)\n", rulecount, rules);
1135 vlib_cli_output (vm, "Total: %d bytes)\n", rules + domains);
1137 #if MAP_SKIP_IP6_LOOKUP
1138 vlib_cli_output (vm,
1139 "MAP pre-resolve: IP6 next-hop: %U, IP4 next-hop: %U\n",
1140 format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP6],
1141 format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP4]);
1146 vlib_cli_output (vm, "MAP traffic-class: copy");
1148 vlib_cli_output (vm, "MAP traffic-class: %x", mm->tc);
1151 vlib_cli_output (vm, "MAP TCP MSS clamping: %u", mm->tcp_mss);
1153 vlib_cli_output (vm,
1154 "MAP IPv6 inbound security check: %s, fragmented packet security check: %s",
1155 mm->sec_check ? "enabled" : "disabled",
1156 mm->sec_check_frag ? "enabled" : "disabled");
1158 vlib_cli_output (vm, "ICMP-relay IPv4 source address: %U\n",
1159 format_ip4_address, &mm->icmp4_src_address);
1160 vlib_cli_output (vm, "ICMP6 unreachables sent for unmatched packets: %s\n",
1161 mm->icmp6_enabled ? "enabled" : "disabled");
1162 vlib_cli_output (vm, "Inner fragmentation: %s\n",
1163 mm->frag_inner ? "enabled" : "disabled");
1164 vlib_cli_output (vm, "Fragment packets regardless of DF flag: %s\n",
1165 mm->frag_ignore_df ? "enabled" : "disabled");
1170 vlib_combined_counter_main_t *cm = mm->domain_counters;
1171 u64 total_pkts[MAP_N_DOMAIN_COUNTER];
1172 u64 total_bytes[MAP_N_DOMAIN_COUNTER];
1176 clib_memset (total_pkts, 0, sizeof (total_pkts));
1177 clib_memset (total_bytes, 0, sizeof (total_bytes));
1179 map_domain_counter_lock (mm);
1180 vec_foreach (cm, mm->domain_counters)
1182 which = cm - mm->domain_counters;
1184 for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
1186 vlib_get_combined_counter (cm, i, &v);
1187 total_pkts[which] += v.packets;
1188 total_bytes[which] += v.bytes;
1191 map_domain_counter_unlock (mm);
1193 vlib_cli_output (vm, "Encapsulated packets: %lld bytes: %lld\n",
1194 total_pkts[MAP_DOMAIN_COUNTER_TX],
1195 total_bytes[MAP_DOMAIN_COUNTER_TX]);
1196 vlib_cli_output (vm, "Decapsulated packets: %lld bytes: %lld\n",
1197 total_pkts[MAP_DOMAIN_COUNTER_RX],
1198 total_bytes[MAP_DOMAIN_COUNTER_RX]);
1200 vlib_cli_output (vm, "ICMP relayed packets: %d\n",
1201 vlib_get_simple_counter (&mm->icmp_relayed, 0));
1206 static clib_error_t *
1207 map_params_reass_command_fn (vlib_main_t * vm, unformat_input_t * input,
1208 vlib_cli_command_t * cmd)
1210 unformat_input_t _line_input, *line_input = &_line_input;
1212 f64 ht_ratio = (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1);
1214 u64 buffers = ~(0ull);
1215 u8 ip4 = 0, ip6 = 0;
1217 if (!unformat_user (input, unformat_line_input, line_input))
1220 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1222 if (unformat (line_input, "lifetime %u", &lifetime))
1224 else if (unformat (line_input, "ht-ratio %lf", &ht_ratio))
1226 else if (unformat (line_input, "pool-size %u", &pool_size))
1228 else if (unformat (line_input, "buffers %llu", &buffers))
1230 else if (unformat (line_input, "ip4"))
1232 else if (unformat (line_input, "ip6"))
1236 unformat_free (line_input);
1237 return clib_error_return (0, "invalid input");
1240 unformat_free (line_input);
1243 return clib_error_return (0, "must specify ip4 and/or ip6");
1247 if (pool_size != ~0 && pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1248 return clib_error_return (0, "invalid ip4-reass pool-size ( > %d)",
1249 MAP_IP4_REASS_CONF_POOL_SIZE_MAX);
1250 if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1251 && ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1252 return clib_error_return (0, "invalid ip4-reass ht-ratio ( > %d)",
1253 MAP_IP4_REASS_CONF_HT_RATIO_MAX);
1254 if (lifetime != ~0 && lifetime > MAP_IP4_REASS_CONF_LIFETIME_MAX)
1255 return clib_error_return (0, "invalid ip4-reass lifetime ( > %d)",
1256 MAP_IP4_REASS_CONF_LIFETIME_MAX);
1257 if (buffers != ~(0ull) && buffers > MAP_IP4_REASS_CONF_BUFFERS_MAX)
1258 return clib_error_return (0, "invalid ip4-reass buffers ( > %ld)",
1259 MAP_IP4_REASS_CONF_BUFFERS_MAX);
1264 if (pool_size != ~0 && pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1265 return clib_error_return (0, "invalid ip6-reass pool-size ( > %d)",
1266 MAP_IP6_REASS_CONF_POOL_SIZE_MAX);
1267 if (ht_ratio != (MAP_IP4_REASS_CONF_HT_RATIO_MAX + 1)
1268 && ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1269 return clib_error_return (0, "invalid ip6-reass ht-log2len ( > %d)",
1270 MAP_IP6_REASS_CONF_HT_RATIO_MAX);
1271 if (lifetime != ~0 && lifetime > MAP_IP6_REASS_CONF_LIFETIME_MAX)
1272 return clib_error_return (0, "invalid ip6-reass lifetime ( > %d)",
1273 MAP_IP6_REASS_CONF_LIFETIME_MAX);
1274 if (buffers != ~(0ull) && buffers > MAP_IP6_REASS_CONF_BUFFERS_MAX)
1275 return clib_error_return (0, "invalid ip6-reass buffers ( > %ld)",
1276 MAP_IP6_REASS_CONF_BUFFERS_MAX);
1280 u32 reass = 0, packets = 0;
1281 rv = map_param_set_reassembly (!ip4, lifetime, pool_size, buffers, ht_ratio,
1287 vlib_cli_output (vm,
1288 "Note: destroyed-reassembly=%u , dropped-fragments=%u",
1292 case MAP_ERR_BAD_POOL_SIZE:
1293 return clib_error_return (0, "Could not set reass pool-size");
1295 case MAP_ERR_BAD_HT_RATIO:
1296 return clib_error_return (0, "Could not set reass ht-log2len");
1298 case MAP_ERR_BAD_LIFETIME:
1299 return clib_error_return (0, "Could not set ip6-reass lifetime");
1301 case MAP_ERR_BAD_BUFFERS:
1302 return clib_error_return (0, "Could not set ip6-reass buffers");
1304 case MAP_ERR_BAD_BUFFERS_TOO_LARGE:
1305 return clib_error_return (0,
1306 "Note: 'ip6-reass buffers' > pool-size * max-fragments-per-reassembly.");
1313 static clib_error_t *
1314 map_if_command_fn (vlib_main_t * vm,
1315 unformat_input_t * input, vlib_cli_command_t * cmd)
1317 unformat_input_t _line_input, *line_input = &_line_input;
1318 clib_error_t *error = NULL;
1319 bool is_enable = true, is_translation = false;
1320 vnet_main_t *vnm = vnet_get_main ();
1321 u32 sw_if_index = ~0;
1323 /* Get a line of input. */
1324 if (!unformat_user (input, unformat_line_input, line_input))
1327 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1330 (line_input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1332 else if (unformat (line_input, "del"))
1334 else if (unformat (line_input, "map-t"))
1335 is_translation = true;
1338 error = clib_error_return (0, "unknown input `%U'",
1339 format_unformat_error, line_input);
1345 unformat_free (line_input);
1347 if (sw_if_index == ~0)
1349 error = clib_error_return (0, "unknown interface");
1353 int rv = map_if_enable_disable (is_enable, sw_if_index, is_translation);
1356 error = clib_error_return (0, "failure enabling MAP on interface");
1364 * packet trace format function
1367 format_map_trace (u8 * s, va_list * args)
1369 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1370 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1371 map_trace_t *t = va_arg (*args, map_trace_t *);
1372 u32 map_domain_index = t->map_domain_index;
1376 format (s, "MAP domain index: %d L4 port: %u", map_domain_index,
1377 clib_net_to_host_u16 (port));
1382 static_always_inline map_ip4_reass_t *
1383 map_ip4_reass_lookup (map_ip4_reass_key_t * k, u32 bucket, f64 now)
1385 map_main_t *mm = &map_main;
1386 u32 ri = mm->ip4_reass_hash_table[bucket];
1387 while (ri != MAP_REASS_INDEX_NONE)
1389 map_ip4_reass_t *r = pool_elt_at_index (mm->ip4_reass_pool, ri);
1390 if (r->key.as_u64[0] == k->as_u64[0] &&
1391 r->key.as_u64[1] == k->as_u64[1] &&
1392 now < r->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000))
1396 ri = r->bucket_next;
1401 #define map_ip4_reass_pool_index(r) (r - map_main.ip4_reass_pool)
1404 map_ip4_reass_free (map_ip4_reass_t * r, u32 ** pi_to_drop)
1406 map_main_t *mm = &map_main;
1407 map_ip4_reass_get_fragments (r, pi_to_drop);
1409 // Unlink in hash bucket
1410 map_ip4_reass_t *r2 = NULL;
1411 u32 r2i = mm->ip4_reass_hash_table[r->bucket];
1412 while (r2i != map_ip4_reass_pool_index (r))
1414 ASSERT (r2i != MAP_REASS_INDEX_NONE);
1415 r2 = pool_elt_at_index (mm->ip4_reass_pool, r2i);
1416 r2i = r2->bucket_next;
1420 r2->bucket_next = r->bucket_next;
1424 mm->ip4_reass_hash_table[r->bucket] = r->bucket_next;
1428 if (r->fifo_next == map_ip4_reass_pool_index (r))
1430 mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
1434 if (mm->ip4_reass_fifo_last == map_ip4_reass_pool_index (r))
1435 mm->ip4_reass_fifo_last = r->fifo_prev;
1436 pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next =
1438 pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev =
1442 pool_put (mm->ip4_reass_pool, r);
1443 mm->ip4_reass_allocated--;
1447 map_ip4_reass_get (u32 src, u32 dst, u16 fragment_id,
1448 u8 protocol, u32 ** pi_to_drop)
1451 map_main_t *mm = &map_main;
1452 map_ip4_reass_key_t k = {.src.data_u32 = src,
1453 .dst.data_u32 = dst,
1454 .fragment_id = fragment_id,
1455 .protocol = protocol
1459 #ifdef clib_crc32c_uses_intrinsics
1460 h = clib_crc32c ((u8 *) k.as_u32, 16);
1462 u64 tmp = k.as_u32[0] ^ k.as_u32[1] ^ k.as_u32[2] ^ k.as_u32[3];
1463 h = clib_xxhash (tmp);
1465 h = h >> (32 - mm->ip4_reass_ht_log2len);
1467 f64 now = vlib_time_now (mm->vlib_main);
1469 //Cache garbage collection
1470 while (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
1472 map_ip4_reass_t *last =
1473 pool_elt_at_index (mm->ip4_reass_pool, mm->ip4_reass_fifo_last);
1474 if (last->ts + (((f64) mm->ip4_reass_conf_lifetime_ms) / 1000) < now)
1475 map_ip4_reass_free (last, pi_to_drop);
1480 if ((r = map_ip4_reass_lookup (&k, h, now)))
1483 if (mm->ip4_reass_allocated >= mm->ip4_reass_conf_pool_size)
1486 pool_get (mm->ip4_reass_pool, r);
1487 mm->ip4_reass_allocated++;
1489 for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1490 r->fragments[i] = ~0;
1492 u32 ri = map_ip4_reass_pool_index (r);
1494 //Link in new bucket
1496 r->bucket_next = mm->ip4_reass_hash_table[h];
1497 mm->ip4_reass_hash_table[h] = ri;
1500 if (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
1503 pool_elt_at_index (mm->ip4_reass_pool,
1504 mm->ip4_reass_fifo_last)->fifo_next;
1505 r->fifo_prev = mm->ip4_reass_fifo_last;
1506 pool_elt_at_index (mm->ip4_reass_pool, r->fifo_prev)->fifo_next = ri;
1507 pool_elt_at_index (mm->ip4_reass_pool, r->fifo_next)->fifo_prev = ri;
1511 r->fifo_next = r->fifo_prev = ri;
1512 mm->ip4_reass_fifo_last = ri;
1519 #ifdef MAP_IP4_REASS_COUNT_BYTES
1520 r->expected_total = 0xffff;
1528 map_ip4_reass_add_fragment (map_ip4_reass_t * r, u32 pi)
1530 if (map_main.ip4_reass_buffered_counter >= map_main.ip4_reass_conf_buffers)
1534 for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1535 if (r->fragments[i] == ~0)
1537 r->fragments[i] = pi;
1538 map_main.ip4_reass_buffered_counter++;
1544 static_always_inline map_ip6_reass_t *
1545 map_ip6_reass_lookup (map_ip6_reass_key_t * k, u32 bucket, f64 now)
1547 map_main_t *mm = &map_main;
1548 u32 ri = mm->ip6_reass_hash_table[bucket];
1549 while (ri != MAP_REASS_INDEX_NONE)
1551 map_ip6_reass_t *r = pool_elt_at_index (mm->ip6_reass_pool, ri);
1552 if (now < r->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) &&
1553 r->key.as_u64[0] == k->as_u64[0] &&
1554 r->key.as_u64[1] == k->as_u64[1] &&
1555 r->key.as_u64[2] == k->as_u64[2] &&
1556 r->key.as_u64[3] == k->as_u64[3] &&
1557 r->key.as_u64[4] == k->as_u64[4])
1559 ri = r->bucket_next;
1564 #define map_ip6_reass_pool_index(r) (r - map_main.ip6_reass_pool)
1567 map_ip6_reass_free (map_ip6_reass_t * r, u32 ** pi_to_drop)
1569 map_main_t *mm = &map_main;
1571 for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1572 if (r->fragments[i].pi != ~0)
1574 vec_add1 (*pi_to_drop, r->fragments[i].pi);
1575 r->fragments[i].pi = ~0;
1576 map_main.ip6_reass_buffered_counter--;
1579 // Unlink in hash bucket
1580 map_ip6_reass_t *r2 = NULL;
1581 u32 r2i = mm->ip6_reass_hash_table[r->bucket];
1582 while (r2i != map_ip6_reass_pool_index (r))
1584 ASSERT (r2i != MAP_REASS_INDEX_NONE);
1585 r2 = pool_elt_at_index (mm->ip6_reass_pool, r2i);
1586 r2i = r2->bucket_next;
1590 r2->bucket_next = r->bucket_next;
1594 mm->ip6_reass_hash_table[r->bucket] = r->bucket_next;
1598 if (r->fifo_next == map_ip6_reass_pool_index (r))
1600 //Single element in the list, list is now empty
1601 mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
1605 if (mm->ip6_reass_fifo_last == map_ip6_reass_pool_index (r)) //First element
1606 mm->ip6_reass_fifo_last = r->fifo_prev;
1607 pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next =
1609 pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev =
1613 // Free from pool if necessary
1614 pool_put (mm->ip6_reass_pool, r);
1615 mm->ip6_reass_allocated--;
1619 map_ip6_reass_get (ip6_address_t * src, ip6_address_t * dst, u32 fragment_id,
1620 u8 protocol, u32 ** pi_to_drop)
1623 map_main_t *mm = &map_main;
1624 map_ip6_reass_key_t k = {
1627 .fragment_id = fragment_id,
1628 .protocol = protocol
1634 #ifdef clib_crc32c_uses_intrinsics
1635 h = clib_crc32c ((u8 *) k.as_u32, 40);
1638 k.as_u64[0] ^ k.as_u64[1] ^ k.as_u64[2] ^ k.as_u64[3] ^ k.as_u64[4];
1639 h = clib_xxhash (tmp);
1642 h = h >> (32 - mm->ip6_reass_ht_log2len);
1644 f64 now = vlib_time_now (mm->vlib_main);
1646 //Cache garbage collection
1647 while (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
1649 map_ip6_reass_t *last =
1650 pool_elt_at_index (mm->ip6_reass_pool, mm->ip6_reass_fifo_last);
1651 if (last->ts + (((f64) mm->ip6_reass_conf_lifetime_ms) / 1000) < now)
1652 map_ip6_reass_free (last, pi_to_drop);
1657 if ((r = map_ip6_reass_lookup (&k, h, now)))
1660 if (mm->ip6_reass_allocated >= mm->ip6_reass_conf_pool_size)
1663 pool_get (mm->ip6_reass_pool, r);
1664 mm->ip6_reass_allocated++;
1665 for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1667 r->fragments[i].pi = ~0;
1668 r->fragments[i].next_data_len = 0;
1669 r->fragments[i].next_data_offset = 0;
1672 u32 ri = map_ip6_reass_pool_index (r);
1674 //Link in new bucket
1676 r->bucket_next = mm->ip6_reass_hash_table[h];
1677 mm->ip6_reass_hash_table[h] = ri;
1680 if (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
1683 pool_elt_at_index (mm->ip6_reass_pool,
1684 mm->ip6_reass_fifo_last)->fifo_next;
1685 r->fifo_prev = mm->ip6_reass_fifo_last;
1686 pool_elt_at_index (mm->ip6_reass_pool, r->fifo_prev)->fifo_next = ri;
1687 pool_elt_at_index (mm->ip6_reass_pool, r->fifo_next)->fifo_prev = ri;
1691 r->fifo_next = r->fifo_prev = ri;
1692 mm->ip6_reass_fifo_last = ri;
1698 r->ip4_header.ip_version_and_header_length = 0;
1699 #ifdef MAP_IP6_REASS_COUNT_BYTES
1700 r->expected_total = 0xffff;
1707 map_ip6_reass_add_fragment (map_ip6_reass_t * r, u32 pi,
1708 u16 data_offset, u16 next_data_offset,
1709 u8 * data_start, u16 data_len)
1711 map_ip6_fragment_t *f = NULL, *prev_f = NULL;
1712 u16 copied_len = (data_len > 20) ? 20 : data_len;
1714 if (map_main.ip6_reass_buffered_counter >= map_main.ip6_reass_conf_buffers)
1717 //Lookup for fragments for the current buffer
1718 //and the one before that
1720 for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1722 if (data_offset && r->fragments[i].next_data_offset == data_offset)
1724 prev_f = &r->fragments[i]; // This is buffer for previous packet
1726 else if (r->fragments[i].next_data_offset == next_data_offset)
1728 f = &r->fragments[i]; // This is a buffer for the current packet
1730 else if (r->fragments[i].next_data_offset == 0)
1733 f = &r->fragments[i];
1734 else if (prev_f == NULL)
1735 prev_f = &r->fragments[i];
1739 if (!f || f->pi != ~0)
1747 clib_memcpy_fast (prev_f->next_data, data_start, copied_len);
1748 prev_f->next_data_len = copied_len;
1749 prev_f->next_data_offset = data_offset;
1753 if (((ip4_header_t *) data_start)->ip_version_and_header_length != 0x45)
1756 if (r->ip4_header.ip_version_and_header_length == 0)
1757 clib_memcpy_fast (&r->ip4_header, data_start, sizeof (ip4_header_t));
1762 f->next_data_offset = next_data_offset;
1764 map_main.ip6_reass_buffered_counter++;
1770 map_ip4_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1772 map_main_t *mm = &map_main;
1775 if (dropped_packets)
1776 *dropped_packets = mm->ip4_reass_buffered_counter;
1778 *trashed_reass = mm->ip4_reass_allocated;
1779 if (mm->ip4_reass_fifo_last != MAP_REASS_INDEX_NONE)
1781 u16 ri = mm->ip4_reass_fifo_last;
1784 map_ip4_reass_t *r = pool_elt_at_index (mm->ip4_reass_pool, ri);
1785 for (i = 0; i < MAP_IP4_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1786 if (r->fragments[i] != ~0)
1787 map_ip4_drop_pi (r->fragments[i]);
1790 pool_put (mm->ip4_reass_pool, r);
1792 while (ri != mm->ip4_reass_fifo_last);
1795 vec_free (mm->ip4_reass_hash_table);
1796 vec_resize (mm->ip4_reass_hash_table, 1 << mm->ip4_reass_ht_log2len);
1797 for (i = 0; i < (1 << mm->ip4_reass_ht_log2len); i++)
1798 mm->ip4_reass_hash_table[i] = MAP_REASS_INDEX_NONE;
1799 pool_free (mm->ip4_reass_pool);
1800 pool_alloc (mm->ip4_reass_pool, mm->ip4_reass_conf_pool_size);
1802 mm->ip4_reass_allocated = 0;
1803 mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
1804 mm->ip4_reass_buffered_counter = 0;
1808 map_get_ht_log2len (f32 ht_ratio, u16 pool_size)
1810 u32 desired_size = (u32) (pool_size * ht_ratio);
1812 for (i = 1; i < 31; i++)
1813 if ((1 << i) >= desired_size)
1819 map_ip4_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1820 u32 * dropped_packets)
1822 map_main_t *mm = &map_main;
1823 if (ht_ratio > MAP_IP4_REASS_CONF_HT_RATIO_MAX)
1826 map_ip4_reass_lock ();
1827 mm->ip4_reass_conf_ht_ratio = ht_ratio;
1828 mm->ip4_reass_ht_log2len =
1829 map_get_ht_log2len (ht_ratio, mm->ip4_reass_conf_pool_size);
1830 map_ip4_reass_reinit (trashed_reass, dropped_packets);
1831 map_ip4_reass_unlock ();
1836 map_ip4_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1837 u32 * dropped_packets)
1839 map_main_t *mm = &map_main;
1840 if (pool_size > MAP_IP4_REASS_CONF_POOL_SIZE_MAX)
1843 map_ip4_reass_lock ();
1844 mm->ip4_reass_conf_pool_size = pool_size;
1845 map_ip4_reass_reinit (trashed_reass, dropped_packets);
1846 map_ip4_reass_unlock ();
1851 map_ip4_reass_conf_lifetime (u16 lifetime_ms)
1853 map_main.ip4_reass_conf_lifetime_ms = lifetime_ms;
1858 map_ip4_reass_conf_buffers (u32 buffers)
1860 map_main.ip4_reass_conf_buffers = buffers;
1865 map_ip6_reass_reinit (u32 * trashed_reass, u32 * dropped_packets)
1867 map_main_t *mm = &map_main;
1868 if (dropped_packets)
1869 *dropped_packets = mm->ip6_reass_buffered_counter;
1871 *trashed_reass = mm->ip6_reass_allocated;
1873 if (mm->ip6_reass_fifo_last != MAP_REASS_INDEX_NONE)
1875 u16 ri = mm->ip6_reass_fifo_last;
1878 map_ip6_reass_t *r = pool_elt_at_index (mm->ip6_reass_pool, ri);
1879 for (i = 0; i < MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY; i++)
1880 if (r->fragments[i].pi != ~0)
1881 map_ip6_drop_pi (r->fragments[i].pi);
1884 pool_put (mm->ip6_reass_pool, r);
1886 while (ri != mm->ip6_reass_fifo_last);
1887 mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
1890 vec_free (mm->ip6_reass_hash_table);
1891 vec_resize (mm->ip6_reass_hash_table, 1 << mm->ip6_reass_ht_log2len);
1892 for (i = 0; i < (1 << mm->ip6_reass_ht_log2len); i++)
1893 mm->ip6_reass_hash_table[i] = MAP_REASS_INDEX_NONE;
1894 pool_free (mm->ip6_reass_pool);
1895 pool_alloc (mm->ip6_reass_pool, mm->ip4_reass_conf_pool_size);
1897 mm->ip6_reass_allocated = 0;
1898 mm->ip6_reass_buffered_counter = 0;
1902 map_ip6_reass_conf_ht_ratio (f32 ht_ratio, u32 * trashed_reass,
1903 u32 * dropped_packets)
1905 map_main_t *mm = &map_main;
1906 if (ht_ratio > MAP_IP6_REASS_CONF_HT_RATIO_MAX)
1909 map_ip6_reass_lock ();
1910 mm->ip6_reass_conf_ht_ratio = ht_ratio;
1911 mm->ip6_reass_ht_log2len =
1912 map_get_ht_log2len (ht_ratio, mm->ip6_reass_conf_pool_size);
1913 map_ip6_reass_reinit (trashed_reass, dropped_packets);
1914 map_ip6_reass_unlock ();
1919 map_ip6_reass_conf_pool_size (u16 pool_size, u32 * trashed_reass,
1920 u32 * dropped_packets)
1922 map_main_t *mm = &map_main;
1923 if (pool_size > MAP_IP6_REASS_CONF_POOL_SIZE_MAX)
1926 map_ip6_reass_lock ();
1927 mm->ip6_reass_conf_pool_size = pool_size;
1928 map_ip6_reass_reinit (trashed_reass, dropped_packets);
1929 map_ip6_reass_unlock ();
1934 map_ip6_reass_conf_lifetime (u16 lifetime_ms)
1936 map_main.ip6_reass_conf_lifetime_ms = lifetime_ms;
1941 map_ip6_reass_conf_buffers (u32 buffers)
1943 map_main.ip6_reass_conf_buffers = buffers;
1947 static clib_error_t *
1948 map_tcp_mss_command_fn (vlib_main_t * vm,
1949 unformat_input_t * input, vlib_cli_command_t * cmd)
1951 unformat_input_t _line_input, *line_input = &_line_input;
1952 clib_error_t *error = NULL;
1955 /* Get a line of input. */
1956 if (!unformat_user (input, unformat_line_input, line_input))
1959 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1961 if (unformat (line_input, "%u", &tcp_mss))
1965 error = clib_error_return (0, "unknown input `%U'",
1966 format_unformat_error, line_input);
1971 if (tcp_mss >= (0x1 << 16))
1973 error = clib_error_return (0, "invalid value `%u'", tcp_mss);
1977 map_param_set_tcp (tcp_mss);
1980 unformat_free (line_input);
1989 * Configure MAP reassembly behaviour
1992 * @cliexstart{map params reassembly}
1995 VLIB_CLI_COMMAND(map_ip4_reass_lifetime_command, static) = {
1996 .path = "map params reassembly",
1997 .short_help = "map params reassembly [ip4 | ip6] [lifetime <lifetime-ms>] "
1998 "[pool-size <pool-size>] [buffers <buffers>] "
1999 "[ht-ratio <ht-ratio>]",
2000 .function = map_params_reass_command_fn,
2004 * Set or copy the IP TOS/Traffic Class field
2007 * @cliexstart{map params traffic-class}
2009 * This command is used to set the traffic-class field in translated
2010 * or encapsulated packets. If copy is specifed (the default) then the
2011 * traffic-class/TOS field is copied from the original packet to the
2012 * translated / encapsulating header.
2015 VLIB_CLI_COMMAND(map_traffic_class_command, static) = {
2016 .path = "map params traffic-class",
2017 .short_help = "map params traffic-class {0x0-0xff | copy}",
2018 .function = map_traffic_class_command_fn,
2025 * @cliexstart{map params tcp-mss}
2027 * This command is used to set the TCP MSS in translated
2028 * or encapsulated packets.
2031 VLIB_CLI_COMMAND(map_tcp_mss_command, static) = {
2032 .path = "map params tcp-mss",
2033 .short_help = "map params tcp-mss <value>",
2034 .function = map_tcp_mss_command_fn,
2038 * Bypass IP4/IP6 lookup
2041 * @cliexstart{map params pre-resolve}
2043 * Bypass a second FIB lookup of the translated or encapsulated
2044 * packet, and forward the packet directly to the specified
2045 * next-hop. This optimization trades forwarding flexibility for
2049 VLIB_CLI_COMMAND(map_pre_resolve_command, static) = {
2050 .path = "map params pre-resolve",
2051 .short_help = " map params pre-resolve {ip4-nh <address>} "
2052 "| {ip6-nh <address>}",
2053 .function = map_pre_resolve_command_fn,
2057 * Enable or disable the MAP-E inbound security check
2058 * Specifiy if the inbound security check should be done on fragments
2061 * @cliexstart{map params security-check}
2063 * By default, a decapsulated packet's IPv4 source address will be
2064 * verified against the outer header's IPv6 source address. Disabling
2065 * this feature will allow IPv4 source address spoofing.
2067 * Typically the inbound on-decapsulation security check is only done
2068 * on the first packet. The packet that contains the L4
2069 * information. While a security check on every fragment is possible,
2070 * it has a cost. State must be created on the first fragment.
2073 VLIB_CLI_COMMAND(map_security_check_command, static) = {
2074 .path = "map params security-check",
2075 .short_help = "map params security-check enable|disable fragments on|off",
2076 .function = map_security_check_command_fn,
2081 * Specifiy the IPv4 source address used for relayed ICMP error messages
2084 * @cliexstart{map params icmp source-address}
2086 * This command specifies which IPv4 source address (must be local to
2087 * the system), that is used for relayed received IPv6 ICMP error
2091 VLIB_CLI_COMMAND(map_icmp_relay_source_address_command, static) = {
2092 .path = "map params icmp source-address",
2093 .short_help = "map params icmp source-address <ip4-address>",
2094 .function = map_icmp_relay_source_address_command_fn,
2098 * Send IPv6 ICMP unreachables
2101 * @cliexstart{map params icmp6 unreachables}
2103 * Send IPv6 ICMP unreachable messages back if security check fails or
2104 * no MAP domain exists.
2107 VLIB_CLI_COMMAND(map_icmp_unreachables_command, static) = {
2108 .path = "map params icmp6 unreachables",
2109 .short_help = "map params icmp6 unreachables {on|off}",
2110 .function = map_icmp_unreachables_command_fn,
2114 * Configure MAP fragmentation behaviour
2117 * @cliexstart{map params fragment}
2119 * Allows fragmentation of the IPv4 packet even if the DF bit is
2120 * set. The choice between inner or outer fragmentation of tunnel
2121 * packets is complicated. The benefit of inner fragmentation is that
2122 * the ultimate endpoint must reassemble, instead of the tunnel
2126 VLIB_CLI_COMMAND(map_fragment_command, static) = {
2127 .path = "map params fragment",
2128 .short_help = "map params fragment inner|outer ignore-df|honor-df",
2129 .function = map_fragment_command_fn,
2137 * @cliexstart{map add domain}
2140 VLIB_CLI_COMMAND(map_add_domain_command, static) = {
2141 .path = "map add domain",
2142 .short_help = "map add domain [tag <tag>] ip4-pfx <ip4-pfx> "
2143 "ip6-pfx <ip6-pfx> "
2144 "ip6-src <ip6-pfx> ea-bits-len <n> psid-offset <n> psid-len <n> "
2145 "[map-t] [mtu <mtu>]",
2146 .function = map_add_domain_command_fn,
2150 * Add MAP rule to a domain
2153 * @cliexstart{map add rule}
2156 VLIB_CLI_COMMAND(map_add_rule_command, static) = {
2157 .path = "map add rule",
2158 .short_help = "map add rule index <domain> psid <psid> ip6-dst <ip6-addr>",
2159 .function = map_add_rule_command_fn,
2166 * @cliexstart{map del domain}
2169 VLIB_CLI_COMMAND(map_del_command, static) = {
2170 .path = "map del domain",
2171 .short_help = "map del domain index <domain>",
2172 .function = map_del_domain_command_fn,
2179 * @cliexstart{show map domain}
2182 VLIB_CLI_COMMAND(show_map_domain_command, static) = {
2183 .path = "show map domain",
2184 .short_help = "show map domain index <n> [counters]",
2185 .function = show_map_domain_command_fn,
2189 * Show MAP statistics
2192 * @cliexstart{show map stats}
2195 VLIB_CLI_COMMAND(show_map_stats_command, static) = {
2196 .path = "show map stats",
2197 .short_help = "show map stats",
2198 .function = show_map_stats_command_fn,
2202 * Show MAP fragmentation information
2205 * @cliexstart{show map fragments}
2208 VLIB_CLI_COMMAND(show_map_fragments_command, static) = {
2209 .path = "show map fragments",
2210 .short_help = "show map fragments",
2211 .function = show_map_fragments_command_fn,
2215 * Enable MAP processing on interface (input feature)
2218 VLIB_CLI_COMMAND(map_if_command, static) = {
2219 .path = "map interface",
2220 .short_help = "map interface <interface-name> [map-t] [del]",
2221 .function = map_if_command_fn,
2224 VLIB_PLUGIN_REGISTER() = {
2225 .version = VPP_BUILD_VER,
2226 .description = "Mapping of address and port (MAP)",
2235 map_init (vlib_main_t * vm)
2237 map_main_t *mm = &map_main;
2238 clib_error_t *error = 0;
2240 memset (mm, 0, sizeof (*mm));
2242 mm->vnet_main = vnet_get_main ();
2245 #ifdef MAP_SKIP_IP6_LOOKUP
2246 fib_protocol_t proto;
2248 FOR_EACH_FIB_PROTOCOL (proto)
2250 map_pre_resolve_init (&pre_resolved[proto]);
2258 /* Inbound security check */
2259 mm->sec_check = true;
2260 mm->sec_check_frag = false;
2262 /* ICMP6 Type 1, Code 5 for security check failure */
2263 mm->icmp6_enabled = false;
2265 /* Inner or outer fragmentation */
2266 mm->frag_inner = false;
2267 mm->frag_ignore_df = false;
2269 vec_validate (mm->domain_counters, MAP_N_DOMAIN_COUNTER - 1);
2270 mm->domain_counters[MAP_DOMAIN_COUNTER_RX].name = "/map/rx";
2271 mm->domain_counters[MAP_DOMAIN_COUNTER_TX].name = "/map/tx";
2273 vlib_validate_simple_counter (&mm->icmp_relayed, 0);
2274 vlib_zero_simple_counter (&mm->icmp_relayed, 0);
2275 mm->icmp_relayed.stat_segment_name = "/map/icmp-relayed";
2277 /* IP4 virtual reassembly */
2278 mm->ip4_reass_hash_table = 0;
2279 mm->ip4_reass_pool = 0;
2280 mm->ip4_reass_lock =
2281 clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
2282 *mm->ip4_reass_lock = 0;
2283 mm->ip4_reass_conf_ht_ratio = MAP_IP4_REASS_HT_RATIO_DEFAULT;
2284 mm->ip4_reass_conf_lifetime_ms = MAP_IP4_REASS_LIFETIME_DEFAULT;
2285 mm->ip4_reass_conf_pool_size = MAP_IP4_REASS_POOL_SIZE_DEFAULT;
2286 mm->ip4_reass_conf_buffers = MAP_IP4_REASS_BUFFERS_DEFAULT;
2287 mm->ip4_reass_ht_log2len =
2288 map_get_ht_log2len (mm->ip4_reass_conf_ht_ratio,
2289 mm->ip4_reass_conf_pool_size);
2290 mm->ip4_reass_fifo_last = MAP_REASS_INDEX_NONE;
2291 map_ip4_reass_reinit (NULL, NULL);
2293 /* IP6 virtual reassembly */
2294 mm->ip6_reass_hash_table = 0;
2295 mm->ip6_reass_pool = 0;
2296 mm->ip6_reass_lock =
2297 clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
2298 *mm->ip6_reass_lock = 0;
2299 mm->ip6_reass_conf_ht_ratio = MAP_IP6_REASS_HT_RATIO_DEFAULT;
2300 mm->ip6_reass_conf_lifetime_ms = MAP_IP6_REASS_LIFETIME_DEFAULT;
2301 mm->ip6_reass_conf_pool_size = MAP_IP6_REASS_POOL_SIZE_DEFAULT;
2302 mm->ip6_reass_conf_buffers = MAP_IP6_REASS_BUFFERS_DEFAULT;
2303 mm->ip6_reass_ht_log2len =
2304 map_get_ht_log2len (mm->ip6_reass_conf_ht_ratio,
2305 mm->ip6_reass_conf_pool_size);
2306 mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
2307 map_ip6_reass_reinit (NULL, NULL);
2309 #ifdef MAP_SKIP_IP6_LOOKUP
2310 fib_node_register_type (FIB_NODE_TYPE_MAP_E, &map_vft);
2313 /* LPM lookup tables */
2314 mm->ip4_prefix_tbl = lpm_table_init (LPM_TYPE_KEY32);
2315 mm->ip6_prefix_tbl = lpm_table_init (LPM_TYPE_KEY128);
2316 mm->ip6_src_prefix_tbl = lpm_table_init (LPM_TYPE_KEY128);
2318 mm->bm_trans_enabled_by_sw_if = 0;
2319 mm->bm_encap_enabled_by_sw_if = 0;
2321 error = map_plugin_api_hookup (vm);
2326 VLIB_INIT_FUNCTION (map_init);
2329 * fd.io coding-style-patch-verification: ON
2332 * eval: (c-set-style "gnu")