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 IPv6 to IPv4 translation (inside to outside network)
20 #include <nat/nat64.h>
21 #include <nat/nat_inlines.h>
22 #include <vnet/ip/ip6_to_ip4.h>
23 #include <vnet/fib/fib_table.h>
24 #include <nat/lib/nat_inlines.h>
31 } nat64_in2out_trace_t;
34 format_nat64_in2out_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_in2out_trace_t *t = va_arg (*args, nat64_in2out_trace_t *);
41 tag = t->is_slow_path ? "NAT64-in2out-slowpath" : "NAT64-in2out";
44 format (s, "%s: sw_if_index %d, next index %d", tag, t->sw_if_index,
50 #define foreach_nat64_in2out_error \
51 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
52 _(NO_TRANSLATION, "no translation") \
58 #define _(sym,str) NAT64_IN2OUT_ERROR_##sym,
59 foreach_nat64_in2out_error
62 } nat64_in2out_error_t;
64 static char *nat64_in2out_error_strings[] = {
65 #define _(sym,string) string,
66 foreach_nat64_in2out_error
72 NAT64_IN2OUT_NEXT_IP4_LOOKUP,
73 NAT64_IN2OUT_NEXT_IP6_LOOKUP,
74 NAT64_IN2OUT_NEXT_DROP,
75 NAT64_IN2OUT_NEXT_SLOWPATH,
77 } nat64_in2out_next_t;
79 typedef struct nat64_in2out_set_ctx_t_
84 } nat64_in2out_set_ctx_t;
87 nat64_not_translate (u32 sw_if_index, ip6_address_t ip6_addr)
90 ip6_main_t *im6 = &ip6_main;
91 ip_lookup_main_t *lm6 = &im6->lookup_main;
92 ip_interface_address_t *ia = 0;
95 foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
97 addr = ip_interface_address_get_address (lm6, ia);
98 if (0 == ip6_address_compare (addr, &ip6_addr))
107 * @brief Check whether is a hairpinning.
109 * If the destination IP address of the packet is an IPv4 address assigned to
110 * the NAT64 itself, then the packet is a hairpin packet.
112 * param dst_addr Destination address of the packet.
114 * @returns 1 if hairpinning, otherwise 0.
116 static_always_inline int
117 is_hairpinning (ip6_address_t * dst_addr)
119 nat64_main_t *nm = &nat64_main;
122 for (i = 0; i < vec_len (nm->addr_pool); i++)
124 if (nm->addr_pool[i].addr.as_u32 == dst_addr->as_u32[3])
132 nat64_in2out_tcp_udp (vlib_main_t * vm, vlib_buffer_t * p, u16 l4_offset,
133 u16 frag_hdr_offset, nat64_in2out_set_ctx_t * ctx)
141 nat64_main_t *nm = &nat64_main;
142 nat64_db_bib_entry_t *bibe;
143 nat64_db_st_entry_t *ste;
144 ip46_address_t old_saddr, old_daddr;
145 ip4_address_t new_daddr;
146 u32 sw_if_index, fib_index;
147 u8 proto = vnet_buffer (p)->ip.reass.ip_proto;
148 u16 sport = vnet_buffer (p)->ip.reass.l4_src_port;
149 u16 dport = vnet_buffer (p)->ip.reass.l4_dst_port;
150 nat64_db_t *db = &nm->db[ctx->thread_index];
152 ip6 = vlib_buffer_get_current (p);
154 vlib_buffer_advance (p, l4_offset - sizeof (*ip4));
155 ip4 = vlib_buffer_get_current (p);
157 u32 ip_version_traffic_class_and_flow_label =
158 ip6->ip_version_traffic_class_and_flow_label;
159 u16 payload_length = ip6->payload_length;
160 u8 hop_limit = ip6->hop_limit;
162 old_saddr.as_u64[0] = ip6->src_address.as_u64[0];
163 old_saddr.as_u64[1] = ip6->src_address.as_u64[1];
164 old_daddr.as_u64[0] = ip6->dst_address.as_u64[0];
165 old_daddr.as_u64[1] = ip6->dst_address.as_u64[1];
167 if (PREDICT_FALSE (frag_hdr_offset))
169 //Only the first fragment
170 ip6_frag_hdr_t *hdr =
171 (ip6_frag_hdr_t *) u8_ptr_add (ip6, frag_hdr_offset);
172 fragment_id = frag_id_6to4 (hdr->identification);
173 frag_more = ip6_frag_hdr_more (hdr);
174 frag_offset = ip6_frag_hdr_offset (hdr);
183 ip4->ip_version_and_header_length =
184 IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS;
185 ip4->tos = ip6_translate_tos (ip_version_traffic_class_and_flow_label);
187 u16_net_add (payload_length, sizeof (*ip4) + sizeof (*ip6) - l4_offset);
188 ip4->fragment_id = fragment_id;
189 ip4->flags_and_fragment_offset =
190 clib_host_to_net_u16 (frag_offset |
191 (frag_more ? IP4_HEADER_FLAG_MORE_FRAGMENTS : 0));
192 ip4->ttl = hop_limit;
193 ip4->protocol = (proto == IP_PROTOCOL_ICMP6) ? IP_PROTOCOL_ICMP : proto;
195 sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
197 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
200 nat64_db_st_entry_find (db, &old_saddr, &old_daddr, sport, dport, proto,
205 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
212 nat64_db_bib_entry_find (db, &old_saddr, sport, proto, fib_index, 1);
217 ip4_address_t out_addr;
218 if (nat64_alloc_out_addr_and_port
219 (fib_index, ip_proto_to_nat_proto (proto), &out_addr,
220 &out_port, ctx->thread_index))
224 nat64_db_bib_entry_create (ctx->thread_index, db,
225 &old_saddr.ip6, &out_addr, sport,
226 out_port, fib_index, proto, 0);
230 vlib_set_simple_counter (&nm->total_bibs, ctx->thread_index, 0,
231 db->bib.bib_entries_num);
234 nat64_extract_ip4 (&old_daddr.ip6, &new_daddr, fib_index);
236 nat64_db_st_entry_create (ctx->thread_index, db, bibe,
237 &old_daddr.ip6, &new_daddr, dport);
241 vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
242 db->st.st_entries_num);
245 ip4->src_address.as_u32 = bibe->out_addr.as_u32;
246 ip4->dst_address.as_u32 = ste->out_r_addr.as_u32;
248 ip4->checksum = ip4_header_checksum (ip4);
250 if (!vnet_buffer (p)->ip.reass.is_non_first_fragment)
252 udp_header_t *udp = (udp_header_t *) (ip4 + 1);
253 udp->src_port = bibe->out_port;
255 //UDP checksum is optional over IPv4
256 if (proto == IP_PROTOCOL_UDP)
262 tcp_header_t *tcp = (tcp_header_t *) (ip4 + 1);
263 csum = ip_csum_sub_even (tcp->checksum, old_saddr.as_u64[0]);
264 csum = ip_csum_sub_even (csum, old_saddr.as_u64[1]);
265 csum = ip_csum_sub_even (csum, old_daddr.as_u64[0]);
266 csum = ip_csum_sub_even (csum, old_daddr.as_u64[1]);
267 csum = ip_csum_add_even (csum, ip4->dst_address.as_u32);
268 csum = ip_csum_add_even (csum, ip4->src_address.as_u32);
269 csum = ip_csum_sub_even (csum, sport);
270 csum = ip_csum_add_even (csum, udp->src_port);
271 mss_clamping (nm->sm->mss_clamping, tcp, &csum);
272 tcp->checksum = ip_csum_fold (csum);
274 nat64_tcp_session_set_state (ste, tcp, 1);
278 nat64_session_reset_timeout (ste, ctx->vm);
284 nat64_in2out_icmp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4, void *arg)
286 nat64_main_t *nm = &nat64_main;
287 nat64_in2out_set_ctx_t *ctx = arg;
288 nat64_db_bib_entry_t *bibe;
289 nat64_db_st_entry_t *ste;
290 ip46_address_t saddr, daddr;
291 u32 sw_if_index, fib_index;
292 icmp46_header_t *icmp = ip6_next_header (ip6);
293 nat64_db_t *db = &nm->db[ctx->thread_index];
295 sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
297 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
299 saddr.as_u64[0] = ip6->src_address.as_u64[0];
300 saddr.as_u64[1] = ip6->src_address.as_u64[1];
301 daddr.as_u64[0] = ip6->dst_address.as_u64[0];
302 daddr.as_u64[1] = ip6->dst_address.as_u64[1];
304 if (icmp->type == ICMP4_echo_request || icmp->type == ICMP4_echo_reply)
306 u16 in_id = ((u16 *) (icmp))[2];
308 nat64_db_st_entry_find (db, &saddr, &daddr, in_id, 0,
309 IP_PROTOCOL_ICMP, fib_index, 1);
314 nat64_db_bib_entry_by_index (db, IP_PROTOCOL_ICMP,
322 nat64_db_bib_entry_find (db, &saddr, in_id,
323 IP_PROTOCOL_ICMP, fib_index, 1);
328 ip4_address_t out_addr;
329 if (nat64_alloc_out_addr_and_port
330 (fib_index, NAT_PROTOCOL_ICMP, &out_addr, &out_id,
335 nat64_db_bib_entry_create (ctx->thread_index, db,
336 &ip6->src_address, &out_addr,
337 in_id, out_id, fib_index,
338 IP_PROTOCOL_ICMP, 0);
342 vlib_set_simple_counter (&nm->total_bibs, ctx->thread_index, 0,
343 db->bib.bib_entries_num);
346 nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
348 nat64_db_st_entry_create (ctx->thread_index, db, bibe,
349 &ip6->dst_address, &daddr.ip4, 0);
353 vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
354 db->st.st_entries_num);
357 nat64_session_reset_timeout (ste, ctx->vm);
359 ip4->src_address.as_u32 = bibe->out_addr.as_u32;
360 ((u16 *) (icmp))[2] = bibe->out_port;
362 ip4->dst_address.as_u32 = ste->out_r_addr.as_u32;
366 if (!vec_len (nm->addr_pool))
369 ip4->src_address.as_u32 = nm->addr_pool[0].addr.as_u32;
370 nat64_extract_ip4 (&ip6->dst_address, &ip4->dst_address, fib_index);
377 nat64_in2out_inner_icmp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4,
380 nat64_main_t *nm = &nat64_main;
381 nat64_in2out_set_ctx_t *ctx = arg;
382 nat64_db_st_entry_t *ste;
383 nat64_db_bib_entry_t *bibe;
384 ip46_address_t saddr, daddr;
385 u32 sw_if_index, fib_index;
386 u8 proto = ip6->protocol;
387 nat64_db_t *db = &nm->db[ctx->thread_index];
389 sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
391 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
393 saddr.as_u64[0] = ip6->src_address.as_u64[0];
394 saddr.as_u64[1] = ip6->src_address.as_u64[1];
395 daddr.as_u64[0] = ip6->dst_address.as_u64[0];
396 daddr.as_u64[1] = ip6->dst_address.as_u64[1];
398 if (proto == IP_PROTOCOL_ICMP6)
400 icmp46_header_t *icmp = ip6_next_header (ip6);
401 u16 in_id = ((u16 *) (icmp))[2];
402 proto = IP_PROTOCOL_ICMP;
405 (icmp->type == ICMP4_echo_request
406 || icmp->type == ICMP4_echo_reply))
410 nat64_db_st_entry_find (db, &daddr, &saddr, in_id, 0, proto,
415 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
419 ip4->dst_address.as_u32 = bibe->out_addr.as_u32;
420 ((u16 *) (icmp))[2] = bibe->out_port;
421 ip4->src_address.as_u32 = ste->out_r_addr.as_u32;
425 udp_header_t *udp = ip6_next_header (ip6);
426 tcp_header_t *tcp = ip6_next_header (ip6);
430 u16 sport = udp->src_port;
431 u16 dport = udp->dst_port;
434 nat64_db_st_entry_find (db, &daddr, &saddr, dport, sport, proto,
439 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
443 ip4->dst_address.as_u32 = bibe->out_addr.as_u32;
444 udp->dst_port = bibe->out_port;
445 ip4->src_address.as_u32 = ste->out_r_addr.as_u32;
447 if (proto == IP_PROTOCOL_TCP)
448 checksum = &tcp->checksum;
450 checksum = &udp->checksum;
451 csum = ip_csum_sub_even (*checksum, dport);
452 csum = ip_csum_add_even (csum, udp->dst_port);
453 *checksum = ip_csum_fold (csum);
459 typedef struct unk_proto_st_walk_ctx_t_
461 ip6_address_t src_addr;
462 ip6_address_t dst_addr;
463 ip4_address_t out_addr;
467 } unk_proto_st_walk_ctx_t;
470 unk_proto_st_walk (nat64_db_st_entry_t * ste, void *arg)
472 nat64_main_t *nm = &nat64_main;
473 unk_proto_st_walk_ctx_t *ctx = arg;
474 nat64_db_bib_entry_t *bibe;
475 ip46_address_t saddr, daddr;
476 nat64_db_t *db = &nm->db[ctx->thread_index];
478 if (ip6_address_is_equal (&ste->in_r_addr, &ctx->dst_addr))
480 bibe = nat64_db_bib_entry_by_index (db, ste->proto, ste->bibe_index);
484 if (ip6_address_is_equal (&bibe->in_addr, &ctx->src_addr)
485 && bibe->fib_index == ctx->fib_index)
487 clib_memset (&saddr, 0, sizeof (saddr));
488 saddr.ip4.as_u32 = bibe->out_addr.as_u32;
489 clib_memset (&daddr, 0, sizeof (daddr));
490 nat64_extract_ip4 (&ctx->dst_addr, &daddr.ip4, ctx->fib_index);
492 if (nat64_db_st_entry_find
493 (db, &daddr, &saddr, 0, 0, ctx->proto, ctx->fib_index, 0))
496 ctx->out_addr.as_u32 = bibe->out_addr.as_u32;
505 nat64_in2out_unk_proto (vlib_main_t * vm, vlib_buffer_t * p, u8 l4_protocol,
506 u16 l4_offset, u16 frag_hdr_offset,
507 nat64_in2out_set_ctx_t * s_ctx)
515 ip6 = vlib_buffer_get_current (p);
517 ip4 = (ip4_header_t *) u8_ptr_add (ip6, l4_offset - sizeof (*ip4));
519 vlib_buffer_advance (p, l4_offset - sizeof (*ip4));
521 if (PREDICT_FALSE (frag_hdr_offset))
523 //Only the first fragment
524 ip6_frag_hdr_t *hdr =
525 (ip6_frag_hdr_t *) u8_ptr_add (ip6, frag_hdr_offset);
526 fragment_id = frag_id_6to4 (hdr->identification);
527 frag_offset = ip6_frag_hdr_offset (hdr);
528 frag_more = ip6_frag_hdr_more (hdr);
537 nat64_main_t *nm = &nat64_main;
538 nat64_db_bib_entry_t *bibe;
539 nat64_db_st_entry_t *ste;
540 ip46_address_t saddr, daddr, addr;
541 u32 sw_if_index, fib_index;
543 nat64_db_t *db = &nm->db[s_ctx->thread_index];
545 sw_if_index = vnet_buffer (s_ctx->b)->sw_if_index[VLIB_RX];
547 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
549 saddr.as_u64[0] = ip6->src_address.as_u64[0];
550 saddr.as_u64[1] = ip6->src_address.as_u64[1];
551 daddr.as_u64[0] = ip6->dst_address.as_u64[0];
552 daddr.as_u64[1] = ip6->dst_address.as_u64[1];
555 nat64_db_st_entry_find (db, &saddr, &daddr, 0, 0, l4_protocol, fib_index,
560 bibe = nat64_db_bib_entry_by_index (db, l4_protocol, ste->bibe_index);
567 nat64_db_bib_entry_find (db, &saddr, 0, l4_protocol, fib_index, 1);
571 /* Choose same out address as for TCP/UDP session to same dst */
572 unk_proto_st_walk_ctx_t ctx = {
573 .src_addr.as_u64[0] = ip6->src_address.as_u64[0],
574 .src_addr.as_u64[1] = ip6->src_address.as_u64[1],
575 .dst_addr.as_u64[0] = ip6->dst_address.as_u64[0],
576 .dst_addr.as_u64[1] = ip6->dst_address.as_u64[1],
577 .out_addr.as_u32 = 0,
578 .fib_index = fib_index,
579 .proto = l4_protocol,
580 .thread_index = s_ctx->thread_index,
583 nat64_db_st_walk (db, IP_PROTOCOL_TCP, unk_proto_st_walk, &ctx);
585 if (!ctx.out_addr.as_u32)
586 nat64_db_st_walk (db, IP_PROTOCOL_UDP, unk_proto_st_walk, &ctx);
588 /* Verify if out address is not already in use for protocol */
589 clib_memset (&addr, 0, sizeof (addr));
590 addr.ip4.as_u32 = ctx.out_addr.as_u32;
591 if (nat64_db_bib_entry_find (db, &addr, 0, l4_protocol, 0, 0))
592 ctx.out_addr.as_u32 = 0;
594 if (!ctx.out_addr.as_u32)
596 for (i = 0; i < vec_len (nm->addr_pool); i++)
598 addr.ip4.as_u32 = nm->addr_pool[i].addr.as_u32;
599 if (!nat64_db_bib_entry_find
600 (db, &addr, 0, l4_protocol, 0, 0))
605 if (!ctx.out_addr.as_u32)
609 nat64_db_bib_entry_create (s_ctx->thread_index, db,
610 &ip6->src_address, &ctx.out_addr,
611 0, 0, fib_index, l4_protocol, 0);
615 vlib_set_simple_counter (&nm->total_bibs, s_ctx->thread_index, 0,
616 db->bib.bib_entries_num);
619 nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
621 nat64_db_st_entry_create (s_ctx->thread_index, db, bibe,
622 &ip6->dst_address, &daddr.ip4, 0);
626 vlib_set_simple_counter (&nm->total_sessions, s_ctx->thread_index, 0,
627 db->st.st_entries_num);
630 nat64_session_reset_timeout (ste, s_ctx->vm);
632 ip4->src_address.as_u32 = bibe->out_addr.as_u32;
633 ip4->dst_address.as_u32 = ste->out_r_addr.as_u32;
635 ip4->ip_version_and_header_length =
636 IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS;
637 ip4->tos = ip6_translate_tos (ip6->ip_version_traffic_class_and_flow_label);
638 ip4->length = u16_net_add (ip6->payload_length,
639 sizeof (*ip4) + sizeof (*ip6) - l4_offset);
640 ip4->fragment_id = fragment_id;
641 ip4->flags_and_fragment_offset =
642 clib_host_to_net_u16 (frag_offset |
643 (frag_more ? IP4_HEADER_FLAG_MORE_FRAGMENTS : 0));
644 ip4->ttl = ip6->hop_limit;
645 ip4->protocol = l4_protocol;
646 ip4->checksum = ip4_header_checksum (ip4);
652 nat64_in2out_tcp_udp_hairpinning (vlib_main_t * vm, vlib_buffer_t * b,
653 ip6_header_t * ip6, u32 l4_offset,
656 nat64_main_t *nm = &nat64_main;
657 nat64_db_bib_entry_t *bibe;
658 nat64_db_st_entry_t *ste;
659 ip46_address_t saddr, daddr;
660 u32 sw_if_index, fib_index;
661 udp_header_t *udp = (udp_header_t *) u8_ptr_add (ip6, l4_offset);
662 tcp_header_t *tcp = (tcp_header_t *) u8_ptr_add (ip6, l4_offset);
663 u8 proto = vnet_buffer (b)->ip.reass.ip_proto;
664 u16 sport = vnet_buffer (b)->ip.reass.l4_src_port;
665 u16 dport = vnet_buffer (b)->ip.reass.l4_dst_port;
666 u16 *checksum = NULL;
668 nat64_db_t *db = &nm->db[thread_index];
670 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
672 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
674 saddr.as_u64[0] = ip6->src_address.as_u64[0];
675 saddr.as_u64[1] = ip6->src_address.as_u64[1];
676 daddr.as_u64[0] = ip6->dst_address.as_u64[0];
677 daddr.as_u64[1] = ip6->dst_address.as_u64[1];
679 if (!vnet_buffer (b)->ip.reass.is_non_first_fragment)
681 if (proto == IP_PROTOCOL_UDP)
682 checksum = &udp->checksum;
684 checksum = &tcp->checksum;
685 csum = ip_csum_sub_even (*checksum, ip6->src_address.as_u64[0]);
686 csum = ip_csum_sub_even (csum, ip6->src_address.as_u64[1]);
687 csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[0]);
688 csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[1]);
692 nat64_db_st_entry_find (db, &saddr, &daddr, sport, dport, proto,
697 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
703 bibe = nat64_db_bib_entry_find (db, &saddr, sport, proto, fib_index, 1);
708 ip4_address_t out_addr;
709 if (nat64_alloc_out_addr_and_port
710 (fib_index, ip_proto_to_nat_proto (proto), &out_addr,
711 &out_port, thread_index))
715 nat64_db_bib_entry_create (thread_index, db, &ip6->src_address,
716 &out_addr, sport, out_port, fib_index,
721 vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
722 db->bib.bib_entries_num);
725 nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
727 nat64_db_st_entry_create (thread_index, db, bibe, &ip6->dst_address,
732 vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
733 db->st.st_entries_num);
736 if (proto == IP_PROTOCOL_TCP)
737 nat64_tcp_session_set_state (ste, tcp, 1);
739 nat64_session_reset_timeout (ste, vm);
741 if (!vnet_buffer (b)->ip.reass.is_non_first_fragment)
743 udp->src_port = bibe->out_port;
746 nat64_compose_ip6 (&ip6->src_address, &bibe->out_addr, fib_index);
748 clib_memset (&daddr, 0, sizeof (daddr));
749 daddr.ip4.as_u32 = ste->out_r_addr.as_u32;
753 vec_foreach (db, nm->db)
755 bibe = nat64_db_bib_entry_find (db, &daddr, dport, proto, 0, 0);
765 ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
766 ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
768 if (!vnet_buffer (b)->ip.reass.is_non_first_fragment)
770 csum = ip_csum_add_even (csum, ip6->src_address.as_u64[0]);
771 csum = ip_csum_add_even (csum, ip6->src_address.as_u64[1]);
772 csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[0]);
773 csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[1]);
774 csum = ip_csum_sub_even (csum, sport);
775 csum = ip_csum_sub_even (csum, dport);
776 udp->dst_port = bibe->in_port;
777 csum = ip_csum_add_even (csum, udp->src_port);
778 csum = ip_csum_add_even (csum, udp->dst_port);
779 *checksum = ip_csum_fold (csum);
786 nat64_in2out_icmp_hairpinning (vlib_main_t * vm, vlib_buffer_t * b,
787 ip6_header_t * ip6, u32 thread_index)
789 nat64_main_t *nm = &nat64_main;
790 nat64_db_bib_entry_t *bibe;
791 nat64_db_st_entry_t *ste;
792 icmp46_header_t *icmp = ip6_next_header (ip6);
793 ip6_header_t *inner_ip6;
794 ip46_address_t saddr, daddr;
795 u32 sw_if_index, fib_index;
799 u16 *checksum, sport, dport;
801 nat64_db_t *db = &nm->db[thread_index];
803 if (icmp->type == ICMP6_echo_request || icmp->type == ICMP6_echo_reply)
806 inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
808 proto = inner_ip6->protocol;
810 if (proto == IP_PROTOCOL_ICMP6)
813 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
815 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
817 saddr.as_u64[0] = inner_ip6->src_address.as_u64[0];
818 saddr.as_u64[1] = inner_ip6->src_address.as_u64[1];
819 daddr.as_u64[0] = inner_ip6->dst_address.as_u64[0];
820 daddr.as_u64[1] = inner_ip6->dst_address.as_u64[1];
822 udp = ip6_next_header (inner_ip6);
823 tcp = ip6_next_header (inner_ip6);
825 sport = udp->src_port;
826 dport = udp->dst_port;
828 if (proto == IP_PROTOCOL_UDP)
829 checksum = &udp->checksum;
831 checksum = &tcp->checksum;
833 csum = ip_csum_sub_even (*checksum, inner_ip6->src_address.as_u64[0]);
834 csum = ip_csum_sub_even (csum, inner_ip6->src_address.as_u64[1]);
835 csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[0]);
836 csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[1]);
837 csum = ip_csum_sub_even (csum, sport);
838 csum = ip_csum_sub_even (csum, dport);
841 nat64_db_st_entry_find (db, &daddr, &saddr, dport, sport, proto,
846 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
850 dport = udp->dst_port = bibe->out_port;
851 nat64_compose_ip6 (&inner_ip6->dst_address, &bibe->out_addr, fib_index);
853 clib_memset (&saddr, 0, sizeof (saddr));
854 clib_memset (&daddr, 0, sizeof (daddr));
855 saddr.ip4.as_u32 = ste->out_r_addr.as_u32;
856 daddr.ip4.as_u32 = bibe->out_addr.as_u32;
860 vec_foreach (db, nm->db)
862 ste = nat64_db_st_entry_find (db, &saddr, &daddr, sport, dport, proto,
873 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
877 inner_ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
878 inner_ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
879 udp->src_port = bibe->in_port;
881 csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[0]);
882 csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[1]);
883 csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[0]);
884 csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[1]);
885 csum = ip_csum_add_even (csum, udp->src_port);
886 csum = ip_csum_add_even (csum, udp->dst_port);
887 *checksum = ip_csum_fold (csum);
889 if (!vec_len (nm->addr_pool))
892 nat64_compose_ip6 (&ip6->src_address, &nm->addr_pool[0].addr, fib_index);
893 ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0];
894 ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1];
897 csum = ip_csum_with_carry (0, ip6->payload_length);
898 csum = ip_csum_with_carry (csum, clib_host_to_net_u16 (ip6->protocol));
899 csum = ip_csum_with_carry (csum, ip6->src_address.as_u64[0]);
900 csum = ip_csum_with_carry (csum, ip6->src_address.as_u64[1]);
901 csum = ip_csum_with_carry (csum, ip6->dst_address.as_u64[0]);
902 csum = ip_csum_with_carry (csum, ip6->dst_address.as_u64[1]);
904 ip_incremental_checksum (csum, icmp,
905 clib_net_to_host_u16 (ip6->payload_length));
906 icmp->checksum = ~ip_csum_fold (csum);
912 nat64_in2out_unk_proto_hairpinning (vlib_main_t * vm, vlib_buffer_t * b,
913 ip6_header_t * ip6, u32 thread_index)
915 nat64_main_t *nm = &nat64_main;
916 nat64_db_bib_entry_t *bibe;
917 nat64_db_st_entry_t *ste;
918 ip46_address_t saddr, daddr, addr;
919 u32 sw_if_index, fib_index;
920 u8 proto = ip6->protocol;
922 nat64_db_t *db = &nm->db[thread_index];
924 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
926 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
928 saddr.as_u64[0] = ip6->src_address.as_u64[0];
929 saddr.as_u64[1] = ip6->src_address.as_u64[1];
930 daddr.as_u64[0] = ip6->dst_address.as_u64[0];
931 daddr.as_u64[1] = ip6->dst_address.as_u64[1];
934 nat64_db_st_entry_find (db, &saddr, &daddr, 0, 0, proto, fib_index, 1);
938 bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
944 bibe = nat64_db_bib_entry_find (db, &saddr, 0, proto, fib_index, 1);
948 /* Choose same out address as for TCP/UDP session to same dst */
949 unk_proto_st_walk_ctx_t ctx = {
950 .src_addr.as_u64[0] = ip6->src_address.as_u64[0],
951 .src_addr.as_u64[1] = ip6->src_address.as_u64[1],
952 .dst_addr.as_u64[0] = ip6->dst_address.as_u64[0],
953 .dst_addr.as_u64[1] = ip6->dst_address.as_u64[1],
954 .out_addr.as_u32 = 0,
955 .fib_index = fib_index,
957 .thread_index = thread_index,
960 nat64_db_st_walk (db, IP_PROTOCOL_TCP, unk_proto_st_walk, &ctx);
962 if (!ctx.out_addr.as_u32)
963 nat64_db_st_walk (db, IP_PROTOCOL_UDP, unk_proto_st_walk, &ctx);
965 /* Verify if out address is not already in use for protocol */
966 clib_memset (&addr, 0, sizeof (addr));
967 addr.ip4.as_u32 = ctx.out_addr.as_u32;
968 if (nat64_db_bib_entry_find (db, &addr, 0, proto, 0, 0))
969 ctx.out_addr.as_u32 = 0;
971 if (!ctx.out_addr.as_u32)
973 for (i = 0; i < vec_len (nm->addr_pool); i++)
975 addr.ip4.as_u32 = nm->addr_pool[i].addr.as_u32;
976 if (!nat64_db_bib_entry_find (db, &addr, 0, proto, 0, 0))
981 if (!ctx.out_addr.as_u32)
985 nat64_db_bib_entry_create (thread_index, db, &ip6->src_address,
986 &ctx.out_addr, 0, 0, fib_index, proto,
991 vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
992 db->bib.bib_entries_num);
995 nat64_extract_ip4 (&ip6->dst_address, &daddr.ip4, fib_index);
997 nat64_db_st_entry_create (thread_index, db, bibe, &ip6->dst_address,
1002 vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
1003 db->st.st_entries_num);
1006 nat64_session_reset_timeout (ste, vm);
1008 nat64_compose_ip6 (&ip6->src_address, &bibe->out_addr, fib_index);
1010 clib_memset (&daddr, 0, sizeof (daddr));
1011 daddr.ip4.as_u32 = ste->out_r_addr.as_u32;
1015 vec_foreach (db, nm->db)
1017 bibe = nat64_db_bib_entry_find (db, &daddr, 0, proto, 0, 0);
1027 ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
1028 ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
1034 nat64_in2out_node_fn_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1035 vlib_frame_t * frame, u8 is_slow_path)
1037 u32 n_left_from, *from, *to_next;
1038 nat64_in2out_next_t next_index;
1039 u32 thread_index = vm->thread_index;
1040 nat64_main_t *nm = &nat64_main;
1042 from = vlib_frame_vector_args (frame);
1043 n_left_from = frame->n_vectors;
1044 next_index = node->cached_next_index;
1046 while (n_left_from > 0)
1050 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1052 while (n_left_from > 0 && n_left_to_next > 0)
1058 u16 l4_offset0, frag_hdr_offset0;
1061 nat64_in2out_set_ctx_t ctx0;
1064 /* speculatively enqueue b0 to the current next frame */
1070 n_left_to_next -= 1;
1072 b0 = vlib_get_buffer (vm, bi0);
1073 ip60 = vlib_buffer_get_current (b0);
1075 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1079 ctx0.thread_index = thread_index;
1081 next0 = NAT64_IN2OUT_NEXT_IP4_LOOKUP;
1085 (vm, b0, ip60, b0->current_length, &l4_protocol0, &l4_offset0,
1086 &frag_hdr_offset0)))
1088 next0 = NAT64_IN2OUT_NEXT_DROP;
1089 b0->error = node->errors[NAT64_IN2OUT_ERROR_UNKNOWN];
1093 if (nat64_not_translate (sw_if_index0, ip60->dst_address))
1095 next0 = NAT64_IN2OUT_NEXT_IP6_LOOKUP;
1099 proto0 = ip_proto_to_nat_proto (l4_protocol0);
1103 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_OTHER))
1105 vlib_increment_simple_counter (&nm->counters.in2out.other,
1106 thread_index, sw_if_index0,
1108 if (is_hairpinning (&ip60->dst_address))
1110 next0 = NAT64_IN2OUT_NEXT_IP6_LOOKUP;
1111 if (nat64_in2out_unk_proto_hairpinning
1112 (vm, b0, ip60, thread_index))
1114 next0 = NAT64_IN2OUT_NEXT_DROP;
1116 node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
1121 if (nat64_in2out_unk_proto
1122 (vm, b0, l4_protocol0, l4_offset0, frag_hdr_offset0,
1125 next0 = NAT64_IN2OUT_NEXT_DROP;
1127 node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
1135 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1137 next0 = NAT64_IN2OUT_NEXT_SLOWPATH;
1142 if (proto0 == NAT_PROTOCOL_ICMP)
1144 vlib_increment_simple_counter (&nm->counters.in2out.icmp,
1145 thread_index, sw_if_index0, 1);
1146 if (is_hairpinning (&ip60->dst_address))
1148 next0 = NAT64_IN2OUT_NEXT_IP6_LOOKUP;
1149 if (nat64_in2out_icmp_hairpinning
1150 (vm, b0, ip60, thread_index))
1152 next0 = NAT64_IN2OUT_NEXT_DROP;
1154 node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
1160 (vm, b0, nat64_in2out_icmp_set_cb, &ctx0,
1161 nat64_in2out_inner_icmp_set_cb, &ctx0))
1163 next0 = NAT64_IN2OUT_NEXT_DROP;
1164 b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
1168 else if (proto0 == NAT_PROTOCOL_TCP || proto0 == NAT_PROTOCOL_UDP)
1170 if (proto0 == NAT_PROTOCOL_TCP)
1171 vlib_increment_simple_counter (&nm->counters.in2out.tcp,
1172 thread_index, sw_if_index0, 1);
1174 vlib_increment_simple_counter (&nm->counters.in2out.udp,
1175 thread_index, sw_if_index0, 1);
1177 if (is_hairpinning (&ip60->dst_address))
1179 next0 = NAT64_IN2OUT_NEXT_IP6_LOOKUP;
1180 if (nat64_in2out_tcp_udp_hairpinning
1181 (vm, b0, ip60, l4_offset0, thread_index))
1183 next0 = NAT64_IN2OUT_NEXT_DROP;
1185 node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
1190 if (nat64_in2out_tcp_udp
1191 (vm, b0, l4_offset0, frag_hdr_offset0, &ctx0))
1193 next0 = NAT64_IN2OUT_NEXT_DROP;
1194 b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
1200 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1201 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1203 nat64_in2out_trace_t *t =
1204 vlib_add_trace (vm, node, b0, sizeof (*t));
1205 t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1206 t->next_index = next0;
1207 t->is_slow_path = is_slow_path;
1210 if (next0 == NAT64_IN2OUT_NEXT_DROP)
1212 vlib_increment_simple_counter (&nm->counters.in2out.drops,
1213 thread_index, sw_if_index0, 1);
1217 /* verify speculative enqueue, maybe switch current next frame */
1218 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1219 n_left_to_next, bi0, next0);
1221 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1224 return frame->n_vectors;
1227 VLIB_NODE_FN (nat64_in2out_node) (vlib_main_t * vm,
1228 vlib_node_runtime_t * node,
1229 vlib_frame_t * frame)
1231 return nat64_in2out_node_fn_inline (vm, node, frame, 0);
1235 VLIB_REGISTER_NODE (nat64_in2out_node) = {
1236 .name = "nat64-in2out",
1237 .vector_size = sizeof (u32),
1238 .format_trace = format_nat64_in2out_trace,
1239 .type = VLIB_NODE_TYPE_INTERNAL,
1240 .n_errors = ARRAY_LEN (nat64_in2out_error_strings),
1241 .error_strings = nat64_in2out_error_strings,
1242 .n_next_nodes = NAT64_IN2OUT_N_NEXT,
1243 /* edit / add dispositions here */
1245 [NAT64_IN2OUT_NEXT_DROP] = "error-drop",
1246 [NAT64_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup",
1247 [NAT64_IN2OUT_NEXT_IP6_LOOKUP] = "ip6-lookup",
1248 [NAT64_IN2OUT_NEXT_SLOWPATH] = "nat64-in2out-slowpath",
1253 VLIB_NODE_FN (nat64_in2out_slowpath_node) (vlib_main_t * vm,
1254 vlib_node_runtime_t * node,
1255 vlib_frame_t * frame)
1257 return nat64_in2out_node_fn_inline (vm, node, frame, 1);
1261 VLIB_REGISTER_NODE (nat64_in2out_slowpath_node) = {
1262 .name = "nat64-in2out-slowpath",
1263 .vector_size = sizeof (u32),
1264 .format_trace = format_nat64_in2out_trace,
1265 .type = VLIB_NODE_TYPE_INTERNAL,
1266 .n_errors = ARRAY_LEN (nat64_in2out_error_strings),
1267 .error_strings = nat64_in2out_error_strings,
1268 .n_next_nodes = NAT64_IN2OUT_N_NEXT,
1269 /* edit / add dispositions here */
1271 [NAT64_IN2OUT_NEXT_DROP] = "error-drop",
1272 [NAT64_IN2OUT_NEXT_IP4_LOOKUP] = "ip4-lookup",
1273 [NAT64_IN2OUT_NEXT_IP6_LOOKUP] = "ip6-lookup",
1274 [NAT64_IN2OUT_NEXT_SLOWPATH] = "nat64-in2out-slowpath",
1279 typedef struct nat64_in2out_frag_set_ctx_t_
1287 } nat64_in2out_frag_set_ctx_t;
1290 #define foreach_nat64_in2out_handoff_error \
1291 _(CONGESTION_DROP, "congestion drop") \
1292 _(SAME_WORKER, "same worker") \
1293 _(DO_HANDOFF, "do handoff")
1297 #define _(sym,str) NAT64_IN2OUT_HANDOFF_ERROR_##sym,
1298 foreach_nat64_in2out_handoff_error
1300 NAT64_IN2OUT_HANDOFF_N_ERROR,
1301 } nat64_in2out_handoff_error_t;
1303 static char *nat64_in2out_handoff_error_strings[] = {
1304 #define _(sym,string) string,
1305 foreach_nat64_in2out_handoff_error
1311 u32 next_worker_index;
1312 } nat64_in2out_handoff_trace_t;
1315 format_nat64_in2out_handoff_trace (u8 * s, va_list * args)
1317 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1318 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1319 nat64_in2out_handoff_trace_t *t =
1320 va_arg (*args, nat64_in2out_handoff_trace_t *);
1323 format (s, "NAT64-IN2OUT-HANDOFF: next-worker %d", t->next_worker_index);
1328 VLIB_NODE_FN (nat64_in2out_handoff_node) (vlib_main_t * vm,
1329 vlib_node_runtime_t * node,
1330 vlib_frame_t * frame)
1332 nat64_main_t *nm = &nat64_main;
1333 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1334 u32 n_enq, n_left_from, *from;
1335 u16 thread_indices[VLIB_FRAME_SIZE], *ti;
1337 u32 thread_index = vm->thread_index;
1338 u32 do_handoff = 0, same_worker = 0;
1340 from = vlib_frame_vector_args (frame);
1341 n_left_from = frame->n_vectors;
1342 vlib_get_buffers (vm, from, bufs, n_left_from);
1345 ti = thread_indices;
1347 fq_index = nm->fq_in2out_index;
1349 while (n_left_from > 0)
1353 ip0 = vlib_buffer_get_current (b[0]);
1354 ti[0] = nat64_get_worker_in2out (&ip0->src_address);
1356 if (ti[0] != thread_index)
1362 ((node->flags & VLIB_NODE_FLAG_TRACE)
1363 && (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
1365 nat64_in2out_handoff_trace_t *t =
1366 vlib_add_trace (vm, node, b[0], sizeof (*t));
1367 t->next_worker_index = ti[0];
1376 vlib_buffer_enqueue_to_thread (vm, fq_index, from, thread_indices,
1377 frame->n_vectors, 1);
1379 if (n_enq < frame->n_vectors)
1380 vlib_node_increment_counter (vm, node->node_index,
1381 NAT64_IN2OUT_HANDOFF_ERROR_CONGESTION_DROP,
1382 frame->n_vectors - n_enq);
1383 vlib_node_increment_counter (vm, node->node_index,
1384 NAT64_IN2OUT_HANDOFF_ERROR_SAME_WORKER,
1386 vlib_node_increment_counter (vm, node->node_index,
1387 NAT64_IN2OUT_HANDOFF_ERROR_DO_HANDOFF,
1390 return frame->n_vectors;
1394 VLIB_REGISTER_NODE (nat64_in2out_handoff_node) = {
1395 .name = "nat64-in2out-handoff",
1396 .vector_size = sizeof (u32),
1397 .format_trace = format_nat64_in2out_handoff_trace,
1398 .type = VLIB_NODE_TYPE_INTERNAL,
1399 .n_errors = ARRAY_LEN(nat64_in2out_handoff_error_strings),
1400 .error_strings = nat64_in2out_handoff_error_strings,
1411 * fd.io coding-style-patch-verification: ON
1414 * eval: (c-set-style "gnu")