2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vlib/vlib.h>
17 #include <vnet/vnet.h>
18 #include <vnet/pg/pg.h>
19 #include <vnet/handoff.h>
21 #include <vnet/ip/ip.h>
22 #include <vnet/udp/udp.h>
23 #include <vnet/ethernet/ethernet.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <snat/snat.h>
26 #include <snat/snat_ipfix_logging.h>
27 #include <snat/snat_det.h>
29 #include <vppinfra/hash.h>
30 #include <vppinfra/error.h>
31 #include <vppinfra/elog.h>
37 } snat_out2in_trace_t;
40 u32 next_worker_index;
42 } snat_out2in_worker_handoff_trace_t;
44 /* packet trace format function */
45 static u8 * format_snat_out2in_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_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
51 s = format (s, "SNAT_OUT2IN: sw_if_index %d, next index %d, session index %d",
52 t->sw_if_index, t->next_index, t->session_index);
56 static u8 * format_snat_out2in_fast_trace (u8 * s, va_list * args)
58 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
59 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
60 snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
62 s = format (s, "SNAT_OUT2IN_FAST: sw_if_index %d, next index %d",
63 t->sw_if_index, t->next_index);
67 static u8 * format_snat_out2in_worker_handoff_trace (u8 * s, va_list * args)
69 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
70 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
71 snat_out2in_worker_handoff_trace_t * t =
72 va_arg (*args, snat_out2in_worker_handoff_trace_t *);
75 m = t->do_handoff ? "next worker" : "same worker";
76 s = format (s, "SNAT_OUT2IN_WORKER_HANDOFF: %s %d", m, t->next_worker_index);
81 vlib_node_registration_t snat_out2in_node;
82 vlib_node_registration_t snat_out2in_fast_node;
83 vlib_node_registration_t snat_out2in_worker_handoff_node;
84 vlib_node_registration_t snat_det_out2in_node;
86 #define foreach_snat_out2in_error \
87 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
88 _(OUT2IN_PACKETS, "Good out2in packets processed") \
89 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
90 _(NO_TRANSLATION, "No translation")
93 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
94 foreach_snat_out2in_error
97 } snat_out2in_error_t;
99 static char * snat_out2in_error_strings[] = {
100 #define _(sym,string) string,
101 foreach_snat_out2in_error
106 SNAT_OUT2IN_NEXT_DROP,
107 SNAT_OUT2IN_NEXT_LOOKUP,
108 SNAT_OUT2IN_NEXT_ICMP_ERROR,
110 } snat_out2in_next_t;
113 * @brief Create session for static mapping.
115 * Create NAT session initiated by host from external network with static
118 * @param sm SNAT main.
119 * @param b0 Vlib buffer.
120 * @param in2out In2out SNAT session key.
121 * @param out2in Out2in SNAT session key.
122 * @param node Vlib node.
124 * @returns SNAT session if successfully created otherwise 0.
126 static inline snat_session_t *
127 create_session_for_static_mapping (snat_main_t *sm,
129 snat_session_key_t in2out,
130 snat_session_key_t out2in,
131 vlib_node_runtime_t * node,
135 snat_user_key_t user_key;
137 clib_bihash_kv_8_8_t kv0, value0;
138 dlist_elt_t * per_user_translation_list_elt;
139 dlist_elt_t * per_user_list_head_elt;
141 user_key.addr = in2out.addr;
142 user_key.fib_index = in2out.fib_index;
143 kv0.key = user_key.as_u64;
145 /* Ever heard of the "user" = inside ip4 address before? */
146 if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0))
148 /* no, make a new one */
149 pool_get (sm->per_thread_data[thread_index].users, u);
150 memset (u, 0, sizeof (*u));
151 u->addr = in2out.addr;
152 u->fib_index = in2out.fib_index;
154 pool_get (sm->per_thread_data[thread_index].list_pool,
155 per_user_list_head_elt);
157 u->sessions_per_user_list_head_index = per_user_list_head_elt -
158 sm->per_thread_data[thread_index].list_pool;
160 clib_dlist_init (sm->per_thread_data[thread_index].list_pool,
161 u->sessions_per_user_list_head_index);
163 kv0.value = u - sm->per_thread_data[thread_index].users;
166 clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */);
168 /* add non-traslated packets worker lookup */
169 kv0.value = thread_index;
170 clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1);
174 u = pool_elt_at_index (sm->per_thread_data[thread_index].users,
178 pool_get (sm->per_thread_data[thread_index].sessions, s);
179 memset (s, 0, sizeof (*s));
181 s->outside_address_index = ~0;
182 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
183 u->nstaticsessions++;
185 /* Create list elts */
186 pool_get (sm->per_thread_data[thread_index].list_pool,
187 per_user_translation_list_elt);
188 clib_dlist_init (sm->per_thread_data[thread_index].list_pool,
189 per_user_translation_list_elt -
190 sm->per_thread_data[thread_index].list_pool);
192 per_user_translation_list_elt->value =
193 s - sm->per_thread_data[thread_index].sessions;
195 per_user_translation_list_elt - sm->per_thread_data[thread_index].list_pool;
196 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
198 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
199 s->per_user_list_head_index,
200 per_user_translation_list_elt -
201 sm->per_thread_data[thread_index].list_pool);
205 s->in2out.protocol = out2in.protocol;
207 /* Add to translation hashes */
208 kv0.key = s->in2out.as_u64;
209 kv0.value = s - sm->per_thread_data[thread_index].sessions;
210 if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */))
211 clib_warning ("in2out key add failed");
213 kv0.key = s->out2in.as_u64;
214 kv0.value = s - sm->per_thread_data[thread_index].sessions;
216 if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */))
217 clib_warning ("out2in key add failed");
220 snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
221 s->out2in.addr.as_u32,
225 s->in2out.fib_index);
230 snat_out2in_error_t icmp_get_key(ip4_header_t *ip0,
231 snat_session_key_t *p_key0)
233 icmp46_header_t *icmp0;
234 snat_session_key_t key0;
235 icmp_echo_header_t *echo0, *inner_echo0 = 0;
236 ip4_header_t *inner_ip0;
238 icmp46_header_t *inner_icmp0;
240 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
241 echo0 = (icmp_echo_header_t *)(icmp0+1);
243 if (!icmp_is_error_message (icmp0))
245 key0.protocol = SNAT_PROTOCOL_ICMP;
246 key0.addr = ip0->dst_address;
247 key0.port = echo0->identifier;
251 inner_ip0 = (ip4_header_t *)(echo0+1);
252 l4_header = ip4_next_header (inner_ip0);
253 key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
254 key0.addr = inner_ip0->src_address;
255 switch (key0.protocol)
257 case SNAT_PROTOCOL_ICMP:
258 inner_icmp0 = (icmp46_header_t*)l4_header;
259 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
260 key0.port = inner_echo0->identifier;
262 case SNAT_PROTOCOL_UDP:
263 case SNAT_PROTOCOL_TCP:
264 key0.port = ((tcp_udp_header_t*)l4_header)->src_port;
267 return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
271 return -1; /* success */
275 * Get address and port values to be used for packet SNAT translation
276 * and create session if needed
278 * @param[in,out] sm SNAT main
279 * @param[in,out] node SNAT node runtime
280 * @param[in] thread_index thread index
281 * @param[in,out] b0 buffer containing packet to be translated
282 * @param[out] p_proto protocol used for matching
283 * @param[out] p_value address and port after NAT translation
284 * @param[out] p_dont_translate if packet should not be translated
285 * @param d optional parameter
286 * @param e optional parameter
288 u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node,
289 u32 thread_index, vlib_buffer_t *b0, u8 *p_proto,
290 snat_session_key_t *p_value,
291 u8 *p_dont_translate, void *d, void *e)
294 icmp46_header_t *icmp0;
297 snat_session_key_t key0;
298 snat_session_key_t sm0;
299 snat_session_t *s0 = 0;
300 u8 dont_translate = 0;
301 clib_bihash_kv_8_8_t kv0, value0;
306 ip0 = vlib_buffer_get_current (b0);
307 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
308 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
309 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
313 err = icmp_get_key (ip0, &key0);
316 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
317 next0 = SNAT_OUT2IN_NEXT_DROP;
320 key0.fib_index = rx_fib_index0;
322 kv0.key = key0.as_u64;
324 if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
326 /* Try to match static mapping by external address and port,
327 destination address and port in packet */
328 if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only))
330 /* Don't NAT packet aimed at the intfc address */
331 if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
332 ip0->dst_address.as_u32)))
337 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
338 next0 = SNAT_OUT2IN_NEXT_DROP;
342 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
343 (icmp0->type != ICMP4_echo_request || !is_addr_only)))
345 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
346 next0 = SNAT_OUT2IN_NEXT_DROP;
350 /* Create session initiated by host from external network */
351 s0 = create_session_for_static_mapping(sm, b0, sm0, key0,
356 next0 = SNAT_OUT2IN_NEXT_DROP;
362 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
363 icmp0->type != ICMP4_echo_request &&
364 !icmp_is_error_message (icmp0)))
366 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
367 next0 = SNAT_OUT2IN_NEXT_DROP;
371 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
376 *p_proto = key0.protocol;
378 *p_value = s0->in2out;
379 *p_dont_translate = dont_translate;
381 *(snat_session_t**)d = s0;
386 * Get address and port values to be used for packet SNAT translation
388 * @param[in] sm SNAT main
389 * @param[in,out] node SNAT node runtime
390 * @param[in] thread_index thread index
391 * @param[in,out] b0 buffer containing packet to be translated
392 * @param[out] p_proto protocol used for matching
393 * @param[out] p_value address and port after NAT translation
394 * @param[out] p_dont_translate if packet should not be translated
395 * @param d optional parameter
396 * @param e optional parameter
398 u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node,
399 u32 thread_index, vlib_buffer_t *b0, u8 *p_proto,
400 snat_session_key_t *p_value,
401 u8 *p_dont_translate, void *d, void *e)
404 icmp46_header_t *icmp0;
407 snat_session_key_t key0;
408 snat_session_key_t sm0;
409 u8 dont_translate = 0;
414 ip0 = vlib_buffer_get_current (b0);
415 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
416 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
417 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
419 err = icmp_get_key (ip0, &key0);
422 b0->error = node->errors[err];
423 next0 = SNAT_OUT2IN_NEXT_DROP;
426 key0.fib_index = rx_fib_index0;
428 if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only))
430 /* Don't NAT packet aimed at the intfc address */
431 if (is_interface_addr(sm, node, sw_if_index0, ip0->dst_address.as_u32))
436 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
437 next0 = SNAT_OUT2IN_NEXT_DROP;
441 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
442 (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
443 !icmp_is_error_message (icmp0)))
445 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
446 next0 = SNAT_OUT2IN_NEXT_DROP;
453 *p_proto = key0.protocol;
454 *p_dont_translate = dont_translate;
458 static inline u32 icmp_out2in (snat_main_t *sm,
461 icmp46_header_t * icmp0,
464 vlib_node_runtime_t * node,
470 snat_session_key_t sm0;
472 icmp_echo_header_t *echo0, *inner_echo0 = 0;
473 ip4_header_t *inner_ip0 = 0;
475 icmp46_header_t *inner_icmp0;
477 u32 new_addr0, old_addr0;
478 u16 old_id0, new_id0;
483 echo0 = (icmp_echo_header_t *)(icmp0+1);
485 next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0,
486 &protocol, &sm0, &dont_translate, d, e);
489 if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
492 sum0 = ip_incremental_checksum (0, icmp0,
493 ntohs(ip0->length) - ip4_header_bytes (ip0));
494 checksum0 = ~ip_csum_fold (sum0);
495 if (checksum0 != 0 && checksum0 != 0xffff)
497 next0 = SNAT_OUT2IN_NEXT_DROP;
501 old_addr0 = ip0->dst_address.as_u32;
502 new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
503 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
505 sum0 = ip0->checksum;
506 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
507 dst_address /* changed member */);
508 ip0->checksum = ip_csum_fold (sum0);
510 if (!icmp_is_error_message (icmp0))
513 if (PREDICT_FALSE(new_id0 != echo0->identifier))
515 old_id0 = echo0->identifier;
517 echo0->identifier = new_id0;
519 sum0 = icmp0->checksum;
520 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
521 identifier /* changed member */);
522 icmp0->checksum = ip_csum_fold (sum0);
527 inner_ip0 = (ip4_header_t *)(echo0+1);
528 l4_header = ip4_next_header (inner_ip0);
530 if (!ip4_header_checksum_is_valid (inner_ip0))
532 next0 = SNAT_OUT2IN_NEXT_DROP;
536 old_addr0 = inner_ip0->src_address.as_u32;
537 inner_ip0->src_address = sm0.addr;
538 new_addr0 = inner_ip0->src_address.as_u32;
540 sum0 = icmp0->checksum;
541 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
542 src_address /* changed member */);
543 icmp0->checksum = ip_csum_fold (sum0);
547 case SNAT_PROTOCOL_ICMP:
548 inner_icmp0 = (icmp46_header_t*)l4_header;
549 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
551 old_id0 = inner_echo0->identifier;
553 inner_echo0->identifier = new_id0;
555 sum0 = icmp0->checksum;
556 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
558 icmp0->checksum = ip_csum_fold (sum0);
560 case SNAT_PROTOCOL_UDP:
561 case SNAT_PROTOCOL_TCP:
562 old_id0 = ((tcp_udp_header_t*)l4_header)->src_port;
564 ((tcp_udp_header_t*)l4_header)->src_port = new_id0;
566 sum0 = icmp0->checksum;
567 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
569 icmp0->checksum = ip_csum_fold (sum0);
581 static inline u32 icmp_out2in_slow_path (snat_main_t *sm,
584 icmp46_header_t * icmp0,
587 vlib_node_runtime_t * node,
590 snat_session_t ** p_s0)
592 next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
593 next0, thread_index, p_s0, 0);
594 snat_session_t * s0 = *p_s0;
595 if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0))
598 s0->last_heard = now;
600 s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
601 /* Per-user LRU list maintenance for dynamic translation */
602 if (!snat_is_session_static (s0))
604 clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
606 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
607 s0->per_user_list_head_index,
615 snat_out2in_unknown_proto (snat_main_t *sm,
620 clib_bihash_kv_8_8_t kv, value;
621 snat_static_mapping_t *m;
622 snat_session_key_t m_key;
623 u32 old_addr, new_addr;
626 m_key.addr = ip->dst_address;
629 m_key.fib_index = rx_fib_index;
630 kv.key = m_key.as_u64;
631 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
634 m = pool_elt_at_index (sm->static_mappings, value.value);
636 old_addr = ip->dst_address.as_u32;
637 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
639 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
640 ip->checksum = ip_csum_fold (sum);
642 vnet_buffer(b)->sw_if_index[VLIB_TX] = m->fib_index;
646 snat_out2in_node_fn (vlib_main_t * vm,
647 vlib_node_runtime_t * node,
648 vlib_frame_t * frame)
650 u32 n_left_from, * from, * to_next;
651 snat_out2in_next_t next_index;
652 u32 pkts_processed = 0;
653 snat_main_t * sm = &snat_main;
654 f64 now = vlib_time_now (vm);
655 u32 thread_index = vlib_get_thread_index ();
657 from = vlib_frame_vector_args (frame);
658 n_left_from = frame->n_vectors;
659 next_index = node->cached_next_index;
661 while (n_left_from > 0)
665 vlib_get_next_frame (vm, node, next_index,
666 to_next, n_left_to_next);
668 while (n_left_from >= 4 && n_left_to_next >= 2)
671 vlib_buffer_t * b0, * b1;
672 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
673 u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
674 u32 sw_if_index0, sw_if_index1;
675 ip4_header_t * ip0, *ip1;
676 ip_csum_t sum0, sum1;
677 u32 new_addr0, old_addr0;
678 u16 new_port0, old_port0;
679 u32 new_addr1, old_addr1;
680 u16 new_port1, old_port1;
681 udp_header_t * udp0, * udp1;
682 tcp_header_t * tcp0, * tcp1;
683 icmp46_header_t * icmp0, * icmp1;
684 snat_session_key_t key0, key1, sm0, sm1;
685 u32 rx_fib_index0, rx_fib_index1;
687 snat_session_t * s0 = 0, * s1 = 0;
688 clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
690 /* Prefetch next iteration. */
692 vlib_buffer_t * p2, * p3;
694 p2 = vlib_get_buffer (vm, from[2]);
695 p3 = vlib_get_buffer (vm, from[3]);
697 vlib_prefetch_buffer_header (p2, LOAD);
698 vlib_prefetch_buffer_header (p3, LOAD);
700 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
701 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
704 /* speculatively enqueue b0 and b1 to the current next frame */
705 to_next[0] = bi0 = from[0];
706 to_next[1] = bi1 = from[1];
712 b0 = vlib_get_buffer (vm, bi0);
713 b1 = vlib_get_buffer (vm, bi1);
715 ip0 = vlib_buffer_get_current (b0);
716 udp0 = ip4_next_header (ip0);
717 tcp0 = (tcp_header_t *) udp0;
718 icmp0 = (icmp46_header_t *) udp0;
720 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
721 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
724 if (PREDICT_FALSE(ip0->ttl == 1))
726 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
727 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
728 ICMP4_time_exceeded_ttl_exceeded_in_transit,
730 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
734 proto0 = ip_proto_to_snat_proto (ip0->protocol);
736 if (PREDICT_FALSE (proto0 == ~0))
738 snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0);
742 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
744 next0 = icmp_out2in_slow_path
745 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
746 next0, now, thread_index, &s0);
750 key0.addr = ip0->dst_address;
751 key0.port = udp0->dst_port;
752 key0.protocol = proto0;
753 key0.fib_index = rx_fib_index0;
755 kv0.key = key0.as_u64;
757 if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
759 /* Try to match static mapping by external address and port,
760 destination address and port in packet */
761 if (snat_static_mapping_match(sm, key0, &sm0, 1, 0))
763 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
765 * Send DHCP packets to the ipv4 stack, or we won't
766 * be able to use dhcp client on the outside interface
768 if (proto0 != SNAT_PROTOCOL_UDP
770 != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
771 next0 = SNAT_OUT2IN_NEXT_DROP;
775 /* Create session initiated by host from external network */
776 s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
780 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
781 next0 = SNAT_OUT2IN_NEXT_DROP;
786 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
789 old_addr0 = ip0->dst_address.as_u32;
790 ip0->dst_address = s0->in2out.addr;
791 new_addr0 = ip0->dst_address.as_u32;
792 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
794 sum0 = ip0->checksum;
795 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
797 dst_address /* changed member */);
798 ip0->checksum = ip_csum_fold (sum0);
800 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
802 old_port0 = tcp0->dst_port;
803 tcp0->dst_port = s0->in2out.port;
804 new_port0 = tcp0->dst_port;
806 sum0 = tcp0->checksum;
807 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
809 dst_address /* changed member */);
811 sum0 = ip_csum_update (sum0, old_port0, new_port0,
812 ip4_header_t /* cheat */,
813 length /* changed member */);
814 tcp0->checksum = ip_csum_fold(sum0);
818 old_port0 = udp0->dst_port;
819 udp0->dst_port = s0->in2out.port;
824 s0->last_heard = now;
826 s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
827 /* Per-user LRU list maintenance for dynamic translation */
828 if (!snat_is_session_static (s0))
830 clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
832 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
833 s0->per_user_list_head_index,
838 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
839 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
841 snat_out2in_trace_t *t =
842 vlib_add_trace (vm, node, b0, sizeof (*t));
843 t->sw_if_index = sw_if_index0;
844 t->next_index = next0;
845 t->session_index = ~0;
847 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
850 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
853 ip1 = vlib_buffer_get_current (b1);
854 udp1 = ip4_next_header (ip1);
855 tcp1 = (tcp_header_t *) udp1;
856 icmp1 = (icmp46_header_t *) udp1;
858 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
859 rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
862 if (PREDICT_FALSE(ip1->ttl == 1))
864 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
865 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
866 ICMP4_time_exceeded_ttl_exceeded_in_transit,
868 next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
872 proto1 = ip_proto_to_snat_proto (ip1->protocol);
874 if (PREDICT_FALSE (proto1 == ~0))
876 snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1);
880 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
882 next1 = icmp_out2in_slow_path
883 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
884 next1, now, thread_index, &s1);
888 key1.addr = ip1->dst_address;
889 key1.port = udp1->dst_port;
890 key1.protocol = proto1;
891 key1.fib_index = rx_fib_index1;
893 kv1.key = key1.as_u64;
895 if (clib_bihash_search_8_8 (&sm->out2in, &kv1, &value1))
897 /* Try to match static mapping by external address and port,
898 destination address and port in packet */
899 if (snat_static_mapping_match(sm, key1, &sm1, 1, 0))
901 b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
903 * Send DHCP packets to the ipv4 stack, or we won't
904 * be able to use dhcp client on the outside interface
906 if (proto1 != SNAT_PROTOCOL_UDP
908 != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
909 next1 = SNAT_OUT2IN_NEXT_DROP;
913 /* Create session initiated by host from external network */
914 s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node,
918 b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
919 next1 = SNAT_OUT2IN_NEXT_DROP;
924 s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
927 old_addr1 = ip1->dst_address.as_u32;
928 ip1->dst_address = s1->in2out.addr;
929 new_addr1 = ip1->dst_address.as_u32;
930 vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
932 sum1 = ip1->checksum;
933 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
935 dst_address /* changed member */);
936 ip1->checksum = ip_csum_fold (sum1);
938 if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
940 old_port1 = tcp1->dst_port;
941 tcp1->dst_port = s1->in2out.port;
942 new_port1 = tcp1->dst_port;
944 sum1 = tcp1->checksum;
945 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
947 dst_address /* changed member */);
949 sum1 = ip_csum_update (sum1, old_port1, new_port1,
950 ip4_header_t /* cheat */,
951 length /* changed member */);
952 tcp1->checksum = ip_csum_fold(sum1);
956 old_port1 = udp1->dst_port;
957 udp1->dst_port = s1->in2out.port;
962 s1->last_heard = now;
964 s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
965 /* Per-user LRU list maintenance for dynamic translation */
966 if (!snat_is_session_static (s1))
968 clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
970 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
971 s1->per_user_list_head_index,
976 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
977 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
979 snat_out2in_trace_t *t =
980 vlib_add_trace (vm, node, b1, sizeof (*t));
981 t->sw_if_index = sw_if_index1;
982 t->next_index = next1;
983 t->session_index = ~0;
985 t->session_index = s1 - sm->per_thread_data[thread_index].sessions;
988 pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
990 /* verify speculative enqueues, maybe switch current next frame */
991 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
992 to_next, n_left_to_next,
993 bi0, bi1, next0, next1);
996 while (n_left_from > 0 && n_left_to_next > 0)
1000 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1004 u32 new_addr0, old_addr0;
1005 u16 new_port0, old_port0;
1006 udp_header_t * udp0;
1007 tcp_header_t * tcp0;
1008 icmp46_header_t * icmp0;
1009 snat_session_key_t key0, sm0;
1012 snat_session_t * s0 = 0;
1013 clib_bihash_kv_8_8_t kv0, value0;
1015 /* speculatively enqueue b0 to the current next frame */
1021 n_left_to_next -= 1;
1023 b0 = vlib_get_buffer (vm, bi0);
1025 ip0 = vlib_buffer_get_current (b0);
1026 udp0 = ip4_next_header (ip0);
1027 tcp0 = (tcp_header_t *) udp0;
1028 icmp0 = (icmp46_header_t *) udp0;
1030 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1031 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1034 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1036 if (PREDICT_FALSE (proto0 == ~0))
1038 snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0);
1042 if (PREDICT_FALSE(ip0->ttl == 1))
1044 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1045 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1046 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1048 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1052 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1054 next0 = icmp_out2in_slow_path
1055 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1056 next0, now, thread_index, &s0);
1060 key0.addr = ip0->dst_address;
1061 key0.port = udp0->dst_port;
1062 key0.protocol = proto0;
1063 key0.fib_index = rx_fib_index0;
1065 kv0.key = key0.as_u64;
1067 if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
1069 /* Try to match static mapping by external address and port,
1070 destination address and port in packet */
1071 if (snat_static_mapping_match(sm, key0, &sm0, 1, 0))
1073 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1075 * Send DHCP packets to the ipv4 stack, or we won't
1076 * be able to use dhcp client on the outside interface
1078 if (proto0 != SNAT_PROTOCOL_UDP
1080 != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))
1082 next0 = SNAT_OUT2IN_NEXT_DROP;
1086 /* Create session initiated by host from external network */
1087 s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1091 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1092 next0 = SNAT_OUT2IN_NEXT_DROP;
1097 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1100 old_addr0 = ip0->dst_address.as_u32;
1101 ip0->dst_address = s0->in2out.addr;
1102 new_addr0 = ip0->dst_address.as_u32;
1103 vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1105 sum0 = ip0->checksum;
1106 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1108 dst_address /* changed member */);
1109 ip0->checksum = ip_csum_fold (sum0);
1111 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1113 old_port0 = tcp0->dst_port;
1114 tcp0->dst_port = s0->in2out.port;
1115 new_port0 = tcp0->dst_port;
1117 sum0 = tcp0->checksum;
1118 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1120 dst_address /* changed member */);
1122 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1123 ip4_header_t /* cheat */,
1124 length /* changed member */);
1125 tcp0->checksum = ip_csum_fold(sum0);
1129 old_port0 = udp0->dst_port;
1130 udp0->dst_port = s0->in2out.port;
1135 s0->last_heard = now;
1137 s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1138 /* Per-user LRU list maintenance for dynamic translation */
1139 if (!snat_is_session_static (s0))
1141 clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1142 s0->per_user_index);
1143 clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1144 s0->per_user_list_head_index,
1145 s0->per_user_index);
1149 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1150 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1152 snat_out2in_trace_t *t =
1153 vlib_add_trace (vm, node, b0, sizeof (*t));
1154 t->sw_if_index = sw_if_index0;
1155 t->next_index = next0;
1156 t->session_index = ~0;
1158 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1161 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1163 /* verify speculative enqueue, maybe switch current next frame */
1164 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1165 to_next, n_left_to_next,
1169 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1172 vlib_node_increment_counter (vm, snat_out2in_node.index,
1173 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1175 return frame->n_vectors;
1178 VLIB_REGISTER_NODE (snat_out2in_node) = {
1179 .function = snat_out2in_node_fn,
1180 .name = "snat-out2in",
1181 .vector_size = sizeof (u32),
1182 .format_trace = format_snat_out2in_trace,
1183 .type = VLIB_NODE_TYPE_INTERNAL,
1185 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1186 .error_strings = snat_out2in_error_strings,
1188 .runtime_data_bytes = sizeof (snat_runtime_t),
1190 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1192 /* edit / add dispositions here */
1194 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1195 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1196 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1199 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
1201 /**************************/
1202 /*** deterministic mode ***/
1203 /**************************/
1205 snat_det_out2in_node_fn (vlib_main_t * vm,
1206 vlib_node_runtime_t * node,
1207 vlib_frame_t * frame)
1209 u32 n_left_from, * from, * to_next;
1210 snat_out2in_next_t next_index;
1211 u32 pkts_processed = 0;
1212 snat_main_t * sm = &snat_main;
1213 u32 thread_index = vlib_get_thread_index ();
1215 from = vlib_frame_vector_args (frame);
1216 n_left_from = frame->n_vectors;
1217 next_index = node->cached_next_index;
1219 while (n_left_from > 0)
1223 vlib_get_next_frame (vm, node, next_index,
1224 to_next, n_left_to_next);
1226 while (n_left_from >= 4 && n_left_to_next >= 2)
1229 vlib_buffer_t * b0, * b1;
1230 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1231 u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
1232 u32 sw_if_index0, sw_if_index1;
1233 ip4_header_t * ip0, * ip1;
1234 ip_csum_t sum0, sum1;
1235 ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
1236 u16 new_port0, old_port0, old_port1, new_port1;
1237 udp_header_t * udp0, * udp1;
1238 tcp_header_t * tcp0, * tcp1;
1240 snat_det_out_key_t key0, key1;
1241 snat_det_map_t * dm0, * dm1;
1242 snat_det_session_t * ses0 = 0, * ses1 = 0;
1243 u32 rx_fib_index0, rx_fib_index1;
1244 icmp46_header_t * icmp0, * icmp1;
1246 /* Prefetch next iteration. */
1248 vlib_buffer_t * p2, * p3;
1250 p2 = vlib_get_buffer (vm, from[2]);
1251 p3 = vlib_get_buffer (vm, from[3]);
1253 vlib_prefetch_buffer_header (p2, LOAD);
1254 vlib_prefetch_buffer_header (p3, LOAD);
1256 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
1257 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
1260 /* speculatively enqueue b0 and b1 to the current next frame */
1261 to_next[0] = bi0 = from[0];
1262 to_next[1] = bi1 = from[1];
1266 n_left_to_next -= 2;
1268 b0 = vlib_get_buffer (vm, bi0);
1269 b1 = vlib_get_buffer (vm, bi1);
1271 ip0 = vlib_buffer_get_current (b0);
1272 udp0 = ip4_next_header (ip0);
1273 tcp0 = (tcp_header_t *) udp0;
1275 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1277 if (PREDICT_FALSE(ip0->ttl == 1))
1279 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1280 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1281 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1283 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1287 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1289 if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
1291 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
1292 icmp0 = (icmp46_header_t *) udp0;
1294 next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
1295 rx_fib_index0, node, next0, thread_index,
1300 key0.ext_host_addr = ip0->src_address;
1301 key0.ext_host_port = tcp0->src;
1302 key0.out_port = tcp0->dst;
1304 dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
1305 if (PREDICT_FALSE(!dm0))
1307 clib_warning("unknown dst address: %U",
1308 format_ip4_address, &ip0->dst_address);
1309 next0 = SNAT_OUT2IN_NEXT_DROP;
1310 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1314 snat_det_reverse(dm0, &ip0->dst_address,
1315 clib_net_to_host_u16(tcp0->dst), &new_addr0);
1317 ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
1318 if (PREDICT_FALSE(!ses0))
1320 clib_warning("no match src %U:%d dst %U:%d for user %U",
1321 format_ip4_address, &ip0->src_address,
1322 clib_net_to_host_u16 (tcp0->src),
1323 format_ip4_address, &ip0->dst_address,
1324 clib_net_to_host_u16 (tcp0->dst),
1325 format_ip4_address, &new_addr0);
1326 next0 = SNAT_OUT2IN_NEXT_DROP;
1327 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1330 new_port0 = ses0->in_port;
1332 old_addr0 = ip0->dst_address;
1333 ip0->dst_address = new_addr0;
1334 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
1336 sum0 = ip0->checksum;
1337 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1339 dst_address /* changed member */);
1340 ip0->checksum = ip_csum_fold (sum0);
1342 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1344 if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
1345 ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
1346 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
1347 snat_det_ses_close(dm0, ses0);
1349 old_port0 = tcp0->dst;
1350 tcp0->dst = new_port0;
1352 sum0 = tcp0->checksum;
1353 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1355 dst_address /* changed member */);
1357 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1358 ip4_header_t /* cheat */,
1359 length /* changed member */);
1360 tcp0->checksum = ip_csum_fold(sum0);
1364 old_port0 = udp0->dst_port;
1365 udp0->dst_port = new_port0;
1371 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1372 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1374 snat_out2in_trace_t *t =
1375 vlib_add_trace (vm, node, b0, sizeof (*t));
1376 t->sw_if_index = sw_if_index0;
1377 t->next_index = next0;
1378 t->session_index = ~0;
1380 t->session_index = ses0 - dm0->sessions;
1383 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1385 b1 = vlib_get_buffer (vm, bi1);
1387 ip1 = vlib_buffer_get_current (b1);
1388 udp1 = ip4_next_header (ip1);
1389 tcp1 = (tcp_header_t *) udp1;
1391 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1393 if (PREDICT_FALSE(ip1->ttl == 1))
1395 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1396 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1397 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1399 next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1403 proto1 = ip_proto_to_snat_proto (ip1->protocol);
1405 if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP))
1407 rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1);
1408 icmp1 = (icmp46_header_t *) udp1;
1410 next1 = icmp_out2in(sm, b1, ip1, icmp1, sw_if_index1,
1411 rx_fib_index1, node, next1, thread_index,
1416 key1.ext_host_addr = ip1->src_address;
1417 key1.ext_host_port = tcp1->src;
1418 key1.out_port = tcp1->dst;
1420 dm1 = snat_det_map_by_out(sm, &ip1->dst_address);
1421 if (PREDICT_FALSE(!dm1))
1423 clib_warning("unknown dst address: %U",
1424 format_ip4_address, &ip1->dst_address);
1425 next1 = SNAT_OUT2IN_NEXT_DROP;
1426 b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1430 snat_det_reverse(dm1, &ip1->dst_address,
1431 clib_net_to_host_u16(tcp1->dst), &new_addr1);
1433 ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64);
1434 if (PREDICT_FALSE(!ses1))
1436 clib_warning("no match src %U:%d dst %U:%d for user %U",
1437 format_ip4_address, &ip1->src_address,
1438 clib_net_to_host_u16 (tcp1->src),
1439 format_ip4_address, &ip1->dst_address,
1440 clib_net_to_host_u16 (tcp1->dst),
1441 format_ip4_address, &new_addr1);
1442 next1 = SNAT_OUT2IN_NEXT_DROP;
1443 b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1446 new_port1 = ses1->in_port;
1448 old_addr1 = ip1->dst_address;
1449 ip1->dst_address = new_addr1;
1450 vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
1452 sum1 = ip1->checksum;
1453 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
1455 dst_address /* changed member */);
1456 ip1->checksum = ip_csum_fold (sum1);
1458 if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1460 if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
1461 ses1->state = SNAT_SESSION_TCP_CLOSE_WAIT;
1462 else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_LAST_ACK)
1463 snat_det_ses_close(dm1, ses1);
1465 old_port1 = tcp1->dst;
1466 tcp1->dst = new_port1;
1468 sum1 = tcp1->checksum;
1469 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
1471 dst_address /* changed member */);
1473 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1474 ip4_header_t /* cheat */,
1475 length /* changed member */);
1476 tcp1->checksum = ip_csum_fold(sum1);
1480 old_port1 = udp1->dst_port;
1481 udp1->dst_port = new_port1;
1487 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1488 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1490 snat_out2in_trace_t *t =
1491 vlib_add_trace (vm, node, b1, sizeof (*t));
1492 t->sw_if_index = sw_if_index1;
1493 t->next_index = next1;
1494 t->session_index = ~0;
1496 t->session_index = ses1 - dm1->sessions;
1499 pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1501 /* verify speculative enqueues, maybe switch current next frame */
1502 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1503 to_next, n_left_to_next,
1504 bi0, bi1, next0, next1);
1507 while (n_left_from > 0 && n_left_to_next > 0)
1511 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1515 ip4_address_t new_addr0, old_addr0;
1516 u16 new_port0, old_port0;
1517 udp_header_t * udp0;
1518 tcp_header_t * tcp0;
1520 snat_det_out_key_t key0;
1521 snat_det_map_t * dm0;
1522 snat_det_session_t * ses0 = 0;
1524 icmp46_header_t * icmp0;
1526 /* speculatively enqueue b0 to the current next frame */
1532 n_left_to_next -= 1;
1534 b0 = vlib_get_buffer (vm, bi0);
1536 ip0 = vlib_buffer_get_current (b0);
1537 udp0 = ip4_next_header (ip0);
1538 tcp0 = (tcp_header_t *) udp0;
1540 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1542 if (PREDICT_FALSE(ip0->ttl == 1))
1544 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1545 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1546 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1548 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1552 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1554 if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
1556 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
1557 icmp0 = (icmp46_header_t *) udp0;
1559 next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
1560 rx_fib_index0, node, next0, thread_index,
1565 key0.ext_host_addr = ip0->src_address;
1566 key0.ext_host_port = tcp0->src;
1567 key0.out_port = tcp0->dst;
1569 dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
1570 if (PREDICT_FALSE(!dm0))
1572 clib_warning("unknown dst address: %U",
1573 format_ip4_address, &ip0->dst_address);
1574 next0 = SNAT_OUT2IN_NEXT_DROP;
1575 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1579 snat_det_reverse(dm0, &ip0->dst_address,
1580 clib_net_to_host_u16(tcp0->dst), &new_addr0);
1582 ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
1583 if (PREDICT_FALSE(!ses0))
1585 clib_warning("no match src %U:%d dst %U:%d for user %U",
1586 format_ip4_address, &ip0->src_address,
1587 clib_net_to_host_u16 (tcp0->src),
1588 format_ip4_address, &ip0->dst_address,
1589 clib_net_to_host_u16 (tcp0->dst),
1590 format_ip4_address, &new_addr0);
1591 next0 = SNAT_OUT2IN_NEXT_DROP;
1592 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1595 new_port0 = ses0->in_port;
1597 old_addr0 = ip0->dst_address;
1598 ip0->dst_address = new_addr0;
1599 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
1601 sum0 = ip0->checksum;
1602 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1604 dst_address /* changed member */);
1605 ip0->checksum = ip_csum_fold (sum0);
1607 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1609 if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
1610 ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
1611 else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
1612 snat_det_ses_close(dm0, ses0);
1614 old_port0 = tcp0->dst;
1615 tcp0->dst = new_port0;
1617 sum0 = tcp0->checksum;
1618 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
1620 dst_address /* changed member */);
1622 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1623 ip4_header_t /* cheat */,
1624 length /* changed member */);
1625 tcp0->checksum = ip_csum_fold(sum0);
1629 old_port0 = udp0->dst_port;
1630 udp0->dst_port = new_port0;
1636 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1637 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1639 snat_out2in_trace_t *t =
1640 vlib_add_trace (vm, node, b0, sizeof (*t));
1641 t->sw_if_index = sw_if_index0;
1642 t->next_index = next0;
1643 t->session_index = ~0;
1645 t->session_index = ses0 - dm0->sessions;
1648 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1650 /* verify speculative enqueue, maybe switch current next frame */
1651 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1652 to_next, n_left_to_next,
1656 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1659 vlib_node_increment_counter (vm, snat_det_out2in_node.index,
1660 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1662 return frame->n_vectors;
1665 VLIB_REGISTER_NODE (snat_det_out2in_node) = {
1666 .function = snat_det_out2in_node_fn,
1667 .name = "snat-det-out2in",
1668 .vector_size = sizeof (u32),
1669 .format_trace = format_snat_out2in_trace,
1670 .type = VLIB_NODE_TYPE_INTERNAL,
1672 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1673 .error_strings = snat_out2in_error_strings,
1675 .runtime_data_bytes = sizeof (snat_runtime_t),
1677 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1679 /* edit / add dispositions here */
1681 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1682 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1683 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1686 VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn);
1689 * Get address and port values to be used for packet SNAT translation
1690 * and create session if needed
1692 * @param[in,out] sm SNAT main
1693 * @param[in,out] node SNAT node runtime
1694 * @param[in] thread_index thread index
1695 * @param[in,out] b0 buffer containing packet to be translated
1696 * @param[out] p_proto protocol used for matching
1697 * @param[out] p_value address and port after NAT translation
1698 * @param[out] p_dont_translate if packet should not be translated
1699 * @param d optional parameter
1700 * @param e optional parameter
1702 u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node,
1703 u32 thread_index, vlib_buffer_t *b0, u8 *p_proto,
1704 snat_session_key_t *p_value,
1705 u8 *p_dont_translate, void *d, void *e)
1708 icmp46_header_t *icmp0;
1711 snat_det_out_key_t key0;
1712 u8 dont_translate = 0;
1714 icmp_echo_header_t *echo0, *inner_echo0 = 0;
1715 ip4_header_t *inner_ip0;
1716 void *l4_header = 0;
1717 icmp46_header_t *inner_icmp0;
1718 snat_det_map_t * dm0 = 0;
1719 ip4_address_t new_addr0 = {{0}};
1720 snat_det_session_t * ses0 = 0;
1721 ip4_address_t out_addr;
1723 ip0 = vlib_buffer_get_current (b0);
1724 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
1725 echo0 = (icmp_echo_header_t *)(icmp0+1);
1726 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1728 if (!icmp_is_error_message (icmp0))
1730 protocol = SNAT_PROTOCOL_ICMP;
1731 key0.ext_host_addr = ip0->src_address;
1732 key0.ext_host_port = 0;
1733 key0.out_port = echo0->identifier;
1734 out_addr = ip0->dst_address;
1738 inner_ip0 = (ip4_header_t *)(echo0+1);
1739 l4_header = ip4_next_header (inner_ip0);
1740 protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
1741 key0.ext_host_addr = inner_ip0->dst_address;
1742 out_addr = inner_ip0->src_address;
1745 case SNAT_PROTOCOL_ICMP:
1746 inner_icmp0 = (icmp46_header_t*)l4_header;
1747 inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
1748 key0.ext_host_port = 0;
1749 key0.out_port = inner_echo0->identifier;
1751 case SNAT_PROTOCOL_UDP:
1752 case SNAT_PROTOCOL_TCP:
1753 key0.ext_host_port = ((tcp_udp_header_t*)l4_header)->dst_port;
1754 key0.out_port = ((tcp_udp_header_t*)l4_header)->src_port;
1757 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1758 next0 = SNAT_OUT2IN_NEXT_DROP;
1763 dm0 = snat_det_map_by_out(sm, &out_addr);
1764 if (PREDICT_FALSE(!dm0))
1766 /* Don't NAT packet aimed at the intfc address */
1767 if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
1768 ip0->dst_address.as_u32)))
1773 clib_warning("unknown dst address: %U",
1774 format_ip4_address, &ip0->dst_address);
1778 snat_det_reverse(dm0, &ip0->dst_address,
1779 clib_net_to_host_u16(key0.out_port), &new_addr0);
1781 ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
1782 if (PREDICT_FALSE(!ses0))
1784 /* Don't NAT packet aimed at the intfc address */
1785 if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
1786 ip0->dst_address.as_u32)))
1791 clib_warning("no match src %U:%d dst %U:%d for user %U",
1792 format_ip4_address, &key0.ext_host_addr,
1793 clib_net_to_host_u16 (key0.ext_host_port),
1794 format_ip4_address, &out_addr,
1795 clib_net_to_host_u16 (key0.out_port),
1796 format_ip4_address, &new_addr0);
1797 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1798 next0 = SNAT_OUT2IN_NEXT_DROP;
1802 if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
1803 !icmp_is_error_message (icmp0)))
1805 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
1806 next0 = SNAT_OUT2IN_NEXT_DROP;
1813 *p_proto = protocol;
1816 p_value->addr = new_addr0;
1817 p_value->fib_index = sm->inside_fib_index;
1818 p_value->port = ses0->in_port;
1820 *p_dont_translate = dont_translate;
1822 *(snat_det_session_t**)d = ses0;
1824 *(snat_det_map_t**)e = dm0;
1828 /**********************/
1829 /*** worker handoff ***/
1830 /**********************/
1832 snat_out2in_worker_handoff_fn (vlib_main_t * vm,
1833 vlib_node_runtime_t * node,
1834 vlib_frame_t * frame)
1836 snat_main_t *sm = &snat_main;
1837 vlib_thread_main_t *tm = vlib_get_thread_main ();
1838 u32 n_left_from, *from, *to_next = 0;
1839 static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
1840 static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
1842 vlib_frame_queue_elt_t *hf = 0;
1843 vlib_frame_t *f = 0;
1845 u32 n_left_to_next_worker = 0, *to_next_worker = 0;
1846 u32 next_worker_index = 0;
1847 u32 current_worker_index = ~0;
1848 u32 thread_index = vlib_get_thread_index ();
1850 ASSERT (vec_len (sm->workers));
1852 if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
1854 vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
1856 vec_validate_init_empty (congested_handoff_queue_by_worker_index,
1857 sm->first_worker_index + sm->num_workers - 1,
1858 (vlib_frame_queue_t *) (~0));
1861 from = vlib_frame_vector_args (frame);
1862 n_left_from = frame->n_vectors;
1864 while (n_left_from > 0)
1877 b0 = vlib_get_buffer (vm, bi0);
1879 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1880 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
1882 ip0 = vlib_buffer_get_current (b0);
1884 next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0);
1886 if (PREDICT_FALSE (next_worker_index != thread_index))
1890 if (next_worker_index != current_worker_index)
1893 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
1895 hf = vlib_get_worker_handoff_queue_elt (sm->fq_out2in_index,
1897 handoff_queue_elt_by_worker_index);
1899 n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
1900 to_next_worker = &hf->buffer_index[hf->n_vectors];
1901 current_worker_index = next_worker_index;
1904 /* enqueue to correct worker thread */
1905 to_next_worker[0] = bi0;
1907 n_left_to_next_worker--;
1909 if (n_left_to_next_worker == 0)
1911 hf->n_vectors = VLIB_FRAME_SIZE;
1912 vlib_put_frame_queue_elt (hf);
1913 current_worker_index = ~0;
1914 handoff_queue_elt_by_worker_index[next_worker_index] = 0;
1921 /* if this is 1st frame */
1924 f = vlib_get_frame_to_node (vm, sm->out2in_node_index);
1925 to_next = vlib_frame_vector_args (f);
1933 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1934 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1936 snat_out2in_worker_handoff_trace_t *t =
1937 vlib_add_trace (vm, node, b0, sizeof (*t));
1938 t->next_worker_index = next_worker_index;
1939 t->do_handoff = do_handoff;
1944 vlib_put_frame_to_node (vm, sm->out2in_node_index, f);
1947 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
1949 /* Ship frames to the worker nodes */
1950 for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
1952 if (handoff_queue_elt_by_worker_index[i])
1954 hf = handoff_queue_elt_by_worker_index[i];
1956 * It works better to let the handoff node
1957 * rate-adapt, always ship the handoff queue element.
1959 if (1 || hf->n_vectors == hf->last_n_vectors)
1961 vlib_put_frame_queue_elt (hf);
1962 handoff_queue_elt_by_worker_index[i] = 0;
1965 hf->last_n_vectors = hf->n_vectors;
1967 congested_handoff_queue_by_worker_index[i] =
1968 (vlib_frame_queue_t *) (~0);
1971 current_worker_index = ~0;
1972 return frame->n_vectors;
1975 VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = {
1976 .function = snat_out2in_worker_handoff_fn,
1977 .name = "snat-out2in-worker-handoff",
1978 .vector_size = sizeof (u32),
1979 .format_trace = format_snat_out2in_worker_handoff_trace,
1980 .type = VLIB_NODE_TYPE_INTERNAL,
1989 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_worker_handoff_node, snat_out2in_worker_handoff_fn);
1992 snat_out2in_fast_node_fn (vlib_main_t * vm,
1993 vlib_node_runtime_t * node,
1994 vlib_frame_t * frame)
1996 u32 n_left_from, * from, * to_next;
1997 snat_out2in_next_t next_index;
1998 u32 pkts_processed = 0;
1999 snat_main_t * sm = &snat_main;
2001 from = vlib_frame_vector_args (frame);
2002 n_left_from = frame->n_vectors;
2003 next_index = node->cached_next_index;
2005 while (n_left_from > 0)
2009 vlib_get_next_frame (vm, node, next_index,
2010 to_next, n_left_to_next);
2012 while (n_left_from > 0 && n_left_to_next > 0)
2016 u32 next0 = SNAT_OUT2IN_NEXT_DROP;
2020 u32 new_addr0, old_addr0;
2021 u16 new_port0, old_port0;
2022 udp_header_t * udp0;
2023 tcp_header_t * tcp0;
2024 icmp46_header_t * icmp0;
2025 snat_session_key_t key0, sm0;
2029 /* speculatively enqueue b0 to the current next frame */
2035 n_left_to_next -= 1;
2037 b0 = vlib_get_buffer (vm, bi0);
2039 ip0 = vlib_buffer_get_current (b0);
2040 udp0 = ip4_next_header (ip0);
2041 tcp0 = (tcp_header_t *) udp0;
2042 icmp0 = (icmp46_header_t *) udp0;
2044 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2045 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2047 vnet_feature_next (sw_if_index0, &next0, b0);
2049 if (PREDICT_FALSE(ip0->ttl == 1))
2051 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2052 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2053 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2055 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
2059 proto0 = ip_proto_to_snat_proto (ip0->protocol);
2061 if (PREDICT_FALSE (proto0 == ~0))
2064 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2066 next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2067 rx_fib_index0, node, next0, ~0, 0, 0);
2071 key0.addr = ip0->dst_address;
2072 key0.port = udp0->dst_port;
2073 key0.fib_index = rx_fib_index0;
2075 if (snat_static_mapping_match(sm, key0, &sm0, 1, 0))
2077 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2081 new_addr0 = sm0.addr.as_u32;
2082 new_port0 = sm0.port;
2083 vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2084 old_addr0 = ip0->dst_address.as_u32;
2085 ip0->dst_address.as_u32 = new_addr0;
2087 sum0 = ip0->checksum;
2088 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2090 dst_address /* changed member */);
2091 ip0->checksum = ip_csum_fold (sum0);
2093 if (PREDICT_FALSE(new_port0 != udp0->dst_port))
2095 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2097 old_port0 = tcp0->dst_port;
2098 tcp0->dst_port = new_port0;
2100 sum0 = tcp0->checksum;
2101 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2103 dst_address /* changed member */);
2105 sum0 = ip_csum_update (sum0, old_port0, new_port0,
2106 ip4_header_t /* cheat */,
2107 length /* changed member */);
2108 tcp0->checksum = ip_csum_fold(sum0);
2112 old_port0 = udp0->dst_port;
2113 udp0->dst_port = new_port0;
2119 if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2121 sum0 = tcp0->checksum;
2122 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2124 dst_address /* changed member */);
2126 tcp0->checksum = ip_csum_fold(sum0);
2132 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2133 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2135 snat_out2in_trace_t *t =
2136 vlib_add_trace (vm, node, b0, sizeof (*t));
2137 t->sw_if_index = sw_if_index0;
2138 t->next_index = next0;
2141 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2143 /* verify speculative enqueue, maybe switch current next frame */
2144 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2145 to_next, n_left_to_next,
2149 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2152 vlib_node_increment_counter (vm, snat_out2in_fast_node.index,
2153 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2155 return frame->n_vectors;
2158 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
2159 .function = snat_out2in_fast_node_fn,
2160 .name = "snat-out2in-fast",
2161 .vector_size = sizeof (u32),
2162 .format_trace = format_snat_out2in_fast_trace,
2163 .type = VLIB_NODE_TYPE_INTERNAL,
2165 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2166 .error_strings = snat_out2in_error_strings,
2168 .runtime_data_bytes = sizeof (snat_runtime_t),
2170 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
2172 /* edit / add dispositions here */
2174 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2175 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2176 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2179 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn);