2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 #include <vnet/ip/ip_frag.h>
18 #include <vnet/ip/ip4_to_ip6.h>
19 #include <vnet/ip/ip6_to_ip4.h>
20 #include <vnet/ip/reass/ip4_sv_reass.h>
24 IP6_MAP_NEXT_IP4_LOOKUP,
25 #ifdef MAP_SKIP_IP6_LOOKUP
26 IP6_MAP_NEXT_IP4_REWRITE,
28 IP6_MAP_NEXT_IP4_REASS,
29 IP6_MAP_NEXT_IP4_FRAGMENT,
30 IP6_MAP_NEXT_IP6_ICMP_RELAY,
31 IP6_MAP_NEXT_IP6_LOCAL,
37 enum ip6_map_ip6_reass_next_e
39 IP6_MAP_IP6_REASS_NEXT_IP6_MAP,
40 IP6_MAP_IP6_REASS_NEXT_DROP,
41 IP6_MAP_IP6_REASS_N_NEXT,
44 enum ip6_map_post_ip4_reass_next_e
46 IP6_MAP_POST_IP4_REASS_NEXT_IP4_LOOKUP,
47 IP6_MAP_POST_IP4_REASS_NEXT_IP4_FRAGMENT,
48 IP6_MAP_POST_IP4_REASS_NEXT_DROP,
49 IP6_MAP_POST_IP4_REASS_N_NEXT,
52 enum ip6_icmp_relay_next_e
54 IP6_ICMP_RELAY_NEXT_IP4_LOOKUP,
55 IP6_ICMP_RELAY_NEXT_DROP,
56 IP6_ICMP_RELAY_N_NEXT,
59 vlib_node_registration_t ip6_map_post_ip4_reass_node;
60 vlib_node_registration_t ip6_map_ip6_reass_node;
61 static vlib_node_registration_t ip6_map_icmp_relay_node;
68 } map_ip6_map_ip4_reass_trace_t;
71 format_ip6_map_post_ip4_reass_trace (u8 * s, va_list * args)
73 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
74 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
75 map_ip6_map_ip4_reass_trace_t *t =
76 va_arg (*args, map_ip6_map_ip4_reass_trace_t *);
77 return format (s, "MAP domain index: %d L4 port: %u Status: %s",
78 t->map_domain_index, clib_net_to_host_u16 (t->port),
79 t->cached ? "cached" : "forwarded");
87 } map_ip6_map_ip6_reass_trace_t;
90 format_ip6_map_ip6_reass_trace (u8 * s, va_list * args)
92 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
93 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
94 map_ip6_map_ip6_reass_trace_t *t =
95 va_arg (*args, map_ip6_map_ip6_reass_trace_t *);
96 return format (s, "Offset: %d Fragment length: %d Status: %s", t->offset,
97 t->frag_len, t->out ? "out" : "in");
103 static_always_inline bool
104 ip6_map_sec_check (map_domain_t * d, u16 port, ip4_header_t * ip4,
107 u16 sp4 = clib_net_to_host_u16 (port);
108 u32 sa4 = clib_net_to_host_u32 (ip4->src_address.as_u32);
109 u64 sal6 = map_get_pfx (d, sa4, sp4);
110 u64 sar6 = map_get_sfx (d, sa4, sp4);
113 (sal6 != clib_net_to_host_u64 (ip6->src_address.as_u64[0])
114 || sar6 != clib_net_to_host_u64 (ip6->src_address.as_u64[1])))
119 static_always_inline void
120 ip6_map_security_check (map_domain_t * d, vlib_buffer_t * b0,
121 ip4_header_t * ip4, ip6_header_t * ip6, u32 * next,
124 map_main_t *mm = &map_main;
125 if (d->ea_bits_len || d->rules)
127 if (d->psid_length > 0)
129 if (!ip4_is_fragment (ip4))
131 u16 port = ip4_get_port (ip4, 1);
136 ip6_map_sec_check (d, port, ip4,
137 ip6) ? MAP_ERROR_NONE :
138 MAP_ERROR_DECAP_SEC_CHECK;
142 *error = MAP_ERROR_BAD_PROTOCOL;
147 if (mm->sec_check_frag)
149 vnet_buffer (b0)->ip.reass.next_index =
150 map_main.ip4_sv_reass_custom_next_index;
151 *next = IP6_MAP_NEXT_IP4_REASS;
162 ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
164 u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
165 vlib_node_runtime_t *error_node =
166 vlib_node_get_runtime (vm, ip6_map_node.index);
167 map_main_t *mm = &map_main;
168 vlib_combined_counter_main_t *cm = mm->domain_counters;
169 u32 thread_index = vm->thread_index;
171 from = vlib_frame_vector_args (frame);
172 n_left_from = frame->n_vectors;
173 next_index = node->cached_next_index;
174 while (n_left_from > 0)
176 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
179 while (n_left_from >= 4 && n_left_to_next >= 2)
182 vlib_buffer_t *p0, *p1;
183 u8 error0 = MAP_ERROR_NONE;
184 u8 error1 = MAP_ERROR_NONE;
185 map_domain_t *d0 = 0, *d1 = 0;
186 ip4_header_t *ip40, *ip41;
187 ip6_header_t *ip60, *ip61;
188 u16 port0 = 0, port1 = 0;
189 u32 map_domain_index0 = ~0, map_domain_index1 = ~0;
190 u32 next0 = IP6_MAP_NEXT_IP4_LOOKUP;
191 u32 next1 = IP6_MAP_NEXT_IP4_LOOKUP;
193 /* Prefetch next iteration. */
195 vlib_buffer_t *p2, *p3;
197 p2 = vlib_get_buffer (vm, from[2]);
198 p3 = vlib_get_buffer (vm, from[3]);
200 vlib_prefetch_buffer_header (p2, LOAD);
201 vlib_prefetch_buffer_header (p3, LOAD);
203 /* IPv6 + IPv4 header + 8 bytes of ULP */
204 CLIB_PREFETCH (p2->data, 68, LOAD);
205 CLIB_PREFETCH (p3->data, 68, LOAD);
208 pi0 = to_next[0] = from[0];
209 pi1 = to_next[1] = from[1];
215 p0 = vlib_get_buffer (vm, pi0);
216 p1 = vlib_get_buffer (vm, pi1);
217 ip60 = vlib_buffer_get_current (p0);
218 ip61 = vlib_buffer_get_current (p1);
219 vlib_buffer_advance (p0, sizeof (ip6_header_t));
220 vlib_buffer_advance (p1, sizeof (ip6_header_t));
221 ip40 = vlib_buffer_get_current (p0);
222 ip41 = vlib_buffer_get_current (p1);
225 * Encapsulated IPv4 packet
226 * - IPv4 fragmented -> Pass to virtual reassembly unless security check disabled
227 * - Lookup/Rewrite or Fragment node in case of packet > MTU
228 * Fragmented IPv6 packet
230 * - Error -> Pass to ICMPv6/ICMPv4 relay
231 * - Info -> Pass to IPv6 local
232 * Anything else -> drop
235 (ip60->protocol == IP_PROTOCOL_IP_IN_IP
236 && clib_net_to_host_u16 (ip60->payload_length) > 20))
239 ip4_map_get_domain ((ip4_address_t *) & ip40->
240 src_address.as_u32, &map_domain_index0,
243 else if (ip60->protocol == IP_PROTOCOL_ICMP6 &&
244 clib_net_to_host_u16 (ip60->payload_length) >
245 sizeof (icmp46_header_t))
247 icmp46_header_t *icmp = (void *) (ip60 + 1);
248 next0 = (icmp->type == ICMP6_echo_request
250 ICMP6_echo_reply) ? IP6_MAP_NEXT_IP6_LOCAL :
251 IP6_MAP_NEXT_IP6_ICMP_RELAY;
253 else if (ip60->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
255 error0 = MAP_ERROR_FRAGMENTED;
259 error0 = MAP_ERROR_BAD_PROTOCOL;
262 (ip61->protocol == IP_PROTOCOL_IP_IN_IP
263 && clib_net_to_host_u16 (ip61->payload_length) > 20))
266 ip4_map_get_domain ((ip4_address_t *) & ip41->
267 src_address.as_u32, &map_domain_index1,
270 else if (ip61->protocol == IP_PROTOCOL_ICMP6 &&
271 clib_net_to_host_u16 (ip61->payload_length) >
272 sizeof (icmp46_header_t))
274 icmp46_header_t *icmp = (void *) (ip61 + 1);
275 next1 = (icmp->type == ICMP6_echo_request
277 ICMP6_echo_reply) ? IP6_MAP_NEXT_IP6_LOCAL :
278 IP6_MAP_NEXT_IP6_ICMP_RELAY;
280 else if (ip61->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
282 error1 = MAP_ERROR_FRAGMENTED;
286 error1 = MAP_ERROR_BAD_PROTOCOL;
291 /* MAP inbound security check */
292 ip6_map_security_check (d0, p0, ip40, ip60, &next0, &error0);
294 if (PREDICT_TRUE (error0 == MAP_ERROR_NONE &&
295 next0 == IP6_MAP_NEXT_IP4_LOOKUP))
299 && (clib_host_to_net_u16 (ip40->length) > d0->mtu)))
301 vnet_buffer (p0)->ip_frag.flags = 0;
302 vnet_buffer (p0)->ip_frag.next_index =
303 IP_FRAG_NEXT_IP4_LOOKUP;
304 vnet_buffer (p0)->ip_frag.mtu = d0->mtu;
305 next0 = IP6_MAP_NEXT_IP4_FRAGMENT;
310 ip6_map_ip4_lookup_bypass (p0,
312 IP6_MAP_NEXT_IP4_REWRITE : next0;
314 vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
316 map_domain_index0, 1,
323 /* MAP inbound security check */
324 ip6_map_security_check (d1, p1, ip41, ip61, &next1, &error1);
326 if (PREDICT_TRUE (error1 == MAP_ERROR_NONE &&
327 next1 == IP6_MAP_NEXT_IP4_LOOKUP))
331 && (clib_host_to_net_u16 (ip41->length) > d1->mtu)))
333 vnet_buffer (p1)->ip_frag.flags = 0;
334 vnet_buffer (p1)->ip_frag.next_index =
335 IP_FRAG_NEXT_IP4_LOOKUP;
336 vnet_buffer (p1)->ip_frag.mtu = d1->mtu;
337 next1 = IP6_MAP_NEXT_IP4_FRAGMENT;
342 ip6_map_ip4_lookup_bypass (p1,
344 IP6_MAP_NEXT_IP4_REWRITE : next1;
346 vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
348 map_domain_index1, 1,
354 if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
356 map_add_trace (vm, node, p0, map_domain_index0, port0);
359 if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED))
361 map_add_trace (vm, node, p1, map_domain_index1, port1);
364 if (error0 == MAP_ERROR_DECAP_SEC_CHECK && mm->icmp6_enabled)
366 /* Set ICMP parameters */
367 vlib_buffer_advance (p0, -sizeof (ip6_header_t));
368 icmp6_error_set_vnet_buffer (p0, ICMP6_destination_unreachable,
369 ICMP6_destination_unreachable_source_address_failed_policy,
371 next0 = IP6_MAP_NEXT_ICMP;
375 next0 = (error0 == MAP_ERROR_NONE) ? next0 : IP6_MAP_NEXT_DROP;
378 if (error1 == MAP_ERROR_DECAP_SEC_CHECK && mm->icmp6_enabled)
380 /* Set ICMP parameters */
381 vlib_buffer_advance (p1, -sizeof (ip6_header_t));
382 icmp6_error_set_vnet_buffer (p1, ICMP6_destination_unreachable,
383 ICMP6_destination_unreachable_source_address_failed_policy,
385 next1 = IP6_MAP_NEXT_ICMP;
389 next1 = (error1 == MAP_ERROR_NONE) ? next1 : IP6_MAP_NEXT_DROP;
393 if (next0 == IP6_MAP_NEXT_IP6_LOCAL)
394 vlib_buffer_advance (p0, -sizeof (ip6_header_t));
395 if (next1 == IP6_MAP_NEXT_IP6_LOCAL)
396 vlib_buffer_advance (p1, -sizeof (ip6_header_t));
398 p0->error = error_node->errors[error0];
399 p1->error = error_node->errors[error1];
400 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
401 n_left_to_next, pi0, pi1, next0,
406 while (n_left_from > 0 && n_left_to_next > 0)
410 u8 error0 = MAP_ERROR_NONE;
411 map_domain_t *d0 = 0;
415 u32 map_domain_index0 = ~0;
416 u32 next0 = IP6_MAP_NEXT_IP4_LOOKUP;
418 pi0 = to_next[0] = from[0];
424 p0 = vlib_get_buffer (vm, pi0);
425 ip60 = vlib_buffer_get_current (p0);
426 vlib_buffer_advance (p0, sizeof (ip6_header_t));
427 ip40 = vlib_buffer_get_current (p0);
430 * Encapsulated IPv4 packet
431 * - IPv4 fragmented -> Pass to virtual reassembly unless security check disabled
432 * - Lookup/Rewrite or Fragment node in case of packet > MTU
433 * Fragmented IPv6 packet
435 * - Error -> Pass to ICMPv6/ICMPv4 relay
436 * - Info -> Pass to IPv6 local
437 * Anything else -> drop
440 (ip60->protocol == IP_PROTOCOL_IP_IN_IP
441 && clib_net_to_host_u16 (ip60->payload_length) > 20))
444 ip4_map_get_domain ((ip4_address_t *) & ip40->
445 src_address.as_u32, &map_domain_index0,
448 else if (ip60->protocol == IP_PROTOCOL_ICMP6 &&
449 clib_net_to_host_u16 (ip60->payload_length) >
450 sizeof (icmp46_header_t))
452 icmp46_header_t *icmp = (void *) (ip60 + 1);
453 next0 = (icmp->type == ICMP6_echo_request
455 ICMP6_echo_reply) ? IP6_MAP_NEXT_IP6_LOCAL :
456 IP6_MAP_NEXT_IP6_ICMP_RELAY;
458 else if (ip60->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION &&
459 (((ip6_frag_hdr_t *) (ip60 + 1))->next_hdr ==
460 IP_PROTOCOL_IP_IN_IP))
462 error0 = MAP_ERROR_FRAGMENTED;
466 /* XXX: Move get_domain to ip6_get_domain lookup on source */
467 //error0 = MAP_ERROR_BAD_PROTOCOL;
468 vlib_buffer_advance (p0, -sizeof (ip6_header_t));
469 vnet_feature_next (&next0, p0);
474 /* MAP inbound security check */
475 ip6_map_security_check (d0, p0, ip40, ip60, &next0, &error0);
477 if (PREDICT_TRUE (error0 == MAP_ERROR_NONE &&
478 next0 == IP6_MAP_NEXT_IP4_LOOKUP))
482 && (clib_host_to_net_u16 (ip40->length) > d0->mtu)))
484 vnet_buffer (p0)->ip_frag.flags = 0;
485 vnet_buffer (p0)->ip_frag.next_index =
486 IP_FRAG_NEXT_IP4_LOOKUP;
487 vnet_buffer (p0)->ip_frag.mtu = d0->mtu;
488 next0 = IP6_MAP_NEXT_IP4_FRAGMENT;
493 ip6_map_ip4_lookup_bypass (p0,
495 IP6_MAP_NEXT_IP4_REWRITE : next0;
497 vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
499 map_domain_index0, 1,
505 if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
507 map_add_trace (vm, node, p0, map_domain_index0, port0);
510 if (mm->icmp6_enabled &&
511 (error0 == MAP_ERROR_DECAP_SEC_CHECK
512 || error0 == MAP_ERROR_NO_DOMAIN))
514 /* Set ICMP parameters */
515 vlib_buffer_advance (p0, -sizeof (ip6_header_t));
516 icmp6_error_set_vnet_buffer (p0, ICMP6_destination_unreachable,
517 ICMP6_destination_unreachable_source_address_failed_policy,
519 next0 = IP6_MAP_NEXT_ICMP;
523 next0 = (error0 == MAP_ERROR_NONE) ? next0 : IP6_MAP_NEXT_DROP;
527 if (next0 == IP6_MAP_NEXT_IP6_LOCAL)
528 vlib_buffer_advance (p0, -sizeof (ip6_header_t));
530 p0->error = error_node->errors[error0];
531 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
532 n_left_to_next, pi0, next0);
534 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
537 return frame->n_vectors;
542 map_ip6_drop_pi (u32 pi)
544 vlib_main_t *vm = vlib_get_main ();
545 vlib_node_runtime_t *n =
546 vlib_node_get_runtime (vm, ip6_map_ip6_reass_node.index);
547 vlib_set_next_frame_buffer (vm, n, IP6_MAP_IP6_REASS_NEXT_DROP, pi);
551 * ip6_map_post_ip4_reass
554 ip6_map_post_ip4_reass (vlib_main_t * vm,
555 vlib_node_runtime_t * node, vlib_frame_t * frame)
557 u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
558 vlib_node_runtime_t *error_node =
559 vlib_node_get_runtime (vm, ip6_map_post_ip4_reass_node.index);
560 map_main_t *mm = &map_main;
561 vlib_combined_counter_main_t *cm = mm->domain_counters;
562 u32 thread_index = vm->thread_index;
564 from = vlib_frame_vector_args (frame);
565 n_left_from = frame->n_vectors;
566 next_index = node->cached_next_index;
567 while (n_left_from > 0)
569 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
572 while (n_left_from > 0 && n_left_to_next > 0)
576 u8 error0 = MAP_ERROR_NONE;
581 u32 map_domain_index0 = ~0;
582 u32 next0 = IP6_MAP_POST_IP4_REASS_NEXT_IP4_LOOKUP;
584 pi0 = to_next[0] = from[0];
590 p0 = vlib_get_buffer (vm, pi0);
591 ip40 = vlib_buffer_get_current (p0);
592 ip60 = ((ip6_header_t *) ip40) - 1;
595 ip4_map_get_domain ((ip4_address_t *) & ip40->src_address.as_u32,
596 &map_domain_index0, &error0);
598 port0 = vnet_buffer (p0)->ip.reass.l4_src_port;
600 if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
602 ip6_map_sec_check (d0, port0, ip40,
603 ip60) ? MAP_ERROR_NONE :
604 MAP_ERROR_DECAP_SEC_CHECK;
607 (error0 == MAP_ERROR_NONE &&
608 d0->mtu && (clib_host_to_net_u16 (ip40->length) > d0->mtu)))
610 vnet_buffer (p0)->ip_frag.flags = 0;
611 vnet_buffer (p0)->ip_frag.next_index = IP_FRAG_NEXT_IP4_LOOKUP;
612 vnet_buffer (p0)->ip_frag.mtu = d0->mtu;
613 next0 = IP6_MAP_POST_IP4_REASS_NEXT_IP4_FRAGMENT;
616 if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
618 map_ip6_map_ip4_reass_trace_t *tr =
619 vlib_add_trace (vm, node, p0, sizeof (*tr));
620 tr->map_domain_index = map_domain_index0;
624 if (error0 == MAP_ERROR_NONE)
625 vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
627 map_domain_index0, 1,
632 MAP_ERROR_NONE) ? next0 : IP6_MAP_POST_IP4_REASS_NEXT_DROP;
633 p0->error = error_node->errors[error0];
634 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
635 n_left_to_next, pi0, next0);
638 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
640 return frame->n_vectors;
647 ip6_map_icmp_relay (vlib_main_t * vm,
648 vlib_node_runtime_t * node, vlib_frame_t * frame)
650 u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
651 vlib_node_runtime_t *error_node =
652 vlib_node_get_runtime (vm, ip6_map_icmp_relay_node.index);
653 map_main_t *mm = &map_main;
654 u32 thread_index = vm->thread_index;
655 u16 *fragment_ids, *fid;
657 from = vlib_frame_vector_args (frame);
658 n_left_from = frame->n_vectors;
659 next_index = node->cached_next_index;
661 /* Get random fragment IDs for replies. */
663 clib_random_buffer_get_data (&vm->random_buffer,
664 n_left_from * sizeof (fragment_ids[0]));
666 while (n_left_from > 0)
668 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
671 while (n_left_from > 0 && n_left_to_next > 0)
675 u8 error0 = MAP_ERROR_NONE;
677 u32 next0 = IP6_ICMP_RELAY_NEXT_IP4_LOOKUP;
680 pi0 = to_next[0] = from[0];
686 p0 = vlib_get_buffer (vm, pi0);
687 ip60 = vlib_buffer_get_current (p0);
688 u16 tlen = clib_net_to_host_u16 (ip60->payload_length);
695 * Original IPv4 header / packet
699 * Original IPv4 header / packet
702 /* Need at least ICMP(8) + IPv6(40) + IPv4(20) + L4 header(8) */
705 error0 = MAP_ERROR_ICMP_RELAY;
709 icmp46_header_t *icmp60 = (icmp46_header_t *) (ip60 + 1);
710 ip6_header_t *inner_ip60 = (ip6_header_t *) (icmp60 + 2);
712 if (inner_ip60->protocol != IP_PROTOCOL_IP_IN_IP)
714 error0 = MAP_ERROR_ICMP_RELAY;
718 ip4_header_t *inner_ip40 = (ip4_header_t *) (inner_ip60 + 1);
719 vlib_buffer_advance (p0, 60); /* sizeof ( IPv6 + ICMP + IPv6 - IPv4 - ICMP ) */
720 ip4_header_t *new_ip40 = vlib_buffer_get_current (p0);
721 icmp46_header_t *new_icmp40 = (icmp46_header_t *) (new_ip40 + 1);
724 * Relay according to RFC2473, section 8.3
726 switch (icmp60->type)
728 case ICMP6_destination_unreachable:
729 case ICMP6_time_exceeded:
730 case ICMP6_parameter_problem:
731 /* Type 3 - destination unreachable, Code 1 - host unreachable */
732 new_icmp40->type = ICMP4_destination_unreachable;
734 ICMP4_destination_unreachable_destination_unreachable_host;
737 case ICMP6_packet_too_big:
738 /* Type 3 - destination unreachable, Code 4 - packet too big */
739 /* Potential TODO: Adjust domain tunnel MTU based on the value received here */
740 mtu = clib_net_to_host_u32 (*((u32 *) (icmp60 + 1)));
744 (inner_ip40->flags_and_fragment_offset &
745 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT)))
747 error0 = MAP_ERROR_ICMP_RELAY;
751 new_icmp40->type = ICMP4_destination_unreachable;
753 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set;
754 *((u32 *) (new_icmp40 + 1)) =
755 clib_host_to_net_u32 (mtu < 1280 ? 1280 : mtu);
759 error0 = MAP_ERROR_ICMP_RELAY;
764 * Ensure the total ICMP packet is no longer than 576 bytes (RFC1812)
766 new_ip40->ip_version_and_header_length = 0x45;
768 u16 nlen = (tlen - 20) > 576 ? 576 : tlen - 20;
769 new_ip40->length = clib_host_to_net_u16 (nlen);
770 new_ip40->fragment_id = fid[0];
773 new_ip40->protocol = IP_PROTOCOL_ICMP;
774 new_ip40->src_address = mm->icmp4_src_address;
775 new_ip40->dst_address = inner_ip40->src_address;
776 new_ip40->checksum = ip4_header_checksum (new_ip40);
778 new_icmp40->checksum = 0;
779 ip_csum_t sum = ip_incremental_checksum (0, new_icmp40, nlen - 20);
780 new_icmp40->checksum = ~ip_csum_fold (sum);
782 vlib_increment_simple_counter (&mm->icmp_relayed, thread_index, 0,
786 if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
788 map_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr));
789 tr->map_domain_index = 0;
794 (error0 == MAP_ERROR_NONE) ? next0 : IP6_ICMP_RELAY_NEXT_DROP;
795 p0->error = error_node->errors[error0];
796 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
797 n_left_to_next, pi0, next0);
799 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
802 return frame->n_vectors;
806 static char *map_error_strings[] = {
807 #define _(sym,string) string,
813 VNET_FEATURE_INIT (ip6_map_feature, static) =
815 .arc_name = "ip6-unicast",
816 .node_name = "ip6-map",
817 .runs_before = VNET_FEATURES ("ip6-flow-classify"),
818 .runs_after = VNET_FEATURES ("ip6-full-reassembly-feature"),
821 VLIB_REGISTER_NODE(ip6_map_node) = {
824 .vector_size = sizeof(u32),
825 .format_trace = format_map_trace,
826 .type = VLIB_NODE_TYPE_INTERNAL,
828 .n_errors = MAP_N_ERROR,
829 .error_strings = map_error_strings,
831 .n_next_nodes = IP6_MAP_N_NEXT,
833 [IP6_MAP_NEXT_IP4_LOOKUP] = "ip4-lookup",
834 #ifdef MAP_SKIP_IP6_LOOKUP
835 [IP6_MAP_NEXT_IP4_REWRITE] = "ip4-load-balance",
837 [IP6_MAP_NEXT_IP4_REASS] = "ip4-sv-reassembly-custom-next",
838 [IP6_MAP_NEXT_IP4_FRAGMENT] = "ip4-frag",
839 [IP6_MAP_NEXT_IP6_ICMP_RELAY] = "ip6-map-icmp-relay",
840 [IP6_MAP_NEXT_IP6_LOCAL] = "ip6-local",
841 [IP6_MAP_NEXT_DROP] = "error-drop",
842 [IP6_MAP_NEXT_ICMP] = "ip6-icmp-error",
848 VLIB_REGISTER_NODE(ip6_map_post_ip4_reass_node) = {
849 .function = ip6_map_post_ip4_reass,
850 .name = "ip6-map-post-ip4-reass",
851 .vector_size = sizeof(u32),
852 .format_trace = format_ip6_map_post_ip4_reass_trace,
853 .type = VLIB_NODE_TYPE_INTERNAL,
854 .n_errors = MAP_N_ERROR,
855 .error_strings = map_error_strings,
856 .n_next_nodes = IP6_MAP_POST_IP4_REASS_N_NEXT,
858 [IP6_MAP_POST_IP4_REASS_NEXT_IP4_LOOKUP] = "ip4-lookup",
859 [IP6_MAP_POST_IP4_REASS_NEXT_IP4_FRAGMENT] = "ip4-frag",
860 [IP6_MAP_POST_IP4_REASS_NEXT_DROP] = "error-drop",
866 VLIB_REGISTER_NODE(ip6_map_icmp_relay_node, static) = {
867 .function = ip6_map_icmp_relay,
868 .name = "ip6-map-icmp-relay",
869 .vector_size = sizeof(u32),
870 .format_trace = format_map_trace, //FIXME
871 .type = VLIB_NODE_TYPE_INTERNAL,
872 .n_errors = MAP_N_ERROR,
873 .error_strings = map_error_strings,
874 .n_next_nodes = IP6_ICMP_RELAY_N_NEXT,
876 [IP6_ICMP_RELAY_NEXT_IP4_LOOKUP] = "ip4-lookup",
877 [IP6_ICMP_RELAY_NEXT_DROP] = "error-drop",
883 ip6_map_init (vlib_main_t * vm)
885 map_main.ip4_sv_reass_custom_next_index =
886 ip4_sv_reass_custom_register_next_node
887 (ip6_map_post_ip4_reass_node.index);
891 VLIB_INIT_FUNCTION (ip6_map_init) =
893 .runs_after = VLIB_INITS ("map_init"),};
896 * fd.io coding-style-patch-verification: ON
899 * eval: (c-set-style "gnu")