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>
32 #include <nat/nat_syslog.h>
34 #include <vppinfra/hash.h>
35 #include <vppinfra/error.h>
36 #include <vppinfra/elog.h>
43 } snat_out2in_trace_t;
45 /* packet trace format function */
47 format_snat_out2in_trace (u8 * s, va_list * args)
49 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
50 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
51 snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
55 "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
56 t->sw_if_index, t->next_index, t->session_index);
61 format_snat_out2in_fast_trace (u8 * s, va_list * args)
63 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
64 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
65 snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
67 s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
68 t->sw_if_index, t->next_index);
72 vlib_node_registration_t snat_out2in_node;
73 vlib_node_registration_t snat_out2in_fast_node;
74 vlib_node_registration_t nat44_out2in_reass_node;
76 #define foreach_snat_out2in_error \
77 _(UNSUPPORTED_PROTOCOL, "unsupported protocol") \
78 _(OUT2IN_PACKETS, "good out2in packets processed") \
79 _(OUT_OF_PORTS, "out of ports") \
80 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
81 _(NO_TRANSLATION, "no translation") \
82 _(MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \
83 _(DROP_FRAGMENT, "drop fragment") \
84 _(MAX_REASS, "maximum reassemblies exceeded") \
85 _(MAX_FRAG, "maximum fragments per reassembly exceeded")\
86 _(TCP_PACKETS, "TCP packets") \
87 _(UDP_PACKETS, "UDP packets") \
88 _(ICMP_PACKETS, "ICMP packets") \
89 _(OTHER_PACKETS, "other protocol packets") \
90 _(FRAGMENTS, "fragments") \
91 _(CACHED_FRAGMENTS, "cached fragments") \
92 _(PROCESSED_FRAGMENTS, "processed fragments")
96 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
97 foreach_snat_out2in_error
100 } snat_out2in_error_t;
102 static char *snat_out2in_error_strings[] = {
103 #define _(sym,string) string,
104 foreach_snat_out2in_error
110 SNAT_OUT2IN_NEXT_DROP,
111 SNAT_OUT2IN_NEXT_LOOKUP,
112 SNAT_OUT2IN_NEXT_ICMP_ERROR,
113 SNAT_OUT2IN_NEXT_REASS,
115 } snat_out2in_next_t;
118 nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
120 snat_main_t *sm = &snat_main;
121 nat44_is_idle_session_ctx_t *ctx = arg;
123 u64 sess_timeout_time;
124 snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
126 clib_bihash_kv_8_8_t s_kv;
128 s = pool_elt_at_index (tsm->sessions, kv->value);
129 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
130 if (ctx->now >= sess_timeout_time)
132 s_kv.key = s->in2out.as_u64;
133 if (clib_bihash_add_del_8_8 (&tsm->in2out, &s_kv, 0))
134 nat_log_warn ("out2in key del failed");
136 snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
137 s->out2in.addr.as_u32,
141 s->in2out.fib_index);
143 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
144 &s->in2out.addr, s->in2out.port,
145 &s->out2in.addr, s->out2in.port,
148 if (!snat_is_session_static (s))
149 snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
152 nat44_delete_session (sm, s, ctx->thread_index);
160 * @brief Create session for static mapping.
162 * Create NAT session initiated by host from external network with static
165 * @param sm NAT main.
166 * @param b0 Vlib buffer.
167 * @param in2out In2out NAT44 session key.
168 * @param out2in Out2in NAT44 session key.
169 * @param node Vlib node.
171 * @returns SNAT session if successfully created otherwise 0.
173 static inline snat_session_t *
174 create_session_for_static_mapping (snat_main_t * sm,
176 snat_session_key_t in2out,
177 snat_session_key_t out2in,
178 vlib_node_runtime_t * node,
179 u32 thread_index, f64 now)
183 clib_bihash_kv_8_8_t kv0;
186 nat44_is_idle_session_ctx_t ctx0;
188 if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
190 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
191 nat_log_notice ("maximum sessions exceeded");
195 ip0 = vlib_buffer_get_current (b0);
196 udp0 = ip4_next_header (ip0);
199 nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index);
202 nat_log_warn ("create NAT user failed");
206 s = nat_session_alloc_or_recycle (sm, u, thread_index);
209 nat44_delete_user_with_no_session (sm, u, thread_index);
210 nat_log_warn ("create NAT session failed");
214 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
215 s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
216 s->ext_host_port = udp0->src_port;
217 user_session_increment (sm, u, 1 /* static */ );
220 s->in2out.protocol = out2in.protocol;
222 /* Add to translation hashes */
224 ctx0.thread_index = thread_index;
225 kv0.key = s->in2out.as_u64;
226 kv0.value = s - sm->per_thread_data[thread_index].sessions;
227 if (clib_bihash_add_or_overwrite_stale_8_8
228 (&sm->per_thread_data[thread_index].in2out, &kv0,
229 nat44_i2o_is_idle_session_cb, &ctx0))
230 nat_log_notice ("in2out key add failed");
232 kv0.key = s->out2in.as_u64;
234 if (clib_bihash_add_or_overwrite_stale_8_8
235 (&sm->per_thread_data[thread_index].out2in, &kv0,
236 nat44_o2i_is_idle_session_cb, &ctx0))
237 nat_log_notice ("out2in key add failed");
240 snat_ipfix_logging_nat44_ses_create (s->in2out.addr.as_u32,
241 s->out2in.addr.as_u32,
244 s->out2in.port, s->in2out.fib_index);
246 nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
247 &s->in2out.addr, s->in2out.port, &s->out2in.addr,
248 s->out2in.port, s->in2out.protocol);
254 snat_out2in_error_t icmp_get_key (ip4_header_t * ip0,
255 snat_session_key_t * p_key0)
257 icmp46_header_t *icmp0;
258 snat_session_key_t key0;
259 icmp_echo_header_t *echo0, *inner_echo0 = 0;
260 ip4_header_t *inner_ip0;
262 icmp46_header_t *inner_icmp0;
264 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
265 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
267 if (!icmp_is_error_message (icmp0))
269 key0.protocol = SNAT_PROTOCOL_ICMP;
270 key0.addr = ip0->dst_address;
271 key0.port = echo0->identifier;
275 inner_ip0 = (ip4_header_t *) (echo0 + 1);
276 l4_header = ip4_next_header (inner_ip0);
277 key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
278 key0.addr = inner_ip0->src_address;
279 switch (key0.protocol)
281 case SNAT_PROTOCOL_ICMP:
282 inner_icmp0 = (icmp46_header_t *) l4_header;
283 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
284 key0.port = inner_echo0->identifier;
286 case SNAT_PROTOCOL_UDP:
287 case SNAT_PROTOCOL_TCP:
288 key0.port = ((tcp_udp_header_t *) l4_header)->src_port;
291 return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
295 return -1; /* success */
299 * Get address and port values to be used for ICMP packet translation
300 * and create session if needed
302 * @param[in,out] sm NAT main
303 * @param[in,out] node NAT node runtime
304 * @param[in] thread_index thread index
305 * @param[in,out] b0 buffer containing packet to be translated
306 * @param[out] p_proto protocol used for matching
307 * @param[out] p_value address and port after NAT translation
308 * @param[out] p_dont_translate if packet should not be translated
309 * @param d optional parameter
310 * @param e optional parameter
313 icmp_match_out2in_slow (snat_main_t * sm, vlib_node_runtime_t * node,
314 u32 thread_index, vlib_buffer_t * b0,
315 ip4_header_t * ip0, u8 * p_proto,
316 snat_session_key_t * p_value,
317 u8 * p_dont_translate, void *d, void *e)
319 icmp46_header_t *icmp0;
322 snat_session_key_t key0;
323 snat_session_key_t sm0;
324 snat_session_t *s0 = 0;
325 u8 dont_translate = 0;
326 clib_bihash_kv_8_8_t kv0, value0;
332 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
333 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
334 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
338 err = icmp_get_key (ip0, &key0);
341 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
342 next0 = SNAT_OUT2IN_NEXT_DROP;
345 key0.fib_index = rx_fib_index0;
347 kv0.key = key0.as_u64;
349 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
352 /* Try to match static mapping by external address and port,
353 destination address and port in packet */
354 if (snat_static_mapping_match
355 (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, &identity_nat))
357 if (!sm->forwarding_enabled)
359 /* Don't NAT packet aimed at the intfc address */
360 if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index0,
361 ip0->dst_address.as_u32)))
366 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
367 next0 = SNAT_OUT2IN_NEXT_DROP;
377 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
378 (icmp0->type != ICMP4_echo_request
381 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
382 next0 = SNAT_OUT2IN_NEXT_DROP;
386 if (PREDICT_FALSE (identity_nat))
391 /* Create session initiated by host from external network */
392 s0 = create_session_for_static_mapping (sm, b0, sm0, key0,
394 vlib_time_now (sm->vlib_main));
398 next0 = SNAT_OUT2IN_NEXT_DROP;
404 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
405 icmp0->type != ICMP4_echo_request &&
406 !icmp_is_error_message (icmp0)))
408 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
409 next0 = SNAT_OUT2IN_NEXT_DROP;
413 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
418 *p_proto = key0.protocol;
420 *p_value = s0->in2out;
421 *p_dont_translate = dont_translate;
423 *(snat_session_t **) d = s0;
428 * Get address and port values to be used for ICMP packet translation
430 * @param[in] sm NAT main
431 * @param[in,out] node NAT node runtime
432 * @param[in] thread_index thread index
433 * @param[in,out] b0 buffer containing packet to be translated
434 * @param[out] p_proto protocol used for matching
435 * @param[out] p_value address and port after NAT translation
436 * @param[out] p_dont_translate if packet should not be translated
437 * @param d optional parameter
438 * @param e optional parameter
441 icmp_match_out2in_fast (snat_main_t * sm, vlib_node_runtime_t * node,
442 u32 thread_index, vlib_buffer_t * b0,
443 ip4_header_t * ip0, u8 * p_proto,
444 snat_session_key_t * p_value,
445 u8 * p_dont_translate, void *d, void *e)
447 icmp46_header_t *icmp0;
450 snat_session_key_t key0;
451 snat_session_key_t sm0;
452 u8 dont_translate = 0;
457 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
458 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
459 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
461 err = icmp_get_key (ip0, &key0);
464 b0->error = node->errors[err];
465 next0 = SNAT_OUT2IN_NEXT_DROP;
468 key0.fib_index = rx_fib_index0;
470 if (snat_static_mapping_match
471 (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, 0))
473 /* Don't NAT packet aimed at the intfc address */
474 if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))
479 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
480 next0 = SNAT_OUT2IN_NEXT_DROP;
484 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
485 (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
486 !icmp_is_error_message (icmp0)))
488 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
489 next0 = SNAT_OUT2IN_NEXT_DROP;
496 *p_proto = key0.protocol;
497 *p_dont_translate = dont_translate;
502 icmp_out2in (snat_main_t * sm,
505 icmp46_header_t * icmp0,
508 vlib_node_runtime_t * node,
509 u32 next0, u32 thread_index, void *d, void *e)
511 snat_session_key_t sm0;
513 icmp_echo_header_t *echo0, *inner_echo0 = 0;
514 ip4_header_t *inner_ip0 = 0;
516 icmp46_header_t *inner_icmp0;
518 u32 new_addr0, old_addr0;
519 u16 old_id0, new_id0;
524 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
526 next0_tmp = sm->icmp_match_out2in_cb (sm, node, thread_index, b0, ip0,
527 &protocol, &sm0, &dont_translate, d,
531 if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
534 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
536 sum0 = ip_incremental_checksum_buffer (sm->vlib_main, b0, (u8 *) icmp0 -
538 vlib_buffer_get_current (b0),
539 ntohs (ip0->length) -
540 ip4_header_bytes (ip0), 0);
541 checksum0 = ~ip_csum_fold (sum0);
542 if (checksum0 != 0 && checksum0 != 0xffff)
544 next0 = SNAT_OUT2IN_NEXT_DROP;
549 old_addr0 = ip0->dst_address.as_u32;
550 new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
551 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
553 sum0 = ip0->checksum;
554 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
555 dst_address /* changed member */ );
556 ip0->checksum = ip_csum_fold (sum0);
558 if (icmp0->checksum == 0)
559 icmp0->checksum = 0xffff;
561 if (!icmp_is_error_message (icmp0))
564 if (PREDICT_FALSE (new_id0 != echo0->identifier))
566 old_id0 = echo0->identifier;
568 echo0->identifier = new_id0;
570 sum0 = icmp0->checksum;
571 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
572 identifier /* changed member */ );
573 icmp0->checksum = ip_csum_fold (sum0);
578 inner_ip0 = (ip4_header_t *) (echo0 + 1);
579 l4_header = ip4_next_header (inner_ip0);
581 if (!ip4_header_checksum_is_valid (inner_ip0))
583 next0 = SNAT_OUT2IN_NEXT_DROP;
587 old_addr0 = inner_ip0->src_address.as_u32;
588 inner_ip0->src_address = sm0.addr;
589 new_addr0 = inner_ip0->src_address.as_u32;
591 sum0 = icmp0->checksum;
592 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
593 src_address /* changed member */ );
594 icmp0->checksum = ip_csum_fold (sum0);
598 case SNAT_PROTOCOL_ICMP:
599 inner_icmp0 = (icmp46_header_t *) l4_header;
600 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
602 old_id0 = inner_echo0->identifier;
604 inner_echo0->identifier = new_id0;
606 sum0 = icmp0->checksum;
607 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
609 icmp0->checksum = ip_csum_fold (sum0);
611 case SNAT_PROTOCOL_UDP:
612 case SNAT_PROTOCOL_TCP:
613 old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
615 ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
617 sum0 = icmp0->checksum;
618 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
620 icmp0->checksum = ip_csum_fold (sum0);
633 icmp_out2in_slow_path (snat_main_t * sm,
636 icmp46_header_t * icmp0,
639 vlib_node_runtime_t * node,
641 u32 thread_index, snat_session_t ** p_s0)
643 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
644 next0, thread_index, p_s0, 0);
645 snat_session_t *s0 = *p_s0;
646 if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP && s0))
649 nat44_session_update_counters (s0, now,
650 vlib_buffer_length_in_chain
651 (sm->vlib_main, b0));
652 /* Per-user LRU list maintenance */
653 nat44_session_update_lru (sm, s0, thread_index);
659 nat_out2in_sm_unknown_proto (snat_main_t * sm,
661 ip4_header_t * ip, u32 rx_fib_index)
663 clib_bihash_kv_8_8_t kv, value;
664 snat_static_mapping_t *m;
665 snat_session_key_t m_key;
666 u32 old_addr, new_addr;
669 m_key.addr = ip->dst_address;
673 kv.key = m_key.as_u64;
674 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
677 m = pool_elt_at_index (sm->static_mappings, value.value);
679 old_addr = ip->dst_address.as_u32;
680 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
682 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
683 ip->checksum = ip_csum_fold (sum);
685 vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
690 snat_out2in_node_fn (vlib_main_t * vm,
691 vlib_node_runtime_t * node, vlib_frame_t * frame)
693 u32 n_left_from, *from, *to_next;
694 snat_out2in_next_t next_index;
695 u32 pkts_processed = 0;
696 snat_main_t *sm = &snat_main;
697 f64 now = vlib_time_now (vm);
698 u32 thread_index = vm->thread_index;
699 u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
702 from = vlib_frame_vector_args (frame);
703 n_left_from = frame->n_vectors;
704 next_index = node->cached_next_index;
706 while (n_left_from > 0)
710 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
712 while (n_left_from >= 4 && n_left_to_next >= 2)
715 vlib_buffer_t *b0, *b1;
716 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
717 u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
718 u32 sw_if_index0, sw_if_index1;
719 ip4_header_t *ip0, *ip1;
720 ip_csum_t sum0, sum1;
721 u32 new_addr0, old_addr0;
722 u16 new_port0, old_port0;
723 u32 new_addr1, old_addr1;
724 u16 new_port1, old_port1;
725 udp_header_t *udp0, *udp1;
726 tcp_header_t *tcp0, *tcp1;
727 icmp46_header_t *icmp0, *icmp1;
728 snat_session_key_t key0, key1, sm0, sm1;
729 u32 rx_fib_index0, rx_fib_index1;
731 snat_session_t *s0 = 0, *s1 = 0;
732 clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
733 u8 identity_nat0, identity_nat1;
735 /* Prefetch next iteration. */
737 vlib_buffer_t *p2, *p3;
739 p2 = vlib_get_buffer (vm, from[2]);
740 p3 = vlib_get_buffer (vm, from[3]);
742 vlib_prefetch_buffer_header (p2, LOAD);
743 vlib_prefetch_buffer_header (p3, LOAD);
745 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
746 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
749 /* speculatively enqueue b0 and b1 to the current next frame */
750 to_next[0] = bi0 = from[0];
751 to_next[1] = bi1 = from[1];
757 b0 = vlib_get_buffer (vm, bi0);
758 b1 = vlib_get_buffer (vm, bi1);
760 vnet_buffer (b0)->snat.flags = 0;
761 vnet_buffer (b1)->snat.flags = 0;
763 ip0 = vlib_buffer_get_current (b0);
764 udp0 = ip4_next_header (ip0);
765 tcp0 = (tcp_header_t *) udp0;
766 icmp0 = (icmp46_header_t *) udp0;
768 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
769 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
772 if (PREDICT_FALSE (ip0->ttl == 1))
774 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
775 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
776 ICMP4_time_exceeded_ttl_exceeded_in_transit,
778 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
782 proto0 = ip_proto_to_snat_proto (ip0->protocol);
784 if (PREDICT_FALSE (proto0 == ~0))
786 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
788 if (!sm->forwarding_enabled)
791 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
792 next0 = SNAT_OUT2IN_NEXT_DROP;
799 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
801 next0 = SNAT_OUT2IN_NEXT_REASS;
806 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
808 next0 = icmp_out2in_slow_path
809 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
810 next0, now, thread_index, &s0);
815 key0.addr = ip0->dst_address;
816 key0.port = udp0->dst_port;
817 key0.protocol = proto0;
818 key0.fib_index = rx_fib_index0;
820 kv0.key = key0.as_u64;
822 if (clib_bihash_search_8_8
823 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
825 /* Try to match static mapping by external address and port,
826 destination address and port in packet */
827 if (snat_static_mapping_match
828 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
831 * Send DHCP packets to the ipv4 stack, or we won't
832 * be able to use dhcp client on the outside interface
834 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
835 && (udp0->dst_port ==
837 (UDP_DST_PORT_dhcp_to_client))))
839 vnet_feature_next (&next0, b0);
843 if (!sm->forwarding_enabled)
846 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
847 next0 = SNAT_OUT2IN_NEXT_DROP;
852 if (PREDICT_FALSE (identity_nat0))
855 /* Create session initiated by host from external network */
856 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
860 next0 = SNAT_OUT2IN_NEXT_DROP;
866 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
869 old_addr0 = ip0->dst_address.as_u32;
870 ip0->dst_address = s0->in2out.addr;
871 new_addr0 = ip0->dst_address.as_u32;
872 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
874 sum0 = ip0->checksum;
875 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
877 dst_address /* changed member */ );
878 ip0->checksum = ip_csum_fold (sum0);
880 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
882 old_port0 = tcp0->dst_port;
883 tcp0->dst_port = s0->in2out.port;
884 new_port0 = tcp0->dst_port;
886 sum0 = tcp0->checksum;
887 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
889 dst_address /* changed member */ );
891 sum0 = ip_csum_update (sum0, old_port0, new_port0,
892 ip4_header_t /* cheat */ ,
893 length /* changed member */ );
894 tcp0->checksum = ip_csum_fold (sum0);
899 old_port0 = udp0->dst_port;
900 udp0->dst_port = s0->in2out.port;
906 nat44_session_update_counters (s0, now,
907 vlib_buffer_length_in_chain (vm,
909 /* Per-user LRU list maintenance */
910 nat44_session_update_lru (sm, s0, thread_index);
913 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
914 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
916 snat_out2in_trace_t *t =
917 vlib_add_trace (vm, node, b0, sizeof (*t));
918 t->sw_if_index = sw_if_index0;
919 t->next_index = next0;
920 t->session_index = ~0;
923 s0 - sm->per_thread_data[thread_index].sessions;
926 pkts_processed += next0 == SNAT_OUT2IN_NEXT_LOOKUP;
929 ip1 = vlib_buffer_get_current (b1);
930 udp1 = ip4_next_header (ip1);
931 tcp1 = (tcp_header_t *) udp1;
932 icmp1 = (icmp46_header_t *) udp1;
934 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
935 rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
938 if (PREDICT_FALSE (ip1->ttl == 1))
940 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
941 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
942 ICMP4_time_exceeded_ttl_exceeded_in_transit,
944 next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
948 proto1 = ip_proto_to_snat_proto (ip1->protocol);
950 if (PREDICT_FALSE (proto1 == ~0))
952 if (nat_out2in_sm_unknown_proto (sm, b1, ip1, rx_fib_index1))
954 if (!sm->forwarding_enabled)
957 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
958 next1 = SNAT_OUT2IN_NEXT_DROP;
965 if (PREDICT_FALSE (ip4_is_fragment (ip1)))
967 next1 = SNAT_OUT2IN_NEXT_REASS;
972 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
974 next1 = icmp_out2in_slow_path
975 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
976 next1, now, thread_index, &s1);
981 key1.addr = ip1->dst_address;
982 key1.port = udp1->dst_port;
983 key1.protocol = proto1;
984 key1.fib_index = rx_fib_index1;
986 kv1.key = key1.as_u64;
988 if (clib_bihash_search_8_8
989 (&sm->per_thread_data[thread_index].out2in, &kv1, &value1))
991 /* Try to match static mapping by external address and port,
992 destination address and port in packet */
993 if (snat_static_mapping_match
994 (sm, key1, &sm1, 1, 0, 0, 0, 0, &identity_nat1))
997 * Send DHCP packets to the ipv4 stack, or we won't
998 * be able to use dhcp client on the outside interface
1000 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
1001 && (udp1->dst_port ==
1002 clib_host_to_net_u16
1003 (UDP_DST_PORT_dhcp_to_client))))
1005 vnet_feature_next (&next1, b1);
1009 if (!sm->forwarding_enabled)
1012 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1013 next1 = SNAT_OUT2IN_NEXT_DROP;
1018 if (PREDICT_FALSE (identity_nat1))
1021 /* Create session initiated by host from external network */
1022 s1 = create_session_for_static_mapping (sm, b1, sm1, key1, node,
1026 next1 = SNAT_OUT2IN_NEXT_DROP;
1032 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1035 old_addr1 = ip1->dst_address.as_u32;
1036 ip1->dst_address = s1->in2out.addr;
1037 new_addr1 = ip1->dst_address.as_u32;
1038 vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1040 sum1 = ip1->checksum;
1041 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1043 dst_address /* changed member */ );
1044 ip1->checksum = ip_csum_fold (sum1);
1046 if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1048 old_port1 = tcp1->dst_port;
1049 tcp1->dst_port = s1->in2out.port;
1050 new_port1 = tcp1->dst_port;
1052 sum1 = tcp1->checksum;
1053 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1055 dst_address /* changed member */ );
1057 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1058 ip4_header_t /* cheat */ ,
1059 length /* changed member */ );
1060 tcp1->checksum = ip_csum_fold (sum1);
1065 old_port1 = udp1->dst_port;
1066 udp1->dst_port = s1->in2out.port;
1072 nat44_session_update_counters (s1, now,
1073 vlib_buffer_length_in_chain (vm,
1075 /* Per-user LRU list maintenance */
1076 nat44_session_update_lru (sm, s1, thread_index);
1079 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1080 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1082 snat_out2in_trace_t *t =
1083 vlib_add_trace (vm, node, b1, sizeof (*t));
1084 t->sw_if_index = sw_if_index1;
1085 t->next_index = next1;
1086 t->session_index = ~0;
1089 s1 - sm->per_thread_data[thread_index].sessions;
1092 pkts_processed += next1 == SNAT_OUT2IN_NEXT_LOOKUP;
1094 /* verify speculative enqueues, maybe switch current next frame */
1095 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1096 to_next, n_left_to_next,
1097 bi0, bi1, next0, next1);
1100 while (n_left_from > 0 && n_left_to_next > 0)
1104 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1108 u32 new_addr0, old_addr0;
1109 u16 new_port0, old_port0;
1112 icmp46_header_t *icmp0;
1113 snat_session_key_t key0, sm0;
1116 snat_session_t *s0 = 0;
1117 clib_bihash_kv_8_8_t kv0, value0;
1120 /* speculatively enqueue b0 to the current next frame */
1126 n_left_to_next -= 1;
1128 b0 = vlib_get_buffer (vm, bi0);
1130 vnet_buffer (b0)->snat.flags = 0;
1132 ip0 = vlib_buffer_get_current (b0);
1133 udp0 = ip4_next_header (ip0);
1134 tcp0 = (tcp_header_t *) udp0;
1135 icmp0 = (icmp46_header_t *) udp0;
1137 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1138 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1141 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1143 if (PREDICT_FALSE (proto0 == ~0))
1145 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
1147 if (!sm->forwarding_enabled)
1150 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1151 next0 = SNAT_OUT2IN_NEXT_DROP;
1158 if (PREDICT_FALSE (ip0->ttl == 1))
1160 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1161 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1162 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1164 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1168 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1170 next0 = SNAT_OUT2IN_NEXT_REASS;
1175 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1177 next0 = icmp_out2in_slow_path
1178 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1179 next0, now, thread_index, &s0);
1184 key0.addr = ip0->dst_address;
1185 key0.port = udp0->dst_port;
1186 key0.protocol = proto0;
1187 key0.fib_index = rx_fib_index0;
1189 kv0.key = key0.as_u64;
1191 if (clib_bihash_search_8_8
1192 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
1194 /* Try to match static mapping by external address and port,
1195 destination address and port in packet */
1196 if (snat_static_mapping_match
1197 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
1200 * Send DHCP packets to the ipv4 stack, or we won't
1201 * be able to use dhcp client on the outside interface
1203 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1204 && (udp0->dst_port ==
1205 clib_host_to_net_u16
1206 (UDP_DST_PORT_dhcp_to_client))))
1208 vnet_feature_next (&next0, b0);
1212 if (!sm->forwarding_enabled)
1215 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1216 next0 = SNAT_OUT2IN_NEXT_DROP;
1221 if (PREDICT_FALSE (identity_nat0))
1224 /* Create session initiated by host from external network */
1225 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
1229 next0 = SNAT_OUT2IN_NEXT_DROP;
1235 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1238 old_addr0 = ip0->dst_address.as_u32;
1239 ip0->dst_address = s0->in2out.addr;
1240 new_addr0 = ip0->dst_address.as_u32;
1241 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1243 sum0 = ip0->checksum;
1244 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1246 dst_address /* changed member */ );
1247 ip0->checksum = ip_csum_fold (sum0);
1249 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1251 old_port0 = tcp0->dst_port;
1252 tcp0->dst_port = s0->in2out.port;
1253 new_port0 = tcp0->dst_port;
1255 sum0 = tcp0->checksum;
1256 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1258 dst_address /* changed member */ );
1260 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1261 ip4_header_t /* cheat */ ,
1262 length /* changed member */ );
1263 tcp0->checksum = ip_csum_fold (sum0);
1268 old_port0 = udp0->dst_port;
1269 udp0->dst_port = s0->in2out.port;
1275 nat44_session_update_counters (s0, now,
1276 vlib_buffer_length_in_chain (vm,
1278 /* Per-user LRU list maintenance */
1279 nat44_session_update_lru (sm, s0, thread_index);
1282 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1283 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1285 snat_out2in_trace_t *t =
1286 vlib_add_trace (vm, node, b0, sizeof (*t));
1287 t->sw_if_index = sw_if_index0;
1288 t->next_index = next0;
1289 t->session_index = ~0;
1292 s0 - sm->per_thread_data[thread_index].sessions;
1295 pkts_processed += next0 == SNAT_OUT2IN_NEXT_LOOKUP;
1297 /* verify speculative enqueue, maybe switch current next frame */
1298 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1299 to_next, n_left_to_next,
1303 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1306 vlib_node_increment_counter (vm, snat_out2in_node.index,
1307 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1309 vlib_node_increment_counter (vm, snat_out2in_node.index,
1310 SNAT_OUT2IN_ERROR_TCP_PACKETS, tcp_packets);
1311 vlib_node_increment_counter (vm, snat_out2in_node.index,
1312 SNAT_OUT2IN_ERROR_UDP_PACKETS, udp_packets);
1313 vlib_node_increment_counter (vm, snat_out2in_node.index,
1314 SNAT_OUT2IN_ERROR_ICMP_PACKETS, icmp_packets);
1315 vlib_node_increment_counter (vm, snat_out2in_node.index,
1316 SNAT_OUT2IN_ERROR_OTHER_PACKETS,
1318 vlib_node_increment_counter (vm, snat_out2in_node.index,
1319 SNAT_OUT2IN_ERROR_FRAGMENTS, fragments);
1321 return frame->n_vectors;
1325 VLIB_REGISTER_NODE (snat_out2in_node) = {
1326 .function = snat_out2in_node_fn,
1327 .name = "nat44-out2in",
1328 .vector_size = sizeof (u32),
1329 .format_trace = format_snat_out2in_trace,
1330 .type = VLIB_NODE_TYPE_INTERNAL,
1332 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1333 .error_strings = snat_out2in_error_strings,
1335 .runtime_data_bytes = sizeof (snat_runtime_t),
1337 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1339 /* edit / add dispositions here */
1341 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1342 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1343 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1344 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1349 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
1352 nat44_out2in_reass_node_fn (vlib_main_t * vm,
1353 vlib_node_runtime_t * node, vlib_frame_t * frame)
1355 u32 n_left_from, *from, *to_next;
1356 snat_out2in_next_t next_index;
1357 u32 pkts_processed = 0, cached_fragments = 0;
1358 snat_main_t *sm = &snat_main;
1359 f64 now = vlib_time_now (vm);
1360 u32 thread_index = vm->thread_index;
1361 snat_main_per_thread_data_t *per_thread_data =
1362 &sm->per_thread_data[thread_index];
1363 u32 *fragments_to_drop = 0;
1364 u32 *fragments_to_loopback = 0;
1366 from = vlib_frame_vector_args (frame);
1367 n_left_from = frame->n_vectors;
1368 next_index = node->cached_next_index;
1370 while (n_left_from > 0)
1374 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1376 while (n_left_from > 0 && n_left_to_next > 0)
1378 u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1383 nat_reass_ip4_t *reass0;
1386 icmp46_header_t *icmp0;
1387 snat_session_key_t key0, sm0;
1388 clib_bihash_kv_8_8_t kv0, value0;
1389 snat_session_t *s0 = 0;
1390 u16 old_port0, new_port0;
1394 /* speculatively enqueue b0 to the current next frame */
1400 n_left_to_next -= 1;
1402 b0 = vlib_get_buffer (vm, bi0);
1403 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1405 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1407 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1410 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1412 next0 = SNAT_OUT2IN_NEXT_DROP;
1413 b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1417 ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1418 udp0 = ip4_next_header (ip0);
1419 tcp0 = (tcp_header_t *) udp0;
1420 icmp0 = (icmp46_header_t *) udp0;
1421 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1423 reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1427 1, &fragments_to_drop);
1429 if (PREDICT_FALSE (!reass0))
1431 next0 = SNAT_OUT2IN_NEXT_DROP;
1432 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1433 nat_log_notice ("maximum reassemblies exceeded");
1437 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1439 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1441 next0 = icmp_out2in_slow_path
1442 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1443 next0, now, thread_index, &s0);
1445 if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP))
1448 reass0->sess_index = s0 - per_thread_data->sessions;
1450 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1451 reass0->thread_index = thread_index;
1452 nat_ip4_reass_get_frags (reass0,
1453 &fragments_to_loopback);
1459 key0.addr = ip0->dst_address;
1460 key0.port = udp0->dst_port;
1461 key0.protocol = proto0;
1462 key0.fib_index = rx_fib_index0;
1463 kv0.key = key0.as_u64;
1465 if (clib_bihash_search_8_8
1466 (&per_thread_data->out2in, &kv0, &value0))
1468 /* Try to match static mapping by external address and port,
1469 destination address and port in packet */
1470 if (snat_static_mapping_match
1471 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
1474 * Send DHCP packets to the ipv4 stack, or we won't
1475 * be able to use dhcp client on the outside interface
1477 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1480 clib_host_to_net_u16
1481 (UDP_DST_PORT_dhcp_to_client))))
1483 vnet_feature_next (&next0, b0);
1487 if (!sm->forwarding_enabled)
1490 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1491 next0 = SNAT_OUT2IN_NEXT_DROP;
1495 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1496 nat_ip4_reass_get_frags (reass0,
1497 &fragments_to_loopback);
1502 if (PREDICT_FALSE (identity_nat0))
1505 /* Create session initiated by host from external network */
1507 create_session_for_static_mapping (sm, b0, sm0, key0,
1513 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1514 next0 = SNAT_OUT2IN_NEXT_DROP;
1517 reass0->sess_index = s0 - per_thread_data->sessions;
1518 reass0->thread_index = thread_index;
1522 s0 = pool_elt_at_index (per_thread_data->sessions,
1524 reass0->sess_index = value0.value;
1526 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1530 if (reass0->flags & NAT_REASS_FLAG_ED_DONT_TRANSLATE)
1532 if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1534 if (nat_ip4_reass_add_fragment
1535 (reass0, bi0, &fragments_to_drop))
1537 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1539 ("maximum fragments per reassembly exceeded");
1540 next0 = SNAT_OUT2IN_NEXT_DROP;
1546 s0 = pool_elt_at_index (per_thread_data->sessions,
1547 reass0->sess_index);
1550 old_addr0 = ip0->dst_address.as_u32;
1551 ip0->dst_address = s0->in2out.addr;
1552 new_addr0 = ip0->dst_address.as_u32;
1553 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1555 sum0 = ip0->checksum;
1556 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1558 dst_address /* changed member */ );
1559 ip0->checksum = ip_csum_fold (sum0);
1561 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1563 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1565 old_port0 = tcp0->dst_port;
1566 tcp0->dst_port = s0->in2out.port;
1567 new_port0 = tcp0->dst_port;
1569 sum0 = tcp0->checksum;
1570 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1572 dst_address /* changed member */ );
1574 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1575 ip4_header_t /* cheat */ ,
1576 length /* changed member */ );
1577 tcp0->checksum = ip_csum_fold (sum0);
1581 old_port0 = udp0->dst_port;
1582 udp0->dst_port = s0->in2out.port;
1588 nat44_session_update_counters (s0, now,
1589 vlib_buffer_length_in_chain (vm,
1591 /* Per-user LRU list maintenance */
1592 nat44_session_update_lru (sm, s0, thread_index);
1595 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1596 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1598 nat44_reass_trace_t *t =
1599 vlib_add_trace (vm, node, b0, sizeof (*t));
1600 t->cached = cached0;
1601 t->sw_if_index = sw_if_index0;
1602 t->next_index = next0;
1613 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1615 /* verify speculative enqueue, maybe switch current next frame */
1616 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1617 to_next, n_left_to_next,
1621 if (n_left_from == 0 && vec_len (fragments_to_loopback))
1623 from = vlib_frame_vector_args (frame);
1624 u32 len = vec_len (fragments_to_loopback);
1625 if (len <= VLIB_FRAME_SIZE)
1627 clib_memcpy_fast (from, fragments_to_loopback,
1628 sizeof (u32) * len);
1630 vec_reset_length (fragments_to_loopback);
1634 clib_memcpy_fast (from, fragments_to_loopback +
1635 (len - VLIB_FRAME_SIZE),
1636 sizeof (u32) * VLIB_FRAME_SIZE);
1637 n_left_from = VLIB_FRAME_SIZE;
1638 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1643 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1646 vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1647 SNAT_OUT2IN_ERROR_PROCESSED_FRAGMENTS,
1649 vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1650 SNAT_OUT2IN_ERROR_CACHED_FRAGMENTS,
1653 nat_send_all_to_node (vm, fragments_to_drop, node,
1654 &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1655 SNAT_OUT2IN_NEXT_DROP);
1657 vec_free (fragments_to_drop);
1658 vec_free (fragments_to_loopback);
1659 return frame->n_vectors;
1663 VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
1664 .function = nat44_out2in_reass_node_fn,
1665 .name = "nat44-out2in-reass",
1666 .vector_size = sizeof (u32),
1667 .format_trace = format_nat44_reass_trace,
1668 .type = VLIB_NODE_TYPE_INTERNAL,
1670 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1671 .error_strings = snat_out2in_error_strings,
1673 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1675 /* edit / add dispositions here */
1677 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1678 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1679 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1680 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1685 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
1686 nat44_out2in_reass_node_fn);
1689 snat_out2in_fast_node_fn (vlib_main_t * vm,
1690 vlib_node_runtime_t * node, vlib_frame_t * frame)
1692 u32 n_left_from, *from, *to_next;
1693 snat_out2in_next_t next_index;
1694 u32 pkts_processed = 0;
1695 snat_main_t *sm = &snat_main;
1697 from = vlib_frame_vector_args (frame);
1698 n_left_from = frame->n_vectors;
1699 next_index = node->cached_next_index;
1701 while (n_left_from > 0)
1705 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1707 while (n_left_from > 0 && n_left_to_next > 0)
1711 u32 next0 = SNAT_OUT2IN_NEXT_DROP;
1715 u32 new_addr0, old_addr0;
1716 u16 new_port0, old_port0;
1719 icmp46_header_t *icmp0;
1720 snat_session_key_t key0, sm0;
1724 /* speculatively enqueue b0 to the current next frame */
1730 n_left_to_next -= 1;
1732 b0 = vlib_get_buffer (vm, bi0);
1734 ip0 = vlib_buffer_get_current (b0);
1735 udp0 = ip4_next_header (ip0);
1736 tcp0 = (tcp_header_t *) udp0;
1737 icmp0 = (icmp46_header_t *) udp0;
1739 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1741 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1743 vnet_feature_next (&next0, b0);
1745 if (PREDICT_FALSE (ip0->ttl == 1))
1747 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1748 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1749 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1751 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1755 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1757 if (PREDICT_FALSE (proto0 == ~0))
1760 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1762 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0,
1763 rx_fib_index0, node, next0, ~0, 0, 0);
1767 key0.addr = ip0->dst_address;
1768 key0.port = udp0->dst_port;
1769 key0.fib_index = rx_fib_index0;
1771 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
1773 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1777 new_addr0 = sm0.addr.as_u32;
1778 new_port0 = sm0.port;
1779 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1780 old_addr0 = ip0->dst_address.as_u32;
1781 ip0->dst_address.as_u32 = new_addr0;
1783 sum0 = ip0->checksum;
1784 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1786 dst_address /* changed member */ );
1787 ip0->checksum = ip_csum_fold (sum0);
1789 if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1791 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1793 old_port0 = tcp0->dst_port;
1794 tcp0->dst_port = new_port0;
1796 sum0 = tcp0->checksum;
1797 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1799 dst_address /* changed member */ );
1801 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1802 ip4_header_t /* cheat */ ,
1803 length /* changed member */ );
1804 tcp0->checksum = ip_csum_fold (sum0);
1808 old_port0 = udp0->dst_port;
1809 udp0->dst_port = new_port0;
1815 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1817 sum0 = tcp0->checksum;
1818 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1820 dst_address /* changed member */ );
1822 tcp0->checksum = ip_csum_fold (sum0);
1828 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1829 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1831 snat_out2in_trace_t *t =
1832 vlib_add_trace (vm, node, b0, sizeof (*t));
1833 t->sw_if_index = sw_if_index0;
1834 t->next_index = next0;
1837 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1839 /* verify speculative enqueue, maybe switch current next frame */
1840 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1841 to_next, n_left_to_next,
1845 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1848 vlib_node_increment_counter (vm, snat_out2in_fast_node.index,
1849 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1851 return frame->n_vectors;
1855 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
1856 .function = snat_out2in_fast_node_fn,
1857 .name = "nat44-out2in-fast",
1858 .vector_size = sizeof (u32),
1859 .format_trace = format_snat_out2in_fast_trace,
1860 .type = VLIB_NODE_TYPE_INTERNAL,
1862 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1863 .error_strings = snat_out2in_error_strings,
1865 .runtime_data_bytes = sizeof (snat_runtime_t),
1867 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1869 /* edit / add dispositions here */
1871 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1872 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1873 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1874 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1879 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node,
1880 snat_out2in_fast_node_fn);
1883 * fd.io coding-style-patch-verification: ON
1886 * eval: (c-set-style "gnu")