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 endpoint-dependent outside to inside network translation
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/pg/pg.h>
24 #include <vnet/ip/ip.h>
25 #include <vnet/udp/udp.h>
26 #include <vnet/ethernet/ethernet.h>
27 #include <vnet/fib/ip4_fib.h>
29 #include <nat/nat_ipfix_logging.h>
30 #include <nat/nat_reass.h>
31 #include <nat/nat_inlines.h>
33 #include <vppinfra/hash.h>
34 #include <vppinfra/error.h>
35 #include <vppinfra/elog.h>
42 } snat_out2in_trace_t;
44 /* packet trace format function */
46 format_snat_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 snat_out2in_trace_t *t = va_arg (*args, snat_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_snat_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 snat_out2in_trace_t *t = va_arg (*args, snat_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 vlib_node_registration_t snat_out2in_node;
72 vlib_node_registration_t snat_out2in_fast_node;
73 vlib_node_registration_t nat44_out2in_reass_node;
75 #define foreach_snat_out2in_error \
76 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
77 _(OUT2IN_PACKETS, "Good out2in packets processed") \
78 _(OUT_OF_PORTS, "Out of ports") \
79 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
80 _(NO_TRANSLATION, "No translation") \
81 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \
82 _(DROP_FRAGMENT, "Drop fragment") \
83 _(MAX_REASS, "Maximum reassemblies exceeded") \
84 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")
88 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
89 foreach_snat_out2in_error
92 } snat_out2in_error_t;
94 static char *snat_out2in_error_strings[] = {
95 #define _(sym,string) string,
96 foreach_snat_out2in_error
102 SNAT_OUT2IN_NEXT_DROP,
103 SNAT_OUT2IN_NEXT_LOOKUP,
104 SNAT_OUT2IN_NEXT_ICMP_ERROR,
105 SNAT_OUT2IN_NEXT_REASS,
107 } snat_out2in_next_t;
110 nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
112 snat_main_t *sm = &snat_main;
113 nat44_is_idle_session_ctx_t *ctx = arg;
115 u64 sess_timeout_time;
116 snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
118 clib_bihash_kv_8_8_t s_kv;
120 s = pool_elt_at_index (tsm->sessions, kv->value);
121 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
122 if (ctx->now >= sess_timeout_time)
124 s_kv.key = s->in2out.as_u64;
125 if (clib_bihash_add_del_8_8 (&tsm->in2out, &s_kv, 0))
126 nat_log_warn ("out2in key del failed");
128 snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
129 s->out2in.addr.as_u32,
133 s->in2out.fib_index);
135 if (!snat_is_session_static (s))
136 snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
139 nat44_delete_session (sm, s, ctx->thread_index);
147 * @brief Create session for static mapping.
149 * Create NAT session initiated by host from external network with static
152 * @param sm NAT main.
153 * @param b0 Vlib buffer.
154 * @param in2out In2out NAT44 session key.
155 * @param out2in Out2in NAT44 session key.
156 * @param node Vlib node.
158 * @returns SNAT session if successfully created otherwise 0.
160 static inline snat_session_t *
161 create_session_for_static_mapping (snat_main_t * sm,
163 snat_session_key_t in2out,
164 snat_session_key_t out2in,
165 vlib_node_runtime_t * node,
166 u32 thread_index, f64 now)
170 clib_bihash_kv_8_8_t kv0;
173 nat44_is_idle_session_ctx_t ctx0;
175 if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
177 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
178 nat_log_notice ("maximum sessions exceeded");
182 ip0 = vlib_buffer_get_current (b0);
183 udp0 = ip4_next_header (ip0);
186 nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index);
189 nat_log_warn ("create NAT user failed");
193 s = nat_session_alloc_or_recycle (sm, u, thread_index);
196 nat44_delete_user_with_no_session (sm, u, thread_index);
197 nat_log_warn ("create NAT session failed");
201 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
202 s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
203 s->ext_host_port = udp0->src_port;
204 user_session_increment (sm, u, 1 /* static */ );
207 s->in2out.protocol = out2in.protocol;
209 /* Add to translation hashes */
211 ctx0.thread_index = thread_index;
212 kv0.key = s->in2out.as_u64;
213 kv0.value = s - sm->per_thread_data[thread_index].sessions;
214 if (clib_bihash_add_or_overwrite_stale_8_8
215 (&sm->per_thread_data[thread_index].in2out, &kv0,
216 nat44_i2o_is_idle_session_cb, &ctx0))
217 nat_log_notice ("in2out key add failed");
219 kv0.key = s->out2in.as_u64;
221 if (clib_bihash_add_or_overwrite_stale_8_8
222 (&sm->per_thread_data[thread_index].out2in, &kv0,
223 nat44_o2i_is_idle_session_cb, &ctx0))
224 nat_log_notice ("out2in key add failed");
227 snat_ipfix_logging_nat44_ses_create (s->in2out.addr.as_u32,
228 s->out2in.addr.as_u32,
231 s->out2in.port, s->in2out.fib_index);
236 snat_out2in_error_t icmp_get_key (ip4_header_t * ip0,
237 snat_session_key_t * p_key0)
239 icmp46_header_t *icmp0;
240 snat_session_key_t key0;
241 icmp_echo_header_t *echo0, *inner_echo0 = 0;
242 ip4_header_t *inner_ip0;
244 icmp46_header_t *inner_icmp0;
246 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
247 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
249 if (!icmp_is_error_message (icmp0))
251 key0.protocol = SNAT_PROTOCOL_ICMP;
252 key0.addr = ip0->dst_address;
253 key0.port = echo0->identifier;
257 inner_ip0 = (ip4_header_t *) (echo0 + 1);
258 l4_header = ip4_next_header (inner_ip0);
259 key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
260 key0.addr = inner_ip0->src_address;
261 switch (key0.protocol)
263 case SNAT_PROTOCOL_ICMP:
264 inner_icmp0 = (icmp46_header_t *) l4_header;
265 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
266 key0.port = inner_echo0->identifier;
268 case SNAT_PROTOCOL_UDP:
269 case SNAT_PROTOCOL_TCP:
270 key0.port = ((tcp_udp_header_t *) l4_header)->src_port;
273 return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
277 return -1; /* success */
281 * Get address and port values to be used for ICMP packet translation
282 * and create session if needed
284 * @param[in,out] sm NAT main
285 * @param[in,out] node NAT node runtime
286 * @param[in] thread_index thread index
287 * @param[in,out] b0 buffer containing packet to be translated
288 * @param[out] p_proto protocol used for matching
289 * @param[out] p_value address and port after NAT translation
290 * @param[out] p_dont_translate if packet should not be translated
291 * @param d optional parameter
292 * @param e optional parameter
295 icmp_match_out2in_slow (snat_main_t * sm, vlib_node_runtime_t * node,
296 u32 thread_index, vlib_buffer_t * b0,
297 ip4_header_t * ip0, u8 * p_proto,
298 snat_session_key_t * p_value,
299 u8 * p_dont_translate, void *d, void *e)
301 icmp46_header_t *icmp0;
304 snat_session_key_t key0;
305 snat_session_key_t sm0;
306 snat_session_t *s0 = 0;
307 u8 dont_translate = 0;
308 clib_bihash_kv_8_8_t kv0, value0;
313 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
314 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
315 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
319 err = icmp_get_key (ip0, &key0);
322 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
323 next0 = SNAT_OUT2IN_NEXT_DROP;
326 key0.fib_index = rx_fib_index0;
328 kv0.key = key0.as_u64;
330 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
333 /* Try to match static mapping by external address and port,
334 destination address and port in packet */
335 if (snat_static_mapping_match
336 (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0))
338 if (!sm->forwarding_enabled)
340 /* Don't NAT packet aimed at the intfc address */
341 if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index0,
342 ip0->dst_address.as_u32)))
347 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
348 next0 = SNAT_OUT2IN_NEXT_DROP;
358 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
359 (icmp0->type != ICMP4_echo_request
362 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
363 next0 = SNAT_OUT2IN_NEXT_DROP;
367 /* Create session initiated by host from external network */
368 s0 = create_session_for_static_mapping (sm, b0, sm0, key0,
370 vlib_time_now (sm->vlib_main));
374 next0 = SNAT_OUT2IN_NEXT_DROP;
380 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
381 icmp0->type != ICMP4_echo_request &&
382 !icmp_is_error_message (icmp0)))
384 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
385 next0 = SNAT_OUT2IN_NEXT_DROP;
389 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
394 *p_proto = key0.protocol;
396 *p_value = s0->in2out;
397 *p_dont_translate = dont_translate;
399 *(snat_session_t **) d = s0;
404 * Get address and port values to be used for ICMP packet translation
406 * @param[in] sm NAT main
407 * @param[in,out] node NAT node runtime
408 * @param[in] thread_index thread index
409 * @param[in,out] b0 buffer containing packet to be translated
410 * @param[out] p_proto protocol used for matching
411 * @param[out] p_value address and port after NAT translation
412 * @param[out] p_dont_translate if packet should not be translated
413 * @param d optional parameter
414 * @param e optional parameter
417 icmp_match_out2in_fast (snat_main_t * sm, vlib_node_runtime_t * node,
418 u32 thread_index, vlib_buffer_t * b0,
419 ip4_header_t * ip0, u8 * p_proto,
420 snat_session_key_t * p_value,
421 u8 * p_dont_translate, void *d, void *e)
423 icmp46_header_t *icmp0;
426 snat_session_key_t key0;
427 snat_session_key_t sm0;
428 u8 dont_translate = 0;
433 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
434 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
435 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
437 err = icmp_get_key (ip0, &key0);
440 b0->error = node->errors[err];
441 next0 = SNAT_OUT2IN_NEXT_DROP;
444 key0.fib_index = rx_fib_index0;
446 if (snat_static_mapping_match (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0))
448 /* Don't NAT packet aimed at the intfc address */
449 if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))
454 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
455 next0 = SNAT_OUT2IN_NEXT_DROP;
459 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
460 (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
461 !icmp_is_error_message (icmp0)))
463 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
464 next0 = SNAT_OUT2IN_NEXT_DROP;
471 *p_proto = key0.protocol;
472 *p_dont_translate = dont_translate;
477 icmp_out2in (snat_main_t * sm,
480 icmp46_header_t * icmp0,
483 vlib_node_runtime_t * node,
484 u32 next0, u32 thread_index, void *d, void *e)
486 snat_session_key_t sm0;
488 icmp_echo_header_t *echo0, *inner_echo0 = 0;
489 ip4_header_t *inner_ip0 = 0;
491 icmp46_header_t *inner_icmp0;
493 u32 new_addr0, old_addr0;
494 u16 old_id0, new_id0;
499 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
501 next0_tmp = sm->icmp_match_out2in_cb (sm, node, thread_index, b0, ip0,
502 &protocol, &sm0, &dont_translate, d,
506 if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
509 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
511 sum0 = ip_incremental_checksum_buffer (sm->vlib_main, b0, (u8 *) icmp0 -
513 vlib_buffer_get_current (b0),
514 ntohs (ip0->length) -
515 ip4_header_bytes (ip0), 0);
516 checksum0 = ~ip_csum_fold (sum0);
517 if (checksum0 != 0 && checksum0 != 0xffff)
519 next0 = SNAT_OUT2IN_NEXT_DROP;
524 old_addr0 = ip0->dst_address.as_u32;
525 new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
526 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
528 sum0 = ip0->checksum;
529 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
530 dst_address /* changed member */ );
531 ip0->checksum = ip_csum_fold (sum0);
533 if (icmp0->checksum == 0)
534 icmp0->checksum = 0xffff;
536 if (!icmp_is_error_message (icmp0))
539 if (PREDICT_FALSE (new_id0 != echo0->identifier))
541 old_id0 = echo0->identifier;
543 echo0->identifier = new_id0;
545 sum0 = icmp0->checksum;
546 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
547 identifier /* changed member */ );
548 icmp0->checksum = ip_csum_fold (sum0);
553 inner_ip0 = (ip4_header_t *) (echo0 + 1);
554 l4_header = ip4_next_header (inner_ip0);
556 if (!ip4_header_checksum_is_valid (inner_ip0))
558 next0 = SNAT_OUT2IN_NEXT_DROP;
562 old_addr0 = inner_ip0->src_address.as_u32;
563 inner_ip0->src_address = sm0.addr;
564 new_addr0 = inner_ip0->src_address.as_u32;
566 sum0 = icmp0->checksum;
567 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
568 src_address /* changed member */ );
569 icmp0->checksum = ip_csum_fold (sum0);
573 case SNAT_PROTOCOL_ICMP:
574 inner_icmp0 = (icmp46_header_t *) l4_header;
575 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
577 old_id0 = inner_echo0->identifier;
579 inner_echo0->identifier = new_id0;
581 sum0 = icmp0->checksum;
582 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
584 icmp0->checksum = ip_csum_fold (sum0);
586 case SNAT_PROTOCOL_UDP:
587 case SNAT_PROTOCOL_TCP:
588 old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
590 ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
592 sum0 = icmp0->checksum;
593 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
595 icmp0->checksum = ip_csum_fold (sum0);
608 icmp_out2in_slow_path (snat_main_t * sm,
611 icmp46_header_t * icmp0,
614 vlib_node_runtime_t * node,
616 u32 thread_index, snat_session_t ** p_s0)
618 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
619 next0, thread_index, p_s0, 0);
620 snat_session_t *s0 = *p_s0;
621 if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP && s0))
624 nat44_session_update_counters (s0, now,
625 vlib_buffer_length_in_chain
626 (sm->vlib_main, b0));
627 /* Per-user LRU list maintenance */
628 nat44_session_update_lru (sm, s0, thread_index);
634 nat_out2in_sm_unknown_proto (snat_main_t * sm,
636 ip4_header_t * ip, u32 rx_fib_index)
638 clib_bihash_kv_8_8_t kv, value;
639 snat_static_mapping_t *m;
640 snat_session_key_t m_key;
641 u32 old_addr, new_addr;
644 m_key.addr = ip->dst_address;
648 kv.key = m_key.as_u64;
649 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
652 m = pool_elt_at_index (sm->static_mappings, value.value);
654 old_addr = ip->dst_address.as_u32;
655 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
657 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
658 ip->checksum = ip_csum_fold (sum);
660 vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
665 snat_out2in_node_fn (vlib_main_t * vm,
666 vlib_node_runtime_t * node, vlib_frame_t * frame)
668 u32 n_left_from, *from, *to_next;
669 snat_out2in_next_t next_index;
670 u32 pkts_processed = 0;
671 snat_main_t *sm = &snat_main;
672 f64 now = vlib_time_now (vm);
673 u32 thread_index = vm->thread_index;
675 from = vlib_frame_vector_args (frame);
676 n_left_from = frame->n_vectors;
677 next_index = node->cached_next_index;
679 while (n_left_from > 0)
683 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
685 while (n_left_from >= 4 && n_left_to_next >= 2)
688 vlib_buffer_t *b0, *b1;
689 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
690 u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
691 u32 sw_if_index0, sw_if_index1;
692 ip4_header_t *ip0, *ip1;
693 ip_csum_t sum0, sum1;
694 u32 new_addr0, old_addr0;
695 u16 new_port0, old_port0;
696 u32 new_addr1, old_addr1;
697 u16 new_port1, old_port1;
698 udp_header_t *udp0, *udp1;
699 tcp_header_t *tcp0, *tcp1;
700 icmp46_header_t *icmp0, *icmp1;
701 snat_session_key_t key0, key1, sm0, sm1;
702 u32 rx_fib_index0, rx_fib_index1;
704 snat_session_t *s0 = 0, *s1 = 0;
705 clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
707 /* Prefetch next iteration. */
709 vlib_buffer_t *p2, *p3;
711 p2 = vlib_get_buffer (vm, from[2]);
712 p3 = vlib_get_buffer (vm, from[3]);
714 vlib_prefetch_buffer_header (p2, LOAD);
715 vlib_prefetch_buffer_header (p3, LOAD);
717 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
718 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
721 /* speculatively enqueue b0 and b1 to the current next frame */
722 to_next[0] = bi0 = from[0];
723 to_next[1] = bi1 = from[1];
729 b0 = vlib_get_buffer (vm, bi0);
730 b1 = vlib_get_buffer (vm, bi1);
732 vnet_buffer (b0)->snat.flags = 0;
733 vnet_buffer (b1)->snat.flags = 0;
735 ip0 = vlib_buffer_get_current (b0);
736 udp0 = ip4_next_header (ip0);
737 tcp0 = (tcp_header_t *) udp0;
738 icmp0 = (icmp46_header_t *) udp0;
740 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
741 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
744 if (PREDICT_FALSE (ip0->ttl == 1))
746 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
747 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
748 ICMP4_time_exceeded_ttl_exceeded_in_transit,
750 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
754 proto0 = ip_proto_to_snat_proto (ip0->protocol);
756 if (PREDICT_FALSE (proto0 == ~0))
758 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
760 if (!sm->forwarding_enabled)
763 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
764 next0 = SNAT_OUT2IN_NEXT_DROP;
770 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
772 next0 = icmp_out2in_slow_path
773 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
774 next0, now, thread_index, &s0);
778 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
780 next0 = SNAT_OUT2IN_NEXT_REASS;
784 key0.addr = ip0->dst_address;
785 key0.port = udp0->dst_port;
786 key0.protocol = proto0;
787 key0.fib_index = rx_fib_index0;
789 kv0.key = key0.as_u64;
791 if (clib_bihash_search_8_8
792 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
794 /* Try to match static mapping by external address and port,
795 destination address and port in packet */
796 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
799 * Send DHCP packets to the ipv4 stack, or we won't
800 * be able to use dhcp client on the outside interface
802 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
803 && (udp0->dst_port ==
805 (UDP_DST_PORT_dhcp_to_client))))
807 vnet_feature_next (&next0, b0);
811 if (!sm->forwarding_enabled)
814 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
815 next0 = SNAT_OUT2IN_NEXT_DROP;
820 /* Create session initiated by host from external network */
821 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
825 next0 = SNAT_OUT2IN_NEXT_DROP;
831 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
834 old_addr0 = ip0->dst_address.as_u32;
835 ip0->dst_address = s0->in2out.addr;
836 new_addr0 = ip0->dst_address.as_u32;
837 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
839 sum0 = ip0->checksum;
840 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
842 dst_address /* changed member */ );
843 ip0->checksum = ip_csum_fold (sum0);
845 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
847 old_port0 = tcp0->dst_port;
848 tcp0->dst_port = s0->in2out.port;
849 new_port0 = tcp0->dst_port;
851 sum0 = tcp0->checksum;
852 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
854 dst_address /* changed member */ );
856 sum0 = ip_csum_update (sum0, old_port0, new_port0,
857 ip4_header_t /* cheat */ ,
858 length /* changed member */ );
859 tcp0->checksum = ip_csum_fold (sum0);
863 old_port0 = udp0->dst_port;
864 udp0->dst_port = s0->in2out.port;
869 nat44_session_update_counters (s0, now,
870 vlib_buffer_length_in_chain (vm,
872 /* Per-user LRU list maintenance */
873 nat44_session_update_lru (sm, s0, thread_index);
876 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
877 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
879 snat_out2in_trace_t *t =
880 vlib_add_trace (vm, node, b0, sizeof (*t));
881 t->sw_if_index = sw_if_index0;
882 t->next_index = next0;
883 t->session_index = ~0;
886 s0 - sm->per_thread_data[thread_index].sessions;
889 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
892 ip1 = vlib_buffer_get_current (b1);
893 udp1 = ip4_next_header (ip1);
894 tcp1 = (tcp_header_t *) udp1;
895 icmp1 = (icmp46_header_t *) udp1;
897 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
898 rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
901 if (PREDICT_FALSE (ip1->ttl == 1))
903 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
904 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
905 ICMP4_time_exceeded_ttl_exceeded_in_transit,
907 next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
911 proto1 = ip_proto_to_snat_proto (ip1->protocol);
913 if (PREDICT_FALSE (proto1 == ~0))
915 if (nat_out2in_sm_unknown_proto (sm, b1, ip1, rx_fib_index1))
917 if (!sm->forwarding_enabled)
920 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
921 next1 = SNAT_OUT2IN_NEXT_DROP;
927 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
929 next1 = icmp_out2in_slow_path
930 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
931 next1, now, thread_index, &s1);
935 if (PREDICT_FALSE (ip4_is_fragment (ip1)))
937 next1 = SNAT_OUT2IN_NEXT_REASS;
941 key1.addr = ip1->dst_address;
942 key1.port = udp1->dst_port;
943 key1.protocol = proto1;
944 key1.fib_index = rx_fib_index1;
946 kv1.key = key1.as_u64;
948 if (clib_bihash_search_8_8
949 (&sm->per_thread_data[thread_index].out2in, &kv1, &value1))
951 /* Try to match static mapping by external address and port,
952 destination address and port in packet */
953 if (snat_static_mapping_match (sm, key1, &sm1, 1, 0, 0, 0, 0))
956 * Send DHCP packets to the ipv4 stack, or we won't
957 * be able to use dhcp client on the outside interface
959 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
960 && (udp1->dst_port ==
962 (UDP_DST_PORT_dhcp_to_client))))
964 vnet_feature_next (&next1, b1);
968 if (!sm->forwarding_enabled)
971 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
972 next1 = SNAT_OUT2IN_NEXT_DROP;
977 /* Create session initiated by host from external network */
978 s1 = create_session_for_static_mapping (sm, b1, sm1, key1, node,
982 next1 = SNAT_OUT2IN_NEXT_DROP;
988 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
991 old_addr1 = ip1->dst_address.as_u32;
992 ip1->dst_address = s1->in2out.addr;
993 new_addr1 = ip1->dst_address.as_u32;
994 vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
996 sum1 = ip1->checksum;
997 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
999 dst_address /* changed member */ );
1000 ip1->checksum = ip_csum_fold (sum1);
1002 if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1004 old_port1 = tcp1->dst_port;
1005 tcp1->dst_port = s1->in2out.port;
1006 new_port1 = tcp1->dst_port;
1008 sum1 = tcp1->checksum;
1009 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1011 dst_address /* changed member */ );
1013 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1014 ip4_header_t /* cheat */ ,
1015 length /* changed member */ );
1016 tcp1->checksum = ip_csum_fold (sum1);
1020 old_port1 = udp1->dst_port;
1021 udp1->dst_port = s1->in2out.port;
1026 nat44_session_update_counters (s1, now,
1027 vlib_buffer_length_in_chain (vm,
1029 /* Per-user LRU list maintenance */
1030 nat44_session_update_lru (sm, s1, thread_index);
1033 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1034 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1036 snat_out2in_trace_t *t =
1037 vlib_add_trace (vm, node, b1, sizeof (*t));
1038 t->sw_if_index = sw_if_index1;
1039 t->next_index = next1;
1040 t->session_index = ~0;
1043 s1 - sm->per_thread_data[thread_index].sessions;
1046 pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1048 /* verify speculative enqueues, maybe switch current next frame */
1049 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1050 to_next, n_left_to_next,
1051 bi0, bi1, next0, next1);
1054 while (n_left_from > 0 && n_left_to_next > 0)
1058 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1062 u32 new_addr0, old_addr0;
1063 u16 new_port0, old_port0;
1066 icmp46_header_t *icmp0;
1067 snat_session_key_t key0, sm0;
1070 snat_session_t *s0 = 0;
1071 clib_bihash_kv_8_8_t kv0, value0;
1073 /* speculatively enqueue b0 to the current next frame */
1079 n_left_to_next -= 1;
1081 b0 = vlib_get_buffer (vm, bi0);
1083 vnet_buffer (b0)->snat.flags = 0;
1085 ip0 = vlib_buffer_get_current (b0);
1086 udp0 = ip4_next_header (ip0);
1087 tcp0 = (tcp_header_t *) udp0;
1088 icmp0 = (icmp46_header_t *) udp0;
1090 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1091 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1094 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1096 if (PREDICT_FALSE (proto0 == ~0))
1098 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
1100 if (!sm->forwarding_enabled)
1103 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1104 next0 = SNAT_OUT2IN_NEXT_DROP;
1110 if (PREDICT_FALSE (ip0->ttl == 1))
1112 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1113 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1114 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1116 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1120 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1122 next0 = icmp_out2in_slow_path
1123 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1124 next0, now, thread_index, &s0);
1128 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1130 next0 = SNAT_OUT2IN_NEXT_REASS;
1134 key0.addr = ip0->dst_address;
1135 key0.port = udp0->dst_port;
1136 key0.protocol = proto0;
1137 key0.fib_index = rx_fib_index0;
1139 kv0.key = key0.as_u64;
1141 if (clib_bihash_search_8_8
1142 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
1144 /* Try to match static mapping by external address and port,
1145 destination address and port in packet */
1146 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
1149 * Send DHCP packets to the ipv4 stack, or we won't
1150 * be able to use dhcp client on the outside interface
1152 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1153 && (udp0->dst_port ==
1154 clib_host_to_net_u16
1155 (UDP_DST_PORT_dhcp_to_client))))
1157 vnet_feature_next (&next0, b0);
1161 if (!sm->forwarding_enabled)
1164 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1165 next0 = SNAT_OUT2IN_NEXT_DROP;
1170 /* Create session initiated by host from external network */
1171 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
1175 next0 = SNAT_OUT2IN_NEXT_DROP;
1181 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1184 old_addr0 = ip0->dst_address.as_u32;
1185 ip0->dst_address = s0->in2out.addr;
1186 new_addr0 = ip0->dst_address.as_u32;
1187 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1189 sum0 = ip0->checksum;
1190 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1192 dst_address /* changed member */ );
1193 ip0->checksum = ip_csum_fold (sum0);
1195 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1197 old_port0 = tcp0->dst_port;
1198 tcp0->dst_port = s0->in2out.port;
1199 new_port0 = tcp0->dst_port;
1201 sum0 = tcp0->checksum;
1202 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1204 dst_address /* changed member */ );
1206 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1207 ip4_header_t /* cheat */ ,
1208 length /* changed member */ );
1209 tcp0->checksum = ip_csum_fold (sum0);
1213 old_port0 = udp0->dst_port;
1214 udp0->dst_port = s0->in2out.port;
1219 nat44_session_update_counters (s0, now,
1220 vlib_buffer_length_in_chain (vm,
1222 /* Per-user LRU list maintenance */
1223 nat44_session_update_lru (sm, s0, thread_index);
1226 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1227 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1229 snat_out2in_trace_t *t =
1230 vlib_add_trace (vm, node, b0, sizeof (*t));
1231 t->sw_if_index = sw_if_index0;
1232 t->next_index = next0;
1233 t->session_index = ~0;
1236 s0 - sm->per_thread_data[thread_index].sessions;
1239 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1241 /* verify speculative enqueue, maybe switch current next frame */
1242 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1243 to_next, n_left_to_next,
1247 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1250 vlib_node_increment_counter (vm, snat_out2in_node.index,
1251 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1253 return frame->n_vectors;
1257 VLIB_REGISTER_NODE (snat_out2in_node) = {
1258 .function = snat_out2in_node_fn,
1259 .name = "nat44-out2in",
1260 .vector_size = sizeof (u32),
1261 .format_trace = format_snat_out2in_trace,
1262 .type = VLIB_NODE_TYPE_INTERNAL,
1264 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1265 .error_strings = snat_out2in_error_strings,
1267 .runtime_data_bytes = sizeof (snat_runtime_t),
1269 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1271 /* edit / add dispositions here */
1273 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1274 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1275 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1276 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1281 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
1284 nat44_out2in_reass_node_fn (vlib_main_t * vm,
1285 vlib_node_runtime_t * node, vlib_frame_t * frame)
1287 u32 n_left_from, *from, *to_next;
1288 snat_out2in_next_t next_index;
1289 u32 pkts_processed = 0;
1290 snat_main_t *sm = &snat_main;
1291 f64 now = vlib_time_now (vm);
1292 u32 thread_index = vm->thread_index;
1293 snat_main_per_thread_data_t *per_thread_data =
1294 &sm->per_thread_data[thread_index];
1295 u32 *fragments_to_drop = 0;
1296 u32 *fragments_to_loopback = 0;
1298 from = vlib_frame_vector_args (frame);
1299 n_left_from = frame->n_vectors;
1300 next_index = node->cached_next_index;
1302 while (n_left_from > 0)
1306 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1308 while (n_left_from > 0 && n_left_to_next > 0)
1310 u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1315 nat_reass_ip4_t *reass0;
1318 snat_session_key_t key0, sm0;
1319 clib_bihash_kv_8_8_t kv0, value0;
1320 snat_session_t *s0 = 0;
1321 u16 old_port0, new_port0;
1324 /* speculatively enqueue b0 to the current next frame */
1330 n_left_to_next -= 1;
1332 b0 = vlib_get_buffer (vm, bi0);
1333 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1335 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1337 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1340 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1342 next0 = SNAT_OUT2IN_NEXT_DROP;
1343 b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1347 ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1348 udp0 = ip4_next_header (ip0);
1349 tcp0 = (tcp_header_t *) udp0;
1350 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1352 reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1356 1, &fragments_to_drop);
1358 if (PREDICT_FALSE (!reass0))
1360 next0 = SNAT_OUT2IN_NEXT_DROP;
1361 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1362 nat_log_notice ("maximum reassemblies exceeded");
1366 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1368 key0.addr = ip0->dst_address;
1369 key0.port = udp0->dst_port;
1370 key0.protocol = proto0;
1371 key0.fib_index = rx_fib_index0;
1372 kv0.key = key0.as_u64;
1374 if (clib_bihash_search_8_8
1375 (&per_thread_data->out2in, &kv0, &value0))
1377 /* Try to match static mapping by external address and port,
1378 destination address and port in packet */
1379 if (snat_static_mapping_match
1380 (sm, key0, &sm0, 1, 0, 0, 0, 0))
1383 * Send DHCP packets to the ipv4 stack, or we won't
1384 * be able to use dhcp client on the outside interface
1386 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1389 clib_host_to_net_u16
1390 (UDP_DST_PORT_dhcp_to_client))))
1392 vnet_feature_next (&next0, b0);
1396 if (!sm->forwarding_enabled)
1399 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1400 next0 = SNAT_OUT2IN_NEXT_DROP;
1405 /* Create session initiated by host from external network */
1407 create_session_for_static_mapping (sm, b0, sm0, key0,
1413 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1414 next0 = SNAT_OUT2IN_NEXT_DROP;
1417 reass0->sess_index = s0 - per_thread_data->sessions;
1418 reass0->thread_index = thread_index;
1422 s0 = pool_elt_at_index (per_thread_data->sessions,
1424 reass0->sess_index = value0.value;
1426 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1430 if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1432 if (nat_ip4_reass_add_fragment
1433 (reass0, bi0, &fragments_to_drop))
1435 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1437 ("maximum fragments per reassembly exceeded");
1438 next0 = SNAT_OUT2IN_NEXT_DROP;
1444 s0 = pool_elt_at_index (per_thread_data->sessions,
1445 reass0->sess_index);
1448 old_addr0 = ip0->dst_address.as_u32;
1449 ip0->dst_address = s0->in2out.addr;
1450 new_addr0 = ip0->dst_address.as_u32;
1451 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1453 sum0 = ip0->checksum;
1454 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1456 dst_address /* changed member */ );
1457 ip0->checksum = ip_csum_fold (sum0);
1459 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1461 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1463 old_port0 = tcp0->dst_port;
1464 tcp0->dst_port = s0->in2out.port;
1465 new_port0 = tcp0->dst_port;
1467 sum0 = tcp0->checksum;
1468 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1470 dst_address /* changed member */ );
1472 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1473 ip4_header_t /* cheat */ ,
1474 length /* changed member */ );
1475 tcp0->checksum = ip_csum_fold (sum0);
1479 old_port0 = udp0->dst_port;
1480 udp0->dst_port = s0->in2out.port;
1486 nat44_session_update_counters (s0, now,
1487 vlib_buffer_length_in_chain (vm,
1489 /* Per-user LRU list maintenance */
1490 nat44_session_update_lru (sm, s0, thread_index);
1493 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1494 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1496 nat44_reass_trace_t *t =
1497 vlib_add_trace (vm, node, b0, sizeof (*t));
1498 t->cached = cached0;
1499 t->sw_if_index = sw_if_index0;
1500 t->next_index = next0;
1510 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1512 /* verify speculative enqueue, maybe switch current next frame */
1513 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1514 to_next, n_left_to_next,
1518 if (n_left_from == 0 && vec_len (fragments_to_loopback))
1520 from = vlib_frame_vector_args (frame);
1521 u32 len = vec_len (fragments_to_loopback);
1522 if (len <= VLIB_FRAME_SIZE)
1524 clib_memcpy (from, fragments_to_loopback,
1525 sizeof (u32) * len);
1527 vec_reset_length (fragments_to_loopback);
1532 fragments_to_loopback + (len -
1534 sizeof (u32) * VLIB_FRAME_SIZE);
1535 n_left_from = VLIB_FRAME_SIZE;
1536 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1541 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1544 vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1545 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1548 nat_send_all_to_node (vm, fragments_to_drop, node,
1549 &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1550 SNAT_OUT2IN_NEXT_DROP);
1552 vec_free (fragments_to_drop);
1553 vec_free (fragments_to_loopback);
1554 return frame->n_vectors;
1558 VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
1559 .function = nat44_out2in_reass_node_fn,
1560 .name = "nat44-out2in-reass",
1561 .vector_size = sizeof (u32),
1562 .format_trace = format_nat44_reass_trace,
1563 .type = VLIB_NODE_TYPE_INTERNAL,
1565 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1566 .error_strings = snat_out2in_error_strings,
1568 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1570 /* edit / add dispositions here */
1572 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1573 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1574 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1575 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1580 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
1581 nat44_out2in_reass_node_fn);
1584 snat_out2in_fast_node_fn (vlib_main_t * vm,
1585 vlib_node_runtime_t * node, vlib_frame_t * frame)
1587 u32 n_left_from, *from, *to_next;
1588 snat_out2in_next_t next_index;
1589 u32 pkts_processed = 0;
1590 snat_main_t *sm = &snat_main;
1592 from = vlib_frame_vector_args (frame);
1593 n_left_from = frame->n_vectors;
1594 next_index = node->cached_next_index;
1596 while (n_left_from > 0)
1600 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1602 while (n_left_from > 0 && n_left_to_next > 0)
1606 u32 next0 = SNAT_OUT2IN_NEXT_DROP;
1610 u32 new_addr0, old_addr0;
1611 u16 new_port0, old_port0;
1614 icmp46_header_t *icmp0;
1615 snat_session_key_t key0, sm0;
1619 /* speculatively enqueue b0 to the current next frame */
1625 n_left_to_next -= 1;
1627 b0 = vlib_get_buffer (vm, bi0);
1629 ip0 = vlib_buffer_get_current (b0);
1630 udp0 = ip4_next_header (ip0);
1631 tcp0 = (tcp_header_t *) udp0;
1632 icmp0 = (icmp46_header_t *) udp0;
1634 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1636 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1638 vnet_feature_next (&next0, b0);
1640 if (PREDICT_FALSE (ip0->ttl == 1))
1642 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1643 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1644 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1646 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1650 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1652 if (PREDICT_FALSE (proto0 == ~0))
1655 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1657 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0,
1658 rx_fib_index0, node, next0, ~0, 0, 0);
1662 key0.addr = ip0->dst_address;
1663 key0.port = udp0->dst_port;
1664 key0.fib_index = rx_fib_index0;
1666 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
1668 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1672 new_addr0 = sm0.addr.as_u32;
1673 new_port0 = sm0.port;
1674 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1675 old_addr0 = ip0->dst_address.as_u32;
1676 ip0->dst_address.as_u32 = new_addr0;
1678 sum0 = ip0->checksum;
1679 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1681 dst_address /* changed member */ );
1682 ip0->checksum = ip_csum_fold (sum0);
1684 if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1686 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1688 old_port0 = tcp0->dst_port;
1689 tcp0->dst_port = new_port0;
1691 sum0 = tcp0->checksum;
1692 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1694 dst_address /* changed member */ );
1696 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1697 ip4_header_t /* cheat */ ,
1698 length /* changed member */ );
1699 tcp0->checksum = ip_csum_fold (sum0);
1703 old_port0 = udp0->dst_port;
1704 udp0->dst_port = new_port0;
1710 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1712 sum0 = tcp0->checksum;
1713 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1715 dst_address /* changed member */ );
1717 tcp0->checksum = ip_csum_fold (sum0);
1723 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1724 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1726 snat_out2in_trace_t *t =
1727 vlib_add_trace (vm, node, b0, sizeof (*t));
1728 t->sw_if_index = sw_if_index0;
1729 t->next_index = next0;
1732 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1734 /* verify speculative enqueue, maybe switch current next frame */
1735 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1736 to_next, n_left_to_next,
1740 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1743 vlib_node_increment_counter (vm, snat_out2in_fast_node.index,
1744 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1746 return frame->n_vectors;
1750 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
1751 .function = snat_out2in_fast_node_fn,
1752 .name = "nat44-out2in-fast",
1753 .vector_size = sizeof (u32),
1754 .format_trace = format_snat_out2in_fast_trace,
1755 .type = VLIB_NODE_TYPE_INTERNAL,
1757 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1758 .error_strings = snat_out2in_error_strings,
1760 .runtime_data_bytes = sizeof (snat_runtime_t),
1762 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1764 /* edit / add dispositions here */
1766 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1767 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1768 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1769 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1774 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node,
1775 snat_out2in_fast_node_fn);
1778 * fd.io coding-style-patch-verification: ON
1781 * eval: (c-set-style "gnu")