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.
16 #include <vlib/vlib.h>
17 #include <vnet/vnet.h>
18 #include <vnet/pg/pg.h>
19 #include <vnet/handoff.h>
21 #include <vnet/ip/ip.h>
22 #include <vnet/udp/udp.h>
23 #include <vnet/ethernet/ethernet.h>
24 #include <vnet/fib/ip4_fib.h>
26 #include <nat/nat_ipfix_logging.h>
27 #include <nat/nat_det.h>
28 #include <nat/nat_reass.h>
29 #include <nat/nat_inlines.h>
31 #include <vppinfra/hash.h>
32 #include <vppinfra/error.h>
33 #include <vppinfra/elog.h>
39 } snat_out2in_trace_t;
42 u32 next_worker_index;
44 } snat_out2in_worker_handoff_trace_t;
46 /* packet trace format function */
47 static u8 * 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 *);
53 s = format (s, "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
54 t->sw_if_index, t->next_index, t->session_index);
58 static u8 * format_snat_out2in_fast_trace (u8 * s, va_list * args)
60 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
61 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
62 snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
64 s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
65 t->sw_if_index, t->next_index);
69 static u8 * format_snat_out2in_worker_handoff_trace (u8 * s, va_list * args)
71 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
72 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
73 snat_out2in_worker_handoff_trace_t * t =
74 va_arg (*args, snat_out2in_worker_handoff_trace_t *);
77 m = t->do_handoff ? "next worker" : "same worker";
78 s = format (s, "NAT44_OUT2IN_WORKER_HANDOFF: %s %d", m, t->next_worker_index);
87 } nat44_out2in_reass_trace_t;
89 static u8 * format_nat44_out2in_reass_trace (u8 * s, va_list * args)
91 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
92 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
93 nat44_out2in_reass_trace_t * t = va_arg (*args, nat44_out2in_reass_trace_t *);
95 s = format (s, "NAT44_OUT2IN_REASS: sw_if_index %d, next index %d, status %s",
96 t->sw_if_index, t->next_index,
97 t->cached ? "cached" : "translated");
102 vlib_node_registration_t snat_out2in_node;
103 vlib_node_registration_t snat_out2in_fast_node;
104 vlib_node_registration_t snat_out2in_worker_handoff_node;
105 vlib_node_registration_t snat_det_out2in_node;
106 vlib_node_registration_t nat44_out2in_reass_node;
107 vlib_node_registration_t nat44_ed_out2in_node;
108 vlib_node_registration_t nat44_ed_out2in_slowpath_node;
109 vlib_node_registration_t nat44_ed_out2in_reass_node;
111 #define foreach_snat_out2in_error \
112 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
113 _(OUT2IN_PACKETS, "Good out2in packets processed") \
114 _(OUT_OF_PORTS, "Out of ports") \
115 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
116 _(NO_TRANSLATION, "No translation") \
117 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \
118 _(DROP_FRAGMENT, "Drop fragment") \
119 _(MAX_REASS, "Maximum reassemblies exceeded") \
120 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")\
121 _(FQ_CONGESTED, "Handoff frame queue congested")
124 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
125 foreach_snat_out2in_error
128 } snat_out2in_error_t;
130 static char * snat_out2in_error_strings[] = {
131 #define _(sym,string) string,
132 foreach_snat_out2in_error
137 SNAT_OUT2IN_NEXT_DROP,
138 SNAT_OUT2IN_NEXT_LOOKUP,
139 SNAT_OUT2IN_NEXT_ICMP_ERROR,
140 SNAT_OUT2IN_NEXT_REASS,
142 } snat_out2in_next_t;
145 nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void * arg)
147 snat_main_t *sm = &snat_main;
148 nat44_is_idle_session_ctx_t *ctx = arg;
150 u64 sess_timeout_time;
151 snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
153 clib_bihash_kv_8_8_t s_kv;
155 s = pool_elt_at_index (tsm->sessions, kv->value);
156 sess_timeout_time = s->last_heard + (f64)nat44_session_get_timeout(sm, s);
157 if (ctx->now >= sess_timeout_time)
159 s_kv.key = s->in2out.as_u64;
160 if (clib_bihash_add_del_8_8 (&tsm->in2out, &s_kv, 0))
161 nat_log_warn ("out2in key del failed");
163 snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
164 s->out2in.addr.as_u32,
168 s->in2out.fib_index);
170 if (!snat_is_session_static (s))
171 snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
174 nat44_delete_session (sm, s, ctx->thread_index);
182 * @brief Create session for static mapping.
184 * Create NAT session initiated by host from external network with static
187 * @param sm NAT main.
188 * @param b0 Vlib buffer.
189 * @param in2out In2out NAT44 session key.
190 * @param out2in Out2in NAT44 session key.
191 * @param node Vlib node.
193 * @returns SNAT session if successfully created otherwise 0.
195 static inline snat_session_t *
196 create_session_for_static_mapping (snat_main_t *sm,
198 snat_session_key_t in2out,
199 snat_session_key_t out2in,
200 vlib_node_runtime_t * node,
206 clib_bihash_kv_8_8_t kv0;
209 nat44_is_idle_session_ctx_t ctx0;
211 if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
213 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
214 nat_log_notice ("maximum sessions exceeded");
218 ip0 = vlib_buffer_get_current (b0);
219 udp0 = ip4_next_header (ip0);
221 u = nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index);
224 nat_log_warn ("create NAT user failed");
228 s = nat_session_alloc_or_recycle (sm, u, thread_index);
231 nat44_delete_user_with_no_session (sm, u, thread_index);
232 nat_log_warn ("create NAT session failed");
236 s->outside_address_index = ~0;
237 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
238 s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
239 s->ext_host_port = udp0->src_port;
240 user_session_increment (sm, u, 1 /* static */);
243 s->in2out.protocol = out2in.protocol;
245 /* Add to translation hashes */
247 ctx0.thread_index = thread_index;
248 kv0.key = s->in2out.as_u64;
249 kv0.value = s - sm->per_thread_data[thread_index].sessions;
250 if (clib_bihash_add_or_overwrite_stale_8_8 (
251 &sm->per_thread_data[thread_index].in2out, &kv0,
252 nat44_i2o_is_idle_session_cb, &ctx0))
253 nat_log_notice ("in2out key add failed");
255 kv0.key = s->out2in.as_u64;
257 if (clib_bihash_add_or_overwrite_stale_8_8 (
258 &sm->per_thread_data[thread_index].out2in, &kv0,
259 nat44_o2i_is_idle_session_cb, &ctx0))
260 nat_log_notice ("out2in key add failed");
263 snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
264 s->out2in.addr.as_u32,
268 s->in2out.fib_index);
273 snat_out2in_error_t icmp_get_key(ip4_header_t *ip0,
274 snat_session_key_t *p_key0)
276 icmp46_header_t *icmp0;
277 snat_session_key_t key0;
278 icmp_echo_header_t *echo0, *inner_echo0 = 0;
279 ip4_header_t *inner_ip0;
281 icmp46_header_t *inner_icmp0;
283 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
284 echo0 = (icmp_echo_header_t *)(icmp0+1);
286 if (!icmp_is_error_message (icmp0))
288 key0.protocol = SNAT_PROTOCOL_ICMP;
289 key0.addr = ip0->dst_address;
290 key0.port = echo0->identifier;
294 inner_ip0 = (ip4_header_t *)(echo0+1);
295 l4_header = ip4_next_header (inner_ip0);
296 key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
297 key0.addr = inner_ip0->src_address;
298 switch (key0.protocol)
300 case SNAT_PROTOCOL_ICMP:
301 inner_icmp0 = (icmp46_header_t*)l4_header;
302 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
303 key0.port = inner_echo0->identifier;
305 case SNAT_PROTOCOL_UDP:
306 case SNAT_PROTOCOL_TCP:
307 key0.port = ((tcp_udp_header_t*)l4_header)->src_port;
310 return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
314 return -1; /* success */
318 * Get address and port values to be used for ICMP packet translation
319 * and create session if needed
321 * @param[in,out] sm NAT main
322 * @param[in,out] node NAT node runtime
323 * @param[in] thread_index thread index
324 * @param[in,out] b0 buffer containing packet to be translated
325 * @param[out] p_proto protocol used for matching
326 * @param[out] p_value address and port after NAT translation
327 * @param[out] p_dont_translate if packet should not be translated
328 * @param d optional parameter
329 * @param e optional parameter
331 u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node,
332 u32 thread_index, vlib_buffer_t *b0,
333 ip4_header_t *ip0, u8 *p_proto,
334 snat_session_key_t *p_value,
335 u8 *p_dont_translate, void *d, void *e)
337 icmp46_header_t *icmp0;
340 snat_session_key_t key0;
341 snat_session_key_t sm0;
342 snat_session_t *s0 = 0;
343 u8 dont_translate = 0;
344 clib_bihash_kv_8_8_t kv0, value0;
349 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
350 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
351 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
355 err = icmp_get_key (ip0, &key0);
358 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
359 next0 = SNAT_OUT2IN_NEXT_DROP;
362 key0.fib_index = rx_fib_index0;
364 kv0.key = key0.as_u64;
366 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
369 /* Try to match static mapping by external address and port,
370 destination address and port in packet */
371 if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0))
373 if (!sm->forwarding_enabled)
375 /* Don't NAT packet aimed at the intfc address */
376 if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
377 ip0->dst_address.as_u32)))
382 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
383 next0 = SNAT_OUT2IN_NEXT_DROP;
393 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
394 (icmp0->type != ICMP4_echo_request || !is_addr_only)))
396 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
397 next0 = SNAT_OUT2IN_NEXT_DROP;
401 /* Create session initiated by host from external network */
402 s0 = create_session_for_static_mapping(sm, b0, sm0, key0,
404 vlib_time_now (sm->vlib_main));
408 next0 = SNAT_OUT2IN_NEXT_DROP;
414 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
415 icmp0->type != ICMP4_echo_request &&
416 !icmp_is_error_message (icmp0)))
418 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
419 next0 = SNAT_OUT2IN_NEXT_DROP;
423 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
428 *p_proto = key0.protocol;
430 *p_value = s0->in2out;
431 *p_dont_translate = dont_translate;
433 *(snat_session_t**)d = s0;
438 * Get address and port values to be used for ICMP packet translation
440 * @param[in] sm NAT main
441 * @param[in,out] node NAT node runtime
442 * @param[in] thread_index thread index
443 * @param[in,out] b0 buffer containing packet to be translated
444 * @param[out] p_proto protocol used for matching
445 * @param[out] p_value address and port after NAT translation
446 * @param[out] p_dont_translate if packet should not be translated
447 * @param d optional parameter
448 * @param e optional parameter
450 u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node,
451 u32 thread_index, vlib_buffer_t *b0,
452 ip4_header_t *ip0, u8 *p_proto,
453 snat_session_key_t *p_value,
454 u8 *p_dont_translate, void *d, void *e)
456 icmp46_header_t *icmp0;
459 snat_session_key_t key0;
460 snat_session_key_t sm0;
461 u8 dont_translate = 0;
466 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
467 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
468 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
470 err = icmp_get_key (ip0, &key0);
473 b0->error = node->errors[err];
474 next0 = SNAT_OUT2IN_NEXT_DROP;
477 key0.fib_index = rx_fib_index0;
479 if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0))
481 /* Don't NAT packet aimed at the intfc address */
482 if (is_interface_addr(sm, node, sw_if_index0, ip0->dst_address.as_u32))
487 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
488 next0 = SNAT_OUT2IN_NEXT_DROP;
492 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
493 (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
494 !icmp_is_error_message (icmp0)))
496 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
497 next0 = SNAT_OUT2IN_NEXT_DROP;
504 *p_proto = key0.protocol;
505 *p_dont_translate = dont_translate;
509 static inline u32 icmp_out2in (snat_main_t *sm,
512 icmp46_header_t * icmp0,
515 vlib_node_runtime_t * node,
521 snat_session_key_t sm0;
523 icmp_echo_header_t *echo0, *inner_echo0 = 0;
524 ip4_header_t *inner_ip0 = 0;
526 icmp46_header_t *inner_icmp0;
528 u32 new_addr0, old_addr0;
529 u16 old_id0, new_id0;
534 echo0 = (icmp_echo_header_t *)(icmp0+1);
536 next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0, ip0,
537 &protocol, &sm0, &dont_translate, d, e);
540 if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
543 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
545 sum0 = ip_incremental_checksum (0, icmp0,
546 ntohs(ip0->length) - ip4_header_bytes (ip0));
547 checksum0 = ~ip_csum_fold (sum0);
548 if (checksum0 != 0 && checksum0 != 0xffff)
550 next0 = SNAT_OUT2IN_NEXT_DROP;
555 old_addr0 = ip0->dst_address.as_u32;
556 new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
557 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
559 sum0 = ip0->checksum;
560 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
561 dst_address /* changed member */);
562 ip0->checksum = ip_csum_fold (sum0);
564 if (icmp0->checksum == 0)
565 icmp0->checksum = 0xffff;
567 if (!icmp_is_error_message (icmp0))
570 if (PREDICT_FALSE(new_id0 != echo0->identifier))
572 old_id0 = echo0->identifier;
574 echo0->identifier = new_id0;
576 sum0 = icmp0->checksum;
577 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
578 identifier /* changed member */);
579 icmp0->checksum = ip_csum_fold (sum0);
584 inner_ip0 = (ip4_header_t *)(echo0+1);
585 l4_header = ip4_next_header (inner_ip0);
587 if (!ip4_header_checksum_is_valid (inner_ip0))
589 next0 = SNAT_OUT2IN_NEXT_DROP;
593 old_addr0 = inner_ip0->src_address.as_u32;
594 inner_ip0->src_address = sm0.addr;
595 new_addr0 = inner_ip0->src_address.as_u32;
597 sum0 = icmp0->checksum;
598 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
599 src_address /* changed member */);
600 icmp0->checksum = ip_csum_fold (sum0);
604 case SNAT_PROTOCOL_ICMP:
605 inner_icmp0 = (icmp46_header_t*)l4_header;
606 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
608 old_id0 = inner_echo0->identifier;
610 inner_echo0->identifier = new_id0;
612 sum0 = icmp0->checksum;
613 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
615 icmp0->checksum = ip_csum_fold (sum0);
617 case SNAT_PROTOCOL_UDP:
618 case SNAT_PROTOCOL_TCP:
619 old_id0 = ((tcp_udp_header_t*)l4_header)->src_port;
621 ((tcp_udp_header_t*)l4_header)->src_port = new_id0;
623 sum0 = icmp0->checksum;
624 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
626 icmp0->checksum = ip_csum_fold (sum0);
638 static inline u32 icmp_out2in_slow_path (snat_main_t *sm,
641 icmp46_header_t * icmp0,
644 vlib_node_runtime_t * node,
647 snat_session_t ** p_s0)
649 next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
650 next0, thread_index, p_s0, 0);
651 snat_session_t * s0 = *p_s0;
652 if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0))
655 nat44_session_update_counters (s0, now,
656 vlib_buffer_length_in_chain (sm->vlib_main, b0));
657 /* Per-user LRU list maintenance */
658 nat44_session_update_lru (sm, s0, thread_index);
664 nat_out2in_sm_unknown_proto (snat_main_t *sm,
669 clib_bihash_kv_8_8_t kv, value;
670 snat_static_mapping_t *m;
671 snat_session_key_t m_key;
672 u32 old_addr, new_addr;
675 m_key.addr = ip->dst_address;
679 kv.key = m_key.as_u64;
680 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
683 m = pool_elt_at_index (sm->static_mappings, value.value);
685 old_addr = ip->dst_address.as_u32;
686 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
688 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
689 ip->checksum = ip_csum_fold (sum);
691 vnet_buffer(b)->sw_if_index[VLIB_TX] = m->fib_index;
696 snat_out2in_node_fn (vlib_main_t * vm,
697 vlib_node_runtime_t * node,
698 vlib_frame_t * frame)
700 u32 n_left_from, * from, * to_next;
701 snat_out2in_next_t next_index;
702 u32 pkts_processed = 0;
703 snat_main_t * sm = &snat_main;
704 f64 now = vlib_time_now (vm);
705 u32 thread_index = vm->thread_index;
707 from = vlib_frame_vector_args (frame);
708 n_left_from = frame->n_vectors;
709 next_index = node->cached_next_index;
711 while (n_left_from > 0)
715 vlib_get_next_frame (vm, node, next_index,
716 to_next, n_left_to_next);
718 while (n_left_from >= 4 && n_left_to_next >= 2)
721 vlib_buffer_t * b0, * b1;
722 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
723 u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
724 u32 sw_if_index0, sw_if_index1;
725 ip4_header_t * ip0, *ip1;
726 ip_csum_t sum0, sum1;
727 u32 new_addr0, old_addr0;
728 u16 new_port0, old_port0;
729 u32 new_addr1, old_addr1;
730 u16 new_port1, old_port1;
731 udp_header_t * udp0, * udp1;
732 tcp_header_t * tcp0, * tcp1;
733 icmp46_header_t * icmp0, * icmp1;
734 snat_session_key_t key0, key1, sm0, sm1;
735 u32 rx_fib_index0, rx_fib_index1;
737 snat_session_t * s0 = 0, * s1 = 0;
738 clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
740 /* Prefetch next iteration. */
742 vlib_buffer_t * p2, * p3;
744 p2 = vlib_get_buffer (vm, from[2]);
745 p3 = vlib_get_buffer (vm, from[3]);
747 vlib_prefetch_buffer_header (p2, LOAD);
748 vlib_prefetch_buffer_header (p3, LOAD);
750 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
751 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
754 /* speculatively enqueue b0 and b1 to the current next frame */
755 to_next[0] = bi0 = from[0];
756 to_next[1] = bi1 = from[1];
762 b0 = vlib_get_buffer (vm, bi0);
763 b1 = vlib_get_buffer (vm, bi1);
765 vnet_buffer (b0)->snat.flags = 0;
766 vnet_buffer (b1)->snat.flags = 0;
768 ip0 = vlib_buffer_get_current (b0);
769 udp0 = ip4_next_header (ip0);
770 tcp0 = (tcp_header_t *) udp0;
771 icmp0 = (icmp46_header_t *) udp0;
773 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
774 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
777 if (PREDICT_FALSE(ip0->ttl == 1))
779 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
780 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
781 ICMP4_time_exceeded_ttl_exceeded_in_transit,
783 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
787 proto0 = ip_proto_to_snat_proto (ip0->protocol);
789 if (PREDICT_FALSE (proto0 == ~0))
791 if (nat_out2in_sm_unknown_proto(sm, b0, ip0, rx_fib_index0))
793 if (!sm->forwarding_enabled)
795 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
796 next0 = SNAT_OUT2IN_NEXT_DROP;
802 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
804 next0 = icmp_out2in_slow_path
805 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
806 next0, now, thread_index, &s0);
810 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
812 next0 = SNAT_OUT2IN_NEXT_REASS;
816 key0.addr = ip0->dst_address;
817 key0.port = udp0->dst_port;
818 key0.protocol = proto0;
819 key0.fib_index = rx_fib_index0;
821 kv0.key = key0.as_u64;
823 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
826 /* Try to match static mapping by external address and port,
827 destination address and port in packet */
828 if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0, 0))
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 ==
836 clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
838 vnet_feature_next (&next0, b0);
842 if (!sm->forwarding_enabled)
844 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
845 next0 = SNAT_OUT2IN_NEXT_DROP;
850 /* Create session initiated by host from external network */
851 s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
855 next0 = SNAT_OUT2IN_NEXT_DROP;
860 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
863 old_addr0 = ip0->dst_address.as_u32;
864 ip0->dst_address = s0->in2out.addr;
865 new_addr0 = ip0->dst_address.as_u32;
866 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
868 sum0 = ip0->checksum;
869 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
871 dst_address /* changed member */);
872 ip0->checksum = ip_csum_fold (sum0);
874 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
876 old_port0 = tcp0->dst_port;
877 tcp0->dst_port = s0->in2out.port;
878 new_port0 = tcp0->dst_port;
880 sum0 = tcp0->checksum;
881 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
883 dst_address /* changed member */);
885 sum0 = ip_csum_update (sum0, old_port0, new_port0,
886 ip4_header_t /* cheat */,
887 length /* changed member */);
888 tcp0->checksum = ip_csum_fold(sum0);
892 old_port0 = udp0->dst_port;
893 udp0->dst_port = s0->in2out.port;
898 nat44_session_update_counters (s0, now,
899 vlib_buffer_length_in_chain (vm, b0));
900 /* Per-user LRU list maintenance */
901 nat44_session_update_lru (sm, s0, thread_index);
904 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
905 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
907 snat_out2in_trace_t *t =
908 vlib_add_trace (vm, node, b0, sizeof (*t));
909 t->sw_if_index = sw_if_index0;
910 t->next_index = next0;
911 t->session_index = ~0;
913 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
916 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
919 ip1 = vlib_buffer_get_current (b1);
920 udp1 = ip4_next_header (ip1);
921 tcp1 = (tcp_header_t *) udp1;
922 icmp1 = (icmp46_header_t *) udp1;
924 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
925 rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
928 if (PREDICT_FALSE(ip1->ttl == 1))
930 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
931 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
932 ICMP4_time_exceeded_ttl_exceeded_in_transit,
934 next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
938 proto1 = ip_proto_to_snat_proto (ip1->protocol);
940 if (PREDICT_FALSE (proto1 == ~0))
942 if (nat_out2in_sm_unknown_proto(sm, b1, ip1, rx_fib_index1))
944 if (!sm->forwarding_enabled)
946 b1->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
947 next1 = SNAT_OUT2IN_NEXT_DROP;
953 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
955 next1 = icmp_out2in_slow_path
956 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
957 next1, now, thread_index, &s1);
961 if (PREDICT_FALSE (ip4_is_fragment (ip1)))
963 next1 = SNAT_OUT2IN_NEXT_REASS;
967 key1.addr = ip1->dst_address;
968 key1.port = udp1->dst_port;
969 key1.protocol = proto1;
970 key1.fib_index = rx_fib_index1;
972 kv1.key = key1.as_u64;
974 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
977 /* Try to match static mapping by external address and port,
978 destination address and port in packet */
979 if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0, 0, 0))
982 * Send DHCP packets to the ipv4 stack, or we won't
983 * be able to use dhcp client on the outside interface
985 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
986 && (udp1->dst_port ==
987 clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
989 vnet_feature_next (&next1, b1);
993 if (!sm->forwarding_enabled)
995 b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
996 next1 = SNAT_OUT2IN_NEXT_DROP;
1001 /* Create session initiated by host from external network */
1002 s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node,
1006 next1 = SNAT_OUT2IN_NEXT_DROP;
1011 s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1014 old_addr1 = ip1->dst_address.as_u32;
1015 ip1->dst_address = s1->in2out.addr;
1016 new_addr1 = ip1->dst_address.as_u32;
1017 vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1019 sum1 = ip1->checksum;
1020 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1022 dst_address /* changed member */);
1023 ip1->checksum = ip_csum_fold (sum1);
1025 if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1027 old_port1 = tcp1->dst_port;
1028 tcp1->dst_port = s1->in2out.port;
1029 new_port1 = tcp1->dst_port;
1031 sum1 = tcp1->checksum;
1032 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1034 dst_address /* changed member */);
1036 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1037 ip4_header_t /* cheat */,
1038 length /* changed member */);
1039 tcp1->checksum = ip_csum_fold(sum1);
1043 old_port1 = udp1->dst_port;
1044 udp1->dst_port = s1->in2out.port;
1049 nat44_session_update_counters (s1, now,
1050 vlib_buffer_length_in_chain (vm, b1));
1051 /* Per-user LRU list maintenance */
1052 nat44_session_update_lru (sm, s1, thread_index);
1055 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1056 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1058 snat_out2in_trace_t *t =
1059 vlib_add_trace (vm, node, b1, sizeof (*t));
1060 t->sw_if_index = sw_if_index1;
1061 t->next_index = next1;
1062 t->session_index = ~0;
1064 t->session_index = s1 - sm->per_thread_data[thread_index].sessions;
1067 pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1069 /* verify speculative enqueues, maybe switch current next frame */
1070 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1071 to_next, n_left_to_next,
1072 bi0, bi1, next0, next1);
1075 while (n_left_from > 0 && n_left_to_next > 0)
1079 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1083 u32 new_addr0, old_addr0;
1084 u16 new_port0, old_port0;
1085 udp_header_t * udp0;
1086 tcp_header_t * tcp0;
1087 icmp46_header_t * icmp0;
1088 snat_session_key_t key0, sm0;
1091 snat_session_t * s0 = 0;
1092 clib_bihash_kv_8_8_t kv0, value0;
1094 /* speculatively enqueue b0 to the current next frame */
1100 n_left_to_next -= 1;
1102 b0 = vlib_get_buffer (vm, bi0);
1104 vnet_buffer (b0)->snat.flags = 0;
1106 ip0 = vlib_buffer_get_current (b0);
1107 udp0 = ip4_next_header (ip0);
1108 tcp0 = (tcp_header_t *) udp0;
1109 icmp0 = (icmp46_header_t *) udp0;
1111 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1112 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1115 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1117 if (PREDICT_FALSE (proto0 == ~0))
1119 if (nat_out2in_sm_unknown_proto(sm, b0, ip0, rx_fib_index0))
1121 if (!sm->forwarding_enabled)
1123 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1124 next0 = SNAT_OUT2IN_NEXT_DROP;
1130 if (PREDICT_FALSE(ip0->ttl == 1))
1132 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1133 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1134 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1136 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1140 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1142 next0 = icmp_out2in_slow_path
1143 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1144 next0, now, thread_index, &s0);
1148 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1150 next0 = SNAT_OUT2IN_NEXT_REASS;
1154 key0.addr = ip0->dst_address;
1155 key0.port = udp0->dst_port;
1156 key0.protocol = proto0;
1157 key0.fib_index = rx_fib_index0;
1159 kv0.key = key0.as_u64;
1161 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1164 /* Try to match static mapping by external address and port,
1165 destination address and port in packet */
1166 if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0, 0))
1169 * Send DHCP packets to the ipv4 stack, or we won't
1170 * be able to use dhcp client on the outside interface
1172 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1173 && (udp0->dst_port ==
1174 clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1176 vnet_feature_next (&next0, b0);
1180 if (!sm->forwarding_enabled)
1182 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1183 next0 = SNAT_OUT2IN_NEXT_DROP;
1188 /* Create session initiated by host from external network */
1189 s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1193 next0 = SNAT_OUT2IN_NEXT_DROP;
1198 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1201 old_addr0 = ip0->dst_address.as_u32;
1202 ip0->dst_address = s0->in2out.addr;
1203 new_addr0 = ip0->dst_address.as_u32;
1204 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1206 sum0 = ip0->checksum;
1207 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1209 dst_address /* changed member */);
1210 ip0->checksum = ip_csum_fold (sum0);
1212 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1214 old_port0 = tcp0->dst_port;
1215 tcp0->dst_port = s0->in2out.port;
1216 new_port0 = tcp0->dst_port;
1218 sum0 = tcp0->checksum;
1219 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1221 dst_address /* changed member */);
1223 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1224 ip4_header_t /* cheat */,
1225 length /* changed member */);
1226 tcp0->checksum = ip_csum_fold(sum0);
1230 old_port0 = udp0->dst_port;
1231 udp0->dst_port = s0->in2out.port;
1236 nat44_session_update_counters (s0, now,
1237 vlib_buffer_length_in_chain (vm, b0));
1238 /* Per-user LRU list maintenance */
1239 nat44_session_update_lru (sm, s0, thread_index);
1242 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1243 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1245 snat_out2in_trace_t *t =
1246 vlib_add_trace (vm, node, b0, sizeof (*t));
1247 t->sw_if_index = sw_if_index0;
1248 t->next_index = next0;
1249 t->session_index = ~0;
1251 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1254 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1256 /* verify speculative enqueue, maybe switch current next frame */
1257 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1258 to_next, n_left_to_next,
1262 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1265 vlib_node_increment_counter (vm, snat_out2in_node.index,
1266 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1268 return frame->n_vectors;
1271 VLIB_REGISTER_NODE (snat_out2in_node) = {
1272 .function = snat_out2in_node_fn,
1273 .name = "nat44-out2in",
1274 .vector_size = sizeof (u32),
1275 .format_trace = format_snat_out2in_trace,
1276 .type = VLIB_NODE_TYPE_INTERNAL,
1278 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1279 .error_strings = snat_out2in_error_strings,
1281 .runtime_data_bytes = sizeof (snat_runtime_t),
1283 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1285 /* edit / add dispositions here */
1287 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1288 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1289 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1290 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1293 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
1296 nat44_out2in_reass_node_fn (vlib_main_t * vm,
1297 vlib_node_runtime_t * node,
1298 vlib_frame_t * frame)
1300 u32 n_left_from, *from, *to_next;
1301 snat_out2in_next_t next_index;
1302 u32 pkts_processed = 0;
1303 snat_main_t *sm = &snat_main;
1304 f64 now = vlib_time_now (vm);
1305 u32 thread_index = vm->thread_index;
1306 snat_main_per_thread_data_t *per_thread_data =
1307 &sm->per_thread_data[thread_index];
1308 u32 *fragments_to_drop = 0;
1309 u32 *fragments_to_loopback = 0;
1311 from = vlib_frame_vector_args (frame);
1312 n_left_from = frame->n_vectors;
1313 next_index = node->cached_next_index;
1315 while (n_left_from > 0)
1319 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1321 while (n_left_from > 0 && n_left_to_next > 0)
1323 u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1328 nat_reass_ip4_t *reass0;
1329 udp_header_t * udp0;
1330 tcp_header_t * tcp0;
1331 snat_session_key_t key0, sm0;
1332 clib_bihash_kv_8_8_t kv0, value0;
1333 snat_session_t * s0 = 0;
1334 u16 old_port0, new_port0;
1337 /* speculatively enqueue b0 to the current next frame */
1343 n_left_to_next -= 1;
1345 b0 = vlib_get_buffer (vm, bi0);
1346 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1348 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1349 rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1352 if (PREDICT_FALSE (nat_reass_is_drop_frag(0)))
1354 next0 = SNAT_OUT2IN_NEXT_DROP;
1355 b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1359 ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1360 udp0 = ip4_next_header (ip0);
1361 tcp0 = (tcp_header_t *) udp0;
1362 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1364 reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1369 &fragments_to_drop);
1371 if (PREDICT_FALSE (!reass0))
1373 next0 = SNAT_OUT2IN_NEXT_DROP;
1374 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1375 nat_log_notice ("maximum reassemblies exceeded");
1379 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1381 key0.addr = ip0->dst_address;
1382 key0.port = udp0->dst_port;
1383 key0.protocol = proto0;
1384 key0.fib_index = rx_fib_index0;
1385 kv0.key = key0.as_u64;
1387 if (clib_bihash_search_8_8 (&per_thread_data->out2in, &kv0, &value0))
1389 /* Try to match static mapping by external address and port,
1390 destination address and port in packet */
1391 if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0, 0))
1394 * Send DHCP packets to the ipv4 stack, or we won't
1395 * be able to use dhcp client on the outside interface
1397 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1399 == clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1401 vnet_feature_next (&next0, b0);
1405 if (!sm->forwarding_enabled)
1407 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1408 next0 = SNAT_OUT2IN_NEXT_DROP;
1413 /* Create session initiated by host from external network */
1414 s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1418 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1419 next0 = SNAT_OUT2IN_NEXT_DROP;
1422 reass0->sess_index = s0 - per_thread_data->sessions;
1423 reass0->thread_index = thread_index;
1427 s0 = pool_elt_at_index (per_thread_data->sessions,
1429 reass0->sess_index = value0.value;
1431 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1435 if (PREDICT_FALSE (reass0->sess_index == (u32) ~0))
1437 if (nat_ip4_reass_add_fragment (reass0, bi0, &fragments_to_drop))
1439 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1440 nat_log_notice ("maximum fragments per reassembly exceeded");
1441 next0 = SNAT_OUT2IN_NEXT_DROP;
1447 s0 = pool_elt_at_index (per_thread_data->sessions,
1448 reass0->sess_index);
1451 old_addr0 = ip0->dst_address.as_u32;
1452 ip0->dst_address = s0->in2out.addr;
1453 new_addr0 = ip0->dst_address.as_u32;
1454 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1456 sum0 = ip0->checksum;
1457 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1459 dst_address /* changed member */);
1460 ip0->checksum = ip_csum_fold (sum0);
1462 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1464 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1466 old_port0 = tcp0->dst_port;
1467 tcp0->dst_port = s0->in2out.port;
1468 new_port0 = tcp0->dst_port;
1470 sum0 = tcp0->checksum;
1471 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1473 dst_address /* changed member */);
1475 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1476 ip4_header_t /* cheat */,
1477 length /* changed member */);
1478 tcp0->checksum = ip_csum_fold(sum0);
1482 old_port0 = udp0->dst_port;
1483 udp0->dst_port = s0->in2out.port;
1489 nat44_session_update_counters (s0, now,
1490 vlib_buffer_length_in_chain (vm, b0));
1491 /* Per-user LRU list maintenance */
1492 nat44_session_update_lru (sm, s0, thread_index);
1495 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1496 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1498 nat44_out2in_reass_trace_t *t =
1499 vlib_add_trace (vm, node, b0, sizeof (*t));
1500 t->cached = cached0;
1501 t->sw_if_index = sw_if_index0;
1502 t->next_index = next0;
1512 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1514 /* verify speculative enqueue, maybe switch current next frame */
1515 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1516 to_next, n_left_to_next,
1520 if (n_left_from == 0 && vec_len (fragments_to_loopback))
1522 from = vlib_frame_vector_args (frame);
1523 u32 len = vec_len (fragments_to_loopback);
1524 if (len <= VLIB_FRAME_SIZE)
1526 clib_memcpy (from, fragments_to_loopback, sizeof (u32) * len);
1528 vec_reset_length (fragments_to_loopback);
1533 fragments_to_loopback + (len - VLIB_FRAME_SIZE),
1534 sizeof (u32) * VLIB_FRAME_SIZE);
1535 n_left_from = VLIB_FRAME_SIZE;
1536 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1541 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1544 vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1545 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1548 nat_send_all_to_node (vm, fragments_to_drop, node,
1549 &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1550 SNAT_OUT2IN_NEXT_DROP);
1552 vec_free (fragments_to_drop);
1553 vec_free (fragments_to_loopback);
1554 return frame->n_vectors;
1557 VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
1558 .function = nat44_out2in_reass_node_fn,
1559 .name = "nat44-out2in-reass",
1560 .vector_size = sizeof (u32),
1561 .format_trace = format_nat44_out2in_reass_trace,
1562 .type = VLIB_NODE_TYPE_INTERNAL,
1564 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1565 .error_strings = snat_out2in_error_strings,
1567 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1569 /* edit / add dispositions here */
1571 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1572 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1573 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1574 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1577 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
1578 nat44_out2in_reass_node_fn);
1580 /*******************************/
1581 /*** endpoint-dependent mode ***/
1582 /*******************************/
1584 NAT44_ED_OUT2IN_NEXT_DROP,
1585 NAT44_ED_OUT2IN_NEXT_LOOKUP,
1586 NAT44_ED_OUT2IN_NEXT_ICMP_ERROR,
1587 NAT44_ED_OUT2IN_NEXT_IN2OUT,
1588 NAT44_ED_OUT2IN_NEXT_SLOW_PATH,
1589 NAT44_ED_OUT2IN_NEXT_REASS,
1590 NAT44_ED_OUT2IN_N_NEXT,
1591 } nat44_ed_out2in_next_t;
1598 } nat44_ed_out2in_trace_t;
1601 format_nat44_ed_out2in_trace (u8 * s, va_list * args)
1603 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1604 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1605 nat44_ed_out2in_trace_t *t = va_arg (*args, nat44_ed_out2in_trace_t *);
1608 tag = t->is_slow_path ? "NAT44_OUT2IN_SLOW_PATH" : "NAT44_OUT2IN_FAST_PATH";
1610 s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
1611 t->sw_if_index, t->next_index, t->session_index);
1617 icmp_out2in_ed_slow_path (snat_main_t * sm, vlib_buffer_t * b0,
1618 ip4_header_t * ip0, icmp46_header_t * icmp0,
1619 u32 sw_if_index0, u32 rx_fib_index0,
1620 vlib_node_runtime_t * node, u32 next0, f64 now,
1621 u32 thread_index, snat_session_t ** p_s0)
1623 next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1624 next0, thread_index, p_s0, 0);
1625 snat_session_t * s0 = *p_s0;
1626 if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0))
1629 nat44_session_update_counters (s0, now,
1630 vlib_buffer_length_in_chain (sm->vlib_main, b0));
1636 nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void * arg)
1638 snat_main_t *sm = &snat_main;
1639 nat44_is_idle_session_ctx_t *ctx = arg;
1641 u64 sess_timeout_time;
1642 nat_ed_ses_key_t ed_key;
1643 clib_bihash_kv_16_8_t ed_kv;
1646 snat_session_key_t key;
1647 snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
1650 s = pool_elt_at_index (tsm->sessions, kv->value);
1651 sess_timeout_time = s->last_heard + (f64)nat44_session_get_timeout(sm, s);
1652 if (ctx->now >= sess_timeout_time)
1654 ed_key.l_addr = s->in2out.addr;
1655 ed_key.r_addr = s->ext_host_addr;
1656 ed_key.fib_index = s->out2in.fib_index;
1657 if (snat_is_unk_proto_session (s))
1659 ed_key.proto = s->in2out.port;
1665 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
1666 ed_key.l_port = s->in2out.port;
1667 ed_key.r_port = s->ext_host_port;
1669 if (is_twice_nat_session (s))
1671 ed_key.r_addr = s->ext_host_nat_addr;
1672 ed_key.r_port = s->ext_host_nat_port;
1674 ed_kv.key[0] = ed_key.as_u64[0];
1675 ed_kv.key[1] = ed_key.as_u64[1];
1676 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
1677 nat_log_warn ("in2out_ed key del failed");
1679 if (snat_is_unk_proto_session (s))
1682 snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
1683 s->out2in.addr.as_u32,
1687 s->in2out.fib_index);
1689 if (is_twice_nat_session (s))
1691 for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
1693 key.protocol = s->in2out.protocol;
1694 key.port = s->ext_host_nat_port;
1695 a = sm->twice_nat_addresses + i;
1696 if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
1698 snat_free_outside_address_and_port (sm->twice_nat_addresses,
1699 ctx->thread_index, &key);
1705 if (snat_is_session_static (s))
1708 if (s->outside_address_index != ~0)
1709 snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
1712 nat44_delete_session (sm, s, ctx->thread_index);
1719 static snat_session_t *
1720 create_session_for_static_mapping_ed (snat_main_t * sm,
1722 snat_session_key_t l_key,
1723 snat_session_key_t e_key,
1724 vlib_node_runtime_t * node,
1726 twice_nat_type_t twice_nat,
1727 lb_nat_type_t lb_nat,
1734 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1735 clib_bihash_kv_16_8_t kv;
1736 snat_session_key_t eh_key;
1738 nat44_is_idle_session_ctx_t ctx;
1740 if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
1742 b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
1743 nat_log_notice ("maximum sessions exceeded");
1747 u = nat_user_get_or_create (sm, &l_key.addr, l_key.fib_index, thread_index);
1750 nat_log_warn ("create NAT user failed");
1754 s = nat_ed_session_alloc (sm, u, thread_index);
1757 nat44_delete_user_with_no_session (sm, u, thread_index);
1758 nat_log_warn ("create NAT session failed");
1762 ip = vlib_buffer_get_current (b);
1763 udp = ip4_next_header (ip);
1765 s->ext_host_addr.as_u32 = ip->src_address.as_u32;
1766 s->ext_host_port = e_key.protocol == SNAT_PROTOCOL_ICMP ? 0 : udp->src_port;
1767 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
1769 s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
1770 if (lb_nat == AFFINITY_LB_NAT)
1771 s->flags |= SNAT_SESSION_FLAG_AFFINITY;
1772 s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
1773 s->outside_address_index = ~0;
1776 s->in2out.protocol = s->out2in.protocol;
1777 user_session_increment (sm, u, 1);
1779 /* Add to lookup tables */
1780 make_ed_kv (&kv, &e_key.addr, &s->ext_host_addr, ip->protocol,
1781 e_key.fib_index, e_key.port, s->ext_host_port);
1782 kv.value = s - tsm->sessions;
1784 ctx.thread_index = thread_index;
1785 if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, &kv,
1786 nat44_o2i_ed_is_idle_session_cb,
1788 nat_log_notice ("out2in-ed key add failed");
1790 if (twice_nat == TWICE_NAT || (twice_nat == TWICE_NAT_SELF &&
1791 ip->src_address.as_u32 == l_key.addr.as_u32))
1793 eh_key.protocol = e_key.protocol;
1794 if (snat_alloc_outside_address_and_port (sm->twice_nat_addresses, 0,
1795 thread_index, &eh_key,
1797 sm->port_per_thread,
1798 tsm->snat_thread_index))
1800 b->error = node->errors[SNAT_OUT2IN_ERROR_OUT_OF_PORTS];
1801 nat44_delete_session (sm, s, thread_index);
1802 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 0))
1803 nat_log_notice ("out2in-ed key del failed");
1806 s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32;
1807 s->ext_host_nat_port = eh_key.port;
1808 s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
1809 make_ed_kv (&kv, &l_key.addr, &s->ext_host_nat_addr, ip->protocol,
1810 l_key.fib_index, l_key.port, s->ext_host_nat_port);
1814 make_ed_kv (&kv, &l_key.addr, &s->ext_host_addr, ip->protocol,
1815 l_key.fib_index, l_key.port, s->ext_host_port);
1817 kv.value = s - tsm->sessions;
1818 if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &kv,
1819 nat44_i2o_ed_is_idle_session_cb,
1821 nat_log_notice ("in2out-ed key add failed");
1826 static_always_inline int
1827 icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0)
1829 icmp46_header_t *icmp0;
1830 nat_ed_ses_key_t key0;
1831 icmp_echo_header_t *echo0, *inner_echo0 = 0;
1832 ip4_header_t *inner_ip0;
1833 void *l4_header = 0;
1834 icmp46_header_t *inner_icmp0;
1836 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
1837 echo0 = (icmp_echo_header_t *)(icmp0+1);
1839 if (!icmp_is_error_message (icmp0))
1841 key0.proto = IP_PROTOCOL_ICMP;
1842 key0.l_addr = ip0->dst_address;
1843 key0.r_addr = ip0->src_address;
1844 key0.l_port = echo0->identifier;
1849 inner_ip0 = (ip4_header_t *)(echo0+1);
1850 l4_header = ip4_next_header (inner_ip0);
1851 key0.proto = inner_ip0->protocol;
1852 key0.l_addr = inner_ip0->src_address;
1853 key0.r_addr = inner_ip0->dst_address;
1854 switch (ip_proto_to_snat_proto (inner_ip0->protocol))
1856 case SNAT_PROTOCOL_ICMP:
1857 inner_icmp0 = (icmp46_header_t*)l4_header;
1858 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
1859 key0.l_port = inner_echo0->identifier;
1862 case SNAT_PROTOCOL_UDP:
1863 case SNAT_PROTOCOL_TCP:
1864 key0.l_port = ((tcp_udp_header_t*)l4_header)->src_port;
1865 key0.r_port = ((tcp_udp_header_t*)l4_header)->dst_port;
1876 next_src_nat (snat_main_t * sm, ip4_header_t * ip, u8 proto, u16 src_port,
1877 u16 dst_port, u32 thread_index, u32 rx_fib_index)
1879 clib_bihash_kv_16_8_t kv, value;
1880 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1882 make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto,
1883 rx_fib_index, src_port, dst_port);
1884 if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
1891 create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index,
1894 nat_ed_ses_key_t key;
1895 clib_bihash_kv_16_8_t kv, value;
1898 snat_session_t *s = 0;
1899 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1900 f64 now = vlib_time_now (sm->vlib_main);
1902 if (ip->protocol == IP_PROTOCOL_ICMP)
1904 if (icmp_get_ed_key (ip, &key))
1907 else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
1909 udp = ip4_next_header(ip);
1910 key.r_addr = ip->src_address;
1911 key.l_addr = ip->dst_address;
1912 key.proto = ip->protocol;
1913 key.l_port = udp->dst_port;
1914 key.r_port = udp->src_port;
1918 key.r_addr = ip->src_address;
1919 key.l_addr = ip->dst_address;
1920 key.proto = ip->protocol;
1921 key.l_port = key.r_port = 0;
1924 kv.key[0] = key.as_u64[0];
1925 kv.key[1] = key.as_u64[1];
1927 if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
1929 s = pool_elt_at_index (tsm->sessions, value.value);
1933 if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
1936 u = nat_user_get_or_create (sm, &ip->dst_address, sm->inside_fib_index,
1940 nat_log_warn ("create NAT user failed");
1944 s = nat_ed_session_alloc (sm, u, thread_index);
1947 nat44_delete_user_with_no_session (sm, u, thread_index);
1948 nat_log_warn ("create NAT session failed");
1952 s->ext_host_addr = key.r_addr;
1953 s->ext_host_port = key.r_port;
1954 s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS;
1955 s->outside_address_index = ~0;
1956 s->out2in.addr = key.l_addr;
1957 s->out2in.port = key.l_port;
1958 s->out2in.protocol = ip_proto_to_snat_proto (key.proto);
1959 s->out2in.fib_index = 0;
1960 s->in2out = s->out2in;
1961 user_session_increment (sm, u, 0);
1963 kv.value = s - tsm->sessions;
1964 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
1965 nat_log_notice ("in2out_ed key add failed");
1968 if (ip->protocol == IP_PROTOCOL_TCP)
1970 tcp_header_t *tcp = ip4_next_header(ip);
1971 if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index))
1976 nat44_session_update_counters (s, now, 0);
1980 icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
1981 u32 thread_index, vlib_buffer_t * b, ip4_header_t * ip,
1982 u8 * p_proto, snat_session_key_t * p_value,
1983 u8 * p_dont_translate, void * d, void * e)
1985 u32 next = ~0, sw_if_index, rx_fib_index;
1986 icmp46_header_t *icmp;
1987 nat_ed_ses_key_t key;
1988 clib_bihash_kv_16_8_t kv, value;
1989 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1990 snat_session_t *s = 0;
1991 u8 dont_translate = 0, is_addr_only;
1992 snat_session_key_t e_key, l_key;
1994 icmp = (icmp46_header_t *) ip4_next_header (ip);
1995 sw_if_index = vnet_buffer(b)->sw_if_index[VLIB_RX];
1996 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
1998 if (icmp_get_ed_key (ip, &key))
2000 b->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
2001 next = SNAT_OUT2IN_NEXT_DROP;
2004 key.fib_index = rx_fib_index;
2005 kv.key[0] = key.as_u64[0];
2006 kv.key[1] = key.as_u64[1];
2008 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
2010 /* Try to match static mapping */
2011 e_key.addr = ip->dst_address;
2012 e_key.port = key.l_port;
2013 e_key.protocol = ip_proto_to_snat_proto (key.proto);
2014 e_key.fib_index = rx_fib_index;
2015 if (snat_static_mapping_match(sm, e_key, &l_key, 1, &is_addr_only, 0, 0, 0))
2017 if (!sm->forwarding_enabled)
2019 /* Don't NAT packet aimed at the intfc address */
2020 if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index,
2021 ip->dst_address.as_u32)))
2026 b->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2027 next = NAT44_ED_OUT2IN_NEXT_DROP;
2033 if (next_src_nat(sm, ip, key.proto, key.l_port, key.r_port,
2034 thread_index, rx_fib_index))
2036 next = NAT44_ED_OUT2IN_NEXT_IN2OUT;
2039 create_bypass_for_fwd(sm, ip, rx_fib_index, thread_index);
2044 if (PREDICT_FALSE(icmp->type != ICMP4_echo_reply &&
2045 (icmp->type != ICMP4_echo_request || !is_addr_only)))
2047 b->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
2048 next = NAT44_ED_OUT2IN_NEXT_DROP;
2052 /* Create session initiated by host from external network */
2053 s = create_session_for_static_mapping_ed(sm, b, l_key, e_key, node,
2055 vlib_time_now (sm->vlib_main));
2059 next = NAT44_ED_OUT2IN_NEXT_DROP;
2065 if (PREDICT_FALSE(icmp->type != ICMP4_echo_reply &&
2066 icmp->type != ICMP4_echo_request &&
2067 !icmp_is_error_message (icmp)))
2069 b->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
2070 next = SNAT_OUT2IN_NEXT_DROP;
2074 s = pool_elt_at_index (tsm->sessions, value.value);
2077 *p_proto = ip_proto_to_snat_proto (key.proto);
2080 *p_value = s->in2out;
2081 *p_dont_translate = dont_translate;
2083 *(snat_session_t**)d = s;
2087 static snat_session_t *
2088 nat44_ed_out2in_unknown_proto (snat_main_t *sm,
2095 vlib_node_runtime_t * node)
2097 clib_bihash_kv_8_8_t kv, value;
2098 clib_bihash_kv_16_8_t s_kv, s_value;
2099 snat_static_mapping_t *m;
2100 u32 old_addr, new_addr;
2103 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
2106 old_addr = ip->dst_address.as_u32;
2108 make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol,
2109 rx_fib_index, 0, 0);
2111 if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
2113 s = pool_elt_at_index (tsm->sessions, s_value.value);
2114 new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
2118 if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
2120 b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
2121 nat_log_notice ("maximum sessions exceeded");
2125 make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
2126 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2128 b->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2132 m = pool_elt_at_index (sm->static_mappings, value.value);
2134 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
2136 u = nat_user_get_or_create (sm, &m->local_addr, m->fib_index,
2140 nat_log_warn ("create NAT user failed");
2144 /* Create a new session */
2145 s = nat_ed_session_alloc (sm, u, thread_index);
2148 nat44_delete_user_with_no_session (sm, u, thread_index);
2149 nat_log_warn ("create NAT session failed");
2153 s->ext_host_addr.as_u32 = ip->src_address.as_u32;
2154 s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
2155 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
2156 s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
2157 s->outside_address_index = ~0;
2158 s->out2in.addr.as_u32 = old_addr;
2159 s->out2in.fib_index = rx_fib_index;
2160 s->in2out.addr.as_u32 = new_addr;
2161 s->in2out.fib_index = m->fib_index;
2162 s->in2out.port = s->out2in.port = ip->protocol;
2163 user_session_increment (sm, u, 1);
2165 /* Add to lookup tables */
2166 s_kv.value = s - tsm->sessions;
2167 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
2168 nat_log_notice ("out2in key add failed");
2170 make_ed_kv (&s_kv, &ip->dst_address, &ip->src_address, ip->protocol,
2171 m->fib_index, 0, 0);
2172 s_kv.value = s - tsm->sessions;
2173 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
2174 nat_log_notice ("in2out key add failed");
2177 /* Update IP checksum */
2179 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
2180 ip->checksum = ip_csum_fold (sum);
2182 vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
2185 nat44_session_update_counters (s, now,
2186 vlib_buffer_length_in_chain (vm, b));
2192 nat44_ed_out2in_node_fn_inline (vlib_main_t * vm,
2193 vlib_node_runtime_t * node,
2194 vlib_frame_t * frame, int is_slow_path)
2196 u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
2197 nat44_ed_out2in_next_t next_index;
2198 snat_main_t *sm = &snat_main;
2199 f64 now = vlib_time_now (vm);
2200 u32 thread_index = vm->thread_index;
2201 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
2203 stats_node_index = is_slow_path ? nat44_ed_out2in_slowpath_node.index :
2204 nat44_ed_out2in_node.index;
2206 from = vlib_frame_vector_args (frame);
2207 n_left_from = frame->n_vectors;
2208 next_index = node->cached_next_index;
2210 while (n_left_from > 0)
2214 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2216 while (n_left_from >= 4 && n_left_to_next >= 2)
2219 vlib_buffer_t *b0, *b1;
2220 u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0, new_addr0;
2221 u32 next1, sw_if_index1, rx_fib_index1, proto1, old_addr1, new_addr1;
2222 u16 old_port0, new_port0, old_port1, new_port1;
2223 ip4_header_t *ip0, *ip1;
2224 udp_header_t *udp0, *udp1;
2225 tcp_header_t *tcp0, *tcp1;
2226 icmp46_header_t *icmp0, *icmp1;
2227 snat_session_t *s0 = 0, *s1 = 0;
2228 clib_bihash_kv_16_8_t kv0, value0, kv1, value1;
2229 ip_csum_t sum0, sum1;
2230 snat_session_key_t e_key0, l_key0, e_key1, l_key1;
2231 lb_nat_type_t lb_nat0, lb_nat1;
2232 twice_nat_type_t twice_nat0, twice_nat1;
2234 /* Prefetch next iteration. */
2236 vlib_buffer_t * p2, * p3;
2238 p2 = vlib_get_buffer (vm, from[2]);
2239 p3 = vlib_get_buffer (vm, from[3]);
2241 vlib_prefetch_buffer_header (p2, LOAD);
2242 vlib_prefetch_buffer_header (p3, LOAD);
2244 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
2245 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
2248 /* speculatively enqueue b0 and b1 to the current next frame */
2249 to_next[0] = bi0 = from[0];
2250 to_next[1] = bi1 = from[1];
2254 n_left_to_next -= 2;
2256 b0 = vlib_get_buffer (vm, bi0);
2257 b1 = vlib_get_buffer (vm, bi1);
2259 next0 = NAT44_ED_OUT2IN_NEXT_LOOKUP;
2260 vnet_buffer (b0)->snat.flags = 0;
2261 ip0 = vlib_buffer_get_current (b0);
2263 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2264 rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2267 if (PREDICT_FALSE(ip0->ttl == 1))
2269 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2270 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2271 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2273 next0 = NAT44_ED_OUT2IN_NEXT_ICMP_ERROR;
2277 udp0 = ip4_next_header (ip0);
2278 tcp0 = (tcp_header_t *) udp0;
2279 icmp0 = (icmp46_header_t *) udp0;
2280 proto0 = ip_proto_to_snat_proto (ip0->protocol);
2284 if (PREDICT_FALSE (proto0 == ~0))
2286 s0 = nat44_ed_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
2287 thread_index, now, vm, node);
2288 if (!sm->forwarding_enabled)
2291 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2296 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2298 next0 = icmp_out2in_ed_slow_path
2299 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
2300 next0, now, thread_index, &s0);
2306 if (PREDICT_FALSE (proto0 == ~0))
2308 next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
2312 if (ip4_is_fragment (ip0))
2314 next0 = NAT44_ED_OUT2IN_NEXT_REASS;
2318 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2320 next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
2325 make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address, ip0->protocol,
2326 rx_fib_index0, udp0->dst_port, udp0->src_port);
2328 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
2332 /* Try to match static mapping by external address and port,
2333 destination address and port in packet */
2334 e_key0.addr = ip0->dst_address;
2335 e_key0.port = udp0->dst_port;
2336 e_key0.protocol = proto0;
2337 e_key0.fib_index = rx_fib_index0;
2338 if (snat_static_mapping_match(sm, e_key0, &l_key0, 1, 0,
2339 &twice_nat0, &lb_nat0, &ip0->src_address))
2342 * Send DHCP packets to the ipv4 stack, or we won't
2343 * be able to use dhcp client on the outside interface
2345 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
2346 && (udp0->dst_port ==
2347 clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
2349 vnet_feature_next (&next0, b0);
2353 if (!sm->forwarding_enabled)
2355 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2356 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2360 if (next_src_nat(sm, ip0, ip0->protocol,
2361 udp0->src_port, udp0->dst_port,
2362 thread_index, rx_fib_index0))
2364 next0 = NAT44_ED_OUT2IN_NEXT_IN2OUT;
2367 create_bypass_for_fwd(sm, ip0, rx_fib_index0,
2373 /* Create session initiated by host from external network */
2374 s0 = create_session_for_static_mapping_ed(sm, b0, l_key0,
2383 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2389 next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
2395 s0 = pool_elt_at_index (tsm->sessions, value0.value);
2398 old_addr0 = ip0->dst_address.as_u32;
2399 new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
2400 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
2402 sum0 = ip0->checksum;
2403 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
2405 if (PREDICT_FALSE (is_twice_nat_session (s0)))
2406 sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
2407 s0->ext_host_nat_addr.as_u32, ip4_header_t,
2409 ip0->checksum = ip_csum_fold (sum0);
2411 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
2413 old_port0 = tcp0->dst_port;
2414 new_port0 = tcp0->dst_port = s0->in2out.port;
2416 sum0 = tcp0->checksum;
2417 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
2419 sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
2421 if (is_twice_nat_session (s0))
2423 sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
2424 s0->ext_host_nat_addr.as_u32,
2425 ip4_header_t, dst_address);
2426 sum0 = ip_csum_update (sum0, tcp0->src_port,
2427 s0->ext_host_nat_port, ip4_header_t,
2429 tcp0->src_port = s0->ext_host_nat_port;
2430 ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
2432 tcp0->checksum = ip_csum_fold(sum0);
2433 if (nat44_set_tcp_session_state_o2i (sm, s0, tcp0, thread_index))
2438 udp0->dst_port = s0->in2out.port;
2439 if (is_twice_nat_session (s0))
2441 udp0->src_port = s0->ext_host_nat_port;
2442 ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
2448 nat44_session_update_counters (s0, now,
2449 vlib_buffer_length_in_chain (vm, b0));
2452 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2453 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2455 nat44_ed_out2in_trace_t *t =
2456 vlib_add_trace (vm, node, b0, sizeof (*t));
2457 t->is_slow_path = is_slow_path;
2458 t->sw_if_index = sw_if_index0;
2459 t->next_index = next0;
2460 t->session_index = ~0;
2462 t->session_index = s0 - tsm->sessions;
2465 pkts_processed += next0 != NAT44_ED_OUT2IN_NEXT_DROP;
2467 next1 = NAT44_ED_OUT2IN_NEXT_LOOKUP;
2468 vnet_buffer (b1)->snat.flags = 0;
2469 ip1 = vlib_buffer_get_current (b1);
2471 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
2472 rx_fib_index1 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2475 if (PREDICT_FALSE(ip1->ttl == 1))
2477 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2478 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
2479 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2481 next1 = NAT44_ED_OUT2IN_NEXT_ICMP_ERROR;
2485 udp1 = ip4_next_header (ip1);
2486 tcp1 = (tcp_header_t *) udp1;
2487 icmp1 = (icmp46_header_t *) udp1;
2488 proto1 = ip_proto_to_snat_proto (ip1->protocol);
2492 if (PREDICT_FALSE (proto1 == ~0))
2494 s1 = nat44_ed_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1,
2495 thread_index, now, vm, node);
2496 if (!sm->forwarding_enabled)
2499 next1 = NAT44_ED_OUT2IN_NEXT_DROP;
2504 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
2506 next1 = icmp_out2in_ed_slow_path
2507 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
2508 next1, now, thread_index, &s1);
2514 if (PREDICT_FALSE (proto1 == ~0))
2516 next1 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
2520 if (ip4_is_fragment (ip1))
2522 next1 = NAT44_ED_OUT2IN_NEXT_REASS;
2526 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
2528 next1 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
2533 make_ed_kv (&kv1, &ip1->dst_address, &ip1->src_address, ip1->protocol,
2534 rx_fib_index1, udp1->dst_port, udp1->src_port);
2536 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv1, &value1))
2540 /* Try to match static mapping by external address and port,
2541 destination address and port in packet */
2542 e_key1.addr = ip1->dst_address;
2543 e_key1.port = udp1->dst_port;
2544 e_key1.protocol = proto1;
2545 e_key1.fib_index = rx_fib_index1;
2546 if (snat_static_mapping_match(sm, e_key1, &l_key1, 1, 0,
2547 &twice_nat1, &lb_nat1, &ip1->src_address))
2550 * Send DHCP packets to the ipv4 stack, or we won't
2551 * be able to use dhcp client on the outside interface
2553 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
2554 && (udp1->dst_port ==
2555 clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
2557 vnet_feature_next (&next1, b1);
2561 if (!sm->forwarding_enabled)
2563 b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2564 next1 = NAT44_ED_OUT2IN_NEXT_DROP;
2568 if (next_src_nat(sm, ip1, ip1->protocol,
2569 udp1->src_port, udp1->dst_port,
2570 thread_index, rx_fib_index1))
2572 next1 = NAT44_ED_OUT2IN_NEXT_IN2OUT;
2575 create_bypass_for_fwd(sm, ip1, rx_fib_index1,
2581 /* Create session initiated by host from external network */
2582 s1 = create_session_for_static_mapping_ed(sm, b1, l_key1,
2591 next1 = NAT44_ED_OUT2IN_NEXT_DROP;
2597 next1 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
2603 s1 = pool_elt_at_index (tsm->sessions, value1.value);
2606 old_addr1 = ip1->dst_address.as_u32;
2607 new_addr1 = ip1->dst_address.as_u32 = s1->in2out.addr.as_u32;
2608 vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
2610 sum1 = ip1->checksum;
2611 sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
2613 if (PREDICT_FALSE (is_twice_nat_session (s1)))
2614 sum1 = ip_csum_update (sum1, ip1->src_address.as_u32,
2615 s1->ext_host_nat_addr.as_u32, ip4_header_t,
2617 ip1->checksum = ip_csum_fold (sum1);
2619 if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
2621 old_port1 = tcp1->dst_port;
2622 new_port1 = tcp1->dst_port = s1->in2out.port;
2624 sum1 = tcp1->checksum;
2625 sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
2627 sum1 = ip_csum_update (sum1, old_port1, new_port1, ip4_header_t,
2629 if (is_twice_nat_session (s1))
2631 sum1 = ip_csum_update (sum1, ip1->src_address.as_u32,
2632 s1->ext_host_nat_addr.as_u32,
2633 ip4_header_t, dst_address);
2634 sum1 = ip_csum_update (sum1, tcp1->src_port,
2635 s1->ext_host_nat_port, ip4_header_t,
2637 tcp1->src_port = s1->ext_host_nat_port;
2638 ip1->src_address.as_u32 = s1->ext_host_nat_addr.as_u32;
2640 tcp1->checksum = ip_csum_fold(sum1);
2641 if (nat44_set_tcp_session_state_o2i (sm, s1, tcp1, thread_index))
2646 udp1->dst_port = s1->in2out.port;
2647 if (is_twice_nat_session (s1))
2649 udp1->src_port = s1->ext_host_nat_port;
2650 ip1->src_address.as_u32 = s1->ext_host_nat_addr.as_u32;
2656 nat44_session_update_counters (s1, now,
2657 vlib_buffer_length_in_chain (vm, b1));
2660 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2661 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
2663 nat44_ed_out2in_trace_t *t =
2664 vlib_add_trace (vm, node, b1, sizeof (*t));
2665 t->is_slow_path = is_slow_path;
2666 t->sw_if_index = sw_if_index1;
2667 t->next_index = next1;
2668 t->session_index = ~0;
2670 t->session_index = s1 - tsm->sessions;
2673 pkts_processed += next1 != NAT44_ED_OUT2IN_NEXT_DROP;
2675 /* verify speculative enqueues, maybe switch current next frame */
2676 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2677 to_next, n_left_to_next,
2678 bi0, bi1, next0, next1);
2681 while (n_left_from > 0 && n_left_to_next > 0)
2685 u32 next0, sw_if_index0, rx_fib_index0, proto0, old_addr0, new_addr0;
2686 u16 old_port0, new_port0;
2690 icmp46_header_t * icmp0;
2691 snat_session_t *s0 = 0;
2692 clib_bihash_kv_16_8_t kv0, value0;
2694 snat_session_key_t e_key0, l_key0;
2695 lb_nat_type_t lb_nat0;
2696 twice_nat_type_t twice_nat0;
2698 /* speculatively enqueue b0 to the current next frame */
2704 n_left_to_next -= 1;
2706 b0 = vlib_get_buffer (vm, bi0);
2707 next0 = NAT44_ED_OUT2IN_NEXT_LOOKUP;
2708 vnet_buffer (b0)->snat.flags = 0;
2709 ip0 = vlib_buffer_get_current (b0);
2711 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2712 rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2715 if (PREDICT_FALSE(ip0->ttl == 1))
2717 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2718 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2719 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2721 next0 = NAT44_ED_OUT2IN_NEXT_ICMP_ERROR;
2725 udp0 = ip4_next_header (ip0);
2726 tcp0 = (tcp_header_t *) udp0;
2727 icmp0 = (icmp46_header_t *) udp0;
2728 proto0 = ip_proto_to_snat_proto (ip0->protocol);
2732 if (PREDICT_FALSE (proto0 == ~0))
2734 s0 = nat44_ed_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
2735 thread_index, now, vm, node);
2736 if (!sm->forwarding_enabled)
2739 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2744 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2746 next0 = icmp_out2in_ed_slow_path
2747 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
2748 next0, now, thread_index, &s0);
2754 if (PREDICT_FALSE (proto0 == ~0))
2756 next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
2760 if (ip4_is_fragment (ip0))
2762 next0 = NAT44_ED_OUT2IN_NEXT_REASS;
2766 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2768 next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
2773 make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address, ip0->protocol,
2774 rx_fib_index0, udp0->dst_port, udp0->src_port);
2776 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0))
2780 /* Try to match static mapping by external address and port,
2781 destination address and port in packet */
2782 e_key0.addr = ip0->dst_address;
2783 e_key0.port = udp0->dst_port;
2784 e_key0.protocol = proto0;
2785 e_key0.fib_index = rx_fib_index0;
2786 if (snat_static_mapping_match(sm, e_key0, &l_key0, 1, 0,
2787 &twice_nat0, &lb_nat0, &ip0->src_address))
2790 * Send DHCP packets to the ipv4 stack, or we won't
2791 * be able to use dhcp client on the outside interface
2793 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
2794 && (udp0->dst_port ==
2795 clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
2797 vnet_feature_next (&next0, b0);
2801 if (!sm->forwarding_enabled)
2803 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2804 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2808 if (next_src_nat(sm, ip0, ip0->protocol,
2809 udp0->src_port, udp0->dst_port,
2810 thread_index, rx_fib_index0))
2812 next0 = NAT44_ED_OUT2IN_NEXT_IN2OUT;
2815 create_bypass_for_fwd(sm, ip0, rx_fib_index0,
2821 /* Create session initiated by host from external network */
2822 s0 = create_session_for_static_mapping_ed(sm, b0, l_key0,
2831 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
2837 next0 = NAT44_ED_OUT2IN_NEXT_SLOW_PATH;
2843 s0 = pool_elt_at_index (tsm->sessions, value0.value);
2846 old_addr0 = ip0->dst_address.as_u32;
2847 new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
2848 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
2850 sum0 = ip0->checksum;
2851 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
2853 if (PREDICT_FALSE (is_twice_nat_session (s0)))
2854 sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
2855 s0->ext_host_nat_addr.as_u32, ip4_header_t,
2857 ip0->checksum = ip_csum_fold (sum0);
2859 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
2861 old_port0 = tcp0->dst_port;
2862 new_port0 = tcp0->dst_port = s0->in2out.port;
2864 sum0 = tcp0->checksum;
2865 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
2867 sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
2869 if (is_twice_nat_session (s0))
2871 sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
2872 s0->ext_host_nat_addr.as_u32,
2873 ip4_header_t, dst_address);
2874 sum0 = ip_csum_update (sum0, tcp0->src_port,
2875 s0->ext_host_nat_port, ip4_header_t,
2877 tcp0->src_port = s0->ext_host_nat_port;
2878 ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
2880 tcp0->checksum = ip_csum_fold(sum0);
2881 if (nat44_set_tcp_session_state_o2i (sm, s0, tcp0, thread_index))
2886 udp0->dst_port = s0->in2out.port;
2887 if (is_twice_nat_session (s0))
2889 udp0->src_port = s0->ext_host_nat_port;
2890 ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
2896 nat44_session_update_counters (s0, now,
2897 vlib_buffer_length_in_chain (vm, b0));
2900 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2901 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2903 nat44_ed_out2in_trace_t *t =
2904 vlib_add_trace (vm, node, b0, sizeof (*t));
2905 t->is_slow_path = is_slow_path;
2906 t->sw_if_index = sw_if_index0;
2907 t->next_index = next0;
2908 t->session_index = ~0;
2910 t->session_index = s0 - tsm->sessions;
2913 pkts_processed += next0 != NAT44_ED_OUT2IN_NEXT_DROP;
2914 /* verify speculative enqueue, maybe switch current next frame */
2915 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2916 to_next, n_left_to_next,
2920 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2923 vlib_node_increment_counter (vm, stats_node_index,
2924 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2926 return frame->n_vectors;
2930 nat44_ed_out2in_fast_path_fn (vlib_main_t * vm,
2931 vlib_node_runtime_t * node,
2932 vlib_frame_t * frame)
2934 return nat44_ed_out2in_node_fn_inline (vm, node, frame, 0);
2937 VLIB_REGISTER_NODE (nat44_ed_out2in_node) = {
2938 .function = nat44_ed_out2in_fast_path_fn,
2939 .name = "nat44-ed-out2in",
2940 .vector_size = sizeof (u32),
2941 .format_trace = format_nat44_ed_out2in_trace,
2942 .type = VLIB_NODE_TYPE_INTERNAL,
2944 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2945 .error_strings = snat_out2in_error_strings,
2947 .runtime_data_bytes = sizeof (snat_runtime_t),
2949 .n_next_nodes = NAT44_ED_OUT2IN_N_NEXT,
2951 /* edit / add dispositions here */
2953 [NAT44_ED_OUT2IN_NEXT_DROP] = "error-drop",
2954 [NAT44_ED_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2955 [NAT44_ED_OUT2IN_NEXT_SLOW_PATH] = "nat44-ed-out2in-slowpath",
2956 [NAT44_ED_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2957 [NAT44_ED_OUT2IN_NEXT_IN2OUT] = "nat44-ed-in2out",
2958 [NAT44_ED_OUT2IN_NEXT_REASS] = "nat44-ed-out2in-reass",
2962 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_out2in_node, nat44_ed_out2in_fast_path_fn);
2965 nat44_ed_out2in_slow_path_fn (vlib_main_t * vm,
2966 vlib_node_runtime_t * node,
2967 vlib_frame_t * frame)
2969 return nat44_ed_out2in_node_fn_inline (vm, node, frame, 1);
2972 VLIB_REGISTER_NODE (nat44_ed_out2in_slowpath_node) = {
2973 .function = nat44_ed_out2in_slow_path_fn,
2974 .name = "nat44-ed-out2in-slowpath",
2975 .vector_size = sizeof (u32),
2976 .format_trace = format_nat44_ed_out2in_trace,
2977 .type = VLIB_NODE_TYPE_INTERNAL,
2979 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2980 .error_strings = snat_out2in_error_strings,
2982 .runtime_data_bytes = sizeof (snat_runtime_t),
2984 .n_next_nodes = NAT44_ED_OUT2IN_N_NEXT,
2986 /* edit / add dispositions here */
2988 [NAT44_ED_OUT2IN_NEXT_DROP] = "error-drop",
2989 [NAT44_ED_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2990 [NAT44_ED_OUT2IN_NEXT_SLOW_PATH] = "nat44-ed-out2in-slowpath",
2991 [NAT44_ED_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2992 [NAT44_ED_OUT2IN_NEXT_IN2OUT] = "nat44-ed-in2out",
2993 [NAT44_ED_OUT2IN_NEXT_REASS] = "nat44-ed-out2in-reass",
2997 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_out2in_slowpath_node,
2998 nat44_ed_out2in_slow_path_fn);
3001 nat44_ed_out2in_reass_node_fn (vlib_main_t * vm,
3002 vlib_node_runtime_t * node,
3003 vlib_frame_t * frame)
3005 u32 n_left_from, *from, *to_next;
3006 snat_out2in_next_t next_index;
3007 u32 pkts_processed = 0;
3008 snat_main_t *sm = &snat_main;
3009 f64 now = vlib_time_now (vm);
3010 u32 thread_index = vm->thread_index;
3011 snat_main_per_thread_data_t *per_thread_data =
3012 &sm->per_thread_data[thread_index];
3013 u32 *fragments_to_drop = 0;
3014 u32 *fragments_to_loopback = 0;
3016 from = vlib_frame_vector_args (frame);
3017 n_left_from = frame->n_vectors;
3018 next_index = node->cached_next_index;
3020 while (n_left_from > 0)
3024 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3026 while (n_left_from > 0 && n_left_to_next > 0)
3028 u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
3033 nat_reass_ip4_t *reass0;
3034 udp_header_t * udp0;
3035 tcp_header_t * tcp0;
3036 icmp46_header_t * icmp0;
3037 clib_bihash_kv_16_8_t kv0, value0;
3038 snat_session_t * s0 = 0;
3039 u16 old_port0, new_port0;
3041 snat_session_key_t e_key0, l_key0;
3043 twice_nat_type_t twice_nat0;
3045 /* speculatively enqueue b0 to the current next frame */
3051 n_left_to_next -= 1;
3053 b0 = vlib_get_buffer (vm, bi0);
3054 next0 = NAT44_ED_OUT2IN_NEXT_LOOKUP;
3056 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3057 rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3060 if (PREDICT_FALSE (nat_reass_is_drop_frag(0)))
3062 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
3063 b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
3067 ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
3068 udp0 = ip4_next_header (ip0);
3069 tcp0 = (tcp_header_t *) udp0;
3070 icmp0 = (icmp46_header_t *) udp0;
3071 proto0 = ip_proto_to_snat_proto (ip0->protocol);
3073 reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
3078 &fragments_to_drop);
3080 if (PREDICT_FALSE (!reass0))
3082 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
3083 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
3084 nat_log_notice ("maximum reassemblies exceeded");
3088 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
3090 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
3092 next0 = icmp_out2in_slow_path
3093 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
3094 next0, now, thread_index, &s0);
3096 if (PREDICT_TRUE(next0 != NAT44_ED_OUT2IN_NEXT_DROP))
3099 reass0->sess_index = s0 - per_thread_data->sessions;
3101 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
3102 reass0->thread_index = thread_index;
3103 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
3109 make_ed_kv (&kv0, &ip0->dst_address, &ip0->src_address, ip0->protocol,
3110 rx_fib_index0, udp0->dst_port, udp0->src_port);
3112 if (clib_bihash_search_16_8 (&per_thread_data->out2in_ed, &kv0, &value0))
3114 /* Try to match static mapping by external address and port,
3115 destination address and port in packet */
3116 e_key0.addr = ip0->dst_address;
3117 e_key0.port = udp0->dst_port;
3118 e_key0.protocol = proto0;
3119 e_key0.fib_index = rx_fib_index0;
3120 if (snat_static_mapping_match(sm, e_key0, &l_key0, 1, 0,
3121 &twice_nat0, &lb0, 0))
3124 * Send DHCP packets to the ipv4 stack, or we won't
3125 * be able to use dhcp client on the outside interface
3127 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
3129 == clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
3131 vnet_feature_next(&next0, b0);
3135 if (!sm->forwarding_enabled)
3137 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3138 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
3142 if (next_src_nat(sm, ip0, ip0->protocol,
3143 udp0->src_port, udp0->dst_port,
3144 thread_index, rx_fib_index0))
3146 next0 = NAT44_ED_OUT2IN_NEXT_IN2OUT;
3149 create_bypass_for_fwd(sm, ip0, rx_fib_index0,
3151 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
3152 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
3157 /* Create session initiated by host from external network */
3158 s0 = create_session_for_static_mapping_ed(sm, b0, l_key0,
3165 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3166 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
3169 reass0->sess_index = s0 - per_thread_data->sessions;
3170 reass0->thread_index = thread_index;
3174 s0 = pool_elt_at_index (per_thread_data->sessions,
3176 reass0->sess_index = value0.value;
3178 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
3182 if (reass0->flags & NAT_REASS_FLAG_ED_DONT_TRANSLATE)
3184 if (PREDICT_FALSE (reass0->sess_index == (u32) ~0))
3186 if (nat_ip4_reass_add_fragment (reass0, bi0, &fragments_to_drop))
3188 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
3189 nat_log_notice ("maximum fragments per reassembly exceeded");
3190 next0 = NAT44_ED_OUT2IN_NEXT_DROP;
3196 s0 = pool_elt_at_index (per_thread_data->sessions,
3197 reass0->sess_index);
3200 old_addr0 = ip0->dst_address.as_u32;
3201 ip0->dst_address = s0->in2out.addr;
3202 new_addr0 = ip0->dst_address.as_u32;
3203 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
3205 sum0 = ip0->checksum;
3206 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
3208 dst_address /* changed member */);
3209 if (PREDICT_FALSE (is_twice_nat_session (s0)))
3210 sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
3211 s0->ext_host_nat_addr.as_u32, ip4_header_t,
3213 ip0->checksum = ip_csum_fold (sum0);
3215 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
3217 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
3219 old_port0 = tcp0->dst_port;
3220 tcp0->dst_port = s0->in2out.port;
3221 new_port0 = tcp0->dst_port;
3223 sum0 = tcp0->checksum;
3224 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
3226 dst_address /* changed member */);
3228 sum0 = ip_csum_update (sum0, old_port0, new_port0,
3229 ip4_header_t /* cheat */,
3230 length /* changed member */);
3231 if (is_twice_nat_session (s0))
3233 sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
3234 s0->ext_host_nat_addr.as_u32,
3235 ip4_header_t, dst_address);
3236 sum0 = ip_csum_update (sum0, tcp0->src_port,
3237 s0->ext_host_nat_port, ip4_header_t,
3239 tcp0->src_port = s0->ext_host_nat_port;
3240 ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
3242 tcp0->checksum = ip_csum_fold(sum0);
3246 old_port0 = udp0->dst_port;
3247 udp0->dst_port = s0->in2out.port;
3248 if (is_twice_nat_session (s0))
3250 udp0->src_port = s0->ext_host_nat_port;
3251 ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
3258 nat44_session_update_counters (s0, now,
3259 vlib_buffer_length_in_chain (vm, b0));
3260 /* Per-user LRU list maintenance */
3261 nat44_session_update_lru (sm, s0, thread_index);
3264 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
3265 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3267 nat44_out2in_reass_trace_t *t =
3268 vlib_add_trace (vm, node, b0, sizeof (*t));
3269 t->cached = cached0;
3270 t->sw_if_index = sw_if_index0;
3271 t->next_index = next0;
3281 pkts_processed += next0 != NAT44_ED_OUT2IN_NEXT_DROP;
3283 /* verify speculative enqueue, maybe switch current next frame */
3284 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3285 to_next, n_left_to_next,
3289 if (n_left_from == 0 && vec_len (fragments_to_loopback))
3291 from = vlib_frame_vector_args (frame);
3292 u32 len = vec_len (fragments_to_loopback);
3293 if (len <= VLIB_FRAME_SIZE)
3295 clib_memcpy (from, fragments_to_loopback, sizeof (u32) * len);
3297 vec_reset_length (fragments_to_loopback);
3302 fragments_to_loopback + (len - VLIB_FRAME_SIZE),
3303 sizeof (u32) * VLIB_FRAME_SIZE);
3304 n_left_from = VLIB_FRAME_SIZE;
3305 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
3310 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3313 vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
3314 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
3317 nat_send_all_to_node (vm, fragments_to_drop, node,
3318 &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
3319 SNAT_OUT2IN_NEXT_DROP);
3321 vec_free (fragments_to_drop);
3322 vec_free (fragments_to_loopback);
3323 return frame->n_vectors;
3326 VLIB_REGISTER_NODE (nat44_ed_out2in_reass_node) = {
3327 .function = nat44_ed_out2in_reass_node_fn,
3328 .name = "nat44-ed-out2in-reass",
3329 .vector_size = sizeof (u32),
3330 .format_trace = format_nat44_out2in_reass_trace,
3331 .type = VLIB_NODE_TYPE_INTERNAL,
3333 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
3334 .error_strings = snat_out2in_error_strings,
3336 .n_next_nodes = NAT44_ED_OUT2IN_N_NEXT,
3338 /* edit / add dispositions here */
3340 [NAT44_ED_OUT2IN_NEXT_DROP] = "error-drop",
3341 [NAT44_ED_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
3342 [NAT44_ED_OUT2IN_NEXT_SLOW_PATH] = "nat44-ed-out2in-slowpath",
3343 [NAT44_ED_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3344 [NAT44_ED_OUT2IN_NEXT_IN2OUT] = "nat44-ed-in2out",
3345 [NAT44_ED_OUT2IN_NEXT_REASS] = "nat44-ed-out2in-reass",
3349 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_out2in_reass_node,
3350 nat44_ed_out2in_reass_node_fn);
3352 /**************************/
3353 /*** deterministic mode ***/
3354 /**************************/
3356 snat_det_out2in_node_fn (vlib_main_t * vm,
3357 vlib_node_runtime_t * node,
3358 vlib_frame_t * frame)
3360 u32 n_left_from, * from, * to_next;
3361 snat_out2in_next_t next_index;
3362 u32 pkts_processed = 0;
3363 snat_main_t * sm = &snat_main;
3364 u32 thread_index = vm->thread_index;
3366 from = vlib_frame_vector_args (frame);
3367 n_left_from = frame->n_vectors;
3368 next_index = node->cached_next_index;
3370 while (n_left_from > 0)
3374 vlib_get_next_frame (vm, node, next_index,
3375 to_next, n_left_to_next);
3377 while (n_left_from >= 4 && n_left_to_next >= 2)
3380 vlib_buffer_t * b0, * b1;
3381 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
3382 u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
3383 u32 sw_if_index0, sw_if_index1;
3384 ip4_header_t * ip0, * ip1;
3385 ip_csum_t sum0, sum1;
3386 ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
3387 u16 new_port0, old_port0, old_port1, new_port1;
3388 udp_header_t * udp0, * udp1;
3389 tcp_header_t * tcp0, * tcp1;
3391 snat_det_out_key_t key0, key1;
3392 snat_det_map_t * dm0, * dm1;
3393 snat_det_session_t * ses0 = 0, * ses1 = 0;
3394 u32 rx_fib_index0, rx_fib_index1;
3395 icmp46_header_t * icmp0, * icmp1;
3397 /* Prefetch next iteration. */
3399 vlib_buffer_t * p2, * p3;
3401 p2 = vlib_get_buffer (vm, from[2]);
3402 p3 = vlib_get_buffer (vm, from[3]);
3404 vlib_prefetch_buffer_header (p2, LOAD);
3405 vlib_prefetch_buffer_header (p3, LOAD);
3407 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
3408 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
3411 /* speculatively enqueue b0 and b1 to the current next frame */
3412 to_next[0] = bi0 = from[0];
3413 to_next[1] = bi1 = from[1];
3417 n_left_to_next -= 2;
3419 b0 = vlib_get_buffer (vm, bi0);
3420 b1 = vlib_get_buffer (vm, bi1);
3422 ip0 = vlib_buffer_get_current (b0);
3423 udp0 = ip4_next_header (ip0);
3424 tcp0 = (tcp_header_t *) udp0;
3426 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3428 if (PREDICT_FALSE(ip0->ttl == 1))
3430 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3431 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
3432 ICMP4_time_exceeded_ttl_exceeded_in_transit,
3434 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
3438 proto0 = ip_proto_to_snat_proto (ip0->protocol);
3440 if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
3442 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
3443 icmp0 = (icmp46_header_t *) udp0;
3445 next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
3446 rx_fib_index0, node, next0, thread_index,
3451 key0.ext_host_addr = ip0->src_address;
3452 key0.ext_host_port = tcp0->src;
3453 key0.out_port = tcp0->dst;
3455 dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
3456 if (PREDICT_FALSE(!dm0))
3458 nat_log_info ("unknown dst address: %U",
3459 format_ip4_address, &ip0->dst_address);
3460 next0 = SNAT_OUT2IN_NEXT_DROP;
3461 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3465 snat_det_reverse(dm0, &ip0->dst_address,
3466 clib_net_to_host_u16(tcp0->dst), &new_addr0);
3468 ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
3469 if (PREDICT_FALSE(!ses0))
3471 nat_log_info ("no match src %U:%d dst %U:%d for user %U",
3472 format_ip4_address, &ip0->src_address,
3473 clib_net_to_host_u16 (tcp0->src),
3474 format_ip4_address, &ip0->dst_address,
3475 clib_net_to_host_u16 (tcp0->dst),
3476 format_ip4_address, &new_addr0);
3477 next0 = SNAT_OUT2IN_NEXT_DROP;
3478 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3481 new_port0 = ses0->in_port;
3483 old_addr0 = ip0->dst_address;
3484 ip0->dst_address = new_addr0;
3485 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
3487 sum0 = ip0->checksum;
3488 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
3490 dst_address /* changed member */);
3491 ip0->checksum = ip_csum_fold (sum0);
3493 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
3495 if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
3496 ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
3497 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
3498 snat_det_ses_close(dm0, ses0);
3500 old_port0 = tcp0->dst;
3501 tcp0->dst = new_port0;
3503 sum0 = tcp0->checksum;
3504 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
3506 dst_address /* changed member */);
3508 sum0 = ip_csum_update (sum0, old_port0, new_port0,
3509 ip4_header_t /* cheat */,
3510 length /* changed member */);
3511 tcp0->checksum = ip_csum_fold(sum0);
3515 old_port0 = udp0->dst_port;
3516 udp0->dst_port = new_port0;
3522 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
3523 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3525 snat_out2in_trace_t *t =
3526 vlib_add_trace (vm, node, b0, sizeof (*t));
3527 t->sw_if_index = sw_if_index0;
3528 t->next_index = next0;
3529 t->session_index = ~0;
3531 t->session_index = ses0 - dm0->sessions;
3534 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
3536 b1 = vlib_get_buffer (vm, bi1);
3538 ip1 = vlib_buffer_get_current (b1);
3539 udp1 = ip4_next_header (ip1);
3540 tcp1 = (tcp_header_t *) udp1;
3542 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
3544 if (PREDICT_FALSE(ip1->ttl == 1))
3546 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3547 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
3548 ICMP4_time_exceeded_ttl_exceeded_in_transit,
3550 next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
3554 proto1 = ip_proto_to_snat_proto (ip1->protocol);
3556 if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP))
3558 rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1);
3559 icmp1 = (icmp46_header_t *) udp1;
3561 next1 = icmp_out2in(sm, b1, ip1, icmp1, sw_if_index1,
3562 rx_fib_index1, node, next1, thread_index,
3567 key1.ext_host_addr = ip1->src_address;
3568 key1.ext_host_port = tcp1->src;
3569 key1.out_port = tcp1->dst;
3571 dm1 = snat_det_map_by_out(sm, &ip1->dst_address);
3572 if (PREDICT_FALSE(!dm1))
3574 nat_log_info ("unknown dst address: %U",
3575 format_ip4_address, &ip1->dst_address);
3576 next1 = SNAT_OUT2IN_NEXT_DROP;
3577 b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3581 snat_det_reverse(dm1, &ip1->dst_address,
3582 clib_net_to_host_u16(tcp1->dst), &new_addr1);
3584 ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64);
3585 if (PREDICT_FALSE(!ses1))
3587 nat_log_info ("no match src %U:%d dst %U:%d for user %U",
3588 format_ip4_address, &ip1->src_address,
3589 clib_net_to_host_u16 (tcp1->src),
3590 format_ip4_address, &ip1->dst_address,
3591 clib_net_to_host_u16 (tcp1->dst),
3592 format_ip4_address, &new_addr1);
3593 next1 = SNAT_OUT2IN_NEXT_DROP;
3594 b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3597 new_port1 = ses1->in_port;
3599 old_addr1 = ip1->dst_address;
3600 ip1->dst_address = new_addr1;
3601 vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
3603 sum1 = ip1->checksum;
3604 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
3606 dst_address /* changed member */);
3607 ip1->checksum = ip_csum_fold (sum1);
3609 if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
3611 if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
3612 ses1->state = SNAT_SESSION_TCP_CLOSE_WAIT;
3613 else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_LAST_ACK)
3614 snat_det_ses_close(dm1, ses1);
3616 old_port1 = tcp1->dst;
3617 tcp1->dst = new_port1;
3619 sum1 = tcp1->checksum;
3620 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
3622 dst_address /* changed member */);
3624 sum1 = ip_csum_update (sum1, old_port1, new_port1,
3625 ip4_header_t /* cheat */,
3626 length /* changed member */);
3627 tcp1->checksum = ip_csum_fold(sum1);
3631 old_port1 = udp1->dst_port;
3632 udp1->dst_port = new_port1;
3638 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
3639 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
3641 snat_out2in_trace_t *t =
3642 vlib_add_trace (vm, node, b1, sizeof (*t));
3643 t->sw_if_index = sw_if_index1;
3644 t->next_index = next1;
3645 t->session_index = ~0;
3647 t->session_index = ses1 - dm1->sessions;
3650 pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
3652 /* verify speculative enqueues, maybe switch current next frame */
3653 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
3654 to_next, n_left_to_next,
3655 bi0, bi1, next0, next1);
3658 while (n_left_from > 0 && n_left_to_next > 0)
3662 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
3666 ip4_address_t new_addr0, old_addr0;
3667 u16 new_port0, old_port0;
3668 udp_header_t * udp0;
3669 tcp_header_t * tcp0;
3671 snat_det_out_key_t key0;
3672 snat_det_map_t * dm0;
3673 snat_det_session_t * ses0 = 0;
3675 icmp46_header_t * icmp0;
3677 /* speculatively enqueue b0 to the current next frame */
3683 n_left_to_next -= 1;
3685 b0 = vlib_get_buffer (vm, bi0);
3687 ip0 = vlib_buffer_get_current (b0);
3688 udp0 = ip4_next_header (ip0);
3689 tcp0 = (tcp_header_t *) udp0;
3691 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3693 if (PREDICT_FALSE(ip0->ttl == 1))
3695 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3696 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
3697 ICMP4_time_exceeded_ttl_exceeded_in_transit,
3699 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
3703 proto0 = ip_proto_to_snat_proto (ip0->protocol);
3705 if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
3707 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
3708 icmp0 = (icmp46_header_t *) udp0;
3710 next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
3711 rx_fib_index0, node, next0, thread_index,
3716 key0.ext_host_addr = ip0->src_address;
3717 key0.ext_host_port = tcp0->src;
3718 key0.out_port = tcp0->dst;
3720 dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
3721 if (PREDICT_FALSE(!dm0))
3723 nat_log_info ("unknown dst address: %U",
3724 format_ip4_address, &ip0->dst_address);
3725 next0 = SNAT_OUT2IN_NEXT_DROP;
3726 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3730 snat_det_reverse(dm0, &ip0->dst_address,
3731 clib_net_to_host_u16(tcp0->dst), &new_addr0);
3733 ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
3734 if (PREDICT_FALSE(!ses0))
3736 nat_log_info ("no match src %U:%d dst %U:%d for user %U",
3737 format_ip4_address, &ip0->src_address,
3738 clib_net_to_host_u16 (tcp0->src),
3739 format_ip4_address, &ip0->dst_address,
3740 clib_net_to_host_u16 (tcp0->dst),
3741 format_ip4_address, &new_addr0);
3742 next0 = SNAT_OUT2IN_NEXT_DROP;
3743 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3746 new_port0 = ses0->in_port;
3748 old_addr0 = ip0->dst_address;
3749 ip0->dst_address = new_addr0;
3750 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
3752 sum0 = ip0->checksum;
3753 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
3755 dst_address /* changed member */);
3756 ip0->checksum = ip_csum_fold (sum0);
3758 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
3760 if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
3761 ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
3762 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
3763 snat_det_ses_close(dm0, ses0);
3765 old_port0 = tcp0->dst;
3766 tcp0->dst = new_port0;
3768 sum0 = tcp0->checksum;
3769 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
3771 dst_address /* changed member */);
3773 sum0 = ip_csum_update (sum0, old_port0, new_port0,
3774 ip4_header_t /* cheat */,
3775 length /* changed member */);
3776 tcp0->checksum = ip_csum_fold(sum0);
3780 old_port0 = udp0->dst_port;
3781 udp0->dst_port = new_port0;
3787 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
3788 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3790 snat_out2in_trace_t *t =
3791 vlib_add_trace (vm, node, b0, sizeof (*t));
3792 t->sw_if_index = sw_if_index0;
3793 t->next_index = next0;
3794 t->session_index = ~0;
3796 t->session_index = ses0 - dm0->sessions;
3799 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
3801 /* verify speculative enqueue, maybe switch current next frame */
3802 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3803 to_next, n_left_to_next,
3807 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3810 vlib_node_increment_counter (vm, snat_det_out2in_node.index,
3811 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
3813 return frame->n_vectors;
3816 VLIB_REGISTER_NODE (snat_det_out2in_node) = {
3817 .function = snat_det_out2in_node_fn,
3818 .name = "nat44-det-out2in",
3819 .vector_size = sizeof (u32),
3820 .format_trace = format_snat_out2in_trace,
3821 .type = VLIB_NODE_TYPE_INTERNAL,
3823 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
3824 .error_strings = snat_out2in_error_strings,
3826 .runtime_data_bytes = sizeof (snat_runtime_t),
3828 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
3830 /* edit / add dispositions here */
3832 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
3833 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
3834 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3835 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
3838 VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn);
3841 * Get address and port values to be used for ICMP packet translation
3842 * and create session if needed
3844 * @param[in,out] sm NAT main
3845 * @param[in,out] node NAT node runtime
3846 * @param[in] thread_index thread index
3847 * @param[in,out] b0 buffer containing packet to be translated
3848 * @param[out] p_proto protocol used for matching
3849 * @param[out] p_value address and port after NAT translation
3850 * @param[out] p_dont_translate if packet should not be translated
3851 * @param d optional parameter
3852 * @param e optional parameter
3854 u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node,
3855 u32 thread_index, vlib_buffer_t *b0,
3856 ip4_header_t *ip0, u8 *p_proto,
3857 snat_session_key_t *p_value,
3858 u8 *p_dont_translate, void *d, void *e)
3860 icmp46_header_t *icmp0;
3863 snat_det_out_key_t key0;
3864 u8 dont_translate = 0;
3866 icmp_echo_header_t *echo0, *inner_echo0 = 0;
3867 ip4_header_t *inner_ip0;
3868 void *l4_header = 0;
3869 icmp46_header_t *inner_icmp0;
3870 snat_det_map_t * dm0 = 0;
3871 ip4_address_t new_addr0 = {{0}};
3872 snat_det_session_t * ses0 = 0;
3873 ip4_address_t out_addr;
3875 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
3876 echo0 = (icmp_echo_header_t *)(icmp0+1);
3877 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3879 if (!icmp_is_error_message (icmp0))
3881 protocol = SNAT_PROTOCOL_ICMP;
3882 key0.ext_host_addr = ip0->src_address;
3883 key0.ext_host_port = 0;
3884 key0.out_port = echo0->identifier;
3885 out_addr = ip0->dst_address;
3889 inner_ip0 = (ip4_header_t *)(echo0+1);
3890 l4_header = ip4_next_header (inner_ip0);
3891 protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
3892 key0.ext_host_addr = inner_ip0->dst_address;
3893 out_addr = inner_ip0->src_address;
3896 case SNAT_PROTOCOL_ICMP:
3897 inner_icmp0 = (icmp46_header_t*)l4_header;
3898 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
3899 key0.ext_host_port = 0;
3900 key0.out_port = inner_echo0->identifier;
3902 case SNAT_PROTOCOL_UDP:
3903 case SNAT_PROTOCOL_TCP:
3904 key0.ext_host_port = ((tcp_udp_header_t*)l4_header)->dst_port;
3905 key0.out_port = ((tcp_udp_header_t*)l4_header)->src_port;
3908 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
3909 next0 = SNAT_OUT2IN_NEXT_DROP;
3914 dm0 = snat_det_map_by_out(sm, &out_addr);
3915 if (PREDICT_FALSE(!dm0))
3917 /* Don't NAT packet aimed at the intfc address */
3918 if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
3919 ip0->dst_address.as_u32)))
3924 nat_log_info ("unknown dst address: %U",
3925 format_ip4_address, &ip0->dst_address);
3929 snat_det_reverse(dm0, &ip0->dst_address,
3930 clib_net_to_host_u16(key0.out_port), &new_addr0);
3932 ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
3933 if (PREDICT_FALSE(!ses0))
3935 /* Don't NAT packet aimed at the intfc address */
3936 if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
3937 ip0->dst_address.as_u32)))
3942 nat_log_info ("no match src %U:%d dst %U:%d for user %U",
3943 format_ip4_address, &key0.ext_host_addr,
3944 clib_net_to_host_u16 (key0.ext_host_port),
3945 format_ip4_address, &out_addr,
3946 clib_net_to_host_u16 (key0.out_port),
3947 format_ip4_address, &new_addr0);
3948 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
3949 next0 = SNAT_OUT2IN_NEXT_DROP;
3953 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
3954 !icmp_is_error_message (icmp0)))
3956 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
3957 next0 = SNAT_OUT2IN_NEXT_DROP;
3964 *p_proto = protocol;
3967 p_value->addr = new_addr0;
3968 p_value->fib_index = sm->inside_fib_index;
3969 p_value->port = ses0->in_port;
3971 *p_dont_translate = dont_translate;
3973 *(snat_det_session_t**)d = ses0;
3975 *(snat_det_map_t**)e = dm0;
3979 /**********************/
3980 /*** worker handoff ***/
3981 /**********************/
3983 snat_out2in_worker_handoff_fn (vlib_main_t * vm,
3984 vlib_node_runtime_t * node,
3985 vlib_frame_t * frame)
3987 snat_main_t *sm = &snat_main;
3988 vlib_thread_main_t *tm = vlib_get_thread_main ();
3989 u32 n_left_from, *from, *to_next = 0, *to_next_drop = 0;
3990 static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
3991 static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
3993 vlib_frame_queue_elt_t *hf = 0;
3994 vlib_frame_queue_t *fq;
3995 vlib_frame_t *f = 0;
3997 u32 n_left_to_next_worker = 0, *to_next_worker = 0;
3998 u32 next_worker_index = 0;
3999 u32 current_worker_index = ~0;
4000 u32 thread_index = vm->thread_index;
4001 vlib_frame_t *d = 0;
4003 ASSERT (vec_len (sm->workers));
4005 if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
4007 vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
4009 vec_validate_init_empty (congested_handoff_queue_by_worker_index,
4010 tm->n_vlib_mains - 1,
4011 (vlib_frame_queue_t *) (~0));
4014 from = vlib_frame_vector_args (frame);
4015 n_left_from = frame->n_vectors;
4017 while (n_left_from > 0)
4030 b0 = vlib_get_buffer (vm, bi0);
4032 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
4033 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
4035 ip0 = vlib_buffer_get_current (b0);
4037 next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0);
4039 if (PREDICT_FALSE (next_worker_index != thread_index))
4043 if (next_worker_index != current_worker_index)
4045 fq = is_vlib_frame_queue_congested (
4046 sm->fq_out2in_index, next_worker_index, NAT_FQ_NELTS - 2,
4047 congested_handoff_queue_by_worker_index);
4051 /* if this is 1st frame */
4054 d = vlib_get_frame_to_node (vm, sm->error_node_index);
4055 to_next_drop = vlib_frame_vector_args (d);
4058 to_next_drop[0] = bi0;
4061 b0->error = node->errors[SNAT_OUT2IN_ERROR_FQ_CONGESTED];
4066 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
4068 hf = vlib_get_worker_handoff_queue_elt (sm->fq_out2in_index,
4070 handoff_queue_elt_by_worker_index);
4072 n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
4073 to_next_worker = &hf->buffer_index[hf->n_vectors];
4074 current_worker_index = next_worker_index;
4077 /* enqueue to correct worker thread */
4078 to_next_worker[0] = bi0;
4080 n_left_to_next_worker--;
4082 if (n_left_to_next_worker == 0)
4084 hf->n_vectors = VLIB_FRAME_SIZE;
4085 vlib_put_frame_queue_elt (hf);
4086 current_worker_index = ~0;
4087 handoff_queue_elt_by_worker_index[next_worker_index] = 0;
4094 /* if this is 1st frame */
4097 f = vlib_get_frame_to_node (vm, sm->out2in_node_index);
4098 to_next = vlib_frame_vector_args (f);
4107 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
4108 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
4110 snat_out2in_worker_handoff_trace_t *t =
4111 vlib_add_trace (vm, node, b0, sizeof (*t));
4112 t->next_worker_index = next_worker_index;
4113 t->do_handoff = do_handoff;
4118 vlib_put_frame_to_node (vm, sm->out2in_node_index, f);
4121 vlib_put_frame_to_node (vm, sm->error_node_index, d);
4124 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
4126 /* Ship frames to the worker nodes */
4127 for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
4129 if (handoff_queue_elt_by_worker_index[i])
4131 hf = handoff_queue_elt_by_worker_index[i];
4133 * It works better to let the handoff node
4134 * rate-adapt, always ship the handoff queue element.
4136 if (1 || hf->n_vectors == hf->last_n_vectors)
4138 vlib_put_frame_queue_elt (hf);
4139 handoff_queue_elt_by_worker_index[i] = 0;
4142 hf->last_n_vectors = hf->n_vectors;
4144 congested_handoff_queue_by_worker_index[i] =
4145 (vlib_frame_queue_t *) (~0);
4148 current_worker_index = ~0;
4149 return frame->n_vectors;
4152 VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = {
4153 .function = snat_out2in_worker_handoff_fn,
4154 .name = "nat44-out2in-worker-handoff",
4155 .vector_size = sizeof (u32),
4156 .format_trace = format_snat_out2in_worker_handoff_trace,
4157 .type = VLIB_NODE_TYPE_INTERNAL,
4159 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
4160 .error_strings = snat_out2in_error_strings,
4169 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_worker_handoff_node, snat_out2in_worker_handoff_fn);
4172 snat_out2in_fast_node_fn (vlib_main_t * vm,
4173 vlib_node_runtime_t * node,
4174 vlib_frame_t * frame)
4176 u32 n_left_from, * from, * to_next;
4177 snat_out2in_next_t next_index;
4178 u32 pkts_processed = 0;
4179 snat_main_t * sm = &snat_main;
4181 from = vlib_frame_vector_args (frame);
4182 n_left_from = frame->n_vectors;
4183 next_index = node->cached_next_index;
4185 while (n_left_from > 0)
4189 vlib_get_next_frame (vm, node, next_index,
4190 to_next, n_left_to_next);
4192 while (n_left_from > 0 && n_left_to_next > 0)
4196 u32 next0 = SNAT_OUT2IN_NEXT_DROP;
4200 u32 new_addr0, old_addr0;
4201 u16 new_port0, old_port0;
4202 udp_header_t * udp0;
4203 tcp_header_t * tcp0;
4204 icmp46_header_t * icmp0;
4205 snat_session_key_t key0, sm0;
4209 /* speculatively enqueue b0 to the current next frame */
4215 n_left_to_next -= 1;
4217 b0 = vlib_get_buffer (vm, bi0);
4219 ip0 = vlib_buffer_get_current (b0);
4220 udp0 = ip4_next_header (ip0);
4221 tcp0 = (tcp_header_t *) udp0;
4222 icmp0 = (icmp46_header_t *) udp0;
4224 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
4225 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
4227 vnet_feature_next (&next0, b0);
4229 if (PREDICT_FALSE(ip0->ttl == 1))
4231 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
4232 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
4233 ICMP4_time_exceeded_ttl_exceeded_in_transit,
4235 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
4239 proto0 = ip_proto_to_snat_proto (ip0->protocol);
4241 if (PREDICT_FALSE (proto0 == ~0))
4244 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
4246 next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
4247 rx_fib_index0, node, next0, ~0, 0, 0);
4251 key0.addr = ip0->dst_address;
4252 key0.port = udp0->dst_port;
4253 key0.fib_index = rx_fib_index0;
4255 if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0, 0))
4257 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
4261 new_addr0 = sm0.addr.as_u32;
4262 new_port0 = sm0.port;
4263 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
4264 old_addr0 = ip0->dst_address.as_u32;
4265 ip0->dst_address.as_u32 = new_addr0;
4267 sum0 = ip0->checksum;
4268 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
4270 dst_address /* changed member */);
4271 ip0->checksum = ip_csum_fold (sum0);
4273 if (PREDICT_FALSE(new_port0 != udp0->dst_port))
4275 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
4277 old_port0 = tcp0->dst_port;
4278 tcp0->dst_port = new_port0;
4280 sum0 = tcp0->checksum;
4281 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
4283 dst_address /* changed member */);
4285 sum0 = ip_csum_update (sum0, old_port0, new_port0,
4286 ip4_header_t /* cheat */,
4287 length /* changed member */);
4288 tcp0->checksum = ip_csum_fold(sum0);
4292 old_port0 = udp0->dst_port;
4293 udp0->dst_port = new_port0;
4299 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
4301 sum0 = tcp0->checksum;
4302 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
4304 dst_address /* changed member */);
4306 tcp0->checksum = ip_csum_fold(sum0);
4312 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
4313 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
4315 snat_out2in_trace_t *t =
4316 vlib_add_trace (vm, node, b0, sizeof (*t));
4317 t->sw_if_index = sw_if_index0;
4318 t->next_index = next0;
4321 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
4323 /* verify speculative enqueue, maybe switch current next frame */
4324 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
4325 to_next, n_left_to_next,
4329 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
4332 vlib_node_increment_counter (vm, snat_out2in_fast_node.index,
4333 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
4335 return frame->n_vectors;
4338 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
4339 .function = snat_out2in_fast_node_fn,
4340 .name = "nat44-out2in-fast",
4341 .vector_size = sizeof (u32),
4342 .format_trace = format_snat_out2in_fast_trace,
4343 .type = VLIB_NODE_TYPE_INTERNAL,
4345 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
4346 .error_strings = snat_out2in_error_strings,
4348 .runtime_data_bytes = sizeof (snat_runtime_t),
4350 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
4352 /* edit / add dispositions here */
4354 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
4355 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
4356 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4357 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
4360 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn);