2 * Copyright (c) 2020 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.
18 * @brief Deterministic NAT (CGN) inside to outside translation
21 #include <vlib/vlib.h>
22 #include <vnet/vnet.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <vppinfra/error.h>
26 #include <vppinfra/elog.h>
28 #include <nat/det44/det44.h>
29 #include <nat/det44/det44_inlines.h>
31 #include <nat/lib/lib.h>
32 #include <nat/lib/inlines.h>
33 #include <nat/lib/nat_inlines.h>
37 DET44_IN2OUT_NEXT_LOOKUP,
38 DET44_IN2OUT_NEXT_DROP,
39 DET44_IN2OUT_NEXT_ICMP_ERROR,
41 } det44_in2out_next_t;
48 } det44_in2out_trace_t;
50 #define foreach_det44_in2out_error \
51 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
52 _(NO_TRANSLATION, "No translation") \
53 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
54 _(OUT_OF_PORTS, "Out of ports") \
55 _(IN2OUT_PACKETS, "Good in2out packets processed")
59 #define _(sym,str) DET44_IN2OUT_ERROR_##sym,
60 foreach_det44_in2out_error
63 } det44_in2out_error_t;
65 static char *det44_in2out_error_strings[] = {
66 #define _(sym,string) string,
67 foreach_det44_in2out_error
72 format_det44_in2out_trace (u8 * s, va_list * args)
74 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
75 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
76 det44_in2out_trace_t *t = va_arg (*args, det44_in2out_trace_t *);
78 s = format (s, "DET44_IN2OUT: sw_if_index %d, next index %d, session %d",
79 t->sw_if_index, t->next_index, t->session_index);
84 #ifndef CLIB_MARCH_VARIANT
86 * Get address and port values to be used for ICMP packet translation
87 * and create session if needed
89 * @param[in,out] node NAT node runtime
90 * @param[in] thread_index thread index
91 * @param[in,out] b0 buffer containing packet to be translated
92 * @param[in,out] ip0 ip header
93 * @param[out] p_proto protocol used for matching
94 * @param[out] p_value address and port after NAT translation
95 * @param[out] p_dont_translate if packet should not be translated
96 * @param d optional parameter
97 * @param e optional parameter
100 icmp_match_in2out_det (vlib_node_runtime_t * node,
101 u32 thread_index, vlib_buffer_t * b0,
102 ip4_header_t * ip0, ip4_address_t * addr,
103 u16 * port, u32 * fib_index,
104 nat_protocol_t * proto, void *d, void *e,
107 det44_main_t *dm = &det44_main;
108 vlib_main_t *vm = vlib_get_main ();
109 icmp46_header_t *icmp0;
112 nat_protocol_t protocol;
113 snat_det_out_key_t key0;
115 icmp_echo_header_t *echo0, *inner_echo0 = 0;
116 ip4_header_t *inner_ip0;
118 icmp46_header_t *inner_icmp0;
119 snat_det_map_t *mp0 = 0;
120 ip4_address_t new_addr0;
122 snat_det_session_t *ses0 = 0;
123 ip4_address_t in_addr;
127 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
128 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
129 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
130 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
132 if (!icmp_type_is_error_message
133 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
135 protocol = NAT_PROTOCOL_ICMP;
136 in_addr = ip0->src_address;
137 in_port = vnet_buffer (b0)->ip.reass.l4_src_port;
141 /* if error message, then it's not fragmented and we can access it */
142 inner_ip0 = (ip4_header_t *) (echo0 + 1);
143 l4_header = ip4_next_header (inner_ip0);
144 protocol = ip_proto_to_nat_proto (inner_ip0->protocol);
145 in_addr = inner_ip0->dst_address;
148 case NAT_PROTOCOL_ICMP:
149 inner_icmp0 = (icmp46_header_t *) l4_header;
150 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
151 in_port = inner_echo0->identifier;
153 case NAT_PROTOCOL_UDP:
154 case NAT_PROTOCOL_TCP:
155 in_port = ((tcp_udp_header_t *) l4_header)->dst_port;
158 b0->error = node->errors[DET44_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
159 next0 = DET44_IN2OUT_NEXT_DROP;
164 mp0 = snat_det_map_by_user (&in_addr);
165 if (PREDICT_FALSE (!mp0))
167 if (PREDICT_FALSE (det44_translate (node, sw_if_index0, ip0,
168 IP_PROTOCOL_ICMP, rx_fib_index0)))
173 next0 = DET44_IN2OUT_NEXT_DROP;
174 b0->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
178 snat_det_forward (mp0, &in_addr, &new_addr0, &lo_port0);
180 key0.ext_host_addr = ip0->dst_address;
181 key0.ext_host_port = 0;
183 ses0 = snat_det_find_ses_by_in (mp0, &in_addr, in_port, key0);
184 if (PREDICT_FALSE (!ses0))
186 if (PREDICT_FALSE (det44_translate (node, sw_if_index0, ip0,
187 IP_PROTOCOL_ICMP, rx_fib_index0)))
192 if (icmp0->type != ICMP4_echo_request)
194 b0->error = node->errors[DET44_IN2OUT_ERROR_BAD_ICMP_TYPE];
195 next0 = DET44_IN2OUT_NEXT_DROP;
198 for (i0 = 0; i0 < mp0->ports_per_host; i0++)
200 key0.out_port = clib_host_to_net_u16 (lo_port0 +
203 (echo0->identifier)) %
204 mp0->ports_per_host));
206 if (snat_det_get_ses_by_out (mp0, &in_addr, key0.as_u64))
210 snat_det_ses_create (thread_index, mp0,
211 &in_addr, echo0->identifier, &key0);
214 if (PREDICT_FALSE (!ses0))
216 next0 = DET44_IN2OUT_NEXT_DROP;
217 b0->error = node->errors[DET44_IN2OUT_ERROR_OUT_OF_PORTS];
223 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request
224 && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
225 reass.icmp_type_or_tcp_flags)))
227 b0->error = node->errors[DET44_IN2OUT_ERROR_BAD_ICMP_TYPE];
228 next0 = DET44_IN2OUT_NEXT_DROP;
232 u32 now = (u32) vlib_time_now (vm);
234 ses0->state = DET44_SESSION_ICMP_ACTIVE;
235 ses0->expire = now + dm->timeouts.icmp;
242 *fib_index = dm->outside_fib_index;
243 *port = ses0->out.out_port;
246 *(snat_det_session_t **) d = ses0;
248 *(snat_det_map_t **) e = mp0;
253 #ifndef CLIB_MARCH_VARIANT
255 det44_icmp_in2out (vlib_buffer_t * b0,
257 icmp46_header_t * icmp0,
260 vlib_node_runtime_t * node,
261 u32 next0, u32 thread_index, void *d, void *e)
263 vlib_main_t *vm = vlib_get_main ();
264 u16 old_id0, new_id0, port, checksum0, old_checksum0, new_checksum0;
265 u32 new_addr0, old_addr0, next0_tmp, fib_index;
266 icmp_echo_header_t *echo0, *inner_echo0;
267 icmp46_header_t *inner_icmp0;
268 ip4_header_t *inner_ip0;
273 nat_protocol_t protocol;
275 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
276 next0_tmp = icmp_match_in2out_det (node, thread_index, b0, ip0,
277 &addr, &port, &fib_index, &protocol,
278 d, e, &dont_translate);
281 if (next0 == DET44_IN2OUT_NEXT_DROP || dont_translate)
284 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
287 ip_incremental_checksum_buffer (vm, b0,
289 (u8 *) vlib_buffer_get_current (b0),
290 ntohs (ip0->length) -
291 ip4_header_bytes (ip0), 0);
292 checksum0 = ~ip_csum_fold (sum0);
293 if (PREDICT_FALSE (checksum0 != 0 && checksum0 != 0xffff))
295 next0 = DET44_IN2OUT_NEXT_DROP;
300 old_addr0 = ip0->src_address.as_u32;
301 new_addr0 = ip0->src_address.as_u32 = addr.as_u32;
303 sum0 = ip0->checksum;
304 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
305 src_address /* changed member */ );
306 ip0->checksum = ip_csum_fold (sum0);
308 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
310 if (icmp0->checksum == 0)
311 icmp0->checksum = 0xffff;
313 if (!icmp_type_is_error_message (icmp0->type))
316 if (PREDICT_FALSE (new_id0 != echo0->identifier))
318 old_id0 = echo0->identifier;
320 echo0->identifier = new_id0;
322 sum0 = icmp0->checksum;
324 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
326 icmp0->checksum = ip_csum_fold (sum0);
331 inner_ip0 = (ip4_header_t *) (echo0 + 1);
332 l4_header = ip4_next_header (inner_ip0);
334 if (!ip4_header_checksum_is_valid (inner_ip0))
336 next0 = DET44_IN2OUT_NEXT_DROP;
340 /* update inner destination IP address */
341 old_addr0 = inner_ip0->dst_address.as_u32;
342 inner_ip0->dst_address = addr;
343 new_addr0 = inner_ip0->dst_address.as_u32;
344 sum0 = icmp0->checksum;
345 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
346 dst_address /* changed member */ );
347 icmp0->checksum = ip_csum_fold (sum0);
349 /* update inner IP header checksum */
350 old_checksum0 = inner_ip0->checksum;
351 sum0 = inner_ip0->checksum;
352 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
353 dst_address /* changed member */ );
354 inner_ip0->checksum = ip_csum_fold (sum0);
355 new_checksum0 = inner_ip0->checksum;
356 sum0 = icmp0->checksum;
358 ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t,
360 icmp0->checksum = ip_csum_fold (sum0);
364 case NAT_PROTOCOL_ICMP:
365 inner_icmp0 = (icmp46_header_t *) l4_header;
366 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
368 old_id0 = inner_echo0->identifier;
370 inner_echo0->identifier = new_id0;
372 sum0 = icmp0->checksum;
374 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
376 icmp0->checksum = ip_csum_fold (sum0);
378 case NAT_PROTOCOL_UDP:
379 case NAT_PROTOCOL_TCP:
380 old_id0 = ((tcp_udp_header_t *) l4_header)->dst_port;
382 ((tcp_udp_header_t *) l4_header)->dst_port = new_id0;
384 sum0 = icmp0->checksum;
385 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
387 icmp0->checksum = ip_csum_fold (sum0);
395 if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
396 vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
402 VLIB_NODE_FN (det44_in2out_node) (vlib_main_t * vm,
403 vlib_node_runtime_t * node,
404 vlib_frame_t * frame)
406 u32 n_left_from, *from, *to_next;
407 det44_in2out_next_t next_index;
408 u32 pkts_processed = 0;
409 det44_main_t *dm = &det44_main;
410 u32 now = (u32) vlib_time_now (vm);
411 u32 thread_index = vm->thread_index;
413 from = vlib_frame_vector_args (frame);
414 n_left_from = frame->n_vectors;
415 next_index = node->cached_next_index;
417 while (n_left_from > 0)
421 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
423 while (n_left_from >= 4 && n_left_to_next >= 2)
426 vlib_buffer_t *b0, *b1;
428 u32 sw_if_index0, sw_if_index1;
429 ip4_header_t *ip0, *ip1;
430 ip_csum_t sum0, sum1;
431 ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
432 u16 old_port0, new_port0, lo_port0, i0;
433 u16 old_port1, new_port1, lo_port1, i1;
434 udp_header_t *udp0, *udp1;
435 tcp_header_t *tcp0, *tcp1;
437 snat_det_out_key_t key0, key1;
438 snat_det_map_t *mp0, *mp1;
439 snat_det_session_t *ses0 = 0, *ses1 = 0;
440 u32 rx_fib_index0, rx_fib_index1;
441 icmp46_header_t *icmp0, *icmp1;
443 /* Prefetch next iteration. */
445 vlib_buffer_t *p2, *p3;
447 p2 = vlib_get_buffer (vm, from[2]);
448 p3 = vlib_get_buffer (vm, from[3]);
450 vlib_prefetch_buffer_header (p2, LOAD);
451 vlib_prefetch_buffer_header (p3, LOAD);
453 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
454 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, LOAD);
457 /* speculatively enqueue b0 and b1 to the current next frame */
458 to_next[0] = bi0 = from[0];
459 to_next[1] = bi1 = from[1];
465 b0 = vlib_get_buffer (vm, bi0);
466 b1 = vlib_get_buffer (vm, bi1);
468 next0 = DET44_IN2OUT_NEXT_LOOKUP;
469 next1 = DET44_IN2OUT_NEXT_LOOKUP;
471 ip0 = vlib_buffer_get_current (b0);
472 udp0 = ip4_next_header (ip0);
473 tcp0 = (tcp_header_t *) udp0;
475 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
477 if (PREDICT_FALSE (ip0->ttl == 1))
479 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
480 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
481 ICMP4_time_exceeded_ttl_exceeded_in_transit,
483 next0 = DET44_IN2OUT_NEXT_ICMP_ERROR;
487 proto0 = ip_proto_to_nat_proto (ip0->protocol);
489 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
492 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
493 icmp0 = (icmp46_header_t *) udp0;
496 next0 = det44_icmp_in2out (b0, ip0, icmp0, sw_if_index0,
497 rx_fib_index0, node, next0,
498 thread_index, &ses0, &mp0);
502 mp0 = snat_det_map_by_user (&ip0->src_address);
503 if (PREDICT_FALSE (!mp0))
505 det44_log_info ("no match for internal host %U",
506 format_ip4_address, &ip0->src_address);
507 next0 = DET44_IN2OUT_NEXT_DROP;
508 b0->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
512 snat_det_forward (mp0, &ip0->src_address, &new_addr0, &lo_port0);
514 key0.ext_host_addr = ip0->dst_address;
515 key0.ext_host_port = tcp0->dst;
518 snat_det_find_ses_by_in (mp0, &ip0->src_address, tcp0->src, key0);
519 if (PREDICT_FALSE (!ses0))
521 for (i0 = 0; i0 < mp0->ports_per_host; i0++)
523 key0.out_port = clib_host_to_net_u16 (lo_port0 +
530 if (snat_det_get_ses_by_out
531 (mp0, &ip0->src_address, key0.as_u64))
535 snat_det_ses_create (thread_index, mp0, &ip0->src_address,
539 if (PREDICT_FALSE (!ses0))
541 /* too many sessions for user, send ICMP error packet */
542 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
543 icmp4_error_set_vnet_buffer (b0,
544 ICMP4_destination_unreachable,
545 ICMP4_destination_unreachable_destination_unreachable_host,
547 next0 = DET44_IN2OUT_NEXT_ICMP_ERROR;
552 old_port0 = udp0->src_port;
553 udp0->src_port = new_port0 = ses0->out.out_port;
555 old_addr0.as_u32 = ip0->src_address.as_u32;
556 ip0->src_address.as_u32 = new_addr0.as_u32;
557 vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->outside_fib_index;
559 sum0 = ip0->checksum;
560 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
562 src_address /* changed member */ );
563 ip0->checksum = ip_csum_fold (sum0);
565 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
567 if (tcp0->flags & TCP_FLAG_SYN)
568 ses0->state = DET44_SESSION_TCP_SYN_SENT;
569 else if (tcp0->flags & TCP_FLAG_ACK
570 && ses0->state == DET44_SESSION_TCP_SYN_SENT)
571 ses0->state = DET44_SESSION_TCP_ESTABLISHED;
572 else if (tcp0->flags & TCP_FLAG_FIN
573 && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
574 ses0->state = DET44_SESSION_TCP_FIN_WAIT;
575 else if (tcp0->flags & TCP_FLAG_ACK
576 && ses0->state == DET44_SESSION_TCP_FIN_WAIT)
577 snat_det_ses_close (mp0, ses0);
578 else if (tcp0->flags & TCP_FLAG_FIN
579 && ses0->state == DET44_SESSION_TCP_CLOSE_WAIT)
580 ses0->state = DET44_SESSION_TCP_LAST_ACK;
581 else if (tcp0->flags == 0
582 && ses0->state == DET44_SESSION_UNKNOWN)
583 ses0->state = DET44_SESSION_TCP_ESTABLISHED;
585 sum0 = tcp0->checksum;
586 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
588 dst_address /* changed member */ );
589 sum0 = ip_csum_update (sum0, old_port0, new_port0,
590 ip4_header_t /* cheat */ ,
591 length /* changed member */ );
592 mss_clamping (dm->mss_clamping, tcp0, &sum0);
593 tcp0->checksum = ip_csum_fold (sum0);
597 ses0->state = DET44_SESSION_UDP_ACTIVE;
599 if (PREDICT_FALSE (udp0->checksum))
601 sum0 = udp0->checksum;
603 ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
605 dst_address /* changed member */ );
607 ip_csum_update (sum0, old_port0, new_port0,
608 ip4_header_t /* cheat */ ,
609 length /* changed member */ );
610 udp0->checksum = ip_csum_fold (sum0);
616 case DET44_SESSION_UDP_ACTIVE:
617 ses0->expire = now + dm->timeouts.udp;
619 case DET44_SESSION_TCP_SYN_SENT:
620 case DET44_SESSION_TCP_FIN_WAIT:
621 case DET44_SESSION_TCP_CLOSE_WAIT:
622 case DET44_SESSION_TCP_LAST_ACK:
623 ses0->expire = now + dm->timeouts.tcp.transitory;
625 case DET44_SESSION_TCP_ESTABLISHED:
626 ses0->expire = now + dm->timeouts.tcp.established;
631 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
632 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
634 det44_in2out_trace_t *t =
635 vlib_add_trace (vm, node, b0, sizeof (*t));
636 t->sw_if_index = sw_if_index0;
637 t->next_index = next0;
638 t->session_index = ~0;
640 t->session_index = ses0 - mp0->sessions;
643 pkts_processed += next0 != DET44_IN2OUT_NEXT_DROP;
645 ip1 = vlib_buffer_get_current (b1);
646 udp1 = ip4_next_header (ip1);
647 tcp1 = (tcp_header_t *) udp1;
649 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
651 if (PREDICT_FALSE (ip1->ttl == 1))
653 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
654 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
655 ICMP4_time_exceeded_ttl_exceeded_in_transit,
657 next1 = DET44_IN2OUT_NEXT_ICMP_ERROR;
661 proto1 = ip_proto_to_nat_proto (ip1->protocol);
663 if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
666 ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
667 icmp1 = (icmp46_header_t *) udp1;
669 next1 = det44_icmp_in2out (b1, ip1, icmp1, sw_if_index1,
670 rx_fib_index1, node, next1,
671 thread_index, &ses1, &mp1);
675 mp1 = snat_det_map_by_user (&ip1->src_address);
676 if (PREDICT_FALSE (!mp1))
678 det44_log_info ("no match for internal host %U",
679 format_ip4_address, &ip0->src_address);
680 next1 = DET44_IN2OUT_NEXT_DROP;
681 b1->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
685 snat_det_forward (mp1, &ip1->src_address, &new_addr1, &lo_port1);
687 key1.ext_host_addr = ip1->dst_address;
688 key1.ext_host_port = tcp1->dst;
691 snat_det_find_ses_by_in (mp1, &ip1->src_address, tcp1->src, key1);
692 if (PREDICT_FALSE (!ses1))
694 for (i1 = 0; i1 < mp1->ports_per_host; i1++)
696 key1.out_port = clib_host_to_net_u16 (lo_port1 +
703 if (snat_det_get_ses_by_out
704 (mp1, &ip1->src_address, key1.as_u64))
708 snat_det_ses_create (thread_index, mp1, &ip1->src_address,
712 if (PREDICT_FALSE (!ses1))
714 /* too many sessions for user, send ICMP error packet */
715 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
716 icmp4_error_set_vnet_buffer (b1,
717 ICMP4_destination_unreachable,
718 ICMP4_destination_unreachable_destination_unreachable_host,
720 next1 = DET44_IN2OUT_NEXT_ICMP_ERROR;
725 old_port1 = udp1->src_port;
726 udp1->src_port = new_port1 = ses1->out.out_port;
728 old_addr1.as_u32 = ip1->src_address.as_u32;
729 ip1->src_address.as_u32 = new_addr1.as_u32;
730 vnet_buffer (b1)->sw_if_index[VLIB_TX] = dm->outside_fib_index;
732 sum1 = ip1->checksum;
733 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
735 src_address /* changed member */ );
736 ip1->checksum = ip_csum_fold (sum1);
738 if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
740 if (tcp1->flags & TCP_FLAG_SYN)
741 ses1->state = DET44_SESSION_TCP_SYN_SENT;
742 else if (tcp1->flags & TCP_FLAG_ACK
743 && ses1->state == DET44_SESSION_TCP_SYN_SENT)
744 ses1->state = DET44_SESSION_TCP_ESTABLISHED;
745 else if (tcp1->flags & TCP_FLAG_FIN
746 && ses1->state == DET44_SESSION_TCP_ESTABLISHED)
747 ses1->state = DET44_SESSION_TCP_FIN_WAIT;
748 else if (tcp1->flags & TCP_FLAG_ACK
749 && ses1->state == DET44_SESSION_TCP_FIN_WAIT)
750 snat_det_ses_close (mp1, ses1);
751 else if (tcp1->flags & TCP_FLAG_FIN
752 && ses1->state == DET44_SESSION_TCP_CLOSE_WAIT)
753 ses1->state = DET44_SESSION_TCP_LAST_ACK;
754 else if (tcp1->flags == 0
755 && ses1->state == DET44_SESSION_UNKNOWN)
756 ses1->state = DET44_SESSION_TCP_ESTABLISHED;
758 sum1 = tcp1->checksum;
759 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
761 dst_address /* changed member */ );
762 sum1 = ip_csum_update (sum1, old_port1, new_port1,
763 ip4_header_t /* cheat */ ,
764 length /* changed member */ );
765 mss_clamping (dm->mss_clamping, tcp1, &sum1);
766 tcp1->checksum = ip_csum_fold (sum1);
770 ses1->state = DET44_SESSION_UDP_ACTIVE;
772 if (PREDICT_FALSE (udp1->checksum))
774 sum1 = udp1->checksum;
776 ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
778 dst_address /* changed member */ );
780 ip_csum_update (sum1, old_port1, new_port1,
781 ip4_header_t /* cheat */ ,
782 length /* changed member */ );
783 udp1->checksum = ip_csum_fold (sum1);
789 case DET44_SESSION_UDP_ACTIVE:
790 ses1->expire = now + dm->timeouts.udp;
792 case DET44_SESSION_TCP_SYN_SENT:
793 case DET44_SESSION_TCP_FIN_WAIT:
794 case DET44_SESSION_TCP_CLOSE_WAIT:
795 case DET44_SESSION_TCP_LAST_ACK:
796 ses1->expire = now + dm->timeouts.tcp.transitory;
798 case DET44_SESSION_TCP_ESTABLISHED:
799 ses1->expire = now + dm->timeouts.tcp.established;
804 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
805 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
807 det44_in2out_trace_t *t =
808 vlib_add_trace (vm, node, b1, sizeof (*t));
809 t->sw_if_index = sw_if_index1;
810 t->next_index = next1;
811 t->session_index = ~0;
813 t->session_index = ses1 - mp1->sessions;
816 pkts_processed += next1 != DET44_IN2OUT_NEXT_DROP;
818 /* verify speculative enqueues, maybe switch current next frame */
819 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
820 to_next, n_left_to_next,
821 bi0, bi1, next0, next1);
824 while (n_left_from > 0 && n_left_to_next > 0)
832 ip4_address_t new_addr0, old_addr0;
833 u16 old_port0, new_port0, lo_port0, i0;
837 snat_det_out_key_t key0;
839 snat_det_session_t *ses0 = 0;
841 icmp46_header_t *icmp0;
843 /* speculatively enqueue b0 to the current next frame */
851 b0 = vlib_get_buffer (vm, bi0);
852 next0 = DET44_IN2OUT_NEXT_LOOKUP;
854 ip0 = vlib_buffer_get_current (b0);
855 udp0 = ip4_next_header (ip0);
856 tcp0 = (tcp_header_t *) udp0;
858 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
860 if (PREDICT_FALSE (ip0->ttl == 1))
862 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
863 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
864 ICMP4_time_exceeded_ttl_exceeded_in_transit,
866 next0 = DET44_IN2OUT_NEXT_ICMP_ERROR;
870 proto0 = ip_proto_to_nat_proto (ip0->protocol);
872 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
875 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
876 icmp0 = (icmp46_header_t *) udp0;
878 next0 = det44_icmp_in2out (b0, ip0, icmp0, sw_if_index0,
879 rx_fib_index0, node, next0,
880 thread_index, &ses0, &mp0);
884 mp0 = snat_det_map_by_user (&ip0->src_address);
885 if (PREDICT_FALSE (!mp0))
887 det44_log_info ("no match for internal host %U",
888 format_ip4_address, &ip0->src_address);
889 next0 = DET44_IN2OUT_NEXT_DROP;
890 b0->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
894 snat_det_forward (mp0, &ip0->src_address, &new_addr0, &lo_port0);
896 key0.ext_host_addr = ip0->dst_address;
897 key0.ext_host_port = tcp0->dst;
900 snat_det_find_ses_by_in (mp0, &ip0->src_address, tcp0->src, key0);
901 if (PREDICT_FALSE (!ses0))
903 for (i0 = 0; i0 < mp0->ports_per_host; i0++)
905 key0.out_port = clib_host_to_net_u16 (lo_port0 +
912 if (snat_det_get_ses_by_out
913 (mp0, &ip0->src_address, key0.as_u64))
917 snat_det_ses_create (thread_index, mp0, &ip0->src_address,
921 if (PREDICT_FALSE (!ses0))
923 /* too many sessions for user, send ICMP error packet */
924 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
925 icmp4_error_set_vnet_buffer (b0,
926 ICMP4_destination_unreachable,
927 ICMP4_destination_unreachable_destination_unreachable_host,
929 next0 = DET44_IN2OUT_NEXT_ICMP_ERROR;
934 old_port0 = udp0->src_port;
935 udp0->src_port = new_port0 = ses0->out.out_port;
937 old_addr0.as_u32 = ip0->src_address.as_u32;
938 ip0->src_address.as_u32 = new_addr0.as_u32;
939 vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->outside_fib_index;
941 sum0 = ip0->checksum;
942 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
944 src_address /* changed member */ );
945 ip0->checksum = ip_csum_fold (sum0);
947 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
949 if (tcp0->flags & TCP_FLAG_SYN)
950 ses0->state = DET44_SESSION_TCP_SYN_SENT;
951 else if (tcp0->flags & TCP_FLAG_ACK
952 && ses0->state == DET44_SESSION_TCP_SYN_SENT)
953 ses0->state = DET44_SESSION_TCP_ESTABLISHED;
954 else if (tcp0->flags & TCP_FLAG_FIN
955 && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
956 ses0->state = DET44_SESSION_TCP_FIN_WAIT;
957 else if (tcp0->flags & TCP_FLAG_ACK
958 && ses0->state == DET44_SESSION_TCP_FIN_WAIT)
959 snat_det_ses_close (mp0, ses0);
960 else if (tcp0->flags & TCP_FLAG_FIN
961 && ses0->state == DET44_SESSION_TCP_CLOSE_WAIT)
962 ses0->state = DET44_SESSION_TCP_LAST_ACK;
963 else if (tcp0->flags == 0
964 && ses0->state == DET44_SESSION_UNKNOWN)
965 ses0->state = DET44_SESSION_TCP_ESTABLISHED;
967 sum0 = tcp0->checksum;
968 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
970 dst_address /* changed member */ );
971 sum0 = ip_csum_update (sum0, old_port0, new_port0,
972 ip4_header_t /* cheat */ ,
973 length /* changed member */ );
974 mss_clamping (dm->mss_clamping, tcp0, &sum0);
975 tcp0->checksum = ip_csum_fold (sum0);
979 ses0->state = DET44_SESSION_UDP_ACTIVE;
981 if (PREDICT_FALSE (udp0->checksum))
983 sum0 = udp0->checksum;
985 ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
987 dst_address /* changed member */ );
989 ip_csum_update (sum0, old_port0, new_port0,
990 ip4_header_t /* cheat */ ,
991 length /* changed member */ );
992 udp0->checksum = ip_csum_fold (sum0);
998 case DET44_SESSION_UDP_ACTIVE:
999 ses0->expire = now + dm->timeouts.udp;
1001 case DET44_SESSION_TCP_SYN_SENT:
1002 case DET44_SESSION_TCP_FIN_WAIT:
1003 case DET44_SESSION_TCP_CLOSE_WAIT:
1004 case DET44_SESSION_TCP_LAST_ACK:
1005 ses0->expire = now + dm->timeouts.tcp.transitory;
1007 case DET44_SESSION_TCP_ESTABLISHED:
1008 ses0->expire = now + dm->timeouts.tcp.established;
1013 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1014 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1016 det44_in2out_trace_t *t =
1017 vlib_add_trace (vm, node, b0, sizeof (*t));
1018 t->sw_if_index = sw_if_index0;
1019 t->next_index = next0;
1020 t->session_index = ~0;
1022 t->session_index = ses0 - mp0->sessions;
1025 pkts_processed += next0 != DET44_IN2OUT_NEXT_DROP;
1027 /* verify speculative enqueue, maybe switch current next frame */
1028 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1029 to_next, n_left_to_next,
1033 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1036 vlib_node_increment_counter (vm, dm->in2out_node_index,
1037 DET44_IN2OUT_ERROR_IN2OUT_PACKETS,
1039 return frame->n_vectors;
1043 VLIB_REGISTER_NODE (det44_in2out_node) = {
1044 .name = "det44-in2out",
1045 .vector_size = sizeof (u32),
1046 .format_trace = format_det44_in2out_trace,
1047 .type = VLIB_NODE_TYPE_INTERNAL,
1048 .n_errors = ARRAY_LEN(det44_in2out_error_strings),
1049 .error_strings = det44_in2out_error_strings,
1050 .runtime_data_bytes = sizeof (det44_runtime_t),
1051 .n_next_nodes = DET44_IN2OUT_N_NEXT,
1052 /* edit / add dispositions here */
1054 [DET44_IN2OUT_NEXT_DROP] = "error-drop",
1055 [DET44_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1056 [DET44_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1062 * fd.io coding-style-patch-verification: ON
1065 * eval: (c-set-style "gnu")