api: clean up use of deprecated flag
[vpp.git] / src / plugins / nat / det44 / det44_out2in.c
1 /*
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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 /**
17  * @file
18  * @brief Deterministic NAT (CGN) outside to inside translation
19  */
20
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>
27
28 #include <nat/det44/det44.h>
29 #include <nat/det44/det44_inlines.h>
30
31 #include <nat/lib/lib.h>
32 #include <nat/lib/inlines.h>
33 #include <nat/lib/nat_inlines.h>
34
35 typedef enum
36 {
37   DET44_OUT2IN_NEXT_DROP,
38   DET44_OUT2IN_NEXT_LOOKUP,
39   DET44_OUT2IN_NEXT_ICMP_ERROR,
40   DET44_OUT2IN_N_NEXT,
41 } det44_out2in_next_t;
42
43 typedef struct
44 {
45   u32 sw_if_index;
46   u32 next_index;
47   u32 session_index;
48 } det44_out2in_trace_t;
49
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")
55
56 typedef enum
57 {
58 #define _(sym,str) DET44_OUT2IN_ERROR_##sym,
59   foreach_det44_out2in_error
60 #undef _
61     DET44_OUT2IN_N_ERROR,
62 } det44_out2in_error_t;
63
64 static char *det44_out2in_error_strings[] = {
65 #define _(sym,string) string,
66   foreach_det44_out2in_error
67 #undef _
68 };
69
70 static u8 *
71 format_det44_out2in_trace (u8 * s, va_list * args)
72 {
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 *);
76
77   s =
78     format (s,
79             "DET44_OUT2IN: sw_if_index %d, next index %d, session index %d",
80             t->sw_if_index, t->next_index, t->session_index);
81   return s;
82 }
83
84 #ifndef CLIB_MARCH_VARIANT
85 /**
86  * Get address and port values to be used for ICMP packet translation
87  * and create session if needed
88  *
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
98  */
99 u32
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,
105                        u8 * dont_translate)
106 {
107   det44_main_t *dm = &det44_main;
108   icmp46_header_t *icmp0;
109   u32 sw_if_index0;
110   u8 protocol;
111   snat_det_out_key_t key0;
112   u32 next0 = ~0;
113   icmp_echo_header_t *echo0, *inner_echo0 = 0;
114   ip4_header_t *inner_ip0;
115   void *l4_header = 0;
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;
121   *dont_translate = 0;
122
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];
126
127   if (!icmp_type_is_error_message
128       (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
129     {
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;
135     }
136   else
137     {
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;
144       switch (protocol)
145         {
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;
151           break;
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;
156           break;
157         default:
158           b0->error = node->errors[DET44_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
159           next0 = DET44_OUT2IN_NEXT_DROP;
160           goto out;
161         }
162     }
163
164   mp0 = snat_det_map_by_out (&out_addr);
165   if (PREDICT_FALSE (!mp0))
166     {
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)))
170         {
171           *dont_translate = 1;
172           goto out;
173         }
174       det44_log_info ("unknown dst address:  %U",
175                       format_ip4_address, &ip0->dst_address);
176       goto out;
177     }
178
179   snat_det_reverse (mp0, &ip0->dst_address,
180                     clib_net_to_host_u16 (key0.out_port), &new_addr0);
181
182   ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
183   if (PREDICT_FALSE (!ses0))
184     {
185       /* Don't NAT packet aimed at the intfc address */
186       if (PREDICT_FALSE (!det44_is_interface_addr (node, sw_if_index0,
187                                                    ip0->dst_address.as_u32)))
188         {
189           *dont_translate = 1;
190           goto out;
191         }
192       det44_log_info ("no match src %U:%d dst %U:%d for user %U",
193                       format_ip4_address, &key0.ext_host_addr,
194                       clib_net_to_host_u16 (key0.ext_host_port),
195                       format_ip4_address, &out_addr,
196                       clib_net_to_host_u16 (key0.out_port),
197                       format_ip4_address, &new_addr0);
198       b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
199       next0 = DET44_OUT2IN_NEXT_DROP;
200       goto out;
201     }
202
203   if (PREDICT_FALSE
204       (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
205        && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
206                                        reass.icmp_type_or_tcp_flags)))
207     {
208       b0->error = node->errors[DET44_OUT2IN_ERROR_BAD_ICMP_TYPE];
209       next0 = DET44_OUT2IN_NEXT_DROP;
210       goto out;
211     }
212
213   goto out;
214
215 out:
216   *proto = protocol;
217   if (ses0)
218     {
219       *addr = new_addr0;
220       *fib_index = dm->inside_fib_index;
221       *port = ses0->in_port;
222     }
223   if (d)
224     *(snat_det_session_t **) d = ses0;
225   if (e)
226     *(snat_det_map_t **) e = mp0;
227   return next0;
228 }
229 #endif
230
231 #ifndef CLIB_MARCH_VARIANT
232 u32
233 det44_icmp_out2in (vlib_buffer_t * b0,
234                    ip4_header_t * ip0,
235                    icmp46_header_t * icmp0,
236                    u32 sw_if_index0,
237                    u32 rx_fib_index0,
238                    vlib_node_runtime_t * node,
239                    u32 next0, u32 thread_index, void *d, void *e)
240 {
241   vlib_main_t *vm = vlib_get_main ();
242   u32 new_addr0, old_addr0, next0_tmp, fib_index;
243   u16 old_id0, new_id0, port, checksum0;
244   icmp_echo_header_t *echo0, *inner_echo0;
245   icmp46_header_t *inner_icmp0;
246   ip4_header_t *inner_ip0;
247   ip4_address_t addr;
248   void *l4_header;
249   u8 dont_translate;
250   ip_csum_t sum0;
251   nat_protocol_t proto;
252
253   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
254   next0_tmp = icmp_match_out2in_det (node, thread_index, b0, ip0,
255                                      &addr, &port, &fib_index, &proto,
256                                      d, e, &dont_translate);
257   if (next0_tmp != ~0)
258     next0 = next0_tmp;
259   if (next0 == DET44_OUT2IN_NEXT_DROP || dont_translate)
260     goto out;
261
262   if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
263     {
264       sum0 =
265         ip_incremental_checksum_buffer (vm, b0,
266                                         (u8 *) icmp0 -
267                                         (u8 *) vlib_buffer_get_current (b0),
268                                         ntohs (ip0->length) -
269                                         ip4_header_bytes (ip0), 0);
270       checksum0 = ~ip_csum_fold (sum0);
271       if (checksum0 != 0 && checksum0 != 0xffff)
272         {
273           next0 = DET44_OUT2IN_NEXT_DROP;
274           goto out;
275         }
276     }
277
278   old_addr0 = ip0->dst_address.as_u32;
279   new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
280   vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
281
282   sum0 = ip0->checksum;
283   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
284                          dst_address /* changed member */ );
285   ip0->checksum = ip_csum_fold (sum0);
286
287
288   if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
289     {
290       if (icmp0->checksum == 0)
291         icmp0->checksum = 0xffff;
292
293       if (!icmp_type_is_error_message (icmp0->type))
294         {
295           new_id0 = port;
296           if (PREDICT_FALSE (new_id0 != echo0->identifier))
297             {
298               old_id0 = echo0->identifier;
299               new_id0 = port;
300               echo0->identifier = new_id0;
301
302               sum0 = icmp0->checksum;
303               sum0 =
304                 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
305                                 identifier /* changed member */ );
306               icmp0->checksum = ip_csum_fold (sum0);
307             }
308         }
309       else
310         {
311           inner_ip0 = (ip4_header_t *) (echo0 + 1);
312           l4_header = ip4_next_header (inner_ip0);
313
314           if (!ip4_header_checksum_is_valid (inner_ip0))
315             {
316               next0 = DET44_OUT2IN_NEXT_DROP;
317               goto out;
318             }
319
320           old_addr0 = inner_ip0->src_address.as_u32;
321           inner_ip0->src_address = addr;
322           new_addr0 = inner_ip0->src_address.as_u32;
323
324           sum0 = icmp0->checksum;
325           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
326                                  src_address /* changed member */ );
327           icmp0->checksum = ip_csum_fold (sum0);
328
329           switch (proto)
330             {
331             case NAT_PROTOCOL_ICMP:
332               inner_icmp0 = (icmp46_header_t *) l4_header;
333               inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
334
335               old_id0 = inner_echo0->identifier;
336               new_id0 = port;
337               inner_echo0->identifier = new_id0;
338
339               sum0 = icmp0->checksum;
340               sum0 =
341                 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
342                                 identifier);
343               icmp0->checksum = ip_csum_fold (sum0);
344               break;
345             case NAT_PROTOCOL_UDP:
346             case NAT_PROTOCOL_TCP:
347               old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
348               new_id0 = port;
349               ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
350
351               sum0 = icmp0->checksum;
352               sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
353                                      src_port);
354               icmp0->checksum = ip_csum_fold (sum0);
355               break;
356             default:
357               ASSERT (0);
358             }
359         }
360     }
361
362 out:
363   return next0;
364 }
365 #endif
366
367 VLIB_NODE_FN (det44_out2in_node) (vlib_main_t * vm,
368                                   vlib_node_runtime_t * node,
369                                   vlib_frame_t * frame)
370 {
371   u32 n_left_from, *from;
372   u32 pkts_processed = 0;
373   det44_main_t *dm = &det44_main;
374   u32 thread_index = vm->thread_index;
375
376   from = vlib_frame_vector_args (frame);
377   n_left_from = frame->n_vectors;
378
379   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
380   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
381   vlib_get_buffers (vm, from, b, n_left_from);
382
383   while (n_left_from >= 2)
384     {
385       vlib_buffer_t *b0, *b1;
386       u32 next0 = DET44_OUT2IN_NEXT_LOOKUP;
387       u32 next1 = DET44_OUT2IN_NEXT_LOOKUP;
388       u32 sw_if_index0, sw_if_index1;
389       ip4_header_t *ip0, *ip1;
390       ip_csum_t sum0, sum1;
391       ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
392       u16 new_port0, old_port0, old_port1, new_port1;
393       udp_header_t *udp0, *udp1;
394       tcp_header_t *tcp0, *tcp1;
395       u32 proto0, proto1;
396       snat_det_out_key_t key0, key1;
397       snat_det_map_t *mp0, *mp1;
398       snat_det_session_t *ses0 = 0, *ses1 = 0;
399       u32 rx_fib_index0, rx_fib_index1;
400       icmp46_header_t *icmp0, *icmp1;
401
402       b0 = *b;
403       b++;
404       b1 = *b;
405       b++;
406
407       /* Prefetch next iteration. */
408       if (PREDICT_TRUE (n_left_from >= 4))
409         {
410           vlib_buffer_t *p2, *p3;
411
412           p2 = *b;
413           p3 = *(b + 1);
414
415           vlib_prefetch_buffer_header (p2, LOAD);
416           vlib_prefetch_buffer_header (p3, LOAD);
417
418           CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
419           CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, LOAD);
420         }
421
422
423       ip0 = vlib_buffer_get_current (b0);
424       udp0 = ip4_next_header (ip0);
425       tcp0 = (tcp_header_t *) udp0;
426
427       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
428
429       if (PREDICT_FALSE (ip0->ttl == 1))
430         {
431           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
432           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
433                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
434                                        0);
435           next0 = DET44_OUT2IN_NEXT_ICMP_ERROR;
436           goto trace0;
437         }
438
439       proto0 = ip_proto_to_nat_proto (ip0->protocol);
440
441       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
442         {
443           rx_fib_index0 =
444             ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
445           icmp0 = (icmp46_header_t *) udp0;
446
447           next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
448                                      rx_fib_index0, node, next0,
449                                      thread_index, &ses0, &mp0);
450           goto trace0;
451         }
452
453       key0.ext_host_addr = ip0->src_address;
454       key0.ext_host_port = tcp0->src;
455       key0.out_port = tcp0->dst;
456
457       mp0 = snat_det_map_by_out (&ip0->dst_address);
458       if (PREDICT_FALSE (!mp0))
459         {
460           det44_log_info ("unknown dst address:  %U",
461                           format_ip4_address, &ip0->dst_address);
462           next0 = DET44_OUT2IN_NEXT_DROP;
463           b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
464           goto trace0;
465         }
466
467       snat_det_reverse (mp0, &ip0->dst_address,
468                         clib_net_to_host_u16 (tcp0->dst), &new_addr0);
469
470       ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
471       if (PREDICT_FALSE (!ses0))
472         {
473           det44_log_info ("no match src %U:%d dst %U:%d for user %U",
474                           format_ip4_address, &ip0->src_address,
475                           clib_net_to_host_u16 (tcp0->src),
476                           format_ip4_address, &ip0->dst_address,
477                           clib_net_to_host_u16 (tcp0->dst),
478                           format_ip4_address, &new_addr0);
479           next0 = DET44_OUT2IN_NEXT_DROP;
480           b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
481           goto trace0;
482         }
483       old_port0 = udp0->dst_port;
484       udp0->dst_port = new_port0 = ses0->in_port;
485
486       old_addr0 = ip0->dst_address;
487       ip0->dst_address = new_addr0;
488       vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
489
490       sum0 = ip0->checksum;
491       sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
492                              ip4_header_t, dst_address /* changed member */ );
493       ip0->checksum = ip_csum_fold (sum0);
494
495       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
496         {
497           if (tcp0->flags & TCP_FLAG_FIN
498               && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
499             ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
500           else if (tcp0->flags & TCP_FLAG_ACK
501                    && ses0->state == DET44_SESSION_TCP_LAST_ACK)
502             snat_det_ses_close (mp0, ses0);
503
504           sum0 = tcp0->checksum;
505           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
506                                  ip4_header_t,
507                                  dst_address /* changed member */ );
508           sum0 = ip_csum_update (sum0, old_port0, new_port0,
509                                  ip4_header_t /* cheat */ ,
510                                  length /* changed member */ );
511           tcp0->checksum = ip_csum_fold (sum0);
512         }
513       else if (udp0->checksum)
514         {
515           sum0 = udp0->checksum;
516           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
517                                  ip4_header_t,
518                                  dst_address /* changed member */ );
519           sum0 = ip_csum_update (sum0, old_port0, new_port0,
520                                  ip4_header_t /* cheat */ ,
521                                  length /* changed member */ );
522           udp0->checksum = ip_csum_fold (sum0);
523         }
524
525     trace0:
526
527       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
528                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
529         {
530           det44_out2in_trace_t *t =
531             vlib_add_trace (vm, node, b0, sizeof (*t));
532           t->sw_if_index = sw_if_index0;
533           t->next_index = next0;
534           t->session_index = ~0;
535           if (ses0)
536             t->session_index = ses0 - mp0->sessions;
537         }
538
539       pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
540
541       ip1 = vlib_buffer_get_current (b1);
542       udp1 = ip4_next_header (ip1);
543       tcp1 = (tcp_header_t *) udp1;
544
545       sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
546
547       if (PREDICT_FALSE (ip1->ttl == 1))
548         {
549           vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
550           icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
551                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
552                                        0);
553           next1 = DET44_OUT2IN_NEXT_ICMP_ERROR;
554           goto trace1;
555         }
556
557       proto1 = ip_proto_to_nat_proto (ip1->protocol);
558
559       if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
560         {
561           rx_fib_index1 =
562             ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
563           icmp1 = (icmp46_header_t *) udp1;
564
565           next1 = det44_icmp_out2in (b1, ip1, icmp1, sw_if_index1,
566                                      rx_fib_index1, node, next1,
567                                      thread_index, &ses1, &mp1);
568           goto trace1;
569         }
570
571       key1.ext_host_addr = ip1->src_address;
572       key1.ext_host_port = tcp1->src;
573       key1.out_port = tcp1->dst;
574
575       mp1 = snat_det_map_by_out (&ip1->dst_address);
576       if (PREDICT_FALSE (!mp1))
577         {
578           det44_log_info ("unknown dst address:  %U",
579                           format_ip4_address, &ip1->dst_address);
580           next1 = DET44_OUT2IN_NEXT_DROP;
581           b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
582           goto trace1;
583         }
584
585       snat_det_reverse (mp1, &ip1->dst_address,
586                         clib_net_to_host_u16 (tcp1->dst), &new_addr1);
587
588       ses1 = snat_det_get_ses_by_out (mp1, &new_addr1, key1.as_u64);
589       if (PREDICT_FALSE (!ses1))
590         {
591           det44_log_info ("no match src %U:%d dst %U:%d for user %U",
592                           format_ip4_address, &ip1->src_address,
593                           clib_net_to_host_u16 (tcp1->src),
594                           format_ip4_address, &ip1->dst_address,
595                           clib_net_to_host_u16 (tcp1->dst),
596                           format_ip4_address, &new_addr1);
597           next1 = DET44_OUT2IN_NEXT_DROP;
598           b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
599           goto trace1;
600         }
601       old_port1 = udp1->dst_port;
602       udp1->dst_port = new_port1 = ses1->in_port;
603
604       old_addr1 = ip1->dst_address;
605       ip1->dst_address = new_addr1;
606       vnet_buffer (b1)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
607
608       sum1 = ip1->checksum;
609       sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
610                              ip4_header_t, dst_address /* changed member */ );
611       ip1->checksum = ip_csum_fold (sum1);
612
613       if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
614         {
615           if (tcp1->flags & TCP_FLAG_FIN
616               && ses1->state == DET44_SESSION_TCP_ESTABLISHED)
617             ses1->state = DET44_SESSION_TCP_CLOSE_WAIT;
618           else if (tcp1->flags & TCP_FLAG_ACK
619                    && ses1->state == DET44_SESSION_TCP_LAST_ACK)
620             snat_det_ses_close (mp1, ses1);
621
622           sum1 = tcp1->checksum;
623           sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
624                                  ip4_header_t,
625                                  dst_address /* changed member */ );
626           sum1 = ip_csum_update (sum1, old_port1, new_port1,
627                                  ip4_header_t /* cheat */ ,
628                                  length /* changed member */ );
629           tcp1->checksum = ip_csum_fold (sum1);
630         }
631       else if (udp1->checksum)
632         {
633           sum1 = udp1->checksum;
634           sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
635                                  ip4_header_t,
636                                  dst_address /* changed member */ );
637           sum1 = ip_csum_update (sum1, old_port1, new_port1,
638                                  ip4_header_t /* cheat */ ,
639                                  length /* changed member */ );
640           udp1->checksum = ip_csum_fold (sum1);
641         }
642
643     trace1:
644
645       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
646                          && (b1->flags & VLIB_BUFFER_IS_TRACED)))
647         {
648           det44_out2in_trace_t *t =
649             vlib_add_trace (vm, node, b1, sizeof (*t));
650           t->sw_if_index = sw_if_index1;
651           t->next_index = next1;
652           t->session_index = ~0;
653           if (ses1)
654             t->session_index = ses1 - mp1->sessions;
655         }
656
657       pkts_processed += next1 != DET44_OUT2IN_NEXT_DROP;
658
659       n_left_from -= 2;
660       next[0] = next0;
661       next[1] = next1;
662       next += 2;
663     }
664
665   while (n_left_from > 0)
666     {
667       vlib_buffer_t *b0;
668       u32 next0 = DET44_OUT2IN_NEXT_LOOKUP;
669       u32 sw_if_index0;
670       ip4_header_t *ip0;
671       ip_csum_t sum0;
672       ip4_address_t new_addr0, old_addr0;
673       u16 new_port0, old_port0;
674       udp_header_t *udp0;
675       tcp_header_t *tcp0;
676       u32 proto0;
677       snat_det_out_key_t key0;
678       snat_det_map_t *mp0;
679       snat_det_session_t *ses0 = 0;
680       u32 rx_fib_index0;
681       icmp46_header_t *icmp0;
682
683       b0 = *b;
684       b++;
685
686       ip0 = vlib_buffer_get_current (b0);
687       udp0 = ip4_next_header (ip0);
688       tcp0 = (tcp_header_t *) udp0;
689
690       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
691
692       if (PREDICT_FALSE (ip0->ttl == 1))
693         {
694           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
695           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
696                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
697                                        0);
698           next0 = DET44_OUT2IN_NEXT_ICMP_ERROR;
699           goto trace00;
700         }
701
702       proto0 = ip_proto_to_nat_proto (ip0->protocol);
703
704       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
705         {
706           rx_fib_index0 =
707             ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
708           icmp0 = (icmp46_header_t *) udp0;
709
710           next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
711                                      rx_fib_index0, node, next0,
712                                      thread_index, &ses0, &mp0);
713           goto trace00;
714         }
715
716       key0.ext_host_addr = ip0->src_address;
717       key0.ext_host_port = tcp0->src;
718       key0.out_port = tcp0->dst;
719
720       mp0 = snat_det_map_by_out (&ip0->dst_address);
721       if (PREDICT_FALSE (!mp0))
722         {
723           det44_log_info ("unknown dst address:  %U",
724                           format_ip4_address, &ip0->dst_address);
725           next0 = DET44_OUT2IN_NEXT_DROP;
726           b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
727           goto trace00;
728         }
729
730       snat_det_reverse (mp0, &ip0->dst_address,
731                         clib_net_to_host_u16 (tcp0->dst), &new_addr0);
732
733       ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
734       if (PREDICT_FALSE (!ses0))
735         {
736           det44_log_info ("no match src %U:%d dst %U:%d for user %U",
737                           format_ip4_address, &ip0->src_address,
738                           clib_net_to_host_u16 (tcp0->src),
739                           format_ip4_address, &ip0->dst_address,
740                           clib_net_to_host_u16 (tcp0->dst),
741                           format_ip4_address, &new_addr0);
742           next0 = DET44_OUT2IN_NEXT_DROP;
743           b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
744           goto trace00;
745         }
746       old_port0 = udp0->dst_port;
747       udp0->dst_port = new_port0 = ses0->in_port;
748
749       old_addr0 = ip0->dst_address;
750       ip0->dst_address = new_addr0;
751       vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
752
753       sum0 = ip0->checksum;
754       sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
755                              ip4_header_t, dst_address /* changed member */ );
756       ip0->checksum = ip_csum_fold (sum0);
757
758       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
759         {
760           if (tcp0->flags & TCP_FLAG_FIN
761               && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
762             ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
763           else if (tcp0->flags & TCP_FLAG_ACK
764                    && ses0->state == DET44_SESSION_TCP_LAST_ACK)
765             snat_det_ses_close (mp0, ses0);
766
767           sum0 = tcp0->checksum;
768           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
769                                  ip4_header_t,
770                                  dst_address /* changed member */ );
771           sum0 = ip_csum_update (sum0, old_port0, new_port0,
772                                  ip4_header_t /* cheat */ ,
773                                  length /* changed member */ );
774           tcp0->checksum = ip_csum_fold (sum0);
775         }
776       else if (udp0->checksum)
777         {
778           sum0 = udp0->checksum;
779           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
780                                  ip4_header_t,
781                                  dst_address /* changed member */ );
782           sum0 = ip_csum_update (sum0, old_port0, new_port0,
783                                  ip4_header_t /* cheat */ ,
784                                  length /* changed member */ );
785           udp0->checksum = ip_csum_fold (sum0);
786         }
787
788     trace00:
789
790       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
791                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
792         {
793           det44_out2in_trace_t *t =
794             vlib_add_trace (vm, node, b0, sizeof (*t));
795           t->sw_if_index = sw_if_index0;
796           t->next_index = next0;
797           t->session_index = ~0;
798           if (ses0)
799             t->session_index = ses0 - mp0->sessions;
800         }
801
802       pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
803
804       n_left_from--;
805       next[0] = next0;
806       next++;
807     }
808   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
809                                frame->n_vectors);
810
811
812   vlib_node_increment_counter (vm, dm->out2in_node_index,
813                                DET44_OUT2IN_ERROR_OUT2IN_PACKETS,
814                                pkts_processed);
815   return frame->n_vectors;
816 }
817
818 /* *INDENT-OFF* */
819 VLIB_REGISTER_NODE (det44_out2in_node) = {
820   .name = "det44-out2in",
821   .vector_size = sizeof (u32),
822   .format_trace = format_det44_out2in_trace,
823   .type = VLIB_NODE_TYPE_INTERNAL,
824   .n_errors = ARRAY_LEN(det44_out2in_error_strings),
825   .error_strings = det44_out2in_error_strings,
826   .runtime_data_bytes = sizeof (det44_runtime_t),
827   .n_next_nodes = DET44_OUT2IN_N_NEXT,
828   /* edit / add dispositions here */
829   .next_nodes = {
830     [DET44_OUT2IN_NEXT_DROP] = "error-drop",
831     [DET44_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
832     [DET44_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
833   },
834 };
835 /* *INDENT-ON* */
836
837 /*
838  * fd.io coding-style-patch-verification: ON
839  *
840  * Local Variables:
841  * eval: (c-set-style "gnu")
842  * End:
843  */