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;
314 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
315 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
316 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
320 err = icmp_get_key (ip0, &key0);
323 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
324 next0 = SNAT_OUT2IN_NEXT_DROP;
327 key0.fib_index = rx_fib_index0;
329 kv0.key = key0.as_u64;
331 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
334 /* Try to match static mapping by external address and port,
335 destination address and port in packet */
336 if (snat_static_mapping_match
337 (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, &identity_nat))
339 if (!sm->forwarding_enabled)
341 /* Don't NAT packet aimed at the intfc address */
342 if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index0,
343 ip0->dst_address.as_u32)))
348 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
349 next0 = SNAT_OUT2IN_NEXT_DROP;
359 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
360 (icmp0->type != ICMP4_echo_request
363 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
364 next0 = SNAT_OUT2IN_NEXT_DROP;
368 if (PREDICT_FALSE (identity_nat))
373 /* Create session initiated by host from external network */
374 s0 = create_session_for_static_mapping (sm, b0, sm0, key0,
376 vlib_time_now (sm->vlib_main));
380 next0 = SNAT_OUT2IN_NEXT_DROP;
386 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
387 icmp0->type != ICMP4_echo_request &&
388 !icmp_is_error_message (icmp0)))
390 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
391 next0 = SNAT_OUT2IN_NEXT_DROP;
395 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
400 *p_proto = key0.protocol;
402 *p_value = s0->in2out;
403 *p_dont_translate = dont_translate;
405 *(snat_session_t **) d = s0;
410 * Get address and port values to be used for ICMP packet translation
412 * @param[in] sm NAT main
413 * @param[in,out] node NAT node runtime
414 * @param[in] thread_index thread index
415 * @param[in,out] b0 buffer containing packet to be translated
416 * @param[out] p_proto protocol used for matching
417 * @param[out] p_value address and port after NAT translation
418 * @param[out] p_dont_translate if packet should not be translated
419 * @param d optional parameter
420 * @param e optional parameter
423 icmp_match_out2in_fast (snat_main_t * sm, vlib_node_runtime_t * node,
424 u32 thread_index, vlib_buffer_t * b0,
425 ip4_header_t * ip0, u8 * p_proto,
426 snat_session_key_t * p_value,
427 u8 * p_dont_translate, void *d, void *e)
429 icmp46_header_t *icmp0;
432 snat_session_key_t key0;
433 snat_session_key_t sm0;
434 u8 dont_translate = 0;
439 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
440 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
441 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
443 err = icmp_get_key (ip0, &key0);
446 b0->error = node->errors[err];
447 next0 = SNAT_OUT2IN_NEXT_DROP;
450 key0.fib_index = rx_fib_index0;
452 if (snat_static_mapping_match
453 (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, 0))
455 /* Don't NAT packet aimed at the intfc address */
456 if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))
461 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
462 next0 = SNAT_OUT2IN_NEXT_DROP;
466 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
467 (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
468 !icmp_is_error_message (icmp0)))
470 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
471 next0 = SNAT_OUT2IN_NEXT_DROP;
478 *p_proto = key0.protocol;
479 *p_dont_translate = dont_translate;
484 icmp_out2in (snat_main_t * sm,
487 icmp46_header_t * icmp0,
490 vlib_node_runtime_t * node,
491 u32 next0, u32 thread_index, void *d, void *e)
493 snat_session_key_t sm0;
495 icmp_echo_header_t *echo0, *inner_echo0 = 0;
496 ip4_header_t *inner_ip0 = 0;
498 icmp46_header_t *inner_icmp0;
500 u32 new_addr0, old_addr0;
501 u16 old_id0, new_id0;
506 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
508 next0_tmp = sm->icmp_match_out2in_cb (sm, node, thread_index, b0, ip0,
509 &protocol, &sm0, &dont_translate, d,
513 if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
516 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
518 sum0 = ip_incremental_checksum_buffer (sm->vlib_main, b0, (u8 *) icmp0 -
520 vlib_buffer_get_current (b0),
521 ntohs (ip0->length) -
522 ip4_header_bytes (ip0), 0);
523 checksum0 = ~ip_csum_fold (sum0);
524 if (checksum0 != 0 && checksum0 != 0xffff)
526 next0 = SNAT_OUT2IN_NEXT_DROP;
531 old_addr0 = ip0->dst_address.as_u32;
532 new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
533 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
535 sum0 = ip0->checksum;
536 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
537 dst_address /* changed member */ );
538 ip0->checksum = ip_csum_fold (sum0);
540 if (icmp0->checksum == 0)
541 icmp0->checksum = 0xffff;
543 if (!icmp_is_error_message (icmp0))
546 if (PREDICT_FALSE (new_id0 != echo0->identifier))
548 old_id0 = echo0->identifier;
550 echo0->identifier = new_id0;
552 sum0 = icmp0->checksum;
553 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
554 identifier /* changed member */ );
555 icmp0->checksum = ip_csum_fold (sum0);
560 inner_ip0 = (ip4_header_t *) (echo0 + 1);
561 l4_header = ip4_next_header (inner_ip0);
563 if (!ip4_header_checksum_is_valid (inner_ip0))
565 next0 = SNAT_OUT2IN_NEXT_DROP;
569 old_addr0 = inner_ip0->src_address.as_u32;
570 inner_ip0->src_address = sm0.addr;
571 new_addr0 = inner_ip0->src_address.as_u32;
573 sum0 = icmp0->checksum;
574 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
575 src_address /* changed member */ );
576 icmp0->checksum = ip_csum_fold (sum0);
580 case SNAT_PROTOCOL_ICMP:
581 inner_icmp0 = (icmp46_header_t *) l4_header;
582 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
584 old_id0 = inner_echo0->identifier;
586 inner_echo0->identifier = new_id0;
588 sum0 = icmp0->checksum;
589 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
591 icmp0->checksum = ip_csum_fold (sum0);
593 case SNAT_PROTOCOL_UDP:
594 case SNAT_PROTOCOL_TCP:
595 old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
597 ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
599 sum0 = icmp0->checksum;
600 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
602 icmp0->checksum = ip_csum_fold (sum0);
615 icmp_out2in_slow_path (snat_main_t * sm,
618 icmp46_header_t * icmp0,
621 vlib_node_runtime_t * node,
623 u32 thread_index, snat_session_t ** p_s0)
625 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
626 next0, thread_index, p_s0, 0);
627 snat_session_t *s0 = *p_s0;
628 if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP && s0))
631 nat44_session_update_counters (s0, now,
632 vlib_buffer_length_in_chain
633 (sm->vlib_main, b0));
634 /* Per-user LRU list maintenance */
635 nat44_session_update_lru (sm, s0, thread_index);
641 nat_out2in_sm_unknown_proto (snat_main_t * sm,
643 ip4_header_t * ip, u32 rx_fib_index)
645 clib_bihash_kv_8_8_t kv, value;
646 snat_static_mapping_t *m;
647 snat_session_key_t m_key;
648 u32 old_addr, new_addr;
651 m_key.addr = ip->dst_address;
655 kv.key = m_key.as_u64;
656 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
659 m = pool_elt_at_index (sm->static_mappings, value.value);
661 old_addr = ip->dst_address.as_u32;
662 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
664 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
665 ip->checksum = ip_csum_fold (sum);
667 vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
672 snat_out2in_node_fn (vlib_main_t * vm,
673 vlib_node_runtime_t * node, vlib_frame_t * frame)
675 u32 n_left_from, *from, *to_next;
676 snat_out2in_next_t next_index;
677 u32 pkts_processed = 0;
678 snat_main_t *sm = &snat_main;
679 f64 now = vlib_time_now (vm);
680 u32 thread_index = vm->thread_index;
682 from = vlib_frame_vector_args (frame);
683 n_left_from = frame->n_vectors;
684 next_index = node->cached_next_index;
686 while (n_left_from > 0)
690 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
692 while (n_left_from >= 4 && n_left_to_next >= 2)
695 vlib_buffer_t *b0, *b1;
696 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
697 u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
698 u32 sw_if_index0, sw_if_index1;
699 ip4_header_t *ip0, *ip1;
700 ip_csum_t sum0, sum1;
701 u32 new_addr0, old_addr0;
702 u16 new_port0, old_port0;
703 u32 new_addr1, old_addr1;
704 u16 new_port1, old_port1;
705 udp_header_t *udp0, *udp1;
706 tcp_header_t *tcp0, *tcp1;
707 icmp46_header_t *icmp0, *icmp1;
708 snat_session_key_t key0, key1, sm0, sm1;
709 u32 rx_fib_index0, rx_fib_index1;
711 snat_session_t *s0 = 0, *s1 = 0;
712 clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
713 u8 identity_nat0, identity_nat1;
715 /* Prefetch next iteration. */
717 vlib_buffer_t *p2, *p3;
719 p2 = vlib_get_buffer (vm, from[2]);
720 p3 = vlib_get_buffer (vm, from[3]);
722 vlib_prefetch_buffer_header (p2, LOAD);
723 vlib_prefetch_buffer_header (p3, LOAD);
725 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
726 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
729 /* speculatively enqueue b0 and b1 to the current next frame */
730 to_next[0] = bi0 = from[0];
731 to_next[1] = bi1 = from[1];
737 b0 = vlib_get_buffer (vm, bi0);
738 b1 = vlib_get_buffer (vm, bi1);
740 vnet_buffer (b0)->snat.flags = 0;
741 vnet_buffer (b1)->snat.flags = 0;
743 ip0 = vlib_buffer_get_current (b0);
744 udp0 = ip4_next_header (ip0);
745 tcp0 = (tcp_header_t *) udp0;
746 icmp0 = (icmp46_header_t *) udp0;
748 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
749 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
752 if (PREDICT_FALSE (ip0->ttl == 1))
754 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
755 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
756 ICMP4_time_exceeded_ttl_exceeded_in_transit,
758 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
762 proto0 = ip_proto_to_snat_proto (ip0->protocol);
764 if (PREDICT_FALSE (proto0 == ~0))
766 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
768 if (!sm->forwarding_enabled)
771 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
772 next0 = SNAT_OUT2IN_NEXT_DROP;
778 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
780 next0 = icmp_out2in_slow_path
781 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
782 next0, now, thread_index, &s0);
786 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
788 next0 = SNAT_OUT2IN_NEXT_REASS;
792 key0.addr = ip0->dst_address;
793 key0.port = udp0->dst_port;
794 key0.protocol = proto0;
795 key0.fib_index = rx_fib_index0;
797 kv0.key = key0.as_u64;
799 if (clib_bihash_search_8_8
800 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
802 /* Try to match static mapping by external address and port,
803 destination address and port in packet */
804 if (snat_static_mapping_match
805 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
808 * Send DHCP packets to the ipv4 stack, or we won't
809 * be able to use dhcp client on the outside interface
811 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
812 && (udp0->dst_port ==
814 (UDP_DST_PORT_dhcp_to_client))))
816 vnet_feature_next (&next0, b0);
820 if (!sm->forwarding_enabled)
823 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
824 next0 = SNAT_OUT2IN_NEXT_DROP;
829 if (PREDICT_FALSE (identity_nat0))
832 /* Create session initiated by host from external network */
833 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
837 next0 = SNAT_OUT2IN_NEXT_DROP;
843 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
846 old_addr0 = ip0->dst_address.as_u32;
847 ip0->dst_address = s0->in2out.addr;
848 new_addr0 = ip0->dst_address.as_u32;
849 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
851 sum0 = ip0->checksum;
852 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
854 dst_address /* changed member */ );
855 ip0->checksum = ip_csum_fold (sum0);
857 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
859 old_port0 = tcp0->dst_port;
860 tcp0->dst_port = s0->in2out.port;
861 new_port0 = tcp0->dst_port;
863 sum0 = tcp0->checksum;
864 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
866 dst_address /* changed member */ );
868 sum0 = ip_csum_update (sum0, old_port0, new_port0,
869 ip4_header_t /* cheat */ ,
870 length /* changed member */ );
871 tcp0->checksum = ip_csum_fold (sum0);
875 old_port0 = udp0->dst_port;
876 udp0->dst_port = s0->in2out.port;
881 nat44_session_update_counters (s0, now,
882 vlib_buffer_length_in_chain (vm,
884 /* Per-user LRU list maintenance */
885 nat44_session_update_lru (sm, s0, thread_index);
888 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
889 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
891 snat_out2in_trace_t *t =
892 vlib_add_trace (vm, node, b0, sizeof (*t));
893 t->sw_if_index = sw_if_index0;
894 t->next_index = next0;
895 t->session_index = ~0;
898 s0 - sm->per_thread_data[thread_index].sessions;
901 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
904 ip1 = vlib_buffer_get_current (b1);
905 udp1 = ip4_next_header (ip1);
906 tcp1 = (tcp_header_t *) udp1;
907 icmp1 = (icmp46_header_t *) udp1;
909 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
910 rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
913 if (PREDICT_FALSE (ip1->ttl == 1))
915 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
916 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
917 ICMP4_time_exceeded_ttl_exceeded_in_transit,
919 next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
923 proto1 = ip_proto_to_snat_proto (ip1->protocol);
925 if (PREDICT_FALSE (proto1 == ~0))
927 if (nat_out2in_sm_unknown_proto (sm, b1, ip1, rx_fib_index1))
929 if (!sm->forwarding_enabled)
932 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
933 next1 = SNAT_OUT2IN_NEXT_DROP;
939 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
941 next1 = icmp_out2in_slow_path
942 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
943 next1, now, thread_index, &s1);
947 if (PREDICT_FALSE (ip4_is_fragment (ip1)))
949 next1 = SNAT_OUT2IN_NEXT_REASS;
953 key1.addr = ip1->dst_address;
954 key1.port = udp1->dst_port;
955 key1.protocol = proto1;
956 key1.fib_index = rx_fib_index1;
958 kv1.key = key1.as_u64;
960 if (clib_bihash_search_8_8
961 (&sm->per_thread_data[thread_index].out2in, &kv1, &value1))
963 /* Try to match static mapping by external address and port,
964 destination address and port in packet */
965 if (snat_static_mapping_match
966 (sm, key1, &sm1, 1, 0, 0, 0, 0, &identity_nat1))
969 * Send DHCP packets to the ipv4 stack, or we won't
970 * be able to use dhcp client on the outside interface
972 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
973 && (udp1->dst_port ==
975 (UDP_DST_PORT_dhcp_to_client))))
977 vnet_feature_next (&next1, b1);
981 if (!sm->forwarding_enabled)
984 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
985 next1 = SNAT_OUT2IN_NEXT_DROP;
990 if (PREDICT_FALSE (identity_nat1))
993 /* Create session initiated by host from external network */
994 s1 = create_session_for_static_mapping (sm, b1, sm1, key1, node,
998 next1 = SNAT_OUT2IN_NEXT_DROP;
1004 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1007 old_addr1 = ip1->dst_address.as_u32;
1008 ip1->dst_address = s1->in2out.addr;
1009 new_addr1 = ip1->dst_address.as_u32;
1010 vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1012 sum1 = ip1->checksum;
1013 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1015 dst_address /* changed member */ );
1016 ip1->checksum = ip_csum_fold (sum1);
1018 if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1020 old_port1 = tcp1->dst_port;
1021 tcp1->dst_port = s1->in2out.port;
1022 new_port1 = tcp1->dst_port;
1024 sum1 = tcp1->checksum;
1025 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1027 dst_address /* changed member */ );
1029 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1030 ip4_header_t /* cheat */ ,
1031 length /* changed member */ );
1032 tcp1->checksum = ip_csum_fold (sum1);
1036 old_port1 = udp1->dst_port;
1037 udp1->dst_port = s1->in2out.port;
1042 nat44_session_update_counters (s1, now,
1043 vlib_buffer_length_in_chain (vm,
1045 /* Per-user LRU list maintenance */
1046 nat44_session_update_lru (sm, s1, thread_index);
1049 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1050 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1052 snat_out2in_trace_t *t =
1053 vlib_add_trace (vm, node, b1, sizeof (*t));
1054 t->sw_if_index = sw_if_index1;
1055 t->next_index = next1;
1056 t->session_index = ~0;
1059 s1 - sm->per_thread_data[thread_index].sessions;
1062 pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1064 /* verify speculative enqueues, maybe switch current next frame */
1065 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1066 to_next, n_left_to_next,
1067 bi0, bi1, next0, next1);
1070 while (n_left_from > 0 && n_left_to_next > 0)
1074 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1078 u32 new_addr0, old_addr0;
1079 u16 new_port0, old_port0;
1082 icmp46_header_t *icmp0;
1083 snat_session_key_t key0, sm0;
1086 snat_session_t *s0 = 0;
1087 clib_bihash_kv_8_8_t kv0, value0;
1090 /* speculatively enqueue b0 to the current next frame */
1096 n_left_to_next -= 1;
1098 b0 = vlib_get_buffer (vm, bi0);
1100 vnet_buffer (b0)->snat.flags = 0;
1102 ip0 = vlib_buffer_get_current (b0);
1103 udp0 = ip4_next_header (ip0);
1104 tcp0 = (tcp_header_t *) udp0;
1105 icmp0 = (icmp46_header_t *) udp0;
1107 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1108 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1111 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1113 if (PREDICT_FALSE (proto0 == ~0))
1115 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
1117 if (!sm->forwarding_enabled)
1120 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1121 next0 = SNAT_OUT2IN_NEXT_DROP;
1127 if (PREDICT_FALSE (ip0->ttl == 1))
1129 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1130 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1131 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1133 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1137 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1139 next0 = icmp_out2in_slow_path
1140 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1141 next0, now, thread_index, &s0);
1145 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1147 next0 = SNAT_OUT2IN_NEXT_REASS;
1151 key0.addr = ip0->dst_address;
1152 key0.port = udp0->dst_port;
1153 key0.protocol = proto0;
1154 key0.fib_index = rx_fib_index0;
1156 kv0.key = key0.as_u64;
1158 if (clib_bihash_search_8_8
1159 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
1161 /* Try to match static mapping by external address and port,
1162 destination address and port in packet */
1163 if (snat_static_mapping_match
1164 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
1167 * Send DHCP packets to the ipv4 stack, or we won't
1168 * be able to use dhcp client on the outside interface
1170 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1171 && (udp0->dst_port ==
1172 clib_host_to_net_u16
1173 (UDP_DST_PORT_dhcp_to_client))))
1175 vnet_feature_next (&next0, b0);
1179 if (!sm->forwarding_enabled)
1182 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1183 next0 = SNAT_OUT2IN_NEXT_DROP;
1188 if (PREDICT_FALSE (identity_nat0))
1191 /* Create session initiated by host from external network */
1192 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
1196 next0 = SNAT_OUT2IN_NEXT_DROP;
1202 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1205 old_addr0 = ip0->dst_address.as_u32;
1206 ip0->dst_address = s0->in2out.addr;
1207 new_addr0 = ip0->dst_address.as_u32;
1208 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1210 sum0 = ip0->checksum;
1211 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1213 dst_address /* changed member */ );
1214 ip0->checksum = ip_csum_fold (sum0);
1216 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1218 old_port0 = tcp0->dst_port;
1219 tcp0->dst_port = s0->in2out.port;
1220 new_port0 = tcp0->dst_port;
1222 sum0 = tcp0->checksum;
1223 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1225 dst_address /* changed member */ );
1227 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1228 ip4_header_t /* cheat */ ,
1229 length /* changed member */ );
1230 tcp0->checksum = ip_csum_fold (sum0);
1234 old_port0 = udp0->dst_port;
1235 udp0->dst_port = s0->in2out.port;
1240 nat44_session_update_counters (s0, now,
1241 vlib_buffer_length_in_chain (vm,
1243 /* Per-user LRU list maintenance */
1244 nat44_session_update_lru (sm, s0, thread_index);
1247 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1248 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1250 snat_out2in_trace_t *t =
1251 vlib_add_trace (vm, node, b0, sizeof (*t));
1252 t->sw_if_index = sw_if_index0;
1253 t->next_index = next0;
1254 t->session_index = ~0;
1257 s0 - sm->per_thread_data[thread_index].sessions;
1260 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1262 /* verify speculative enqueue, maybe switch current next frame */
1263 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1264 to_next, n_left_to_next,
1268 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1271 vlib_node_increment_counter (vm, snat_out2in_node.index,
1272 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1274 return frame->n_vectors;
1278 VLIB_REGISTER_NODE (snat_out2in_node) = {
1279 .function = snat_out2in_node_fn,
1280 .name = "nat44-out2in",
1281 .vector_size = sizeof (u32),
1282 .format_trace = format_snat_out2in_trace,
1283 .type = VLIB_NODE_TYPE_INTERNAL,
1285 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1286 .error_strings = snat_out2in_error_strings,
1288 .runtime_data_bytes = sizeof (snat_runtime_t),
1290 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1292 /* edit / add dispositions here */
1294 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1295 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1296 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1297 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1302 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
1305 nat44_out2in_reass_node_fn (vlib_main_t * vm,
1306 vlib_node_runtime_t * node, vlib_frame_t * frame)
1308 u32 n_left_from, *from, *to_next;
1309 snat_out2in_next_t next_index;
1310 u32 pkts_processed = 0;
1311 snat_main_t *sm = &snat_main;
1312 f64 now = vlib_time_now (vm);
1313 u32 thread_index = vm->thread_index;
1314 snat_main_per_thread_data_t *per_thread_data =
1315 &sm->per_thread_data[thread_index];
1316 u32 *fragments_to_drop = 0;
1317 u32 *fragments_to_loopback = 0;
1319 from = vlib_frame_vector_args (frame);
1320 n_left_from = frame->n_vectors;
1321 next_index = node->cached_next_index;
1323 while (n_left_from > 0)
1327 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1329 while (n_left_from > 0 && n_left_to_next > 0)
1331 u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1336 nat_reass_ip4_t *reass0;
1339 snat_session_key_t key0, sm0;
1340 clib_bihash_kv_8_8_t kv0, value0;
1341 snat_session_t *s0 = 0;
1342 u16 old_port0, new_port0;
1346 /* speculatively enqueue b0 to the current next frame */
1352 n_left_to_next -= 1;
1354 b0 = vlib_get_buffer (vm, bi0);
1355 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1357 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1359 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1362 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1364 next0 = SNAT_OUT2IN_NEXT_DROP;
1365 b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1369 ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1370 udp0 = ip4_next_header (ip0);
1371 tcp0 = (tcp_header_t *) udp0;
1372 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1374 reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1378 1, &fragments_to_drop);
1380 if (PREDICT_FALSE (!reass0))
1382 next0 = SNAT_OUT2IN_NEXT_DROP;
1383 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1384 nat_log_notice ("maximum reassemblies exceeded");
1388 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1390 key0.addr = ip0->dst_address;
1391 key0.port = udp0->dst_port;
1392 key0.protocol = proto0;
1393 key0.fib_index = rx_fib_index0;
1394 kv0.key = key0.as_u64;
1396 if (clib_bihash_search_8_8
1397 (&per_thread_data->out2in, &kv0, &value0))
1399 /* Try to match static mapping by external address and port,
1400 destination address and port in packet */
1401 if (snat_static_mapping_match
1402 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
1405 * Send DHCP packets to the ipv4 stack, or we won't
1406 * be able to use dhcp client on the outside interface
1408 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1411 clib_host_to_net_u16
1412 (UDP_DST_PORT_dhcp_to_client))))
1414 vnet_feature_next (&next0, b0);
1418 if (!sm->forwarding_enabled)
1421 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1422 next0 = SNAT_OUT2IN_NEXT_DROP;
1427 if (PREDICT_FALSE (identity_nat0))
1430 /* Create session initiated by host from external network */
1432 create_session_for_static_mapping (sm, b0, sm0, key0,
1438 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1439 next0 = SNAT_OUT2IN_NEXT_DROP;
1442 reass0->sess_index = s0 - per_thread_data->sessions;
1443 reass0->thread_index = thread_index;
1447 s0 = pool_elt_at_index (per_thread_data->sessions,
1449 reass0->sess_index = value0.value;
1451 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1455 if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1457 if (nat_ip4_reass_add_fragment
1458 (reass0, bi0, &fragments_to_drop))
1460 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1462 ("maximum fragments per reassembly exceeded");
1463 next0 = SNAT_OUT2IN_NEXT_DROP;
1469 s0 = pool_elt_at_index (per_thread_data->sessions,
1470 reass0->sess_index);
1473 old_addr0 = ip0->dst_address.as_u32;
1474 ip0->dst_address = s0->in2out.addr;
1475 new_addr0 = ip0->dst_address.as_u32;
1476 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1478 sum0 = ip0->checksum;
1479 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1481 dst_address /* changed member */ );
1482 ip0->checksum = ip_csum_fold (sum0);
1484 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1486 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1488 old_port0 = tcp0->dst_port;
1489 tcp0->dst_port = s0->in2out.port;
1490 new_port0 = tcp0->dst_port;
1492 sum0 = tcp0->checksum;
1493 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1495 dst_address /* changed member */ );
1497 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1498 ip4_header_t /* cheat */ ,
1499 length /* changed member */ );
1500 tcp0->checksum = ip_csum_fold (sum0);
1504 old_port0 = udp0->dst_port;
1505 udp0->dst_port = s0->in2out.port;
1511 nat44_session_update_counters (s0, now,
1512 vlib_buffer_length_in_chain (vm,
1514 /* Per-user LRU list maintenance */
1515 nat44_session_update_lru (sm, s0, thread_index);
1518 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1519 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1521 nat44_reass_trace_t *t =
1522 vlib_add_trace (vm, node, b0, sizeof (*t));
1523 t->cached = cached0;
1524 t->sw_if_index = sw_if_index0;
1525 t->next_index = next0;
1535 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1537 /* verify speculative enqueue, maybe switch current next frame */
1538 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1539 to_next, n_left_to_next,
1543 if (n_left_from == 0 && vec_len (fragments_to_loopback))
1545 from = vlib_frame_vector_args (frame);
1546 u32 len = vec_len (fragments_to_loopback);
1547 if (len <= VLIB_FRAME_SIZE)
1549 clib_memcpy (from, fragments_to_loopback,
1550 sizeof (u32) * len);
1552 vec_reset_length (fragments_to_loopback);
1557 fragments_to_loopback + (len -
1559 sizeof (u32) * VLIB_FRAME_SIZE);
1560 n_left_from = VLIB_FRAME_SIZE;
1561 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1566 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1569 vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1570 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1573 nat_send_all_to_node (vm, fragments_to_drop, node,
1574 &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1575 SNAT_OUT2IN_NEXT_DROP);
1577 vec_free (fragments_to_drop);
1578 vec_free (fragments_to_loopback);
1579 return frame->n_vectors;
1583 VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
1584 .function = nat44_out2in_reass_node_fn,
1585 .name = "nat44-out2in-reass",
1586 .vector_size = sizeof (u32),
1587 .format_trace = format_nat44_reass_trace,
1588 .type = VLIB_NODE_TYPE_INTERNAL,
1590 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1591 .error_strings = snat_out2in_error_strings,
1593 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1595 /* edit / add dispositions here */
1597 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1598 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1599 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1600 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1605 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
1606 nat44_out2in_reass_node_fn);
1609 snat_out2in_fast_node_fn (vlib_main_t * vm,
1610 vlib_node_runtime_t * node, vlib_frame_t * frame)
1612 u32 n_left_from, *from, *to_next;
1613 snat_out2in_next_t next_index;
1614 u32 pkts_processed = 0;
1615 snat_main_t *sm = &snat_main;
1617 from = vlib_frame_vector_args (frame);
1618 n_left_from = frame->n_vectors;
1619 next_index = node->cached_next_index;
1621 while (n_left_from > 0)
1625 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1627 while (n_left_from > 0 && n_left_to_next > 0)
1631 u32 next0 = SNAT_OUT2IN_NEXT_DROP;
1635 u32 new_addr0, old_addr0;
1636 u16 new_port0, old_port0;
1639 icmp46_header_t *icmp0;
1640 snat_session_key_t key0, sm0;
1644 /* speculatively enqueue b0 to the current next frame */
1650 n_left_to_next -= 1;
1652 b0 = vlib_get_buffer (vm, bi0);
1654 ip0 = vlib_buffer_get_current (b0);
1655 udp0 = ip4_next_header (ip0);
1656 tcp0 = (tcp_header_t *) udp0;
1657 icmp0 = (icmp46_header_t *) udp0;
1659 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1661 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1663 vnet_feature_next (&next0, b0);
1665 if (PREDICT_FALSE (ip0->ttl == 1))
1667 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1668 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1669 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1671 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1675 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1677 if (PREDICT_FALSE (proto0 == ~0))
1680 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1682 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0,
1683 rx_fib_index0, node, next0, ~0, 0, 0);
1687 key0.addr = ip0->dst_address;
1688 key0.port = udp0->dst_port;
1689 key0.fib_index = rx_fib_index0;
1691 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
1693 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1697 new_addr0 = sm0.addr.as_u32;
1698 new_port0 = sm0.port;
1699 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1700 old_addr0 = ip0->dst_address.as_u32;
1701 ip0->dst_address.as_u32 = new_addr0;
1703 sum0 = ip0->checksum;
1704 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1706 dst_address /* changed member */ );
1707 ip0->checksum = ip_csum_fold (sum0);
1709 if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1711 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1713 old_port0 = tcp0->dst_port;
1714 tcp0->dst_port = new_port0;
1716 sum0 = tcp0->checksum;
1717 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1719 dst_address /* changed member */ );
1721 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1722 ip4_header_t /* cheat */ ,
1723 length /* changed member */ );
1724 tcp0->checksum = ip_csum_fold (sum0);
1728 old_port0 = udp0->dst_port;
1729 udp0->dst_port = new_port0;
1735 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1737 sum0 = tcp0->checksum;
1738 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1740 dst_address /* changed member */ );
1742 tcp0->checksum = ip_csum_fold (sum0);
1748 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1749 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1751 snat_out2in_trace_t *t =
1752 vlib_add_trace (vm, node, b0, sizeof (*t));
1753 t->sw_if_index = sw_if_index0;
1754 t->next_index = next0;
1757 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1759 /* verify speculative enqueue, maybe switch current next frame */
1760 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1761 to_next, n_left_to_next,
1765 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1768 vlib_node_increment_counter (vm, snat_out2in_fast_node.index,
1769 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1771 return frame->n_vectors;
1775 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
1776 .function = snat_out2in_fast_node_fn,
1777 .name = "nat44-out2in-fast",
1778 .vector_size = sizeof (u32),
1779 .format_trace = format_snat_out2in_fast_trace,
1780 .type = VLIB_NODE_TYPE_INTERNAL,
1782 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1783 .error_strings = snat_out2in_error_strings,
1785 .runtime_data_bytes = sizeof (snat_runtime_t),
1787 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1789 /* edit / add dispositions here */
1791 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1792 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1793 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1794 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1799 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node,
1800 snat_out2in_fast_node_fn);
1803 * fd.io coding-style-patch-verification: ON
1806 * eval: (c-set-style "gnu")