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.
17 * @brief NAT44 endpoint-dependent outside to inside network translation
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/pg/pg.h>
24 #include <vnet/ip/ip.h>
25 #include <vnet/udp/udp.h>
26 #include <vnet/ethernet/ethernet.h>
27 #include <vnet/fib/ip4_fib.h>
29 #include <nat/nat_ipfix_logging.h>
30 #include <nat/nat_reass.h>
31 #include <nat/nat_inlines.h>
32 #include <nat/nat_syslog.h>
34 #include <vppinfra/hash.h>
35 #include <vppinfra/error.h>
36 #include <vppinfra/elog.h>
43 } snat_out2in_trace_t;
45 /* packet trace format function */
47 format_snat_out2in_trace (u8 * s, va_list * args)
49 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
50 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
51 snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
55 "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
56 t->sw_if_index, t->next_index, t->session_index);
61 format_snat_out2in_fast_trace (u8 * s, va_list * args)
63 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
64 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
65 snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
67 s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
68 t->sw_if_index, t->next_index);
72 vlib_node_registration_t snat_out2in_node;
73 vlib_node_registration_t snat_out2in_fast_node;
74 vlib_node_registration_t nat44_out2in_reass_node;
76 #define foreach_snat_out2in_error \
77 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
78 _(OUT2IN_PACKETS, "Good out2in packets processed") \
79 _(OUT_OF_PORTS, "Out of ports") \
80 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
81 _(NO_TRANSLATION, "No translation") \
82 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \
83 _(DROP_FRAGMENT, "Drop fragment") \
84 _(MAX_REASS, "Maximum reassemblies exceeded") \
85 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")
89 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
90 foreach_snat_out2in_error
93 } snat_out2in_error_t;
95 static char *snat_out2in_error_strings[] = {
96 #define _(sym,string) string,
97 foreach_snat_out2in_error
103 SNAT_OUT2IN_NEXT_DROP,
104 SNAT_OUT2IN_NEXT_LOOKUP,
105 SNAT_OUT2IN_NEXT_ICMP_ERROR,
106 SNAT_OUT2IN_NEXT_REASS,
108 } snat_out2in_next_t;
111 nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
113 snat_main_t *sm = &snat_main;
114 nat44_is_idle_session_ctx_t *ctx = arg;
116 u64 sess_timeout_time;
117 snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
119 clib_bihash_kv_8_8_t s_kv;
121 s = pool_elt_at_index (tsm->sessions, kv->value);
122 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
123 if (ctx->now >= sess_timeout_time)
125 s_kv.key = s->in2out.as_u64;
126 if (clib_bihash_add_del_8_8 (&tsm->in2out, &s_kv, 0))
127 nat_log_warn ("out2in key del failed");
129 snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
130 s->out2in.addr.as_u32,
134 s->in2out.fib_index);
136 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
137 &s->in2out.addr, s->in2out.port,
138 &s->out2in.addr, s->out2in.port,
141 if (!snat_is_session_static (s))
142 snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
145 nat44_delete_session (sm, s, ctx->thread_index);
153 * @brief Create session for static mapping.
155 * Create NAT session initiated by host from external network with static
158 * @param sm NAT main.
159 * @param b0 Vlib buffer.
160 * @param in2out In2out NAT44 session key.
161 * @param out2in Out2in NAT44 session key.
162 * @param node Vlib node.
164 * @returns SNAT session if successfully created otherwise 0.
166 static inline snat_session_t *
167 create_session_for_static_mapping (snat_main_t * sm,
169 snat_session_key_t in2out,
170 snat_session_key_t out2in,
171 vlib_node_runtime_t * node,
172 u32 thread_index, f64 now)
176 clib_bihash_kv_8_8_t kv0;
179 nat44_is_idle_session_ctx_t ctx0;
181 if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index)))
183 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
184 nat_log_notice ("maximum sessions exceeded");
188 ip0 = vlib_buffer_get_current (b0);
189 udp0 = ip4_next_header (ip0);
192 nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index);
195 nat_log_warn ("create NAT user failed");
199 s = nat_session_alloc_or_recycle (sm, u, thread_index);
202 nat44_delete_user_with_no_session (sm, u, thread_index);
203 nat_log_warn ("create NAT session failed");
207 s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
208 s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
209 s->ext_host_port = udp0->src_port;
210 user_session_increment (sm, u, 1 /* static */ );
213 s->in2out.protocol = out2in.protocol;
215 /* Add to translation hashes */
217 ctx0.thread_index = thread_index;
218 kv0.key = s->in2out.as_u64;
219 kv0.value = s - sm->per_thread_data[thread_index].sessions;
220 if (clib_bihash_add_or_overwrite_stale_8_8
221 (&sm->per_thread_data[thread_index].in2out, &kv0,
222 nat44_i2o_is_idle_session_cb, &ctx0))
223 nat_log_notice ("in2out key add failed");
225 kv0.key = s->out2in.as_u64;
227 if (clib_bihash_add_or_overwrite_stale_8_8
228 (&sm->per_thread_data[thread_index].out2in, &kv0,
229 nat44_o2i_is_idle_session_cb, &ctx0))
230 nat_log_notice ("out2in key add failed");
233 snat_ipfix_logging_nat44_ses_create (s->in2out.addr.as_u32,
234 s->out2in.addr.as_u32,
237 s->out2in.port, s->in2out.fib_index);
239 nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
240 &s->in2out.addr, s->in2out.port, &s->out2in.addr,
241 s->out2in.port, s->in2out.protocol);
247 snat_out2in_error_t icmp_get_key (ip4_header_t * ip0,
248 snat_session_key_t * p_key0)
250 icmp46_header_t *icmp0;
251 snat_session_key_t key0;
252 icmp_echo_header_t *echo0, *inner_echo0 = 0;
253 ip4_header_t *inner_ip0;
255 icmp46_header_t *inner_icmp0;
257 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
258 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
260 if (!icmp_is_error_message (icmp0))
262 key0.protocol = SNAT_PROTOCOL_ICMP;
263 key0.addr = ip0->dst_address;
264 key0.port = echo0->identifier;
268 inner_ip0 = (ip4_header_t *) (echo0 + 1);
269 l4_header = ip4_next_header (inner_ip0);
270 key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
271 key0.addr = inner_ip0->src_address;
272 switch (key0.protocol)
274 case SNAT_PROTOCOL_ICMP:
275 inner_icmp0 = (icmp46_header_t *) l4_header;
276 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
277 key0.port = inner_echo0->identifier;
279 case SNAT_PROTOCOL_UDP:
280 case SNAT_PROTOCOL_TCP:
281 key0.port = ((tcp_udp_header_t *) l4_header)->src_port;
284 return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
288 return -1; /* success */
292 * Get address and port values to be used for ICMP packet translation
293 * and create session if needed
295 * @param[in,out] sm NAT main
296 * @param[in,out] node NAT node runtime
297 * @param[in] thread_index thread index
298 * @param[in,out] b0 buffer containing packet to be translated
299 * @param[out] p_proto protocol used for matching
300 * @param[out] p_value address and port after NAT translation
301 * @param[out] p_dont_translate if packet should not be translated
302 * @param d optional parameter
303 * @param e optional parameter
306 icmp_match_out2in_slow (snat_main_t * sm, vlib_node_runtime_t * node,
307 u32 thread_index, vlib_buffer_t * b0,
308 ip4_header_t * ip0, u8 * p_proto,
309 snat_session_key_t * p_value,
310 u8 * p_dont_translate, void *d, void *e)
312 icmp46_header_t *icmp0;
315 snat_session_key_t key0;
316 snat_session_key_t sm0;
317 snat_session_t *s0 = 0;
318 u8 dont_translate = 0;
319 clib_bihash_kv_8_8_t kv0, value0;
325 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
326 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
327 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
331 err = icmp_get_key (ip0, &key0);
334 b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
335 next0 = SNAT_OUT2IN_NEXT_DROP;
338 key0.fib_index = rx_fib_index0;
340 kv0.key = key0.as_u64;
342 if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
345 /* Try to match static mapping by external address and port,
346 destination address and port in packet */
347 if (snat_static_mapping_match
348 (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, &identity_nat))
350 if (!sm->forwarding_enabled)
352 /* Don't NAT packet aimed at the intfc address */
353 if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index0,
354 ip0->dst_address.as_u32)))
359 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
360 next0 = SNAT_OUT2IN_NEXT_DROP;
370 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
371 (icmp0->type != ICMP4_echo_request
374 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
375 next0 = SNAT_OUT2IN_NEXT_DROP;
379 if (PREDICT_FALSE (identity_nat))
384 /* Create session initiated by host from external network */
385 s0 = create_session_for_static_mapping (sm, b0, sm0, key0,
387 vlib_time_now (sm->vlib_main));
391 next0 = SNAT_OUT2IN_NEXT_DROP;
397 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
398 icmp0->type != ICMP4_echo_request &&
399 !icmp_is_error_message (icmp0)))
401 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
402 next0 = SNAT_OUT2IN_NEXT_DROP;
406 s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
411 *p_proto = key0.protocol;
413 *p_value = s0->in2out;
414 *p_dont_translate = dont_translate;
416 *(snat_session_t **) d = s0;
421 * Get address and port values to be used for ICMP packet translation
423 * @param[in] sm NAT main
424 * @param[in,out] node NAT node runtime
425 * @param[in] thread_index thread index
426 * @param[in,out] b0 buffer containing packet to be translated
427 * @param[out] p_proto protocol used for matching
428 * @param[out] p_value address and port after NAT translation
429 * @param[out] p_dont_translate if packet should not be translated
430 * @param d optional parameter
431 * @param e optional parameter
434 icmp_match_out2in_fast (snat_main_t * sm, vlib_node_runtime_t * node,
435 u32 thread_index, vlib_buffer_t * b0,
436 ip4_header_t * ip0, u8 * p_proto,
437 snat_session_key_t * p_value,
438 u8 * p_dont_translate, void *d, void *e)
440 icmp46_header_t *icmp0;
443 snat_session_key_t key0;
444 snat_session_key_t sm0;
445 u8 dont_translate = 0;
450 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
451 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
452 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
454 err = icmp_get_key (ip0, &key0);
457 b0->error = node->errors[err];
458 next0 = SNAT_OUT2IN_NEXT_DROP;
461 key0.fib_index = rx_fib_index0;
463 if (snat_static_mapping_match
464 (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, 0))
466 /* Don't NAT packet aimed at the intfc address */
467 if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))
472 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
473 next0 = SNAT_OUT2IN_NEXT_DROP;
477 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_reply &&
478 (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
479 !icmp_is_error_message (icmp0)))
481 b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
482 next0 = SNAT_OUT2IN_NEXT_DROP;
489 *p_proto = key0.protocol;
490 *p_dont_translate = dont_translate;
495 icmp_out2in (snat_main_t * sm,
498 icmp46_header_t * icmp0,
501 vlib_node_runtime_t * node,
502 u32 next0, u32 thread_index, void *d, void *e)
504 snat_session_key_t sm0;
506 icmp_echo_header_t *echo0, *inner_echo0 = 0;
507 ip4_header_t *inner_ip0 = 0;
509 icmp46_header_t *inner_icmp0;
511 u32 new_addr0, old_addr0;
512 u16 old_id0, new_id0;
517 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
519 next0_tmp = sm->icmp_match_out2in_cb (sm, node, thread_index, b0, ip0,
520 &protocol, &sm0, &dont_translate, d,
524 if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
527 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
529 sum0 = ip_incremental_checksum_buffer (sm->vlib_main, b0, (u8 *) icmp0 -
531 vlib_buffer_get_current (b0),
532 ntohs (ip0->length) -
533 ip4_header_bytes (ip0), 0);
534 checksum0 = ~ip_csum_fold (sum0);
535 if (checksum0 != 0 && checksum0 != 0xffff)
537 next0 = SNAT_OUT2IN_NEXT_DROP;
542 old_addr0 = ip0->dst_address.as_u32;
543 new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
544 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
546 sum0 = ip0->checksum;
547 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
548 dst_address /* changed member */ );
549 ip0->checksum = ip_csum_fold (sum0);
551 if (icmp0->checksum == 0)
552 icmp0->checksum = 0xffff;
554 if (!icmp_is_error_message (icmp0))
557 if (PREDICT_FALSE (new_id0 != echo0->identifier))
559 old_id0 = echo0->identifier;
561 echo0->identifier = new_id0;
563 sum0 = icmp0->checksum;
564 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
565 identifier /* changed member */ );
566 icmp0->checksum = ip_csum_fold (sum0);
571 inner_ip0 = (ip4_header_t *) (echo0 + 1);
572 l4_header = ip4_next_header (inner_ip0);
574 if (!ip4_header_checksum_is_valid (inner_ip0))
576 next0 = SNAT_OUT2IN_NEXT_DROP;
580 old_addr0 = inner_ip0->src_address.as_u32;
581 inner_ip0->src_address = sm0.addr;
582 new_addr0 = inner_ip0->src_address.as_u32;
584 sum0 = icmp0->checksum;
585 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
586 src_address /* changed member */ );
587 icmp0->checksum = ip_csum_fold (sum0);
591 case SNAT_PROTOCOL_ICMP:
592 inner_icmp0 = (icmp46_header_t *) l4_header;
593 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
595 old_id0 = inner_echo0->identifier;
597 inner_echo0->identifier = new_id0;
599 sum0 = icmp0->checksum;
600 sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
602 icmp0->checksum = ip_csum_fold (sum0);
604 case SNAT_PROTOCOL_UDP:
605 case SNAT_PROTOCOL_TCP:
606 old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
608 ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
610 sum0 = icmp0->checksum;
611 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
613 icmp0->checksum = ip_csum_fold (sum0);
626 icmp_out2in_slow_path (snat_main_t * sm,
629 icmp46_header_t * icmp0,
632 vlib_node_runtime_t * node,
634 u32 thread_index, snat_session_t ** p_s0)
636 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
637 next0, thread_index, p_s0, 0);
638 snat_session_t *s0 = *p_s0;
639 if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP && s0))
642 nat44_session_update_counters (s0, now,
643 vlib_buffer_length_in_chain
644 (sm->vlib_main, b0));
645 /* Per-user LRU list maintenance */
646 nat44_session_update_lru (sm, s0, thread_index);
652 nat_out2in_sm_unknown_proto (snat_main_t * sm,
654 ip4_header_t * ip, u32 rx_fib_index)
656 clib_bihash_kv_8_8_t kv, value;
657 snat_static_mapping_t *m;
658 snat_session_key_t m_key;
659 u32 old_addr, new_addr;
662 m_key.addr = ip->dst_address;
666 kv.key = m_key.as_u64;
667 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
670 m = pool_elt_at_index (sm->static_mappings, value.value);
672 old_addr = ip->dst_address.as_u32;
673 new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
675 sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
676 ip->checksum = ip_csum_fold (sum);
678 vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
683 snat_out2in_node_fn (vlib_main_t * vm,
684 vlib_node_runtime_t * node, vlib_frame_t * frame)
686 u32 n_left_from, *from, *to_next;
687 snat_out2in_next_t next_index;
688 u32 pkts_processed = 0;
689 snat_main_t *sm = &snat_main;
690 f64 now = vlib_time_now (vm);
691 u32 thread_index = vm->thread_index;
693 from = vlib_frame_vector_args (frame);
694 n_left_from = frame->n_vectors;
695 next_index = node->cached_next_index;
697 while (n_left_from > 0)
701 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
703 while (n_left_from >= 4 && n_left_to_next >= 2)
706 vlib_buffer_t *b0, *b1;
707 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
708 u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
709 u32 sw_if_index0, sw_if_index1;
710 ip4_header_t *ip0, *ip1;
711 ip_csum_t sum0, sum1;
712 u32 new_addr0, old_addr0;
713 u16 new_port0, old_port0;
714 u32 new_addr1, old_addr1;
715 u16 new_port1, old_port1;
716 udp_header_t *udp0, *udp1;
717 tcp_header_t *tcp0, *tcp1;
718 icmp46_header_t *icmp0, *icmp1;
719 snat_session_key_t key0, key1, sm0, sm1;
720 u32 rx_fib_index0, rx_fib_index1;
722 snat_session_t *s0 = 0, *s1 = 0;
723 clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
724 u8 identity_nat0, identity_nat1;
726 /* Prefetch next iteration. */
728 vlib_buffer_t *p2, *p3;
730 p2 = vlib_get_buffer (vm, from[2]);
731 p3 = vlib_get_buffer (vm, from[3]);
733 vlib_prefetch_buffer_header (p2, LOAD);
734 vlib_prefetch_buffer_header (p3, LOAD);
736 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
737 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
740 /* speculatively enqueue b0 and b1 to the current next frame */
741 to_next[0] = bi0 = from[0];
742 to_next[1] = bi1 = from[1];
748 b0 = vlib_get_buffer (vm, bi0);
749 b1 = vlib_get_buffer (vm, bi1);
751 vnet_buffer (b0)->snat.flags = 0;
752 vnet_buffer (b1)->snat.flags = 0;
754 ip0 = vlib_buffer_get_current (b0);
755 udp0 = ip4_next_header (ip0);
756 tcp0 = (tcp_header_t *) udp0;
757 icmp0 = (icmp46_header_t *) udp0;
759 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
760 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
763 if (PREDICT_FALSE (ip0->ttl == 1))
765 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
766 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
767 ICMP4_time_exceeded_ttl_exceeded_in_transit,
769 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
773 proto0 = ip_proto_to_snat_proto (ip0->protocol);
775 if (PREDICT_FALSE (proto0 == ~0))
777 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
779 if (!sm->forwarding_enabled)
782 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
783 next0 = SNAT_OUT2IN_NEXT_DROP;
789 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
791 next0 = SNAT_OUT2IN_NEXT_REASS;
795 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
797 next0 = icmp_out2in_slow_path
798 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
799 next0, now, thread_index, &s0);
803 key0.addr = ip0->dst_address;
804 key0.port = udp0->dst_port;
805 key0.protocol = proto0;
806 key0.fib_index = rx_fib_index0;
808 kv0.key = key0.as_u64;
810 if (clib_bihash_search_8_8
811 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
813 /* Try to match static mapping by external address and port,
814 destination address and port in packet */
815 if (snat_static_mapping_match
816 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
819 * Send DHCP packets to the ipv4 stack, or we won't
820 * be able to use dhcp client on the outside interface
822 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
823 && (udp0->dst_port ==
825 (UDP_DST_PORT_dhcp_to_client))))
827 vnet_feature_next (&next0, b0);
831 if (!sm->forwarding_enabled)
834 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
835 next0 = SNAT_OUT2IN_NEXT_DROP;
840 if (PREDICT_FALSE (identity_nat0))
843 /* Create session initiated by host from external network */
844 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
848 next0 = SNAT_OUT2IN_NEXT_DROP;
854 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
857 old_addr0 = ip0->dst_address.as_u32;
858 ip0->dst_address = s0->in2out.addr;
859 new_addr0 = ip0->dst_address.as_u32;
860 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
862 sum0 = ip0->checksum;
863 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
865 dst_address /* changed member */ );
866 ip0->checksum = ip_csum_fold (sum0);
868 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
870 old_port0 = tcp0->dst_port;
871 tcp0->dst_port = s0->in2out.port;
872 new_port0 = tcp0->dst_port;
874 sum0 = tcp0->checksum;
875 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
877 dst_address /* changed member */ );
879 sum0 = ip_csum_update (sum0, old_port0, new_port0,
880 ip4_header_t /* cheat */ ,
881 length /* changed member */ );
882 tcp0->checksum = ip_csum_fold (sum0);
886 old_port0 = udp0->dst_port;
887 udp0->dst_port = s0->in2out.port;
892 nat44_session_update_counters (s0, now,
893 vlib_buffer_length_in_chain (vm,
895 /* Per-user LRU list maintenance */
896 nat44_session_update_lru (sm, s0, thread_index);
899 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
900 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
902 snat_out2in_trace_t *t =
903 vlib_add_trace (vm, node, b0, sizeof (*t));
904 t->sw_if_index = sw_if_index0;
905 t->next_index = next0;
906 t->session_index = ~0;
909 s0 - sm->per_thread_data[thread_index].sessions;
912 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
915 ip1 = vlib_buffer_get_current (b1);
916 udp1 = ip4_next_header (ip1);
917 tcp1 = (tcp_header_t *) udp1;
918 icmp1 = (icmp46_header_t *) udp1;
920 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
921 rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
924 if (PREDICT_FALSE (ip1->ttl == 1))
926 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
927 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
928 ICMP4_time_exceeded_ttl_exceeded_in_transit,
930 next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
934 proto1 = ip_proto_to_snat_proto (ip1->protocol);
936 if (PREDICT_FALSE (proto1 == ~0))
938 if (nat_out2in_sm_unknown_proto (sm, b1, ip1, rx_fib_index1))
940 if (!sm->forwarding_enabled)
943 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
944 next1 = SNAT_OUT2IN_NEXT_DROP;
950 if (PREDICT_FALSE (ip4_is_fragment (ip1)))
952 next1 = SNAT_OUT2IN_NEXT_REASS;
956 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
958 next1 = icmp_out2in_slow_path
959 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
960 next1, now, thread_index, &s1);
964 key1.addr = ip1->dst_address;
965 key1.port = udp1->dst_port;
966 key1.protocol = proto1;
967 key1.fib_index = rx_fib_index1;
969 kv1.key = key1.as_u64;
971 if (clib_bihash_search_8_8
972 (&sm->per_thread_data[thread_index].out2in, &kv1, &value1))
974 /* Try to match static mapping by external address and port,
975 destination address and port in packet */
976 if (snat_static_mapping_match
977 (sm, key1, &sm1, 1, 0, 0, 0, 0, &identity_nat1))
980 * Send DHCP packets to the ipv4 stack, or we won't
981 * be able to use dhcp client on the outside interface
983 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_UDP
984 && (udp1->dst_port ==
986 (UDP_DST_PORT_dhcp_to_client))))
988 vnet_feature_next (&next1, b1);
992 if (!sm->forwarding_enabled)
995 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
996 next1 = SNAT_OUT2IN_NEXT_DROP;
1001 if (PREDICT_FALSE (identity_nat1))
1004 /* Create session initiated by host from external network */
1005 s1 = create_session_for_static_mapping (sm, b1, sm1, key1, node,
1009 next1 = SNAT_OUT2IN_NEXT_DROP;
1015 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1018 old_addr1 = ip1->dst_address.as_u32;
1019 ip1->dst_address = s1->in2out.addr;
1020 new_addr1 = ip1->dst_address.as_u32;
1021 vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1023 sum1 = ip1->checksum;
1024 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1026 dst_address /* changed member */ );
1027 ip1->checksum = ip_csum_fold (sum1);
1029 if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
1031 old_port1 = tcp1->dst_port;
1032 tcp1->dst_port = s1->in2out.port;
1033 new_port1 = tcp1->dst_port;
1035 sum1 = tcp1->checksum;
1036 sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1038 dst_address /* changed member */ );
1040 sum1 = ip_csum_update (sum1, old_port1, new_port1,
1041 ip4_header_t /* cheat */ ,
1042 length /* changed member */ );
1043 tcp1->checksum = ip_csum_fold (sum1);
1047 old_port1 = udp1->dst_port;
1048 udp1->dst_port = s1->in2out.port;
1053 nat44_session_update_counters (s1, now,
1054 vlib_buffer_length_in_chain (vm,
1056 /* Per-user LRU list maintenance */
1057 nat44_session_update_lru (sm, s1, thread_index);
1060 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1061 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1063 snat_out2in_trace_t *t =
1064 vlib_add_trace (vm, node, b1, sizeof (*t));
1065 t->sw_if_index = sw_if_index1;
1066 t->next_index = next1;
1067 t->session_index = ~0;
1070 s1 - sm->per_thread_data[thread_index].sessions;
1073 pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1075 /* verify speculative enqueues, maybe switch current next frame */
1076 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1077 to_next, n_left_to_next,
1078 bi0, bi1, next0, next1);
1081 while (n_left_from > 0 && n_left_to_next > 0)
1085 u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1089 u32 new_addr0, old_addr0;
1090 u16 new_port0, old_port0;
1093 icmp46_header_t *icmp0;
1094 snat_session_key_t key0, sm0;
1097 snat_session_t *s0 = 0;
1098 clib_bihash_kv_8_8_t kv0, value0;
1101 /* speculatively enqueue b0 to the current next frame */
1107 n_left_to_next -= 1;
1109 b0 = vlib_get_buffer (vm, bi0);
1111 vnet_buffer (b0)->snat.flags = 0;
1113 ip0 = vlib_buffer_get_current (b0);
1114 udp0 = ip4_next_header (ip0);
1115 tcp0 = (tcp_header_t *) udp0;
1116 icmp0 = (icmp46_header_t *) udp0;
1118 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1119 rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1122 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1124 if (PREDICT_FALSE (proto0 == ~0))
1126 if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
1128 if (!sm->forwarding_enabled)
1131 node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1132 next0 = SNAT_OUT2IN_NEXT_DROP;
1138 if (PREDICT_FALSE (ip0->ttl == 1))
1140 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1141 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1142 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1144 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1148 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1150 next0 = SNAT_OUT2IN_NEXT_REASS;
1154 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1156 next0 = icmp_out2in_slow_path
1157 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1158 next0, now, thread_index, &s0);
1162 key0.addr = ip0->dst_address;
1163 key0.port = udp0->dst_port;
1164 key0.protocol = proto0;
1165 key0.fib_index = rx_fib_index0;
1167 kv0.key = key0.as_u64;
1169 if (clib_bihash_search_8_8
1170 (&sm->per_thread_data[thread_index].out2in, &kv0, &value0))
1172 /* Try to match static mapping by external address and port,
1173 destination address and port in packet */
1174 if (snat_static_mapping_match
1175 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
1178 * Send DHCP packets to the ipv4 stack, or we won't
1179 * be able to use dhcp client on the outside interface
1181 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1182 && (udp0->dst_port ==
1183 clib_host_to_net_u16
1184 (UDP_DST_PORT_dhcp_to_client))))
1186 vnet_feature_next (&next0, b0);
1190 if (!sm->forwarding_enabled)
1193 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1194 next0 = SNAT_OUT2IN_NEXT_DROP;
1199 if (PREDICT_FALSE (identity_nat0))
1202 /* Create session initiated by host from external network */
1203 s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
1207 next0 = SNAT_OUT2IN_NEXT_DROP;
1213 pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
1216 old_addr0 = ip0->dst_address.as_u32;
1217 ip0->dst_address = s0->in2out.addr;
1218 new_addr0 = ip0->dst_address.as_u32;
1219 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1221 sum0 = ip0->checksum;
1222 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1224 dst_address /* changed member */ );
1225 ip0->checksum = ip_csum_fold (sum0);
1227 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1229 old_port0 = tcp0->dst_port;
1230 tcp0->dst_port = s0->in2out.port;
1231 new_port0 = tcp0->dst_port;
1233 sum0 = tcp0->checksum;
1234 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1236 dst_address /* changed member */ );
1238 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1239 ip4_header_t /* cheat */ ,
1240 length /* changed member */ );
1241 tcp0->checksum = ip_csum_fold (sum0);
1245 old_port0 = udp0->dst_port;
1246 udp0->dst_port = s0->in2out.port;
1251 nat44_session_update_counters (s0, now,
1252 vlib_buffer_length_in_chain (vm,
1254 /* Per-user LRU list maintenance */
1255 nat44_session_update_lru (sm, s0, thread_index);
1258 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1259 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1261 snat_out2in_trace_t *t =
1262 vlib_add_trace (vm, node, b0, sizeof (*t));
1263 t->sw_if_index = sw_if_index0;
1264 t->next_index = next0;
1265 t->session_index = ~0;
1268 s0 - sm->per_thread_data[thread_index].sessions;
1271 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1273 /* verify speculative enqueue, maybe switch current next frame */
1274 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1275 to_next, n_left_to_next,
1279 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1282 vlib_node_increment_counter (vm, snat_out2in_node.index,
1283 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1285 return frame->n_vectors;
1289 VLIB_REGISTER_NODE (snat_out2in_node) = {
1290 .function = snat_out2in_node_fn,
1291 .name = "nat44-out2in",
1292 .vector_size = sizeof (u32),
1293 .format_trace = format_snat_out2in_trace,
1294 .type = VLIB_NODE_TYPE_INTERNAL,
1296 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1297 .error_strings = snat_out2in_error_strings,
1299 .runtime_data_bytes = sizeof (snat_runtime_t),
1301 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1303 /* edit / add dispositions here */
1305 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1306 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1307 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1308 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1313 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
1316 nat44_out2in_reass_node_fn (vlib_main_t * vm,
1317 vlib_node_runtime_t * node, vlib_frame_t * frame)
1319 u32 n_left_from, *from, *to_next;
1320 snat_out2in_next_t next_index;
1321 u32 pkts_processed = 0;
1322 snat_main_t *sm = &snat_main;
1323 f64 now = vlib_time_now (vm);
1324 u32 thread_index = vm->thread_index;
1325 snat_main_per_thread_data_t *per_thread_data =
1326 &sm->per_thread_data[thread_index];
1327 u32 *fragments_to_drop = 0;
1328 u32 *fragments_to_loopback = 0;
1330 from = vlib_frame_vector_args (frame);
1331 n_left_from = frame->n_vectors;
1332 next_index = node->cached_next_index;
1334 while (n_left_from > 0)
1338 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1340 while (n_left_from > 0 && n_left_to_next > 0)
1342 u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1347 nat_reass_ip4_t *reass0;
1350 icmp46_header_t *icmp0;
1351 snat_session_key_t key0, sm0;
1352 clib_bihash_kv_8_8_t kv0, value0;
1353 snat_session_t *s0 = 0;
1354 u16 old_port0, new_port0;
1358 /* speculatively enqueue b0 to the current next frame */
1364 n_left_to_next -= 1;
1366 b0 = vlib_get_buffer (vm, bi0);
1367 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1369 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1371 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1374 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
1376 next0 = SNAT_OUT2IN_NEXT_DROP;
1377 b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1381 ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1382 udp0 = ip4_next_header (ip0);
1383 tcp0 = (tcp_header_t *) udp0;
1384 icmp0 = (icmp46_header_t *) udp0;
1385 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1387 reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1391 1, &fragments_to_drop);
1393 if (PREDICT_FALSE (!reass0))
1395 next0 = SNAT_OUT2IN_NEXT_DROP;
1396 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1397 nat_log_notice ("maximum reassemblies exceeded");
1401 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1403 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1405 next0 = icmp_out2in_slow_path
1406 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1407 next0, now, thread_index, &s0);
1409 if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP))
1412 reass0->sess_index = s0 - per_thread_data->sessions;
1414 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1415 reass0->thread_index = thread_index;
1416 nat_ip4_reass_get_frags (reass0,
1417 &fragments_to_loopback);
1423 key0.addr = ip0->dst_address;
1424 key0.port = udp0->dst_port;
1425 key0.protocol = proto0;
1426 key0.fib_index = rx_fib_index0;
1427 kv0.key = key0.as_u64;
1429 if (clib_bihash_search_8_8
1430 (&per_thread_data->out2in, &kv0, &value0))
1432 /* Try to match static mapping by external address and port,
1433 destination address and port in packet */
1434 if (snat_static_mapping_match
1435 (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
1438 * Send DHCP packets to the ipv4 stack, or we won't
1439 * be able to use dhcp client on the outside interface
1441 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_UDP
1444 clib_host_to_net_u16
1445 (UDP_DST_PORT_dhcp_to_client))))
1447 vnet_feature_next (&next0, b0);
1451 if (!sm->forwarding_enabled)
1454 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1455 next0 = SNAT_OUT2IN_NEXT_DROP;
1459 reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
1460 nat_ip4_reass_get_frags (reass0,
1461 &fragments_to_loopback);
1466 if (PREDICT_FALSE (identity_nat0))
1469 /* Create session initiated by host from external network */
1471 create_session_for_static_mapping (sm, b0, sm0, key0,
1477 node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1478 next0 = SNAT_OUT2IN_NEXT_DROP;
1481 reass0->sess_index = s0 - per_thread_data->sessions;
1482 reass0->thread_index = thread_index;
1486 s0 = pool_elt_at_index (per_thread_data->sessions,
1488 reass0->sess_index = value0.value;
1490 nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1494 if (reass0->flags & NAT_REASS_FLAG_ED_DONT_TRANSLATE)
1496 if (PREDICT_FALSE (reass0->sess_index == (u32) ~ 0))
1498 if (nat_ip4_reass_add_fragment
1499 (reass0, bi0, &fragments_to_drop))
1501 b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1503 ("maximum fragments per reassembly exceeded");
1504 next0 = SNAT_OUT2IN_NEXT_DROP;
1510 s0 = pool_elt_at_index (per_thread_data->sessions,
1511 reass0->sess_index);
1514 old_addr0 = ip0->dst_address.as_u32;
1515 ip0->dst_address = s0->in2out.addr;
1516 new_addr0 = ip0->dst_address.as_u32;
1517 vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1519 sum0 = ip0->checksum;
1520 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1522 dst_address /* changed member */ );
1523 ip0->checksum = ip_csum_fold (sum0);
1525 if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1527 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1529 old_port0 = tcp0->dst_port;
1530 tcp0->dst_port = s0->in2out.port;
1531 new_port0 = tcp0->dst_port;
1533 sum0 = tcp0->checksum;
1534 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1536 dst_address /* changed member */ );
1538 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1539 ip4_header_t /* cheat */ ,
1540 length /* changed member */ );
1541 tcp0->checksum = ip_csum_fold (sum0);
1545 old_port0 = udp0->dst_port;
1546 udp0->dst_port = s0->in2out.port;
1552 nat44_session_update_counters (s0, now,
1553 vlib_buffer_length_in_chain (vm,
1555 /* Per-user LRU list maintenance */
1556 nat44_session_update_lru (sm, s0, thread_index);
1559 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1560 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1562 nat44_reass_trace_t *t =
1563 vlib_add_trace (vm, node, b0, sizeof (*t));
1564 t->cached = cached0;
1565 t->sw_if_index = sw_if_index0;
1566 t->next_index = next0;
1576 pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1578 /* verify speculative enqueue, maybe switch current next frame */
1579 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1580 to_next, n_left_to_next,
1584 if (n_left_from == 0 && vec_len (fragments_to_loopback))
1586 from = vlib_frame_vector_args (frame);
1587 u32 len = vec_len (fragments_to_loopback);
1588 if (len <= VLIB_FRAME_SIZE)
1590 clib_memcpy_fast (from, fragments_to_loopback,
1591 sizeof (u32) * len);
1593 vec_reset_length (fragments_to_loopback);
1597 clib_memcpy_fast (from, fragments_to_loopback +
1598 (len - VLIB_FRAME_SIZE),
1599 sizeof (u32) * VLIB_FRAME_SIZE);
1600 n_left_from = VLIB_FRAME_SIZE;
1601 _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1606 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1609 vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1610 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1613 nat_send_all_to_node (vm, fragments_to_drop, node,
1614 &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1615 SNAT_OUT2IN_NEXT_DROP);
1617 vec_free (fragments_to_drop);
1618 vec_free (fragments_to_loopback);
1619 return frame->n_vectors;
1623 VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
1624 .function = nat44_out2in_reass_node_fn,
1625 .name = "nat44-out2in-reass",
1626 .vector_size = sizeof (u32),
1627 .format_trace = format_nat44_reass_trace,
1628 .type = VLIB_NODE_TYPE_INTERNAL,
1630 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1631 .error_strings = snat_out2in_error_strings,
1633 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1635 /* edit / add dispositions here */
1637 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1638 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1639 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1640 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1645 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
1646 nat44_out2in_reass_node_fn);
1649 snat_out2in_fast_node_fn (vlib_main_t * vm,
1650 vlib_node_runtime_t * node, vlib_frame_t * frame)
1652 u32 n_left_from, *from, *to_next;
1653 snat_out2in_next_t next_index;
1654 u32 pkts_processed = 0;
1655 snat_main_t *sm = &snat_main;
1657 from = vlib_frame_vector_args (frame);
1658 n_left_from = frame->n_vectors;
1659 next_index = node->cached_next_index;
1661 while (n_left_from > 0)
1665 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1667 while (n_left_from > 0 && n_left_to_next > 0)
1671 u32 next0 = SNAT_OUT2IN_NEXT_DROP;
1675 u32 new_addr0, old_addr0;
1676 u16 new_port0, old_port0;
1679 icmp46_header_t *icmp0;
1680 snat_session_key_t key0, sm0;
1684 /* speculatively enqueue b0 to the current next frame */
1690 n_left_to_next -= 1;
1692 b0 = vlib_get_buffer (vm, bi0);
1694 ip0 = vlib_buffer_get_current (b0);
1695 udp0 = ip4_next_header (ip0);
1696 tcp0 = (tcp_header_t *) udp0;
1697 icmp0 = (icmp46_header_t *) udp0;
1699 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1701 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1703 vnet_feature_next (&next0, b0);
1705 if (PREDICT_FALSE (ip0->ttl == 1))
1707 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1708 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1709 ICMP4_time_exceeded_ttl_exceeded_in_transit,
1711 next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1715 proto0 = ip_proto_to_snat_proto (ip0->protocol);
1717 if (PREDICT_FALSE (proto0 == ~0))
1720 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1722 next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0,
1723 rx_fib_index0, node, next0, ~0, 0, 0);
1727 key0.addr = ip0->dst_address;
1728 key0.port = udp0->dst_port;
1729 key0.fib_index = rx_fib_index0;
1731 if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
1733 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1737 new_addr0 = sm0.addr.as_u32;
1738 new_port0 = sm0.port;
1739 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
1740 old_addr0 = ip0->dst_address.as_u32;
1741 ip0->dst_address.as_u32 = new_addr0;
1743 sum0 = ip0->checksum;
1744 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1746 dst_address /* changed member */ );
1747 ip0->checksum = ip_csum_fold (sum0);
1749 if (PREDICT_FALSE (new_port0 != udp0->dst_port))
1751 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1753 old_port0 = tcp0->dst_port;
1754 tcp0->dst_port = new_port0;
1756 sum0 = tcp0->checksum;
1757 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1759 dst_address /* changed member */ );
1761 sum0 = ip_csum_update (sum0, old_port0, new_port0,
1762 ip4_header_t /* cheat */ ,
1763 length /* changed member */ );
1764 tcp0->checksum = ip_csum_fold (sum0);
1768 old_port0 = udp0->dst_port;
1769 udp0->dst_port = new_port0;
1775 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
1777 sum0 = tcp0->checksum;
1778 sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1780 dst_address /* changed member */ );
1782 tcp0->checksum = ip_csum_fold (sum0);
1788 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1789 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1791 snat_out2in_trace_t *t =
1792 vlib_add_trace (vm, node, b0, sizeof (*t));
1793 t->sw_if_index = sw_if_index0;
1794 t->next_index = next0;
1797 pkts_processed += next0 != SNAT_OUT2IN_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_out2in_fast_node.index,
1809 SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1811 return frame->n_vectors;
1815 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
1816 .function = snat_out2in_fast_node_fn,
1817 .name = "nat44-out2in-fast",
1818 .vector_size = sizeof (u32),
1819 .format_trace = format_snat_out2in_fast_trace,
1820 .type = VLIB_NODE_TYPE_INTERNAL,
1822 .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1823 .error_strings = snat_out2in_error_strings,
1825 .runtime_data_bytes = sizeof (snat_runtime_t),
1827 .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1829 /* edit / add dispositions here */
1831 [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1832 [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1833 [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1834 [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1839 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node,
1840 snat_out2in_fast_node_fn);
1843 * fd.io coding-style-patch-verification: ON
1846 * eval: (c-set-style "gnu")