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>
24 #include <snat/snat.h>
25 #include <snat/snat_ipfix_logging.h>
26 #include <snat/snat_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 ? "SNAT_IN2OUT_SLOW_PATH" : "SNAT_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, "SANT_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, "SNAT_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;
92 #define foreach_snat_in2out_error \
93 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
94 _(IN2OUT_PACKETS, "Good in2out packets processed") \
95 _(OUT_OF_PORTS, "Out of ports") \
96 _(BAD_OUTSIDE_FIB, "Outside VRF ID not found") \
97 _(BAD_ICMP_TYPE, "icmp type not echo-request") \
98 _(NO_TRANSLATION, "No translation")
101 #define _(sym,str) SNAT_IN2OUT_ERROR_##sym,
102 foreach_snat_in2out_error
105 } snat_in2out_error_t;
107 static char * snat_in2out_error_strings[] = {
108 #define _(sym,string) string,
109 foreach_snat_in2out_error
114 SNAT_IN2OUT_NEXT_LOOKUP,
115 SNAT_IN2OUT_NEXT_DROP,
116 SNAT_IN2OUT_NEXT_SLOW_PATH,
117 SNAT_IN2OUT_NEXT_ICMP_ERROR,
119 } snat_in2out_next_t;
122 * @brief Check if packet should be translated
124 * Packets aimed at outside interface and external addresss with active session
125 * should be translated.
127 * @param sm SNAT main
128 * @param rt SNAT runtime data
129 * @param sw_if_index0 index of the inside interface
130 * @param ip0 IPv4 header
131 * @param proto0 SNAT protocol
132 * @param rx_fib_index0 RX FIB index
134 * @returns 0 if packet should be translated otherwise 1
137 snat_not_translate (snat_main_t * sm, snat_runtime_t * rt, u32 sw_if_index0,
138 ip4_header_t * ip0, u32 proto0, u32 rx_fib_index0)
140 ip4_address_t * first_int_addr;
141 udp_header_t * udp0 = ip4_next_header (ip0);
142 snat_session_key_t key0, sm0;
143 clib_bihash_kv_8_8_t kv0, value0;
144 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
146 .fp_proto = FIB_PROTOCOL_IP4,
149 .ip4.as_u32 = ip0->dst_address.as_u32,
153 if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0))
156 ip4_interface_first_address (sm->ip4_main, sw_if_index0,
157 0 /* just want the address */);
158 rt->cached_sw_if_index = sw_if_index0;
160 rt->cached_ip4_address = first_int_addr->as_u32;
162 rt->cached_ip4_address = 0;
165 /* Don't NAT packet aimed at the intfc address */
166 if (PREDICT_FALSE(ip0->dst_address.as_u32 == rt->cached_ip4_address))
169 key0.addr = ip0->dst_address;
170 key0.port = udp0->dst_port;
171 key0.protocol = proto0;
172 key0.fib_index = sm->outside_fib_index;
173 kv0.key = key0.as_u64;
175 /* NAT packet aimed at external address if */
176 /* has active sessions */
177 if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
179 /* or is static mappings */
180 if (!snat_static_mapping_match(sm, key0, &sm0, 1))
186 fei = fib_table_lookup (rx_fib_index0, &pfx);
187 if (FIB_NODE_INDEX_INVALID != fei)
189 u32 sw_if_index = fib_entry_get_resolving_interface (fei);
190 if (sw_if_index == ~0)
192 fei = fib_table_lookup (sm->outside_fib_index, &pfx);
193 if (FIB_NODE_INDEX_INVALID != fei)
194 sw_if_index = fib_entry_get_resolving_interface (fei);
197 pool_foreach (i, sm->interfaces,
199 /* NAT packet aimed at outside interface */
200 if ((i->is_inside == 0) && (sw_if_index == i->sw_if_index))
208 static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
211 snat_session_key_t * key0,
212 snat_session_t ** sessionp,
213 vlib_node_runtime_t * node,
218 snat_user_key_t user_key;
220 clib_bihash_kv_8_8_t kv0, value0;
221 u32 oldest_per_user_translation_list_index;
222 dlist_elt_t * oldest_per_user_translation_list_elt;
223 dlist_elt_t * per_user_translation_list_elt;
224 dlist_elt_t * per_user_list_head_elt;
226 snat_session_key_t key1;
227 u32 address_index = ~0;
228 u32 outside_fib_index;
230 snat_worker_key_t worker_by_out_key;
232 p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id);
235 b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_OUTSIDE_FIB];
236 return SNAT_IN2OUT_NEXT_DROP;
238 outside_fib_index = p[0];
240 key1.protocol = key0->protocol;
241 user_key.addr = ip0->src_address;
242 user_key.fib_index = rx_fib_index0;
243 kv0.key = user_key.as_u64;
245 /* Ever heard of the "user" = src ip4 address before? */
246 if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0))
248 /* no, make a new one */
249 pool_get (sm->per_thread_data[cpu_index].users, u);
250 memset (u, 0, sizeof (*u));
251 u->addr = ip0->src_address;
252 u->fib_index = rx_fib_index0;
254 pool_get (sm->per_thread_data[cpu_index].list_pool, per_user_list_head_elt);
256 u->sessions_per_user_list_head_index = per_user_list_head_elt -
257 sm->per_thread_data[cpu_index].list_pool;
259 clib_dlist_init (sm->per_thread_data[cpu_index].list_pool,
260 u->sessions_per_user_list_head_index);
262 kv0.value = u - sm->per_thread_data[cpu_index].users;
265 clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */);
269 u = pool_elt_at_index (sm->per_thread_data[cpu_index].users,
273 /* Over quota? Recycle the least recently used dynamic translation */
274 if (u->nsessions >= sm->max_translations_per_user)
276 /* Remove the oldest dynamic translation */
278 oldest_per_user_translation_list_index =
279 clib_dlist_remove_head (sm->per_thread_data[cpu_index].list_pool,
280 u->sessions_per_user_list_head_index);
282 ASSERT (oldest_per_user_translation_list_index != ~0);
284 /* add it back to the end of the LRU list */
285 clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
286 u->sessions_per_user_list_head_index,
287 oldest_per_user_translation_list_index);
288 /* Get the list element */
289 oldest_per_user_translation_list_elt =
290 pool_elt_at_index (sm->per_thread_data[cpu_index].list_pool,
291 oldest_per_user_translation_list_index);
293 /* Get the session index from the list element */
294 session_index = oldest_per_user_translation_list_elt->value;
296 /* Get the session */
297 s = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
299 } while (snat_is_session_static (s));
301 /* Remove in2out, out2in keys */
302 kv0.key = s->in2out.as_u64;
303 if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 0 /* is_add */))
304 clib_warning ("in2out key delete failed");
305 kv0.key = s->out2in.as_u64;
306 if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 0 /* is_add */))
307 clib_warning ("out2in key delete failed");
310 snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
311 s->out2in.addr.as_u32,
315 s->in2out.fib_index);
317 snat_free_outside_address_and_port
318 (sm, &s->out2in, s->outside_address_index);
319 s->outside_address_index = ~0;
321 if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1,
326 b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
327 return SNAT_IN2OUT_NEXT_DROP;
329 s->outside_address_index = address_index;
333 u8 static_mapping = 1;
335 /* First try to match static mapping by local address and port */
336 if (snat_static_mapping_match (sm, *key0, &key1, 0))
339 /* Try to create dynamic translation */
340 if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1,
343 b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
344 return SNAT_IN2OUT_NEXT_DROP;
348 /* Create a new session */
349 pool_get (sm->per_thread_data[cpu_index].sessions, s);
350 memset (s, 0, sizeof (*s));
352 s->outside_address_index = address_index;
356 u->nstaticsessions++;
357 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
364 /* Create list elts */
365 pool_get (sm->per_thread_data[cpu_index].list_pool,
366 per_user_translation_list_elt);
367 clib_dlist_init (sm->per_thread_data[cpu_index].list_pool,
368 per_user_translation_list_elt -
369 sm->per_thread_data[cpu_index].list_pool);
371 per_user_translation_list_elt->value =
372 s - sm->per_thread_data[cpu_index].sessions;
373 s->per_user_index = per_user_translation_list_elt -
374 sm->per_thread_data[cpu_index].list_pool;
375 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
377 clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
378 s->per_user_list_head_index,
379 per_user_translation_list_elt -
380 sm->per_thread_data[cpu_index].list_pool);
385 s->out2in.protocol = key0->protocol;
386 s->out2in.fib_index = outside_fib_index;
389 /* Add to translation hashes */
390 kv0.key = s->in2out.as_u64;
391 kv0.value = s - sm->per_thread_data[cpu_index].sessions;
392 if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */))
393 clib_warning ("in2out key add failed");
395 kv0.key = s->out2in.as_u64;
396 kv0.value = s - sm->per_thread_data[cpu_index].sessions;
398 if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */))
399 clib_warning ("out2in key add failed");
401 /* Add to translated packets worker lookup */
402 worker_by_out_key.addr = s->out2in.addr;
403 worker_by_out_key.port = s->out2in.port;
404 worker_by_out_key.fib_index = s->out2in.fib_index;
405 kv0.key = worker_by_out_key.as_u64;
406 kv0.value = cpu_index;
407 clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1);
410 snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
411 s->out2in.addr.as_u32,
415 s->in2out.fib_index);
420 u16 src_port, dst_port;
423 static inline u32 icmp_in2out_slow_path (snat_main_t *sm,
426 icmp46_header_t * icmp0,
429 vlib_node_runtime_t * node,
433 snat_session_t ** p_s0)
435 snat_session_key_t key0;
436 icmp_echo_header_t *echo0, *inner_echo0 = 0;
437 ip4_header_t *inner_ip0 = 0;
439 icmp46_header_t *inner_icmp0;
440 clib_bihash_kv_8_8_t kv0, value0;
441 snat_session_t * s0 = 0;
442 u32 new_addr0, old_addr0;
443 u16 old_id0, new_id0;
446 snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data;
447 u8 is_error_message = 0;
449 echo0 = (icmp_echo_header_t *)(icmp0+1);
451 key0.addr = ip0->src_address;
452 key0.fib_index = rx_fib_index0;
456 case ICMP4_destination_unreachable:
457 case ICMP4_time_exceeded:
458 case ICMP4_parameter_problem:
459 case ICMP4_source_quench:
461 case ICMP4_alternate_host_address:
462 is_error_message = 1;
465 if (!is_error_message)
467 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request))
469 b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
470 next0 = SNAT_IN2OUT_NEXT_DROP;
473 key0.protocol = SNAT_PROTOCOL_ICMP;
474 key0.port = echo0->identifier;
478 inner_ip0 = (ip4_header_t *)(echo0+1);
479 l4_header = ip4_next_header (inner_ip0);
480 key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
481 switch (key0.protocol)
483 case SNAT_PROTOCOL_ICMP:
484 inner_icmp0 = (icmp46_header_t*)l4_header;
485 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
486 key0.port = inner_echo0->identifier;
488 case SNAT_PROTOCOL_UDP:
489 case SNAT_PROTOCOL_TCP:
490 key0.port = ((tcp_udp_header_t*)l4_header)->dst_port;
493 b0->error = node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
494 next0 = SNAT_IN2OUT_NEXT_DROP;
499 kv0.key = key0.as_u64;
501 if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0))
503 if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index0, ip0,
504 IP_PROTOCOL_ICMP, rx_fib_index0)))
507 if (is_error_message)
509 next0 = SNAT_IN2OUT_NEXT_DROP;
513 next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
514 &s0, node, next0, cpu_index);
516 if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
520 s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
523 sum0 = ip_incremental_checksum (0, icmp0,
524 ntohs(ip0->length) - ip4_header_bytes (ip0));
525 checksum0 = ~ip_csum_fold (sum0);
526 if (PREDICT_FALSE(checksum0 != 0 && checksum0 != 0xffff))
528 next0 = SNAT_IN2OUT_NEXT_DROP;
532 old_addr0 = ip0->src_address.as_u32;
533 ip0->src_address = s0->out2in.addr;
534 new_addr0 = ip0->src_address.as_u32;
535 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
537 sum0 = ip0->checksum;
538 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
539 src_address /* changed member */);
540 ip0->checksum = ip_csum_fold (sum0);
542 if (!is_error_message)
544 old_id0 = echo0->identifier;
545 new_id0 = s0->out2in.port;
546 echo0->identifier = new_id0;
548 sum0 = icmp0->checksum;
549 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
551 icmp0->checksum = ip_csum_fold (sum0);
555 if (!ip4_header_checksum_is_valid (inner_ip0))
557 next0 = SNAT_IN2OUT_NEXT_DROP;
561 old_addr0 = inner_ip0->dst_address.as_u32;
562 inner_ip0->dst_address = s0->out2in.addr;
563 new_addr0 = inner_ip0->src_address.as_u32;
565 sum0 = icmp0->checksum;
566 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
567 dst_address /* changed member */);
568 icmp0->checksum = ip_csum_fold (sum0);
570 switch (key0.protocol)
572 case SNAT_PROTOCOL_ICMP:
573 old_id0 = inner_echo0->identifier;
574 new_id0 = s0->out2in.port;
575 inner_echo0->identifier = new_id0;
577 sum0 = icmp0->checksum;
578 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
580 icmp0->checksum = ip_csum_fold (sum0);
582 case SNAT_PROTOCOL_UDP:
583 case SNAT_PROTOCOL_TCP:
584 old_id0 = ((tcp_udp_header_t*)l4_header)->dst_port;
585 new_id0 = s0->out2in.port;
586 ((tcp_udp_header_t*)l4_header)->dst_port = new_id0;
588 sum0 = icmp0->checksum;
589 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
591 icmp0->checksum = ip_csum_fold (sum0);
599 s0->last_heard = now;
601 s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
602 /* Per-user LRU list maintenance for dynamic translations */
603 if (!snat_is_session_static (s0))
605 clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
607 clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
608 s0->per_user_list_head_index,
620 * Hairpinning allows two endpoints on the internal side of the NAT to
621 * communicate even if they only use each other's external IP addresses
624 * @param sm SNAT main.
625 * @param b0 Vlib buffer.
626 * @param ip0 IP header.
627 * @param udp0 UDP header.
628 * @param tcp0 TCP header.
629 * @param proto0 SNAT protocol.
632 snat_hairpinning (snat_main_t *sm,
639 snat_session_key_t key0, sm0;
640 snat_worker_key_t k0;
642 clib_bihash_kv_8_8_t kv0, value0;
644 u32 new_dst_addr0 = 0, old_dst_addr0, ti = 0, si;
645 u16 new_dst_port0, old_dst_port0;
647 key0.addr = ip0->dst_address;
648 key0.port = udp0->dst_port;
649 key0.protocol = proto0;
650 key0.fib_index = sm->outside_fib_index;
651 kv0.key = key0.as_u64;
653 /* Check if destination is in active sessions */
654 if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
656 /* or static mappings */
657 if (!snat_static_mapping_match(sm, key0, &sm0, 1))
659 new_dst_addr0 = sm0.addr.as_u32;
660 new_dst_port0 = sm0.port;
661 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
667 if (sm->num_workers > 1)
669 k0.addr = ip0->dst_address;
670 k0.port = udp0->dst_port;
671 k0.fib_index = sm->outside_fib_index;
673 if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
679 ti = sm->num_workers;
681 s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si);
682 new_dst_addr0 = s0->in2out.addr.as_u32;
683 new_dst_port0 = s0->in2out.port;
684 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
687 /* Destination is behind the same NAT, use internal address and port */
690 old_dst_addr0 = ip0->dst_address.as_u32;
691 ip0->dst_address.as_u32 = new_dst_addr0;
692 sum0 = ip0->checksum;
693 sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
694 ip4_header_t, dst_address);
695 ip0->checksum = ip_csum_fold (sum0);
697 old_dst_port0 = tcp0->dst;
698 if (PREDICT_TRUE(new_dst_port0 != old_dst_port0))
700 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
702 tcp0->dst = new_dst_port0;
703 sum0 = tcp0->checksum;
704 sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
705 ip4_header_t, dst_address);
706 sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0,
707 ip4_header_t /* cheat */, length);
708 tcp0->checksum = ip_csum_fold(sum0);
712 udp0->dst_port = new_dst_port0;
720 snat_in2out_node_fn_inline (vlib_main_t * vm,
721 vlib_node_runtime_t * node,
722 vlib_frame_t * frame, int is_slow_path)
724 u32 n_left_from, * from, * to_next;
725 snat_in2out_next_t next_index;
726 u32 pkts_processed = 0;
727 snat_main_t * sm = &snat_main;
728 snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data;
729 f64 now = vlib_time_now (vm);
730 u32 stats_node_index;
731 u32 cpu_index = os_get_cpu_number ();
733 stats_node_index = is_slow_path ? snat_in2out_slowpath_node.index :
734 snat_in2out_node.index;
736 from = vlib_frame_vector_args (frame);
737 n_left_from = frame->n_vectors;
738 next_index = node->cached_next_index;
740 while (n_left_from > 0)
744 vlib_get_next_frame (vm, node, next_index,
745 to_next, n_left_to_next);
747 while (n_left_from >= 4 && n_left_to_next >= 2)
750 vlib_buffer_t * b0, * b1;
752 u32 sw_if_index0, sw_if_index1;
753 ip4_header_t * ip0, * ip1;
754 ip_csum_t sum0, sum1;
755 u32 new_addr0, old_addr0, new_addr1, old_addr1;
756 u16 old_port0, new_port0, old_port1, new_port1;
757 udp_header_t * udp0, * udp1;
758 tcp_header_t * tcp0, * tcp1;
759 icmp46_header_t * icmp0, * icmp1;
760 snat_session_key_t key0, key1;
761 u32 rx_fib_index0, rx_fib_index1;
763 snat_session_t * s0 = 0, * s1 = 0;
764 clib_bihash_kv_8_8_t kv0, value0, kv1, value1;
766 /* Prefetch next iteration. */
768 vlib_buffer_t * p2, * p3;
770 p2 = vlib_get_buffer (vm, from[2]);
771 p3 = vlib_get_buffer (vm, from[3]);
773 vlib_prefetch_buffer_header (p2, LOAD);
774 vlib_prefetch_buffer_header (p3, LOAD);
776 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
777 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
780 /* speculatively enqueue b0 and b1 to the current next frame */
781 to_next[0] = bi0 = from[0];
782 to_next[1] = bi1 = from[1];
788 b0 = vlib_get_buffer (vm, bi0);
789 b1 = vlib_get_buffer (vm, bi1);
791 ip0 = vlib_buffer_get_current (b0);
792 udp0 = ip4_next_header (ip0);
793 tcp0 = (tcp_header_t *) udp0;
794 icmp0 = (icmp46_header_t *) udp0;
796 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
797 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
800 next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP;
802 proto0 = ip_proto_to_snat_proto (ip0->protocol);
804 if (PREDICT_FALSE(ip0->ttl == 1))
806 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
807 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
808 ICMP4_time_exceeded_ttl_exceeded_in_transit,
810 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
814 /* Next configured feature, probably ip4-lookup */
817 if (PREDICT_FALSE (proto0 == ~0))
820 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
822 next0 = icmp_in2out_slow_path
823 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
824 node, next0, now, cpu_index, &s0);
830 if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
832 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
837 key0.addr = ip0->src_address;
838 key0.port = udp0->src_port;
839 key0.protocol = proto0;
840 key0.fib_index = rx_fib_index0;
842 kv0.key = key0.as_u64;
844 if (PREDICT_FALSE (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0) != 0))
848 if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index0, ip0,
849 proto0, rx_fib_index0)))
852 next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
853 &s0, node, next0, cpu_index);
854 if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
859 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
864 s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
867 old_addr0 = ip0->src_address.as_u32;
868 ip0->src_address = s0->out2in.addr;
869 new_addr0 = ip0->src_address.as_u32;
870 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
872 sum0 = ip0->checksum;
873 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
875 src_address /* changed member */);
876 ip0->checksum = ip_csum_fold (sum0);
878 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
880 old_port0 = tcp0->src_port;
881 tcp0->src_port = s0->out2in.port;
882 new_port0 = tcp0->src_port;
884 sum0 = tcp0->checksum;
885 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
887 dst_address /* changed member */);
888 sum0 = ip_csum_update (sum0, old_port0, new_port0,
889 ip4_header_t /* cheat */,
890 length /* changed member */);
891 tcp0->checksum = ip_csum_fold(sum0);
895 old_port0 = udp0->src_port;
896 udp0->src_port = s0->out2in.port;
901 snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
904 s0->last_heard = now;
906 s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
907 /* Per-user LRU list maintenance for dynamic translation */
908 if (!snat_is_session_static (s0))
910 clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
912 clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
913 s0->per_user_list_head_index,
918 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
919 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
921 snat_in2out_trace_t *t =
922 vlib_add_trace (vm, node, b0, sizeof (*t));
923 t->is_slow_path = is_slow_path;
924 t->sw_if_index = sw_if_index0;
925 t->next_index = next0;
926 t->session_index = ~0;
928 t->session_index = s0 - sm->per_thread_data[cpu_index].sessions;
931 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
933 ip1 = vlib_buffer_get_current (b1);
934 udp1 = ip4_next_header (ip1);
935 tcp1 = (tcp_header_t *) udp1;
936 icmp1 = (icmp46_header_t *) udp1;
938 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
939 rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
942 proto1 = ip_proto_to_snat_proto (ip1->protocol);
944 if (PREDICT_FALSE(ip0->ttl == 1))
946 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
947 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
948 ICMP4_time_exceeded_ttl_exceeded_in_transit,
950 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
954 /* Next configured feature, probably ip4-lookup */
957 if (PREDICT_FALSE (proto1 == ~0))
960 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
962 next1 = icmp_in2out_slow_path
963 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
964 next1, now, cpu_index, &s1);
970 if (PREDICT_FALSE (proto1 == ~0 || proto1 == SNAT_PROTOCOL_ICMP))
972 next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
977 key1.addr = ip1->src_address;
978 key1.port = udp1->src_port;
979 key1.protocol = proto1;
980 key1.fib_index = rx_fib_index1;
982 kv1.key = key1.as_u64;
984 if (PREDICT_FALSE(clib_bihash_search_8_8 (&sm->in2out, &kv1, &value1) != 0))
988 if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index1, ip1,
989 proto1, rx_fib_index1)))
992 next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1,
993 &s1, node, next1, cpu_index);
994 if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP))
999 next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1004 s1 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
1007 old_addr1 = ip1->src_address.as_u32;
1008 ip1->src_address = s1->out2in.addr;
1009 new_addr1 = ip1->src_address.as_u32;
1010 vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->out2in.fib_index;
1012 sum1 = ip1->checksum;
1013 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1015 src_address /* changed member */);
1016 ip1->checksum = ip_csum_fold (sum1);
1018 if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1020 old_port1 = tcp1->src_port;
1021 tcp1->src_port = s1->out2in.port;
1022 new_port1 = tcp1->src_port;
1024 sum1 = tcp1->checksum;
1025 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1027 dst_address /* changed member */);
1028 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1029 ip4_header_t /* cheat */,
1030 length /* changed member */);
1031 tcp1->checksum = ip_csum_fold(sum1);
1035 old_port1 = udp1->src_port;
1036 udp1->src_port = s1->out2in.port;
1041 snat_hairpinning (sm, b1, ip1, udp1, tcp1, proto1);
1044 s1->last_heard = now;
1046 s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
1047 /* Per-user LRU list maintenance for dynamic translation */
1048 if (!snat_is_session_static (s1))
1050 clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
1051 s1->per_user_index);
1052 clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
1053 s1->per_user_list_head_index,
1054 s1->per_user_index);
1058 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1059 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1061 snat_in2out_trace_t *t =
1062 vlib_add_trace (vm, node, b1, sizeof (*t));
1063 t->sw_if_index = sw_if_index1;
1064 t->next_index = next1;
1065 t->session_index = ~0;
1067 t->session_index = s1 - sm->per_thread_data[cpu_index].sessions;
1070 pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP;
1072 /* verify speculative enqueues, maybe switch current next frame */
1073 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1074 to_next, n_left_to_next,
1075 bi0, bi1, next0, next1);
1078 while (n_left_from > 0 && n_left_to_next > 0)
1086 u32 new_addr0, old_addr0;
1087 u16 old_port0, new_port0;
1088 udp_header_t * udp0;
1089 tcp_header_t * tcp0;
1090 icmp46_header_t * icmp0;
1091 snat_session_key_t key0;
1094 snat_session_t * s0 = 0;
1095 clib_bihash_kv_8_8_t kv0, value0;
1097 /* speculatively enqueue b0 to the current next frame */
1103 n_left_to_next -= 1;
1105 b0 = vlib_get_buffer (vm, bi0);
1106 next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1108 ip0 = vlib_buffer_get_current (b0);
1109 udp0 = ip4_next_header (ip0);
1110 tcp0 = (tcp_header_t *) udp0;
1111 icmp0 = (icmp46_header_t *) udp0;
1113 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1114 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1117 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1119 if (PREDICT_FALSE(ip0->ttl == 1))
1121 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1122 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1123 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1125 next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
1129 /* Next configured feature, probably ip4-lookup */
1132 if (PREDICT_FALSE (proto0 == ~0))
1135 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1137 next0 = icmp_in2out_slow_path
1138 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1139 next0, now, cpu_index, &s0);
1145 if (PREDICT_FALSE (proto0 == ~0 || proto0 == SNAT_PROTOCOL_ICMP))
1147 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1152 key0.addr = ip0->src_address;
1153 key0.port = udp0->src_port;
1154 key0.protocol = proto0;
1155 key0.fib_index = rx_fib_index0;
1157 kv0.key = key0.as_u64;
1159 if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0))
1163 if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index0, ip0,
1164 proto0, rx_fib_index0)))
1167 next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0,
1168 &s0, node, next0, cpu_index);
1170 if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
1175 next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
1180 s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions,
1183 old_addr0 = ip0->src_address.as_u32;
1184 ip0->src_address = s0->out2in.addr;
1185 new_addr0 = ip0->src_address.as_u32;
1186 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->out2in.fib_index;
1188 sum0 = ip0->checksum;
1189 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1191 src_address /* changed member */);
1192 ip0->checksum = ip_csum_fold (sum0);
1194 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1196 old_port0 = tcp0->src_port;
1197 tcp0->src_port = s0->out2in.port;
1198 new_port0 = tcp0->src_port;
1200 sum0 = tcp0->checksum;
1201 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1203 dst_address /* changed member */);
1204 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1205 ip4_header_t /* cheat */,
1206 length /* changed member */);
1207 tcp0->checksum = ip_csum_fold(sum0);
1211 old_port0 = udp0->src_port;
1212 udp0->src_port = s0->out2in.port;
1217 snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
1220 s0->last_heard = now;
1222 s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1223 /* Per-user LRU list maintenance for dynamic translation */
1224 if (!snat_is_session_static (s0))
1226 clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool,
1227 s0->per_user_index);
1228 clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool,
1229 s0->per_user_list_head_index,
1230 s0->per_user_index);
1234 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1235 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1237 snat_in2out_trace_t *t =
1238 vlib_add_trace (vm, node, b0, sizeof (*t));
1239 t->is_slow_path = is_slow_path;
1240 t->sw_if_index = sw_if_index0;
1241 t->next_index = next0;
1242 t->session_index = ~0;
1244 t->session_index = s0 - sm->per_thread_data[cpu_index].sessions;
1247 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1249 /* verify speculative enqueue, maybe switch current next frame */
1250 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1251 to_next, n_left_to_next,
1255 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1258 vlib_node_increment_counter (vm, stats_node_index,
1259 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
1261 return frame->n_vectors;
1265 snat_in2out_fast_path_fn (vlib_main_t * vm,
1266 vlib_node_runtime_t * node,
1267 vlib_frame_t * frame)
1269 return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */);
1272 VLIB_REGISTER_NODE (snat_in2out_node) = {
1273 .function = snat_in2out_fast_path_fn,
1274 .name = "snat-in2out",
1275 .vector_size = sizeof (u32),
1276 .format_trace = format_snat_in2out_trace,
1277 .type = VLIB_NODE_TYPE_INTERNAL,
1279 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1280 .error_strings = snat_in2out_error_strings,
1282 .runtime_data_bytes = sizeof (snat_runtime_t),
1284 .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1286 /* edit / add dispositions here */
1288 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1289 [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1290 [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath",
1291 [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1295 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_node, snat_in2out_fast_path_fn);
1298 snat_in2out_slow_path_fn (vlib_main_t * vm,
1299 vlib_node_runtime_t * node,
1300 vlib_frame_t * frame)
1302 return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */);
1305 VLIB_REGISTER_NODE (snat_in2out_slowpath_node) = {
1306 .function = snat_in2out_slow_path_fn,
1307 .name = "snat-in2out-slowpath",
1308 .vector_size = sizeof (u32),
1309 .format_trace = format_snat_in2out_trace,
1310 .type = VLIB_NODE_TYPE_INTERNAL,
1312 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1313 .error_strings = snat_in2out_error_strings,
1315 .runtime_data_bytes = sizeof (snat_runtime_t),
1317 .n_next_nodes = SNAT_IN2OUT_N_NEXT,
1319 /* edit / add dispositions here */
1321 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1322 [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1323 [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath",
1324 [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1328 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_slowpath_node, snat_in2out_slow_path_fn);
1330 /**************************/
1331 /*** deterministic mode ***/
1332 /**************************/
1334 snat_det_in2out_node_fn (vlib_main_t * vm,
1335 vlib_node_runtime_t * node,
1336 vlib_frame_t * frame)
1338 u32 n_left_from, * from, * to_next;
1339 snat_in2out_next_t next_index;
1340 u32 pkts_processed = 0;
1341 snat_main_t * sm = &snat_main;
1342 u32 now = (u32) vlib_time_now (vm);
1344 from = vlib_frame_vector_args (frame);
1345 n_left_from = frame->n_vectors;
1346 next_index = node->cached_next_index;
1348 while (n_left_from > 0)
1352 vlib_get_next_frame (vm, node, next_index,
1353 to_next, n_left_to_next);
1355 while (n_left_from >= 4 && n_left_to_next >= 2)
1358 vlib_buffer_t * b0, * b1;
1360 u32 sw_if_index0, sw_if_index1;
1361 ip4_header_t * ip0, * ip1;
1362 ip_csum_t sum0, sum1;
1363 ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
1364 u16 old_port0, new_port0, lo_port0, i0;
1365 u16 old_port1, new_port1, lo_port1, i1;
1366 udp_header_t * udp0, * udp1;
1367 tcp_header_t * tcp0, * tcp1;
1369 snat_det_out_key_t key0, key1;
1370 snat_det_map_t * dm0, * dm1;
1371 snat_det_session_t * ses0 = 0, * ses1 = 0;
1373 /* Prefetch next iteration. */
1375 vlib_buffer_t * p2, * p3;
1377 p2 = vlib_get_buffer (vm, from[2]);
1378 p3 = vlib_get_buffer (vm, from[3]);
1380 vlib_prefetch_buffer_header (p2, LOAD);
1381 vlib_prefetch_buffer_header (p3, LOAD);
1383 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
1384 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
1387 /* speculatively enqueue b0 and b1 to the current next frame */
1388 to_next[0] = bi0 = from[0];
1389 to_next[1] = bi1 = from[1];
1393 n_left_to_next -= 2;
1395 b0 = vlib_get_buffer (vm, bi0);
1396 b1 = vlib_get_buffer (vm, bi1);
1398 next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1399 next1 = SNAT_IN2OUT_NEXT_LOOKUP;
1401 ip0 = vlib_buffer_get_current (b0);
1402 udp0 = ip4_next_header (ip0);
1403 tcp0 = (tcp_header_t *) udp0;
1405 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1407 dm0 = snat_det_map_by_user(sm, &ip0->src_address);
1408 if (PREDICT_FALSE(!dm0))
1410 clib_warning("no match for internal host %U",
1411 format_ip4_address, &ip0->src_address);
1412 b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
1416 snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0);
1418 ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src);
1419 if (PREDICT_FALSE(!ses0))
1421 key0.ext_host_addr = ip0->dst_address;
1422 key0.ext_host_port = tcp0->dst;
1423 for (i0 = 0; i0 < dm0->ports_per_host; i0++)
1425 key0.out_port = clib_host_to_net_u16 (lo_port0 +
1426 ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host));
1428 if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64))
1431 ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0);
1434 if (PREDICT_FALSE(!ses0))
1436 next0 = SNAT_IN2OUT_NEXT_DROP;
1437 b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
1442 new_port0 = ses0->out.out_port;
1443 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1445 old_addr0.as_u32 = ip0->src_address.as_u32;
1446 ip0->src_address.as_u32 = new_addr0.as_u32;
1447 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1449 sum0 = ip0->checksum;
1450 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1452 src_address /* changed member */);
1453 ip0->checksum = ip_csum_fold (sum0);
1455 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1457 if (tcp0->flags & TCP_FLAG_SYN)
1458 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
1459 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
1460 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
1461 else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
1462 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
1463 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
1464 snat_det_ses_close(dm0, ses0);
1465 else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
1466 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
1467 else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN)
1468 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
1470 old_port0 = tcp0->src;
1471 tcp0->src = new_port0;
1473 sum0 = tcp0->checksum;
1474 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1476 dst_address /* changed member */);
1477 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1478 ip4_header_t /* cheat */,
1479 length /* changed member */);
1480 tcp0->checksum = ip_csum_fold(sum0);
1484 ses0->state = SNAT_SESSION_UDP_ACTIVE;
1485 old_port0 = udp0->src_port;
1486 udp0->src_port = new_port0;
1492 case SNAT_SESSION_UDP_ACTIVE:
1493 ses0->expire = now + SNAT_UDP_TIMEOUT;
1495 case SNAT_SESSION_TCP_SYN_SENT:
1496 case SNAT_SESSION_TCP_FIN_WAIT:
1497 case SNAT_SESSION_TCP_CLOSE_WAIT:
1498 case SNAT_SESSION_TCP_LAST_ACK:
1499 ses0->expire = now + SNAT_TCP_TRANSITORY_TIMEOUT;
1501 case SNAT_SESSION_TCP_ESTABLISHED:
1502 ses0->expire = now + SNAT_TCP_ESTABLISHED_TIMEOUT;
1507 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1508 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1510 snat_in2out_trace_t *t =
1511 vlib_add_trace (vm, node, b0, sizeof (*t));
1512 t->is_slow_path = 0;
1513 t->sw_if_index = sw_if_index0;
1514 t->next_index = next0;
1515 t->session_index = ~0;
1517 t->session_index = ses0 - dm0->sessions;
1520 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1522 ip1 = vlib_buffer_get_current (b1);
1523 udp1 = ip4_next_header (ip1);
1524 tcp1 = (tcp_header_t *) udp1;
1526 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1528 dm1 = snat_det_map_by_user(sm, &ip1->src_address);
1529 if (PREDICT_FALSE(!dm1))
1531 clib_warning("no match for internal host %U",
1532 format_ip4_address, &ip0->src_address);
1533 b1->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
1537 snat_det_forward(dm1, &ip1->src_address, &new_addr1, &lo_port1);
1540 ses1 = snat_det_find_ses_by_in(dm1, &ip1->src_address, tcp1->src);
1541 if (PREDICT_FALSE(!ses1))
1543 key1.ext_host_addr = ip1->dst_address;
1544 key1.ext_host_port = tcp1->dst;
1545 for (i1 = 0; i1 < dm1->ports_per_host; i1++)
1547 key1.out_port = clib_host_to_net_u16 (lo_port1 +
1548 ((i1 + clib_net_to_host_u16 (tcp1->src)) % dm1->ports_per_host));
1550 if (snat_det_get_ses_by_out (dm1, &ip1->src_address, key1.as_u64))
1553 ses1 = snat_det_ses_create(dm1, &ip1->src_address, tcp1->src, &key1);
1556 if (PREDICT_FALSE(!ses1))
1558 next1 = SNAT_IN2OUT_NEXT_DROP;
1559 b1->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
1564 new_port1 = ses1->out.out_port;
1565 proto1 = ip_proto_to_snat_proto (ip1->protocol);
1567 old_addr1.as_u32 = ip1->src_address.as_u32;
1568 ip1->src_address.as_u32 = new_addr1.as_u32;
1569 vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1571 sum1 = ip1->checksum;
1572 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
1574 src_address /* changed member */);
1575 ip1->checksum = ip_csum_fold (sum1);
1577 if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1579 if (tcp1->flags & TCP_FLAG_SYN)
1580 ses1->state = SNAT_SESSION_TCP_SYN_SENT;
1581 else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_SYN_SENT)
1582 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
1583 else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
1584 ses1->state = SNAT_SESSION_TCP_FIN_WAIT;
1585 else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_FIN_WAIT)
1586 snat_det_ses_close(dm1, ses1);
1587 else if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_CLOSE_WAIT)
1588 ses1->state = SNAT_SESSION_TCP_LAST_ACK;
1589 else if (tcp1->flags == 0 && ses1->state == SNAT_SESSION_UNKNOWN)
1590 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
1592 old_port1 = tcp1->src;
1593 tcp1->src = new_port1;
1595 sum1 = tcp1->checksum;
1596 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
1598 dst_address /* changed member */);
1599 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1600 ip4_header_t /* cheat */,
1601 length /* changed member */);
1602 tcp1->checksum = ip_csum_fold(sum1);
1606 ses1->state = SNAT_SESSION_UDP_ACTIVE;
1607 old_port1 = udp1->src_port;
1608 udp1->src_port = new_port1;
1614 case SNAT_SESSION_UDP_ACTIVE:
1615 ses1->expire = now + SNAT_UDP_TIMEOUT;
1617 case SNAT_SESSION_TCP_SYN_SENT:
1618 case SNAT_SESSION_TCP_FIN_WAIT:
1619 case SNAT_SESSION_TCP_CLOSE_WAIT:
1620 case SNAT_SESSION_TCP_LAST_ACK:
1621 ses1->expire = now + SNAT_TCP_TRANSITORY_TIMEOUT;
1623 case SNAT_SESSION_TCP_ESTABLISHED:
1624 ses1->expire = now + SNAT_TCP_ESTABLISHED_TIMEOUT;
1629 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1630 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1632 snat_in2out_trace_t *t =
1633 vlib_add_trace (vm, node, b1, sizeof (*t));
1634 t->is_slow_path = 0;
1635 t->sw_if_index = sw_if_index1;
1636 t->next_index = next1;
1637 t->session_index = ~0;
1639 t->session_index = ses1 - dm1->sessions;
1642 pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP;
1644 /* verify speculative enqueues, maybe switch current next frame */
1645 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1646 to_next, n_left_to_next,
1647 bi0, bi1, next0, next1);
1650 while (n_left_from > 0 && n_left_to_next > 0)
1658 ip4_address_t new_addr0, old_addr0;
1659 u16 old_port0, new_port0, lo_port0, i0;
1660 udp_header_t * udp0;
1661 tcp_header_t * tcp0;
1663 snat_det_out_key_t key0;
1664 snat_det_map_t * dm0;
1665 snat_det_session_t * ses0 = 0;
1667 /* speculatively enqueue b0 to the current next frame */
1673 n_left_to_next -= 1;
1675 b0 = vlib_get_buffer (vm, bi0);
1676 next0 = SNAT_IN2OUT_NEXT_LOOKUP;
1678 ip0 = vlib_buffer_get_current (b0);
1679 udp0 = ip4_next_header (ip0);
1680 tcp0 = (tcp_header_t *) udp0;
1682 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1684 dm0 = snat_det_map_by_user(sm, &ip0->src_address);
1685 if (PREDICT_FALSE(!dm0))
1687 clib_warning("no match for internal host %U",
1688 format_ip4_address, &ip0->src_address);
1689 b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
1693 snat_det_forward(dm0, &ip0->src_address, &new_addr0, &lo_port0);
1695 ses0 = snat_det_find_ses_by_in(dm0, &ip0->src_address, tcp0->src);
1696 if (PREDICT_FALSE(!ses0))
1698 key0.ext_host_addr = ip0->dst_address;
1699 key0.ext_host_port = tcp0->dst;
1700 for (i0 = 0; i0 < dm0->ports_per_host; i0++)
1702 key0.out_port = clib_host_to_net_u16 (lo_port0 +
1703 ((i0 + clib_net_to_host_u16 (tcp0->src)) % dm0->ports_per_host));
1705 if (snat_det_get_ses_by_out (dm0, &ip0->src_address, key0.as_u64))
1708 ses0 = snat_det_ses_create(dm0, &ip0->src_address, tcp0->src, &key0);
1711 if (PREDICT_FALSE(!ses0))
1713 next0 = SNAT_IN2OUT_NEXT_DROP;
1714 b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
1719 new_port0 = ses0->out.out_port;
1720 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1722 old_addr0.as_u32 = ip0->src_address.as_u32;
1723 ip0->src_address.as_u32 = new_addr0.as_u32;
1724 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
1726 sum0 = ip0->checksum;
1727 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1729 src_address /* changed member */);
1730 ip0->checksum = ip_csum_fold (sum0);
1732 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1734 if (tcp0->flags & TCP_FLAG_SYN)
1735 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
1736 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
1737 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
1738 else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
1739 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
1740 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
1741 snat_det_ses_close(dm0, ses0);
1742 else if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
1743 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
1744 else if (tcp0->flags == 0 && ses0->state == SNAT_SESSION_UNKNOWN)
1745 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
1747 old_port0 = tcp0->src;
1748 tcp0->src = new_port0;
1750 sum0 = tcp0->checksum;
1751 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1753 dst_address /* changed member */);
1754 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1755 ip4_header_t /* cheat */,
1756 length /* changed member */);
1757 tcp0->checksum = ip_csum_fold(sum0);
1761 ses0->state = SNAT_SESSION_UDP_ACTIVE;
1762 old_port0 = udp0->src_port;
1763 udp0->src_port = new_port0;
1769 case SNAT_SESSION_UDP_ACTIVE:
1770 ses0->expire = now + SNAT_UDP_TIMEOUT;
1772 case SNAT_SESSION_TCP_SYN_SENT:
1773 case SNAT_SESSION_TCP_FIN_WAIT:
1774 case SNAT_SESSION_TCP_CLOSE_WAIT:
1775 case SNAT_SESSION_TCP_LAST_ACK:
1776 ses0->expire = now + SNAT_TCP_TRANSITORY_TIMEOUT;
1778 case SNAT_SESSION_TCP_ESTABLISHED:
1779 ses0->expire = now + SNAT_TCP_ESTABLISHED_TIMEOUT;
1784 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1785 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1787 snat_in2out_trace_t *t =
1788 vlib_add_trace (vm, node, b0, sizeof (*t));
1789 t->is_slow_path = 0;
1790 t->sw_if_index = sw_if_index0;
1791 t->next_index = next0;
1792 t->session_index = ~0;
1794 t->session_index = ses0 - dm0->sessions;
1797 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
1799 /* verify speculative enqueue, maybe switch current next frame */
1800 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1801 to_next, n_left_to_next,
1805 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1808 vlib_node_increment_counter (vm, snat_det_in2out_node.index,
1809 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
1811 return frame->n_vectors;
1814 VLIB_REGISTER_NODE (snat_det_in2out_node) = {
1815 .function = snat_det_in2out_node_fn,
1816 .name = "snat-det-in2out",
1817 .vector_size = sizeof (u32),
1818 .format_trace = format_snat_in2out_trace,
1819 .type = VLIB_NODE_TYPE_INTERNAL,
1821 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
1822 .error_strings = snat_in2out_error_strings,
1824 .runtime_data_bytes = sizeof (snat_runtime_t),
1828 /* edit / add dispositions here */
1830 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
1831 [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1835 VLIB_NODE_FUNCTION_MULTIARCH (snat_det_in2out_node, snat_det_in2out_node_fn);
1837 /**********************/
1838 /*** worker handoff ***/
1839 /**********************/
1841 snat_in2out_worker_handoff_fn (vlib_main_t * vm,
1842 vlib_node_runtime_t * node,
1843 vlib_frame_t * frame)
1845 snat_main_t *sm = &snat_main;
1846 vlib_thread_main_t *tm = vlib_get_thread_main ();
1847 u32 n_left_from, *from, *to_next = 0;
1848 static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
1849 static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
1851 vlib_frame_queue_elt_t *hf = 0;
1852 vlib_frame_t *f = 0;
1854 u32 n_left_to_next_worker = 0, *to_next_worker = 0;
1855 u32 next_worker_index = 0;
1856 u32 current_worker_index = ~0;
1857 u32 cpu_index = os_get_cpu_number ();
1859 ASSERT (vec_len (sm->workers));
1861 if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
1863 vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
1865 vec_validate_init_empty (congested_handoff_queue_by_worker_index,
1866 sm->first_worker_index + sm->num_workers - 1,
1867 (vlib_frame_queue_t *) (~0));
1870 from = vlib_frame_vector_args (frame);
1871 n_left_from = frame->n_vectors;
1873 while (n_left_from > 0)
1886 b0 = vlib_get_buffer (vm, bi0);
1888 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1889 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
1891 ip0 = vlib_buffer_get_current (b0);
1893 next_worker_index = sm->worker_in2out_cb(ip0, rx_fib_index0);
1895 if (PREDICT_FALSE (next_worker_index != cpu_index))
1899 if (next_worker_index != current_worker_index)
1902 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
1904 hf = vlib_get_worker_handoff_queue_elt (sm->fq_in2out_index,
1906 handoff_queue_elt_by_worker_index);
1908 n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
1909 to_next_worker = &hf->buffer_index[hf->n_vectors];
1910 current_worker_index = next_worker_index;
1913 /* enqueue to correct worker thread */
1914 to_next_worker[0] = bi0;
1916 n_left_to_next_worker--;
1918 if (n_left_to_next_worker == 0)
1920 hf->n_vectors = VLIB_FRAME_SIZE;
1921 vlib_put_frame_queue_elt (hf);
1922 current_worker_index = ~0;
1923 handoff_queue_elt_by_worker_index[next_worker_index] = 0;
1930 /* if this is 1st frame */
1933 f = vlib_get_frame_to_node (vm, sm->in2out_node_index);
1934 to_next = vlib_frame_vector_args (f);
1942 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1943 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1945 snat_in2out_worker_handoff_trace_t *t =
1946 vlib_add_trace (vm, node, b0, sizeof (*t));
1947 t->next_worker_index = next_worker_index;
1948 t->do_handoff = do_handoff;
1953 vlib_put_frame_to_node (vm, sm->in2out_node_index, f);
1956 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
1958 /* Ship frames to the worker nodes */
1959 for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
1961 if (handoff_queue_elt_by_worker_index[i])
1963 hf = handoff_queue_elt_by_worker_index[i];
1965 * It works better to let the handoff node
1966 * rate-adapt, always ship the handoff queue element.
1968 if (1 || hf->n_vectors == hf->last_n_vectors)
1970 vlib_put_frame_queue_elt (hf);
1971 handoff_queue_elt_by_worker_index[i] = 0;
1974 hf->last_n_vectors = hf->n_vectors;
1976 congested_handoff_queue_by_worker_index[i] =
1977 (vlib_frame_queue_t *) (~0);
1980 current_worker_index = ~0;
1981 return frame->n_vectors;
1984 VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node) = {
1985 .function = snat_in2out_worker_handoff_fn,
1986 .name = "snat-in2out-worker-handoff",
1987 .vector_size = sizeof (u32),
1988 .format_trace = format_snat_in2out_worker_handoff_trace,
1989 .type = VLIB_NODE_TYPE_INTERNAL,
1998 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_worker_handoff_node, snat_in2out_worker_handoff_fn);
2000 /********************************/
2001 /*** static mapping only mode ***/
2002 /********************************/
2003 static inline u32 icmp_in2out_static_map (snat_main_t *sm,
2006 icmp46_header_t * icmp0,
2008 vlib_node_runtime_t * node,
2012 snat_session_key_t key0, sm0;
2013 icmp_echo_header_t *echo0;
2014 u32 new_addr0, old_addr0;
2015 u16 old_id0, new_id0;
2017 snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data;
2019 echo0 = (icmp_echo_header_t *)(icmp0+1);
2021 key0.addr = ip0->src_address;
2022 key0.port = echo0->identifier;
2023 key0.fib_index = rx_fib_index0;
2025 if (snat_static_mapping_match(sm, key0, &sm0, 0))
2027 if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index0, ip0,
2028 IP_PROTOCOL_ICMP, rx_fib_index0)))
2031 b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2032 return SNAT_IN2OUT_NEXT_DROP;
2035 new_addr0 = sm0.addr.as_u32;
2037 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2038 old_addr0 = ip0->src_address.as_u32;
2039 ip0->src_address.as_u32 = new_addr0;
2041 sum0 = ip0->checksum;
2042 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2044 src_address /* changed member */);
2045 ip0->checksum = ip_csum_fold (sum0);
2047 if (PREDICT_FALSE(new_id0 != echo0->identifier))
2049 old_id0 = echo0->identifier;
2050 echo0->identifier = new_id0;
2052 sum0 = icmp0->checksum;
2053 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
2055 icmp0->checksum = ip_csum_fold (sum0);
2062 snat_in2out_fast_static_map_fn (vlib_main_t * vm,
2063 vlib_node_runtime_t * node,
2064 vlib_frame_t * frame)
2066 u32 n_left_from, * from, * to_next;
2067 snat_in2out_next_t next_index;
2068 u32 pkts_processed = 0;
2069 snat_main_t * sm = &snat_main;
2070 snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data;
2071 u32 stats_node_index;
2073 stats_node_index = snat_in2out_fast_node.index;
2075 from = vlib_frame_vector_args (frame);
2076 n_left_from = frame->n_vectors;
2077 next_index = node->cached_next_index;
2079 while (n_left_from > 0)
2083 vlib_get_next_frame (vm, node, next_index,
2084 to_next, n_left_to_next);
2086 while (n_left_from > 0 && n_left_to_next > 0)
2094 u32 new_addr0, old_addr0;
2095 u16 old_port0, new_port0;
2096 udp_header_t * udp0;
2097 tcp_header_t * tcp0;
2098 icmp46_header_t * icmp0;
2099 snat_session_key_t key0, sm0;
2103 /* speculatively enqueue b0 to the current next frame */
2109 n_left_to_next -= 1;
2111 b0 = vlib_get_buffer (vm, bi0);
2112 next0 = SNAT_IN2OUT_NEXT_LOOKUP;
2114 ip0 = vlib_buffer_get_current (b0);
2115 udp0 = ip4_next_header (ip0);
2116 tcp0 = (tcp_header_t *) udp0;
2117 icmp0 = (icmp46_header_t *) udp0;
2119 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2120 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2122 proto0 = ip_proto_to_snat_proto (ip0->protocol);
2124 if (PREDICT_FALSE (proto0 == ~0))
2127 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2129 if (PREDICT_FALSE(snat_not_translate(sm, rt, sw_if_index0, ip0,
2130 proto0, rx_fib_index0)))
2133 next0 = icmp_in2out_static_map
2134 (sm, b0, ip0, icmp0, sw_if_index0, node, next0, rx_fib_index0);
2138 key0.addr = ip0->src_address;
2139 key0.port = udp0->src_port;
2140 key0.fib_index = rx_fib_index0;
2142 if (snat_static_mapping_match(sm, key0, &sm0, 0))
2144 b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
2145 next0= SNAT_IN2OUT_NEXT_DROP;
2149 new_addr0 = sm0.addr.as_u32;
2150 new_port0 = sm0.port;
2151 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2152 old_addr0 = ip0->src_address.as_u32;
2153 ip0->src_address.as_u32 = new_addr0;
2155 sum0 = ip0->checksum;
2156 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2158 src_address /* changed member */);
2159 ip0->checksum = ip_csum_fold (sum0);
2161 if (PREDICT_FALSE(new_port0 != udp0->dst_port))
2163 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2165 old_port0 = tcp0->src_port;
2166 tcp0->src_port = new_port0;
2168 sum0 = tcp0->checksum;
2169 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2171 dst_address /* changed member */);
2172 sum0 = ip_csum_update (sum0, old_port0, new_port0,
2173 ip4_header_t /* cheat */,
2174 length /* changed member */);
2175 tcp0->checksum = ip_csum_fold(sum0);
2179 old_port0 = udp0->src_port;
2180 udp0->src_port = new_port0;
2186 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2188 sum0 = tcp0->checksum;
2189 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2191 dst_address /* changed member */);
2192 tcp0->checksum = ip_csum_fold(sum0);
2197 snat_hairpinning (sm, b0, ip0, udp0, tcp0, proto0);
2200 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2201 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2203 snat_in2out_trace_t *t =
2204 vlib_add_trace (vm, node, b0, sizeof (*t));
2205 t->sw_if_index = sw_if_index0;
2206 t->next_index = next0;
2209 pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP;
2211 /* verify speculative enqueue, maybe switch current next frame */
2212 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2213 to_next, n_left_to_next,
2217 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2220 vlib_node_increment_counter (vm, stats_node_index,
2221 SNAT_IN2OUT_ERROR_IN2OUT_PACKETS,
2223 return frame->n_vectors;
2227 VLIB_REGISTER_NODE (snat_in2out_fast_node) = {
2228 .function = snat_in2out_fast_static_map_fn,
2229 .name = "snat-in2out-fast",
2230 .vector_size = sizeof (u32),
2231 .format_trace = format_snat_in2out_fast_trace,
2232 .type = VLIB_NODE_TYPE_INTERNAL,
2234 .n_errors = ARRAY_LEN(snat_in2out_error_strings),
2235 .error_strings = snat_in2out_error_strings,
2237 .runtime_data_bytes = sizeof (snat_runtime_t),
2239 .n_next_nodes = SNAT_IN2OUT_N_NEXT,
2241 /* edit / add dispositions here */
2243 [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
2244 [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
2245 [SNAT_IN2OUT_NEXT_SLOW_PATH] = "snat-in2out-slowpath",
2246 [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2250 VLIB_NODE_FUNCTION_MULTIARCH (snat_in2out_fast_node, snat_in2out_fast_static_map_fn);