2 * Copyright (c) 2017 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 * @brief NAT64 IPv4 to IPv6 translation (otside to inside network)
20 #include <nat/nat64.h>
21 #include <nat/nat_reass.h>
22 #include <nat/nat_inlines.h>
23 #include <vnet/ip/ip4_to_ip6.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <vnet/udp/udp.h>
31 } nat64_out2in_trace_t;
34 format_nat64_out2in_trace (u8 * s, va_list * args)
36 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
37 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
38 nat64_out2in_trace_t *t = va_arg (*args, nat64_out2in_trace_t *);
41 format (s, "NAT64-out2in: sw_if_index %d, next index %d", t->sw_if_index,
52 } nat64_out2in_reass_trace_t;
55 format_nat64_out2in_reass_trace (u8 * s, va_list * args)
57 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
58 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
59 nat64_out2in_reass_trace_t *t =
60 va_arg (*args, nat64_out2in_reass_trace_t *);
63 format (s, "NAT64-out2in-reass: sw_if_index %d, next index %d, status %s",
64 t->sw_if_index, t->next_index,
65 t->cached ? "cached" : "translated");
70 vlib_node_registration_t nat64_out2in_node;
71 vlib_node_registration_t nat64_out2in_reass_node;
72 vlib_node_registration_t nat64_out2in_handoff_node;
74 #define foreach_nat64_out2in_error \
75 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
76 _(OUT2IN_PACKETS, "good out2in packets processed") \
77 _(NO_TRANSLATION, "no translation") \
78 _(UNKNOWN, "unknown") \
79 _(DROP_FRAGMENT, "drop fragment") \
80 _(MAX_REASS, "maximum reassemblies exceeded") \
81 _(MAX_FRAG, "maximum fragments per reassembly exceeded") \
82 _(TCP_PACKETS, "TCP packets") \
83 _(UDP_PACKETS, "UDP packets") \
84 _(ICMP_PACKETS, "ICMP packets") \
85 _(OTHER_PACKETS, "other protocol packets") \
86 _(FRAGMENTS, "fragments") \
87 _(CACHED_FRAGMENTS, "cached fragments") \
88 _(PROCESSED_FRAGMENTS, "processed fragments")
93 #define _(sym,str) NAT64_OUT2IN_ERROR_##sym,
94 foreach_nat64_out2in_error
97 } nat64_out2in_error_t;
99 static char *nat64_out2in_error_strings[] = {
100 #define _(sym,string) string,
101 foreach_nat64_out2in_error
107 NAT64_OUT2IN_NEXT_IP6_LOOKUP,
108 NAT64_OUT2IN_NEXT_IP4_LOOKUP,
109 NAT64_OUT2IN_NEXT_DROP,
110 NAT64_OUT2IN_NEXT_REASS,
112 } nat64_out2in_next_t;
114 typedef struct nat64_out2in_set_ctx_t_
119 } nat64_out2in_set_ctx_t;
122 nat64_out2in_tcp_udp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6,
125 nat64_main_t *nm = &nat64_main;
126 nat64_out2in_set_ctx_t *ctx = arg;
127 nat64_db_bib_entry_t *bibe;
128 nat64_db_st_entry_t *ste;
129 ip46_address_t saddr, daddr;
130 ip6_address_t ip6_saddr;
131 udp_header_t *udp = ip4_next_header (ip4);
132 tcp_header_t *tcp = ip4_next_header (ip4);
133 u8 proto = ip4->protocol;
134 u16 dport = udp->dst_port;
135 u16 sport = udp->src_port;
136 u32 sw_if_index, fib_index;
139 nat64_db_t *db = &nm->db[ctx->thread_index];
141 sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
142 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
144 clib_memset (&saddr, 0, sizeof (saddr));
145 saddr.ip4.as_u32 = ip4->src_address.as_u32;
146 clib_memset (&daddr, 0, sizeof (daddr));
147 daddr.ip4.as_u32 = ip4->dst_address.as_u32;
150 nat64_db_st_entry_find (db, &daddr, &saddr, dport, sport, proto,
154 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
160 bibe = nat64_db_bib_entry_find (db, &daddr, dport, proto, fib_index, 0);
165 nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
167 nat64_db_st_entry_create (db, bibe, &ip6_saddr, &saddr.ip4, sport);
172 vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
173 db->st.st_entries_num);
176 ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
177 ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
179 ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
180 ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
181 udp->dst_port = bibe->in_port;
183 if (proto == IP_PROTOCOL_UDP)
184 checksum = &udp->checksum;
187 checksum = &tcp->checksum;
188 nat64_tcp_session_set_state (ste, tcp, 0);
191 csum = ip_csum_sub_even (*checksum, dport);
192 csum = ip_csum_add_even (csum, udp->dst_port);
193 *checksum = ip_csum_fold (csum);
195 vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
197 nat64_session_reset_timeout (ste, ctx->vm);
203 nat64_out2in_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, void *arg)
205 nat64_main_t *nm = &nat64_main;
206 nat64_out2in_set_ctx_t *ctx = arg;
207 nat64_db_bib_entry_t *bibe;
208 nat64_db_st_entry_t *ste;
209 ip46_address_t saddr, daddr;
210 ip6_address_t ip6_saddr;
211 u32 sw_if_index, fib_index;
212 icmp46_header_t *icmp = ip4_next_header (ip4);
213 nat64_db_t *db = &nm->db[ctx->thread_index];
215 sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
216 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
218 clib_memset (&saddr, 0, sizeof (saddr));
219 saddr.ip4.as_u32 = ip4->src_address.as_u32;
220 clib_memset (&daddr, 0, sizeof (daddr));
221 daddr.ip4.as_u32 = ip4->dst_address.as_u32;
223 if (icmp->type == ICMP6_echo_request || icmp->type == ICMP6_echo_reply)
225 u16 out_id = ((u16 *) (icmp))[2];
227 nat64_db_st_entry_find (db, &daddr, &saddr, out_id, 0,
228 IP_PROTOCOL_ICMP, fib_index, 0);
233 nat64_db_bib_entry_by_index (db, IP_PROTOCOL_ICMP,
241 nat64_db_bib_entry_find (db, &daddr, out_id,
242 IP_PROTOCOL_ICMP, fib_index, 0);
246 nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
248 nat64_db_st_entry_create (db, bibe, &ip6_saddr, &saddr.ip4, 0);
253 vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
254 db->st.st_entries_num);
257 nat64_session_reset_timeout (ste, ctx->vm);
259 ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
260 ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
262 ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
263 ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
264 ((u16 *) (icmp))[2] = bibe->in_port;
266 vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
270 ip6_header_t *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
272 nat64_compose_ip6 (&ip6->src_address, &ip4->src_address,
273 vnet_buffer (ctx->b)->sw_if_index[VLIB_TX]);
274 ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0];
275 ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1];
282 nat64_out2in_inner_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6,
285 nat64_main_t *nm = &nat64_main;
286 nat64_out2in_set_ctx_t *ctx = arg;
287 nat64_db_bib_entry_t *bibe;
288 nat64_db_st_entry_t *ste;
289 ip46_address_t saddr, daddr;
290 u32 sw_if_index, fib_index;
291 u8 proto = ip4->protocol;
292 nat64_db_t *db = &nm->db[ctx->thread_index];
294 sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
296 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
298 clib_memset (&saddr, 0, sizeof (saddr));
299 saddr.ip4.as_u32 = ip4->src_address.as_u32;
300 clib_memset (&daddr, 0, sizeof (daddr));
301 daddr.ip4.as_u32 = ip4->dst_address.as_u32;
303 if (proto == IP_PROTOCOL_ICMP6)
305 icmp46_header_t *icmp = ip4_next_header (ip4);
306 u16 out_id = ((u16 *) (icmp))[2];
307 proto = IP_PROTOCOL_ICMP;
310 (icmp->type == ICMP6_echo_request
311 || icmp->type == ICMP6_echo_reply))
315 nat64_db_st_entry_find (db, &saddr, &daddr, out_id, 0, proto,
320 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
324 ip6->dst_address.as_u64[0] = ste->in_r_addr.as_u64[0];
325 ip6->dst_address.as_u64[1] = ste->in_r_addr.as_u64[1];
326 ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
327 ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
328 ((u16 *) (icmp))[2] = bibe->in_port;
330 vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
334 udp_header_t *udp = ip4_next_header (ip4);
335 tcp_header_t *tcp = ip4_next_header (ip4);
336 u16 dport = udp->dst_port;
337 u16 sport = udp->src_port;
342 nat64_db_st_entry_find (db, &saddr, &daddr, sport, dport, proto,
347 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
351 nat64_compose_ip6 (&ip6->dst_address, &daddr.ip4, bibe->fib_index);
352 ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
353 ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
354 udp->src_port = bibe->in_port;
356 if (proto == IP_PROTOCOL_UDP)
357 checksum = &udp->checksum;
359 checksum = &tcp->checksum;
362 csum = ip_csum_sub_even (*checksum, sport);
363 csum = ip_csum_add_even (csum, udp->src_port);
364 *checksum = ip_csum_fold (csum);
367 vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
374 nat64_out2in_unk_proto_set_cb (ip4_header_t * ip4, ip6_header_t * ip6,
377 nat64_main_t *nm = &nat64_main;
378 nat64_out2in_set_ctx_t *ctx = arg;
379 nat64_db_bib_entry_t *bibe;
380 nat64_db_st_entry_t *ste;
381 ip46_address_t saddr, daddr;
382 ip6_address_t ip6_saddr;
383 u32 sw_if_index, fib_index;
384 u8 proto = ip4->protocol;
385 nat64_db_t *db = &nm->db[ctx->thread_index];
387 sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
388 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
390 clib_memset (&saddr, 0, sizeof (saddr));
391 saddr.ip4.as_u32 = ip4->src_address.as_u32;
392 clib_memset (&daddr, 0, sizeof (daddr));
393 daddr.ip4.as_u32 = ip4->dst_address.as_u32;
396 nat64_db_st_entry_find (db, &daddr, &saddr, 0, 0, proto, fib_index, 0);
399 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
405 bibe = nat64_db_bib_entry_find (db, &daddr, 0, proto, fib_index, 0);
410 nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
411 ste = nat64_db_st_entry_create (db, bibe, &ip6_saddr, &saddr.ip4, 0);
416 vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
417 db->st.st_entries_num);
420 nat64_session_reset_timeout (ste, ctx->vm);
422 ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
423 ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
425 ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
426 ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
428 vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
434 nat64_out2in_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
435 vlib_frame_t * frame)
437 u32 n_left_from, *from, *to_next;
438 nat64_out2in_next_t next_index;
439 u32 pkts_processed = 0;
440 u32 thread_index = vm->thread_index;
441 u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
444 from = vlib_frame_vector_args (frame);
445 n_left_from = frame->n_vectors;
446 next_index = node->cached_next_index;
447 while (n_left_from > 0)
451 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
453 while (n_left_from > 0 && n_left_to_next > 0)
460 nat64_out2in_set_ctx_t ctx0;
463 /* speculatively enqueue b0 to the current next frame */
471 b0 = vlib_get_buffer (vm, bi0);
472 ip40 = vlib_buffer_get_current (b0);
476 ctx0.thread_index = thread_index;
478 next0 = NAT64_OUT2IN_NEXT_IP6_LOOKUP;
480 proto0 = ip_proto_to_snat_proto (ip40->protocol);
482 if (PREDICT_FALSE (proto0 == ~0))
484 if (ip4_to_ip6 (b0, nat64_out2in_unk_proto_set_cb, &ctx0))
486 next0 = NAT64_OUT2IN_NEXT_DROP;
487 b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
493 if (PREDICT_FALSE (ip4_is_fragment (ip40)))
495 next0 = NAT64_OUT2IN_NEXT_REASS;
500 if (proto0 == SNAT_PROTOCOL_ICMP)
504 (b0, nat64_out2in_icmp_set_cb, &ctx0,
505 nat64_out2in_inner_icmp_set_cb, &ctx0))
507 next0 = NAT64_OUT2IN_NEXT_DROP;
508 b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
514 if (proto0 == SNAT_PROTOCOL_TCP)
519 if (ip4_to_ip6_tcp_udp (b0, nat64_out2in_tcp_udp_set_cb, &ctx0))
521 udp0 = ip4_next_header (ip40);
523 * Send DHCP packets to the ipv4 stack, or we won't
524 * be able to use dhcp client on the outside interface
526 if ((proto0 == SNAT_PROTOCOL_UDP)
527 && (udp0->dst_port ==
528 clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client)))
530 next0 = NAT64_OUT2IN_NEXT_IP4_LOOKUP;
533 next0 = NAT64_OUT2IN_NEXT_DROP;
534 b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
540 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
541 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
543 nat64_out2in_trace_t *t =
544 vlib_add_trace (vm, node, b0, sizeof (*t));
545 t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
546 t->next_index = next0;
549 pkts_processed += next0 == NAT64_OUT2IN_NEXT_IP6_LOOKUP;
551 /* verify speculative enqueue, maybe switch current next frame */
552 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
553 n_left_to_next, bi0, next0);
555 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
557 vlib_node_increment_counter (vm, nat64_out2in_node.index,
558 NAT64_OUT2IN_ERROR_OUT2IN_PACKETS,
560 vlib_node_increment_counter (vm, nat64_out2in_node.index,
561 NAT64_OUT2IN_ERROR_TCP_PACKETS, tcp_packets);
562 vlib_node_increment_counter (vm, nat64_out2in_node.index,
563 NAT64_OUT2IN_ERROR_UDP_PACKETS, tcp_packets);
564 vlib_node_increment_counter (vm, nat64_out2in_node.index,
565 NAT64_OUT2IN_ERROR_ICMP_PACKETS, icmp_packets);
566 vlib_node_increment_counter (vm, nat64_out2in_node.index,
567 NAT64_OUT2IN_ERROR_OTHER_PACKETS,
569 vlib_node_increment_counter (vm, nat64_out2in_node.index,
570 NAT64_OUT2IN_ERROR_FRAGMENTS, fragments);
572 return frame->n_vectors;
576 VLIB_REGISTER_NODE (nat64_out2in_node) = {
577 .function = nat64_out2in_node_fn,
578 .name = "nat64-out2in",
579 .vector_size = sizeof (u32),
580 .format_trace = format_nat64_out2in_trace,
581 .type = VLIB_NODE_TYPE_INTERNAL,
582 .n_errors = ARRAY_LEN (nat64_out2in_error_strings),
583 .error_strings = nat64_out2in_error_strings,
584 .n_next_nodes = NAT64_OUT2IN_N_NEXT,
585 /* edit / add dispositions here */
587 [NAT64_OUT2IN_NEXT_DROP] = "error-drop",
588 [NAT64_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup",
589 [NAT64_OUT2IN_NEXT_IP4_LOOKUP] = "ip4-lookup",
590 [NAT64_OUT2IN_NEXT_REASS] = "nat64-out2in-reass",
595 VLIB_NODE_FUNCTION_MULTIARCH (nat64_out2in_node, nat64_out2in_node_fn);
597 typedef struct nat64_out2in_frag_set_ctx_t_
605 } nat64_out2in_frag_set_ctx_t;
608 nat64_out2in_frag_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, void *arg)
610 nat64_main_t *nm = &nat64_main;
611 nat64_out2in_frag_set_ctx_t *ctx = arg;
612 nat64_db_st_entry_t *ste;
613 nat64_db_bib_entry_t *bibe;
614 udp_header_t *udp = ip4_next_header (ip4);
617 nat64_db_t *db = &nm->db[ctx->thread_index];
619 ste = nat64_db_st_entry_by_index (db, ctx->proto, ctx->sess_index);
623 bibe = nat64_db_bib_entry_by_index (db, ctx->proto, ste->bibe_index);
629 udp->dst_port = bibe->in_port;
631 if (ip4->protocol == IP_PROTOCOL_UDP)
633 checksum = &udp->checksum;
638 clib_host_to_net_u16 (ip4->length) - sizeof (*ip4);
639 csum = ip_incremental_checksum (0, udp, udp_len);
641 ip_csum_with_carry (csum, clib_host_to_net_u16 (udp_len));
643 ip_csum_with_carry (csum,
644 clib_host_to_net_u16 (IP_PROTOCOL_UDP));
645 csum = ip_csum_with_carry (csum, ste->in_r_addr.as_u64[0]);
646 csum = ip_csum_with_carry (csum, ste->in_r_addr.as_u64[1]);
647 csum = ip_csum_with_carry (csum, bibe->in_addr.as_u64[0]);
648 csum = ip_csum_with_carry (csum, bibe->in_addr.as_u64[1]);
649 *checksum = ~ip_csum_fold (csum);
653 csum = ip_csum_sub_even (*checksum, bibe->out_addr.as_u32);
654 csum = ip_csum_sub_even (csum, ste->out_r_addr.as_u32);
655 csum = ip_csum_sub_even (csum, bibe->out_port);
656 csum = ip_csum_add_even (csum, ste->in_r_addr.as_u64[0]);
657 csum = ip_csum_add_even (csum, ste->in_r_addr.as_u64[1]);
658 csum = ip_csum_add_even (csum, bibe->in_addr.as_u64[0]);
659 csum = ip_csum_add_even (csum, bibe->in_addr.as_u64[1]);
660 csum = ip_csum_add_even (csum, bibe->in_port);
661 *checksum = ip_csum_fold (csum);
666 tcp_header_t *tcp = ip4_next_header (ip4);
667 nat64_tcp_session_set_state (ste, tcp, 0);
668 checksum = &tcp->checksum;
669 csum = ip_csum_sub_even (*checksum, bibe->out_addr.as_u32);
670 csum = ip_csum_sub_even (csum, ste->out_r_addr.as_u32);
671 csum = ip_csum_sub_even (csum, bibe->out_port);
672 csum = ip_csum_add_even (csum, ste->in_r_addr.as_u64[0]);
673 csum = ip_csum_add_even (csum, ste->in_r_addr.as_u64[1]);
674 csum = ip_csum_add_even (csum, bibe->in_addr.as_u64[0]);
675 csum = ip_csum_add_even (csum, bibe->in_addr.as_u64[1]);
676 csum = ip_csum_add_even (csum, bibe->in_port);
677 *checksum = ip_csum_fold (csum);
682 ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
683 ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
685 ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
686 ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
688 vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
690 nat64_session_reset_timeout (ste, ctx->vm);
696 nat64_out2in_reass_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
697 vlib_frame_t * frame)
699 u32 n_left_from, *from, *to_next;
700 nat64_out2in_next_t next_index;
701 u32 pkts_processed = 0, cached_fragments = 0;
702 u32 *fragments_to_drop = 0;
703 u32 *fragments_to_loopback = 0;
704 nat64_main_t *nm = &nat64_main;
705 u32 thread_index = vm->thread_index;
707 from = vlib_frame_vector_args (frame);
708 n_left_from = frame->n_vectors;
709 next_index = node->cached_next_index;
711 while (n_left_from > 0)
715 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
717 while (n_left_from > 0 && n_left_to_next > 0)
724 u32 sw_if_index0, fib_index0;
726 nat_reass_ip4_t *reass0;
727 ip46_address_t saddr0, daddr0;
728 nat64_db_st_entry_t *ste0;
729 nat64_db_bib_entry_t *bibe0;
730 ip6_address_t ip6_saddr0;
731 nat64_out2in_frag_set_ctx_t ctx0;
732 nat64_db_t *db = &nm->db[thread_index];
734 /* speculatively enqueue b0 to the current next frame */
742 b0 = vlib_get_buffer (vm, bi0);
743 next0 = NAT64_OUT2IN_NEXT_IP6_LOOKUP;
745 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
747 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
750 ctx0.thread_index = thread_index;
752 if (PREDICT_FALSE (nat_reass_is_drop_frag (1)))
754 next0 = NAT64_OUT2IN_NEXT_DROP;
755 b0->error = node->errors[NAT64_OUT2IN_ERROR_DROP_FRAGMENT];
759 ip40 = vlib_buffer_get_current (b0);
761 if (PREDICT_FALSE (!(ip40->protocol == IP_PROTOCOL_TCP
762 || ip40->protocol == IP_PROTOCOL_UDP)))
764 next0 = NAT64_OUT2IN_NEXT_DROP;
765 b0->error = node->errors[NAT64_OUT2IN_ERROR_DROP_FRAGMENT];
769 udp0 = ip4_next_header (ip40);
771 reass0 = nat_ip4_reass_find_or_create (ip40->src_address,
775 1, &fragments_to_drop);
777 if (PREDICT_FALSE (!reass0))
779 next0 = NAT64_OUT2IN_NEXT_DROP;
780 b0->error = node->errors[NAT64_OUT2IN_ERROR_MAX_REASS];
784 if (PREDICT_FALSE (ip4_is_first_fragment (ip40)))
788 clib_memset (&saddr0, 0, sizeof (saddr0));
789 saddr0.ip4.as_u32 = ip40->src_address.as_u32;
790 clib_memset (&daddr0, 0, sizeof (daddr0));
791 daddr0.ip4.as_u32 = ip40->dst_address.as_u32;
794 nat64_db_st_entry_find (db, &daddr0, &saddr0,
795 udp0->dst_port, udp0->src_port,
796 ip40->protocol, fib_index0, 0);
800 nat64_db_bib_entry_find (db, &daddr0, udp0->dst_port,
801 ip40->protocol, fib_index0, 0);
804 next0 = NAT64_OUT2IN_NEXT_DROP;
806 node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
810 nat64_compose_ip6 (&ip6_saddr0, &ip40->src_address,
813 nat64_db_st_entry_create (db, bibe0, &ip6_saddr0,
814 &saddr0.ip4, udp0->src_port);
818 next0 = NAT64_OUT2IN_NEXT_DROP;
820 node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
824 vlib_set_simple_counter (&nm->total_sessions, thread_index,
825 0, db->st.st_entries_num);
827 reass0->sess_index = nat64_db_st_entry_get_index (db, ste0);
828 reass0->thread_index = thread_index;
830 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
836 if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
838 if (nat_ip4_reass_add_fragment
839 (reass0, bi0, &fragments_to_drop))
841 b0->error = node->errors[NAT64_OUT2IN_ERROR_MAX_FRAG];
842 next0 = NAT64_OUT2IN_NEXT_DROP;
850 ctx0.sess_index = reass0->sess_index;
851 ctx0.proto = ip40->protocol;
855 if (ip4_to_ip6_fragmented (b0, nat64_out2in_frag_set_cb, &ctx0))
857 next0 = NAT64_OUT2IN_NEXT_DROP;
858 b0->error = node->errors[NAT64_OUT2IN_ERROR_UNKNOWN];
864 ((node->flags & VLIB_NODE_FLAG_TRACE)
865 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
867 nat64_out2in_reass_trace_t *t =
868 vlib_add_trace (vm, node, b0, sizeof (*t));
870 t->sw_if_index = sw_if_index0;
871 t->next_index = next0;
882 pkts_processed += next0 != NAT64_OUT2IN_NEXT_DROP;
884 /* verify speculative enqueue, maybe switch current next frame */
885 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
886 to_next, n_left_to_next,
890 if (n_left_from == 0 && vec_len (fragments_to_loopback))
892 from = vlib_frame_vector_args (frame);
893 u32 len = vec_len (fragments_to_loopback);
894 if (len <= VLIB_FRAME_SIZE)
896 clib_memcpy_fast (from, fragments_to_loopback,
899 vec_reset_length (fragments_to_loopback);
903 clib_memcpy_fast (from, fragments_to_loopback +
904 (len - VLIB_FRAME_SIZE),
905 sizeof (u32) * VLIB_FRAME_SIZE);
906 n_left_from = VLIB_FRAME_SIZE;
907 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
912 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
915 vlib_node_increment_counter (vm, nat64_out2in_reass_node.index,
916 NAT64_OUT2IN_ERROR_PROCESSED_FRAGMENTS,
918 vlib_node_increment_counter (vm, nat64_out2in_reass_node.index,
919 NAT64_OUT2IN_ERROR_CACHED_FRAGMENTS,
922 nat_send_all_to_node (vm, fragments_to_drop, node,
923 &node->errors[NAT64_OUT2IN_ERROR_DROP_FRAGMENT],
924 NAT64_OUT2IN_NEXT_DROP);
926 vec_free (fragments_to_drop);
927 vec_free (fragments_to_loopback);
928 return frame->n_vectors;
932 VLIB_REGISTER_NODE (nat64_out2in_reass_node) = {
933 .function = nat64_out2in_reass_node_fn,
934 .name = "nat64-out2in-reass",
935 .vector_size = sizeof (u32),
936 .format_trace = format_nat64_out2in_reass_trace,
937 .type = VLIB_NODE_TYPE_INTERNAL,
938 .n_errors = ARRAY_LEN (nat64_out2in_error_strings),
939 .error_strings = nat64_out2in_error_strings,
940 .n_next_nodes = NAT64_OUT2IN_N_NEXT,
941 /* edit / add dispositions here */
943 [NAT64_OUT2IN_NEXT_DROP] = "error-drop",
944 [NAT64_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup",
945 [NAT64_OUT2IN_NEXT_IP4_LOOKUP] = "ip4-lookup",
946 [NAT64_OUT2IN_NEXT_REASS] = "nat64-out2in-reass",
951 VLIB_NODE_FUNCTION_MULTIARCH (nat64_out2in_reass_node,
952 nat64_out2in_reass_node_fn);
954 #define foreach_nat64_out2in_handoff_error \
955 _(CONGESTION_DROP, "congestion drop") \
956 _(SAME_WORKER, "same worker") \
957 _(DO_HANDOFF, "do handoff")
961 #define _(sym,str) NAT64_OUT2IN_HANDOFF_ERROR_##sym,
962 foreach_nat64_out2in_handoff_error
964 NAT64_OUT2IN_HANDOFF_N_ERROR,
965 } nat64_out2in_handoff_error_t;
967 static char *nat64_out2in_handoff_error_strings[] = {
968 #define _(sym,string) string,
969 foreach_nat64_out2in_handoff_error
975 u32 next_worker_index;
976 } nat64_out2in_handoff_trace_t;
979 format_nat64_out2in_handoff_trace (u8 * s, va_list * args)
981 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
982 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
983 nat64_out2in_handoff_trace_t *t =
984 va_arg (*args, nat64_out2in_handoff_trace_t *);
987 format (s, "NAT64-OUT2IN-HANDOFF: next-worker %d", t->next_worker_index);
993 nat64_out2in_handoff_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
994 vlib_frame_t * frame)
996 nat64_main_t *nm = &nat64_main;
997 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
998 u32 n_enq, n_left_from, *from;
999 u16 thread_indices[VLIB_FRAME_SIZE], *ti;
1001 u32 thread_index = vm->thread_index;
1002 u32 do_handoff = 0, same_worker = 0;
1004 from = vlib_frame_vector_args (frame);
1005 n_left_from = frame->n_vectors;
1006 vlib_get_buffers (vm, from, bufs, n_left_from);
1009 ti = thread_indices;
1011 fq_index = nm->fq_out2in_index;
1013 while (n_left_from > 0)
1017 ip0 = vlib_buffer_get_current (b[0]);
1018 ti[0] = nat64_get_worker_out2in (ip0);
1020 if (ti[0] != thread_index)
1026 ((node->flags & VLIB_NODE_FLAG_TRACE)
1027 && (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
1029 nat64_out2in_handoff_trace_t *t =
1030 vlib_add_trace (vm, node, b[0], sizeof (*t));
1031 t->next_worker_index = ti[0];
1040 vlib_buffer_enqueue_to_thread (vm, fq_index, from, thread_indices,
1041 frame->n_vectors, 1);
1043 if (n_enq < frame->n_vectors)
1044 vlib_node_increment_counter (vm, node->node_index,
1045 NAT64_OUT2IN_HANDOFF_ERROR_CONGESTION_DROP,
1046 frame->n_vectors - n_enq);
1047 vlib_node_increment_counter (vm, node->node_index,
1048 NAT64_OUT2IN_HANDOFF_ERROR_SAME_WORKER,
1050 vlib_node_increment_counter (vm, node->node_index,
1051 NAT64_OUT2IN_HANDOFF_ERROR_DO_HANDOFF,
1054 return frame->n_vectors;
1058 VLIB_REGISTER_NODE (nat64_out2in_handoff_node) = {
1059 .function = nat64_out2in_handoff_node_fn,
1060 .name = "nat64-out2in-handoff",
1061 .vector_size = sizeof (u32),
1062 .format_trace = format_nat64_out2in_handoff_trace,
1063 .type = VLIB_NODE_TYPE_INTERNAL,
1064 .n_errors = ARRAY_LEN(nat64_out2in_handoff_error_strings),
1065 .error_strings = nat64_out2in_handoff_error_strings,
1075 VLIB_NODE_FUNCTION_MULTIARCH (nat64_out2in_handoff_node,
1076 nat64_out2in_handoff_node_fn);
1078 * fd.io coding-style-patch-verification: ON
1081 * eval: (c-set-style "gnu")