2 * Copyright (c) 2018 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 * @brief NAT44 endpoint-dependent inside to outside network translation
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/pg/pg.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/ethernet/ethernet.h>
25 #include <vnet/fib/ip4_fib.h>
26 #include <vppinfra/error.h>
28 #include <nat/nat_ipfix_logging.h>
29 #include <nat/nat_reass.h>
30 #include <nat/nat_inlines.h>
32 #define foreach_nat_in2out_ed_error \
33 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
34 _(IN2OUT_PACKETS, "Good in2out packets processed") \
35 _(OUT_OF_PORTS, "Out of ports") \
36 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
37 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \
38 _(DROP_FRAGMENT, "Drop fragment") \
39 _(MAX_REASS, "Maximum reassemblies exceeded") \
40 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")
44 #define _(sym,str) NAT_IN2OUT_ED_ERROR_##sym,
45 foreach_nat_in2out_ed_error
47 NAT_IN2OUT_ED_N_ERROR,
48 } nat_in2out_ed_error_t;
50 static char *nat_in2out_ed_error_strings[] = {
51 #define _(sym,string) string,
52 foreach_nat_in2out_ed_error
58 NAT_IN2OUT_ED_NEXT_LOOKUP,
59 NAT_IN2OUT_ED_NEXT_DROP,
60 NAT_IN2OUT_ED_NEXT_ICMP_ERROR,
61 NAT_IN2OUT_ED_NEXT_SLOW_PATH,
62 NAT_IN2OUT_ED_NEXT_REASS,
64 } nat_in2out_ed_next_t;
72 } nat_in2out_ed_trace_t;
74 vlib_node_registration_t nat44_ed_in2out_node;
75 vlib_node_registration_t nat44_ed_in2out_slowpath_node;
76 vlib_node_registration_t nat44_ed_in2out_output_node;
77 vlib_node_registration_t nat44_ed_in2out_output_slowpath_node;
78 vlib_node_registration_t nat44_ed_in2out_reass_node;
81 format_nat_in2out_ed_trace (u8 * s, va_list * args)
83 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
84 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
85 nat_in2out_ed_trace_t *t = va_arg (*args, nat_in2out_ed_trace_t *);
89 t->is_slow_path ? "NAT44_IN2OUT_ED_SLOW_PATH" :
90 "NAT44_IN2OUT_ED_FAST_PATH";
92 s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
93 t->sw_if_index, t->next_index, t->session_index);
98 static_always_inline int
99 icmp_get_ed_key (ip4_header_t * ip0, nat_ed_ses_key_t * p_key0)
101 icmp46_header_t *icmp0;
102 nat_ed_ses_key_t key0;
103 icmp_echo_header_t *echo0, *inner_echo0 = 0;
104 ip4_header_t *inner_ip0 = 0;
106 icmp46_header_t *inner_icmp0;
108 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
109 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
111 if (!icmp_is_error_message (icmp0))
113 key0.proto = IP_PROTOCOL_ICMP;
114 key0.l_addr = ip0->src_address;
115 key0.r_addr = ip0->dst_address;
116 key0.l_port = echo0->identifier;
121 inner_ip0 = (ip4_header_t *) (echo0 + 1);
122 l4_header = ip4_next_header (inner_ip0);
123 key0.proto = inner_ip0->protocol;
124 key0.r_addr = inner_ip0->src_address;
125 key0.l_addr = inner_ip0->dst_address;
126 switch (ip_proto_to_snat_proto (inner_ip0->protocol))
128 case SNAT_PROTOCOL_ICMP:
129 inner_icmp0 = (icmp46_header_t *) l4_header;
130 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
132 key0.l_port = inner_echo0->identifier;
134 case SNAT_PROTOCOL_UDP:
135 case SNAT_PROTOCOL_TCP:
136 key0.l_port = ((tcp_udp_header_t *) l4_header)->dst_port;
137 key0.r_port = ((tcp_udp_header_t *) l4_header)->src_port;
140 return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
148 nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
150 snat_main_t *sm = &snat_main;
151 nat44_is_idle_session_ctx_t *ctx = arg;
153 u64 sess_timeout_time;
154 nat_ed_ses_key_t ed_key;
155 clib_bihash_kv_16_8_t ed_kv;
158 snat_session_key_t key;
159 snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
162 s = pool_elt_at_index (tsm->sessions, kv->value);
163 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
164 if (ctx->now >= sess_timeout_time)
166 if (is_fwd_bypass_session (s))
169 ed_key.l_addr = s->out2in.addr;
170 ed_key.r_addr = s->ext_host_addr;
171 ed_key.fib_index = s->out2in.fib_index;
172 if (snat_is_unk_proto_session (s))
174 ed_key.proto = s->in2out.port;
180 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
181 ed_key.l_port = s->out2in.port;
182 ed_key.r_port = s->ext_host_port;
184 ed_kv.key[0] = ed_key.as_u64[0];
185 ed_kv.key[1] = ed_key.as_u64[1];
186 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
187 nat_log_warn ("out2in_ed key del failed");
189 if (snat_is_unk_proto_session (s))
192 snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
193 s->out2in.addr.as_u32,
197 s->in2out.fib_index);
199 if (is_twice_nat_session (s))
201 for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
203 key.protocol = s->in2out.protocol;
204 key.port = s->ext_host_nat_port;
205 a = sm->twice_nat_addresses + i;
206 if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
208 snat_free_outside_address_and_port (sm->twice_nat_addresses,
216 if (snat_is_session_static (s))
219 snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
222 nat44_delete_session (sm, s, ctx->thread_index);
230 icmp_in2out_ed_slow_path (snat_main_t * sm, vlib_buffer_t * b0,
231 ip4_header_t * ip0, icmp46_header_t * icmp0,
232 u32 sw_if_index0, u32 rx_fib_index0,
233 vlib_node_runtime_t * node, u32 next0, f64 now,
234 u32 thread_index, snat_session_t ** p_s0)
236 next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
237 next0, thread_index, p_s0, 0);
238 snat_session_t *s0 = *p_s0;
239 if (PREDICT_TRUE (next0 != NAT_IN2OUT_ED_NEXT_DROP && s0))
242 if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
243 snat_icmp_hairpinning (sm, b0, ip0, icmp0, sm->endpoint_dependent);
245 nat44_session_update_counters (s0, now,
246 vlib_buffer_length_in_chain
247 (sm->vlib_main, b0));
253 slow_path_ed (snat_main_t * sm,
256 clib_bihash_kv_16_8_t * kv,
257 snat_session_t ** sessionp,
258 vlib_node_runtime_t * node, u32 next, u32 thread_index, f64 now)
262 snat_session_key_t key0, key1;
263 lb_nat_type_t lb = 0, is_sm = 0;
264 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
265 nat_ed_ses_key_t *key = (nat_ed_ses_key_t *) kv->key;
266 u32 proto = ip_proto_to_snat_proto (key->proto);
267 nat_outside_fib_t *outside_fib;
268 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
270 .fp_proto = FIB_PROTOCOL_IP4,
273 .ip4.as_u32 = key->r_addr.as_u32,
276 nat44_is_idle_session_ctx_t ctx;
278 if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
280 b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
281 nat_ipfix_logging_max_sessions (sm->max_translations);
282 nat_log_notice ("maximum sessions exceeded");
283 return NAT_IN2OUT_ED_NEXT_DROP;
286 key0.addr = key->l_addr;
287 key0.port = key->l_port;
288 key1.protocol = key0.protocol = proto;
289 key0.fib_index = rx_fib_index;
290 key1.fib_index = sm->outside_fib_index;
291 /* First try to match static mapping by local address and port */
292 if (snat_static_mapping_match (sm, key0, &key1, 0, 0, 0, &lb, 0))
294 /* Try to create dynamic translation */
295 if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index,
298 tsm->snat_thread_index))
300 nat_log_notice ("addresses exhausted");
301 b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
302 return NAT_IN2OUT_ED_NEXT_DROP;
308 u = nat_user_get_or_create (sm, &key->l_addr, rx_fib_index, thread_index);
311 nat_log_warn ("create NAT user failed");
313 snat_free_outside_address_and_port (sm->addresses,
314 thread_index, &key1);
315 return NAT_IN2OUT_ED_NEXT_DROP;
318 s = nat_ed_session_alloc (sm, u, thread_index);
321 nat44_delete_user_with_no_session (sm, u, thread_index);
322 nat_log_warn ("create NAT session failed");
324 snat_free_outside_address_and_port (sm->addresses,
325 thread_index, &key1);
326 return NAT_IN2OUT_ED_NEXT_DROP;
329 user_session_increment (sm, u, is_sm);
331 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
333 s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
334 s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
335 s->ext_host_addr = key->r_addr;
336 s->ext_host_port = key->r_port;
339 s->out2in.protocol = key0.protocol;
341 switch (vec_len (sm->outside_fibs))
344 s->out2in.fib_index = sm->outside_fib_index;
347 s->out2in.fib_index = sm->outside_fibs[0].fib_index;
351 vec_foreach (outside_fib, sm->outside_fibs)
353 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
354 if (FIB_NODE_INDEX_INVALID != fei)
356 if (fib_entry_get_resolving_interface (fei) != ~0)
358 s->out2in.fib_index = outside_fib->fib_index;
367 /* Add to lookup tables */
368 kv->value = s - tsm->sessions;
370 ctx.thread_index = thread_index;
371 if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, kv,
372 nat44_i2o_ed_is_idle_session_cb,
374 nat_log_notice ("in2out-ed key add failed");
376 make_ed_kv (kv, &key1.addr, &key->r_addr, key->proto, s->out2in.fib_index,
377 key1.port, key->r_port);
378 kv->value = s - tsm->sessions;
379 if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->out2in_ed, kv,
380 nat44_o2i_ed_is_idle_session_cb,
382 nat_log_notice ("out2in-ed key add failed");
387 snat_ipfix_logging_nat44_ses_create (s->in2out.addr.as_u32,
388 s->out2in.addr.as_u32,
391 s->out2in.port, s->in2out.fib_index);
395 static_always_inline int
396 nat44_ed_not_translate (snat_main_t * sm, vlib_node_runtime_t * node,
397 u32 sw_if_index, ip4_header_t * ip, u32 proto,
398 u32 rx_fib_index, u32 thread_index)
400 udp_header_t *udp = ip4_next_header (ip);
401 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
402 clib_bihash_kv_16_8_t kv, value;
403 snat_session_key_t key0, key1;
405 make_ed_kv (&kv, &ip->dst_address, &ip->src_address, ip->protocol,
406 sm->outside_fib_index, udp->dst_port, udp->src_port);
408 /* NAT packet aimed at external address if */
409 /* has active sessions */
410 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
412 key0.addr = ip->dst_address;
413 key0.port = udp->dst_port;
414 key0.protocol = proto;
415 key0.fib_index = sm->outside_fib_index;
416 /* or is static mappings */
417 if (!snat_static_mapping_match (sm, key0, &key1, 1, 0, 0, 0, 0))
423 if (sm->forwarding_enabled)
426 return snat_not_translate_fast (sm, node, sw_if_index, ip, proto,
430 static_always_inline int
431 nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
432 u32 thread_index, f64 now,
433 vlib_main_t * vm, vlib_buffer_t * b)
435 nat_ed_ses_key_t key;
436 clib_bihash_kv_16_8_t kv, value;
438 snat_session_t *s = 0;
439 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
441 if (!sm->forwarding_enabled)
444 if (ip->protocol == IP_PROTOCOL_ICMP)
446 key.as_u64[0] = key.as_u64[1] = 0;
447 if (icmp_get_ed_key (ip, &key))
450 kv.key[0] = key.as_u64[0];
451 kv.key[1] = key.as_u64[1];
453 else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
455 udp = ip4_next_header (ip);
456 make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0,
457 udp->src_port, udp->dst_port);
461 make_ed_kv (&kv, &ip->src_address, &ip->dst_address, ip->protocol, 0, 0,
465 if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
467 s = pool_elt_at_index (tsm->sessions, value.value);
468 if (is_fwd_bypass_session (s))
470 if (ip->protocol == IP_PROTOCOL_TCP)
472 tcp_header_t *tcp = ip4_next_header (ip);
473 if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index))
477 nat44_session_update_counters (s, now,
478 vlib_buffer_length_in_chain (vm, b));
488 static_always_inline int
489 nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
490 u8 proto, u16 src_port, u16 dst_port,
491 u32 thread_index, u32 rx_sw_if_index,
494 clib_bihash_kv_16_8_t kv, value;
495 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
498 u32 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (rx_sw_if_index);
499 u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index);
502 make_ed_kv (&kv, &ip->src_address, &ip->dst_address, proto, tx_fib_index,
504 if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
508 make_ed_kv (&kv, &ip->dst_address, &ip->src_address, proto, rx_fib_index,
510 if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
512 s = pool_elt_at_index (tsm->sessions, value.value);
513 if (is_fwd_bypass_session (s))
518 pool_foreach (i, sm->output_feature_interfaces,
520 if ((nat_interface_is_inside (i)) && (rx_sw_if_index == i->sw_if_index))
531 icmp_match_in2out_ed (snat_main_t * sm, vlib_node_runtime_t * node,
532 u32 thread_index, vlib_buffer_t * b, ip4_header_t * ip,
533 u8 * p_proto, snat_session_key_t * p_value,
534 u8 * p_dont_translate, void *d, void *e)
536 icmp46_header_t *icmp;
539 nat_ed_ses_key_t key;
540 snat_session_t *s = 0;
541 u8 dont_translate = 0;
542 clib_bihash_kv_16_8_t kv, value;
545 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
547 icmp = (icmp46_header_t *) ip4_next_header (ip);
548 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
549 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
551 key.as_u64[0] = key.as_u64[1] = 0;
552 err = icmp_get_ed_key (ip, &key);
555 b->error = node->errors[err];
556 next = NAT_IN2OUT_ED_NEXT_DROP;
559 key.fib_index = rx_fib_index;
561 kv.key[0] = key.as_u64[0];
562 kv.key[1] = key.as_u64[1];
564 if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
566 if (vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0)
568 if (PREDICT_FALSE (nat44_ed_not_translate_output_feature (sm, ip,
587 if (PREDICT_FALSE (nat44_ed_not_translate (sm, node, sw_if_index,
588 ip, SNAT_PROTOCOL_ICMP,
597 if (PREDICT_FALSE (icmp_is_error_message (icmp)))
599 b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
600 next = NAT_IN2OUT_ED_NEXT_DROP;
604 next = slow_path_ed (sm, b, rx_fib_index, &kv, &s, node, next,
605 thread_index, vlib_time_now (sm->vlib_main));
607 if (PREDICT_FALSE (next == NAT_IN2OUT_ED_NEXT_DROP))
612 if (PREDICT_FALSE (icmp->type != ICMP4_echo_request &&
613 icmp->type != ICMP4_echo_reply &&
614 !icmp_is_error_message (icmp)))
616 b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
617 next = NAT_IN2OUT_ED_NEXT_DROP;
621 s = pool_elt_at_index (tsm->sessions, value.value);
624 *p_proto = ip_proto_to_snat_proto (key.proto);
627 *p_value = s->out2in;
628 *p_dont_translate = dont_translate;
630 *(snat_session_t **) d = s;
634 static snat_session_t *
635 nat44_ed_in2out_unknown_proto (snat_main_t * sm,
641 vlib_main_t * vm, vlib_node_runtime_t * node)
643 clib_bihash_kv_8_8_t kv, value;
644 clib_bihash_kv_16_8_t s_kv, s_value;
645 snat_static_mapping_t *m;
646 u32 old_addr, new_addr = 0;
649 dlist_elt_t *head, *elt;
650 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
651 u32 elt_index, head_index, ses_index;
653 u32 outside_fib_index = sm->outside_fib_index;
656 nat_outside_fib_t *outside_fib;
657 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
659 .fp_proto = FIB_PROTOCOL_IP4,
662 .ip4.as_u32 = ip->dst_address.as_u32,
666 switch (vec_len (sm->outside_fibs))
669 outside_fib_index = sm->outside_fib_index;
672 outside_fib_index = sm->outside_fibs[0].fib_index;
676 vec_foreach (outside_fib, sm->outside_fibs)
678 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
679 if (FIB_NODE_INDEX_INVALID != fei)
681 if (fib_entry_get_resolving_interface (fei) != ~0)
683 outside_fib_index = outside_fib->fib_index;
691 old_addr = ip->src_address.as_u32;
693 make_ed_kv (&s_kv, &ip->src_address, &ip->dst_address, ip->protocol,
696 if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &s_kv, &s_value))
698 s = pool_elt_at_index (tsm->sessions, s_value.value);
699 new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
703 if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
705 b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
706 nat_ipfix_logging_max_sessions (sm->max_translations);
707 nat_log_notice ("maximum sessions exceeded");
711 u = nat_user_get_or_create (sm, &ip->src_address, rx_fib_index,
715 nat_log_warn ("create NAT user failed");
719 make_sm_kv (&kv, &ip->src_address, 0, rx_fib_index, 0);
721 /* Try to find static mapping first */
722 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
724 m = pool_elt_at_index (sm->static_mappings, value.value);
725 new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
729 /* Fallback to 3-tuple key */
732 /* Choose same out address as for TCP/UDP session to same destination */
733 head_index = u->sessions_per_user_list_head_index;
734 head = pool_elt_at_index (tsm->list_pool, head_index);
735 elt_index = head->next;
736 if (PREDICT_FALSE (elt_index == ~0))
740 elt = pool_elt_at_index (tsm->list_pool, elt_index);
741 ses_index = elt->value;
744 while (ses_index != ~0)
746 s = pool_elt_at_index (tsm->sessions, ses_index);
747 elt_index = elt->next;
748 elt = pool_elt_at_index (tsm->list_pool, elt_index);
749 ses_index = elt->value;
751 if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
753 new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
755 make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address,
756 ip->protocol, outside_fib_index, 0, 0);
757 if (clib_bihash_search_16_8
758 (&tsm->out2in_ed, &s_kv, &s_value))
765 for (i = 0; i < vec_len (sm->addresses); i++)
767 make_ed_kv (&s_kv, &sm->addresses[i].addr, &ip->dst_address,
768 ip->protocol, outside_fib_index, 0, 0);
769 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &s_kv, &s_value))
771 new_addr = ip->src_address.as_u32 =
772 sm->addresses[i].addr.as_u32;
780 s = nat_ed_session_alloc (sm, u, thread_index);
783 nat44_delete_user_with_no_session (sm, u, thread_index);
784 nat_log_warn ("create NAT session failed");
788 s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
789 s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
790 s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
791 s->out2in.addr.as_u32 = new_addr;
792 s->out2in.fib_index = outside_fib_index;
793 s->in2out.addr.as_u32 = old_addr;
794 s->in2out.fib_index = rx_fib_index;
795 s->in2out.port = s->out2in.port = ip->protocol;
797 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
798 user_session_increment (sm, u, is_sm);
800 /* Add to lookup tables */
801 make_ed_kv (&s_kv, &s->in2out.addr, &ip->dst_address, ip->protocol,
803 s_kv.value = s - tsm->sessions;
804 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
805 nat_log_notice ("in2out key add failed");
807 make_ed_kv (&s_kv, &s->out2in.addr, &ip->dst_address, ip->protocol,
808 outside_fib_index, 0, 0);
809 s_kv.value = s - tsm->sessions;
810 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &s_kv, 1))
811 nat_log_notice ("out2in key add failed");
814 /* Update IP checksum */
816 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
817 ip->checksum = ip_csum_fold (sum);
820 nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b));
823 if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
824 nat44_ed_hairpinning_unknown_proto (sm, b, ip);
826 if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
827 vnet_buffer (b)->sw_if_index[VLIB_TX] = outside_fib_index;
833 nat44_ed_in2out_node_fn_inline (vlib_main_t * vm,
834 vlib_node_runtime_t * node,
835 vlib_frame_t * frame, int is_slow_path,
836 int is_output_feature)
838 u32 n_left_from, *from, *to_next, pkts_processed = 0, stats_node_index;
839 nat_in2out_ed_next_t next_index;
840 snat_main_t *sm = &snat_main;
841 f64 now = vlib_time_now (vm);
842 u32 thread_index = vm->thread_index;
843 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
845 stats_node_index = is_slow_path ? nat44_ed_in2out_slowpath_node.index :
846 nat44_ed_in2out_node.index;
848 from = vlib_frame_vector_args (frame);
849 n_left_from = frame->n_vectors;
850 next_index = node->cached_next_index;
852 while (n_left_from > 0)
856 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
858 while (n_left_from >= 4 && n_left_to_next >= 2)
861 vlib_buffer_t *b0, *b1;
862 u32 next0, sw_if_index0, rx_fib_index0, iph_offset0 = 0, proto0,
863 new_addr0, old_addr0;
864 u32 next1, sw_if_index1, rx_fib_index1, iph_offset1 = 0, proto1,
865 new_addr1, old_addr1;
866 u16 old_port0, new_port0, old_port1, new_port1;
867 ip4_header_t *ip0, *ip1;
868 udp_header_t *udp0, *udp1;
869 tcp_header_t *tcp0, *tcp1;
870 icmp46_header_t *icmp0, *icmp1;
871 snat_session_t *s0 = 0, *s1 = 0;
872 clib_bihash_kv_16_8_t kv0, value0, kv1, value1;
873 ip_csum_t sum0, sum1;
875 /* Prefetch next iteration. */
877 vlib_buffer_t *p2, *p3;
879 p2 = vlib_get_buffer (vm, from[2]);
880 p3 = vlib_get_buffer (vm, from[3]);
882 vlib_prefetch_buffer_header (p2, LOAD);
883 vlib_prefetch_buffer_header (p3, LOAD);
885 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
886 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
889 /* speculatively enqueue b0 and b1 to the current next frame */
890 to_next[0] = bi0 = from[0];
891 to_next[1] = bi1 = from[1];
897 b0 = vlib_get_buffer (vm, bi0);
898 b1 = vlib_get_buffer (vm, bi1);
900 next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
902 if (is_output_feature)
903 iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
905 ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
908 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
910 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
913 if (PREDICT_FALSE (ip0->ttl == 1))
915 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
916 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
917 ICMP4_time_exceeded_ttl_exceeded_in_transit,
919 next0 = NAT_IN2OUT_ED_NEXT_ICMP_ERROR;
923 udp0 = ip4_next_header (ip0);
924 tcp0 = (tcp_header_t *) udp0;
925 icmp0 = (icmp46_header_t *) udp0;
926 proto0 = ip_proto_to_snat_proto (ip0->protocol);
930 if (PREDICT_FALSE (proto0 == ~0))
932 s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
934 thread_index, now, vm,
937 next0 = NAT_IN2OUT_ED_NEXT_DROP;
941 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
943 next0 = icmp_in2out_ed_slow_path
944 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
945 next0, now, thread_index, &s0);
951 if (PREDICT_FALSE (proto0 == ~0))
953 next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
957 if (ip4_is_fragment (ip0))
959 next0 = NAT_IN2OUT_ED_NEXT_REASS;
963 if (is_output_feature)
966 (nat_not_translate_output_feature_fwd
967 (sm, ip0, thread_index, now, vm, b0)))
971 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
973 next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
978 make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
979 ip0->protocol, rx_fib_index0, udp0->src_port,
982 if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
986 if (is_output_feature)
989 (nat44_ed_not_translate_output_feature
990 (sm, ip0, ip0->protocol, udp0->src_port,
991 udp0->dst_port, thread_index, sw_if_index0,
992 vnet_buffer (b0)->sw_if_index[VLIB_TX])))
997 if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1006 slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node,
1007 next0, thread_index, now);
1009 if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1014 next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1020 s0 = pool_elt_at_index (tsm->sessions, value0.value);
1023 b0->flags |= VNET_BUFFER_F_IS_NATED;
1025 if (!is_output_feature)
1026 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1028 old_addr0 = ip0->src_address.as_u32;
1029 new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1030 sum0 = ip0->checksum;
1031 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1033 if (PREDICT_FALSE (is_twice_nat_session (s0)))
1034 sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1035 s0->ext_host_addr.as_u32, ip4_header_t,
1037 ip0->checksum = ip_csum_fold (sum0);
1039 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1041 old_port0 = tcp0->src_port;
1042 new_port0 = tcp0->src_port = s0->out2in.port;
1044 sum0 = tcp0->checksum;
1045 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1047 sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1049 if (PREDICT_FALSE (is_twice_nat_session (s0)))
1051 sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1052 s0->ext_host_addr.as_u32,
1053 ip4_header_t, dst_address);
1054 sum0 = ip_csum_update (sum0, tcp0->dst_port,
1055 s0->ext_host_port, ip4_header_t,
1057 tcp0->dst_port = s0->ext_host_port;
1058 ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1060 mss_clamping (sm, tcp0, &sum0);
1061 tcp0->checksum = ip_csum_fold (sum0);
1062 if (nat44_set_tcp_session_state_i2o
1063 (sm, s0, tcp0, thread_index))
1068 udp0->src_port = s0->out2in.port;
1070 if (PREDICT_FALSE (is_twice_nat_session (s0)))
1072 udp0->dst_port = s0->ext_host_port;
1073 ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1078 nat44_session_update_counters (s0, now,
1079 vlib_buffer_length_in_chain (vm,
1083 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1084 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1086 nat_in2out_ed_trace_t *t =
1087 vlib_add_trace (vm, node, b0, sizeof (*t));
1088 t->is_slow_path = is_slow_path;
1089 t->sw_if_index = sw_if_index0;
1090 t->next_index = next0;
1091 t->session_index = ~0;
1093 t->session_index = s0 - tsm->sessions;
1096 pkts_processed += next0 != NAT_IN2OUT_ED_NEXT_DROP;
1099 next1 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1101 if (is_output_feature)
1102 iph_offset1 = vnet_buffer (b1)->ip.save_rewrite_length;
1104 ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1107 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1109 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1112 if (PREDICT_FALSE (ip1->ttl == 1))
1114 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1115 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1116 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1118 next1 = NAT_IN2OUT_ED_NEXT_ICMP_ERROR;
1122 udp1 = ip4_next_header (ip1);
1123 tcp1 = (tcp_header_t *) udp1;
1124 icmp1 = (icmp46_header_t *) udp1;
1125 proto1 = ip_proto_to_snat_proto (ip1->protocol);
1129 if (PREDICT_FALSE (proto1 == ~0))
1131 s1 = nat44_ed_in2out_unknown_proto (sm, b1, ip1,
1133 thread_index, now, vm,
1136 next1 = NAT_IN2OUT_ED_NEXT_DROP;
1140 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1142 next1 = icmp_in2out_ed_slow_path
1143 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1144 next1, now, thread_index, &s1);
1150 if (PREDICT_FALSE (proto1 == ~0))
1152 next1 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1156 if (ip4_is_fragment (ip1))
1158 next1 = NAT_IN2OUT_ED_NEXT_REASS;
1162 if (is_output_feature)
1165 (nat_not_translate_output_feature_fwd
1166 (sm, ip1, thread_index, now, vm, b1)))
1170 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1172 next1 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1177 make_ed_kv (&kv1, &ip1->src_address, &ip1->dst_address,
1178 ip1->protocol, rx_fib_index1, udp1->src_port,
1181 if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv1, &value1))
1185 if (is_output_feature)
1188 (nat44_ed_not_translate_output_feature
1189 (sm, ip1, ip1->protocol, udp1->src_port,
1190 udp1->dst_port, thread_index, sw_if_index1,
1191 vnet_buffer (b1)->sw_if_index[VLIB_TX])))
1196 if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1205 slow_path_ed (sm, b1, rx_fib_index1, &kv1, &s1, node,
1206 next1, thread_index, now);
1208 if (PREDICT_FALSE (next1 == NAT_IN2OUT_ED_NEXT_DROP))
1213 next1 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1219 s1 = pool_elt_at_index (tsm->sessions, value1.value);
1222 b1->flags |= VNET_BUFFER_F_IS_NATED;
1224 if (!is_output_feature)
1225 vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1227 old_addr1 = ip1->src_address.as_u32;
1228 new_addr1 = ip1->src_address.as_u32 = s1->out2in.addr.as_u32;
1229 sum1 = ip1->checksum;
1230 sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1232 if (PREDICT_FALSE (is_twice_nat_session (s1)))
1233 sum1 = ip_csum_update (sum1, ip1->dst_address.as_u32,
1234 s1->ext_host_addr.as_u32, ip4_header_t,
1236 ip1->checksum = ip_csum_fold (sum1);
1238 if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1240 old_port1 = tcp1->src_port;
1241 new_port1 = tcp1->src_port = s1->out2in.port;
1243 sum1 = tcp1->checksum;
1244 sum1 = ip_csum_update (sum1, old_addr1, new_addr1, ip4_header_t,
1246 sum1 = ip_csum_update (sum1, old_port1, new_port1, ip4_header_t,
1248 if (PREDICT_FALSE (is_twice_nat_session (s1)))
1250 sum1 = ip_csum_update (sum1, ip1->dst_address.as_u32,
1251 s1->ext_host_addr.as_u32,
1252 ip4_header_t, dst_address);
1253 sum1 = ip_csum_update (sum1, tcp1->dst_port,
1254 s1->ext_host_port, ip4_header_t,
1256 tcp1->dst_port = s1->ext_host_port;
1257 ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
1259 tcp1->checksum = ip_csum_fold (sum1);
1260 mss_clamping (sm, tcp1, &sum1);
1261 if (nat44_set_tcp_session_state_i2o
1262 (sm, s1, tcp1, thread_index))
1267 udp1->src_port = s1->out2in.port;
1269 if (PREDICT_FALSE (is_twice_nat_session (s1)))
1271 udp1->dst_port = s1->ext_host_port;
1272 ip1->dst_address.as_u32 = s1->ext_host_addr.as_u32;
1277 nat44_session_update_counters (s1, now,
1278 vlib_buffer_length_in_chain (vm,
1282 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1283 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1285 nat_in2out_ed_trace_t *t =
1286 vlib_add_trace (vm, node, b1, sizeof (*t));
1287 t->is_slow_path = is_slow_path;
1288 t->sw_if_index = sw_if_index1;
1289 t->next_index = next1;
1290 t->session_index = ~0;
1292 t->session_index = s1 - tsm->sessions;
1295 pkts_processed += next1 != NAT_IN2OUT_ED_NEXT_DROP;
1297 /* verify speculative enqueues, maybe switch current next frame */
1298 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1299 to_next, n_left_to_next,
1300 bi0, bi1, next0, next1);
1303 while (n_left_from > 0 && n_left_to_next > 0)
1307 u32 next0, sw_if_index0, rx_fib_index0, iph_offset0 = 0, proto0,
1308 new_addr0, old_addr0;
1309 u16 old_port0, new_port0;
1313 icmp46_header_t *icmp0;
1314 snat_session_t *s0 = 0;
1315 clib_bihash_kv_16_8_t kv0, value0;
1318 /* speculatively enqueue b0 to the current next frame */
1324 n_left_to_next -= 1;
1326 b0 = vlib_get_buffer (vm, bi0);
1327 next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1329 if (is_output_feature)
1330 iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1332 ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1335 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1337 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1340 if (PREDICT_FALSE (ip0->ttl == 1))
1342 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1343 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1344 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1346 next0 = NAT_IN2OUT_ED_NEXT_ICMP_ERROR;
1350 udp0 = ip4_next_header (ip0);
1351 tcp0 = (tcp_header_t *) udp0;
1352 icmp0 = (icmp46_header_t *) udp0;
1353 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1357 if (PREDICT_FALSE (proto0 == ~0))
1359 s0 = nat44_ed_in2out_unknown_proto (sm, b0, ip0,
1361 thread_index, now, vm,
1364 next0 = NAT_IN2OUT_ED_NEXT_DROP;
1368 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1370 next0 = icmp_in2out_ed_slow_path
1371 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1372 next0, now, thread_index, &s0);
1378 if (PREDICT_FALSE (proto0 == ~0))
1380 next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1384 if (ip4_is_fragment (ip0))
1386 next0 = NAT_IN2OUT_ED_NEXT_REASS;
1390 if (is_output_feature)
1393 (nat_not_translate_output_feature_fwd
1394 (sm, ip0, thread_index, now, vm, b0)))
1398 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1400 next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1405 make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1406 ip0->protocol, rx_fib_index0, udp0->src_port,
1409 if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
1413 if (is_output_feature)
1416 (nat44_ed_not_translate_output_feature
1417 (sm, ip0, ip0->protocol, udp0->src_port,
1418 udp0->dst_port, thread_index, sw_if_index0,
1419 vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1424 if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1433 slow_path_ed (sm, b0, rx_fib_index0, &kv0, &s0, node,
1434 next0, thread_index, now);
1436 if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1441 next0 = NAT_IN2OUT_ED_NEXT_SLOW_PATH;
1447 s0 = pool_elt_at_index (tsm->sessions, value0.value);
1450 b0->flags |= VNET_BUFFER_F_IS_NATED;
1452 if (!is_output_feature)
1453 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1455 old_addr0 = ip0->src_address.as_u32;
1456 new_addr0 = ip0->src_address.as_u32 = s0->out2in.addr.as_u32;
1457 sum0 = ip0->checksum;
1458 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1460 if (PREDICT_FALSE (is_twice_nat_session (s0)))
1461 sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1462 s0->ext_host_addr.as_u32, ip4_header_t,
1464 ip0->checksum = ip_csum_fold (sum0);
1466 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1468 old_port0 = tcp0->src_port;
1469 new_port0 = tcp0->src_port = s0->out2in.port;
1471 sum0 = tcp0->checksum;
1472 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
1474 sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
1476 if (PREDICT_FALSE (is_twice_nat_session (s0)))
1478 sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1479 s0->ext_host_addr.as_u32,
1480 ip4_header_t, dst_address);
1481 sum0 = ip_csum_update (sum0, tcp0->dst_port,
1482 s0->ext_host_port, ip4_header_t,
1484 tcp0->dst_port = s0->ext_host_port;
1485 ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1487 mss_clamping (sm, tcp0, &sum0);
1488 tcp0->checksum = ip_csum_fold (sum0);
1489 if (nat44_set_tcp_session_state_i2o
1490 (sm, s0, tcp0, thread_index))
1495 udp0->src_port = s0->out2in.port;
1497 if (PREDICT_FALSE (is_twice_nat_session (s0)))
1499 udp0->dst_port = s0->ext_host_port;
1500 ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1505 nat44_session_update_counters (s0, now,
1506 vlib_buffer_length_in_chain (vm,
1510 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1511 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1513 nat_in2out_ed_trace_t *t =
1514 vlib_add_trace (vm, node, b0, sizeof (*t));
1515 t->is_slow_path = is_slow_path;
1516 t->sw_if_index = sw_if_index0;
1517 t->next_index = next0;
1518 t->session_index = ~0;
1520 t->session_index = s0 - tsm->sessions;
1523 pkts_processed += next0 != NAT_IN2OUT_ED_NEXT_DROP;
1525 /* verify speculative enqueue, maybe switch current next frame */
1526 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1527 to_next, n_left_to_next,
1531 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1534 vlib_node_increment_counter (vm, stats_node_index,
1535 NAT_IN2OUT_ED_ERROR_IN2OUT_PACKETS,
1537 return frame->n_vectors;
1541 nat44_ed_in2out_fast_path_fn (vlib_main_t * vm,
1542 vlib_node_runtime_t * node,
1543 vlib_frame_t * frame)
1545 return nat44_ed_in2out_node_fn_inline (vm, node, frame, 0, 0);
1549 VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
1550 .function = nat44_ed_in2out_fast_path_fn,
1551 .name = "nat44-ed-in2out",
1552 .vector_size = sizeof (u32),
1553 .format_trace = format_nat_in2out_ed_trace,
1554 .type = VLIB_NODE_TYPE_INTERNAL,
1555 .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1556 .error_strings = nat_in2out_ed_error_strings,
1557 .runtime_data_bytes = sizeof (snat_runtime_t),
1558 .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1560 [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1561 [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
1562 [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-slowpath",
1563 [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1564 [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1569 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_in2out_node,
1570 nat44_ed_in2out_fast_path_fn);
1573 nat44_ed_in2out_output_fast_path_fn (vlib_main_t * vm,
1574 vlib_node_runtime_t * node,
1575 vlib_frame_t * frame)
1577 return nat44_ed_in2out_node_fn_inline (vm, node, frame, 0, 1);
1581 VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
1582 .function = nat44_ed_in2out_output_fast_path_fn,
1583 .name = "nat44-ed-in2out-output",
1584 .vector_size = sizeof (u32),
1585 .format_trace = format_nat_in2out_ed_trace,
1586 .type = VLIB_NODE_TYPE_INTERNAL,
1587 .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1588 .error_strings = nat_in2out_ed_error_strings,
1589 .runtime_data_bytes = sizeof (snat_runtime_t),
1590 .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1592 [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1593 [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
1594 [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
1595 [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1596 [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass-output",
1601 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_in2out_output_node,
1602 nat44_ed_in2out_output_fast_path_fn);
1605 nat44_ed_in2out_slow_path_fn (vlib_main_t * vm,
1606 vlib_node_runtime_t * node,
1607 vlib_frame_t * frame)
1609 return nat44_ed_in2out_node_fn_inline (vm, node, frame, 1, 0);
1613 VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
1614 .function = nat44_ed_in2out_slow_path_fn,
1615 .name = "nat44-ed-in2out-slowpath",
1616 .vector_size = sizeof (u32),
1617 .format_trace = format_nat_in2out_ed_trace,
1618 .type = VLIB_NODE_TYPE_INTERNAL,
1619 .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1620 .error_strings = nat_in2out_ed_error_strings,
1621 .runtime_data_bytes = sizeof (snat_runtime_t),
1622 .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1624 [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1625 [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
1626 [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-slowpath",
1627 [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1628 [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1633 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_in2out_slowpath_node,
1634 nat44_ed_in2out_slow_path_fn);
1637 nat44_ed_in2out_output_slow_path_fn (vlib_main_t * vm,
1638 vlib_node_runtime_t * node,
1639 vlib_frame_t * frame)
1641 return nat44_ed_in2out_node_fn_inline (vm, node, frame, 1, 1);
1645 VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
1646 .function = nat44_ed_in2out_output_slow_path_fn,
1647 .name = "nat44-ed-in2out-output-slowpath",
1648 .vector_size = sizeof (u32),
1649 .format_trace = format_nat_in2out_ed_trace,
1650 .type = VLIB_NODE_TYPE_INTERNAL,
1651 .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
1652 .error_strings = nat_in2out_ed_error_strings,
1653 .runtime_data_bytes = sizeof (snat_runtime_t),
1654 .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
1656 [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
1657 [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
1658 [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
1659 [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1660 [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
1665 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_in2out_output_slowpath_node,
1666 nat44_ed_in2out_output_slow_path_fn);
1669 nat44_ed_in2out_reass_node_fn_inline (vlib_main_t * vm,
1670 vlib_node_runtime_t * node,
1671 vlib_frame_t * frame,
1672 int is_output_feature)
1674 u32 n_left_from, *from, *to_next;
1675 nat_in2out_ed_next_t next_index;
1676 u32 pkts_processed = 0;
1677 snat_main_t *sm = &snat_main;
1678 f64 now = vlib_time_now (vm);
1679 u32 thread_index = vm->thread_index;
1680 snat_main_per_thread_data_t *per_thread_data =
1681 &sm->per_thread_data[thread_index];
1682 u32 *fragments_to_drop = 0;
1683 u32 *fragments_to_loopback = 0;
1685 from = vlib_frame_vector_args (frame);
1686 n_left_from = frame->n_vectors;
1687 next_index = node->cached_next_index;
1689 while (n_left_from > 0)
1693 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1695 while (n_left_from > 0 && n_left_to_next > 0)
1697 u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1698 u32 iph_offset0 = 0;
1702 ip4_header_t *ip0 = 0;
1703 nat_reass_ip4_t *reass0;
1706 icmp46_header_t *icmp0;
1707 clib_bihash_kv_16_8_t kv0, value0;
1708 snat_session_t *s0 = 0;
1709 u16 old_port0, new_port0;
1712 /* speculatively enqueue b0 to the current next frame */
1718 n_left_to_next -= 1;
1720 b0 = vlib_get_buffer (vm, bi0);
1722 next0 = NAT_IN2OUT_ED_NEXT_LOOKUP;
1724 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1726 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1729 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1731 next0 = NAT_IN2OUT_ED_NEXT_DROP;
1732 b0->error = node->errors[NAT_IN2OUT_ED_ERROR_DROP_FRAGMENT];
1736 if (is_output_feature)
1737 iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1739 ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1742 udp0 = ip4_next_header (ip0);
1743 tcp0 = (tcp_header_t *) udp0;
1744 icmp0 = (icmp46_header_t *) udp0;
1745 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1747 reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1751 1, &fragments_to_drop);
1753 if (PREDICT_FALSE (!reass0))
1755 next0 = NAT_IN2OUT_ED_NEXT_DROP;
1756 b0->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_REASS];
1757 nat_log_notice ("maximum reassemblies exceeded");
1761 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1763 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1765 if (is_output_feature)
1768 (nat_not_translate_output_feature_fwd
1769 (sm, ip0, thread_index, now, vm, b0)))
1770 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1774 next0 = icmp_in2out_ed_slow_path
1775 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1776 next0, now, thread_index, &s0);
1778 if (PREDICT_TRUE (next0 != NAT_IN2OUT_ED_NEXT_DROP))
1781 reass0->sess_index = s0 - per_thread_data->sessions;
1783 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1784 nat_ip4_reass_get_frags (reass0,
1785 &fragments_to_loopback);
1791 make_ed_kv (&kv0, &ip0->src_address, &ip0->dst_address,
1792 ip0->protocol, rx_fib_index0, udp0->src_port,
1795 if (clib_bihash_search_16_8
1796 (&per_thread_data->in2out_ed, &kv0, &value0))
1798 if (is_output_feature)
1801 (nat44_ed_not_translate_output_feature
1802 (sm, ip0, ip0->protocol, udp0->src_port,
1803 udp0->dst_port, thread_index, sw_if_index0,
1804 vnet_buffer (b0)->sw_if_index[VLIB_TX])))
1806 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1807 nat_ip4_reass_get_frags (reass0,
1808 &fragments_to_loopback);
1814 if (PREDICT_FALSE (nat44_ed_not_translate (sm, node,
1820 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1821 nat_ip4_reass_get_frags (reass0,
1822 &fragments_to_loopback);
1827 next0 = slow_path_ed (sm, b0, rx_fib_index0, &kv0,
1828 &s0, node, next0, thread_index, now);
1830 if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
1833 reass0->sess_index = s0 - per_thread_data->sessions;
1837 s0 = pool_elt_at_index (per_thread_data->sessions,
1839 reass0->sess_index = value0.value;
1841 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1845 if (reass0->flags & NAT_REASS_FLAG_ED_DONT_TRANSLATE)
1847 if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1849 if (nat_ip4_reass_add_fragment
1850 (reass0, bi0, &fragments_to_drop))
1852 b0->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_FRAG];
1854 ("maximum fragments per reassembly exceeded");
1855 next0 = NAT_IN2OUT_ED_NEXT_DROP;
1861 s0 = pool_elt_at_index (per_thread_data->sessions,
1862 reass0->sess_index);
1865 old_addr0 = ip0->src_address.as_u32;
1866 ip0->src_address = s0->out2in.addr;
1867 new_addr0 = ip0->src_address.as_u32;
1868 if (!is_output_feature)
1869 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1871 sum0 = ip0->checksum;
1872 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1874 src_address /* changed member */ );
1875 if (PREDICT_FALSE (is_twice_nat_session (s0)))
1876 sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1877 s0->ext_host_addr.as_u32, ip4_header_t,
1879 ip0->checksum = ip_csum_fold (sum0);
1881 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1883 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1885 old_port0 = tcp0->src_port;
1886 tcp0->src_port = s0->out2in.port;
1887 new_port0 = tcp0->src_port;
1889 sum0 = tcp0->checksum;
1890 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1892 dst_address /* changed member */ );
1893 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1894 ip4_header_t /* cheat */ ,
1895 length /* changed member */ );
1896 if (PREDICT_FALSE (is_twice_nat_session (s0)))
1898 sum0 = ip_csum_update (sum0, ip0->dst_address.as_u32,
1899 s0->ext_host_addr.as_u32,
1900 ip4_header_t, dst_address);
1901 sum0 = ip_csum_update (sum0, tcp0->dst_port,
1902 s0->ext_host_port, ip4_header_t,
1904 tcp0->dst_port = s0->ext_host_port;
1905 ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1907 tcp0->checksum = ip_csum_fold (sum0);
1911 old_port0 = udp0->src_port;
1912 udp0->src_port = s0->out2in.port;
1914 if (PREDICT_FALSE (is_twice_nat_session (s0)))
1916 udp0->dst_port = s0->ext_host_port;
1917 ip0->dst_address.as_u32 = s0->ext_host_addr.as_u32;
1923 if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_ICMP))
1924 nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
1925 s0->ext_host_port, proto0, 1);
1927 snat_icmp_hairpinning (sm, b0, ip0, icmp0, 1);
1930 nat44_session_update_counters (s0, now,
1931 vlib_buffer_length_in_chain (vm,
1935 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1936 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1938 nat44_reass_trace_t *t =
1939 vlib_add_trace (vm, node, b0, sizeof (*t));
1940 t->cached = cached0;
1941 t->sw_if_index = sw_if_index0;
1942 t->next_index = next0;
1952 pkts_processed += next0 != NAT_IN2OUT_ED_NEXT_DROP;
1954 /* verify speculative enqueue, maybe switch current next frame */
1955 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1956 to_next, n_left_to_next,
1960 if (n_left_from == 0 && vec_len (fragments_to_loopback))
1962 from = vlib_frame_vector_args (frame);
1963 u32 len = vec_len (fragments_to_loopback);
1964 if (len <= VLIB_FRAME_SIZE)
1966 clib_memcpy (from, fragments_to_loopback,
1967 sizeof (u32) * len);
1969 vec_reset_length (fragments_to_loopback);
1974 fragments_to_loopback + (len -
1976 sizeof (u32) * VLIB_FRAME_SIZE);
1977 n_left_from = VLIB_FRAME_SIZE;
1978 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1983 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1986 vlib_node_increment_counter (vm, nat44_ed_in2out_reass_node.index,
1987 NAT_IN2OUT_ED_ERROR_IN2OUT_PACKETS,
1990 nat_send_all_to_node (vm, fragments_to_drop, node,
1991 &node->errors[NAT_IN2OUT_ED_ERROR_DROP_FRAGMENT],
1992 NAT_IN2OUT_ED_NEXT_DROP);
1994 vec_free (fragments_to_drop);
1995 vec_free (fragments_to_loopback);
1996 return frame->n_vectors;
2000 nat44_ed_in2out_reass_node_fn (vlib_main_t * vm,
2001 vlib_node_runtime_t * node,
2002 vlib_frame_t * frame)
2004 return nat44_ed_in2out_reass_node_fn_inline (vm, node, frame, 0);
2008 VLIB_REGISTER_NODE (nat44_ed_in2out_reass_node) = {
2009 .function = nat44_ed_in2out_reass_node_fn,
2010 .name = "nat44-ed-in2out-reass",
2011 .vector_size = sizeof (u32),
2012 .format_trace = format_nat44_reass_trace,
2013 .type = VLIB_NODE_TYPE_INTERNAL,
2014 .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
2015 .error_strings = nat_in2out_ed_error_strings,
2016 .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
2018 [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
2019 [NAT_IN2OUT_ED_NEXT_LOOKUP] = "ip4-lookup",
2020 [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2021 [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2022 [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
2027 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_in2out_reass_node,
2028 nat44_ed_in2out_reass_node_fn);
2031 nat44_ed_in2out_reass_output_node_fn (vlib_main_t * vm,
2032 vlib_node_runtime_t * node,
2033 vlib_frame_t * frame)
2035 return nat44_ed_in2out_reass_node_fn_inline (vm, node, frame, 1);
2039 VLIB_REGISTER_NODE (nat44_ed_in2out_reass_output_node) = {
2040 .function = nat44_ed_in2out_reass_output_node_fn,
2041 .name = "nat44-ed-in2out-reass-output",
2042 .vector_size = sizeof (u32),
2043 .format_trace = format_nat44_reass_trace,
2044 .type = VLIB_NODE_TYPE_INTERNAL,
2045 .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
2046 .error_strings = nat_in2out_ed_error_strings,
2047 .n_next_nodes = NAT_IN2OUT_ED_N_NEXT,
2049 [NAT_IN2OUT_ED_NEXT_DROP] = "error-drop",
2050 [NAT_IN2OUT_ED_NEXT_LOOKUP] = "interface-output",
2051 [NAT_IN2OUT_ED_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2052 [NAT_IN2OUT_ED_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2053 [NAT_IN2OUT_ED_NEXT_REASS] = "nat44-ed-in2out-reass",
2058 VLIB_NODE_FUNCTION_MULTIARCH (nat44_ed_in2out_reass_output_node,
2059 nat44_ed_in2out_reass_output_node_fn);
2062 * fd.io coding-style-patch-verification: ON
2065 * eval: (c-set-style "gnu")