2 * Copyright (c) 2016 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 NAT44 EI outside to inside network translation
20 #include <vlib/vlib.h>
22 #include <vnet/vnet.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/ethernet/ethernet.h>
25 #include <vnet/udp/udp_local.h>
26 #include <vnet/fib/ip4_fib.h>
28 #include <vppinfra/hash.h>
29 #include <vppinfra/error.h>
31 #include <nat/lib/log.h>
32 #include <nat/lib/nat_syslog.h>
33 #include <nat/lib/ipfix_logging.h>
34 #include <nat/nat44-ei/nat44_ei_inlines.h>
35 #include <nat/nat44-ei/nat44_ei.h>
42 } nat44_ei_out2in_trace_t;
44 /* packet trace format function */
46 format_nat44_ei_out2in_trace (u8 *s, va_list *args)
48 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
49 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
50 nat44_ei_out2in_trace_t *t = va_arg (*args, nat44_ei_out2in_trace_t *);
54 "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
55 t->sw_if_index, t->next_index, t->session_index);
60 format_nat44_ei_out2in_fast_trace (u8 *s, va_list *args)
62 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
63 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
64 nat44_ei_out2in_trace_t *t = va_arg (*args, nat44_ei_out2in_trace_t *);
66 s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
67 t->sw_if_index, t->next_index);
71 #define foreach_nat44_ei_out2in_error \
72 _ (UNSUPPORTED_PROTOCOL, "unsupported protocol") \
73 _ (OUT_OF_PORTS, "out of ports") \
74 _ (BAD_ICMP_TYPE, "unsupported ICMP type") \
75 _ (NO_TRANSLATION, "no translation") \
76 _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \
77 _ (CANNOT_CREATE_USER, "cannot create NAT user")
81 #define _(sym, str) NAT44_EI_OUT2IN_ERROR_##sym,
82 foreach_nat44_ei_out2in_error
84 NAT44_EI_OUT2IN_N_ERROR,
85 } nat44_ei_out2in_error_t;
87 static char *nat44_ei_out2in_error_strings[] = {
88 #define _(sym,string) string,
89 foreach_nat44_ei_out2in_error
95 NAT44_EI_OUT2IN_NEXT_DROP,
96 NAT44_EI_OUT2IN_NEXT_LOOKUP,
97 NAT44_EI_OUT2IN_NEXT_ICMP_ERROR,
98 NAT44_EI_OUT2IN_N_NEXT,
99 } nat44_ei_out2in_next_t;
101 #ifndef CLIB_MARCH_VARIANT
103 nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
105 nat44_ei_main_t *nm = &nat44_ei_main;
106 nat44_ei_is_idle_session_ctx_t *ctx = arg;
107 nat44_ei_session_t *s;
108 u64 sess_timeout_time;
109 nat44_ei_main_per_thread_data_t *tnm =
110 vec_elt_at_index (nm->per_thread_data, ctx->thread_index);
111 clib_bihash_kv_8_8_t s_kv;
113 if (ctx->thread_index != nat_value_get_thread_index (kv))
118 s = pool_elt_at_index (tnm->sessions, nat_value_get_session_index (kv));
119 sess_timeout_time = s->last_heard + (f64) nat_session_get_timeout (
120 &nm->timeouts, s->nat_proto, s->state);
121 if (ctx->now >= sess_timeout_time)
123 init_nat_i2o_k (&s_kv, s);
124 if (clib_bihash_add_del_8_8 (&nm->in2out, &s_kv, 0))
125 nat_elog_warn (nm, "out2in key del failed");
127 nat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
128 s->in2out.addr.as_u32,
129 s->out2in.addr.as_u32,
133 s->in2out.fib_index);
135 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
136 &s->in2out.addr, s->in2out.port,
137 &s->out2in.addr, s->out2in.port, s->nat_proto);
139 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
140 s->ext_host_port, s->nat_proto, s->out2in.fib_index,
143 if (!nat44_ei_is_session_static (s))
144 nat44_ei_free_outside_address_and_port (
145 nm->addresses, ctx->thread_index, &s->out2in.addr, s->out2in.port,
148 nat44_ei_delete_session (nm, s, ctx->thread_index);
157 * @brief Create session for static mapping.
159 * Create NAT session initiated by host from external network with static
162 * @param nm NAT main.
163 * @param b0 Vlib buffer.
164 * @param in2out In2out NAT44 session key.
165 * @param out2in Out2in NAT44 session key.
166 * @param node Vlib node.
168 * @returns NAT44_EI session if successfully created otherwise 0.
170 static inline nat44_ei_session_t *
171 create_session_for_static_mapping (
172 nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_address_t i2o_addr, u16 i2o_port,
173 u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index,
174 nat_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index, f64 now)
177 nat44_ei_session_t *s;
178 clib_bihash_kv_8_8_t kv0;
181 nat44_ei_is_idle_session_ctx_t ctx0;
183 if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (nm, thread_index)))
185 b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
186 nat_elog_notice (nm, "maximum sessions exceeded");
190 ip0 = vlib_buffer_get_current (b0);
191 udp0 = ip4_next_header (ip0);
193 u = nat44_ei_user_get_or_create (nm, &i2o_addr, i2o_fib_index, thread_index);
196 b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_CANNOT_CREATE_USER];
200 s = nat44_ei_session_alloc_or_recycle (nm, u, thread_index, now);
203 nat44_ei_delete_user_with_no_session (nm, u, thread_index);
204 nat_elog_warn (nm, "create NAT session failed");
208 s->flags |= NAT44_EI_SESSION_FLAG_STATIC_MAPPING;
209 s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
210 s->ext_host_port = udp0->src_port;
211 nat44_ei_user_session_increment (nm, u, 1 /* static */);
212 s->in2out.addr = i2o_addr;
213 s->in2out.port = i2o_port;
214 s->in2out.fib_index = i2o_fib_index;
215 s->out2in.addr = o2i_addr;
216 s->out2in.port = o2i_port;
217 s->out2in.fib_index = o2i_fib_index;
218 s->nat_proto = proto;
220 /* Add to translation hashes */
222 ctx0.thread_index = thread_index;
223 init_nat_i2o_kv (&kv0, s, thread_index,
224 s - nm->per_thread_data[thread_index].sessions);
225 if (clib_bihash_add_or_overwrite_stale_8_8 (
226 &nm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
227 nat_elog_notice (nm, "in2out key add failed");
229 init_nat_o2i_kv (&kv0, s, thread_index,
230 s - nm->per_thread_data[thread_index].sessions);
231 if (clib_bihash_add_or_overwrite_stale_8_8 (
232 &nm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
233 nat_elog_notice (nm, "out2in key add failed");
236 nat_ipfix_logging_nat44_ses_create (thread_index,
237 s->in2out.addr.as_u32,
238 s->out2in.addr.as_u32,
241 s->out2in.port, s->in2out.fib_index);
243 nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
244 &s->in2out.addr, s->in2out.port, &s->out2in.addr,
245 s->out2in.port, s->nat_proto);
247 nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
248 s->out2in.port, &s->ext_host_addr, s->ext_host_port,
249 &s->ext_host_nat_addr, s->ext_host_nat_port,
250 s->nat_proto, s->in2out.fib_index, s->flags, thread_index, 0);
255 #ifndef CLIB_MARCH_VARIANT
256 static_always_inline nat44_ei_out2in_error_t
257 icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr,
258 u16 *port, nat_protocol_t *nat_proto)
260 icmp46_header_t *icmp0;
261 icmp_echo_header_t *echo0, *inner_echo0 = 0;
262 ip4_header_t *inner_ip0;
264 icmp46_header_t *inner_icmp0;
266 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
267 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
269 if (!icmp_type_is_error_message
270 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
272 *nat_proto = NAT_PROTOCOL_ICMP;
273 *addr = ip0->dst_address;
274 *port = vnet_buffer (b)->ip.reass.l4_src_port;
278 inner_ip0 = (ip4_header_t *) (echo0 + 1);
279 l4_header = ip4_next_header (inner_ip0);
280 *nat_proto = ip_proto_to_nat_proto (inner_ip0->protocol);
281 *addr = inner_ip0->src_address;
284 case NAT_PROTOCOL_ICMP:
285 inner_icmp0 = (icmp46_header_t *) l4_header;
286 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
287 *port = inner_echo0->identifier;
289 case NAT_PROTOCOL_UDP:
290 case NAT_PROTOCOL_TCP:
291 *port = ((tcp_udp_header_t *) l4_header)->src_port;
294 return NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
297 return -1; /* success */
301 * Get address and port values to be used for ICMP packet translation
302 * and create session if needed
304 * @param[in,out] nm NAT main
305 * @param[in,out] node NAT node runtime
306 * @param[in] thread_index thread index
307 * @param[in,out] b0 buffer containing packet to be translated
308 * @param[in,out] ip0 ip header
309 * @param[out] p_proto protocol used for matching
310 * @param[out] p_value address and port after NAT translation
311 * @param[out] p_dont_translate if packet should not be translated
312 * @param d optional parameter
313 * @param e optional parameter
316 nat44_ei_icmp_match_out2in_slow (vlib_node_runtime_t *node, u32 thread_index,
317 vlib_buffer_t *b0, ip4_header_t *ip0,
318 ip4_address_t *addr, u16 *port,
319 u32 *fib_index, nat_protocol_t *proto,
320 nat44_ei_session_t **p_s0, u8 *dont_translate)
322 nat44_ei_main_t *nm = &nat44_ei_main;
323 nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
325 nat44_ei_session_t *s0 = 0;
326 clib_bihash_kv_8_8_t kv0, value0;
331 vlib_main_t *vm = vlib_get_main ();
334 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
335 *fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
339 err = icmp_get_key (b0, ip0, addr, port, proto);
342 b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
343 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
347 ip4_address_t mapping_addr;
349 u32 mapping_fib_index;
351 init_nat_k (&kv0, *addr, *port, *fib_index, *proto);
352 if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
354 /* Try to match static mapping by external address and port,
355 destination address and port in packet */
356 if (nat44_ei_static_mapping_match (
357 *addr, *port, *fib_index, *proto, &mapping_addr, &mapping_port,
358 &mapping_fib_index, 1, &is_addr_only, &identity_nat))
360 if (!nm->forwarding_enabled)
362 /* Don't NAT packet aimed at the intfc address */
363 if (PREDICT_FALSE (nat44_ei_is_interface_addr (
364 nm->ip4_main, node, sw_if_index0,
365 ip0->dst_address.as_u32)))
370 b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
371 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
382 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
384 && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
385 ICMP4_echo_request || !is_addr_only)))
387 b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
388 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
392 if (PREDICT_FALSE (identity_nat))
397 /* Create session initiated by host from external network */
398 s0 = create_session_for_static_mapping (
399 nm, b0, mapping_addr, mapping_port, mapping_fib_index, *addr, *port,
400 *fib_index, *proto, node, thread_index, vlib_time_now (vm));
404 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
411 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
413 && vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
415 && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
416 reass.icmp_type_or_tcp_flags)))
418 b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
419 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
423 s0 = pool_elt_at_index (tnm->sessions,
424 nat_value_get_session_index (&value0));
430 *addr = s0->in2out.addr;
431 *port = s0->in2out.port;
432 *fib_index = s0->in2out.fib_index;
440 #ifndef CLIB_MARCH_VARIANT
442 nat44_ei_icmp_match_out2in_fast (vlib_node_runtime_t *node, u32 thread_index,
443 vlib_buffer_t *b0, ip4_header_t *ip0,
444 ip4_address_t *mapping_addr,
445 u16 *mapping_port, u32 *mapping_fib_index,
446 nat_protocol_t *proto,
447 nat44_ei_session_t **p_s0, u8 *dont_translate)
449 nat44_ei_main_t *nm = &nat44_ei_main;
459 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
460 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
462 err = icmp_get_key (b0, ip0, &addr, &port, proto);
465 b0->error = node->errors[err];
466 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
469 if (nat44_ei_static_mapping_match (addr, port, rx_fib_index0, *proto,
470 mapping_addr, mapping_port,
471 mapping_fib_index, 1, &is_addr_only, 0))
473 /* Don't NAT packet aimed at the intfc address */
474 if (nat44_ei_is_interface_addr (nm->ip4_main, node, sw_if_index0,
475 ip0->dst_address.as_u32))
480 b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
481 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
486 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
487 && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
488 ICMP4_echo_request || !is_addr_only)
489 && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
490 reass.icmp_type_or_tcp_flags)))
492 b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
493 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
502 u32 nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
503 icmp46_header_t *icmp0, u32 sw_if_index0,
504 u32 rx_fib_index0, vlib_node_runtime_t *node,
505 u32 next0, u32 thread_index,
506 nat44_ei_session_t **p_s0);
508 #ifndef CLIB_MARCH_VARIANT
510 nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
511 icmp46_header_t *icmp0, u32 sw_if_index0,
512 u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0,
513 u32 thread_index, nat44_ei_session_t **p_s0)
515 nat44_ei_main_t *nm = &nat44_ei_main;
516 icmp_echo_header_t *echo0, *inner_echo0 = 0;
517 ip4_header_t *inner_ip0 = 0;
519 icmp46_header_t *inner_icmp0;
521 u32 new_addr0, old_addr0;
522 u16 old_id0, new_id0;
526 vlib_main_t *vm = vlib_get_main ();
530 nat_protocol_t proto;
532 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
534 if (PREDICT_TRUE (nm->pat))
536 next0_tmp = nat44_ei_icmp_match_out2in_slow (
537 node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
542 next0_tmp = nat44_ei_icmp_match_out2in_fast (
543 node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
549 if (next0 == NAT44_EI_OUT2IN_NEXT_DROP || dont_translate)
552 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
555 ip_incremental_checksum_buffer (vm, b0,
557 (u8 *) vlib_buffer_get_current (b0),
558 ntohs (ip0->length) -
559 ip4_header_bytes (ip0), 0);
560 checksum0 = ~ip_csum_fold (sum0);
561 if (checksum0 != 0 && checksum0 != 0xffff)
563 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
568 old_addr0 = ip0->dst_address.as_u32;
569 new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
570 vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
572 sum0 = ip0->checksum;
573 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
574 dst_address /* changed member */ );
575 ip0->checksum = ip_csum_fold (sum0);
578 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
580 if (icmp0->checksum == 0)
581 icmp0->checksum = 0xffff;
583 if (!icmp_type_is_error_message (icmp0->type))
586 if (PREDICT_FALSE (new_id0 != echo0->identifier))
588 old_id0 = echo0->identifier;
590 echo0->identifier = new_id0;
592 sum0 = icmp0->checksum;
594 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
595 identifier /* changed member */ );
596 icmp0->checksum = ip_csum_fold (sum0);
601 inner_ip0 = (ip4_header_t *) (echo0 + 1);
602 l4_header = ip4_next_header (inner_ip0);
604 if (!ip4_header_checksum_is_valid (inner_ip0))
606 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
610 old_addr0 = inner_ip0->src_address.as_u32;
611 inner_ip0->src_address = addr;
612 new_addr0 = inner_ip0->src_address.as_u32;
614 sum0 = icmp0->checksum;
615 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
616 src_address /* changed member */ );
617 icmp0->checksum = ip_csum_fold (sum0);
621 case NAT_PROTOCOL_ICMP:
622 inner_icmp0 = (icmp46_header_t *) l4_header;
623 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
625 old_id0 = inner_echo0->identifier;
627 inner_echo0->identifier = new_id0;
629 sum0 = icmp0->checksum;
631 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
633 icmp0->checksum = ip_csum_fold (sum0);
635 case NAT_PROTOCOL_UDP:
636 case NAT_PROTOCOL_TCP:
637 old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
639 ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
641 sum0 = icmp0->checksum;
642 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
644 icmp0->checksum = ip_csum_fold (sum0);
658 nat44_ei_icmp_out2in_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0,
659 ip4_header_t *ip0, icmp46_header_t *icmp0,
660 u32 sw_if_index0, u32 rx_fib_index0,
661 vlib_node_runtime_t *node, u32 next0, f64 now,
662 u32 thread_index, nat44_ei_session_t **p_s0)
664 vlib_main_t *vm = vlib_get_main ();
666 next0 = nat44_ei_icmp_out2in (b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
667 node, next0, thread_index, p_s0);
668 nat44_ei_session_t *s0 = *p_s0;
669 if (PREDICT_TRUE (next0 != NAT44_EI_OUT2IN_NEXT_DROP && s0))
672 nat44_ei_session_update_counters (
673 s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
674 /* Per-user LRU list maintenance */
675 nat44_ei_session_update_lru (nm, s0, thread_index);
681 nat_out2in_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
682 ip4_header_t *ip, u32 rx_fib_index)
684 clib_bihash_kv_8_8_t kv, value;
685 nat44_ei_static_mapping_t *m;
686 u32 old_addr, new_addr;
689 init_nat_k (&kv, ip->dst_address, 0, 0, 0);
690 if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
693 m = pool_elt_at_index (nm->static_mappings, value.value);
695 old_addr = ip->dst_address.as_u32;
696 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
698 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
699 ip->checksum = ip_csum_fold (sum);
701 vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
705 VLIB_NODE_FN (nat44_ei_out2in_node)
706 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
708 u32 n_left_from, *from;
709 nat44_ei_main_t *nm = &nat44_ei_main;
710 f64 now = vlib_time_now (vm);
711 u32 thread_index = vm->thread_index;
712 nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
714 from = vlib_frame_vector_args (frame);
715 n_left_from = frame->n_vectors;
717 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
718 u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
719 vlib_get_buffers (vm, from, b, n_left_from);
721 while (n_left_from >= 2)
723 vlib_buffer_t *b0, *b1;
724 u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
725 u32 next1 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
726 u32 sw_if_index0, sw_if_index1;
727 ip4_header_t *ip0, *ip1;
728 ip_csum_t sum0, sum1;
729 u32 new_addr0, old_addr0;
730 u16 new_port0, old_port0;
731 u32 new_addr1, old_addr1;
732 u16 new_port1, old_port1;
733 udp_header_t *udp0, *udp1;
734 tcp_header_t *tcp0, *tcp1;
735 icmp46_header_t *icmp0, *icmp1;
736 u32 rx_fib_index0, rx_fib_index1;
738 nat44_ei_session_t *s0 = 0, *s1 = 0;
739 clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
740 u8 identity_nat0, identity_nat1;
741 ip4_address_t sm_addr0, sm_addr1;
742 u16 sm_port0, sm_port1;
743 u32 sm_fib_index0, sm_fib_index1;
750 /* Prefetch next iteration. */
751 if (PREDICT_TRUE (n_left_from >= 4))
753 vlib_buffer_t *p2, *p3;
758 vlib_prefetch_buffer_header (p2, LOAD);
759 vlib_prefetch_buffer_header (p3, LOAD);
761 clib_prefetch_load (p2->data);
762 clib_prefetch_load (p3->data);
765 vnet_buffer (b0)->snat.flags = 0;
766 vnet_buffer (b1)->snat.flags = 0;
768 ip0 = vlib_buffer_get_current (b0);
769 udp0 = ip4_next_header (ip0);
770 tcp0 = (tcp_header_t *) udp0;
771 icmp0 = (icmp46_header_t *) udp0;
773 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
775 vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
777 if (PREDICT_FALSE (ip0->ttl == 1))
779 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
780 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
781 ICMP4_time_exceeded_ttl_exceeded_in_transit,
783 next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
787 proto0 = ip_proto_to_nat_proto (ip0->protocol);
789 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
791 if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
793 if (!nm->forwarding_enabled)
796 node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
797 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
800 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
801 thread_index, sw_if_index0, 1);
806 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
808 next0 = nat44_ei_icmp_out2in_slow_path (
809 nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
811 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
812 thread_index, sw_if_index0, 1);
816 init_nat_k (&kv0, ip0->dst_address,
817 vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
819 if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
821 /* Try to match static mapping by external address and port,
822 destination address and port in packet */
823 if (nat44_ei_static_mapping_match (
824 ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
825 rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1,
829 * Send DHCP packets to the ipv4 stack, or we won't
830 * be able to use dhcp client on the outside interface
833 (proto0 == NAT_PROTOCOL_UDP
834 && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
835 clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
837 vnet_feature_next (&next0, b0);
841 if (!nm->forwarding_enabled)
844 node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
845 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
850 if (PREDICT_FALSE (identity_nat0))
853 /* Create session initiated by host from external network */
854 s0 = create_session_for_static_mapping (
855 nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
856 vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
857 node, thread_index, now);
860 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
865 s0 = pool_elt_at_index (tnm->sessions,
866 nat_value_get_session_index (&value0));
868 old_addr0 = ip0->dst_address.as_u32;
869 ip0->dst_address = s0->in2out.addr;
870 new_addr0 = ip0->dst_address.as_u32;
871 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
873 sum0 = ip0->checksum;
874 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
875 ip4_header_t, dst_address /* changed member */ );
876 ip0->checksum = ip_csum_fold (sum0);
878 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
880 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
882 old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
883 new_port0 = udp0->dst_port = s0->in2out.port;
884 sum0 = tcp0->checksum;
885 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
887 dst_address /* changed member */ );
889 sum0 = ip_csum_update (sum0, old_port0, new_port0,
890 ip4_header_t /* cheat */ ,
891 length /* changed member */ );
892 tcp0->checksum = ip_csum_fold (sum0);
894 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
895 thread_index, sw_if_index0, 1);
899 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
901 old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
902 new_port0 = udp0->dst_port = s0->in2out.port;
903 if (PREDICT_FALSE (udp0->checksum))
905 sum0 = udp0->checksum;
906 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
909 ip_csum_update (sum0, old_port0, new_port0,
910 ip4_header_t /* cheat */ ,
911 length /* changed member */ );
912 udp0->checksum = ip_csum_fold (sum0);
915 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
916 thread_index, sw_if_index0, 1);
920 nat44_ei_session_update_counters (
921 s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
922 /* Per-user LRU list maintenance */
923 nat44_ei_session_update_lru (nm, s0, thread_index);
926 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
927 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
929 nat44_ei_out2in_trace_t *t =
930 vlib_add_trace (vm, node, b0, sizeof (*t));
931 t->sw_if_index = sw_if_index0;
932 t->next_index = next0;
933 t->session_index = ~0;
935 t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
938 if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
940 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
941 thread_index, sw_if_index0, 1);
945 ip1 = vlib_buffer_get_current (b1);
946 udp1 = ip4_next_header (ip1);
947 tcp1 = (tcp_header_t *) udp1;
948 icmp1 = (icmp46_header_t *) udp1;
950 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
952 vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index1);
954 if (PREDICT_FALSE (ip1->ttl == 1))
956 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
957 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
958 ICMP4_time_exceeded_ttl_exceeded_in_transit,
960 next1 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
964 proto1 = ip_proto_to_nat_proto (ip1->protocol);
966 if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
968 if (nat_out2in_sm_unknown_proto (nm, b1, ip1, rx_fib_index1))
970 if (!nm->forwarding_enabled)
973 node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
974 next1 = NAT44_EI_OUT2IN_NEXT_DROP;
977 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
978 thread_index, sw_if_index1, 1);
982 if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
984 next1 = nat44_ei_icmp_out2in_slow_path (
985 nm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, next1, now,
987 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
988 thread_index, sw_if_index1, 1);
992 init_nat_k (&kv1, ip1->dst_address,
993 vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1,
995 if (clib_bihash_search_8_8 (&nm->out2in, &kv1, &value1))
997 /* Try to match static mapping by external address and port,
998 destination address and port in packet */
999 if (nat44_ei_static_mapping_match (
1000 ip1->dst_address, vnet_buffer (b1)->ip.reass.l4_dst_port,
1001 rx_fib_index1, proto1, &sm_addr1, &sm_port1, &sm_fib_index1, 1,
1005 * Send DHCP packets to the ipv4 stack, or we won't
1006 * be able to use dhcp client on the outside interface
1009 (proto1 == NAT_PROTOCOL_UDP
1010 && (vnet_buffer (b1)->ip.reass.l4_dst_port ==
1011 clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
1013 vnet_feature_next (&next1, b1);
1017 if (!nm->forwarding_enabled)
1020 node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
1021 next1 = NAT44_EI_OUT2IN_NEXT_DROP;
1026 if (PREDICT_FALSE (identity_nat1))
1029 /* Create session initiated by host from external network */
1030 s1 = create_session_for_static_mapping (
1031 nm, b1, sm_addr1, sm_port1, sm_fib_index1, ip1->dst_address,
1032 vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1, proto1,
1033 node, thread_index, now);
1036 next1 = NAT44_EI_OUT2IN_NEXT_DROP;
1041 s1 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1042 nat_value_get_session_index (&value1));
1044 old_addr1 = ip1->dst_address.as_u32;
1045 ip1->dst_address = s1->in2out.addr;
1046 new_addr1 = ip1->dst_address.as_u32;
1047 vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1049 sum1 = ip1->checksum;
1050 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1051 ip4_header_t, dst_address /* changed member */ );
1052 ip1->checksum = ip_csum_fold (sum1);
1054 if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
1056 if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1058 old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1059 new_port1 = udp1->dst_port = s1->in2out.port;
1061 sum1 = tcp1->checksum;
1062 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1064 dst_address /* changed member */ );
1066 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1067 ip4_header_t /* cheat */ ,
1068 length /* changed member */ );
1069 tcp1->checksum = ip_csum_fold (sum1);
1071 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
1072 thread_index, sw_if_index1, 1);
1076 if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1078 old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1079 new_port1 = udp1->dst_port = s1->in2out.port;
1080 if (PREDICT_FALSE (udp1->checksum))
1083 sum1 = udp1->checksum;
1085 ip_csum_update (sum1, old_addr1, new_addr1,
1087 dst_address /* changed member */ );
1089 ip_csum_update (sum1, old_port1, new_port1,
1090 ip4_header_t /* cheat */ ,
1091 length /* changed member */ );
1092 udp1->checksum = ip_csum_fold (sum1);
1095 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
1096 thread_index, sw_if_index1, 1);
1100 nat44_ei_session_update_counters (
1101 s1, now, vlib_buffer_length_in_chain (vm, b1), thread_index);
1102 /* Per-user LRU list maintenance */
1103 nat44_ei_session_update_lru (nm, s1, thread_index);
1106 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1107 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1109 nat44_ei_out2in_trace_t *t =
1110 vlib_add_trace (vm, node, b1, sizeof (*t));
1111 t->sw_if_index = sw_if_index1;
1112 t->next_index = next1;
1113 t->session_index = ~0;
1115 t->session_index = s1 - nm->per_thread_data[thread_index].sessions;
1118 if (next1 == NAT44_EI_OUT2IN_NEXT_DROP)
1120 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
1121 thread_index, sw_if_index1, 1);
1130 while (n_left_from > 0)
1133 u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
1137 u32 new_addr0, old_addr0;
1138 u16 new_port0, old_port0;
1141 icmp46_header_t *icmp0;
1144 nat44_ei_session_t *s0 = 0;
1145 clib_bihash_kv_8_8_t kv0, value0;
1147 ip4_address_t sm_addr0;
1154 vnet_buffer (b0)->snat.flags = 0;
1156 ip0 = vlib_buffer_get_current (b0);
1157 udp0 = ip4_next_header (ip0);
1158 tcp0 = (tcp_header_t *) udp0;
1159 icmp0 = (icmp46_header_t *) udp0;
1161 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1163 vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
1165 proto0 = ip_proto_to_nat_proto (ip0->protocol);
1167 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1169 if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
1171 if (!nm->forwarding_enabled)
1174 node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1175 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1178 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
1179 thread_index, sw_if_index0, 1);
1183 if (PREDICT_FALSE (ip0->ttl == 1))
1185 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1186 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1187 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1189 next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
1193 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1195 next0 = nat44_ei_icmp_out2in_slow_path (
1196 nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
1198 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
1199 thread_index, sw_if_index0, 1);
1203 init_nat_k (&kv0, ip0->dst_address,
1204 vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
1207 if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
1209 /* Try to match static mapping by external address and port,
1210 destination address and port in packet */
1211 if (nat44_ei_static_mapping_match (
1212 ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
1213 rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1,
1217 * Send DHCP packets to the ipv4 stack, or we won't
1218 * be able to use dhcp client on the outside interface
1221 (proto0 == NAT_PROTOCOL_UDP
1222 && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1223 clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
1225 vnet_feature_next (&next0, b0);
1229 if (!nm->forwarding_enabled)
1232 node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
1233 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1238 if (PREDICT_FALSE (identity_nat0))
1241 /* Create session initiated by host from external network */
1242 s0 = create_session_for_static_mapping (
1243 nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
1244 vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
1245 node, thread_index, now);
1248 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1253 s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1254 nat_value_get_session_index (&value0));
1256 old_addr0 = ip0->dst_address.as_u32;
1257 ip0->dst_address = s0->in2out.addr;
1258 new_addr0 = ip0->dst_address.as_u32;
1259 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1261 sum0 = ip0->checksum;
1262 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1263 ip4_header_t, dst_address /* changed member */ );
1264 ip0->checksum = ip_csum_fold (sum0);
1266 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1268 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1270 old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1271 new_port0 = udp0->dst_port = s0->in2out.port;
1273 sum0 = tcp0->checksum;
1274 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1276 dst_address /* changed member */ );
1278 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1279 ip4_header_t /* cheat */ ,
1280 length /* changed member */ );
1281 tcp0->checksum = ip_csum_fold (sum0);
1283 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
1284 thread_index, sw_if_index0, 1);
1288 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1290 old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1291 new_port0 = udp0->dst_port = s0->in2out.port;
1292 if (PREDICT_FALSE (udp0->checksum))
1294 sum0 = udp0->checksum;
1295 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
1298 ip_csum_update (sum0, old_port0, new_port0,
1299 ip4_header_t /* cheat */ ,
1300 length /* changed member */ );
1301 udp0->checksum = ip_csum_fold (sum0);
1304 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
1305 thread_index, sw_if_index0, 1);
1309 nat44_ei_session_update_counters (
1310 s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
1311 /* Per-user LRU list maintenance */
1312 nat44_ei_session_update_lru (nm, s0, thread_index);
1315 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1316 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1318 nat44_ei_out2in_trace_t *t =
1319 vlib_add_trace (vm, node, b0, sizeof (*t));
1320 t->sw_if_index = sw_if_index0;
1321 t->next_index = next0;
1322 t->session_index = ~0;
1324 t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
1327 if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
1329 vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
1330 thread_index, sw_if_index0, 1);
1338 vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1341 return frame->n_vectors;
1345 VLIB_REGISTER_NODE (nat44_ei_out2in_node) = {
1346 .name = "nat44-ei-out2in",
1347 .vector_size = sizeof (u32),
1348 .format_trace = format_nat44_ei_out2in_trace,
1349 .type = VLIB_NODE_TYPE_INTERNAL,
1351 .n_errors = ARRAY_LEN(nat44_ei_out2in_error_strings),
1352 .error_strings = nat44_ei_out2in_error_strings,
1354 .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
1356 .n_next_nodes = NAT44_EI_OUT2IN_N_NEXT,
1358 /* edit / add dispositions here */
1360 [NAT44_EI_OUT2IN_NEXT_DROP] = "error-drop",
1361 [NAT44_EI_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1362 [NAT44_EI_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1367 VLIB_NODE_FN (nat44_ei_out2in_fast_node)
1368 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1370 u32 n_left_from, *from;
1371 nat44_ei_main_t *nm = &nat44_ei_main;
1373 from = vlib_frame_vector_args (frame);
1374 n_left_from = frame->n_vectors;
1376 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
1377 u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
1378 vlib_get_buffers (vm, from, b, n_left_from);
1379 while (n_left_from > 0)
1382 u32 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1386 u32 new_addr0, old_addr0;
1387 u16 new_port0, old_port0;
1390 icmp46_header_t *icmp0;
1393 ip4_address_t sm_addr0;
1400 ip0 = vlib_buffer_get_current (b0);
1401 udp0 = ip4_next_header (ip0);
1402 tcp0 = (tcp_header_t *) udp0;
1403 icmp0 = (icmp46_header_t *) udp0;
1405 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1406 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1408 vnet_feature_next (&next0, b0);
1410 if (PREDICT_FALSE (ip0->ttl == 1))
1412 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1413 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1414 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1416 next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
1420 proto0 = ip_proto_to_nat_proto (ip0->protocol);
1422 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1425 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1427 next0 = nat44_ei_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
1428 rx_fib_index0, node, next0, ~0, 0);
1432 if (nat44_ei_static_mapping_match (ip0->dst_address, udp0->dst_port,
1433 rx_fib_index0, proto0, &sm_addr0,
1434 &sm_port0, &sm_fib_index0, 1, 0, 0))
1436 b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
1440 new_addr0 = sm_addr0.as_u32;
1441 new_port0 = sm_port0;
1442 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm_fib_index0;
1443 old_addr0 = ip0->dst_address.as_u32;
1444 ip0->dst_address.as_u32 = new_addr0;
1446 sum0 = ip0->checksum;
1447 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1448 ip4_header_t, dst_address /* changed member */ );
1449 ip0->checksum = ip_csum_fold (sum0);
1451 if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1453 old_port0 = udp0->dst_port;
1454 udp0->dst_port = new_port0;
1456 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1458 sum0 = tcp0->checksum;
1459 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1461 dst_address /* changed member */ );
1462 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1463 ip4_header_t /* cheat */ ,
1464 length /* changed member */ );
1465 tcp0->checksum = ip_csum_fold (sum0);
1467 else if (udp0->checksum)
1469 sum0 = udp0->checksum;
1470 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1472 dst_address /* changed member */ );
1473 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1474 ip4_header_t /* cheat */ ,
1475 length /* changed member */ );
1476 udp0->checksum = ip_csum_fold (sum0);
1481 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1483 sum0 = tcp0->checksum;
1484 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1486 dst_address /* changed member */ );
1487 tcp0->checksum = ip_csum_fold (sum0);
1489 else if (udp0->checksum)
1491 sum0 = udp0->checksum;
1492 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1494 dst_address /* changed member */ );
1495 udp0->checksum = ip_csum_fold (sum0);
1501 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1502 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1504 nat44_ei_out2in_trace_t *t =
1505 vlib_add_trace (vm, node, b0, sizeof (*t));
1506 t->sw_if_index = sw_if_index0;
1507 t->next_index = next0;
1510 if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
1512 vlib_increment_simple_counter (&nm->counters.fastpath.out2in.drops,
1513 vm->thread_index, sw_if_index0, 1);
1521 vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1524 return frame->n_vectors;
1528 VLIB_REGISTER_NODE (nat44_ei_out2in_fast_node) = {
1529 .name = "nat44-ei-out2in-fast",
1530 .vector_size = sizeof (u32),
1531 .format_trace = format_nat44_ei_out2in_fast_trace,
1532 .type = VLIB_NODE_TYPE_INTERNAL,
1534 .n_errors = ARRAY_LEN(nat44_ei_out2in_error_strings),
1535 .error_strings = nat44_ei_out2in_error_strings,
1537 .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
1539 .n_next_nodes = NAT44_EI_OUT2IN_N_NEXT,
1541 /* edit / add dispositions here */
1543 [NAT44_EI_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1544 [NAT44_EI_OUT2IN_NEXT_DROP] = "error-drop",
1545 [NAT44_EI_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1551 * fd.io coding-style-patch-verification: ON
1554 * eval: (c-set-style "gnu")