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) outside to inside 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_OUT2IN_NEXT_DROP,
38 DET44_OUT2IN_NEXT_LOOKUP,
39 DET44_OUT2IN_NEXT_ICMP_ERROR,
41 } det44_out2in_next_t;
48 } det44_out2in_trace_t;
50 #define foreach_det44_out2in_error \
51 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
52 _(NO_TRANSLATION, "No translation") \
53 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
54 _(OUT2IN_PACKETS, "Good out2in packets processed")
58 #define _(sym,str) DET44_OUT2IN_ERROR_##sym,
59 foreach_det44_out2in_error
62 } det44_out2in_error_t;
64 static char *det44_out2in_error_strings[] = {
65 #define _(sym,string) string,
66 foreach_det44_out2in_error
71 format_det44_out2in_trace (u8 * s, va_list * args)
73 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
74 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
75 det44_out2in_trace_t *t = va_arg (*args, det44_out2in_trace_t *);
79 "DET44_OUT2IN: sw_if_index %d, next index %d, session index %d",
80 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_out2in_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 icmp46_header_t *icmp0;
111 snat_det_out_key_t key0;
113 icmp_echo_header_t *echo0, *inner_echo0 = 0;
114 ip4_header_t *inner_ip0;
116 icmp46_header_t *inner_icmp0;
117 snat_det_map_t *mp0 = 0;
118 ip4_address_t new_addr0 = { {0} };
119 snat_det_session_t *ses0 = 0;
120 ip4_address_t out_addr;
123 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
124 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
125 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
127 if (!icmp_type_is_error_message
128 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
130 protocol = NAT_PROTOCOL_ICMP;
131 key0.ext_host_addr = ip0->src_address;
132 key0.ext_host_port = 0;
133 key0.out_port = vnet_buffer (b0)->ip.reass.l4_src_port;
134 out_addr = ip0->dst_address;
138 /* if error message, then it's not fragmented and we can access it */
139 inner_ip0 = (ip4_header_t *) (echo0 + 1);
140 l4_header = ip4_next_header (inner_ip0);
141 protocol = ip_proto_to_nat_proto (inner_ip0->protocol);
142 key0.ext_host_addr = inner_ip0->dst_address;
143 out_addr = inner_ip0->src_address;
146 case NAT_PROTOCOL_ICMP:
147 inner_icmp0 = (icmp46_header_t *) l4_header;
148 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
149 key0.ext_host_port = 0;
150 key0.out_port = inner_echo0->identifier;
152 case NAT_PROTOCOL_UDP:
153 case NAT_PROTOCOL_TCP:
154 key0.ext_host_port = ((tcp_udp_header_t *) l4_header)->dst_port;
155 key0.out_port = ((tcp_udp_header_t *) l4_header)->src_port;
158 b0->error = node->errors[DET44_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
159 next0 = DET44_OUT2IN_NEXT_DROP;
164 mp0 = snat_det_map_by_out (&out_addr);
165 if (PREDICT_FALSE (!mp0))
167 /* Don't NAT packet aimed at the intfc address */
168 if (PREDICT_FALSE (!det44_is_interface_addr (node, sw_if_index0,
169 ip0->dst_address.as_u32)))
174 det44_log_info ("unknown dst address: %U",
175 format_ip4_address, &ip0->dst_address);
176 b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
177 next0 = DET44_OUT2IN_NEXT_DROP;
182 snat_det_reverse (mp0, &ip0->dst_address,
183 clib_net_to_host_u16 (key0.out_port), &new_addr0);
185 ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
186 if (PREDICT_FALSE (!ses0))
188 /* Don't NAT packet aimed at the intfc address */
189 if (PREDICT_FALSE (!det44_is_interface_addr (node, sw_if_index0,
190 ip0->dst_address.as_u32)))
195 det44_log_info ("no match src %U:%d dst %U:%d for user %U",
196 format_ip4_address, &key0.ext_host_addr,
197 clib_net_to_host_u16 (key0.ext_host_port),
198 format_ip4_address, &out_addr,
199 clib_net_to_host_u16 (key0.out_port),
200 format_ip4_address, &new_addr0);
201 b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
202 next0 = DET44_OUT2IN_NEXT_DROP;
207 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
208 && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
209 reass.icmp_type_or_tcp_flags)))
211 b0->error = node->errors[DET44_OUT2IN_ERROR_BAD_ICMP_TYPE];
212 next0 = DET44_OUT2IN_NEXT_DROP;
223 *fib_index = dm->inside_fib_index;
224 *port = ses0->in_port;
227 *(snat_det_session_t **) d = ses0;
229 *(snat_det_map_t **) e = mp0;
234 #ifndef CLIB_MARCH_VARIANT
236 det44_icmp_out2in (vlib_buffer_t * b0,
238 icmp46_header_t * icmp0,
241 vlib_node_runtime_t * node,
242 u32 next0, u32 thread_index, void *d, void *e)
244 vlib_main_t *vm = vlib_get_main ();
245 u32 new_addr0, old_addr0, next0_tmp, fib_index;
246 u16 old_id0, new_id0, port, checksum0;
247 icmp_echo_header_t *echo0, *inner_echo0;
248 icmp46_header_t *inner_icmp0;
249 ip4_header_t *inner_ip0;
254 nat_protocol_t proto;
256 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
257 next0_tmp = icmp_match_out2in_det (node, thread_index, b0, ip0,
258 &addr, &port, &fib_index, &proto,
259 d, e, &dont_translate);
262 if (next0 == DET44_OUT2IN_NEXT_DROP || dont_translate)
265 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
268 ip_incremental_checksum_buffer (vm, b0,
270 (u8 *) vlib_buffer_get_current (b0),
271 ntohs (ip0->length) -
272 ip4_header_bytes (ip0), 0);
273 checksum0 = ~ip_csum_fold (sum0);
274 if (checksum0 != 0 && checksum0 != 0xffff)
276 next0 = DET44_OUT2IN_NEXT_DROP;
281 old_addr0 = ip0->dst_address.as_u32;
282 new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
283 vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
285 sum0 = ip0->checksum;
286 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
287 dst_address /* changed member */ );
288 ip0->checksum = ip_csum_fold (sum0);
291 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
293 if (icmp0->checksum == 0)
294 icmp0->checksum = 0xffff;
296 if (!icmp_type_is_error_message (icmp0->type))
299 if (PREDICT_FALSE (new_id0 != echo0->identifier))
301 old_id0 = echo0->identifier;
303 echo0->identifier = new_id0;
305 sum0 = icmp0->checksum;
307 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
308 identifier /* changed member */ );
309 icmp0->checksum = ip_csum_fold (sum0);
314 inner_ip0 = (ip4_header_t *) (echo0 + 1);
315 l4_header = ip4_next_header (inner_ip0);
317 if (!ip4_header_checksum_is_valid (inner_ip0))
319 next0 = DET44_OUT2IN_NEXT_DROP;
323 old_addr0 = inner_ip0->src_address.as_u32;
324 inner_ip0->src_address = addr;
325 new_addr0 = inner_ip0->src_address.as_u32;
327 sum0 = icmp0->checksum;
328 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
329 src_address /* changed member */ );
330 icmp0->checksum = ip_csum_fold (sum0);
334 case NAT_PROTOCOL_ICMP:
335 inner_icmp0 = (icmp46_header_t *) l4_header;
336 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
338 old_id0 = inner_echo0->identifier;
340 inner_echo0->identifier = new_id0;
342 sum0 = icmp0->checksum;
344 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
346 icmp0->checksum = ip_csum_fold (sum0);
348 case NAT_PROTOCOL_UDP:
349 case NAT_PROTOCOL_TCP:
350 old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
352 ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
354 sum0 = icmp0->checksum;
355 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
357 icmp0->checksum = ip_csum_fold (sum0);
370 VLIB_NODE_FN (det44_out2in_node) (vlib_main_t * vm,
371 vlib_node_runtime_t * node,
372 vlib_frame_t * frame)
374 u32 n_left_from, *from;
375 u32 pkts_processed = 0;
376 det44_main_t *dm = &det44_main;
377 u32 thread_index = vm->thread_index;
379 from = vlib_frame_vector_args (frame);
380 n_left_from = frame->n_vectors;
382 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
383 u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
384 vlib_get_buffers (vm, from, b, n_left_from);
386 while (n_left_from >= 2)
388 vlib_buffer_t *b0, *b1;
389 u32 next0 = DET44_OUT2IN_NEXT_LOOKUP;
390 u32 next1 = DET44_OUT2IN_NEXT_LOOKUP;
391 u32 sw_if_index0, sw_if_index1;
392 ip4_header_t *ip0, *ip1;
393 ip_csum_t sum0, sum1;
394 ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
395 u16 new_port0, old_port0, old_port1, new_port1;
396 udp_header_t *udp0, *udp1;
397 tcp_header_t *tcp0, *tcp1;
399 snat_det_out_key_t key0, key1;
400 snat_det_map_t *mp0, *mp1;
401 snat_det_session_t *ses0 = 0, *ses1 = 0;
402 u32 rx_fib_index0, rx_fib_index1;
403 icmp46_header_t *icmp0, *icmp1;
410 /* Prefetch next iteration. */
411 if (PREDICT_TRUE (n_left_from >= 4))
413 vlib_buffer_t *p2, *p3;
418 vlib_prefetch_buffer_header (p2, LOAD);
419 vlib_prefetch_buffer_header (p3, LOAD);
421 clib_prefetch_load (p2->data);
422 clib_prefetch_load (p3->data);
426 ip0 = vlib_buffer_get_current (b0);
427 udp0 = ip4_next_header (ip0);
428 tcp0 = (tcp_header_t *) udp0;
430 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
432 if (PREDICT_FALSE (ip0->ttl == 1))
434 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
435 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
436 ICMP4_time_exceeded_ttl_exceeded_in_transit,
438 next0 = DET44_OUT2IN_NEXT_ICMP_ERROR;
442 proto0 = ip_proto_to_nat_proto (ip0->protocol);
444 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
447 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
448 icmp0 = (icmp46_header_t *) udp0;
450 next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
451 rx_fib_index0, node, next0,
452 thread_index, &ses0, &mp0);
456 key0.ext_host_addr = ip0->src_address;
457 key0.ext_host_port = tcp0->src;
458 key0.out_port = tcp0->dst;
460 mp0 = snat_det_map_by_out (&ip0->dst_address);
461 if (PREDICT_FALSE (!mp0))
463 det44_log_info ("unknown dst address: %U",
464 format_ip4_address, &ip0->dst_address);
465 next0 = DET44_OUT2IN_NEXT_DROP;
466 b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
470 snat_det_reverse (mp0, &ip0->dst_address,
471 clib_net_to_host_u16 (tcp0->dst), &new_addr0);
473 ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
474 if (PREDICT_FALSE (!ses0))
476 det44_log_info ("no match src %U:%d dst %U:%d for user %U",
477 format_ip4_address, &ip0->src_address,
478 clib_net_to_host_u16 (tcp0->src),
479 format_ip4_address, &ip0->dst_address,
480 clib_net_to_host_u16 (tcp0->dst),
481 format_ip4_address, &new_addr0);
482 next0 = DET44_OUT2IN_NEXT_DROP;
483 b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
486 old_port0 = udp0->dst_port;
487 udp0->dst_port = new_port0 = ses0->in_port;
489 old_addr0 = ip0->dst_address;
490 ip0->dst_address = new_addr0;
491 vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
493 sum0 = ip0->checksum;
494 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
495 ip4_header_t, dst_address /* changed member */ );
496 ip0->checksum = ip_csum_fold (sum0);
498 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
500 if (tcp0->flags & TCP_FLAG_FIN
501 && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
502 ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
503 else if (tcp0->flags & TCP_FLAG_ACK
504 && ses0->state == DET44_SESSION_TCP_LAST_ACK)
505 snat_det_ses_close (mp0, ses0);
507 sum0 = tcp0->checksum;
508 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
510 dst_address /* changed member */ );
511 sum0 = ip_csum_update (sum0, old_port0, new_port0,
512 ip4_header_t /* cheat */ ,
513 length /* changed member */ );
514 tcp0->checksum = ip_csum_fold (sum0);
516 else if (udp0->checksum)
518 sum0 = udp0->checksum;
519 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
521 dst_address /* changed member */ );
522 sum0 = ip_csum_update (sum0, old_port0, new_port0,
523 ip4_header_t /* cheat */ ,
524 length /* changed member */ );
525 udp0->checksum = ip_csum_fold (sum0);
530 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
531 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
533 det44_out2in_trace_t *t =
534 vlib_add_trace (vm, node, b0, sizeof (*t));
535 t->sw_if_index = sw_if_index0;
536 t->next_index = next0;
537 t->session_index = ~0;
539 t->session_index = ses0 - mp0->sessions;
542 pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
544 ip1 = vlib_buffer_get_current (b1);
545 udp1 = ip4_next_header (ip1);
546 tcp1 = (tcp_header_t *) udp1;
548 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
550 if (PREDICT_FALSE (ip1->ttl == 1))
552 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
553 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
554 ICMP4_time_exceeded_ttl_exceeded_in_transit,
556 next1 = DET44_OUT2IN_NEXT_ICMP_ERROR;
560 proto1 = ip_proto_to_nat_proto (ip1->protocol);
562 if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
565 ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
566 icmp1 = (icmp46_header_t *) udp1;
568 next1 = det44_icmp_out2in (b1, ip1, icmp1, sw_if_index1,
569 rx_fib_index1, node, next1,
570 thread_index, &ses1, &mp1);
574 key1.ext_host_addr = ip1->src_address;
575 key1.ext_host_port = tcp1->src;
576 key1.out_port = tcp1->dst;
578 mp1 = snat_det_map_by_out (&ip1->dst_address);
579 if (PREDICT_FALSE (!mp1))
581 det44_log_info ("unknown dst address: %U",
582 format_ip4_address, &ip1->dst_address);
583 next1 = DET44_OUT2IN_NEXT_DROP;
584 b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
588 snat_det_reverse (mp1, &ip1->dst_address,
589 clib_net_to_host_u16 (tcp1->dst), &new_addr1);
591 ses1 = snat_det_get_ses_by_out (mp1, &new_addr1, key1.as_u64);
592 if (PREDICT_FALSE (!ses1))
594 det44_log_info ("no match src %U:%d dst %U:%d for user %U",
595 format_ip4_address, &ip1->src_address,
596 clib_net_to_host_u16 (tcp1->src),
597 format_ip4_address, &ip1->dst_address,
598 clib_net_to_host_u16 (tcp1->dst),
599 format_ip4_address, &new_addr1);
600 next1 = DET44_OUT2IN_NEXT_DROP;
601 b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
604 old_port1 = udp1->dst_port;
605 udp1->dst_port = new_port1 = ses1->in_port;
607 old_addr1 = ip1->dst_address;
608 ip1->dst_address = new_addr1;
609 vnet_buffer (b1)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
611 sum1 = ip1->checksum;
612 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
613 ip4_header_t, dst_address /* changed member */ );
614 ip1->checksum = ip_csum_fold (sum1);
616 if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
618 if (tcp1->flags & TCP_FLAG_FIN
619 && ses1->state == DET44_SESSION_TCP_ESTABLISHED)
620 ses1->state = DET44_SESSION_TCP_CLOSE_WAIT;
621 else if (tcp1->flags & TCP_FLAG_ACK
622 && ses1->state == DET44_SESSION_TCP_LAST_ACK)
623 snat_det_ses_close (mp1, ses1);
625 sum1 = tcp1->checksum;
626 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
628 dst_address /* changed member */ );
629 sum1 = ip_csum_update (sum1, old_port1, new_port1,
630 ip4_header_t /* cheat */ ,
631 length /* changed member */ );
632 tcp1->checksum = ip_csum_fold (sum1);
634 else if (udp1->checksum)
636 sum1 = udp1->checksum;
637 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
639 dst_address /* changed member */ );
640 sum1 = ip_csum_update (sum1, old_port1, new_port1,
641 ip4_header_t /* cheat */ ,
642 length /* changed member */ );
643 udp1->checksum = ip_csum_fold (sum1);
648 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
649 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
651 det44_out2in_trace_t *t =
652 vlib_add_trace (vm, node, b1, sizeof (*t));
653 t->sw_if_index = sw_if_index1;
654 t->next_index = next1;
655 t->session_index = ~0;
657 t->session_index = ses1 - mp1->sessions;
660 pkts_processed += next1 != DET44_OUT2IN_NEXT_DROP;
668 while (n_left_from > 0)
671 u32 next0 = DET44_OUT2IN_NEXT_LOOKUP;
675 ip4_address_t new_addr0, old_addr0;
676 u16 new_port0, old_port0;
680 snat_det_out_key_t key0;
682 snat_det_session_t *ses0 = 0;
684 icmp46_header_t *icmp0;
689 ip0 = vlib_buffer_get_current (b0);
690 udp0 = ip4_next_header (ip0);
691 tcp0 = (tcp_header_t *) udp0;
693 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
695 if (PREDICT_FALSE (ip0->ttl == 1))
697 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
698 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
699 ICMP4_time_exceeded_ttl_exceeded_in_transit,
701 next0 = DET44_OUT2IN_NEXT_ICMP_ERROR;
705 proto0 = ip_proto_to_nat_proto (ip0->protocol);
707 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
710 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
711 icmp0 = (icmp46_header_t *) udp0;
713 next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
714 rx_fib_index0, node, next0,
715 thread_index, &ses0, &mp0);
719 key0.ext_host_addr = ip0->src_address;
720 key0.ext_host_port = tcp0->src;
721 key0.out_port = tcp0->dst;
723 mp0 = snat_det_map_by_out (&ip0->dst_address);
724 if (PREDICT_FALSE (!mp0))
726 det44_log_info ("unknown dst address: %U",
727 format_ip4_address, &ip0->dst_address);
728 next0 = DET44_OUT2IN_NEXT_DROP;
729 b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
733 snat_det_reverse (mp0, &ip0->dst_address,
734 clib_net_to_host_u16 (tcp0->dst), &new_addr0);
736 ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
737 if (PREDICT_FALSE (!ses0))
739 det44_log_info ("no match src %U:%d dst %U:%d for user %U",
740 format_ip4_address, &ip0->src_address,
741 clib_net_to_host_u16 (tcp0->src),
742 format_ip4_address, &ip0->dst_address,
743 clib_net_to_host_u16 (tcp0->dst),
744 format_ip4_address, &new_addr0);
745 next0 = DET44_OUT2IN_NEXT_DROP;
746 b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
749 old_port0 = udp0->dst_port;
750 udp0->dst_port = new_port0 = ses0->in_port;
752 old_addr0 = ip0->dst_address;
753 ip0->dst_address = new_addr0;
754 vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
756 sum0 = ip0->checksum;
757 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
758 ip4_header_t, dst_address /* changed member */ );
759 ip0->checksum = ip_csum_fold (sum0);
761 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
763 if (tcp0->flags & TCP_FLAG_FIN
764 && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
765 ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
766 else if (tcp0->flags & TCP_FLAG_ACK
767 && ses0->state == DET44_SESSION_TCP_LAST_ACK)
768 snat_det_ses_close (mp0, ses0);
770 sum0 = tcp0->checksum;
771 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
773 dst_address /* changed member */ );
774 sum0 = ip_csum_update (sum0, old_port0, new_port0,
775 ip4_header_t /* cheat */ ,
776 length /* changed member */ );
777 tcp0->checksum = ip_csum_fold (sum0);
779 else if (udp0->checksum)
781 sum0 = udp0->checksum;
782 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
784 dst_address /* changed member */ );
785 sum0 = ip_csum_update (sum0, old_port0, new_port0,
786 ip4_header_t /* cheat */ ,
787 length /* changed member */ );
788 udp0->checksum = ip_csum_fold (sum0);
793 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
794 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
796 det44_out2in_trace_t *t =
797 vlib_add_trace (vm, node, b0, sizeof (*t));
798 t->sw_if_index = sw_if_index0;
799 t->next_index = next0;
800 t->session_index = ~0;
802 t->session_index = ses0 - mp0->sessions;
805 pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
811 vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
815 vlib_node_increment_counter (vm, dm->out2in_node_index,
816 DET44_OUT2IN_ERROR_OUT2IN_PACKETS,
818 return frame->n_vectors;
821 VLIB_REGISTER_NODE (det44_out2in_node) = {
822 .name = "det44-out2in",
823 .vector_size = sizeof (u32),
824 .format_trace = format_det44_out2in_trace,
825 .type = VLIB_NODE_TYPE_INTERNAL,
826 .n_errors = ARRAY_LEN(det44_out2in_error_strings),
827 .error_strings = det44_out2in_error_strings,
828 .runtime_data_bytes = sizeof (det44_runtime_t),
829 .n_next_nodes = DET44_OUT2IN_N_NEXT,
830 /* edit / add dispositions here */
832 [DET44_OUT2IN_NEXT_DROP] = "error-drop",
833 [DET44_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
834 [DET44_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
839 * fd.io coding-style-patch-verification: ON
842 * eval: (c-set-style "gnu")