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 (0, icmp0,
512 ntohs (ip0->length) -
513 ip4_header_bytes (ip0));
514 checksum0 = ~ip_csum_fold (sum0);
515 if (checksum0 != 0 && checksum0 != 0xffff)
517 next0 = SNAT_OUT2IN_NEXT_DROP;
522 old_addr0 = ip0->dst_address.as_u32;
523 new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
524 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
526 sum0 = ip0->checksum;
527 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
528 dst_address /* changed member */ );
529 ip0->checksum = ip_csum_fold (sum0);
531 if (icmp0->checksum == 0)
532 icmp0->checksum = 0xffff;
534 if (!icmp_is_error_message (icmp0))
537 if (PREDICT_FALSE (new_id0 != echo0->identifier))
539 old_id0 = echo0->identifier;
541 echo0->identifier = new_id0;
543 sum0 = icmp0->checksum;
544 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
545 identifier /* changed member */ );
546 icmp0->checksum = ip_csum_fold (sum0);
551 inner_ip0 = (ip4_header_t *) (echo0 + 1);
552 l4_header = ip4_next_header (inner_ip0);
554 if (!ip4_header_checksum_is_valid (inner_ip0))
556 next0 = SNAT_OUT2IN_NEXT_DROP;
560 old_addr0 = inner_ip0->src_address.as_u32;
561 inner_ip0->src_address = sm0.addr;
562 new_addr0 = inner_ip0->src_address.as_u32;
564 sum0 = icmp0->checksum;
565 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
566 src_address /* changed member */ );
567 icmp0->checksum = ip_csum_fold (sum0);
571 case SNAT_PROTOCOL_ICMP:
572 inner_icmp0 = (icmp46_header_t *) l4_header;
573 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
575 old_id0 = inner_echo0->identifier;
577 inner_echo0->identifier = new_id0;
579 sum0 = icmp0->checksum;
580 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
582 icmp0->checksum = ip_csum_fold (sum0);
584 case SNAT_PROTOCOL_UDP:
585 case SNAT_PROTOCOL_TCP:
586 old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
588 ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
590 sum0 = icmp0->checksum;
591 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
593 icmp0->checksum = ip_csum_fold (sum0);
606 icmp_out2in_slow_path (snat_main_t * sm,
609 icmp46_header_t * icmp0,
612 vlib_node_runtime_t * node,
614 u32 thread_index, snat_session_t ** p_s0)
616 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
617 next0, thread_index, p_s0, 0);
618 snat_session_t *s0 = *p_s0;
619 if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP && s0))
622 nat44_session_update_counters (s0, now,
623 vlib_buffer_length_in_chain
624 (sm->vlib_main, b0));
625 /* Per-user LRU list maintenance */
626 nat44_session_update_lru (sm, s0, thread_index);
632 nat_out2in_sm_unknown_proto (snat_main_t * sm,
634 ip4_header_t * ip, u32 rx_fib_index)
636 clib_bihash_kv_8_8_t kv, value;
637 snat_static_mapping_t *m;
638 snat_session_key_t m_key;
639 u32 old_addr, new_addr;
642 m_key.addr = ip->dst_address;
646 kv.key = m_key.as_u64;
647 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
650 m = pool_elt_at_index (sm->static_mappings, value.value);
652 old_addr = ip->dst_address.as_u32;
653 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
655 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
656 ip->checksum = ip_csum_fold (sum);
658 vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
663 snat_out2in_node_fn (vlib_main_t * vm,
664 vlib_node_runtime_t * node, vlib_frame_t * frame)
666 u32 n_left_from, *from, *to_next;
667 snat_out2in_next_t next_index;
668 u32 pkts_processed = 0;
669 snat_main_t *sm = &snat_main;
670 f64 now = vlib_time_now (vm);
671 u32 thread_index = vm->thread_index;
673 from = vlib_frame_vector_args (frame);
674 n_left_from = frame->n_vectors;
675 next_index = node->cached_next_index;
677 while (n_left_from > 0)
681 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
683 while (n_left_from >= 4 && n_left_to_next >= 2)
686 vlib_buffer_t *b0, *b1;
687 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
688 u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
689 u32 sw_if_index0, sw_if_index1;
690 ip4_header_t *ip0, *ip1;
691 ip_csum_t sum0, sum1;
692 u32 new_addr0, old_addr0;
693 u16 new_port0, old_port0;
694 u32 new_addr1, old_addr1;
695 u16 new_port1, old_port1;
696 udp_header_t *udp0, *udp1;
697 tcp_header_t *tcp0, *tcp1;
698 icmp46_header_t *icmp0, *icmp1;
699 snat_session_key_t key0, key1, sm0, sm1;
700 u32 rx_fib_index0, rx_fib_index1;
702 snat_session_t *s0 = 0, *s1 = 0;
703 clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
705 /* Prefetch next iteration. */
707 vlib_buffer_t *p2, *p3;
709 p2 = vlib_get_buffer (vm, from[2]);
710 p3 = vlib_get_buffer (vm, from[3]);
712 vlib_prefetch_buffer_header (p2, LOAD);
713 vlib_prefetch_buffer_header (p3, LOAD);
715 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
716 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
719 /* speculatively enqueue b0 and b1 to the current next frame */
720 to_next[0] = bi0 = from[0];
721 to_next[1] = bi1 = from[1];
727 b0 = vlib_get_buffer (vm, bi0);
728 b1 = vlib_get_buffer (vm, bi1);
730 vnet_buffer (b0)->snat.flags = 0;
731 vnet_buffer (b1)->snat.flags = 0;
733 ip0 = vlib_buffer_get_current (b0);
734 udp0 = ip4_next_header (ip0);
735 tcp0 = (tcp_header_t *) udp0;
736 icmp0 = (icmp46_header_t *) udp0;
738 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
739 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
742 if (PREDICT_FALSE (ip0->ttl == 1))
744 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
745 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
746 ICMP4_time_exceeded_ttl_exceeded_in_transit,
748 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
752 proto0 = ip_proto_to_snat_proto (ip0->protocol);
754 if (PREDICT_FALSE (proto0 == ~0))
756 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
758 if (!sm->forwarding_enabled)
761 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
762 next0 = SNAT_OUT2IN_NEXT_DROP;
768 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
770 next0 = icmp_out2in_slow_path
771 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
772 next0, now, thread_index, &s0);
776 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
778 next0 = SNAT_OUT2IN_NEXT_REASS;
782 key0.addr = ip0->dst_address;
783 key0.port = udp0->dst_port;
784 key0.protocol = proto0;
785 key0.fib_index = rx_fib_index0;
787 kv0.key = key0.as_u64;
789 if (clib_bihash_search_8_8
790 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
792 /* Try to match static mapping by external address and port,
793 destination address and port in packet */
794 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
797 * Send DHCP packets to the ipv4 stack, or we won't
798 * be able to use dhcp client on the outside interface
800 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
801 && (udp0->dst_port ==
803 (UDP_DST_PORT_dhcp_to_client))))
805 vnet_feature_next (&next0, b0);
809 if (!sm->forwarding_enabled)
812 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
813 next0 = SNAT_OUT2IN_NEXT_DROP;
818 /* Create session initiated by host from external network */
819 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
823 next0 = SNAT_OUT2IN_NEXT_DROP;
829 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
832 old_addr0 = ip0->dst_address.as_u32;
833 ip0->dst_address = s0->in2out.addr;
834 new_addr0 = ip0->dst_address.as_u32;
835 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
837 sum0 = ip0->checksum;
838 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
840 dst_address /* changed member */ );
841 ip0->checksum = ip_csum_fold (sum0);
843 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
845 old_port0 = tcp0->dst_port;
846 tcp0->dst_port = s0->in2out.port;
847 new_port0 = tcp0->dst_port;
849 sum0 = tcp0->checksum;
850 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
852 dst_address /* changed member */ );
854 sum0 = ip_csum_update (sum0, old_port0, new_port0,
855 ip4_header_t /* cheat */ ,
856 length /* changed member */ );
857 tcp0->checksum = ip_csum_fold (sum0);
861 old_port0 = udp0->dst_port;
862 udp0->dst_port = s0->in2out.port;
867 nat44_session_update_counters (s0, now,
868 vlib_buffer_length_in_chain (vm,
870 /* Per-user LRU list maintenance */
871 nat44_session_update_lru (sm, s0, thread_index);
874 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
875 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
877 snat_out2in_trace_t *t =
878 vlib_add_trace (vm, node, b0, sizeof (*t));
879 t->sw_if_index = sw_if_index0;
880 t->next_index = next0;
881 t->session_index = ~0;
884 s0 - sm->per_thread_data[thread_index].sessions;
887 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
890 ip1 = vlib_buffer_get_current (b1);
891 udp1 = ip4_next_header (ip1);
892 tcp1 = (tcp_header_t *) udp1;
893 icmp1 = (icmp46_header_t *) udp1;
895 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
896 rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
899 if (PREDICT_FALSE (ip1->ttl == 1))
901 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
902 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
903 ICMP4_time_exceeded_ttl_exceeded_in_transit,
905 next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
909 proto1 = ip_proto_to_snat_proto (ip1->protocol);
911 if (PREDICT_FALSE (proto1 == ~0))
913 if (nat_out2in_sm_unknown_proto (sm, b1, ip1, rx_fib_index1))
915 if (!sm->forwarding_enabled)
918 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
919 next1 = SNAT_OUT2IN_NEXT_DROP;
925 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
927 next1 = icmp_out2in_slow_path
928 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
929 next1, now, thread_index, &s1);
933 if (PREDICT_FALSE (ip4_is_fragment (ip1)))
935 next1 = SNAT_OUT2IN_NEXT_REASS;
939 key1.addr = ip1->dst_address;
940 key1.port = udp1->dst_port;
941 key1.protocol = proto1;
942 key1.fib_index = rx_fib_index1;
944 kv1.key = key1.as_u64;
946 if (clib_bihash_search_8_8
947 (&sm->per_thread_data[thread_index].out2in, &kv1, &value1))
949 /* Try to match static mapping by external address and port,
950 destination address and port in packet */
951 if (snat_static_mapping_match (sm, key1, &sm1, 1, 0, 0, 0, 0))
954 * Send DHCP packets to the ipv4 stack, or we won't
955 * be able to use dhcp client on the outside interface
957 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
958 && (udp1->dst_port ==
960 (UDP_DST_PORT_dhcp_to_client))))
962 vnet_feature_next (&next1, b1);
966 if (!sm->forwarding_enabled)
969 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
970 next1 = SNAT_OUT2IN_NEXT_DROP;
975 /* Create session initiated by host from external network */
976 s1 = create_session_for_static_mapping (sm, b1, sm1, key1, node,
980 next1 = SNAT_OUT2IN_NEXT_DROP;
986 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
989 old_addr1 = ip1->dst_address.as_u32;
990 ip1->dst_address = s1->in2out.addr;
991 new_addr1 = ip1->dst_address.as_u32;
992 vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
994 sum1 = ip1->checksum;
995 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
997 dst_address /* changed member */ );
998 ip1->checksum = ip_csum_fold (sum1);
1000 if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1002 old_port1 = tcp1->dst_port;
1003 tcp1->dst_port = s1->in2out.port;
1004 new_port1 = tcp1->dst_port;
1006 sum1 = tcp1->checksum;
1007 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1009 dst_address /* changed member */ );
1011 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1012 ip4_header_t /* cheat */ ,
1013 length /* changed member */ );
1014 tcp1->checksum = ip_csum_fold (sum1);
1018 old_port1 = udp1->dst_port;
1019 udp1->dst_port = s1->in2out.port;
1024 nat44_session_update_counters (s1, now,
1025 vlib_buffer_length_in_chain (vm,
1027 /* Per-user LRU list maintenance */
1028 nat44_session_update_lru (sm, s1, thread_index);
1031 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1032 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1034 snat_out2in_trace_t *t =
1035 vlib_add_trace (vm, node, b1, sizeof (*t));
1036 t->sw_if_index = sw_if_index1;
1037 t->next_index = next1;
1038 t->session_index = ~0;
1041 s1 - sm->per_thread_data[thread_index].sessions;
1044 pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1046 /* verify speculative enqueues, maybe switch current next frame */
1047 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1048 to_next, n_left_to_next,
1049 bi0, bi1, next0, next1);
1052 while (n_left_from > 0 && n_left_to_next > 0)
1056 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1060 u32 new_addr0, old_addr0;
1061 u16 new_port0, old_port0;
1064 icmp46_header_t *icmp0;
1065 snat_session_key_t key0, sm0;
1068 snat_session_t *s0 = 0;
1069 clib_bihash_kv_8_8_t kv0, value0;
1071 /* speculatively enqueue b0 to the current next frame */
1077 n_left_to_next -= 1;
1079 b0 = vlib_get_buffer (vm, bi0);
1081 vnet_buffer (b0)->snat.flags = 0;
1083 ip0 = vlib_buffer_get_current (b0);
1084 udp0 = ip4_next_header (ip0);
1085 tcp0 = (tcp_header_t *) udp0;
1086 icmp0 = (icmp46_header_t *) udp0;
1088 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1089 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1092 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1094 if (PREDICT_FALSE (proto0 == ~0))
1096 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
1098 if (!sm->forwarding_enabled)
1101 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1102 next0 = SNAT_OUT2IN_NEXT_DROP;
1108 if (PREDICT_FALSE (ip0->ttl == 1))
1110 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1111 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1112 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1114 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1118 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1120 next0 = icmp_out2in_slow_path
1121 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1122 next0, now, thread_index, &s0);
1126 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1128 next0 = SNAT_OUT2IN_NEXT_REASS;
1132 key0.addr = ip0->dst_address;
1133 key0.port = udp0->dst_port;
1134 key0.protocol = proto0;
1135 key0.fib_index = rx_fib_index0;
1137 kv0.key = key0.as_u64;
1139 if (clib_bihash_search_8_8
1140 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
1142 /* Try to match static mapping by external address and port,
1143 destination address and port in packet */
1144 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
1147 * Send DHCP packets to the ipv4 stack, or we won't
1148 * be able to use dhcp client on the outside interface
1150 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1151 && (udp0->dst_port ==
1152 clib_host_to_net_u16
1153 (UDP_DST_PORT_dhcp_to_client))))
1155 vnet_feature_next (&next0, b0);
1159 if (!sm->forwarding_enabled)
1162 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1163 next0 = SNAT_OUT2IN_NEXT_DROP;
1168 /* Create session initiated by host from external network */
1169 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
1173 next0 = SNAT_OUT2IN_NEXT_DROP;
1179 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1182 old_addr0 = ip0->dst_address.as_u32;
1183 ip0->dst_address = s0->in2out.addr;
1184 new_addr0 = ip0->dst_address.as_u32;
1185 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1187 sum0 = ip0->checksum;
1188 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1190 dst_address /* changed member */ );
1191 ip0->checksum = ip_csum_fold (sum0);
1193 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1195 old_port0 = tcp0->dst_port;
1196 tcp0->dst_port = s0->in2out.port;
1197 new_port0 = tcp0->dst_port;
1199 sum0 = tcp0->checksum;
1200 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1202 dst_address /* changed member */ );
1204 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1205 ip4_header_t /* cheat */ ,
1206 length /* changed member */ );
1207 tcp0->checksum = ip_csum_fold (sum0);
1211 old_port0 = udp0->dst_port;
1212 udp0->dst_port = s0->in2out.port;
1217 nat44_session_update_counters (s0, now,
1218 vlib_buffer_length_in_chain (vm,
1220 /* Per-user LRU list maintenance */
1221 nat44_session_update_lru (sm, s0, thread_index);
1224 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1225 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1227 snat_out2in_trace_t *t =
1228 vlib_add_trace (vm, node, b0, sizeof (*t));
1229 t->sw_if_index = sw_if_index0;
1230 t->next_index = next0;
1231 t->session_index = ~0;
1234 s0 - sm->per_thread_data[thread_index].sessions;
1237 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1239 /* verify speculative enqueue, maybe switch current next frame */
1240 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1241 to_next, n_left_to_next,
1245 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1248 vlib_node_increment_counter (vm, snat_out2in_node.index,
1249 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1251 return frame->n_vectors;
1255 VLIB_REGISTER_NODE (snat_out2in_node) = {
1256 .function = snat_out2in_node_fn,
1257 .name = "nat44-out2in",
1258 .vector_size = sizeof (u32),
1259 .format_trace = format_snat_out2in_trace,
1260 .type = VLIB_NODE_TYPE_INTERNAL,
1262 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1263 .error_strings = snat_out2in_error_strings,
1265 .runtime_data_bytes = sizeof (snat_runtime_t),
1267 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1269 /* edit / add dispositions here */
1271 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1272 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1273 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1274 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1279 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
1282 nat44_out2in_reass_node_fn (vlib_main_t * vm,
1283 vlib_node_runtime_t * node, vlib_frame_t * frame)
1285 u32 n_left_from, *from, *to_next;
1286 snat_out2in_next_t next_index;
1287 u32 pkts_processed = 0;
1288 snat_main_t *sm = &snat_main;
1289 f64 now = vlib_time_now (vm);
1290 u32 thread_index = vm->thread_index;
1291 snat_main_per_thread_data_t *per_thread_data =
1292 &sm->per_thread_data[thread_index];
1293 u32 *fragments_to_drop = 0;
1294 u32 *fragments_to_loopback = 0;
1296 from = vlib_frame_vector_args (frame);
1297 n_left_from = frame->n_vectors;
1298 next_index = node->cached_next_index;
1300 while (n_left_from > 0)
1304 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1306 while (n_left_from > 0 && n_left_to_next > 0)
1308 u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1313 nat_reass_ip4_t *reass0;
1316 snat_session_key_t key0, sm0;
1317 clib_bihash_kv_8_8_t kv0, value0;
1318 snat_session_t *s0 = 0;
1319 u16 old_port0, new_port0;
1322 /* speculatively enqueue b0 to the current next frame */
1328 n_left_to_next -= 1;
1330 b0 = vlib_get_buffer (vm, bi0);
1331 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1333 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1335 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1338 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1340 next0 = SNAT_OUT2IN_NEXT_DROP;
1341 b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1345 ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1346 udp0 = ip4_next_header (ip0);
1347 tcp0 = (tcp_header_t *) udp0;
1348 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1350 reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1354 1, &fragments_to_drop);
1356 if (PREDICT_FALSE (!reass0))
1358 next0 = SNAT_OUT2IN_NEXT_DROP;
1359 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1360 nat_log_notice ("maximum reassemblies exceeded");
1364 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1366 key0.addr = ip0->dst_address;
1367 key0.port = udp0->dst_port;
1368 key0.protocol = proto0;
1369 key0.fib_index = rx_fib_index0;
1370 kv0.key = key0.as_u64;
1372 if (clib_bihash_search_8_8
1373 (&per_thread_data->out2in, &kv0, &value0))
1375 /* Try to match static mapping by external address and port,
1376 destination address and port in packet */
1377 if (snat_static_mapping_match
1378 (sm, key0, &sm0, 1, 0, 0, 0, 0))
1381 * Send DHCP packets to the ipv4 stack, or we won't
1382 * be able to use dhcp client on the outside interface
1384 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1387 clib_host_to_net_u16
1388 (UDP_DST_PORT_dhcp_to_client))))
1390 vnet_feature_next (&next0, b0);
1394 if (!sm->forwarding_enabled)
1397 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1398 next0 = SNAT_OUT2IN_NEXT_DROP;
1403 /* Create session initiated by host from external network */
1405 create_session_for_static_mapping (sm, b0, sm0, key0,
1411 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1412 next0 = SNAT_OUT2IN_NEXT_DROP;
1415 reass0->sess_index = s0 - per_thread_data->sessions;
1416 reass0->thread_index = thread_index;
1420 s0 = pool_elt_at_index (per_thread_data->sessions,
1422 reass0->sess_index = value0.value;
1424 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1428 if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1430 if (nat_ip4_reass_add_fragment
1431 (reass0, bi0, &fragments_to_drop))
1433 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1435 ("maximum fragments per reassembly exceeded");
1436 next0 = SNAT_OUT2IN_NEXT_DROP;
1442 s0 = pool_elt_at_index (per_thread_data->sessions,
1443 reass0->sess_index);
1446 old_addr0 = ip0->dst_address.as_u32;
1447 ip0->dst_address = s0->in2out.addr;
1448 new_addr0 = ip0->dst_address.as_u32;
1449 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1451 sum0 = ip0->checksum;
1452 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1454 dst_address /* changed member */ );
1455 ip0->checksum = ip_csum_fold (sum0);
1457 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1459 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1461 old_port0 = tcp0->dst_port;
1462 tcp0->dst_port = s0->in2out.port;
1463 new_port0 = tcp0->dst_port;
1465 sum0 = tcp0->checksum;
1466 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1468 dst_address /* changed member */ );
1470 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1471 ip4_header_t /* cheat */ ,
1472 length /* changed member */ );
1473 tcp0->checksum = ip_csum_fold (sum0);
1477 old_port0 = udp0->dst_port;
1478 udp0->dst_port = s0->in2out.port;
1484 nat44_session_update_counters (s0, now,
1485 vlib_buffer_length_in_chain (vm,
1487 /* Per-user LRU list maintenance */
1488 nat44_session_update_lru (sm, s0, thread_index);
1491 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1492 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1494 nat44_reass_trace_t *t =
1495 vlib_add_trace (vm, node, b0, sizeof (*t));
1496 t->cached = cached0;
1497 t->sw_if_index = sw_if_index0;
1498 t->next_index = next0;
1508 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1510 /* verify speculative enqueue, maybe switch current next frame */
1511 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1512 to_next, n_left_to_next,
1516 if (n_left_from == 0 && vec_len (fragments_to_loopback))
1518 from = vlib_frame_vector_args (frame);
1519 u32 len = vec_len (fragments_to_loopback);
1520 if (len <= VLIB_FRAME_SIZE)
1522 clib_memcpy (from, fragments_to_loopback,
1523 sizeof (u32) * len);
1525 vec_reset_length (fragments_to_loopback);
1530 fragments_to_loopback + (len -
1532 sizeof (u32) * VLIB_FRAME_SIZE);
1533 n_left_from = VLIB_FRAME_SIZE;
1534 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1539 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1542 vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1543 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1546 nat_send_all_to_node (vm, fragments_to_drop, node,
1547 &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1548 SNAT_OUT2IN_NEXT_DROP);
1550 vec_free (fragments_to_drop);
1551 vec_free (fragments_to_loopback);
1552 return frame->n_vectors;
1556 VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
1557 .function = nat44_out2in_reass_node_fn,
1558 .name = "nat44-out2in-reass",
1559 .vector_size = sizeof (u32),
1560 .format_trace = format_nat44_reass_trace,
1561 .type = VLIB_NODE_TYPE_INTERNAL,
1563 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1564 .error_strings = snat_out2in_error_strings,
1566 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1568 /* edit / add dispositions here */
1570 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1571 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1572 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1573 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1578 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
1579 nat44_out2in_reass_node_fn);
1582 snat_out2in_fast_node_fn (vlib_main_t * vm,
1583 vlib_node_runtime_t * node, vlib_frame_t * frame)
1585 u32 n_left_from, *from, *to_next;
1586 snat_out2in_next_t next_index;
1587 u32 pkts_processed = 0;
1588 snat_main_t *sm = &snat_main;
1590 from = vlib_frame_vector_args (frame);
1591 n_left_from = frame->n_vectors;
1592 next_index = node->cached_next_index;
1594 while (n_left_from > 0)
1598 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1600 while (n_left_from > 0 && n_left_to_next > 0)
1604 u32 next0 = SNAT_OUT2IN_NEXT_DROP;
1608 u32 new_addr0, old_addr0;
1609 u16 new_port0, old_port0;
1612 icmp46_header_t *icmp0;
1613 snat_session_key_t key0, sm0;
1617 /* speculatively enqueue b0 to the current next frame */
1623 n_left_to_next -= 1;
1625 b0 = vlib_get_buffer (vm, bi0);
1627 ip0 = vlib_buffer_get_current (b0);
1628 udp0 = ip4_next_header (ip0);
1629 tcp0 = (tcp_header_t *) udp0;
1630 icmp0 = (icmp46_header_t *) udp0;
1632 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1634 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1636 vnet_feature_next (&next0, b0);
1638 if (PREDICT_FALSE (ip0->ttl == 1))
1640 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1641 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1642 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1644 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1648 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1650 if (PREDICT_FALSE (proto0 == ~0))
1653 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1655 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0,
1656 rx_fib_index0, node, next0, ~0, 0, 0);
1660 key0.addr = ip0->dst_address;
1661 key0.port = udp0->dst_port;
1662 key0.fib_index = rx_fib_index0;
1664 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
1666 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1670 new_addr0 = sm0.addr.as_u32;
1671 new_port0 = sm0.port;
1672 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1673 old_addr0 = ip0->dst_address.as_u32;
1674 ip0->dst_address.as_u32 = new_addr0;
1676 sum0 = ip0->checksum;
1677 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1679 dst_address /* changed member */ );
1680 ip0->checksum = ip_csum_fold (sum0);
1682 if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1684 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1686 old_port0 = tcp0->dst_port;
1687 tcp0->dst_port = new_port0;
1689 sum0 = tcp0->checksum;
1690 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1692 dst_address /* changed member */ );
1694 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1695 ip4_header_t /* cheat */ ,
1696 length /* changed member */ );
1697 tcp0->checksum = ip_csum_fold (sum0);
1701 old_port0 = udp0->dst_port;
1702 udp0->dst_port = new_port0;
1708 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1710 sum0 = tcp0->checksum;
1711 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1713 dst_address /* changed member */ );
1715 tcp0->checksum = ip_csum_fold (sum0);
1721 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1722 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1724 snat_out2in_trace_t *t =
1725 vlib_add_trace (vm, node, b0, sizeof (*t));
1726 t->sw_if_index = sw_if_index0;
1727 t->next_index = next0;
1730 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1732 /* verify speculative enqueue, maybe switch current next frame */
1733 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1734 to_next, n_left_to_next,
1738 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1741 vlib_node_increment_counter (vm, snat_out2in_fast_node.index,
1742 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1744 return frame->n_vectors;
1748 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
1749 .function = snat_out2in_fast_node_fn,
1750 .name = "nat44-out2in-fast",
1751 .vector_size = sizeof (u32),
1752 .format_trace = format_snat_out2in_fast_trace,
1753 .type = VLIB_NODE_TYPE_INTERNAL,
1755 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1756 .error_strings = snat_out2in_error_strings,
1758 .runtime_data_bytes = sizeof (snat_runtime_t),
1760 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1762 /* edit / add dispositions here */
1764 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1765 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1766 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1767 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1772 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node,
1773 snat_out2in_fast_node_fn);
1776 * fd.io coding-style-patch-verification: ON
1779 * eval: (c-set-style "gnu")