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/ethernet/ethernet.h>
23 #include <vnet/fib/ip4_fib.h>
25 #include <nat/nat_ipfix_logging.h>
26 #include <nat/nat_det.h>
28 #include <vppinfra/hash.h>
29 #include <vppinfra/error.h>
30 #include <vppinfra/elog.h>
37 } snat_in2out_trace_t;
40 u32 next_worker_index;
42 } snat_in2out_worker_handoff_trace_t;
44 /* packet trace format function */
45 static u8 * format_snat_in2out_trace (u8 * s, va_list * args)
47 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
48 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
49 snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *);
52 tag = t->is_slow_path ? "NAT44_IN2OUT_SLOW_PATH" : "NAT44_IN2OUT_FAST_PATH";
54 s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
55 t->sw_if_index, t->next_index, t->session_index);
60 static u8 * format_snat_in2out_fast_trace (u8 * s, va_list * args)
62 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
63 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
64 snat_in2out_trace_t * t = va_arg (*args, snat_in2out_trace_t *);
66 s = format (s, "NAT44_IN2OUT_FAST: sw_if_index %d, next index %d",
67 t->sw_if_index, t->next_index);
72 static u8 * format_snat_in2out_worker_handoff_trace (u8 * s, va_list * args)
74 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
75 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
76 snat_in2out_worker_handoff_trace_t * t =
77 va_arg (*args, snat_in2out_worker_handoff_trace_t *);
80 m = t->do_handoff ? "next worker" : "same worker";
81 s = format (s, "NAT44_IN2OUT_WORKER_HANDOFF: %s %d", m, t->next_worker_index);
86 vlib_node_registration_t snat_in2out_node;
87 vlib_node_registration_t snat_in2out_slowpath_node;
88 vlib_node_registration_t snat_in2out_fast_node;
89 vlib_node_registration_t snat_in2out_worker_handoff_node;
90 vlib_node_registration_t snat_det_in2out_node;
91 vlib_node_registration_t snat_in2out_output_node;
92 vlib_node_registration_t snat_in2out_output_slowpath_node;
93 vlib_node_registration_t snat_in2out_output_worker_handoff_node;
94 vlib_node_registration_t snat_hairpin_dst_node;
95 vlib_node_registration_t snat_hairpin_src_node;
98 #define foreach_snat_in2out_error \
99 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
100 _(IN2OUT_PACKETS, "Good in2out packets processed") \
101 _(OUT_OF_PORTS, "Out of ports") \
102 _(BAD_OUTSIDE_FIB, "Outside VRF ID not found") \
103 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
104 _(NO_TRANSLATION, "No translation")
107 #define _(sym,str) SNAT_IN2OUT_ERROR_##sym,
108 foreach_snat_in2out_error
111 } snat_in2out_error_t;
113 static char * snat_in2out_error_strings[] = {
114 #define _(sym,string) string,
115 foreach_snat_in2out_error
120 SNAT_IN2OUT_NEXT_LOOKUP,
121 SNAT_IN2OUT_NEXT_DROP,
122 SNAT_IN2OUT_NEXT_ICMP_ERROR,
123 SNAT_IN2OUT_NEXT_SLOW_PATH,
125 } snat_in2out_next_t;
128 SNAT_HAIRPIN_SRC_NEXT_DROP,
129 SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT,
130 SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH,
131 SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT,
132 SNAT_HAIRPIN_SRC_N_NEXT,
133 } snat_hairpin_next_t;
136 * @brief Check if packet should be translated
138 * Packets aimed at outside interface and external addresss with active session
139 * should be translated.
142 * @param rt NAT runtime data
143 * @param sw_if_index0 index of the inside interface
144 * @param ip0 IPv4 header
145 * @param proto0 NAT protocol
146 * @param rx_fib_index0 RX FIB index
148 * @returns 0 if packet should be translated otherwise 1
151 snat_not_translate_fast (snat_main_t * sm, vlib_node_runtime_t *node,
152 u32 sw_if_index0, ip4_header_t * ip0, u32 proto0,
155 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
157 .fp_proto = FIB_PROTOCOL_IP4,
160 .ip4.as_u32 = ip0->dst_address.as_u32,
164 /* Don't NAT packet aimed at the intfc address */
165 if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
166 ip0->dst_address.as_u32)))
169 fei = fib_table_lookup (rx_fib_index0, &pfx);
170 if (FIB_NODE_INDEX_INVALID != fei)
172 u32 sw_if_index = fib_entry_get_resolving_interface (fei);
173 if (sw_if_index == ~0)
175 fei = fib_table_lookup (sm->outside_fib_index, &pfx);
176 if (FIB_NODE_INDEX_INVALID != fei)
177 sw_if_index = fib_entry_get_resolving_interface (fei);
180 pool_foreach (i, sm->interfaces,
182 /* NAT packet aimed at outside interface */
183 if ((i->is_inside == 0) && (sw_if_index == i->sw_if_index))
192 snat_not_translate (snat_main_t * sm, vlib_node_runtime_t *node,
193 u32 sw_if_index0, ip4_header_t * ip0, u32 proto0,
194 u32 rx_fib_index0, u32 thread_index)
196 udp_header_t * udp0 = ip4_next_header (ip0);
197 snat_session_key_t key0, sm0;
198 clib_bihash_kv_8_8_t kv0, value0;
200 key0.addr = ip0->dst_address;
201 key0.port = udp0->dst_port;
202 key0.protocol = proto0;
203 key0.fib_index = sm->outside_fib_index;
204 kv0.key = key0.as_u64;
206 /* NAT packet aimed at external address if */
207 /* has active sessions */
208 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
211 /* or is static mappings */
212 if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0))
218 return snat_not_translate_fast(sm, node, sw_if_index0, ip0, proto0,
222 static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
225 snat_session_key_t * key0,
226 snat_session_t ** sessionp,
227 vlib_node_runtime_t * node,
232 snat_user_key_t user_key;
234 clib_bihash_kv_8_8_t kv0, value0;
235 u32 oldest_per_user_translation_list_index;
236 dlist_elt_t * oldest_per_user_translation_list_elt;
237 dlist_elt_t * per_user_translation_list_elt;
238 dlist_elt_t * per_user_list_head_elt;
240 snat_session_key_t key1;
241 u32 address_index = ~0;
242 u32 outside_fib_index;
244 snat_worker_key_t worker_by_out_key;
246 p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id);
249 b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_OUTSIDE_FIB];
250 return SNAT_IN2OUT_NEXT_DROP;
252 outside_fib_index = p[0];
254 key1.protocol = key0->protocol;
255 user_key.addr = ip0->src_address;
256 user_key.fib_index = rx_fib_index0;
257 kv0.key = user_key.as_u64;
259 /* Ever heard of the "user" = src ip4 address before? */
260 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].user_hash,
263 /* no, make a new one */
264 pool_get (sm->per_thread_data[thread_index].users, u);
265 memset (u, 0, sizeof (*u));
266 u->addr = ip0->src_address;
267 u->fib_index = rx_fib_index0;
269 pool_get (sm->per_thread_data[thread_index].list_pool, per_user_list_head_elt);
271 u->sessions_per_user_list_head_index = per_user_list_head_elt -
272 sm->per_thread_data[thread_index].list_pool;
274 clib_dlist_init (sm->per_thread_data[thread_index].list_pool,
275 u->sessions_per_user_list_head_index);
277 kv0.value = u - sm->per_thread_data[thread_index].users;
280 clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].user_hash,
281 &kv0, 1 /* is_add */);
285 u = pool_elt_at_index (sm->per_thread_data[thread_index].users,
289 /* Over quota? Recycle the least recently used dynamic translation */
290 if (u->nsessions >= sm->max_translations_per_user)
292 /* Remove the oldest dynamic translation */
294 oldest_per_user_translation_list_index =
295 clib_dlist_remove_head (sm->per_thread_data[thread_index].list_pool,
296 u->sessions_per_user_list_head_index);
298 ASSERT (oldest_per_user_translation_list_index != ~0);
300 /* add it back to the end of the LRU list */
301 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
302 u->sessions_per_user_list_head_index,
303 oldest_per_user_translation_list_index);
304 /* Get the list element */
305 oldest_per_user_translation_list_elt =
306 pool_elt_at_index (sm->per_thread_data[thread_index].list_pool,
307 oldest_per_user_translation_list_index);
309 /* Get the session index from the list element */
310 session_index = oldest_per_user_translation_list_elt->value;
312 /* Get the session */
313 s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
315 } while (snat_is_session_static (s));
317 if (snat_is_unk_proto_session (s))
319 clib_bihash_kv_16_8_t up_kv;
320 nat_ed_ses_key_t key;
322 /* Remove from lookup tables */
323 key.l_addr = s->in2out.addr;
324 key.r_addr = s->ext_host_addr;
325 key.fib_index = s->in2out.fib_index;
326 key.proto = s->in2out.port;
329 up_kv.key[0] = key.as_u64[0];
330 up_kv.key[1] = key.as_u64[1];
331 if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &up_kv, 0))
332 clib_warning ("in2out key del failed");
334 key.l_addr = s->out2in.addr;
335 key.fib_index = s->out2in.fib_index;
336 up_kv.key[0] = key.as_u64[0];
337 up_kv.key[1] = key.as_u64[1];
338 if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &up_kv, 0))
339 clib_warning ("out2in key del failed");
343 /* Remove in2out, out2in keys */
344 kv0.key = s->in2out.as_u64;
345 if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out,
346 &kv0, 0 /* is_add */))
347 clib_warning ("in2out key delete failed");
348 kv0.key = s->out2in.as_u64;
349 if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in,
350 &kv0, 0 /* is_add */))
351 clib_warning ("out2in key delete failed");
354 snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
355 s->out2in.addr.as_u32,
359 s->in2out.fib_index);
361 snat_free_outside_address_and_port
362 (sm, thread_index, &s->out2in, s->outside_address_index);
364 s->outside_address_index = ~0;
366 if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, thread_index,
367 &key1, &address_index))
371 b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
372 return SNAT_IN2OUT_NEXT_DROP;
374 s->outside_address_index = address_index;
378 u8 static_mapping = 1;
380 /* First try to match static mapping by local address and port */
381 if (snat_static_mapping_match (sm, *key0, &key1, 0, 0))
384 /* Try to create dynamic translation */
385 if (snat_alloc_outside_address_and_port (sm, rx_fib_index0,
389 b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
390 return SNAT_IN2OUT_NEXT_DROP;
394 /* Create a new session */
395 pool_get (sm->per_thread_data[thread_index].sessions, s);
396 memset (s, 0, sizeof (*s));
398 s->outside_address_index = address_index;
402 u->nstaticsessions++;
403 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
410 /* Create list elts */
411 pool_get (sm->per_thread_data[thread_index].list_pool,
412 per_user_translation_list_elt);
413 clib_dlist_init (sm->per_thread_data[thread_index].list_pool,
414 per_user_translation_list_elt -
415 sm->per_thread_data[thread_index].list_pool);
417 per_user_translation_list_elt->value =
418 s - sm->per_thread_data[thread_index].sessions;
419 s->per_user_index = per_user_translation_list_elt -
420 sm->per_thread_data[thread_index].list_pool;
421 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
423 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
424 s->per_user_list_head_index,
425 per_user_translation_list_elt -
426 sm->per_thread_data[thread_index].list_pool);
431 s->out2in.protocol = key0->protocol;
432 s->out2in.fib_index = outside_fib_index;
433 s->ext_host_addr.as_u32 = ip0->dst_address.as_u32;
436 /* Add to translation hashes */
437 kv0.key = s->in2out.as_u64;
438 kv0.value = s - sm->per_thread_data[thread_index].sessions;
439 if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
441 clib_warning ("in2out key add failed");
443 kv0.key = s->out2in.as_u64;
444 kv0.value = s - sm->per_thread_data[thread_index].sessions;
446 if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
448 clib_warning ("out2in key add failed");
450 /* Add to translated packets worker lookup */
451 worker_by_out_key.addr = s->out2in.addr;
452 worker_by_out_key.port = s->out2in.port;
453 worker_by_out_key.fib_index = s->out2in.fib_index;
454 kv0.key = worker_by_out_key.as_u64;
455 kv0.value = thread_index;
456 clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1);
459 snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
460 s->out2in.addr.as_u32,
464 s->in2out.fib_index);
469 snat_in2out_error_t icmp_get_key(ip4_header_t *ip0,
470 snat_session_key_t *p_key0)
472 icmp46_header_t *icmp0;
473 snat_session_key_t key0;
474 icmp_echo_header_t *echo0, *inner_echo0 = 0;
475 ip4_header_t *inner_ip0 = 0;
477 icmp46_header_t *inner_icmp0;
479 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
480 echo0 = (icmp_echo_header_t *)(icmp0+1);
482 if (!icmp_is_error_message (icmp0))
484 key0.protocol = SNAT_PROTOCOL_ICMP;
485 key0.addr = ip0->src_address;
486 key0.port = echo0->identifier;
490 inner_ip0 = (ip4_header_t *)(echo0+1);
491 l4_header = ip4_next_header (inner_ip0);
492 key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
493 key0.addr = inner_ip0->dst_address;
494 switch (key0.protocol)
496 case SNAT_PROTOCOL_ICMP:
497 inner_icmp0 = (icmp46_header_t*)l4_header;
498 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
499 key0.port = inner_echo0->identifier;
501 case SNAT_PROTOCOL_UDP:
502 case SNAT_PROTOCOL_TCP:
503 key0.port = ((tcp_udp_header_t*)l4_header)->dst_port;
506 return SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
510 return -1; /* success */
514 * Get address and port values to be used for ICMP packet translation
515 * and create session if needed
517 * @param[in,out] sm NAT main
518 * @param[in,out] node NAT node runtime
519 * @param[in] thread_index thread index
520 * @param[in,out] b0 buffer containing packet to be translated
521 * @param[out] p_proto protocol used for matching
522 * @param[out] p_value address and port after NAT translation
523 * @param[out] p_dont_translate if packet should not be translated
524 * @param d optional parameter
525 * @param e optional parameter
527 u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node,
528 u32 thread_index, vlib_buffer_t *b0, u8 *p_proto,
529 snat_session_key_t *p_value,
530 u8 *p_dont_translate, void *d, void *e)
533 icmp46_header_t *icmp0;
536 snat_session_key_t key0;
537 snat_session_t *s0 = 0;
538 u8 dont_translate = 0;
539 clib_bihash_kv_8_8_t kv0, value0;
544 if (PREDICT_FALSE(vnet_buffer(b0)->sw_if_index[VLIB_TX] != ~0))
546 iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
548 ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + iph_offset0);
549 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
550 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
551 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
553 err = icmp_get_key (ip0, &key0);
556 b0->error = node->errors[err];
557 next0 = SNAT_IN2OUT_NEXT_DROP;
560 key0.fib_index = rx_fib_index0;
562 kv0.key = key0.as_u64;
564 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
567 if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0, ip0,
568 IP_PROTOCOL_ICMP, rx_fib_index0, thread_index) &&
569 vnet_buffer(b0)->sw_if_index[VLIB_TX] == ~0))
575 if (PREDICT_FALSE(icmp_is_error_message (icmp0)))
577 b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
578 next0 = SNAT_IN2OUT_NEXT_DROP;
582 next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
583 &s0, node, next0, thread_index);
585 if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
590 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request &&
591 icmp0->type != ICMP4_echo_reply &&
592 !icmp_is_error_message (icmp0)))
594 b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
595 next0 = SNAT_IN2OUT_NEXT_DROP;
599 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
604 *p_proto = key0.protocol;
606 *p_value = s0->out2in;
607 *p_dont_translate = dont_translate;
609 *(snat_session_t**)d = s0;
614 * Get address and port values to be used for ICMP packet translation
616 * @param[in] sm NAT main
617 * @param[in,out] node NAT node runtime
618 * @param[in] thread_index thread index
619 * @param[in,out] b0 buffer containing packet to be translated
620 * @param[out] p_proto protocol used for matching
621 * @param[out] p_value address and port after NAT translation
622 * @param[out] p_dont_translate if packet should not be translated
623 * @param d optional parameter
624 * @param e optional parameter
626 u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node,
627 u32 thread_index, vlib_buffer_t *b0, u8 *p_proto,
628 snat_session_key_t *p_value,
629 u8 *p_dont_translate, void *d, void *e)
632 icmp46_header_t *icmp0;
635 snat_session_key_t key0;
636 snat_session_key_t sm0;
637 u8 dont_translate = 0;
642 ip0 = vlib_buffer_get_current (b0);
643 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
644 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
645 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
647 err = icmp_get_key (ip0, &key0);
650 b0->error = node->errors[err];
651 next0 = SNAT_IN2OUT_NEXT_DROP;
654 key0.fib_index = rx_fib_index0;
656 if (snat_static_mapping_match(sm, key0, &sm0, 0, &is_addr_only))
658 if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0,
659 IP_PROTOCOL_ICMP, rx_fib_index0)))
665 if (icmp_is_error_message (icmp0))
667 next0 = SNAT_IN2OUT_NEXT_DROP;
671 b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
672 next0 = SNAT_IN2OUT_NEXT_DROP;
676 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request &&
677 (icmp0->type != ICMP4_echo_reply || !is_addr_only) &&
678 !icmp_is_error_message (icmp0)))
680 b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
681 next0 = SNAT_IN2OUT_NEXT_DROP;
688 *p_proto = key0.protocol;
689 *p_dont_translate = dont_translate;
693 static inline u32 icmp_in2out (snat_main_t *sm,
696 icmp46_header_t * icmp0,
699 vlib_node_runtime_t * node,
705 snat_session_key_t sm0;
707 icmp_echo_header_t *echo0, *inner_echo0 = 0;
708 ip4_header_t *inner_ip0;
710 icmp46_header_t *inner_icmp0;
712 u32 new_addr0, old_addr0;
713 u16 old_id0, new_id0;
718 echo0 = (icmp_echo_header_t *)(icmp0+1);
720 next0_tmp = sm->icmp_match_in2out_cb(sm, node, thread_index, b0,
721 &protocol, &sm0, &dont_translate, d, e);
724 if (next0 == SNAT_IN2OUT_NEXT_DROP || dont_translate)
727 sum0 = ip_incremental_checksum (0, icmp0,
728 ntohs(ip0->length) - ip4_header_bytes (ip0));
729 checksum0 = ~ip_csum_fold (sum0);
730 if (PREDICT_FALSE(checksum0 != 0 && checksum0 != 0xffff))
732 next0 = SNAT_IN2OUT_NEXT_DROP;
736 old_addr0 = ip0->src_address.as_u32;
737 new_addr0 = ip0->src_address.as_u32 = sm0.addr.as_u32;
738 if (vnet_buffer(b0)->sw_if_index[VLIB_TX] == ~0)
739 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
741 sum0 = ip0->checksum;
742 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
743 src_address /* changed member */);
744 ip0->checksum = ip_csum_fold (sum0);
746 if (!icmp_is_error_message (icmp0))
749 if (PREDICT_FALSE(new_id0 != echo0->identifier))
751 old_id0 = echo0->identifier;
753 echo0->identifier = new_id0;
755 sum0 = icmp0->checksum;
756 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
758 icmp0->checksum = ip_csum_fold (sum0);
763 inner_ip0 = (ip4_header_t *)(echo0+1);
764 l4_header = ip4_next_header (inner_ip0);
766 if (!ip4_header_checksum_is_valid (inner_ip0))
768 next0 = SNAT_IN2OUT_NEXT_DROP;
772 old_addr0 = inner_ip0->dst_address.as_u32;
773 inner_ip0->dst_address = sm0.addr;
774 new_addr0 = inner_ip0->dst_address.as_u32;
776 sum0 = icmp0->checksum;
777 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
778 dst_address /* changed member */);
779 icmp0->checksum = ip_csum_fold (sum0);
783 case SNAT_PROTOCOL_ICMP:
784 inner_icmp0 = (icmp46_header_t*)l4_header;
785 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
787 old_id0 = inner_echo0->identifier;
789 inner_echo0->identifier = new_id0;
791 sum0 = icmp0->checksum;
792 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
794 icmp0->checksum = ip_csum_fold (sum0);
796 case SNAT_PROTOCOL_UDP:
797 case SNAT_PROTOCOL_TCP:
798 old_id0 = ((tcp_udp_header_t*)l4_header)->dst_port;
800 ((tcp_udp_header_t*)l4_header)->dst_port = new_id0;
802 sum0 = icmp0->checksum;
803 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
805 icmp0->checksum = ip_csum_fold (sum0);
819 * Hairpinning allows two endpoints on the internal side of the NAT to
820 * communicate even if they only use each other's external IP addresses
823 * @param sm NAT main.
824 * @param b0 Vlib buffer.
825 * @param ip0 IP header.
826 * @param udp0 UDP header.
827 * @param tcp0 TCP header.
828 * @param proto0 NAT protocol.
831 snat_hairpinning (snat_main_t *sm,
838 snat_session_key_t key0, sm0;
839 snat_worker_key_t k0;
841 clib_bihash_kv_8_8_t kv0, value0;
843 u32 new_dst_addr0 = 0, old_dst_addr0, ti = 0, si;
844 u16 new_dst_port0, old_dst_port0;
846 key0.addr = ip0->dst_address;
847 key0.port = udp0->dst_port;
848 key0.protocol = proto0;
849 key0.fib_index = sm->outside_fib_index;
850 kv0.key = key0.as_u64;
852 if (sm->num_workers > 1)
854 k0.addr = ip0->dst_address;
855 k0.port = udp0->dst_port;
856 k0.fib_index = sm->outside_fib_index;
858 if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
864 ti = sm->num_workers;
866 /* Check if destination is in active sessions */
867 if (clib_bihash_search_8_8 (&sm->per_thread_data[ti].out2in, &kv0, &value0))
869 /* or static mappings */
870 if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0))
872 new_dst_addr0 = sm0.addr.as_u32;
873 new_dst_port0 = sm0.port;
874 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
881 s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si);
882 new_dst_addr0 = s0->in2out.addr.as_u32;
883 new_dst_port0 = s0->in2out.port;
884 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
887 /* Destination is behind the same NAT, use internal address and port */
890 old_dst_addr0 = ip0->dst_address.as_u32;
891 ip0->dst_address.as_u32 = new_dst_addr0;
892 sum0 = ip0->checksum;
893 sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
894 ip4_header_t, dst_address);
895 ip0->checksum = ip_csum_fold (sum0);
897 old_dst_port0 = tcp0->dst;
898 if (PREDICT_TRUE(new_dst_port0 != old_dst_port0))
900 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
902 tcp0->dst = new_dst_port0;
903 sum0 = tcp0->checksum;
904 sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
905 ip4_header_t, dst_address);
906 sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0,
907 ip4_header_t /* cheat */, length);
908 tcp0->checksum = ip_csum_fold(sum0);
912 udp0->dst_port = new_dst_port0;
918 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
920 sum0 = tcp0->checksum;
921 sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
922 ip4_header_t, dst_address);
923 tcp0->checksum = ip_csum_fold(sum0);
930 snat_icmp_hairpinning (snat_main_t *sm,
933 icmp46_header_t * icmp0)
935 snat_session_key_t key0, sm0;
936 clib_bihash_kv_8_8_t kv0, value0;
937 snat_worker_key_t k0;
938 u32 new_dst_addr0 = 0, old_dst_addr0, si, ti = 0;
942 if (!icmp_is_error_message (icmp0))
944 icmp_echo_header_t *echo0 = (icmp_echo_header_t *)(icmp0+1);
945 u16 icmp_id0 = echo0->identifier;
946 key0.addr = ip0->dst_address;
947 key0.port = icmp_id0;
948 key0.protocol = SNAT_PROTOCOL_ICMP;
949 key0.fib_index = sm->outside_fib_index;
950 kv0.key = key0.as_u64;
952 if (sm->num_workers > 1)
954 k0.addr = ip0->dst_address;
956 k0.fib_index = sm->outside_fib_index;
958 if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
964 ti = sm->num_workers;
966 /* Check if destination is in active sessions */
967 if (clib_bihash_search_8_8 (&sm->per_thread_data[ti].out2in, &kv0,
970 /* or static mappings */
971 if (!snat_static_mapping_match(sm, key0, &sm0, 1, 0))
973 new_dst_addr0 = sm0.addr.as_u32;
974 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
981 s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si);
982 new_dst_addr0 = s0->in2out.addr.as_u32;
983 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
984 echo0->identifier = s0->in2out.port;
985 sum0 = icmp0->checksum;
986 sum0 = ip_csum_update (sum0, icmp_id0, s0->in2out.port,
987 icmp_echo_header_t, identifier);
988 icmp0->checksum = ip_csum_fold (sum0);
991 /* Destination is behind the same NAT, use internal address and port */
994 old_dst_addr0 = ip0->dst_address.as_u32;
995 ip0->dst_address.as_u32 = new_dst_addr0;
996 sum0 = ip0->checksum;
997 sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
998 ip4_header_t, dst_address);
999 ip0->checksum = ip_csum_fold (sum0);
1005 static inline u32 icmp_in2out_slow_path (snat_main_t *sm,
1008 icmp46_header_t * icmp0,
1011 vlib_node_runtime_t * node,
1015 snat_session_t ** p_s0)
1017 next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1018 next0, thread_index, p_s0, 0);
1019 snat_session_t * s0 = *p_s0;
1020 if (PREDICT_TRUE(next0 != SNAT_IN2OUT_NEXT_DROP && s0))
1023 if (vnet_buffer(b0)->sw_if_index[VLIB_TX] == 0)
1024 snat_icmp_hairpinning(sm, b0, ip0, icmp0);
1026 s0->last_heard = now;
1028 s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
1029 /* Per-user LRU list maintenance for dynamic translations */
1030 if (!snat_is_session_static (s0))
1032 clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1033 s0->per_user_index);
1034 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1035 s0->per_user_list_head_index,
1036 s0->per_user_index);
1042 snat_hairpinning_unknown_proto (snat_main_t *sm,
1046 u32 old_addr, new_addr = 0, ti = 0;
1047 clib_bihash_kv_8_8_t kv, value;
1048 clib_bihash_kv_16_8_t s_kv, s_value;
1049 nat_ed_ses_key_t key;
1050 snat_session_key_t m_key;
1051 snat_worker_key_t w_key;
1052 snat_static_mapping_t *m;
1056 old_addr = ip->dst_address.as_u32;
1057 key.l_addr.as_u32 = ip->dst_address.as_u32;
1058 key.r_addr.as_u32 = ip->src_address.as_u32;
1059 key.fib_index = sm->outside_fib_index;
1060 key.proto = ip->protocol;
1063 s_kv.key[0] = key.as_u64[0];
1064 s_kv.key[1] = key.as_u64[1];
1065 if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
1067 m_key.addr = ip->dst_address;
1068 m_key.fib_index = sm->outside_fib_index;
1071 kv.key = m_key.as_u64;
1072 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1075 m = pool_elt_at_index (sm->static_mappings, value.value);
1076 if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1077 vnet_buffer(b)->sw_if_index[VLIB_TX] = m->fib_index;
1078 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
1082 if (sm->num_workers > 1)
1084 w_key.addr = ip->dst_address;
1086 w_key.fib_index = sm->outside_fib_index;
1087 kv.key = w_key.as_u64;
1088 if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv, &value))
1094 ti = sm->num_workers;
1096 s = pool_elt_at_index (sm->per_thread_data[ti].sessions, s_value.value);
1097 if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1098 vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
1099 new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
1102 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
1103 ip->checksum = ip_csum_fold (sum);
1107 snat_in2out_unknown_proto (snat_main_t *sm,
1115 clib_bihash_kv_8_8_t kv, value;
1116 clib_bihash_kv_16_8_t s_kv, s_value;
1117 snat_static_mapping_t *m;
1118 snat_session_key_t m_key;
1119 u32 old_addr, new_addr = 0;
1121 snat_user_key_t u_key;
1123 dlist_elt_t *head, *elt, *oldest;
1124 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1125 u32 elt_index, head_index, ses_index, oldest_index;
1127 nat_ed_ses_key_t key;
1128 u32 address_index = ~0;
1132 old_addr = ip->src_address.as_u32;
1134 key.l_addr = ip->src_address;
1135 key.r_addr = ip->dst_address;
1136 key.fib_index = rx_fib_index;
1137 key.proto = ip->protocol;
1140 s_kv.key[0] = key.as_u64[0];
1141 s_kv.key[1] = key.as_u64[1];
1143 if (!clib_bihash_search_16_8 (&sm->in2out_ed, &s_kv, &s_value))
1145 s = pool_elt_at_index (tsm->sessions, s_value.value);
1146 new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
1150 u_key.addr = ip->src_address;
1151 u_key.fib_index = rx_fib_index;
1152 kv.key = u_key.as_u64;
1154 /* Ever heard of the "user" = src ip4 address before? */
1155 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1157 /* no, make a new one */
1158 pool_get (tsm->users, u);
1159 memset (u, 0, sizeof (*u));
1160 u->addr = ip->src_address;
1161 u->fib_index = rx_fib_index;
1163 pool_get (tsm->list_pool, head);
1164 u->sessions_per_user_list_head_index = head - tsm->list_pool;
1166 clib_dlist_init (tsm->list_pool,
1167 u->sessions_per_user_list_head_index);
1169 kv.value = u - tsm->users;
1172 clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1);
1176 u = pool_elt_at_index (tsm->users, value.value);
1179 m_key.addr = ip->src_address;
1182 m_key.fib_index = rx_fib_index;
1183 kv.key = m_key.as_u64;
1185 /* Try to find static mapping first */
1186 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
1188 m = pool_elt_at_index (sm->static_mappings, value.value);
1189 new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
1193 /* Fallback to 3-tuple key */
1196 /* Choose same out address as for TCP/UDP session to same destination */
1197 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1199 head_index = u->sessions_per_user_list_head_index;
1200 head = pool_elt_at_index (tsm->list_pool, head_index);
1201 elt_index = head->next;
1202 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1203 ses_index = elt->value;
1204 while (ses_index != ~0)
1206 s = pool_elt_at_index (tsm->sessions, ses_index);
1207 elt_index = elt->next;
1208 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1209 ses_index = elt->value;
1211 if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
1213 new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
1214 address_index = s->outside_address_index;
1216 key.fib_index = sm->outside_fib_index;
1217 key.l_addr.as_u32 = new_addr;
1218 s_kv.key[0] = key.as_u64[0];
1219 s_kv.key[1] = key.as_u64[1];
1220 if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
1227 key.fib_index = sm->outside_fib_index;
1228 for (i = 0; i < vec_len (sm->addresses); i++)
1230 key.l_addr.as_u32 = sm->addresses[i].addr.as_u32;
1231 s_kv.key[0] = key.as_u64[0];
1232 s_kv.key[1] = key.as_u64[1];
1233 if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
1235 new_addr = ip->src_address.as_u32 = key.l_addr.as_u32;
1244 /* Over quota? Recycle the least recently used dynamic translation */
1245 if (u->nsessions >= sm->max_translations_per_user && !is_sm)
1247 /* Remove the oldest dynamic translation */
1249 oldest_index = clib_dlist_remove_head (
1250 tsm->list_pool, u->sessions_per_user_list_head_index);
1252 ASSERT (oldest_index != ~0);
1254 /* add it back to the end of the LRU list */
1255 clib_dlist_addtail (tsm->list_pool,
1256 u->sessions_per_user_list_head_index,
1258 /* Get the list element */
1259 oldest = pool_elt_at_index (tsm->list_pool, oldest_index);
1261 /* Get the session index from the list element */
1262 ses_index = oldest->value;
1264 /* Get the session */
1265 s = pool_elt_at_index (tsm->sessions, ses_index);
1266 } while (snat_is_session_static (s));
1268 if (snat_is_unk_proto_session (s))
1270 /* Remove from lookup tables */
1271 key.l_addr = s->in2out.addr;
1272 key.r_addr = s->ext_host_addr;
1273 key.fib_index = s->in2out.fib_index;
1274 key.proto = s->in2out.port;
1275 s_kv.key[0] = key.as_u64[0];
1276 s_kv.key[1] = key.as_u64[1];
1277 if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 0))
1278 clib_warning ("in2out key del failed");
1280 key.l_addr = s->out2in.addr;
1281 key.fib_index = s->out2in.fib_index;
1282 s_kv.key[0] = key.as_u64[0];
1283 s_kv.key[1] = key.as_u64[1];
1284 if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 0))
1285 clib_warning ("out2in key del failed");
1290 snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
1291 s->out2in.addr.as_u32,
1295 s->in2out.fib_index);
1297 snat_free_outside_address_and_port (sm, thread_index, &s->out2in,
1298 s->outside_address_index);
1300 /* Remove in2out, out2in keys */
1301 kv.key = s->in2out.as_u64;
1302 if (clib_bihash_add_del_8_8 (
1303 &sm->per_thread_data[thread_index].in2out, &kv, 0))
1304 clib_warning ("in2out key del failed");
1305 kv.key = s->out2in.as_u64;
1306 if (clib_bihash_add_del_8_8 (
1307 &sm->per_thread_data[thread_index].out2in, &kv, 0))
1308 clib_warning ("out2in key del failed");
1313 /* Create a new session */
1314 pool_get (tsm->sessions, s);
1315 memset (s, 0, sizeof (*s));
1317 /* Create list elts */
1318 pool_get (tsm->list_pool, elt);
1319 clib_dlist_init (tsm->list_pool, elt - tsm->list_pool);
1320 elt->value = s - tsm->sessions;
1321 s->per_user_index = elt - tsm->list_pool;
1322 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
1323 clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
1327 s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
1328 s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
1329 s->outside_address_index = address_index;
1330 s->out2in.addr.as_u32 = new_addr;
1331 s->out2in.fib_index = sm->outside_fib_index;
1332 s->in2out.addr.as_u32 = old_addr;
1333 s->in2out.fib_index = rx_fib_index;
1334 s->in2out.port = s->out2in.port = ip->protocol;
1337 u->nstaticsessions++;
1338 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
1345 /* Add to lookup tables */
1346 key.l_addr.as_u32 = old_addr;
1347 key.r_addr = ip->dst_address;
1348 key.proto = ip->protocol;
1349 key.fib_index = rx_fib_index;
1350 s_kv.key[0] = key.as_u64[0];
1351 s_kv.key[1] = key.as_u64[1];
1352 s_kv.value = s - tsm->sessions;
1353 if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
1354 clib_warning ("in2out key add failed");
1356 key.l_addr.as_u32 = new_addr;
1357 key.fib_index = sm->outside_fib_index;
1358 s_kv.key[0] = key.as_u64[0];
1359 s_kv.key[1] = key.as_u64[1];
1360 if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
1361 clib_warning ("out2in key add failed");
1364 /* Update IP checksum */
1366 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
1367 ip->checksum = ip_csum_fold (sum);
1370 s->last_heard = now;
1372 s->total_bytes += vlib_buffer_length_in_chain (vm, b);
1373 /* Per-user LRU list maintenance */
1374 clib_dlist_remove (tsm->list_pool, s->per_user_index);
1375 clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
1379 if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1380 snat_hairpinning_unknown_proto(sm, b, ip);
1382 if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1383 vnet_buffer(b)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1386 static snat_session_t *
1387 snat_in2out_lb (snat_main_t *sm,
1395 nat_ed_ses_key_t key;
1396 clib_bihash_kv_16_8_t s_kv, s_value;
1397 udp_header_t *udp = ip4_next_header (ip);
1398 tcp_header_t *tcp = (tcp_header_t *) udp;
1399 snat_session_t *s = 0;
1400 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
1401 u32 old_addr, new_addr;
1402 u16 new_port, old_port;
1404 u32 proto = ip_proto_to_snat_proto (ip->protocol);
1405 snat_session_key_t e_key, l_key;
1406 clib_bihash_kv_8_8_t kv, value;
1407 snat_user_key_t u_key;
1409 dlist_elt_t *head, *elt;
1411 old_addr = ip->src_address.as_u32;
1413 key.l_addr = ip->src_address;
1414 key.r_addr = ip->dst_address;
1415 key.fib_index = rx_fib_index;
1416 key.proto = ip->protocol;
1418 key.l_port = udp->src_port;
1419 s_kv.key[0] = key.as_u64[0];
1420 s_kv.key[1] = key.as_u64[1];
1422 if (!clib_bihash_search_16_8 (&sm->in2out_ed, &s_kv, &s_value))
1424 s = pool_elt_at_index (tsm->sessions, s_value.value);
1428 l_key.addr = ip->src_address;
1429 l_key.port = udp->src_port;
1430 l_key.protocol = proto;
1431 l_key.fib_index = rx_fib_index;
1432 if (snat_static_mapping_match(sm, l_key, &e_key, 0, 0))
1435 u_key.addr = ip->src_address;
1436 u_key.fib_index = rx_fib_index;
1437 kv.key = u_key.as_u64;
1439 /* Ever heard of the "user" = src ip4 address before? */
1440 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1442 /* no, make a new one */
1443 pool_get (tsm->users, u);
1444 memset (u, 0, sizeof (*u));
1445 u->addr = ip->src_address;
1446 u->fib_index = rx_fib_index;
1448 pool_get (tsm->list_pool, head);
1449 u->sessions_per_user_list_head_index = head - tsm->list_pool;
1451 clib_dlist_init (tsm->list_pool,
1452 u->sessions_per_user_list_head_index);
1454 kv.value = u - tsm->users;
1457 if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
1458 clib_warning ("user key add failed");
1462 u = pool_elt_at_index (tsm->users, value.value);
1465 /* Create a new session */
1466 pool_get (tsm->sessions, s);
1467 memset (s, 0, sizeof (*s));
1469 s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
1470 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
1471 s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
1472 s->outside_address_index = ~0;
1475 u->nstaticsessions++;
1477 /* Create list elts */
1478 pool_get (tsm->list_pool, elt);
1479 clib_dlist_init (tsm->list_pool, elt - tsm->list_pool);
1480 elt->value = s - tsm->sessions;
1481 s->per_user_index = elt - tsm->list_pool;
1482 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
1483 clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
1486 /* Add to lookup tables */
1487 s_kv.value = s - tsm->sessions;
1488 if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
1489 clib_warning ("in2out-ed key add failed");
1491 key.l_addr = e_key.addr;
1492 key.fib_index = e_key.fib_index;
1493 key.l_port = e_key.port;
1494 s_kv.key[0] = key.as_u64[0];
1495 s_kv.key[1] = key.as_u64[1];
1496 if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
1497 clib_warning ("out2in-ed key add failed");
1500 new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
1502 /* Update IP checksum */
1504 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
1505 ip->checksum = ip_csum_fold (sum);
1507 if (PREDICT_TRUE(proto == SNAT_PROTOCOL_TCP))
1509 old_port = tcp->src_port;
1510 tcp->src_port = s->out2in.port;
1511 new_port = tcp->src_port;
1513 sum = tcp->checksum;
1514 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, src_address);
1515 sum = ip_csum_update (sum, old_port, new_port, ip4_header_t, length);
1516 tcp->checksum = ip_csum_fold(sum);
1520 udp->src_port = s->out2in.port;
1524 if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0)
1525 vnet_buffer(b)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1528 s->last_heard = now;
1530 s->total_bytes += vlib_buffer_length_in_chain (vm, b);
1535 snat_in2out_node_fn_inline (vlib_main_t * vm,
1536 vlib_node_runtime_t * node,
1537 vlib_frame_t * frame, int is_slow_path,
1538 int is_output_feature)
1540 u32 n_left_from, * from, * to_next;
1541 snat_in2out_next_t next_index;
1542 u32 pkts_processed = 0;
1543 snat_main_t * sm = &snat_main;
1544 f64 now = vlib_time_now (vm);
1545 u32 stats_node_index;
1546 u32 thread_index = vlib_get_thread_index ();
1548 stats_node_index = is_slow_path ? snat_in2out_slowpath_node.index :
1549 snat_in2out_node.index;
1551 from = vlib_frame_vector_args (frame);
1552 n_left_from = frame->n_vectors;
1553 next_index = node->cached_next_index;
1555 while (n_left_from > 0)
1559 vlib_get_next_frame (vm, node, next_index,
1560 to_next, n_left_to_next);
1562 while (n_left_from >= 4 && n_left_to_next >= 2)
1565 vlib_buffer_t * b0, * b1;
1567 u32 sw_if_index0, sw_if_index1;
1568 ip4_header_t * ip0, * ip1;
1569 ip_csum_t sum0, sum1;
1570 u32 new_addr0, old_addr0, new_addr1, old_addr1;
1571 u16 old_port0, new_port0, old_port1, new_port1;
1572 udp_header_t * udp0, * udp1;
1573 tcp_header_t * tcp0, * tcp1;
1574 icmp46_header_t * icmp0, * icmp1;
1575 snat_session_key_t key0, key1;
1576 u32 rx_fib_index0, rx_fib_index1;
1578 snat_session_t * s0 = 0, * s1 = 0;
1579 clib_bihash_kv_8_8_t kv0, value0, kv1, value1;
1580 u32 iph_offset0 = 0, iph_offset1 = 0;
1582 /* Prefetch next iteration. */
1584 vlib_buffer_t * p2, * p3;
1586 p2 = vlib_get_buffer (vm, from[2]);
1587 p3 = vlib_get_buffer (vm, from[3]);
1589 vlib_prefetch_buffer_header (p2, LOAD);
1590 vlib_prefetch_buffer_header (p3, LOAD);
1592 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
1593 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
1596 /* speculatively enqueue b0 and b1 to the current next frame */
1597 to_next[0] = bi0 = from[0];
1598 to_next[1] = bi1 = from[1];
1602 n_left_to_next -= 2;
1604 b0 = vlib_get_buffer (vm, bi0);
1605 b1 = vlib_get_buffer (vm, bi1);
1607 if (is_output_feature)
1608 iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1610 ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1613 udp0 = ip4_next_header (ip0);
1614 tcp0 = (tcp_header_t *) udp0;
1615 icmp0 = (icmp46_header_t *) udp0;
1617 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1618 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1621 next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP;
1623 if (PREDICT_FALSE(ip0->ttl == 1))
1625 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1626 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1627 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1629 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
1633 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1635 /* Next configured feature, probably ip4-lookup */
1638 if (PREDICT_FALSE (proto0 == ~0))
1640 snat_in2out_unknown_proto (sm, b0, ip0, rx_fib_index0,
1641 thread_index, now, vm);
1645 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1647 next0 = icmp_in2out_slow_path
1648 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
1649 node, next0, now, thread_index, &s0);
1655 if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
1657 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1662 key0.addr = ip0->src_address;
1663 key0.port = udp0->src_port;
1664 key0.protocol = proto0;
1665 key0.fib_index = rx_fib_index0;
1667 kv0.key = key0.as_u64;
1669 if (PREDICT_FALSE (clib_bihash_search_8_8 (
1670 &sm->per_thread_data[thread_index].in2out, &kv0, &value0) != 0))
1674 if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0,
1675 ip0, proto0, rx_fib_index0, thread_index)) && !is_output_feature)
1678 next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1679 &s0, node, next0, thread_index);
1680 if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1685 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1691 if (PREDICT_FALSE (value0.value == ~0ULL))
1695 s0 = snat_in2out_lb(sm, b0, ip0, rx_fib_index0, thread_index,
1701 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1707 s0 = pool_elt_at_index (
1708 sm->per_thread_data[thread_index].sessions,
1713 old_addr0 = ip0->src_address.as_u32;
1714 ip0->src_address = s0->out2in.addr;
1715 new_addr0 = ip0->src_address.as_u32;
1716 if (!is_output_feature)
1717 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1719 sum0 = ip0->checksum;
1720 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1722 src_address /* changed member */);
1723 ip0->checksum = ip_csum_fold (sum0);
1725 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1727 old_port0 = tcp0->src_port;
1728 tcp0->src_port = s0->out2in.port;
1729 new_port0 = tcp0->src_port;
1731 sum0 = tcp0->checksum;
1732 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1734 dst_address /* changed member */);
1735 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1736 ip4_header_t /* cheat */,
1737 length /* changed member */);
1738 tcp0->checksum = ip_csum_fold(sum0);
1742 old_port0 = udp0->src_port;
1743 udp0->src_port = s0->out2in.port;
1748 if (!is_output_feature)
1749 snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
1752 s0->last_heard = now;
1754 s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1755 /* Per-user LRU list maintenance for dynamic translation */
1756 if (!snat_is_session_static (s0))
1758 clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1759 s0->per_user_index);
1760 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1761 s0->per_user_list_head_index,
1762 s0->per_user_index);
1766 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1767 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1769 snat_in2out_trace_t *t =
1770 vlib_add_trace (vm, node, b0, sizeof (*t));
1771 t->is_slow_path = is_slow_path;
1772 t->sw_if_index = sw_if_index0;
1773 t->next_index = next0;
1774 t->session_index = ~0;
1776 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1779 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1781 if (is_output_feature)
1782 iph_offset1 = vnet_buffer (b1)->ip.save_rewrite_length;
1784 ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) +
1787 udp1 = ip4_next_header (ip1);
1788 tcp1 = (tcp_header_t *) udp1;
1789 icmp1 = (icmp46_header_t *) udp1;
1791 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1792 rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1795 if (PREDICT_FALSE(ip1->ttl == 1))
1797 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1798 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1799 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1801 next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
1805 proto1 = ip_proto_to_snat_proto (ip1->protocol);
1807 /* Next configured feature, probably ip4-lookup */
1810 if (PREDICT_FALSE (proto1 == ~0))
1812 snat_in2out_unknown_proto (sm, b1, ip1, rx_fib_index1,
1813 thread_index, now, vm);
1817 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1819 next1 = icmp_in2out_slow_path
1820 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1821 next1, now, thread_index, &s1);
1827 if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP))
1829 next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1834 key1.addr = ip1->src_address;
1835 key1.port = udp1->src_port;
1836 key1.protocol = proto1;
1837 key1.fib_index = rx_fib_index1;
1839 kv1.key = key1.as_u64;
1841 if (PREDICT_FALSE(clib_bihash_search_8_8 (
1842 &sm->per_thread_data[thread_index].in2out, &kv1, &value1) != 0))
1846 if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index1,
1847 ip1, proto1, rx_fib_index1, thread_index)) && !is_output_feature)
1850 next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1,
1851 &s1, node, next1, thread_index);
1852 if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP))
1857 next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1863 if (PREDICT_FALSE (value1.value == ~0ULL))
1867 s1 = snat_in2out_lb(sm, b1, ip1, rx_fib_index1, thread_index,
1873 next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1879 s1 = pool_elt_at_index (
1880 sm->per_thread_data[thread_index].sessions,
1885 old_addr1 = ip1->src_address.as_u32;
1886 ip1->src_address = s1->out2in.addr;
1887 new_addr1 = ip1->src_address.as_u32;
1888 if (!is_output_feature)
1889 vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1891 sum1 = ip1->checksum;
1892 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1894 src_address /* changed member */);
1895 ip1->checksum = ip_csum_fold (sum1);
1897 if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1899 old_port1 = tcp1->src_port;
1900 tcp1->src_port = s1->out2in.port;
1901 new_port1 = tcp1->src_port;
1903 sum1 = tcp1->checksum;
1904 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1906 dst_address /* changed member */);
1907 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1908 ip4_header_t /* cheat */,
1909 length /* changed member */);
1910 tcp1->checksum = ip_csum_fold(sum1);
1914 old_port1 = udp1->src_port;
1915 udp1->src_port = s1->out2in.port;
1920 if (!is_output_feature)
1921 snat_hairpinning (sm, b1, ip1, udp1, tcp1, proto1);
1924 s1->last_heard = now;
1926 s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
1927 /* Per-user LRU list maintenance for dynamic translation */
1928 if (!snat_is_session_static (s1))
1930 clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1931 s1->per_user_index);
1932 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1933 s1->per_user_list_head_index,
1934 s1->per_user_index);
1938 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1939 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1941 snat_in2out_trace_t *t =
1942 vlib_add_trace (vm, node, b1, sizeof (*t));
1943 t->sw_if_index = sw_if_index1;
1944 t->next_index = next1;
1945 t->session_index = ~0;
1947 t->session_index = s1 - sm->per_thread_data[thread_index].sessions;
1950 pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP;
1952 /* verify speculative enqueues, maybe switch current next frame */
1953 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1954 to_next, n_left_to_next,
1955 bi0, bi1, next0, next1);
1958 while (n_left_from > 0 && n_left_to_next > 0)
1966 u32 new_addr0, old_addr0;
1967 u16 old_port0, new_port0;
1968 udp_header_t * udp0;
1969 tcp_header_t * tcp0;
1970 icmp46_header_t * icmp0;
1971 snat_session_key_t key0;
1974 snat_session_t * s0 = 0;
1975 clib_bihash_kv_8_8_t kv0, value0;
1976 u32 iph_offset0 = 0;
1978 /* speculatively enqueue b0 to the current next frame */
1984 n_left_to_next -= 1;
1986 b0 = vlib_get_buffer (vm, bi0);
1987 next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1989 if (is_output_feature)
1990 iph_offset0 = vnet_buffer (b0)->ip.save_rewrite_length;
1992 ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
1995 udp0 = ip4_next_header (ip0);
1996 tcp0 = (tcp_header_t *) udp0;
1997 icmp0 = (icmp46_header_t *) udp0;
1999 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2000 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
2003 if (PREDICT_FALSE(ip0->ttl == 1))
2005 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2006 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2007 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2009 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
2013 proto0 = ip_proto_to_snat_proto (ip0->protocol);
2015 /* Next configured feature, probably ip4-lookup */
2018 if (PREDICT_FALSE (proto0 == ~0))
2020 snat_in2out_unknown_proto (sm, b0, ip0, rx_fib_index0,
2021 thread_index, now, vm);
2025 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2027 next0 = icmp_in2out_slow_path
2028 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
2029 next0, now, thread_index, &s0);
2035 if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
2037 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
2042 key0.addr = ip0->src_address;
2043 key0.port = udp0->src_port;
2044 key0.protocol = proto0;
2045 key0.fib_index = rx_fib_index0;
2047 kv0.key = key0.as_u64;
2049 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out,
2054 if (PREDICT_FALSE(snat_not_translate(sm, node, sw_if_index0,
2055 ip0, proto0, rx_fib_index0, thread_index)) && !is_output_feature)
2058 next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
2059 &s0, node, next0, thread_index);
2061 if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
2066 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
2072 if (PREDICT_FALSE (value0.value == ~0ULL))
2076 s0 = snat_in2out_lb(sm, b0, ip0, rx_fib_index0, thread_index,
2082 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
2088 s0 = pool_elt_at_index (
2089 sm->per_thread_data[thread_index].sessions,
2094 old_addr0 = ip0->src_address.as_u32;
2095 ip0->src_address = s0->out2in.addr;
2096 new_addr0 = ip0->src_address.as_u32;
2097 if (!is_output_feature)
2098 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
2100 sum0 = ip0->checksum;
2101 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2103 src_address /* changed member */);
2104 ip0->checksum = ip_csum_fold (sum0);
2106 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2108 old_port0 = tcp0->src_port;
2109 tcp0->src_port = s0->out2in.port;
2110 new_port0 = tcp0->src_port;
2112 sum0 = tcp0->checksum;
2113 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2115 dst_address /* changed member */);
2116 sum0 = ip_csum_update (sum0, old_port0, new_port0,
2117 ip4_header_t /* cheat */,
2118 length /* changed member */);
2119 tcp0->checksum = ip_csum_fold(sum0);
2123 old_port0 = udp0->src_port;
2124 udp0->src_port = s0->out2in.port;
2129 if (!is_output_feature)
2130 snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
2133 s0->last_heard = now;
2135 s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
2136 /* Per-user LRU list maintenance for dynamic translation */
2137 if (!snat_is_session_static (s0))
2139 clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
2140 s0->per_user_index);
2141 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
2142 s0->per_user_list_head_index,
2143 s0->per_user_index);
2147 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2148 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2150 snat_in2out_trace_t *t =
2151 vlib_add_trace (vm, node, b0, sizeof (*t));
2152 t->is_slow_path = is_slow_path;
2153 t->sw_if_index = sw_if_index0;
2154 t->next_index = next0;
2155 t->session_index = ~0;
2157 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
2160 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2162 /* verify speculative enqueue, maybe switch current next frame */
2163 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2164 to_next, n_left_to_next,
2168 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2171 vlib_node_increment_counter (vm, stats_node_index,
2172 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2174 return frame->n_vectors;
2178 snat_in2out_fast_path_fn (vlib_main_t * vm,
2179 vlib_node_runtime_t * node,
2180 vlib_frame_t * frame)
2182 return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */, 0);
2185 VLIB_REGISTER_NODE (snat_in2out_node) = {
2186 .function = snat_in2out_fast_path_fn,
2187 .name = "nat44-in2out",
2188 .vector_size = sizeof (u32),
2189 .format_trace = format_snat_in2out_trace,
2190 .type = VLIB_NODE_TYPE_INTERNAL,
2192 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2193 .error_strings = snat_in2out_error_strings,
2195 .runtime_data_bytes = sizeof (snat_runtime_t),
2197 .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2199 /* edit / add dispositions here */
2201 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2202 [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2203 [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2204 [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2208 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_node, snat_in2out_fast_path_fn);
2211 snat_in2out_output_fast_path_fn (vlib_main_t * vm,
2212 vlib_node_runtime_t * node,
2213 vlib_frame_t * frame)
2215 return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */, 1);
2218 VLIB_REGISTER_NODE (snat_in2out_output_node) = {
2219 .function = snat_in2out_output_fast_path_fn,
2220 .name = "nat44-in2out-output",
2221 .vector_size = sizeof (u32),
2222 .format_trace = format_snat_in2out_trace,
2223 .type = VLIB_NODE_TYPE_INTERNAL,
2225 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2226 .error_strings = snat_in2out_error_strings,
2228 .runtime_data_bytes = sizeof (snat_runtime_t),
2230 .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2232 /* edit / add dispositions here */
2234 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2235 [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
2236 [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
2237 [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2241 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_output_node,
2242 snat_in2out_output_fast_path_fn);
2245 snat_in2out_slow_path_fn (vlib_main_t * vm,
2246 vlib_node_runtime_t * node,
2247 vlib_frame_t * frame)
2249 return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */, 0);
2252 VLIB_REGISTER_NODE (snat_in2out_slowpath_node) = {
2253 .function = snat_in2out_slow_path_fn,
2254 .name = "nat44-in2out-slowpath",
2255 .vector_size = sizeof (u32),
2256 .format_trace = format_snat_in2out_trace,
2257 .type = VLIB_NODE_TYPE_INTERNAL,
2259 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2260 .error_strings = snat_in2out_error_strings,
2262 .runtime_data_bytes = sizeof (snat_runtime_t),
2264 .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2266 /* edit / add dispositions here */
2268 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2269 [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2270 [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
2271 [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2275 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_slowpath_node,
2276 snat_in2out_slow_path_fn);
2279 snat_in2out_output_slow_path_fn (vlib_main_t * vm,
2280 vlib_node_runtime_t * node,
2281 vlib_frame_t * frame)
2283 return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */, 1);
2286 VLIB_REGISTER_NODE (snat_in2out_output_slowpath_node) = {
2287 .function = snat_in2out_output_slow_path_fn,
2288 .name = "nat44-in2out-output-slowpath",
2289 .vector_size = sizeof (u32),
2290 .format_trace = format_snat_in2out_trace,
2291 .type = VLIB_NODE_TYPE_INTERNAL,
2293 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2294 .error_strings = snat_in2out_error_strings,
2296 .runtime_data_bytes = sizeof (snat_runtime_t),
2298 .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2300 /* edit / add dispositions here */
2302 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2303 [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
2304 [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
2305 [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2309 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_output_slowpath_node,
2310 snat_in2out_output_slow_path_fn);
2312 /**************************/
2313 /*** deterministic mode ***/
2314 /**************************/
2316 snat_det_in2out_node_fn (vlib_main_t * vm,
2317 vlib_node_runtime_t * node,
2318 vlib_frame_t * frame)
2320 u32 n_left_from, * from, * to_next;
2321 snat_in2out_next_t next_index;
2322 u32 pkts_processed = 0;
2323 snat_main_t * sm = &snat_main;
2324 u32 now = (u32) vlib_time_now (vm);
2325 u32 thread_index = vlib_get_thread_index ();
2327 from = vlib_frame_vector_args (frame);
2328 n_left_from = frame->n_vectors;
2329 next_index = node->cached_next_index;
2331 while (n_left_from > 0)
2335 vlib_get_next_frame (vm, node, next_index,
2336 to_next, n_left_to_next);
2338 while (n_left_from >= 4 && n_left_to_next >= 2)
2341 vlib_buffer_t * b0, * b1;
2343 u32 sw_if_index0, sw_if_index1;
2344 ip4_header_t * ip0, * ip1;
2345 ip_csum_t sum0, sum1;
2346 ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
2347 u16 old_port0, new_port0, lo_port0, i0;
2348 u16 old_port1, new_port1, lo_port1, i1;
2349 udp_header_t * udp0, * udp1;
2350 tcp_header_t * tcp0, * tcp1;
2352 snat_det_out_key_t key0, key1;
2353 snat_det_map_t * dm0, * dm1;
2354 snat_det_session_t * ses0 = 0, * ses1 = 0;
2355 u32 rx_fib_index0, rx_fib_index1;
2356 icmp46_header_t * icmp0, * icmp1;
2358 /* Prefetch next iteration. */
2360 vlib_buffer_t * p2, * p3;
2362 p2 = vlib_get_buffer (vm, from[2]);
2363 p3 = vlib_get_buffer (vm, from[3]);
2365 vlib_prefetch_buffer_header (p2, LOAD);
2366 vlib_prefetch_buffer_header (p3, LOAD);
2368 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
2369 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
2372 /* speculatively enqueue b0 and b1 to the current next frame */
2373 to_next[0] = bi0 = from[0];
2374 to_next[1] = bi1 = from[1];
2378 n_left_to_next -= 2;
2380 b0 = vlib_get_buffer (vm, bi0);
2381 b1 = vlib_get_buffer (vm, bi1);
2383 next0 = SNAT_IN2OUT_NEXT_LOOKUP;
2384 next1 = SNAT_IN2OUT_NEXT_LOOKUP;
2386 ip0 = vlib_buffer_get_current (b0);
2387 udp0 = ip4_next_header (ip0);
2388 tcp0 = (tcp_header_t *) udp0;
2390 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2392 if (PREDICT_FALSE(ip0->ttl == 1))
2394 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2395 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2396 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2398 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
2402 proto0 = ip_proto_to_snat_proto (ip0->protocol);
2404 if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2406 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2407 icmp0 = (icmp46_header_t *) udp0;
2409 next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
2410 rx_fib_index0, node, next0, thread_index,
2415 dm0 = snat_det_map_by_user(sm, &ip0->src_address);
2416 if (PREDICT_FALSE(!dm0))
2418 clib_warning("no match for internal host %U",
2419 format_ip4_address, &ip0->src_address);
2420 next0 = SNAT_IN2OUT_NEXT_DROP;
2421 b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2425 snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0);
2427 key0.ext_host_addr = ip0->dst_address;
2428 key0.ext_host_port = tcp0->dst;
2430 ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src, key0);
2431 if (PREDICT_FALSE(!ses0))
2433 for (i0 = 0; i0 < dm0->ports_per_host; i0++)
2435 key0.out_port = clib_host_to_net_u16 (lo_port0 +
2436 ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host));
2438 if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64))
2441 ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0);
2444 if (PREDICT_FALSE(!ses0))
2446 /* too many sessions for user, send ICMP error packet */
2448 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2449 icmp4_error_set_vnet_buffer (b0, ICMP4_destination_unreachable,
2450 ICMP4_destination_unreachable_destination_unreachable_host,
2452 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
2457 new_port0 = ses0->out.out_port;
2459 old_addr0.as_u32 = ip0->src_address.as_u32;
2460 ip0->src_address.as_u32 = new_addr0.as_u32;
2461 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
2463 sum0 = ip0->checksum;
2464 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2466 src_address /* changed member */);
2467 ip0->checksum = ip_csum_fold (sum0);
2469 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2471 if (tcp0->flags & TCP_FLAG_SYN)
2472 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
2473 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
2474 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
2475 else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2476 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
2477 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
2478 snat_det_ses_close(dm0, ses0);
2479 else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
2480 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
2481 else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN)
2482 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
2484 old_port0 = tcp0->src;
2485 tcp0->src = new_port0;
2487 sum0 = tcp0->checksum;
2488 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2490 dst_address /* changed member */);
2491 sum0 = ip_csum_update (sum0, old_port0, new_port0,
2492 ip4_header_t /* cheat */,
2493 length /* changed member */);
2494 tcp0->checksum = ip_csum_fold(sum0);
2498 ses0->state = SNAT_SESSION_UDP_ACTIVE;
2499 old_port0 = udp0->src_port;
2500 udp0->src_port = new_port0;
2506 case SNAT_SESSION_UDP_ACTIVE:
2507 ses0->expire = now + sm->udp_timeout;
2509 case SNAT_SESSION_TCP_SYN_SENT:
2510 case SNAT_SESSION_TCP_FIN_WAIT:
2511 case SNAT_SESSION_TCP_CLOSE_WAIT:
2512 case SNAT_SESSION_TCP_LAST_ACK:
2513 ses0->expire = now + sm->tcp_transitory_timeout;
2515 case SNAT_SESSION_TCP_ESTABLISHED:
2516 ses0->expire = now + sm->tcp_established_timeout;
2521 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2522 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2524 snat_in2out_trace_t *t =
2525 vlib_add_trace (vm, node, b0, sizeof (*t));
2526 t->is_slow_path = 0;
2527 t->sw_if_index = sw_if_index0;
2528 t->next_index = next0;
2529 t->session_index = ~0;
2531 t->session_index = ses0 - dm0->sessions;
2534 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2536 ip1 = vlib_buffer_get_current (b1);
2537 udp1 = ip4_next_header (ip1);
2538 tcp1 = (tcp_header_t *) udp1;
2540 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
2542 if (PREDICT_FALSE(ip1->ttl == 1))
2544 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2545 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
2546 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2548 next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
2552 proto1 = ip_proto_to_snat_proto (ip1->protocol);
2554 if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP))
2556 rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1);
2557 icmp1 = (icmp46_header_t *) udp1;
2559 next1 = icmp_in2out(sm, b1, ip1, icmp1, sw_if_index1,
2560 rx_fib_index1, node, next1, thread_index,
2565 dm1 = snat_det_map_by_user(sm, &ip1->src_address);
2566 if (PREDICT_FALSE(!dm1))
2568 clib_warning("no match for internal host %U",
2569 format_ip4_address, &ip0->src_address);
2570 next1 = SNAT_IN2OUT_NEXT_DROP;
2571 b1->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2575 snat_det_forward(dm1, &ip1->src_address, &new_addr1, &lo_port1);
2577 key1.ext_host_addr = ip1->dst_address;
2578 key1.ext_host_port = tcp1->dst;
2580 ses1 = snat_det_find_ses_by_in(dm1, &ip1->src_address, tcp1->src, key1);
2581 if (PREDICT_FALSE(!ses1))
2583 for (i1 = 0; i1 < dm1->ports_per_host; i1++)
2585 key1.out_port = clib_host_to_net_u16 (lo_port1 +
2586 ((i1 + clib_net_to_host_u16 (tcp1->src)) % dm1->ports_per_host));
2588 if (snat_det_get_ses_by_out (dm1, &ip1->src_address, key1.as_u64))
2591 ses1 = snat_det_ses_create(dm1, &ip1->src_address, tcp1->src, &key1);
2594 if (PREDICT_FALSE(!ses1))
2596 /* too many sessions for user, send ICMP error packet */
2598 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2599 icmp4_error_set_vnet_buffer (b1, ICMP4_destination_unreachable,
2600 ICMP4_destination_unreachable_destination_unreachable_host,
2602 next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
2607 new_port1 = ses1->out.out_port;
2609 old_addr1.as_u32 = ip1->src_address.as_u32;
2610 ip1->src_address.as_u32 = new_addr1.as_u32;
2611 vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
2613 sum1 = ip1->checksum;
2614 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
2616 src_address /* changed member */);
2617 ip1->checksum = ip_csum_fold (sum1);
2619 if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
2621 if (tcp1->flags & TCP_FLAG_SYN)
2622 ses1->state = SNAT_SESSION_TCP_SYN_SENT;
2623 else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_SYN_SENT)
2624 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
2625 else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
2626 ses1->state = SNAT_SESSION_TCP_FIN_WAIT;
2627 else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_FIN_WAIT)
2628 snat_det_ses_close(dm1, ses1);
2629 else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_CLOSE_WAIT)
2630 ses1->state = SNAT_SESSION_TCP_LAST_ACK;
2631 else if (tcp1->flags == 0 && ses1->state == SNAT_SESSION_UNKNOWN)
2632 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
2634 old_port1 = tcp1->src;
2635 tcp1->src = new_port1;
2637 sum1 = tcp1->checksum;
2638 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
2640 dst_address /* changed member */);
2641 sum1 = ip_csum_update (sum1, old_port1, new_port1,
2642 ip4_header_t /* cheat */,
2643 length /* changed member */);
2644 tcp1->checksum = ip_csum_fold(sum1);
2648 ses1->state = SNAT_SESSION_UDP_ACTIVE;
2649 old_port1 = udp1->src_port;
2650 udp1->src_port = new_port1;
2656 case SNAT_SESSION_UDP_ACTIVE:
2657 ses1->expire = now + sm->udp_timeout;
2659 case SNAT_SESSION_TCP_SYN_SENT:
2660 case SNAT_SESSION_TCP_FIN_WAIT:
2661 case SNAT_SESSION_TCP_CLOSE_WAIT:
2662 case SNAT_SESSION_TCP_LAST_ACK:
2663 ses1->expire = now + sm->tcp_transitory_timeout;
2665 case SNAT_SESSION_TCP_ESTABLISHED:
2666 ses1->expire = now + sm->tcp_established_timeout;
2671 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2672 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
2674 snat_in2out_trace_t *t =
2675 vlib_add_trace (vm, node, b1, sizeof (*t));
2676 t->is_slow_path = 0;
2677 t->sw_if_index = sw_if_index1;
2678 t->next_index = next1;
2679 t->session_index = ~0;
2681 t->session_index = ses1 - dm1->sessions;
2684 pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP;
2686 /* verify speculative enqueues, maybe switch current next frame */
2687 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2688 to_next, n_left_to_next,
2689 bi0, bi1, next0, next1);
2692 while (n_left_from > 0 && n_left_to_next > 0)
2700 ip4_address_t new_addr0, old_addr0;
2701 u16 old_port0, new_port0, lo_port0, i0;
2702 udp_header_t * udp0;
2703 tcp_header_t * tcp0;
2705 snat_det_out_key_t key0;
2706 snat_det_map_t * dm0;
2707 snat_det_session_t * ses0 = 0;
2709 icmp46_header_t * icmp0;
2711 /* speculatively enqueue b0 to the current next frame */
2717 n_left_to_next -= 1;
2719 b0 = vlib_get_buffer (vm, bi0);
2720 next0 = SNAT_IN2OUT_NEXT_LOOKUP;
2722 ip0 = vlib_buffer_get_current (b0);
2723 udp0 = ip4_next_header (ip0);
2724 tcp0 = (tcp_header_t *) udp0;
2726 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2728 if (PREDICT_FALSE(ip0->ttl == 1))
2730 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2731 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2732 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2734 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
2738 proto0 = ip_proto_to_snat_proto (ip0->protocol);
2740 if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2742 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2743 icmp0 = (icmp46_header_t *) udp0;
2745 next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
2746 rx_fib_index0, node, next0, thread_index,
2751 dm0 = snat_det_map_by_user(sm, &ip0->src_address);
2752 if (PREDICT_FALSE(!dm0))
2754 clib_warning("no match for internal host %U",
2755 format_ip4_address, &ip0->src_address);
2756 next0 = SNAT_IN2OUT_NEXT_DROP;
2757 b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2761 snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0);
2763 key0.ext_host_addr = ip0->dst_address;
2764 key0.ext_host_port = tcp0->dst;
2766 ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src, key0);
2767 if (PREDICT_FALSE(!ses0))
2769 for (i0 = 0; i0 < dm0->ports_per_host; i0++)
2771 key0.out_port = clib_host_to_net_u16 (lo_port0 +
2772 ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host));
2774 if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64))
2777 ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0);
2780 if (PREDICT_FALSE(!ses0))
2782 /* too many sessions for user, send ICMP error packet */
2784 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2785 icmp4_error_set_vnet_buffer (b0, ICMP4_destination_unreachable,
2786 ICMP4_destination_unreachable_destination_unreachable_host,
2788 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
2793 new_port0 = ses0->out.out_port;
2795 old_addr0.as_u32 = ip0->src_address.as_u32;
2796 ip0->src_address.as_u32 = new_addr0.as_u32;
2797 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
2799 sum0 = ip0->checksum;
2800 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2802 src_address /* changed member */);
2803 ip0->checksum = ip_csum_fold (sum0);
2805 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2807 if (tcp0->flags & TCP_FLAG_SYN)
2808 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
2809 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
2810 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
2811 else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2812 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
2813 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
2814 snat_det_ses_close(dm0, ses0);
2815 else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
2816 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
2817 else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN)
2818 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
2820 old_port0 = tcp0->src;
2821 tcp0->src = new_port0;
2823 sum0 = tcp0->checksum;
2824 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2826 dst_address /* changed member */);
2827 sum0 = ip_csum_update (sum0, old_port0, new_port0,
2828 ip4_header_t /* cheat */,
2829 length /* changed member */);
2830 tcp0->checksum = ip_csum_fold(sum0);
2834 ses0->state = SNAT_SESSION_UDP_ACTIVE;
2835 old_port0 = udp0->src_port;
2836 udp0->src_port = new_port0;
2842 case SNAT_SESSION_UDP_ACTIVE:
2843 ses0->expire = now + sm->udp_timeout;
2845 case SNAT_SESSION_TCP_SYN_SENT:
2846 case SNAT_SESSION_TCP_FIN_WAIT:
2847 case SNAT_SESSION_TCP_CLOSE_WAIT:
2848 case SNAT_SESSION_TCP_LAST_ACK:
2849 ses0->expire = now + sm->tcp_transitory_timeout;
2851 case SNAT_SESSION_TCP_ESTABLISHED:
2852 ses0->expire = now + sm->tcp_established_timeout;
2857 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2858 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2860 snat_in2out_trace_t *t =
2861 vlib_add_trace (vm, node, b0, sizeof (*t));
2862 t->is_slow_path = 0;
2863 t->sw_if_index = sw_if_index0;
2864 t->next_index = next0;
2865 t->session_index = ~0;
2867 t->session_index = ses0 - dm0->sessions;
2870 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2872 /* verify speculative enqueue, maybe switch current next frame */
2873 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2874 to_next, n_left_to_next,
2878 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2881 vlib_node_increment_counter (vm, snat_det_in2out_node.index,
2882 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2884 return frame->n_vectors;
2887 VLIB_REGISTER_NODE (snat_det_in2out_node) = {
2888 .function = snat_det_in2out_node_fn,
2889 .name = "nat44-det-in2out",
2890 .vector_size = sizeof (u32),
2891 .format_trace = format_snat_in2out_trace,
2892 .type = VLIB_NODE_TYPE_INTERNAL,
2894 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2895 .error_strings = snat_in2out_error_strings,
2897 .runtime_data_bytes = sizeof (snat_runtime_t),
2901 /* edit / add dispositions here */
2903 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2904 [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2905 [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2909 VLIB_NODE_FUNCTION_MULTIARCH (snat_det_in2out_node, snat_det_in2out_node_fn);
2912 * Get address and port values to be used for ICMP packet translation
2913 * and create session if needed
2915 * @param[in,out] sm NAT main
2916 * @param[in,out] node NAT node runtime
2917 * @param[in] thread_index thread index
2918 * @param[in,out] b0 buffer containing packet to be translated
2919 * @param[out] p_proto protocol used for matching
2920 * @param[out] p_value address and port after NAT translation
2921 * @param[out] p_dont_translate if packet should not be translated
2922 * @param d optional parameter
2923 * @param e optional parameter
2925 u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node,
2926 u32 thread_index, vlib_buffer_t *b0, u8 *p_proto,
2927 snat_session_key_t *p_value,
2928 u8 *p_dont_translate, void *d, void *e)
2931 icmp46_header_t *icmp0;
2935 snat_det_out_key_t key0;
2936 u8 dont_translate = 0;
2938 icmp_echo_header_t *echo0, *inner_echo0 = 0;
2939 ip4_header_t *inner_ip0;
2940 void *l4_header = 0;
2941 icmp46_header_t *inner_icmp0;
2942 snat_det_map_t * dm0 = 0;
2943 ip4_address_t new_addr0;
2945 snat_det_session_t * ses0 = 0;
2946 ip4_address_t in_addr;
2949 ip0 = vlib_buffer_get_current (b0);
2950 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
2951 echo0 = (icmp_echo_header_t *)(icmp0+1);
2952 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2953 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
2955 if (!icmp_is_error_message (icmp0))
2957 protocol = SNAT_PROTOCOL_ICMP;
2958 in_addr = ip0->src_address;
2959 in_port = echo0->identifier;
2963 inner_ip0 = (ip4_header_t *)(echo0+1);
2964 l4_header = ip4_next_header (inner_ip0);
2965 protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
2966 in_addr = inner_ip0->dst_address;
2969 case SNAT_PROTOCOL_ICMP:
2970 inner_icmp0 = (icmp46_header_t*)l4_header;
2971 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
2972 in_port = inner_echo0->identifier;
2974 case SNAT_PROTOCOL_UDP:
2975 case SNAT_PROTOCOL_TCP:
2976 in_port = ((tcp_udp_header_t*)l4_header)->dst_port;
2979 b0->error = node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
2980 next0 = SNAT_IN2OUT_NEXT_DROP;
2985 dm0 = snat_det_map_by_user(sm, &in_addr);
2986 if (PREDICT_FALSE(!dm0))
2988 clib_warning("no match for internal host %U",
2989 format_ip4_address, &in_addr);
2990 if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0,
2991 IP_PROTOCOL_ICMP, rx_fib_index0)))
2996 next0 = SNAT_IN2OUT_NEXT_DROP;
2997 b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
3001 snat_det_forward(dm0, &in_addr, &new_addr0, &lo_port0);
3003 key0.ext_host_addr = ip0->dst_address;
3004 key0.ext_host_port = 0;
3006 ses0 = snat_det_find_ses_by_in(dm0, &in_addr, in_port, key0);
3007 if (PREDICT_FALSE(!ses0))
3009 if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0,
3010 IP_PROTOCOL_ICMP, rx_fib_index0)))
3015 if (icmp0->type != ICMP4_echo_request)
3017 b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
3018 next0 = SNAT_IN2OUT_NEXT_DROP;
3021 for (i0 = 0; i0 < dm0->ports_per_host; i0++)
3023 key0.out_port = clib_host_to_net_u16 (lo_port0 +
3024 ((i0 + clib_net_to_host_u16 (echo0->identifier)) % dm0->ports_per_host));
3026 if (snat_det_get_ses_by_out (dm0, &in_addr, key0.as_u64))
3029 ses0 = snat_det_ses_create(dm0, &in_addr, echo0->identifier, &key0);
3032 if (PREDICT_FALSE(!ses0))
3034 next0 = SNAT_IN2OUT_NEXT_DROP;
3035 b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
3040 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request &&
3041 !icmp_is_error_message (icmp0)))
3043 b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
3044 next0 = SNAT_IN2OUT_NEXT_DROP;
3048 u32 now = (u32) vlib_time_now (sm->vlib_main);
3050 ses0->state = SNAT_SESSION_ICMP_ACTIVE;
3051 ses0->expire = now + sm->icmp_timeout;
3054 *p_proto = protocol;
3057 p_value->addr = new_addr0;
3058 p_value->fib_index = sm->outside_fib_index;
3059 p_value->port = ses0->out.out_port;
3061 *p_dont_translate = dont_translate;
3063 *(snat_det_session_t**)d = ses0;
3065 *(snat_det_map_t**)e = dm0;
3069 /**********************/
3070 /*** worker handoff ***/
3071 /**********************/
3073 snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm,
3074 vlib_node_runtime_t * node,
3075 vlib_frame_t * frame,
3078 snat_main_t *sm = &snat_main;
3079 vlib_thread_main_t *tm = vlib_get_thread_main ();
3080 u32 n_left_from, *from, *to_next = 0;
3081 static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
3082 static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
3084 vlib_frame_queue_elt_t *hf = 0;
3085 vlib_frame_t *f = 0;
3087 u32 n_left_to_next_worker = 0, *to_next_worker = 0;
3088 u32 next_worker_index = 0;
3089 u32 current_worker_index = ~0;
3090 u32 thread_index = vlib_get_thread_index ();
3094 ASSERT (vec_len (sm->workers));
3098 fq_index = sm->fq_in2out_output_index;
3099 to_node_index = sm->in2out_output_node_index;
3103 fq_index = sm->fq_in2out_index;
3104 to_node_index = sm->in2out_node_index;
3107 if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
3109 vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
3111 vec_validate_init_empty (congested_handoff_queue_by_worker_index,
3112 sm->first_worker_index + sm->num_workers - 1,
3113 (vlib_frame_queue_t *) (~0));
3116 from = vlib_frame_vector_args (frame);
3117 n_left_from = frame->n_vectors;
3119 while (n_left_from > 0)
3132 b0 = vlib_get_buffer (vm, bi0);
3134 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
3135 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
3137 ip0 = vlib_buffer_get_current (b0);
3139 next_worker_index = sm->worker_in2out_cb(ip0, rx_fib_index0);
3141 if (PREDICT_FALSE (next_worker_index != thread_index))
3145 if (next_worker_index != current_worker_index)
3148 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
3150 hf = vlib_get_worker_handoff_queue_elt (fq_index,
3152 handoff_queue_elt_by_worker_index);
3154 n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
3155 to_next_worker = &hf->buffer_index[hf->n_vectors];
3156 current_worker_index = next_worker_index;
3159 /* enqueue to correct worker thread */
3160 to_next_worker[0] = bi0;
3162 n_left_to_next_worker--;
3164 if (n_left_to_next_worker == 0)
3166 hf->n_vectors = VLIB_FRAME_SIZE;
3167 vlib_put_frame_queue_elt (hf);
3168 current_worker_index = ~0;
3169 handoff_queue_elt_by_worker_index[next_worker_index] = 0;
3176 /* if this is 1st frame */
3179 f = vlib_get_frame_to_node (vm, to_node_index);
3180 to_next = vlib_frame_vector_args (f);
3188 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
3189 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3191 snat_in2out_worker_handoff_trace_t *t =
3192 vlib_add_trace (vm, node, b0, sizeof (*t));
3193 t->next_worker_index = next_worker_index;
3194 t->do_handoff = do_handoff;
3199 vlib_put_frame_to_node (vm, to_node_index, f);
3202 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
3204 /* Ship frames to the worker nodes */
3205 for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
3207 if (handoff_queue_elt_by_worker_index[i])
3209 hf = handoff_queue_elt_by_worker_index[i];
3211 * It works better to let the handoff node
3212 * rate-adapt, always ship the handoff queue element.
3214 if (1 || hf->n_vectors == hf->last_n_vectors)
3216 vlib_put_frame_queue_elt (hf);
3217 handoff_queue_elt_by_worker_index[i] = 0;
3220 hf->last_n_vectors = hf->n_vectors;
3222 congested_handoff_queue_by_worker_index[i] =
3223 (vlib_frame_queue_t *) (~0);
3226 current_worker_index = ~0;
3227 return frame->n_vectors;
3231 snat_in2out_worker_handoff_fn (vlib_main_t * vm,
3232 vlib_node_runtime_t * node,
3233 vlib_frame_t * frame)
3235 return snat_in2out_worker_handoff_fn_inline (vm, node, frame, 0);
3238 VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node) = {
3239 .function = snat_in2out_worker_handoff_fn,
3240 .name = "nat44-in2out-worker-handoff",
3241 .vector_size = sizeof (u32),
3242 .format_trace = format_snat_in2out_worker_handoff_trace,
3243 .type = VLIB_NODE_TYPE_INTERNAL,
3252 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_worker_handoff_node,
3253 snat_in2out_worker_handoff_fn);
3256 snat_in2out_output_worker_handoff_fn (vlib_main_t * vm,
3257 vlib_node_runtime_t * node,
3258 vlib_frame_t * frame)
3260 return snat_in2out_worker_handoff_fn_inline (vm, node, frame, 1);
3263 VLIB_REGISTER_NODE (snat_in2out_output_worker_handoff_node) = {
3264 .function = snat_in2out_output_worker_handoff_fn,
3265 .name = "nat44-in2out-output-worker-handoff",
3266 .vector_size = sizeof (u32),
3267 .format_trace = format_snat_in2out_worker_handoff_trace,
3268 .type = VLIB_NODE_TYPE_INTERNAL,
3277 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_output_worker_handoff_node,
3278 snat_in2out_output_worker_handoff_fn);
3280 static_always_inline int
3281 is_hairpinning (snat_main_t *sm, ip4_address_t * dst_addr)
3283 snat_address_t * ap;
3284 clib_bihash_kv_8_8_t kv, value;
3285 snat_session_key_t m_key;
3287 vec_foreach (ap, sm->addresses)
3289 if (ap->addr.as_u32 == dst_addr->as_u32)
3293 m_key.addr.as_u32 = dst_addr->as_u32;
3294 m_key.fib_index = sm->outside_fib_index;
3297 kv.key = m_key.as_u64;
3298 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
3305 snat_hairpin_dst_fn (vlib_main_t * vm,
3306 vlib_node_runtime_t * node,
3307 vlib_frame_t * frame)
3309 u32 n_left_from, * from, * to_next;
3310 snat_in2out_next_t next_index;
3311 u32 pkts_processed = 0;
3312 snat_main_t * sm = &snat_main;
3314 from = vlib_frame_vector_args (frame);
3315 n_left_from = frame->n_vectors;
3316 next_index = node->cached_next_index;
3318 while (n_left_from > 0)
3322 vlib_get_next_frame (vm, node, next_index,
3323 to_next, n_left_to_next);
3325 while (n_left_from > 0 && n_left_to_next > 0)
3333 /* speculatively enqueue b0 to the current next frame */
3339 n_left_to_next -= 1;
3341 b0 = vlib_get_buffer (vm, bi0);
3342 next0 = SNAT_IN2OUT_NEXT_LOOKUP;
3343 ip0 = vlib_buffer_get_current (b0);
3345 proto0 = ip_proto_to_snat_proto (ip0->protocol);
3347 vnet_buffer (b0)->snat.flags = 0;
3348 if (PREDICT_FALSE (is_hairpinning (sm, &ip0->dst_address)))
3350 if (proto0 == SNAT_PROTOCOL_TCP || proto0 == SNAT_PROTOCOL_UDP)
3352 udp_header_t * udp0 = ip4_next_header (ip0);
3353 tcp_header_t * tcp0 = (tcp_header_t *) udp0;
3355 snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
3357 else if (proto0 == SNAT_PROTOCOL_ICMP)
3359 icmp46_header_t * icmp0 = ip4_next_header (ip0);
3361 snat_icmp_hairpinning (sm, b0, ip0, icmp0);
3365 snat_hairpinning_unknown_proto (sm, b0, ip0);
3368 vnet_buffer (b0)->snat.flags = SNAT_FLAG_HAIRPINNING;
3369 clib_warning("is hairpinning");
3372 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
3374 /* verify speculative enqueue, maybe switch current next frame */
3375 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3376 to_next, n_left_to_next,
3380 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3383 vlib_node_increment_counter (vm, snat_hairpin_dst_node.index,
3384 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
3386 return frame->n_vectors;
3389 VLIB_REGISTER_NODE (snat_hairpin_dst_node) = {
3390 .function = snat_hairpin_dst_fn,
3391 .name = "nat44-hairpin-dst",
3392 .vector_size = sizeof (u32),
3393 .type = VLIB_NODE_TYPE_INTERNAL,
3394 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
3395 .error_strings = snat_in2out_error_strings,
3398 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
3399 [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
3403 VLIB_NODE_FUNCTION_MULTIARCH (snat_hairpin_dst_node,
3404 snat_hairpin_dst_fn);
3407 snat_hairpin_src_fn (vlib_main_t * vm,
3408 vlib_node_runtime_t * node,
3409 vlib_frame_t * frame)
3411 u32 n_left_from, * from, * to_next;
3412 snat_in2out_next_t next_index;
3413 u32 pkts_processed = 0;
3414 snat_main_t *sm = &snat_main;
3416 from = vlib_frame_vector_args (frame);
3417 n_left_from = frame->n_vectors;
3418 next_index = node->cached_next_index;
3420 while (n_left_from > 0)
3424 vlib_get_next_frame (vm, node, next_index,
3425 to_next, n_left_to_next);
3427 while (n_left_from > 0 && n_left_to_next > 0)
3432 snat_interface_t *i;
3435 /* speculatively enqueue b0 to the current next frame */
3441 n_left_to_next -= 1;
3443 b0 = vlib_get_buffer (vm, bi0);
3444 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3445 next0 = SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT;
3447 pool_foreach (i, sm->output_feature_interfaces,
3449 /* Only packets from NAT inside interface */
3450 if ((i->is_inside == 1) && (sw_if_index0 == i->sw_if_index))
3452 if (PREDICT_FALSE ((vnet_buffer (b0)->snat.flags) &
3453 SNAT_FLAG_HAIRPINNING))
3455 if (PREDICT_TRUE (sm->num_workers > 1))
3456 next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH;
3458 next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT;
3464 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
3466 /* verify speculative enqueue, maybe switch current next frame */
3467 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3468 to_next, n_left_to_next,
3472 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3475 vlib_node_increment_counter (vm, snat_hairpin_src_node.index,
3476 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
3478 return frame->n_vectors;
3481 VLIB_REGISTER_NODE (snat_hairpin_src_node) = {
3482 .function = snat_hairpin_src_fn,
3483 .name = "nat44-hairpin-src",
3484 .vector_size = sizeof (u32),
3485 .type = VLIB_NODE_TYPE_INTERNAL,
3486 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
3487 .error_strings = snat_in2out_error_strings,
3488 .n_next_nodes = SNAT_HAIRPIN_SRC_N_NEXT,
3490 [SNAT_HAIRPIN_SRC_NEXT_DROP] = "error-drop",
3491 [SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT] = "nat44-in2out-output",
3492 [SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT] = "interface-output",
3493 [SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH] = "nat44-in2out-output-worker-handoff",
3497 VLIB_NODE_FUNCTION_MULTIARCH (snat_hairpin_src_node,
3498 snat_hairpin_src_fn);
3501 snat_in2out_fast_static_map_fn (vlib_main_t * vm,
3502 vlib_node_runtime_t * node,
3503 vlib_frame_t * frame)
3505 u32 n_left_from, * from, * to_next;
3506 snat_in2out_next_t next_index;
3507 u32 pkts_processed = 0;
3508 snat_main_t * sm = &snat_main;
3509 u32 stats_node_index;
3511 stats_node_index = snat_in2out_fast_node.index;
3513 from = vlib_frame_vector_args (frame);
3514 n_left_from = frame->n_vectors;
3515 next_index = node->cached_next_index;
3517 while (n_left_from > 0)
3521 vlib_get_next_frame (vm, node, next_index,
3522 to_next, n_left_to_next);
3524 while (n_left_from > 0 && n_left_to_next > 0)
3532 u32 new_addr0, old_addr0;
3533 u16 old_port0, new_port0;
3534 udp_header_t * udp0;
3535 tcp_header_t * tcp0;
3536 icmp46_header_t * icmp0;
3537 snat_session_key_t key0, sm0;
3541 /* speculatively enqueue b0 to the current next frame */
3547 n_left_to_next -= 1;
3549 b0 = vlib_get_buffer (vm, bi0);
3550 next0 = SNAT_IN2OUT_NEXT_LOOKUP;
3552 ip0 = vlib_buffer_get_current (b0);
3553 udp0 = ip4_next_header (ip0);
3554 tcp0 = (tcp_header_t *) udp0;
3555 icmp0 = (icmp46_header_t *) udp0;
3557 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
3558 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
3560 if (PREDICT_FALSE(ip0->ttl == 1))
3562 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
3563 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
3564 ICMP4_time_exceeded_ttl_exceeded_in_transit,
3566 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
3570 proto0 = ip_proto_to_snat_proto (ip0->protocol);
3572 if (PREDICT_FALSE (proto0 == ~0))
3575 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
3577 next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0,
3578 rx_fib_index0, node, next0, ~0, 0, 0);
3582 key0.addr = ip0->src_address;
3583 key0.protocol = proto0;
3584 key0.port = udp0->src_port;
3585 key0.fib_index = rx_fib_index0;
3587 if (snat_static_mapping_match(sm, key0, &sm0, 0, 0))
3589 b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
3590 next0= SNAT_IN2OUT_NEXT_DROP;
3594 new_addr0 = sm0.addr.as_u32;
3595 new_port0 = sm0.port;
3596 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
3597 old_addr0 = ip0->src_address.as_u32;
3598 ip0->src_address.as_u32 = new_addr0;
3600 sum0 = ip0->checksum;
3601 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
3603 src_address /* changed member */);
3604 ip0->checksum = ip_csum_fold (sum0);
3606 if (PREDICT_FALSE(new_port0 != udp0->dst_port))
3608 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
3610 old_port0 = tcp0->src_port;
3611 tcp0->src_port = new_port0;
3613 sum0 = tcp0->checksum;
3614 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
3616 dst_address /* changed member */);
3617 sum0 = ip_csum_update (sum0, old_port0, new_port0,
3618 ip4_header_t /* cheat */,
3619 length /* changed member */);
3620 tcp0->checksum = ip_csum_fold(sum0);
3624 old_port0 = udp0->src_port;
3625 udp0->src_port = new_port0;
3631 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
3633 sum0 = tcp0->checksum;
3634 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
3636 dst_address /* changed member */);
3637 tcp0->checksum = ip_csum_fold(sum0);
3642 snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
3645 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
3646 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
3648 snat_in2out_trace_t *t =
3649 vlib_add_trace (vm, node, b0, sizeof (*t));
3650 t->sw_if_index = sw_if_index0;
3651 t->next_index = next0;
3654 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
3656 /* verify speculative enqueue, maybe switch current next frame */
3657 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3658 to_next, n_left_to_next,
3662 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3665 vlib_node_increment_counter (vm, stats_node_index,
3666 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
3668 return frame->n_vectors;
3672 VLIB_REGISTER_NODE (snat_in2out_fast_node) = {
3673 .function = snat_in2out_fast_static_map_fn,
3674 .name = "nat44-in2out-fast",
3675 .vector_size = sizeof (u32),
3676 .format_trace = format_snat_in2out_fast_trace,
3677 .type = VLIB_NODE_TYPE_INTERNAL,
3679 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
3680 .error_strings = snat_in2out_error_strings,
3682 .runtime_data_bytes = sizeof (snat_runtime_t),
3684 .n_next_nodes = SNAT_IN2OUT_N_NEXT,
3686 /* edit / add dispositions here */
3688 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
3689 [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
3690 [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
3691 [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3695 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_fast_node, snat_in2out_fast_static_map_fn);