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 (ip4_is_fragment (ip0)))
780 next0 = SNAT_OUT2IN_NEXT_REASS;
784 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
786 next0 = icmp_out2in_slow_path
787 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
788 next0, now, thread_index, &s0);
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 (ip4_is_fragment (ip1)))
941 next1 = SNAT_OUT2IN_NEXT_REASS;
945 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
947 next1 = icmp_out2in_slow_path
948 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
949 next1, now, thread_index, &s1);
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 (ip4_is_fragment (ip0)))
1139 next0 = SNAT_OUT2IN_NEXT_REASS;
1143 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1145 next0 = icmp_out2in_slow_path
1146 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1147 next0, now, thread_index, &s0);
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 icmp46_header_t *icmp0;
1340 snat_session_key_t key0, sm0;
1341 clib_bihash_kv_8_8_t kv0, value0;
1342 snat_session_t *s0 = 0;
1343 u16 old_port0, new_port0;
1347 /* speculatively enqueue b0 to the current next frame */
1353 n_left_to_next -= 1;
1355 b0 = vlib_get_buffer (vm, bi0);
1356 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1358 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1360 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1363 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1365 next0 = SNAT_OUT2IN_NEXT_DROP;
1366 b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1370 ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1371 udp0 = ip4_next_header (ip0);
1372 tcp0 = (tcp_header_t *) udp0;
1373 icmp0 = (icmp46_header_t *) udp0;
1374 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1376 reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1380 1, &fragments_to_drop);
1382 if (PREDICT_FALSE (!reass0))
1384 next0 = SNAT_OUT2IN_NEXT_DROP;
1385 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1386 nat_log_notice ("maximum reassemblies exceeded");
1390 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1392 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1394 next0 = icmp_out2in_slow_path
1395 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1396 next0, now, thread_index, &s0);
1398 if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP))
1401 reass0->sess_index = s0 - per_thread_data->sessions;
1403 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1404 reass0->thread_index = thread_index;
1405 nat_ip4_reass_get_frags (reass0,
1406 &fragments_to_loopback);
1412 key0.addr = ip0->dst_address;
1413 key0.port = udp0->dst_port;
1414 key0.protocol = proto0;
1415 key0.fib_index = rx_fib_index0;
1416 kv0.key = key0.as_u64;
1418 if (clib_bihash_search_8_8
1419 (&per_thread_data->out2in, &kv0, &value0))
1421 /* Try to match static mapping by external address and port,
1422 destination address and port in packet */
1423 if (snat_static_mapping_match
1424 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
1427 * Send DHCP packets to the ipv4 stack, or we won't
1428 * be able to use dhcp client on the outside interface
1430 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1433 clib_host_to_net_u16
1434 (UDP_DST_PORT_dhcp_to_client))))
1436 vnet_feature_next (&next0, b0);
1440 if (!sm->forwarding_enabled)
1443 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1444 next0 = SNAT_OUT2IN_NEXT_DROP;
1449 if (PREDICT_FALSE (identity_nat0))
1452 /* Create session initiated by host from external network */
1454 create_session_for_static_mapping (sm, b0, sm0, key0,
1460 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1461 next0 = SNAT_OUT2IN_NEXT_DROP;
1464 reass0->sess_index = s0 - per_thread_data->sessions;
1465 reass0->thread_index = thread_index;
1469 s0 = pool_elt_at_index (per_thread_data->sessions,
1471 reass0->sess_index = value0.value;
1473 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1477 if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1479 if (nat_ip4_reass_add_fragment
1480 (reass0, bi0, &fragments_to_drop))
1482 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1484 ("maximum fragments per reassembly exceeded");
1485 next0 = SNAT_OUT2IN_NEXT_DROP;
1491 s0 = pool_elt_at_index (per_thread_data->sessions,
1492 reass0->sess_index);
1495 old_addr0 = ip0->dst_address.as_u32;
1496 ip0->dst_address = s0->in2out.addr;
1497 new_addr0 = ip0->dst_address.as_u32;
1498 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1500 sum0 = ip0->checksum;
1501 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1503 dst_address /* changed member */ );
1504 ip0->checksum = ip_csum_fold (sum0);
1506 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1508 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1510 old_port0 = tcp0->dst_port;
1511 tcp0->dst_port = s0->in2out.port;
1512 new_port0 = tcp0->dst_port;
1514 sum0 = tcp0->checksum;
1515 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1517 dst_address /* changed member */ );
1519 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1520 ip4_header_t /* cheat */ ,
1521 length /* changed member */ );
1522 tcp0->checksum = ip_csum_fold (sum0);
1526 old_port0 = udp0->dst_port;
1527 udp0->dst_port = s0->in2out.port;
1533 nat44_session_update_counters (s0, now,
1534 vlib_buffer_length_in_chain (vm,
1536 /* Per-user LRU list maintenance */
1537 nat44_session_update_lru (sm, s0, thread_index);
1540 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1541 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1543 nat44_reass_trace_t *t =
1544 vlib_add_trace (vm, node, b0, sizeof (*t));
1545 t->cached = cached0;
1546 t->sw_if_index = sw_if_index0;
1547 t->next_index = next0;
1557 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1559 /* verify speculative enqueue, maybe switch current next frame */
1560 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1561 to_next, n_left_to_next,
1565 if (n_left_from == 0 && vec_len (fragments_to_loopback))
1567 from = vlib_frame_vector_args (frame);
1568 u32 len = vec_len (fragments_to_loopback);
1569 if (len <= VLIB_FRAME_SIZE)
1571 clib_memcpy (from, fragments_to_loopback,
1572 sizeof (u32) * len);
1574 vec_reset_length (fragments_to_loopback);
1579 fragments_to_loopback + (len -
1581 sizeof (u32) * VLIB_FRAME_SIZE);
1582 n_left_from = VLIB_FRAME_SIZE;
1583 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1588 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1591 vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1592 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1595 nat_send_all_to_node (vm, fragments_to_drop, node,
1596 &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1597 SNAT_OUT2IN_NEXT_DROP);
1599 vec_free (fragments_to_drop);
1600 vec_free (fragments_to_loopback);
1601 return frame->n_vectors;
1605 VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
1606 .function = nat44_out2in_reass_node_fn,
1607 .name = "nat44-out2in-reass",
1608 .vector_size = sizeof (u32),
1609 .format_trace = format_nat44_reass_trace,
1610 .type = VLIB_NODE_TYPE_INTERNAL,
1612 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1613 .error_strings = snat_out2in_error_strings,
1615 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1617 /* edit / add dispositions here */
1619 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1620 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1621 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1622 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1627 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
1628 nat44_out2in_reass_node_fn);
1631 snat_out2in_fast_node_fn (vlib_main_t * vm,
1632 vlib_node_runtime_t * node, vlib_frame_t * frame)
1634 u32 n_left_from, *from, *to_next;
1635 snat_out2in_next_t next_index;
1636 u32 pkts_processed = 0;
1637 snat_main_t *sm = &snat_main;
1639 from = vlib_frame_vector_args (frame);
1640 n_left_from = frame->n_vectors;
1641 next_index = node->cached_next_index;
1643 while (n_left_from > 0)
1647 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1649 while (n_left_from > 0 && n_left_to_next > 0)
1653 u32 next0 = SNAT_OUT2IN_NEXT_DROP;
1657 u32 new_addr0, old_addr0;
1658 u16 new_port0, old_port0;
1661 icmp46_header_t *icmp0;
1662 snat_session_key_t key0, sm0;
1666 /* speculatively enqueue b0 to the current next frame */
1672 n_left_to_next -= 1;
1674 b0 = vlib_get_buffer (vm, bi0);
1676 ip0 = vlib_buffer_get_current (b0);
1677 udp0 = ip4_next_header (ip0);
1678 tcp0 = (tcp_header_t *) udp0;
1679 icmp0 = (icmp46_header_t *) udp0;
1681 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1683 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1685 vnet_feature_next (&next0, b0);
1687 if (PREDICT_FALSE (ip0->ttl == 1))
1689 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1690 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1691 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1693 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1697 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1699 if (PREDICT_FALSE (proto0 == ~0))
1702 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1704 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0,
1705 rx_fib_index0, node, next0, ~0, 0, 0);
1709 key0.addr = ip0->dst_address;
1710 key0.port = udp0->dst_port;
1711 key0.fib_index = rx_fib_index0;
1713 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
1715 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1719 new_addr0 = sm0.addr.as_u32;
1720 new_port0 = sm0.port;
1721 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1722 old_addr0 = ip0->dst_address.as_u32;
1723 ip0->dst_address.as_u32 = new_addr0;
1725 sum0 = ip0->checksum;
1726 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1728 dst_address /* changed member */ );
1729 ip0->checksum = ip_csum_fold (sum0);
1731 if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1733 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1735 old_port0 = tcp0->dst_port;
1736 tcp0->dst_port = new_port0;
1738 sum0 = tcp0->checksum;
1739 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1741 dst_address /* changed member */ );
1743 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1744 ip4_header_t /* cheat */ ,
1745 length /* changed member */ );
1746 tcp0->checksum = ip_csum_fold (sum0);
1750 old_port0 = udp0->dst_port;
1751 udp0->dst_port = new_port0;
1757 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1759 sum0 = tcp0->checksum;
1760 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1762 dst_address /* changed member */ );
1764 tcp0->checksum = ip_csum_fold (sum0);
1770 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1771 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1773 snat_out2in_trace_t *t =
1774 vlib_add_trace (vm, node, b0, sizeof (*t));
1775 t->sw_if_index = sw_if_index0;
1776 t->next_index = next0;
1779 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1781 /* verify speculative enqueue, maybe switch current next frame */
1782 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1783 to_next, n_left_to_next,
1787 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1790 vlib_node_increment_counter (vm, snat_out2in_fast_node.index,
1791 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1793 return frame->n_vectors;
1797 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
1798 .function = snat_out2in_fast_node_fn,
1799 .name = "nat44-out2in-fast",
1800 .vector_size = sizeof (u32),
1801 .format_trace = format_snat_out2in_fast_trace,
1802 .type = VLIB_NODE_TYPE_INTERNAL,
1804 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1805 .error_strings = snat_out2in_error_strings,
1807 .runtime_data_bytes = sizeof (snat_runtime_t),
1809 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1811 /* edit / add dispositions here */
1813 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1814 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1815 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1816 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1821 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node,
1822 snat_out2in_fast_node_fn);
1825 * fd.io coding-style-patch-verification: ON
1828 * eval: (c-set-style "gnu")