2 * Copyright (c) 2018 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 * @brief Deterministic/CGN NAT44 inside to outside network translation
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/ip/ip.h>
23 #include <vnet/fib/ip4_fib.h>
24 #include <vppinfra/error.h>
25 #include <vppinfra/elog.h>
27 #include <nat/nat_det.h>
28 #include <nat/nat_inlines.h>
35 } nat_det_in2out_trace_t;
39 NAT_DET_IN2OUT_NEXT_LOOKUP,
40 NAT_DET_IN2OUT_NEXT_DROP,
41 NAT_DET_IN2OUT_NEXT_ICMP_ERROR,
42 NAT_DET_IN2OUT_N_NEXT,
43 } nat_det_in2out_next_t;
45 #define foreach_nat_det_in2out_error \
46 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
47 _(NO_TRANSLATION, "No translation") \
48 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
49 _(OUT_OF_PORTS, "Out of ports") \
50 _(IN2OUT_PACKETS, "Good in2out packets processed")
54 #define _(sym,str) NAT_DET_IN2OUT_ERROR_##sym,
55 foreach_nat_det_in2out_error
57 NAT_DET_IN2OUT_N_ERROR,
58 } nat_det_in2out_error_t;
60 static char *nat_det_in2out_error_strings[] = {
61 #define _(sym,string) string,
62 foreach_nat_det_in2out_error
66 vlib_node_registration_t snat_det_in2out_node;
69 format_nat_det_in2out_trace (u8 * s, va_list * args)
71 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
72 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
73 nat_det_in2out_trace_t *t = va_arg (*args, nat_det_in2out_trace_t *);
75 s = format (s, "NAT_DET_IN2OUT: sw_if_index %d, next index %d, session %d",
76 t->sw_if_index, t->next_index, t->session_index);
82 * Get address and port values to be used for ICMP packet translation
83 * and create session if needed
85 * @param[in,out] sm NAT main
86 * @param[in,out] node NAT node runtime
87 * @param[in] thread_index thread index
88 * @param[in,out] b0 buffer containing packet to be translated
89 * @param[out] p_proto protocol used for matching
90 * @param[out] p_value address and port after NAT translation
91 * @param[out] p_dont_translate if packet should not be translated
92 * @param d optional parameter
93 * @param e optional parameter
96 icmp_match_in2out_det (snat_main_t * sm, vlib_node_runtime_t * node,
97 u32 thread_index, vlib_buffer_t * b0,
98 ip4_header_t * ip0, u8 * p_proto,
99 snat_session_key_t * p_value,
100 u8 * p_dont_translate, void *d, void *e)
102 icmp46_header_t *icmp0;
106 snat_det_out_key_t key0;
107 u8 dont_translate = 0;
109 icmp_echo_header_t *echo0, *inner_echo0 = 0;
110 ip4_header_t *inner_ip0;
112 icmp46_header_t *inner_icmp0;
113 snat_det_map_t *dm0 = 0;
114 ip4_address_t new_addr0;
116 snat_det_session_t *ses0 = 0;
117 ip4_address_t in_addr;
120 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
121 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
122 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
123 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
125 if (!icmp_is_error_message (icmp0))
127 protocol = SNAT_PROTOCOL_ICMP;
128 in_addr = ip0->src_address;
129 in_port = echo0->identifier;
133 inner_ip0 = (ip4_header_t *) (echo0 + 1);
134 l4_header = ip4_next_header (inner_ip0);
135 protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
136 in_addr = inner_ip0->dst_address;
139 case SNAT_PROTOCOL_ICMP:
140 inner_icmp0 = (icmp46_header_t *) l4_header;
141 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
142 in_port = inner_echo0->identifier;
144 case SNAT_PROTOCOL_UDP:
145 case SNAT_PROTOCOL_TCP:
146 in_port = ((tcp_udp_header_t *) l4_header)->dst_port;
149 b0->error = node->errors[NAT_DET_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
150 next0 = NAT_DET_IN2OUT_NEXT_DROP;
155 dm0 = snat_det_map_by_user (sm, &in_addr);
156 if (PREDICT_FALSE (!dm0))
158 nat_log_info ("no match for internal host %U",
159 format_ip4_address, &in_addr);
160 if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
167 next0 = NAT_DET_IN2OUT_NEXT_DROP;
168 b0->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
172 snat_det_forward (dm0, &in_addr, &new_addr0, &lo_port0);
174 key0.ext_host_addr = ip0->dst_address;
175 key0.ext_host_port = 0;
177 ses0 = snat_det_find_ses_by_in (dm0, &in_addr, in_port, key0);
178 if (PREDICT_FALSE (!ses0))
180 if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
187 if (icmp0->type != ICMP4_echo_request)
189 b0->error = node->errors[NAT_DET_IN2OUT_ERROR_BAD_ICMP_TYPE];
190 next0 = NAT_DET_IN2OUT_NEXT_DROP;
193 for (i0 = 0; i0 < dm0->ports_per_host; i0++)
195 key0.out_port = clib_host_to_net_u16 (lo_port0 +
198 (echo0->identifier)) %
199 dm0->ports_per_host));
201 if (snat_det_get_ses_by_out (dm0, &in_addr, key0.as_u64))
205 snat_det_ses_create (dm0, &in_addr, echo0->identifier, &key0);
208 if (PREDICT_FALSE (!ses0))
210 next0 = NAT_DET_IN2OUT_NEXT_DROP;
211 b0->error = node->errors[NAT_DET_IN2OUT_ERROR_OUT_OF_PORTS];
216 if (PREDICT_FALSE (icmp0->type != ICMP4_echo_request &&
217 !icmp_is_error_message (icmp0)))
219 b0->error = node->errors[NAT_DET_IN2OUT_ERROR_BAD_ICMP_TYPE];
220 next0 = NAT_DET_IN2OUT_NEXT_DROP;
224 u32 now = (u32) vlib_time_now (sm->vlib_main);
226 ses0->state = SNAT_SESSION_ICMP_ACTIVE;
227 ses0->expire = now + sm->icmp_timeout;
233 p_value->addr = new_addr0;
234 p_value->fib_index = sm->outside_fib_index;
235 p_value->port = ses0->out.out_port;
237 *p_dont_translate = dont_translate;
239 *(snat_det_session_t **) d = ses0;
241 *(snat_det_map_t **) e = dm0;
246 snat_det_in2out_node_fn (vlib_main_t * vm,
247 vlib_node_runtime_t * node, vlib_frame_t * frame)
249 u32 n_left_from, *from, *to_next;
250 nat_det_in2out_next_t next_index;
251 u32 pkts_processed = 0;
252 snat_main_t *sm = &snat_main;
253 u32 now = (u32) vlib_time_now (vm);
254 u32 thread_index = vm->thread_index;
256 from = vlib_frame_vector_args (frame);
257 n_left_from = frame->n_vectors;
258 next_index = node->cached_next_index;
260 while (n_left_from > 0)
264 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
266 while (n_left_from >= 4 && n_left_to_next >= 2)
269 vlib_buffer_t *b0, *b1;
271 u32 sw_if_index0, sw_if_index1;
272 ip4_header_t *ip0, *ip1;
273 ip_csum_t sum0, sum1;
274 ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
275 u16 old_port0, new_port0, lo_port0, i0;
276 u16 old_port1, new_port1, lo_port1, i1;
277 udp_header_t *udp0, *udp1;
278 tcp_header_t *tcp0, *tcp1;
280 snat_det_out_key_t key0, key1;
281 snat_det_map_t *dm0, *dm1;
282 snat_det_session_t *ses0 = 0, *ses1 = 0;
283 u32 rx_fib_index0, rx_fib_index1;
284 icmp46_header_t *icmp0, *icmp1;
286 /* Prefetch next iteration. */
288 vlib_buffer_t *p2, *p3;
290 p2 = vlib_get_buffer (vm, from[2]);
291 p3 = vlib_get_buffer (vm, from[3]);
293 vlib_prefetch_buffer_header (p2, LOAD);
294 vlib_prefetch_buffer_header (p3, LOAD);
296 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
297 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
300 /* speculatively enqueue b0 and b1 to the current next frame */
301 to_next[0] = bi0 = from[0];
302 to_next[1] = bi1 = from[1];
308 b0 = vlib_get_buffer (vm, bi0);
309 b1 = vlib_get_buffer (vm, bi1);
311 next0 = NAT_DET_IN2OUT_NEXT_LOOKUP;
312 next1 = NAT_DET_IN2OUT_NEXT_LOOKUP;
314 ip0 = vlib_buffer_get_current (b0);
315 udp0 = ip4_next_header (ip0);
316 tcp0 = (tcp_header_t *) udp0;
318 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
320 if (PREDICT_FALSE (ip0->ttl == 1))
322 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
323 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
324 ICMP4_time_exceeded_ttl_exceeded_in_transit,
326 next0 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
330 proto0 = ip_proto_to_snat_proto (ip0->protocol);
332 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
335 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
336 icmp0 = (icmp46_header_t *) udp0;
338 next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0,
339 rx_fib_index0, node, next0, thread_index,
344 dm0 = snat_det_map_by_user (sm, &ip0->src_address);
345 if (PREDICT_FALSE (!dm0))
347 nat_log_info ("no match for internal host %U",
348 format_ip4_address, &ip0->src_address);
349 next0 = NAT_DET_IN2OUT_NEXT_DROP;
350 b0->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
354 snat_det_forward (dm0, &ip0->src_address, &new_addr0, &lo_port0);
356 key0.ext_host_addr = ip0->dst_address;
357 key0.ext_host_port = tcp0->dst;
360 snat_det_find_ses_by_in (dm0, &ip0->src_address, tcp0->src, key0);
361 if (PREDICT_FALSE (!ses0))
363 for (i0 = 0; i0 < dm0->ports_per_host; i0++)
365 key0.out_port = clib_host_to_net_u16 (lo_port0 +
372 if (snat_det_get_ses_by_out
373 (dm0, &ip0->src_address, key0.as_u64))
377 snat_det_ses_create (dm0, &ip0->src_address, tcp0->src,
381 if (PREDICT_FALSE (!ses0))
383 /* too many sessions for user, send ICMP error packet */
384 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
385 icmp4_error_set_vnet_buffer (b0,
386 ICMP4_destination_unreachable,
387 ICMP4_destination_unreachable_destination_unreachable_host,
389 next0 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
394 new_port0 = ses0->out.out_port;
396 old_addr0.as_u32 = ip0->src_address.as_u32;
397 ip0->src_address.as_u32 = new_addr0.as_u32;
398 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
400 sum0 = ip0->checksum;
401 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
403 src_address /* changed member */ );
404 ip0->checksum = ip_csum_fold (sum0);
406 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
408 if (tcp0->flags & TCP_FLAG_SYN)
409 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
410 else if (tcp0->flags & TCP_FLAG_ACK
411 && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
412 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
413 else if (tcp0->flags & TCP_FLAG_FIN
414 && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
415 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
416 else if (tcp0->flags & TCP_FLAG_ACK
417 && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
418 snat_det_ses_close (dm0, ses0);
419 else if (tcp0->flags & TCP_FLAG_FIN
420 && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
421 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
422 else if (tcp0->flags == 0
423 && ses0->state == SNAT_SESSION_UNKNOWN)
424 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
426 old_port0 = tcp0->src;
427 tcp0->src = new_port0;
429 sum0 = tcp0->checksum;
430 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
432 dst_address /* changed member */ );
433 sum0 = ip_csum_update (sum0, old_port0, new_port0,
434 ip4_header_t /* cheat */ ,
435 length /* changed member */ );
436 mss_clamping (sm, tcp0, &sum0);
437 tcp0->checksum = ip_csum_fold (sum0);
441 ses0->state = SNAT_SESSION_UDP_ACTIVE;
442 old_port0 = udp0->src_port;
443 udp0->src_port = new_port0;
449 case SNAT_SESSION_UDP_ACTIVE:
450 ses0->expire = now + sm->udp_timeout;
452 case SNAT_SESSION_TCP_SYN_SENT:
453 case SNAT_SESSION_TCP_FIN_WAIT:
454 case SNAT_SESSION_TCP_CLOSE_WAIT:
455 case SNAT_SESSION_TCP_LAST_ACK:
456 ses0->expire = now + sm->tcp_transitory_timeout;
458 case SNAT_SESSION_TCP_ESTABLISHED:
459 ses0->expire = now + sm->tcp_established_timeout;
464 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
465 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
467 nat_det_in2out_trace_t *t =
468 vlib_add_trace (vm, node, b0, sizeof (*t));
469 t->sw_if_index = sw_if_index0;
470 t->next_index = next0;
471 t->session_index = ~0;
473 t->session_index = ses0 - dm0->sessions;
476 pkts_processed += next0 != NAT_DET_IN2OUT_NEXT_DROP;
478 ip1 = vlib_buffer_get_current (b1);
479 udp1 = ip4_next_header (ip1);
480 tcp1 = (tcp_header_t *) udp1;
482 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
484 if (PREDICT_FALSE (ip1->ttl == 1))
486 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
487 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
488 ICMP4_time_exceeded_ttl_exceeded_in_transit,
490 next1 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
494 proto1 = ip_proto_to_snat_proto (ip1->protocol);
496 if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
499 ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
500 icmp1 = (icmp46_header_t *) udp1;
502 next1 = icmp_in2out (sm, b1, ip1, icmp1, sw_if_index1,
503 rx_fib_index1, node, next1, thread_index,
508 dm1 = snat_det_map_by_user (sm, &ip1->src_address);
509 if (PREDICT_FALSE (!dm1))
511 nat_log_info ("no match for internal host %U",
512 format_ip4_address, &ip0->src_address);
513 next1 = NAT_DET_IN2OUT_NEXT_DROP;
514 b1->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
518 snat_det_forward (dm1, &ip1->src_address, &new_addr1, &lo_port1);
520 key1.ext_host_addr = ip1->dst_address;
521 key1.ext_host_port = tcp1->dst;
524 snat_det_find_ses_by_in (dm1, &ip1->src_address, tcp1->src, key1);
525 if (PREDICT_FALSE (!ses1))
527 for (i1 = 0; i1 < dm1->ports_per_host; i1++)
529 key1.out_port = clib_host_to_net_u16 (lo_port1 +
536 if (snat_det_get_ses_by_out
537 (dm1, &ip1->src_address, key1.as_u64))
541 snat_det_ses_create (dm1, &ip1->src_address, tcp1->src,
545 if (PREDICT_FALSE (!ses1))
547 /* too many sessions for user, send ICMP error packet */
548 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
549 icmp4_error_set_vnet_buffer (b1,
550 ICMP4_destination_unreachable,
551 ICMP4_destination_unreachable_destination_unreachable_host,
553 next1 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
558 new_port1 = ses1->out.out_port;
560 old_addr1.as_u32 = ip1->src_address.as_u32;
561 ip1->src_address.as_u32 = new_addr1.as_u32;
562 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
564 sum1 = ip1->checksum;
565 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
567 src_address /* changed member */ );
568 ip1->checksum = ip_csum_fold (sum1);
570 if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
572 if (tcp1->flags & TCP_FLAG_SYN)
573 ses1->state = SNAT_SESSION_TCP_SYN_SENT;
574 else if (tcp1->flags & TCP_FLAG_ACK
575 && ses1->state == SNAT_SESSION_TCP_SYN_SENT)
576 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
577 else if (tcp1->flags & TCP_FLAG_FIN
578 && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
579 ses1->state = SNAT_SESSION_TCP_FIN_WAIT;
580 else if (tcp1->flags & TCP_FLAG_ACK
581 && ses1->state == SNAT_SESSION_TCP_FIN_WAIT)
582 snat_det_ses_close (dm1, ses1);
583 else if (tcp1->flags & TCP_FLAG_FIN
584 && ses1->state == SNAT_SESSION_TCP_CLOSE_WAIT)
585 ses1->state = SNAT_SESSION_TCP_LAST_ACK;
586 else if (tcp1->flags == 0
587 && ses1->state == SNAT_SESSION_UNKNOWN)
588 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
590 old_port1 = tcp1->src;
591 tcp1->src = new_port1;
593 sum1 = tcp1->checksum;
594 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
596 dst_address /* changed member */ );
597 sum1 = ip_csum_update (sum1, old_port1, new_port1,
598 ip4_header_t /* cheat */ ,
599 length /* changed member */ );
600 mss_clamping (sm, tcp1, &sum1);
601 tcp1->checksum = ip_csum_fold (sum1);
605 ses1->state = SNAT_SESSION_UDP_ACTIVE;
606 old_port1 = udp1->src_port;
607 udp1->src_port = new_port1;
613 case SNAT_SESSION_UDP_ACTIVE:
614 ses1->expire = now + sm->udp_timeout;
616 case SNAT_SESSION_TCP_SYN_SENT:
617 case SNAT_SESSION_TCP_FIN_WAIT:
618 case SNAT_SESSION_TCP_CLOSE_WAIT:
619 case SNAT_SESSION_TCP_LAST_ACK:
620 ses1->expire = now + sm->tcp_transitory_timeout;
622 case SNAT_SESSION_TCP_ESTABLISHED:
623 ses1->expire = now + sm->tcp_established_timeout;
628 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
629 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
631 nat_det_in2out_trace_t *t =
632 vlib_add_trace (vm, node, b1, sizeof (*t));
633 t->sw_if_index = sw_if_index1;
634 t->next_index = next1;
635 t->session_index = ~0;
637 t->session_index = ses1 - dm1->sessions;
640 pkts_processed += next1 != NAT_DET_IN2OUT_NEXT_DROP;
642 /* verify speculative enqueues, maybe switch current next frame */
643 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
644 to_next, n_left_to_next,
645 bi0, bi1, next0, next1);
648 while (n_left_from > 0 && n_left_to_next > 0)
656 ip4_address_t new_addr0, old_addr0;
657 u16 old_port0, new_port0, lo_port0, i0;
661 snat_det_out_key_t key0;
663 snat_det_session_t *ses0 = 0;
665 icmp46_header_t *icmp0;
667 /* speculatively enqueue b0 to the current next frame */
675 b0 = vlib_get_buffer (vm, bi0);
676 next0 = NAT_DET_IN2OUT_NEXT_LOOKUP;
678 ip0 = vlib_buffer_get_current (b0);
679 udp0 = ip4_next_header (ip0);
680 tcp0 = (tcp_header_t *) udp0;
682 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
684 if (PREDICT_FALSE (ip0->ttl == 1))
686 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
687 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
688 ICMP4_time_exceeded_ttl_exceeded_in_transit,
690 next0 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
694 proto0 = ip_proto_to_snat_proto (ip0->protocol);
696 if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
699 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
700 icmp0 = (icmp46_header_t *) udp0;
702 next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0,
703 rx_fib_index0, node, next0, thread_index,
708 dm0 = snat_det_map_by_user (sm, &ip0->src_address);
709 if (PREDICT_FALSE (!dm0))
711 nat_log_info ("no match for internal host %U",
712 format_ip4_address, &ip0->src_address);
713 next0 = NAT_DET_IN2OUT_NEXT_DROP;
714 b0->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
718 snat_det_forward (dm0, &ip0->src_address, &new_addr0, &lo_port0);
720 key0.ext_host_addr = ip0->dst_address;
721 key0.ext_host_port = tcp0->dst;
724 snat_det_find_ses_by_in (dm0, &ip0->src_address, tcp0->src, key0);
725 if (PREDICT_FALSE (!ses0))
727 for (i0 = 0; i0 < dm0->ports_per_host; i0++)
729 key0.out_port = clib_host_to_net_u16 (lo_port0 +
736 if (snat_det_get_ses_by_out
737 (dm0, &ip0->src_address, key0.as_u64))
741 snat_det_ses_create (dm0, &ip0->src_address, tcp0->src,
745 if (PREDICT_FALSE (!ses0))
747 /* too many sessions for user, send ICMP error packet */
748 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
749 icmp4_error_set_vnet_buffer (b0,
750 ICMP4_destination_unreachable,
751 ICMP4_destination_unreachable_destination_unreachable_host,
753 next0 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
758 new_port0 = ses0->out.out_port;
760 old_addr0.as_u32 = ip0->src_address.as_u32;
761 ip0->src_address.as_u32 = new_addr0.as_u32;
762 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
764 sum0 = ip0->checksum;
765 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
767 src_address /* changed member */ );
768 ip0->checksum = ip_csum_fold (sum0);
770 if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
772 if (tcp0->flags & TCP_FLAG_SYN)
773 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
774 else if (tcp0->flags & TCP_FLAG_ACK
775 && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
776 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
777 else if (tcp0->flags & TCP_FLAG_FIN
778 && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
779 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
780 else if (tcp0->flags & TCP_FLAG_ACK
781 && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
782 snat_det_ses_close (dm0, ses0);
783 else if (tcp0->flags & TCP_FLAG_FIN
784 && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
785 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
786 else if (tcp0->flags == 0
787 && ses0->state == SNAT_SESSION_UNKNOWN)
788 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
790 old_port0 = tcp0->src;
791 tcp0->src = new_port0;
793 sum0 = tcp0->checksum;
794 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
796 dst_address /* changed member */ );
797 sum0 = ip_csum_update (sum0, old_port0, new_port0,
798 ip4_header_t /* cheat */ ,
799 length /* changed member */ );
800 mss_clamping (sm, tcp0, &sum0);
801 tcp0->checksum = ip_csum_fold (sum0);
805 ses0->state = SNAT_SESSION_UDP_ACTIVE;
806 old_port0 = udp0->src_port;
807 udp0->src_port = new_port0;
813 case SNAT_SESSION_UDP_ACTIVE:
814 ses0->expire = now + sm->udp_timeout;
816 case SNAT_SESSION_TCP_SYN_SENT:
817 case SNAT_SESSION_TCP_FIN_WAIT:
818 case SNAT_SESSION_TCP_CLOSE_WAIT:
819 case SNAT_SESSION_TCP_LAST_ACK:
820 ses0->expire = now + sm->tcp_transitory_timeout;
822 case SNAT_SESSION_TCP_ESTABLISHED:
823 ses0->expire = now + sm->tcp_established_timeout;
828 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
829 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
831 nat_det_in2out_trace_t *t =
832 vlib_add_trace (vm, node, b0, sizeof (*t));
833 t->sw_if_index = sw_if_index0;
834 t->next_index = next0;
835 t->session_index = ~0;
837 t->session_index = ses0 - dm0->sessions;
840 pkts_processed += next0 != NAT_DET_IN2OUT_NEXT_DROP;
842 /* verify speculative enqueue, maybe switch current next frame */
843 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
844 to_next, n_left_to_next,
848 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
851 vlib_node_increment_counter (vm, snat_det_in2out_node.index,
852 NAT_DET_IN2OUT_ERROR_IN2OUT_PACKETS,
854 return frame->n_vectors;
858 VLIB_REGISTER_NODE (snat_det_in2out_node) = {
859 .function = snat_det_in2out_node_fn,
860 .name = "nat44-det-in2out",
861 .vector_size = sizeof (u32),
862 .format_trace = format_nat_det_in2out_trace,
863 .type = VLIB_NODE_TYPE_INTERNAL,
864 .n_errors = ARRAY_LEN(nat_det_in2out_error_strings),
865 .error_strings = nat_det_in2out_error_strings,
866 .n_next_nodes = NAT_DET_IN2OUT_N_NEXT,
867 /* edit / add dispositions here */
869 [NAT_DET_IN2OUT_NEXT_DROP] = "error-drop",
870 [NAT_DET_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
871 [NAT_DET_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
876 VLIB_NODE_FUNCTION_MULTIARCH (snat_det_in2out_node, snat_det_in2out_node_fn);
879 * fd.io coding-style-patch-verification: ON
882 * eval: (c-set-style "gnu")