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 <snat/nat64.h>
21 #include <vnet/ip/ip6_to_ip4.h>
22 #include <vnet/fib/fib_table.h>
28 } nat64_in2out_trace_t;
31 format_nat64_in2out_trace (u8 * s, va_list * args)
33 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
34 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
35 nat64_in2out_trace_t *t = va_arg (*args, nat64_in2out_trace_t *);
38 format (s, "NAT64-in2out: sw_if_index %d, next index %d", t->sw_if_index,
44 vlib_node_registration_t nat64_in2out_node;
46 #define foreach_nat64_in2out_error \
47 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
48 _(IN2OUT_PACKETS, "good in2out packets processed") \
49 _(NO_TRANSLATION, "no translation") \
54 #define _(sym,str) NAT64_IN2OUT_ERROR_##sym,
55 foreach_nat64_in2out_error
58 } nat64_in2out_error_t;
60 static char *nat64_in2out_error_strings[] = {
61 #define _(sym,string) string,
62 foreach_nat64_in2out_error
68 NAT64_IN2OUT_NEXT_LOOKUP,
69 NAT64_IN2OUT_NEXT_DROP,
71 } nat64_in2out_next_t;
73 typedef struct nat64_in2out_set_ctx_t_
77 } nat64_in2out_set_ctx_t;
80 nat64_in2out_tcp_udp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4,
83 nat64_main_t *nm = &nat64_main;
84 nat64_in2out_set_ctx_t *ctx = arg;
85 nat64_db_bib_entry_t *bibe;
86 nat64_db_st_entry_t *ste;
87 ip46_address_t saddr, daddr;
88 u32 sw_if_index, fib_index;
89 udp_header_t *udp = ip6_next_header (ip6);
90 snat_protocol_t proto = ip_proto_to_snat_proto (ip6->protocol);
91 u16 sport = udp->src_port;
92 u16 dport = udp->dst_port;
94 sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
96 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
98 saddr.as_u64[0] = ip6->src_address.as_u64[0];
99 saddr.as_u64[1] = ip6->src_address.as_u64[1];
100 daddr.as_u64[0] = ip6->dst_address.as_u64[0];
101 daddr.as_u64[1] = ip6->dst_address.as_u64[1];
104 nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto,
109 bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
116 nat64_db_bib_entry_find (&nm->db, &saddr, sport, proto, fib_index, 1);
121 ip4_address_t out_addr;
122 if (nat64_alloc_out_addr_and_port
123 (fib_index, proto, &out_addr, &out_port))
127 nat64_db_bib_entry_create (&nm->db, &ip6->src_address, &out_addr,
128 sport, clib_host_to_net_u16 (out_port),
129 fib_index, proto, 0);
135 nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
141 nat64_session_reset_timeout (ste, ctx->vm);
143 ip4->src_address.as_u32 = bibe->out_addr.as_u32;
144 udp->src_port = bibe->out_port;
146 ip4->dst_address.as_u32 = daddr.ip4.as_u32;
152 nat64_in2out_icmp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4, void *arg)
154 nat64_main_t *nm = &nat64_main;
155 nat64_in2out_set_ctx_t *ctx = arg;
156 nat64_db_bib_entry_t *bibe;
157 nat64_db_st_entry_t *ste;
158 ip46_address_t saddr, daddr;
159 u32 sw_if_index, fib_index;
160 icmp46_header_t *icmp = ip6_next_header (ip6);
162 sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
164 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
166 saddr.as_u64[0] = ip6->src_address.as_u64[0];
167 saddr.as_u64[1] = ip6->src_address.as_u64[1];
168 daddr.as_u64[0] = ip6->dst_address.as_u64[0];
169 daddr.as_u64[1] = ip6->dst_address.as_u64[1];
171 if (icmp->type == ICMP4_echo_request || icmp->type == ICMP4_echo_reply)
173 u16 in_id = ((u16 *) (icmp))[2];
175 nat64_db_st_entry_find (&nm->db, &saddr, &daddr, in_id, 0,
176 SNAT_PROTOCOL_ICMP, fib_index, 1);
181 nat64_db_bib_entry_by_index (&nm->db, SNAT_PROTOCOL_ICMP,
189 nat64_db_bib_entry_find (&nm->db, &saddr, in_id,
190 SNAT_PROTOCOL_ICMP, fib_index, 1);
195 ip4_address_t out_addr;
196 if (nat64_alloc_out_addr_and_port
197 (fib_index, SNAT_PROTOCOL_ICMP, &out_addr, &out_id))
201 nat64_db_bib_entry_create (&nm->db, &ip6->src_address,
203 clib_host_to_net_u16 (out_id),
204 fib_index, SNAT_PROTOCOL_ICMP, 0);
209 nat64_db_st_entry_create (&nm->db, bibe, &ip6->dst_address,
215 nat64_session_reset_timeout (ste, ctx->vm);
217 ip4->src_address.as_u32 = bibe->out_addr.as_u32;
218 ((u16 *) (icmp))[2] = bibe->out_port;
220 ip4->dst_address.as_u32 = daddr.ip4.as_u32;
225 clib_warning ("not ICMP echo request/reply, %u", icmp->type);
233 nat64_in2out_inner_icmp_set_cb (ip6_header_t * ip6, ip4_header_t * ip4,
241 nat64_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
242 vlib_frame_t * frame)
244 u32 n_left_from, *from, *to_next;
245 nat64_in2out_next_t next_index;
246 u32 pkts_processed = 0;
248 from = vlib_frame_vector_args (frame);
249 n_left_from = frame->n_vectors;
250 next_index = node->cached_next_index;
252 while (n_left_from > 0)
256 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
258 while (n_left_from > 0 && n_left_to_next > 0)
264 u16 l4_offset0, frag_offset0;
267 nat64_in2out_set_ctx_t ctx0;
269 /* speculatively enqueue b0 to the current next frame */
277 b0 = vlib_get_buffer (vm, bi0);
278 ip60 = vlib_buffer_get_current (b0);
283 next0 = NAT64_IN2OUT_NEXT_LOOKUP;
287 (ip60, b0->current_length, &l4_protocol0, &l4_offset0,
290 next0 = NAT64_IN2OUT_NEXT_DROP;
291 b0->error = node->errors[NAT64_IN2OUT_ERROR_UNKNOWN];
295 proto0 = ip_proto_to_snat_proto (l4_protocol0);
296 if (PREDICT_FALSE ((proto0 == ~0) || (frag_offset0 != 0)))
298 next0 = NAT64_IN2OUT_NEXT_DROP;
300 node->errors[NAT64_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
304 if (proto0 == SNAT_PROTOCOL_ICMP)
307 (b0, nat64_in2out_icmp_set_cb, &ctx0,
308 nat64_in2out_inner_icmp_set_cb, &ctx0))
310 next0 = NAT64_IN2OUT_NEXT_DROP;
311 b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
317 if (ip6_to_ip4_tcp_udp
318 (b0, nat64_in2out_tcp_udp_set_cb, &ctx0, 0))
320 next0 = NAT64_IN2OUT_NEXT_DROP;
321 b0->error = node->errors[NAT64_IN2OUT_ERROR_NO_TRANSLATION];
327 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
328 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
330 nat64_in2out_trace_t *t =
331 vlib_add_trace (vm, node, b0, sizeof (*t));
332 t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
333 t->next_index = next0;
336 pkts_processed += next0 != NAT64_IN2OUT_NEXT_DROP;
338 /* verify speculative enqueue, maybe switch current next frame */
339 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
340 n_left_to_next, bi0, next0);
342 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
344 vlib_node_increment_counter (vm, nat64_in2out_node.index,
345 NAT64_IN2OUT_ERROR_IN2OUT_PACKETS,
347 return frame->n_vectors;
351 VLIB_REGISTER_NODE (nat64_in2out_node) = {
352 .function = nat64_in2out_node_fn,.name = "nat64-in2out",
353 .vector_size = sizeof (u32),
354 .format_trace = format_nat64_in2out_trace,
355 .type = VLIB_NODE_TYPE_INTERNAL,
356 .n_errors = ARRAY_LEN (nat64_in2out_error_strings),
357 .error_strings = nat64_in2out_error_strings,
359 /* edit / add dispositions here */
361 [NAT64_IN2OUT_NEXT_DROP] = "error-drop",
362 [NAT64_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
367 VLIB_NODE_FUNCTION_MULTIARCH (nat64_in2out_node, nat64_in2out_node_fn);
370 * fd.io coding-style-patch-verification: ON
373 * eval: (c-set-style "gnu")