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 inside to outside 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/lib/nat_inlines.h>
35 #include <nat/nat44-ei/nat44_ei_inlines.h>
36 #include <nat/nat44-ei/nat44_ei.h>
37 #include <nat/nat44-ei/nat44_ei_hairpinning.h>
46 } nat44_ei_in2out_trace_t;
48 /* packet trace format function */
50 format_nat44_ei_in2out_trace (u8 *s, va_list *args)
52 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
53 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
54 nat44_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *);
57 tag = t->is_slow_path ? "NAT44_IN2OUT_SLOW_PATH" : "NAT44_IN2OUT_FAST_PATH";
59 s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
60 t->sw_if_index, t->next_index, t->session_index);
61 if (t->is_hairpinning)
63 s = format (s, ", with-hairpinning");
70 format_nat44_ei_in2out_fast_trace (u8 *s, va_list *args)
72 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
73 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
74 nat44_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *);
76 s = format (s, "NAT44_IN2OUT_FAST: sw_if_index %d, next index %d",
77 t->sw_if_index, t->next_index);
82 #define foreach_nat44_ei_in2out_error \
83 _ (UNSUPPORTED_PROTOCOL, "unsupported protocol") \
84 _ (OUT_OF_PORTS, "out of ports") \
85 _ (BAD_OUTSIDE_FIB, "outside VRF ID not found") \
86 _ (BAD_ICMP_TYPE, "unsupported ICMP type") \
87 _ (NO_TRANSLATION, "no translation") \
88 _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \
89 _ (CANNOT_CREATE_USER, "cannot create NAT user")
93 #define _(sym, str) NAT44_EI_IN2OUT_ERROR_##sym,
94 foreach_nat44_ei_in2out_error
96 NAT44_EI_IN2OUT_N_ERROR,
97 } nat44_ei_in2out_error_t;
99 static char *nat44_ei_in2out_error_strings[] = {
100 #define _(sym,string) string,
101 foreach_nat44_ei_in2out_error
107 NAT44_EI_IN2OUT_NEXT_LOOKUP,
108 NAT44_EI_IN2OUT_NEXT_DROP,
109 NAT44_EI_IN2OUT_NEXT_ICMP_ERROR,
110 NAT44_EI_IN2OUT_NEXT_SLOW_PATH,
111 NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF,
112 NAT44_EI_IN2OUT_N_NEXT,
113 } nat44_ei_in2out_next_t;
117 NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP,
118 NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP,
119 NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
120 } nat44_ei_in2out_hairpinnig_finish_next_t;
123 nat44_ei_not_translate_fast (vlib_node_runtime_t *node, u32 sw_if_index0,
124 ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0)
126 nat44_ei_main_t *nm = &nat44_ei_main;
131 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
132 nat44_ei_outside_fib_t *outside_fib;
134 .fp_proto = FIB_PROTOCOL_IP4,
137 .ip4.as_u32 = ip0->dst_address.as_u32,
142 /* Don't NAT packet aimed at the intfc address */
143 if (PREDICT_FALSE (nat44_ei_is_interface_addr (
144 nm->ip4_main, node, sw_if_index0, ip0->dst_address.as_u32)))
147 fei = fib_table_lookup (rx_fib_index0, &pfx);
148 if (FIB_NODE_INDEX_INVALID != fei)
150 u32 sw_if_index = fib_entry_get_resolving_interface (fei);
151 if (sw_if_index == ~0)
153 vec_foreach (outside_fib, nm->outside_fibs)
155 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
156 if (FIB_NODE_INDEX_INVALID != fei)
158 sw_if_index = fib_entry_get_resolving_interface (fei);
159 if (sw_if_index != ~0)
164 if (sw_if_index == ~0)
167 nat44_ei_interface_t *i;
168 pool_foreach (i, nm->interfaces)
170 /* NAT packet aimed at outside interface */
171 if ((nat44_ei_interface_is_outside (i)) &&
172 (sw_if_index == i->sw_if_index))
181 nat44_ei_not_translate (nat44_ei_main_t *nm, vlib_node_runtime_t *node,
182 u32 sw_if_index0, ip4_header_t *ip0, u32 proto0,
183 u32 rx_fib_index0, u32 thread_index)
185 udp_header_t *udp0 = ip4_next_header (ip0);
186 clib_bihash_kv_8_8_t kv0, value0;
188 init_nat_k (&kv0, ip0->dst_address, udp0->dst_port, nm->outside_fib_index,
191 /* NAT packet aimed at external address if */
192 /* has active sessions */
193 if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
195 /* or is static mappings */
196 ip4_address_t placeholder_addr;
197 u16 placeholder_port;
198 u32 placeholder_fib_index;
199 if (!nat44_ei_static_mapping_match (ip0->dst_address, udp0->dst_port,
200 nm->outside_fib_index, proto0,
201 &placeholder_addr, &placeholder_port,
202 &placeholder_fib_index, 1, 0, 0))
208 if (nm->forwarding_enabled)
211 return nat44_ei_not_translate_fast (node, sw_if_index0, ip0, proto0,
216 nat44_ei_not_translate_output_feature (nat44_ei_main_t *nm, ip4_header_t *ip0,
217 u32 proto0, u16 src_port, u16 dst_port,
218 u32 thread_index, u32 sw_if_index)
220 clib_bihash_kv_8_8_t kv0, value0;
221 nat44_ei_interface_t *i;
224 init_nat_k (&kv0, ip0->src_address, src_port,
225 ip4_fib_table_get_index_for_sw_if_index (sw_if_index), proto0);
227 if (!clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
231 init_nat_k (&kv0, ip0->dst_address, dst_port,
232 ip4_fib_table_get_index_for_sw_if_index (sw_if_index), proto0);
233 if (!clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0))
236 pool_foreach (i, nm->output_feature_interfaces)
238 if ((nat44_ei_interface_is_inside (i)) &&
239 (sw_if_index == i->sw_if_index))
248 #ifndef CLIB_MARCH_VARIANT
250 nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
252 nat44_ei_main_t *nm = &nat44_ei_main;
253 nat44_ei_is_idle_session_ctx_t *ctx = arg;
254 nat44_ei_session_t *s;
255 u64 sess_timeout_time;
256 nat44_ei_main_per_thread_data_t *tnm =
257 vec_elt_at_index (nm->per_thread_data, ctx->thread_index);
258 clib_bihash_kv_8_8_t s_kv;
260 s = pool_elt_at_index (tnm->sessions, kv->value);
261 sess_timeout_time = s->last_heard + (f64) nat_session_get_timeout (
262 &nm->timeouts, s->nat_proto, s->state);
263 if (ctx->now >= sess_timeout_time)
265 init_nat_o2i_k (&s_kv, s);
266 if (clib_bihash_add_del_8_8 (&nm->out2in, &s_kv, 0))
267 nat_elog_warn (nm, "out2in key del failed");
269 nat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
270 s->in2out.addr.as_u32,
271 s->out2in.addr.as_u32,
275 s->in2out.fib_index);
277 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
278 &s->in2out.addr, s->in2out.port,
279 &s->out2in.addr, s->out2in.port, s->nat_proto);
281 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
282 s->ext_host_port, s->nat_proto, s->out2in.fib_index,
285 if (!nat44_ei_is_session_static (s))
286 nat44_ei_free_outside_address_and_port (
287 nm->addresses, ctx->thread_index, &s->out2in.addr, s->out2in.port,
290 nat44_ei_delete_session (nm, s, ctx->thread_index);
299 slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_header_t *ip0,
300 ip4_address_t i2o_addr, u16 i2o_port, u32 rx_fib_index0,
301 nat_protocol_t nat_proto, nat44_ei_session_t **sessionp,
302 vlib_node_runtime_t *node, u32 next0, u32 thread_index, f64 now)
305 nat44_ei_session_t *s = 0;
306 clib_bihash_kv_8_8_t kv0;
308 nat44_ei_outside_fib_t *outside_fib;
309 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
312 .fp_proto = FIB_PROTOCOL_IP4,
315 .ip4.as_u32 = ip0->dst_address.as_u32,
318 nat44_ei_is_idle_session_ctx_t ctx0;
319 ip4_address_t sm_addr;
323 if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (nm, thread_index)))
325 b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
326 nat_ipfix_logging_max_sessions (thread_index,
327 nm->max_translations_per_thread);
328 nat_elog_notice (nm, "maximum sessions exceeded");
329 return NAT44_EI_IN2OUT_NEXT_DROP;
332 /* First try to match static mapping by local address and port */
333 if (nat44_ei_static_mapping_match (i2o_addr, i2o_port, rx_fib_index0,
334 nat_proto, &sm_addr, &sm_port,
335 &sm_fib_index, 0, 0, &identity_nat))
337 /* Try to create dynamic translation */
338 if (nm->alloc_addr_and_port (
339 nm->addresses, rx_fib_index0, thread_index, nat_proto, &sm_addr,
340 &sm_port, nm->port_per_thread,
341 nm->per_thread_data[thread_index].snat_thread_index))
343 b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_OUT_OF_PORTS];
344 return NAT44_EI_IN2OUT_NEXT_DROP;
349 if (PREDICT_FALSE (identity_nat))
358 u = nat44_ei_user_get_or_create (nm, &ip0->src_address, rx_fib_index0,
362 b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_CANNOT_CREATE_USER];
363 return NAT44_EI_IN2OUT_NEXT_DROP;
366 s = nat44_ei_session_alloc_or_recycle (nm, u, thread_index, now);
369 nat44_ei_delete_user_with_no_session (nm, u, thread_index);
370 nat_elog_warn (nm, "create NAT session failed");
371 return NAT44_EI_IN2OUT_NEXT_DROP;
375 s->flags |= NAT44_EI_SESSION_FLAG_STATIC_MAPPING;
376 nat44_ei_user_session_increment (nm, u, is_sm);
377 s->in2out.addr = i2o_addr;
378 s->in2out.port = i2o_port;
379 s->in2out.fib_index = rx_fib_index0;
380 s->nat_proto = nat_proto;
381 s->out2in.addr = sm_addr;
382 s->out2in.port = sm_port;
383 s->out2in.fib_index = nm->outside_fib_index;
384 switch (vec_len (nm->outside_fibs))
387 s->out2in.fib_index = nm->outside_fib_index;
390 s->out2in.fib_index = nm->outside_fibs[0].fib_index;
393 vec_foreach (outside_fib, nm->outside_fibs)
395 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
396 if (FIB_NODE_INDEX_INVALID != fei)
398 if (fib_entry_get_resolving_interface (fei) != ~0)
400 s->out2in.fib_index = outside_fib->fib_index;
407 s->ext_host_addr.as_u32 = ip0->dst_address.as_u32;
408 s->ext_host_port = vnet_buffer (b0)->ip.reass.l4_dst_port;
411 /* Add to translation hashes */
413 ctx0.thread_index = thread_index;
414 init_nat_i2o_kv (&kv0, s, thread_index,
415 s - nm->per_thread_data[thread_index].sessions);
416 if (clib_bihash_add_or_overwrite_stale_8_8 (
417 &nm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
418 nat_elog_notice (nm, "in2out key add failed");
420 init_nat_o2i_kv (&kv0, s, thread_index,
421 s - nm->per_thread_data[thread_index].sessions);
422 if (clib_bihash_add_or_overwrite_stale_8_8 (
423 &nm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
424 nat_elog_notice (nm, "out2in key add failed");
427 nat_ipfix_logging_nat44_ses_create (
428 thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->nat_proto,
429 s->in2out.port, s->out2in.port, s->in2out.fib_index);
431 nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index, &s->in2out.addr,
432 s->in2out.port, &s->out2in.addr, s->out2in.port,
435 nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
436 s->out2in.port, &s->ext_host_addr, s->ext_host_port,
437 &s->ext_host_nat_addr, s->ext_host_nat_port, s->nat_proto,
438 s->in2out.fib_index, s->flags, thread_index, 0);
443 #ifndef CLIB_MARCH_VARIANT
444 static_always_inline nat44_ei_in2out_error_t
445 icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr,
446 u16 *port, nat_protocol_t *nat_proto)
448 icmp46_header_t *icmp0;
449 icmp_echo_header_t *echo0, *inner_echo0 = 0;
450 ip4_header_t *inner_ip0 = 0;
452 icmp46_header_t *inner_icmp0;
454 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
455 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
457 if (!icmp_type_is_error_message
458 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
460 *nat_proto = NAT_PROTOCOL_ICMP;
461 *addr = ip0->src_address;
462 *port = vnet_buffer (b)->ip.reass.l4_src_port;
466 inner_ip0 = (ip4_header_t *) (echo0 + 1);
467 l4_header = ip4_next_header (inner_ip0);
468 *nat_proto = ip_proto_to_nat_proto (inner_ip0->protocol);
469 *addr = inner_ip0->dst_address;
472 case NAT_PROTOCOL_ICMP:
473 inner_icmp0 = (icmp46_header_t *) l4_header;
474 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
475 *port = inner_echo0->identifier;
477 case NAT_PROTOCOL_UDP:
478 case NAT_PROTOCOL_TCP:
479 *port = ((tcp_udp_header_t *) l4_header)->dst_port;
482 return NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
485 return -1; /* success */
489 * Get address and port values to be used for ICMP packet translation
490 * and create session if needed
492 * @param[in,out] nm NAT main
493 * @param[in,out] node NAT node runtime
494 * @param[in] thread_index thread index
495 * @param[in,out] b0 buffer containing packet to be translated
496 * @param[in,out] ip0 ip header
497 * @param[out] p_proto protocol used for matching
498 * @param[out] p_value address and port after NAT translation
499 * @param[out] p_dont_translate if packet should not be translated
500 * @param d optional parameter
501 * @param e optional parameter
504 nat44_ei_icmp_match_in2out_slow (vlib_node_runtime_t *node, u32 thread_index,
505 vlib_buffer_t *b0, ip4_header_t *ip0,
506 ip4_address_t *addr, u16 *port,
507 u32 *fib_index, nat_protocol_t *proto,
508 nat44_ei_session_t **p_s0, u8 *dont_translate)
510 nat44_ei_main_t *nm = &nat44_ei_main;
511 nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
513 nat44_ei_session_t *s0 = 0;
514 clib_bihash_kv_8_8_t kv0, value0;
517 vlib_main_t *vm = vlib_get_main ();
520 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
521 *fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
523 err = icmp_get_key (b0, ip0, addr, port, proto);
526 b0->error = node->errors[err];
527 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
531 init_nat_k (&kv0, *addr, *port, *fib_index, *proto);
532 if (clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0))
534 if (vnet_buffer (b0)->sw_if_index[VLIB_TX] != ~0)
536 if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
537 nm, ip0, *proto, *port, *port, thread_index, sw_if_index0)))
545 if (PREDICT_FALSE (nat44_ei_not_translate (
546 nm, node, sw_if_index0, ip0, NAT_PROTOCOL_ICMP, *fib_index,
555 (icmp_type_is_error_message
556 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags)))
558 b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_BAD_ICMP_TYPE];
559 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
563 next0 = slow_path (nm, b0, ip0, *addr, *port, *fib_index, *proto, &s0,
564 node, next0, thread_index, vlib_time_now (vm));
566 if (PREDICT_FALSE (next0 == NAT44_EI_IN2OUT_NEXT_DROP))
578 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
580 && vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
582 && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
583 reass.icmp_type_or_tcp_flags)))
585 b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_BAD_ICMP_TYPE];
586 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
590 s0 = pool_elt_at_index (tnm->sessions,
591 nat_value_get_session_index (&value0));
597 *addr = s0->out2in.addr;
598 *port = s0->out2in.port;
599 *fib_index = s0->out2in.fib_index;
607 #ifndef CLIB_MARCH_VARIANT
609 nat44_ei_icmp_match_in2out_fast (vlib_node_runtime_t *node, u32 thread_index,
610 vlib_buffer_t *b0, ip4_header_t *ip0,
611 ip4_address_t *addr, u16 *port,
612 u32 *fib_index, nat_protocol_t *proto,
613 nat44_ei_session_t **s0, u8 *dont_translate)
621 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
622 *fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
624 err = icmp_get_key (b0, ip0, addr, port, proto);
627 b0->error = node->errors[err];
628 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
632 ip4_address_t sm_addr;
636 if (nat44_ei_static_mapping_match (*addr, *port, *fib_index, *proto,
637 &sm_addr, &sm_port, &sm_fib_index, 0,
640 if (PREDICT_FALSE (nat44_ei_not_translate_fast (
641 node, sw_if_index0, ip0, IP_PROTOCOL_ICMP, *fib_index)))
647 if (icmp_type_is_error_message
648 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
650 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
654 b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_NO_TRANSLATION];
655 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
660 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request
661 && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
662 ICMP4_echo_reply || !is_addr_only)
663 && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
664 reass.icmp_type_or_tcp_flags)))
666 b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_BAD_ICMP_TYPE];
667 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
676 u32 nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0,
677 icmp46_header_t *icmp0, u32 sw_if_index0,
678 u32 rx_fib_index0, vlib_node_runtime_t *node,
679 u32 next0, u32 thread_index,
680 nat44_ei_session_t **p_s0);
682 #ifndef CLIB_MARCH_VARIANT
684 nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0,
685 icmp46_header_t *icmp0, u32 sw_if_index0,
686 u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0,
687 u32 thread_index, nat44_ei_session_t **p_s0)
689 nat44_ei_main_t *nm = &nat44_ei_main;
690 vlib_main_t *vm = vlib_get_main ();
694 nat_protocol_t proto;
695 icmp_echo_header_t *echo0, *inner_echo0 = 0;
696 ip4_header_t *inner_ip0;
698 icmp46_header_t *inner_icmp0;
700 u32 new_addr0, old_addr0;
701 u16 old_id0, new_id0;
702 u16 old_checksum0, new_checksum0;
706 u32 required_thread_index = thread_index;
708 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
710 if (PREDICT_TRUE (nm->pat))
712 next0_tmp = nat44_ei_icmp_match_in2out_slow (
713 node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
718 next0_tmp = nat44_ei_icmp_match_in2out_fast (
719 node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
725 if (next0 == NAT44_EI_IN2OUT_NEXT_DROP || dont_translate)
728 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
731 ip_incremental_checksum_buffer (vm, b0,
733 (u8 *) vlib_buffer_get_current (b0),
734 ntohs (ip0->length) -
735 ip4_header_bytes (ip0), 0);
736 checksum0 = ~ip_csum_fold (sum0);
737 if (PREDICT_FALSE (checksum0 != 0 && checksum0 != 0xffff))
739 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
744 old_addr0 = ip0->src_address.as_u32;
745 new_addr0 = ip0->src_address.as_u32 = addr.as_u32;
747 sum0 = ip0->checksum;
748 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
749 src_address /* changed member */ );
750 ip0->checksum = ip_csum_fold (sum0);
752 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
754 if (icmp0->checksum == 0)
755 icmp0->checksum = 0xffff;
757 if (!icmp_type_is_error_message (icmp0->type))
760 if (PREDICT_FALSE (new_id0 != echo0->identifier))
762 old_id0 = echo0->identifier;
764 echo0->identifier = new_id0;
766 sum0 = icmp0->checksum;
768 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
770 icmp0->checksum = ip_csum_fold (sum0);
775 inner_ip0 = (ip4_header_t *) (echo0 + 1);
776 l4_header = ip4_next_header (inner_ip0);
778 if (!ip4_header_checksum_is_valid (inner_ip0))
780 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
784 /* update inner destination IP address */
785 old_addr0 = inner_ip0->dst_address.as_u32;
786 inner_ip0->dst_address = addr;
787 new_addr0 = inner_ip0->dst_address.as_u32;
788 sum0 = icmp0->checksum;
789 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
790 dst_address /* changed member */ );
791 icmp0->checksum = ip_csum_fold (sum0);
793 /* update inner IP header checksum */
794 old_checksum0 = inner_ip0->checksum;
795 sum0 = inner_ip0->checksum;
796 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
797 dst_address /* changed member */ );
798 inner_ip0->checksum = ip_csum_fold (sum0);
799 new_checksum0 = inner_ip0->checksum;
800 sum0 = icmp0->checksum;
802 ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t,
804 icmp0->checksum = ip_csum_fold (sum0);
808 case NAT_PROTOCOL_ICMP:
809 inner_icmp0 = (icmp46_header_t *) l4_header;
810 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
812 old_id0 = inner_echo0->identifier;
814 inner_echo0->identifier = new_id0;
816 sum0 = icmp0->checksum;
818 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
820 icmp0->checksum = ip_csum_fold (sum0);
822 case NAT_PROTOCOL_UDP:
823 case NAT_PROTOCOL_TCP:
824 old_id0 = ((tcp_udp_header_t *) l4_header)->dst_port;
826 ((tcp_udp_header_t *) l4_header)->dst_port = new_id0;
828 sum0 = icmp0->checksum;
829 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
831 icmp0->checksum = ip_csum_fold (sum0);
839 if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
841 if (0 != nat44_ei_icmp_hairpinning (nm, b0, thread_index, ip0, icmp0,
842 &required_thread_index))
843 vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
844 if (thread_index != required_thread_index)
846 vnet_buffer (b0)->snat.required_thread_index = required_thread_index;
847 next0 = NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF;
856 static_always_inline u32
857 nat44_ei_icmp_in2out_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0,
858 ip4_header_t *ip0, icmp46_header_t *icmp0,
859 u32 sw_if_index0, u32 rx_fib_index0,
860 vlib_node_runtime_t *node, u32 next0, f64 now,
861 u32 thread_index, nat44_ei_session_t **p_s0)
863 vlib_main_t *vm = vlib_get_main ();
865 next0 = nat44_ei_icmp_in2out (b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
866 node, next0, thread_index, p_s0);
867 nat44_ei_session_t *s0 = *p_s0;
868 if (PREDICT_TRUE (next0 != NAT44_EI_IN2OUT_NEXT_DROP && s0))
871 nat44_ei_session_update_counters (
872 s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
873 /* Per-user LRU list maintenance */
874 nat44_ei_session_update_lru (nm, s0, thread_index);
880 nat_in2out_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
881 ip4_header_t *ip, u32 rx_fib_index)
883 clib_bihash_kv_8_8_t kv, value;
884 nat44_ei_static_mapping_t *m;
885 u32 old_addr, new_addr;
888 init_nat_k (&kv, ip->src_address, 0, rx_fib_index, 0);
889 if (clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, &value))
892 m = pool_elt_at_index (nm->static_mappings, value.value);
894 old_addr = ip->src_address.as_u32;
895 new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
897 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
898 ip->checksum = ip_csum_fold (sum);
902 if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
904 vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
905 nat44_ei_hairpinning_sm_unknown_proto (nm, b, ip);
912 nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
913 vlib_frame_t *frame, int is_slow_path,
914 int is_output_feature)
916 u32 n_left_from, *from;
917 nat44_ei_main_t *nm = &nat44_ei_main;
918 f64 now = vlib_time_now (vm);
919 u32 thread_index = vm->thread_index;
921 from = vlib_frame_vector_args (frame);
922 n_left_from = frame->n_vectors;
924 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
925 u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
926 vlib_get_buffers (vm, from, b, n_left_from);
928 while (n_left_from >= 2)
930 vlib_buffer_t *b0, *b1;
932 u32 sw_if_index0, sw_if_index1;
933 ip4_header_t *ip0, *ip1;
934 ip_csum_t sum0, sum1;
935 u32 new_addr0, old_addr0, new_addr1, old_addr1;
936 u16 old_port0, new_port0, old_port1, new_port1;
937 udp_header_t *udp0, *udp1;
938 tcp_header_t *tcp0, *tcp1;
939 icmp46_header_t *icmp0, *icmp1;
940 u32 rx_fib_index0, rx_fib_index1;
942 nat44_ei_session_t *s0 = 0, *s1 = 0;
943 clib_bihash_kv_8_8_t kv0, value0, kv1, value1;
944 u32 iph_offset0 = 0, iph_offset1 = 0;
951 /* Prefetch next iteration. */
952 if (PREDICT_TRUE (n_left_from >= 4))
954 vlib_buffer_t *p2, *p3;
959 vlib_prefetch_buffer_header (p2, LOAD);
960 vlib_prefetch_buffer_header (p3, LOAD);
962 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
963 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, LOAD);
966 if (is_output_feature)
967 iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
969 ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
972 udp0 = ip4_next_header (ip0);
973 tcp0 = (tcp_header_t *) udp0;
974 icmp0 = (icmp46_header_t *) udp0;
976 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
978 vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
980 next0 = next1 = NAT44_EI_IN2OUT_NEXT_LOOKUP;
982 if (PREDICT_FALSE (ip0->ttl == 1))
984 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
985 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
986 ICMP4_time_exceeded_ttl_exceeded_in_transit,
988 next0 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
992 proto0 = ip_proto_to_nat_proto (ip0->protocol);
994 /* Next configured feature, probably ip4-lookup */
997 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
999 if (nat_in2out_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
1001 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
1003 node->errors[NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1005 vlib_increment_simple_counter (
1006 is_slow_path ? &nm->counters.slowpath.in2out.other :
1007 &nm->counters.fastpath.in2out.other,
1008 thread_index, sw_if_index0, 1);
1012 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1014 next0 = nat44_ei_icmp_in2out_slow_path (
1015 nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0,
1016 now, thread_index, &s0);
1017 vlib_increment_simple_counter (
1018 is_slow_path ? &nm->counters.slowpath.in2out.icmp :
1019 &nm->counters.fastpath.in2out.icmp,
1020 thread_index, sw_if_index0, 1);
1026 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1028 next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1032 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1034 next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1039 init_nat_k (&kv0, ip0->src_address,
1040 vnet_buffer (b0)->ip.reass.l4_src_port, rx_fib_index0,
1042 if (PREDICT_FALSE (clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0) !=
1047 if (is_output_feature)
1049 if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
1051 vnet_buffer (b0)->ip.reass.l4_src_port,
1052 vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
1057 * Send DHCP packets to the ipv4 stack, or we won't
1058 * be able to use dhcp client on the outside interface
1061 (proto0 == NAT_PROTOCOL_UDP
1062 && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1063 clib_host_to_net_u16
1064 (UDP_DST_PORT_dhcp_to_server))
1065 && ip0->dst_address.as_u32 == 0xffffffff))
1070 if (PREDICT_FALSE (nat44_ei_not_translate (
1071 nm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
1076 next0 = slow_path (nm, b0, ip0, ip0->src_address,
1077 vnet_buffer (b0)->ip.reass.l4_src_port,
1078 rx_fib_index0, proto0, &s0, node, next0,
1080 if (PREDICT_FALSE (next0 == NAT44_EI_IN2OUT_NEXT_DROP))
1083 if (PREDICT_FALSE (!s0))
1088 next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1093 s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1094 nat_value_get_session_index (&value0));
1096 b0->flags |= VNET_BUFFER_F_IS_NATED;
1098 old_addr0 = ip0->src_address.as_u32;
1099 ip0->src_address = s0->out2in.addr;
1100 new_addr0 = ip0->src_address.as_u32;
1101 if (!is_output_feature)
1102 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1104 sum0 = ip0->checksum;
1105 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1106 ip4_header_t, src_address /* changed member */ );
1107 ip0->checksum = ip_csum_fold (sum0);
1110 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1112 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1114 old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1115 new_port0 = udp0->src_port = s0->out2in.port;
1116 sum0 = tcp0->checksum;
1117 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1119 dst_address /* changed member */ );
1120 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1121 ip4_header_t /* cheat */ ,
1122 length /* changed member */ );
1123 mss_clamping (nm->mss_clamping, tcp0, &sum0);
1124 tcp0->checksum = ip_csum_fold (sum0);
1126 vlib_increment_simple_counter (is_slow_path ?
1127 &nm->counters.slowpath.in2out.tcp :
1128 &nm->counters.fastpath.in2out.tcp,
1129 thread_index, sw_if_index0, 1);
1133 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1135 udp0->src_port = s0->out2in.port;
1136 if (PREDICT_FALSE (udp0->checksum))
1138 old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1139 new_port0 = udp0->src_port;
1140 sum0 = udp0->checksum;
1141 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
1144 ip_csum_update (sum0, old_port0, new_port0,
1145 ip4_header_t /* cheat */ ,
1146 length /* changed member */ );
1147 udp0->checksum = ip_csum_fold (sum0);
1150 vlib_increment_simple_counter (is_slow_path ?
1151 &nm->counters.slowpath.in2out.udp :
1152 &nm->counters.fastpath.in2out.udp,
1153 thread_index, sw_if_index0, 1);
1157 nat44_ei_session_update_counters (
1158 s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
1159 /* Per-user LRU list maintenance */
1160 nat44_ei_session_update_lru (nm, s0, thread_index);
1163 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1164 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1166 nat44_ei_in2out_trace_t *t =
1167 vlib_add_trace (vm, node, b0, sizeof (*t));
1168 t->is_slow_path = is_slow_path;
1169 t->sw_if_index = sw_if_index0;
1170 t->next_index = next0;
1171 t->session_index = ~0;
1173 t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
1176 if (next0 == NAT44_EI_IN2OUT_NEXT_DROP)
1178 vlib_increment_simple_counter (
1179 is_slow_path ? &nm->counters.slowpath.in2out.drops :
1180 &nm->counters.fastpath.in2out.drops,
1181 thread_index, sw_if_index0, 1);
1184 if (is_output_feature)
1185 iph_offset1 = vnet_buffer (b1)->ip.reass.save_rewrite_length;
1187 ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1190 udp1 = ip4_next_header (ip1);
1191 tcp1 = (tcp_header_t *) udp1;
1192 icmp1 = (icmp46_header_t *) udp1;
1194 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1196 vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index1);
1198 if (PREDICT_FALSE (ip1->ttl == 1))
1200 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1201 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1202 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1204 next1 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
1208 proto1 = ip_proto_to_nat_proto (ip1->protocol);
1210 /* Next configured feature, probably ip4-lookup */
1213 if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
1215 if (nat_in2out_sm_unknown_proto (nm, b1, ip1, rx_fib_index1))
1217 next1 = NAT44_EI_IN2OUT_NEXT_DROP;
1219 node->errors[NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1221 vlib_increment_simple_counter (
1222 is_slow_path ? &nm->counters.slowpath.in2out.other :
1223 &nm->counters.fastpath.in2out.other,
1224 thread_index, sw_if_index1, 1);
1228 if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
1230 next1 = nat44_ei_icmp_in2out_slow_path (
1231 nm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, next1,
1232 now, thread_index, &s1);
1233 vlib_increment_simple_counter (
1234 is_slow_path ? &nm->counters.slowpath.in2out.icmp :
1235 &nm->counters.fastpath.in2out.icmp,
1236 thread_index, sw_if_index1, 1);
1242 if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
1244 next1 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1248 if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
1250 next1 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1255 init_nat_k (&kv1, ip1->src_address,
1256 vnet_buffer (b1)->ip.reass.l4_src_port, rx_fib_index1,
1258 if (PREDICT_FALSE (clib_bihash_search_8_8 (&nm->in2out, &kv1, &value1) !=
1263 if (is_output_feature)
1265 if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
1267 vnet_buffer (b1)->ip.reass.l4_src_port,
1268 vnet_buffer (b1)->ip.reass.l4_dst_port, thread_index,
1273 * Send DHCP packets to the ipv4 stack, or we won't
1274 * be able to use dhcp client on the outside interface
1277 (proto1 == NAT_PROTOCOL_UDP
1278 && (vnet_buffer (b1)->ip.reass.l4_dst_port ==
1279 clib_host_to_net_u16
1280 (UDP_DST_PORT_dhcp_to_server))
1281 && ip1->dst_address.as_u32 == 0xffffffff))
1286 if (PREDICT_FALSE (nat44_ei_not_translate (
1287 nm, node, sw_if_index1, ip1, proto1, rx_fib_index1,
1292 next1 = slow_path (nm, b1, ip1, ip1->src_address,
1293 vnet_buffer (b1)->ip.reass.l4_src_port,
1294 rx_fib_index1, proto1, &s1, node, next1,
1296 if (PREDICT_FALSE (next1 == NAT44_EI_IN2OUT_NEXT_DROP))
1299 if (PREDICT_FALSE (!s1))
1304 next1 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1309 s1 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1310 nat_value_get_session_index (&value1));
1312 b1->flags |= VNET_BUFFER_F_IS_NATED;
1314 old_addr1 = ip1->src_address.as_u32;
1315 ip1->src_address = s1->out2in.addr;
1316 new_addr1 = ip1->src_address.as_u32;
1317 if (!is_output_feature)
1318 vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1320 sum1 = ip1->checksum;
1321 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1322 ip4_header_t, src_address /* changed member */ );
1323 ip1->checksum = ip_csum_fold (sum1);
1325 if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
1327 if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1329 old_port1 = vnet_buffer (b1)->ip.reass.l4_src_port;
1330 new_port1 = udp1->src_port = s1->out2in.port;
1331 sum1 = tcp1->checksum;
1332 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1334 dst_address /* changed member */ );
1335 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1336 ip4_header_t /* cheat */ ,
1337 length /* changed member */ );
1338 mss_clamping (nm->mss_clamping, tcp1, &sum1);
1339 tcp1->checksum = ip_csum_fold (sum1);
1341 vlib_increment_simple_counter (is_slow_path ?
1342 &nm->counters.slowpath.in2out.tcp :
1343 &nm->counters.fastpath.in2out.tcp,
1344 thread_index, sw_if_index1, 1);
1348 if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1350 udp1->src_port = s1->out2in.port;
1351 if (PREDICT_FALSE (udp1->checksum))
1353 old_port1 = vnet_buffer (b1)->ip.reass.l4_src_port;
1354 new_port1 = udp1->src_port;
1355 sum1 = udp1->checksum;
1356 sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t, dst_address /* changed member */
1359 ip_csum_update (sum1, old_port1, new_port1,
1360 ip4_header_t /* cheat */ ,
1361 length /* changed member */ );
1362 udp1->checksum = ip_csum_fold (sum1);
1365 vlib_increment_simple_counter (is_slow_path ?
1366 &nm->counters.slowpath.in2out.udp :
1367 &nm->counters.fastpath.in2out.udp,
1368 thread_index, sw_if_index1, 1);
1372 nat44_ei_session_update_counters (
1373 s1, now, vlib_buffer_length_in_chain (vm, b1), thread_index);
1374 /* Per-user LRU list maintenance */
1375 nat44_ei_session_update_lru (nm, s1, thread_index);
1378 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1379 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1381 nat44_ei_in2out_trace_t *t =
1382 vlib_add_trace (vm, node, b1, sizeof (*t));
1383 t->sw_if_index = sw_if_index1;
1384 t->next_index = next1;
1385 t->session_index = ~0;
1387 t->session_index = s1 - nm->per_thread_data[thread_index].sessions;
1390 if (next1 == NAT44_EI_IN2OUT_NEXT_DROP)
1392 vlib_increment_simple_counter (
1393 is_slow_path ? &nm->counters.slowpath.in2out.drops :
1394 &nm->counters.fastpath.in2out.drops,
1395 thread_index, sw_if_index1, 1);
1404 while (n_left_from > 0)
1411 u32 new_addr0, old_addr0;
1412 u16 old_port0, new_port0;
1415 icmp46_header_t *icmp0;
1418 nat44_ei_session_t *s0 = 0;
1419 clib_bihash_kv_8_8_t kv0, value0;
1420 u32 iph_offset0 = 0;
1424 next0 = NAT44_EI_IN2OUT_NEXT_LOOKUP;
1426 if (is_output_feature)
1427 iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
1429 ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1432 udp0 = ip4_next_header (ip0);
1433 tcp0 = (tcp_header_t *) udp0;
1434 icmp0 = (icmp46_header_t *) udp0;
1436 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1438 vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
1440 if (PREDICT_FALSE (ip0->ttl == 1))
1442 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1443 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1444 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1446 next0 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
1450 proto0 = ip_proto_to_nat_proto (ip0->protocol);
1452 /* Next configured feature, probably ip4-lookup */
1455 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1457 if (nat_in2out_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
1459 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
1461 node->errors[NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
1463 vlib_increment_simple_counter (
1464 is_slow_path ? &nm->counters.slowpath.in2out.other :
1465 &nm->counters.fastpath.in2out.other,
1466 thread_index, sw_if_index0, 1);
1470 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1472 next0 = nat44_ei_icmp_in2out_slow_path (
1473 nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0,
1474 now, thread_index, &s0);
1475 vlib_increment_simple_counter (
1476 is_slow_path ? &nm->counters.slowpath.in2out.icmp :
1477 &nm->counters.fastpath.in2out.icmp,
1478 thread_index, sw_if_index0, 1);
1484 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1486 next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1490 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1492 next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1497 init_nat_k (&kv0, ip0->src_address,
1498 vnet_buffer (b0)->ip.reass.l4_src_port, rx_fib_index0,
1501 if (clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0))
1505 if (is_output_feature)
1507 if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
1509 vnet_buffer (b0)->ip.reass.l4_src_port,
1510 vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
1515 * Send DHCP packets to the ipv4 stack, or we won't
1516 * be able to use dhcp client on the outside interface
1519 (proto0 == NAT_PROTOCOL_UDP
1520 && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1521 clib_host_to_net_u16
1522 (UDP_DST_PORT_dhcp_to_server))
1523 && ip0->dst_address.as_u32 == 0xffffffff))
1528 if (PREDICT_FALSE (nat44_ei_not_translate (
1529 nm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
1534 next0 = slow_path (nm, b0, ip0, ip0->src_address,
1535 vnet_buffer (b0)->ip.reass.l4_src_port,
1536 rx_fib_index0, proto0, &s0, node, next0,
1539 if (PREDICT_FALSE (next0 == NAT44_EI_IN2OUT_NEXT_DROP))
1542 if (PREDICT_FALSE (!s0))
1547 next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
1552 s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1553 nat_value_get_session_index (&value0));
1555 b0->flags |= VNET_BUFFER_F_IS_NATED;
1557 old_addr0 = ip0->src_address.as_u32;
1558 ip0->src_address = s0->out2in.addr;
1559 new_addr0 = ip0->src_address.as_u32;
1560 if (!is_output_feature)
1561 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1563 sum0 = ip0->checksum;
1564 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1565 ip4_header_t, src_address /* changed member */ );
1566 ip0->checksum = ip_csum_fold (sum0);
1568 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1570 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1572 old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1573 new_port0 = udp0->src_port = s0->out2in.port;
1574 sum0 = tcp0->checksum;
1576 ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1577 dst_address /* changed member */ );
1579 ip_csum_update (sum0, old_port0, new_port0,
1580 ip4_header_t /* cheat */ ,
1581 length /* changed member */ );
1582 mss_clamping (nm->mss_clamping, tcp0, &sum0);
1583 tcp0->checksum = ip_csum_fold (sum0);
1585 vlib_increment_simple_counter (is_slow_path ?
1586 &nm->counters.slowpath.in2out.tcp :
1587 &nm->counters.fastpath.in2out.tcp,
1588 thread_index, sw_if_index0, 1);
1592 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1594 udp0->src_port = s0->out2in.port;
1595 if (PREDICT_FALSE (udp0->checksum))
1597 old_port0 = vnet_buffer (b0)->ip.reass.l4_src_port;
1598 new_port0 = udp0->src_port;
1599 sum0 = udp0->checksum;
1601 ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1602 dst_address /* changed member */ );
1604 ip_csum_update (sum0, old_port0, new_port0,
1605 ip4_header_t /* cheat */ ,
1606 length /* changed member */ );
1607 udp0->checksum = ip_csum_fold (sum0);
1610 vlib_increment_simple_counter (is_slow_path ?
1611 &nm->counters.slowpath.in2out.udp :
1612 &nm->counters.fastpath.in2out.udp,
1613 thread_index, sw_if_index0, 1);
1617 nat44_ei_session_update_counters (
1618 s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
1619 /* Per-user LRU list maintenance */
1620 nat44_ei_session_update_lru (nm, s0, thread_index);
1623 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1624 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1626 nat44_ei_in2out_trace_t *t =
1627 vlib_add_trace (vm, node, b0, sizeof (*t));
1628 t->is_slow_path = is_slow_path;
1629 t->sw_if_index = sw_if_index0;
1630 t->next_index = next0;
1631 t->session_index = ~0;
1633 t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
1636 if (next0 == NAT44_EI_IN2OUT_NEXT_DROP)
1638 vlib_increment_simple_counter (
1639 is_slow_path ? &nm->counters.slowpath.in2out.drops :
1640 &nm->counters.fastpath.in2out.drops,
1641 thread_index, sw_if_index0, 1);
1649 vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1651 return frame->n_vectors;
1654 VLIB_NODE_FN (nat44_ei_in2out_node)
1655 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1657 return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */,
1661 VLIB_REGISTER_NODE (nat44_ei_in2out_node) = {
1662 .name = "nat44-ei-in2out",
1663 .vector_size = sizeof (u32),
1664 .format_trace = format_nat44_ei_in2out_trace,
1665 .type = VLIB_NODE_TYPE_INTERNAL,
1667 .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
1668 .error_strings = nat44_ei_in2out_error_strings,
1670 .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
1672 .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
1674 /* edit / add dispositions here */
1676 [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
1677 [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1678 [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath",
1679 [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1680 [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
1684 VLIB_NODE_FN (nat44_ei_in2out_output_node)
1685 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1687 return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */,
1691 VLIB_REGISTER_NODE (nat44_ei_in2out_output_node) = {
1692 .name = "nat44-ei-in2out-output",
1693 .vector_size = sizeof (u32),
1694 .format_trace = format_nat44_ei_in2out_trace,
1695 .type = VLIB_NODE_TYPE_INTERNAL,
1697 .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
1698 .error_strings = nat44_ei_in2out_error_strings,
1700 .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
1702 .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
1704 /* edit / add dispositions here */
1706 [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
1707 [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output",
1708 [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath",
1709 [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1710 [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output",
1714 VLIB_NODE_FN (nat44_ei_in2out_slowpath_node)
1715 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1717 return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */,
1721 VLIB_REGISTER_NODE (nat44_ei_in2out_slowpath_node) = {
1722 .name = "nat44-ei-in2out-slowpath",
1723 .vector_size = sizeof (u32),
1724 .format_trace = format_nat44_ei_in2out_trace,
1725 .type = VLIB_NODE_TYPE_INTERNAL,
1727 .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
1728 .error_strings = nat44_ei_in2out_error_strings,
1730 .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
1732 .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
1734 /* edit / add dispositions here */
1736 [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
1737 [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1738 [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath",
1739 [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1740 [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
1744 VLIB_NODE_FN (nat44_ei_in2out_output_slowpath_node)
1745 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1747 return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */,
1751 VLIB_REGISTER_NODE (nat44_ei_in2out_output_slowpath_node) = {
1752 .name = "nat44-ei-in2out-output-slowpath",
1753 .vector_size = sizeof (u32),
1754 .format_trace = format_nat44_ei_in2out_trace,
1755 .type = VLIB_NODE_TYPE_INTERNAL,
1757 .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
1758 .error_strings = nat44_ei_in2out_error_strings,
1760 .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
1762 .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
1764 /* edit / add dispositions here */
1766 [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
1767 [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output",
1768 [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath",
1769 [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1770 [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output",
1774 VLIB_NODE_FN (nat44_ei_in2out_fast_node)
1775 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1777 u32 n_left_from, *from, *to_next;
1778 u32 thread_index = vm->thread_index;
1779 nat44_ei_in2out_next_t next_index;
1780 nat44_ei_main_t *nm = &nat44_ei_main;
1781 int is_hairpinning = 0;
1783 from = vlib_frame_vector_args (frame);
1784 n_left_from = frame->n_vectors;
1785 next_index = node->cached_next_index;
1787 while (n_left_from > 0)
1791 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1793 while (n_left_from > 0 && n_left_to_next > 0)
1801 u32 new_addr0, old_addr0;
1802 u16 old_port0, new_port0;
1805 icmp46_header_t *icmp0;
1808 ip4_address_t sm0_addr;
1811 u32 required_thread_index = thread_index;
1813 /* speculatively enqueue b0 to the current next frame */
1819 n_left_to_next -= 1;
1821 b0 = vlib_get_buffer (vm, bi0);
1822 next0 = NAT44_EI_IN2OUT_NEXT_LOOKUP;
1824 ip0 = vlib_buffer_get_current (b0);
1825 udp0 = ip4_next_header (ip0);
1826 tcp0 = (tcp_header_t *) udp0;
1827 icmp0 = (icmp46_header_t *) udp0;
1829 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1831 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1833 if (PREDICT_FALSE (ip0->ttl == 1))
1835 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1836 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1837 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1839 next0 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
1843 proto0 = ip_proto_to_nat_proto (ip0->protocol);
1845 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1848 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1850 next0 = nat44_ei_icmp_in2out (b0, ip0, icmp0, sw_if_index0,
1851 rx_fib_index0, node, next0, ~0, 0);
1855 if (nat44_ei_static_mapping_match (
1856 ip0->src_address, udp0->src_port, rx_fib_index0, proto0,
1857 &sm0_addr, &sm0_port, &sm0_fib_index, 0, 0, 0))
1859 b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_NO_TRANSLATION];
1860 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
1864 new_addr0 = sm0_addr.as_u32;
1865 new_port0 = sm0_port;
1866 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0_fib_index;
1867 old_addr0 = ip0->src_address.as_u32;
1868 ip0->src_address.as_u32 = new_addr0;
1870 sum0 = ip0->checksum;
1871 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1873 src_address /* changed member */ );
1874 ip0->checksum = ip_csum_fold (sum0);
1876 if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1878 old_port0 = udp0->src_port;
1879 udp0->src_port = new_port0;
1881 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1883 sum0 = tcp0->checksum;
1884 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1886 dst_address /* changed member */ );
1887 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1888 ip4_header_t /* cheat */ ,
1889 length /* changed member */ );
1890 mss_clamping (nm->mss_clamping, tcp0, &sum0);
1891 tcp0->checksum = ip_csum_fold (sum0);
1893 else if (udp0->checksum)
1895 sum0 = udp0->checksum;
1896 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1898 dst_address /* changed member */ );
1899 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1900 ip4_header_t /* cheat */ ,
1901 length /* changed member */ );
1902 udp0->checksum = ip_csum_fold (sum0);
1907 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1909 sum0 = tcp0->checksum;
1910 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1912 dst_address /* changed member */ );
1913 mss_clamping (nm->mss_clamping, tcp0, &sum0);
1914 tcp0->checksum = ip_csum_fold (sum0);
1916 else if (udp0->checksum)
1918 sum0 = udp0->checksum;
1919 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1921 dst_address /* changed member */ );
1922 udp0->checksum = ip_csum_fold (sum0);
1927 is_hairpinning = nat44_ei_hairpinning (
1928 vm, node, nm, thread_index, b0, ip0, udp0, tcp0, proto0,
1929 0 /* do_trace */, &required_thread_index);
1931 if (thread_index != required_thread_index)
1933 vnet_buffer (b0)->snat.required_thread_index =
1934 required_thread_index;
1935 next0 = NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF;
1939 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1940 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1942 nat44_ei_in2out_trace_t *t =
1943 vlib_add_trace (vm, node, b0, sizeof (*t));
1944 t->sw_if_index = sw_if_index0;
1945 t->next_index = next0;
1946 t->is_hairpinning = is_hairpinning;
1949 if (next0 != NAT44_EI_IN2OUT_NEXT_DROP)
1952 vlib_increment_simple_counter (
1953 &nm->counters.fastpath.in2out.other, sw_if_index0,
1954 vm->thread_index, 1);
1957 /* verify speculative enqueue, maybe switch current next frame */
1958 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1959 to_next, n_left_to_next,
1963 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1966 return frame->n_vectors;
1969 VLIB_REGISTER_NODE (nat44_ei_in2out_fast_node) = {
1970 .name = "nat44-ei-in2out-fast",
1971 .vector_size = sizeof (u32),
1972 .format_trace = format_nat44_ei_in2out_fast_trace,
1973 .type = VLIB_NODE_TYPE_INTERNAL,
1975 .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
1976 .error_strings = nat44_ei_in2out_error_strings,
1978 .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
1980 .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
1982 /* edit / add dispositions here */
1984 [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
1985 [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1986 [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath",
1987 [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1988 [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
1992 VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node)
1993 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1995 return nat44_ei_hairpinning_handoff_fn_inline (
1997 nat44_ei_main.in2out_hairpinning_finish_ip4_lookup_node_fq_index);
2000 VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node) = {
2001 .name = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
2002 .vector_size = sizeof (u32),
2003 .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings),
2004 .error_strings = nat44_ei_hairpinning_handoff_error_strings,
2005 .format_trace = format_nat44_ei_hairpinning_handoff_trace,
2014 VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_interface_output_node)
2015 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2017 return nat44_ei_hairpinning_handoff_fn_inline (
2019 nat44_ei_main.in2out_hairpinning_finish_interface_output_node_fq_index);
2022 VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_interface_output_node) = {
2023 .name = "nat44-ei-in2out-hairpinning-handoff-interface-output",
2024 .vector_size = sizeof (u32),
2025 .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings),
2026 .error_strings = nat44_ei_hairpinning_handoff_error_strings,
2027 .format_trace = format_nat44_ei_hairpinning_handoff_trace,
2036 static_always_inline int
2037 nat44_ei_in2out_hairpinning_finish_inline (vlib_main_t *vm,
2038 vlib_node_runtime_t *node,
2039 vlib_frame_t *frame)
2041 u32 n_left_from, *from, *to_next;
2042 u32 thread_index = vm->thread_index;
2043 nat44_ei_in2out_next_t next_index;
2044 nat44_ei_main_t *nm = &nat44_ei_main;
2045 int is_hairpinning = 0;
2047 from = vlib_frame_vector_args (frame);
2048 n_left_from = frame->n_vectors;
2049 next_index = node->cached_next_index;
2051 while (n_left_from > 0)
2055 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2057 while (n_left_from > 0 && n_left_to_next > 0)
2066 icmp46_header_t *icmp0;
2068 u32 required_thread_index = thread_index;
2070 /* speculatively enqueue b0 to the current next frame */
2076 n_left_to_next -= 1;
2078 b0 = vlib_get_buffer (vm, bi0);
2079 next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP;
2081 ip0 = vlib_buffer_get_current (b0);
2082 udp0 = ip4_next_header (ip0);
2083 tcp0 = (tcp_header_t *) udp0;
2084 icmp0 = (icmp46_header_t *) udp0;
2086 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2087 proto0 = ip_proto_to_nat_proto (ip0->protocol);
2091 case NAT_PROTOCOL_TCP:
2093 case NAT_PROTOCOL_UDP:
2094 is_hairpinning = nat44_ei_hairpinning (
2095 vm, node, nm, thread_index, b0, ip0, udp0, tcp0, proto0,
2096 0 /* do_trace */, &required_thread_index);
2098 case NAT_PROTOCOL_ICMP:
2099 is_hairpinning = (0 == nat44_ei_icmp_hairpinning (
2100 nm, b0, thread_index, ip0, icmp0,
2101 &required_thread_index));
2103 case NAT_PROTOCOL_OTHER:
2104 // this should never happen
2105 next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP;
2109 if (thread_index != required_thread_index)
2111 // but we already did a handoff ...
2112 next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP;
2115 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2116 (b0->flags & VLIB_BUFFER_IS_TRACED)))
2118 nat44_ei_in2out_trace_t *t =
2119 vlib_add_trace (vm, node, b0, sizeof (*t));
2120 t->sw_if_index = sw_if_index0;
2121 t->next_index = next0;
2122 t->is_hairpinning = is_hairpinning;
2125 if (next0 != NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP)
2127 vlib_increment_simple_counter (
2128 &nm->counters.fastpath.in2out.other, sw_if_index0,
2129 vm->thread_index, 1);
2132 /* verify speculative enqueue, maybe switch current next frame */
2133 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2134 n_left_to_next, bi0, next0);
2137 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2140 return frame->n_vectors;
2143 VLIB_NODE_FN (nat44_ei_in2out_hairpinning_finish_ip4_lookup_node)
2144 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2146 return nat44_ei_in2out_hairpinning_finish_inline (vm, node, frame);
2149 VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_finish_ip4_lookup_node) = {
2150 .name = "nat44-ei-in2out-hairpinning-finish-ip4-lookup",
2151 .vector_size = sizeof (u32),
2152 .format_trace = format_nat44_ei_in2out_fast_trace,
2153 .type = VLIB_NODE_TYPE_INTERNAL,
2155 .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
2156 .error_strings = nat44_ei_in2out_error_strings,
2158 .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
2160 .n_next_nodes = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
2162 /* edit / add dispositions here */
2164 [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop",
2165 [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "ip4-lookup",
2169 VLIB_NODE_FN (nat44_ei_in2out_hairpinning_finish_interface_output_node)
2170 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
2172 return nat44_ei_in2out_hairpinning_finish_inline (vm, node, frame);
2175 VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_finish_interface_output_node) = {
2176 .name = "nat44-ei-in2out-hairpinning-finish-interface-output",
2177 .vector_size = sizeof (u32),
2178 .format_trace = format_nat44_ei_in2out_fast_trace,
2179 .type = VLIB_NODE_TYPE_INTERNAL,
2181 .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
2182 .error_strings = nat44_ei_in2out_error_strings,
2184 .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
2186 .n_next_nodes = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
2188 /* edit / add dispositions here */
2190 [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop",
2191 [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "interface-output",
2196 * fd.io coding-style-patch-verification: ON
2199 * eval: (c-set-style "gnu")