a626bf5c2a6798f74fd2140b413b6d81c95a28f3
[vpp.git] / src / plugins / nat / out2in.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
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 #include <vlib/vlib.h>
17 #include <vnet/vnet.h>
18 #include <vnet/pg/pg.h>
19 #include <vnet/handoff.h>
20
21 #include <vnet/ip/ip.h>
22 #include <vnet/udp/udp.h>
23 #include <vnet/ethernet/ethernet.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <nat/nat.h>
26 #include <nat/nat_ipfix_logging.h>
27 #include <nat/nat_det.h>
28 #include <nat/nat_reass.h>
29
30 #include <vppinfra/hash.h>
31 #include <vppinfra/error.h>
32 #include <vppinfra/elog.h>
33
34 typedef struct {
35   u32 sw_if_index;
36   u32 next_index;
37   u32 session_index;
38 } snat_out2in_trace_t;
39
40 typedef struct {
41   u32 next_worker_index;
42   u8 do_handoff;
43 } snat_out2in_worker_handoff_trace_t;
44
45 /* packet trace format function */
46 static u8 * format_snat_out2in_trace (u8 * s, va_list * args)
47 {
48   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
49   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
50   snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
51
52   s = format (s, "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
53               t->sw_if_index, t->next_index, t->session_index);
54   return s;
55 }
56
57 static u8 * format_snat_out2in_fast_trace (u8 * s, va_list * args)
58 {
59   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
60   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
61   snat_out2in_trace_t * t = va_arg (*args, snat_out2in_trace_t *);
62
63   s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
64               t->sw_if_index, t->next_index);
65   return s;
66 }
67
68 static u8 * format_snat_out2in_worker_handoff_trace (u8 * s, va_list * args)
69 {
70   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
71   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
72   snat_out2in_worker_handoff_trace_t * t =
73     va_arg (*args, snat_out2in_worker_handoff_trace_t *);
74   char * m;
75
76   m = t->do_handoff ? "next worker" : "same worker";
77   s = format (s, "NAT44_OUT2IN_WORKER_HANDOFF: %s %d", m, t->next_worker_index);
78
79   return s;
80 }
81
82 typedef struct {
83   u32 sw_if_index;
84   u32 next_index;
85   u8 cached;
86 } nat44_out2in_reass_trace_t;
87
88 static u8 * format_nat44_out2in_reass_trace (u8 * s, va_list * args)
89 {
90   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
91   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
92   nat44_out2in_reass_trace_t * t = va_arg (*args, nat44_out2in_reass_trace_t *);
93
94   s = format (s, "NAT44_OUT2IN_REASS: sw_if_index %d, next index %d, status %s",
95               t->sw_if_index, t->next_index,
96               t->cached ? "cached" : "translated");
97
98   return s;
99 }
100
101 vlib_node_registration_t snat_out2in_node;
102 vlib_node_registration_t snat_out2in_fast_node;
103 vlib_node_registration_t snat_out2in_worker_handoff_node;
104 vlib_node_registration_t snat_det_out2in_node;
105 vlib_node_registration_t nat44_out2in_reass_node;
106
107 #define foreach_snat_out2in_error                       \
108 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol")         \
109 _(OUT2IN_PACKETS, "Good out2in packets processed")      \
110 _(OUT_OF_PORTS, "Out of ports")                         \
111 _(BAD_ICMP_TYPE, "unsupported ICMP type")               \
112 _(NO_TRANSLATION, "No translation")                     \
113 _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded")   \
114 _(DROP_FRAGMENT, "Drop fragment")                       \
115 _(MAX_REASS, "Maximum reassemblies exceeded")           \
116 _(MAX_FRAG, "Maximum fragments per reassembly exceeded")
117
118 typedef enum {
119 #define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
120   foreach_snat_out2in_error
121 #undef _
122   SNAT_OUT2IN_N_ERROR,
123 } snat_out2in_error_t;
124
125 static char * snat_out2in_error_strings[] = {
126 #define _(sym,string) string,
127   foreach_snat_out2in_error
128 #undef _
129 };
130
131 typedef enum {
132   SNAT_OUT2IN_NEXT_DROP,
133   SNAT_OUT2IN_NEXT_LOOKUP,
134   SNAT_OUT2IN_NEXT_ICMP_ERROR,
135   SNAT_OUT2IN_NEXT_REASS,
136   SNAT_OUT2IN_NEXT_IN2OUT,
137   SNAT_OUT2IN_N_NEXT,
138 } snat_out2in_next_t;
139
140 /**
141  * @brief Create session for static mapping.
142  *
143  * Create NAT session initiated by host from external network with static
144  * mapping.
145  *
146  * @param sm     NAT main.
147  * @param b0     Vlib buffer.
148  * @param in2out In2out NAT44 session key.
149  * @param out2in Out2in NAT44 session key.
150  * @param node   Vlib node.
151  *
152  * @returns SNAT session if successfully created otherwise 0.
153  */
154 static inline snat_session_t *
155 create_session_for_static_mapping (snat_main_t *sm,
156                                    vlib_buffer_t *b0,
157                                    snat_session_key_t in2out,
158                                    snat_session_key_t out2in,
159                                    vlib_node_runtime_t * node,
160                                    u32 thread_index)
161 {
162   snat_user_t *u;
163   snat_session_t *s;
164   clib_bihash_kv_8_8_t kv0;
165   ip4_header_t *ip0;
166   udp_header_t *udp0;
167
168   if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
169     {
170       b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
171       return 0;
172     }
173
174   ip0 = vlib_buffer_get_current (b0);
175   udp0 = ip4_next_header (ip0);
176
177   u = nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index);
178   if (!u)
179     {
180       clib_warning ("create NAT user failed");
181       return 0;
182     }
183
184   s = nat_session_alloc_or_recycle (sm, u, thread_index);
185   if (!s)
186     {
187       clib_warning ("create NAT session failed");
188       return 0;
189     }
190
191   s->outside_address_index = ~0;
192   s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
193   s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
194   s->ext_host_port = udp0->src_port;
195   user_session_increment (sm, u, 1 /* static */);
196   s->in2out = in2out;
197   s->out2in = out2in;
198   s->in2out.protocol = out2in.protocol;
199
200   /* Add to translation hashes */
201   kv0.key = s->in2out.as_u64;
202   kv0.value = s - sm->per_thread_data[thread_index].sessions;
203   if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0,
204                                1 /* is_add */))
205       clib_warning ("in2out key add failed");
206
207   kv0.key = s->out2in.as_u64;
208
209   if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
210                                1 /* is_add */))
211       clib_warning ("out2in key add failed");
212
213   /* log NAT event */
214   snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32,
215                                       s->out2in.addr.as_u32,
216                                       s->in2out.protocol,
217                                       s->in2out.port,
218                                       s->out2in.port,
219                                       s->in2out.fib_index);
220    return s;
221 }
222
223 static_always_inline
224 snat_out2in_error_t icmp_get_key(ip4_header_t *ip0,
225                                  snat_session_key_t *p_key0)
226 {
227   icmp46_header_t *icmp0;
228   snat_session_key_t key0;
229   icmp_echo_header_t *echo0, *inner_echo0 = 0;
230   ip4_header_t *inner_ip0;
231   void *l4_header = 0;
232   icmp46_header_t *inner_icmp0;
233
234   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
235   echo0 = (icmp_echo_header_t *)(icmp0+1);
236
237   if (!icmp_is_error_message (icmp0))
238     {
239       key0.protocol = SNAT_PROTOCOL_ICMP;
240       key0.addr = ip0->dst_address;
241       key0.port = echo0->identifier;
242     }
243   else
244     {
245       inner_ip0 = (ip4_header_t *)(echo0+1);
246       l4_header = ip4_next_header (inner_ip0);
247       key0.protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
248       key0.addr = inner_ip0->src_address;
249       switch (key0.protocol)
250         {
251         case SNAT_PROTOCOL_ICMP:
252           inner_icmp0 = (icmp46_header_t*)l4_header;
253           inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
254           key0.port = inner_echo0->identifier;
255           break;
256         case SNAT_PROTOCOL_UDP:
257         case SNAT_PROTOCOL_TCP:
258           key0.port = ((tcp_udp_header_t*)l4_header)->src_port;
259           break;
260         default:
261           return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
262         }
263     }
264   *p_key0 = key0;
265   return -1; /* success */
266 }
267
268 static_always_inline int
269 icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0)
270 {
271   icmp46_header_t *icmp0;
272   nat_ed_ses_key_t key0;
273   icmp_echo_header_t *echo0, *inner_echo0 = 0;
274   ip4_header_t *inner_ip0;
275   void *l4_header = 0;
276   icmp46_header_t *inner_icmp0;
277
278   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
279   echo0 = (icmp_echo_header_t *)(icmp0+1);
280
281   if (!icmp_is_error_message (icmp0))
282     {
283       key0.proto = IP_PROTOCOL_ICMP;
284       key0.l_addr = ip0->dst_address;
285       key0.r_addr = ip0->src_address;
286       key0.l_port = key0.r_port = echo0->identifier;
287     }
288   else
289     {
290       inner_ip0 = (ip4_header_t *)(echo0+1);
291       l4_header = ip4_next_header (inner_ip0);
292       key0.proto = inner_ip0->protocol;
293       key0.l_addr = inner_ip0->src_address;
294       key0.r_addr = inner_ip0->dst_address;
295       switch (ip_proto_to_snat_proto (inner_ip0->protocol))
296         {
297         case SNAT_PROTOCOL_ICMP:
298           inner_icmp0 = (icmp46_header_t*)l4_header;
299           inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
300           key0.l_port = key0.r_port = inner_echo0->identifier;
301           break;
302         case SNAT_PROTOCOL_UDP:
303         case SNAT_PROTOCOL_TCP:
304           key0.l_port = ((tcp_udp_header_t*)l4_header)->src_port;
305           key0.r_port = ((tcp_udp_header_t*)l4_header)->dst_port;
306           break;
307         default:
308           return -1;
309         }
310     }
311   *p_key0 = key0;
312   return 0;
313 }
314
315 static int
316 next_src_nat (snat_main_t * sm, ip4_header_t * ip, u32 proto, u16 src_port,
317               u32 thread_index)
318 {
319   snat_session_key_t key;
320   clib_bihash_kv_8_8_t kv, value;
321
322   key.addr = ip->src_address;
323   key.port = src_port;
324   key.protocol = proto;
325   key.fib_index = sm->inside_fib_index;
326   kv.key = key.as_u64;
327
328   if (!clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].in2out, &kv,
329                                &value))
330     return 1;
331
332   return 0;
333 }
334
335 static void
336 create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip)
337 {
338   nat_ed_ses_key_t key;
339   clib_bihash_kv_16_8_t kv;
340   udp_header_t *udp;
341
342   if (ip->protocol == IP_PROTOCOL_ICMP)
343     {
344       if (icmp_get_ed_key (ip, &key))
345         return;
346     }
347   else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
348     {
349       udp = ip4_next_header(ip);
350       key.r_addr = ip->src_address;
351       key.l_addr = ip->dst_address;
352       key.proto = ip->protocol;
353       key.l_port = udp->dst_port;
354       key.r_port = udp->src_port;
355     }
356   else
357     {
358       key.r_addr = ip->src_address;
359       key.l_addr = ip->dst_address;
360       key.proto = ip->protocol;
361       key.l_port = key.r_port = 0;
362     }
363   key.fib_index = 0;
364   kv.key[0] = key.as_u64[0];
365   kv.key[1] = key.as_u64[1];
366   kv.value = ~0ULL;
367
368   if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &kv, 1))
369     clib_warning ("in2out_ed key add failed");
370 }
371
372 /**
373  * Get address and port values to be used for ICMP packet translation
374  * and create session if needed
375  *
376  * @param[in,out] sm             NAT main
377  * @param[in,out] node           NAT node runtime
378  * @param[in] thread_index       thread index
379  * @param[in,out] b0             buffer containing packet to be translated
380  * @param[out] p_proto           protocol used for matching
381  * @param[out] p_value           address and port after NAT translation
382  * @param[out] p_dont_translate  if packet should not be translated
383  * @param d                      optional parameter
384  * @param e                      optional parameter
385  */
386 u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node,
387                            u32 thread_index, vlib_buffer_t *b0,
388                            ip4_header_t *ip0, u8 *p_proto,
389                            snat_session_key_t *p_value,
390                            u8 *p_dont_translate, void *d, void *e)
391 {
392   icmp46_header_t *icmp0;
393   u32 sw_if_index0;
394   u32 rx_fib_index0;
395   snat_session_key_t key0;
396   snat_session_key_t sm0;
397   snat_session_t *s0 = 0;
398   u8 dont_translate = 0;
399   clib_bihash_kv_8_8_t kv0, value0;
400   u8 is_addr_only;
401   u32 next0 = ~0;
402   int err;
403
404   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
405   sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
406   rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
407
408   key0.protocol = 0;
409
410   err = icmp_get_key (ip0, &key0);
411   if (err != -1)
412     {
413       b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
414       next0 = SNAT_OUT2IN_NEXT_DROP;
415       goto out;
416     }
417   key0.fib_index = rx_fib_index0;
418
419   kv0.key = key0.as_u64;
420
421   if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0,
422                               &value0))
423     {
424       /* Try to match static mapping by external address and port,
425          destination address and port in packet */
426       if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0))
427         {
428           if (!sm->forwarding_enabled)
429             {
430               /* Don't NAT packet aimed at the intfc address */
431               if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
432                                                   ip0->dst_address.as_u32)))
433                 {
434                   dont_translate = 1;
435                   goto out;
436                 }
437               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
438               next0 = SNAT_OUT2IN_NEXT_DROP;
439               goto out;
440             }
441           else
442             {
443               dont_translate = 1;
444               if (next_src_nat(sm, ip0, key0.protocol, key0.port, thread_index))
445                 {
446                   next0 = SNAT_OUT2IN_NEXT_IN2OUT;
447                   goto out;
448                 }
449               create_bypass_for_fwd(sm, ip0);
450               goto out;
451             }
452         }
453
454       if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
455                         (icmp0->type != ICMP4_echo_request || !is_addr_only)))
456         {
457           b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
458           next0 = SNAT_OUT2IN_NEXT_DROP;
459           goto out;
460         }
461
462       /* Create session initiated by host from external network */
463       s0 = create_session_for_static_mapping(sm, b0, sm0, key0,
464                                              node, thread_index);
465
466       if (!s0)
467         {
468           next0 = SNAT_OUT2IN_NEXT_DROP;
469           goto out;
470         }
471     }
472   else
473     {
474       if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
475                         icmp0->type != ICMP4_echo_request &&
476                         !icmp_is_error_message (icmp0)))
477         {
478           b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
479           next0 = SNAT_OUT2IN_NEXT_DROP;
480           goto out;
481         }
482
483       if (PREDICT_FALSE (value0.value == ~0ULL))
484         {
485           nat_ed_ses_key_t key;
486           clib_bihash_kv_16_8_t s_kv, s_value;
487
488           key.as_u64[0] = 0;
489           key.as_u64[1] = 0;
490           if (icmp_get_ed_key (ip0, &key))
491             {
492               b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
493               next0 = SNAT_OUT2IN_NEXT_DROP;
494               goto out;
495             }
496           key.fib_index = rx_fib_index0;
497           s_kv.key[0] = key.as_u64[0];
498           s_kv.key[1] = key.as_u64[1];
499           if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
500             s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
501                                     s_value.value);
502           else
503            {
504               next0 = SNAT_OUT2IN_NEXT_DROP;
505               goto out;
506            }
507         }
508       else
509         s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
510                                 value0.value);
511     }
512
513 out:
514   *p_proto = key0.protocol;
515   if (s0)
516     *p_value = s0->in2out;
517   *p_dont_translate = dont_translate;
518   if (d)
519     *(snat_session_t**)d = s0;
520   return next0;
521 }
522
523 /**
524  * Get address and port values to be used for ICMP packet translation
525  *
526  * @param[in] sm                 NAT main
527  * @param[in,out] node           NAT node runtime
528  * @param[in] thread_index       thread index
529  * @param[in,out] b0             buffer containing packet to be translated
530  * @param[out] p_proto           protocol used for matching
531  * @param[out] p_value           address and port after NAT translation
532  * @param[out] p_dont_translate  if packet should not be translated
533  * @param d                      optional parameter
534  * @param e                      optional parameter
535  */
536 u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node,
537                            u32 thread_index, vlib_buffer_t *b0,
538                            ip4_header_t *ip0, u8 *p_proto,
539                            snat_session_key_t *p_value,
540                            u8 *p_dont_translate, void *d, void *e)
541 {
542   icmp46_header_t *icmp0;
543   u32 sw_if_index0;
544   u32 rx_fib_index0;
545   snat_session_key_t key0;
546   snat_session_key_t sm0;
547   u8 dont_translate = 0;
548   u8 is_addr_only;
549   u32 next0 = ~0;
550   int err;
551
552   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
553   sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
554   rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
555
556   err = icmp_get_key (ip0, &key0);
557   if (err != -1)
558     {
559       b0->error = node->errors[err];
560       next0 = SNAT_OUT2IN_NEXT_DROP;
561       goto out2;
562     }
563   key0.fib_index = rx_fib_index0;
564
565   if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0, 0))
566     {
567       /* Don't NAT packet aimed at the intfc address */
568       if (is_interface_addr(sm, node, sw_if_index0, ip0->dst_address.as_u32))
569         {
570           dont_translate = 1;
571           goto out;
572         }
573       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
574       next0 = SNAT_OUT2IN_NEXT_DROP;
575       goto out;
576     }
577
578   if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
579                     (icmp0->type != ICMP4_echo_request || !is_addr_only) &&
580                     !icmp_is_error_message (icmp0)))
581     {
582       b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
583       next0 = SNAT_OUT2IN_NEXT_DROP;
584       goto out;
585     }
586
587 out:
588   *p_value = sm0;
589 out2:
590   *p_proto = key0.protocol;
591   *p_dont_translate = dont_translate;
592   return next0;
593 }
594
595 static inline u32 icmp_out2in (snat_main_t *sm,
596                                vlib_buffer_t * b0,
597                                ip4_header_t * ip0,
598                                icmp46_header_t * icmp0,
599                                u32 sw_if_index0,
600                                u32 rx_fib_index0,
601                                vlib_node_runtime_t * node,
602                                u32 next0,
603                                u32 thread_index,
604                                void *d,
605                                void *e)
606 {
607   snat_session_key_t sm0;
608   u8 protocol;
609   icmp_echo_header_t *echo0, *inner_echo0 = 0;
610   ip4_header_t *inner_ip0 = 0;
611   void *l4_header = 0;
612   icmp46_header_t *inner_icmp0;
613   u8 dont_translate;
614   u32 new_addr0, old_addr0;
615   u16 old_id0, new_id0;
616   ip_csum_t sum0;
617   u16 checksum0;
618   u32 next0_tmp;
619
620   echo0 = (icmp_echo_header_t *)(icmp0+1);
621
622   next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0, ip0,
623                                        &protocol, &sm0, &dont_translate, d, e);
624   if (next0_tmp != ~0)
625     next0 = next0_tmp;
626   if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
627     goto out;
628
629   sum0 = ip_incremental_checksum (0, icmp0,
630                                   ntohs(ip0->length) - ip4_header_bytes (ip0));
631   checksum0 = ~ip_csum_fold (sum0);
632   if (checksum0 != 0 && checksum0 != 0xffff)
633     {
634       next0 = SNAT_OUT2IN_NEXT_DROP;
635       goto out;
636     }
637
638   old_addr0 = ip0->dst_address.as_u32;
639   new_addr0 = ip0->dst_address.as_u32 = sm0.addr.as_u32;
640   vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
641
642   sum0 = ip0->checksum;
643   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
644                          dst_address /* changed member */);
645   ip0->checksum = ip_csum_fold (sum0);
646
647   if (icmp0->checksum == 0)
648     icmp0->checksum = 0xffff;
649
650   if (!icmp_is_error_message (icmp0))
651     {
652       new_id0 = sm0.port;
653       if (PREDICT_FALSE(new_id0 != echo0->identifier))
654         {
655           old_id0 = echo0->identifier;
656           new_id0 = sm0.port;
657           echo0->identifier = new_id0;
658
659           sum0 = icmp0->checksum;
660           sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
661                                  identifier /* changed member */);
662           icmp0->checksum = ip_csum_fold (sum0);
663         }
664     }
665   else
666     {
667       inner_ip0 = (ip4_header_t *)(echo0+1);
668       l4_header = ip4_next_header (inner_ip0);
669
670       if (!ip4_header_checksum_is_valid (inner_ip0))
671         {
672           next0 = SNAT_OUT2IN_NEXT_DROP;
673           goto out;
674         }
675
676       old_addr0 = inner_ip0->src_address.as_u32;
677       inner_ip0->src_address = sm0.addr;
678       new_addr0 = inner_ip0->src_address.as_u32;
679
680       sum0 = icmp0->checksum;
681       sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
682                              src_address /* changed member */);
683       icmp0->checksum = ip_csum_fold (sum0);
684
685       switch (protocol)
686         {
687         case SNAT_PROTOCOL_ICMP:
688           inner_icmp0 = (icmp46_header_t*)l4_header;
689           inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
690
691           old_id0 = inner_echo0->identifier;
692           new_id0 = sm0.port;
693           inner_echo0->identifier = new_id0;
694
695           sum0 = icmp0->checksum;
696           sum0 = ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
697                                  identifier);
698           icmp0->checksum = ip_csum_fold (sum0);
699           break;
700         case SNAT_PROTOCOL_UDP:
701         case SNAT_PROTOCOL_TCP:
702           old_id0 = ((tcp_udp_header_t*)l4_header)->src_port;
703           new_id0 = sm0.port;
704           ((tcp_udp_header_t*)l4_header)->src_port = new_id0;
705
706           sum0 = icmp0->checksum;
707           sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
708                                  src_port);
709           icmp0->checksum = ip_csum_fold (sum0);
710           break;
711         default:
712           ASSERT(0);
713         }
714     }
715
716 out:
717   return next0;
718 }
719
720
721 static inline u32 icmp_out2in_slow_path (snat_main_t *sm,
722                                          vlib_buffer_t * b0,
723                                          ip4_header_t * ip0,
724                                          icmp46_header_t * icmp0,
725                                          u32 sw_if_index0,
726                                          u32 rx_fib_index0,
727                                          vlib_node_runtime_t * node,
728                                          u32 next0, f64 now,
729                                          u32 thread_index,
730                                          snat_session_t ** p_s0)
731 {
732   next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
733                       next0, thread_index, p_s0, 0);
734   snat_session_t * s0 = *p_s0;
735   if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0))
736     {
737       /* Accounting */
738       s0->last_heard = now;
739       s0->total_pkts++;
740       s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0);
741       /* Per-user LRU list maintenance */
742       clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
743                          s0->per_user_index);
744       clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
745                           s0->per_user_list_head_index,
746                           s0->per_user_index);
747     }
748   return next0;
749 }
750
751 static snat_session_t *
752 snat_out2in_unknown_proto (snat_main_t *sm,
753                            vlib_buffer_t * b,
754                            ip4_header_t * ip,
755                            u32 rx_fib_index,
756                            u32 thread_index,
757                            f64 now,
758                            vlib_main_t * vm,
759                            vlib_node_runtime_t * node)
760 {
761   clib_bihash_kv_8_8_t kv, value;
762   clib_bihash_kv_16_8_t s_kv, s_value;
763   snat_static_mapping_t *m;
764   snat_session_key_t m_key;
765   u32 old_addr, new_addr;
766   ip_csum_t sum;
767   nat_ed_ses_key_t key;
768   snat_session_t * s;
769   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
770   snat_user_t *u;
771
772   old_addr = ip->dst_address.as_u32;
773
774   key.l_addr = ip->dst_address;
775   key.r_addr = ip->src_address;
776   key.fib_index = rx_fib_index;
777   key.proto = ip->protocol;
778   key.r_port = 0;
779   key.l_port = 0;
780   s_kv.key[0] = key.as_u64[0];
781   s_kv.key[1] = key.as_u64[1];
782
783   if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
784     {
785       s = pool_elt_at_index (tsm->sessions, s_value.value);
786       new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
787     }
788   else
789     {
790       if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
791         {
792           b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
793           return 0;
794         }
795
796       m_key.addr = ip->dst_address;
797       m_key.port = 0;
798       m_key.protocol = 0;
799       m_key.fib_index = rx_fib_index;
800       kv.key = m_key.as_u64;
801       if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
802         {
803           b->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
804           return 0;
805         }
806
807       m = pool_elt_at_index (sm->static_mappings, value.value);
808
809       new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
810
811       u = nat_user_get_or_create (sm, &ip->src_address, m->fib_index,
812                                   thread_index);
813       if (!u)
814         {
815           clib_warning ("create NAT user failed");
816           return 0;
817         }
818
819       /* Create a new session */
820       s = nat_session_alloc_or_recycle (sm, u, thread_index);
821       if (!s)
822         {
823           clib_warning ("create NAT session failed");
824           return 0;
825         }
826
827       s->ext_host_addr.as_u32 = ip->src_address.as_u32;
828       s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
829       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
830       s->outside_address_index = ~0;
831       s->out2in.addr.as_u32 = old_addr;
832       s->out2in.fib_index = rx_fib_index;
833       s->in2out.addr.as_u32 = new_addr;
834       s->in2out.fib_index = m->fib_index;
835       s->in2out.port = s->out2in.port = ip->protocol;
836       user_session_increment (sm, u, 1 /* static */);
837
838       /* Add to lookup tables */
839       s_kv.value = s - tsm->sessions;
840       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
841         clib_warning ("out2in key add failed");
842
843       key.l_addr = ip->dst_address;
844       key.fib_index = m->fib_index;
845       s_kv.key[0] = key.as_u64[0];
846       s_kv.key[1] = key.as_u64[1];
847       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
848         clib_warning ("in2out key add failed");
849    }
850
851   /* Update IP checksum */
852   sum = ip->checksum;
853   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
854   ip->checksum = ip_csum_fold (sum);
855
856   vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
857
858   /* Accounting */
859   s->last_heard = now;
860   s->total_pkts++;
861   s->total_bytes += vlib_buffer_length_in_chain (vm, b);
862   /* Per-user LRU list maintenance */
863   clib_dlist_remove (tsm->list_pool, s->per_user_index);
864   clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
865                       s->per_user_index);
866
867   return s;
868 }
869
870 static snat_session_t *
871 snat_out2in_lb (snat_main_t *sm,
872                 vlib_buffer_t * b,
873                 ip4_header_t * ip,
874                 u32 rx_fib_index,
875                 u32 thread_index,
876                 f64 now,
877                 vlib_main_t * vm,
878                 vlib_node_runtime_t * node)
879 {
880   nat_ed_ses_key_t key;
881   clib_bihash_kv_16_8_t s_kv, s_value;
882   udp_header_t *udp = ip4_next_header (ip);
883   tcp_header_t *tcp = (tcp_header_t *) udp;
884   snat_session_t *s = 0;
885   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
886   snat_session_key_t e_key, l_key;
887   u32 old_addr, new_addr;
888   u32 proto = ip_proto_to_snat_proto (ip->protocol);
889   u16 new_port, old_port;
890   ip_csum_t sum;
891   snat_user_t *u;
892   u32 address_index;
893   snat_session_key_t eh_key;
894   u8 twice_nat, lb;
895
896   old_addr = ip->dst_address.as_u32;
897
898   key.l_addr = ip->dst_address;
899   key.r_addr = ip->src_address;
900   key.fib_index = rx_fib_index;
901   key.proto = ip->protocol;
902   key.r_port = udp->src_port;
903   key.l_port = udp->dst_port;
904   s_kv.key[0] = key.as_u64[0];
905   s_kv.key[1] = key.as_u64[1];
906
907   if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
908     {
909       s = pool_elt_at_index (tsm->sessions, s_value.value);
910     }
911   else
912     {
913       if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index)))
914         {
915           b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
916           return 0;
917         }
918
919       e_key.addr = ip->dst_address;
920       e_key.port = udp->dst_port;
921       e_key.protocol = proto;
922       e_key.fib_index = rx_fib_index;
923       if (snat_static_mapping_match(sm, e_key, &l_key, 1, 0, &twice_nat, &lb))
924         return 0;
925
926       u = nat_user_get_or_create (sm, &l_key.addr, l_key.fib_index,
927                                   thread_index);
928       if (!u)
929       {
930         clib_warning ("create NAT user failed");
931         return 0;
932       }
933
934       s = nat_session_alloc_or_recycle (sm, u, thread_index);
935       if (!s)
936         {
937           clib_warning ("create NAT session failed");
938           return 0;
939         }
940
941       s->ext_host_addr.as_u32 = ip->src_address.as_u32;
942       s->ext_host_port = udp->src_port;
943       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
944       if (lb)
945         s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
946       s->outside_address_index = ~0;
947       s->out2in = e_key;
948       s->in2out = l_key;
949       user_session_increment (sm, u, 1 /* static */);
950
951       /* Add to lookup tables */
952       s_kv.value = s - tsm->sessions;
953       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
954         clib_warning ("out2in-ed key add failed");
955
956       if (twice_nat)
957         {
958           eh_key.protocol = proto;
959           if (snat_alloc_outside_address_and_port (sm->twice_nat_addresses, 0,
960                                                    thread_index, &eh_key,
961                                                    &address_index,
962                                                    sm->port_per_thread,
963                                                    sm->per_thread_data[thread_index].snat_thread_index))
964             {
965               b->error = node->errors[SNAT_OUT2IN_ERROR_OUT_OF_PORTS];
966               return 0;
967             }
968           key.r_addr.as_u32 = s->ext_host_nat_addr.as_u32 = eh_key.addr.as_u32;
969           key.r_port = s->ext_host_nat_port = eh_key.port;
970           s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
971         }
972       key.l_addr = l_key.addr;
973       key.fib_index = l_key.fib_index;
974       key.l_port = l_key.port;
975       s_kv.key[0] = key.as_u64[0];
976       s_kv.key[1] = key.as_u64[1];
977       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1))
978         clib_warning ("in2out-ed key add failed");
979     }
980
981   new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
982
983   /* Update IP checksum */
984   sum = ip->checksum;
985   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
986   if (is_twice_nat_session (s))
987     sum = ip_csum_update (sum, ip->src_address.as_u32,
988                           s->ext_host_nat_addr.as_u32, ip4_header_t,
989                           src_address);
990   ip->checksum = ip_csum_fold (sum);
991
992   if (PREDICT_TRUE(proto == SNAT_PROTOCOL_TCP))
993     {
994       old_port = tcp->dst_port;
995       tcp->dst_port = s->in2out.port;
996       new_port = tcp->dst_port;
997
998       sum = tcp->checksum;
999       sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
1000       sum = ip_csum_update (sum, old_port, new_port, ip4_header_t, length);
1001       if (is_twice_nat_session (s))
1002         {
1003           sum = ip_csum_update (sum, ip->src_address.as_u32,
1004                                 s->ext_host_nat_addr.as_u32, ip4_header_t,
1005                                 dst_address);
1006           sum = ip_csum_update (sum, tcp->src_port, s->ext_host_nat_port,
1007                                 ip4_header_t, length);
1008           tcp->src_port = s->ext_host_nat_port;
1009           ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32;
1010         }
1011       tcp->checksum = ip_csum_fold(sum);
1012     }
1013   else
1014     {
1015       udp->dst_port = s->in2out.port;
1016       if (is_twice_nat_session (s))
1017         {
1018           udp->src_port = s->ext_host_nat_port;
1019           ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32;
1020         }
1021       udp->checksum = 0;
1022     }
1023
1024   vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
1025
1026   /* Accounting */
1027   s->last_heard = now;
1028   s->total_pkts++;
1029   s->total_bytes += vlib_buffer_length_in_chain (vm, b);
1030   /* Per-user LRU list maintenance */
1031   clib_dlist_remove (tsm->list_pool, s->per_user_index);
1032   clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
1033                       s->per_user_index);
1034
1035   return s;
1036 }
1037
1038 static uword
1039 snat_out2in_node_fn (vlib_main_t * vm,
1040                   vlib_node_runtime_t * node,
1041                   vlib_frame_t * frame)
1042 {
1043   u32 n_left_from, * from, * to_next;
1044   snat_out2in_next_t next_index;
1045   u32 pkts_processed = 0;
1046   snat_main_t * sm = &snat_main;
1047   f64 now = vlib_time_now (vm);
1048   u32 thread_index = vlib_get_thread_index ();
1049
1050   from = vlib_frame_vector_args (frame);
1051   n_left_from = frame->n_vectors;
1052   next_index = node->cached_next_index;
1053
1054   while (n_left_from > 0)
1055     {
1056       u32 n_left_to_next;
1057
1058       vlib_get_next_frame (vm, node, next_index,
1059                            to_next, n_left_to_next);
1060
1061       while (n_left_from >= 4 && n_left_to_next >= 2)
1062         {
1063           u32 bi0, bi1;
1064           vlib_buffer_t * b0, * b1;
1065           u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1066           u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
1067           u32 sw_if_index0, sw_if_index1;
1068           ip4_header_t * ip0, *ip1;
1069           ip_csum_t sum0, sum1;
1070           u32 new_addr0, old_addr0;
1071           u16 new_port0, old_port0;
1072           u32 new_addr1, old_addr1;
1073           u16 new_port1, old_port1;
1074           udp_header_t * udp0, * udp1;
1075           tcp_header_t * tcp0, * tcp1;
1076           icmp46_header_t * icmp0, * icmp1;
1077           snat_session_key_t key0, key1, sm0, sm1;
1078           u32 rx_fib_index0, rx_fib_index1;
1079           u32 proto0, proto1;
1080           snat_session_t * s0 = 0, * s1 = 0;
1081           clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
1082
1083           /* Prefetch next iteration. */
1084           {
1085             vlib_buffer_t * p2, * p3;
1086
1087             p2 = vlib_get_buffer (vm, from[2]);
1088             p3 = vlib_get_buffer (vm, from[3]);
1089
1090             vlib_prefetch_buffer_header (p2, LOAD);
1091             vlib_prefetch_buffer_header (p3, LOAD);
1092
1093             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
1094             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
1095           }
1096
1097           /* speculatively enqueue b0 and b1 to the current next frame */
1098           to_next[0] = bi0 = from[0];
1099           to_next[1] = bi1 = from[1];
1100           from += 2;
1101           to_next += 2;
1102           n_left_from -= 2;
1103           n_left_to_next -= 2;
1104
1105           b0 = vlib_get_buffer (vm, bi0);
1106           b1 = vlib_get_buffer (vm, bi1);
1107
1108           vnet_buffer (b0)->snat.flags = 0;
1109           vnet_buffer (b1)->snat.flags = 0;
1110
1111           ip0 = vlib_buffer_get_current (b0);
1112           udp0 = ip4_next_header (ip0);
1113           tcp0 = (tcp_header_t *) udp0;
1114           icmp0 = (icmp46_header_t *) udp0;
1115
1116           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1117           rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1118                                    sw_if_index0);
1119
1120           if (PREDICT_FALSE(ip0->ttl == 1))
1121             {
1122               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1123               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1124                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1125                                            0);
1126               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1127               goto trace0;
1128             }
1129
1130           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1131
1132           if (PREDICT_FALSE (proto0 == ~0))
1133             {
1134               s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
1135                                              thread_index, now, vm, node);
1136               if (!sm->forwarding_enabled)
1137                 if (!s0)
1138                   next0 = SNAT_OUT2IN_NEXT_DROP;
1139               goto trace0;
1140             }
1141
1142           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1143             {
1144               next0 = icmp_out2in_slow_path
1145                 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1146                  next0, now, thread_index, &s0);
1147               goto trace0;
1148             }
1149
1150           if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1151             {
1152               next0 = SNAT_OUT2IN_NEXT_REASS;
1153               goto trace0;
1154             }
1155
1156           key0.addr = ip0->dst_address;
1157           key0.port = udp0->dst_port;
1158           key0.protocol = proto0;
1159           key0.fib_index = rx_fib_index0;
1160
1161           kv0.key = key0.as_u64;
1162
1163           if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1164                                       &kv0, &value0))
1165             {
1166               /* Try to match static mapping by external address and port,
1167                  destination address and port in packet */
1168               if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
1169                 {
1170                   if (!sm->forwarding_enabled)
1171                     {
1172                       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1173                       /*
1174                        * Send DHCP packets to the ipv4 stack, or we won't
1175                        * be able to use dhcp client on the outside interface
1176                        */
1177                       if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP
1178                           || (udp0->dst_port
1179                               != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1180                         next0 = SNAT_OUT2IN_NEXT_DROP;
1181                       else
1182                         vnet_feature_next
1183                           (vnet_buffer (b0)->sw_if_index[VLIB_RX],
1184                            &next0, b0);
1185                       goto trace0;
1186                     }
1187                   else
1188                     {
1189                       if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1190                         {
1191                           next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1192                           goto trace0;
1193                         }
1194                       create_bypass_for_fwd(sm, ip0);
1195                       goto trace0;
1196                     }
1197                 }
1198
1199               /* Create session initiated by host from external network */
1200               s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1201                                                      thread_index);
1202               if (!s0)
1203                 {
1204                   next0 = SNAT_OUT2IN_NEXT_DROP;
1205                   goto trace0;
1206                 }
1207             }
1208           else
1209             {
1210               if (PREDICT_FALSE (value0.value == ~0ULL))
1211                 {
1212                   s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index,
1213                                       now, vm, node);
1214                   if (!s0)
1215                     next0 = SNAT_OUT2IN_NEXT_DROP;
1216                   goto trace0;
1217                 }
1218               else
1219                 {
1220                   s0 = pool_elt_at_index (
1221                     sm->per_thread_data[thread_index].sessions,
1222                     value0.value);
1223                 }
1224             }
1225
1226           old_addr0 = ip0->dst_address.as_u32;
1227           ip0->dst_address = s0->in2out.addr;
1228           new_addr0 = ip0->dst_address.as_u32;
1229           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1230
1231           sum0 = ip0->checksum;
1232           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1233                                  ip4_header_t,
1234                                  dst_address /* changed member */);
1235           ip0->checksum = ip_csum_fold (sum0);
1236
1237           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1238             {
1239               old_port0 = tcp0->dst_port;
1240               tcp0->dst_port = s0->in2out.port;
1241               new_port0 = tcp0->dst_port;
1242
1243               sum0 = tcp0->checksum;
1244               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1245                                      ip4_header_t,
1246                                      dst_address /* changed member */);
1247
1248               sum0 = ip_csum_update (sum0, old_port0, new_port0,
1249                                      ip4_header_t /* cheat */,
1250                                      length /* changed member */);
1251               tcp0->checksum = ip_csum_fold(sum0);
1252             }
1253           else
1254             {
1255               old_port0 = udp0->dst_port;
1256               udp0->dst_port = s0->in2out.port;
1257               udp0->checksum = 0;
1258             }
1259
1260           /* Accounting */
1261           s0->last_heard = now;
1262           s0->total_pkts++;
1263           s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1264           /* Per-user LRU list maintenance */
1265           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1266                              s0->per_user_index);
1267           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1268                               s0->per_user_list_head_index,
1269                               s0->per_user_index);
1270         trace0:
1271
1272           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1273                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1274             {
1275               snat_out2in_trace_t *t =
1276                  vlib_add_trace (vm, node, b0, sizeof (*t));
1277               t->sw_if_index = sw_if_index0;
1278               t->next_index = next0;
1279               t->session_index = ~0;
1280               if (s0)
1281                 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1282             }
1283
1284           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1285
1286
1287           ip1 = vlib_buffer_get_current (b1);
1288           udp1 = ip4_next_header (ip1);
1289           tcp1 = (tcp_header_t *) udp1;
1290           icmp1 = (icmp46_header_t *) udp1;
1291
1292           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1293           rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1294                                    sw_if_index1);
1295
1296           if (PREDICT_FALSE(ip1->ttl == 1))
1297             {
1298               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1299               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
1300                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1301                                            0);
1302               next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1303               goto trace1;
1304             }
1305
1306           proto1 = ip_proto_to_snat_proto (ip1->protocol);
1307
1308           if (PREDICT_FALSE (proto1 == ~0))
1309             {
1310               s1 = snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1,
1311                                              thread_index, now, vm, node);
1312               if (!sm->forwarding_enabled)
1313                 if (!s1)
1314                   next1 = SNAT_OUT2IN_NEXT_DROP;
1315               goto trace1;
1316             }
1317
1318           if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
1319             {
1320               next1 = icmp_out2in_slow_path
1321                 (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
1322                  next1, now, thread_index, &s1);
1323               goto trace1;
1324             }
1325
1326           if (PREDICT_FALSE (ip4_is_fragment (ip1)))
1327             {
1328               next1 = SNAT_OUT2IN_NEXT_REASS;
1329               goto trace1;
1330             }
1331
1332           key1.addr = ip1->dst_address;
1333           key1.port = udp1->dst_port;
1334           key1.protocol = proto1;
1335           key1.fib_index = rx_fib_index1;
1336
1337           kv1.key = key1.as_u64;
1338
1339           if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1340                                       &kv1, &value1))
1341             {
1342               /* Try to match static mapping by external address and port,
1343                  destination address and port in packet */
1344               if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0, 0))
1345                 {
1346                   if (!sm->forwarding_enabled)
1347                     {
1348                       b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1349                       /*
1350                        * Send DHCP packets to the ipv4 stack, or we won't
1351                        * be able to use dhcp client on the outside interface
1352                        */
1353                       if (PREDICT_TRUE (proto1 != SNAT_PROTOCOL_UDP
1354                           || (udp1->dst_port
1355                               != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1356                         next1 = SNAT_OUT2IN_NEXT_DROP;
1357                       else
1358                         vnet_feature_next
1359                           (vnet_buffer (b1)->sw_if_index[VLIB_RX],
1360                            &next1, b1);
1361                       goto trace1;
1362                     }
1363                   else
1364                     {
1365                       if (next_src_nat(sm, ip1, proto1, udp1->src_port, thread_index))
1366                         {
1367                           next1 = SNAT_OUT2IN_NEXT_IN2OUT;
1368                           goto trace1;
1369                         }
1370                       create_bypass_for_fwd(sm, ip1);
1371                       goto trace1;
1372                     }
1373                 }
1374
1375               /* Create session initiated by host from external network */
1376               s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node,
1377                                                      thread_index);
1378               if (!s1)
1379                 {
1380                   next1 = SNAT_OUT2IN_NEXT_DROP;
1381                   goto trace1;
1382                 }
1383             }
1384           else
1385             {
1386               if (PREDICT_FALSE (value1.value == ~0ULL))
1387                 {
1388                   s1 = snat_out2in_lb(sm, b1, ip1, rx_fib_index1, thread_index,
1389                                       now, vm, node);
1390                   if (!s1)
1391                     next1 = SNAT_OUT2IN_NEXT_DROP;
1392                   goto trace1;
1393                 }
1394               else
1395                 {
1396                   s1 = pool_elt_at_index (
1397                     sm->per_thread_data[thread_index].sessions,
1398                     value1.value);
1399                 }
1400             }
1401
1402           old_addr1 = ip1->dst_address.as_u32;
1403           ip1->dst_address = s1->in2out.addr;
1404           new_addr1 = ip1->dst_address.as_u32;
1405           vnet_buffer(b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1406
1407           sum1 = ip1->checksum;
1408           sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1409                                  ip4_header_t,
1410                                  dst_address /* changed member */);
1411           ip1->checksum = ip_csum_fold (sum1);
1412
1413           if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
1414             {
1415               old_port1 = tcp1->dst_port;
1416               tcp1->dst_port = s1->in2out.port;
1417               new_port1 = tcp1->dst_port;
1418
1419               sum1 = tcp1->checksum;
1420               sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1421                                      ip4_header_t,
1422                                      dst_address /* changed member */);
1423
1424               sum1 = ip_csum_update (sum1, old_port1, new_port1,
1425                                      ip4_header_t /* cheat */,
1426                                      length /* changed member */);
1427               tcp1->checksum = ip_csum_fold(sum1);
1428             }
1429           else
1430             {
1431               old_port1 = udp1->dst_port;
1432               udp1->dst_port = s1->in2out.port;
1433               udp1->checksum = 0;
1434             }
1435
1436           /* Accounting */
1437           s1->last_heard = now;
1438           s1->total_pkts++;
1439           s1->total_bytes += vlib_buffer_length_in_chain (vm, b1);
1440           /* Per-user LRU list maintenance */
1441           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1442                              s1->per_user_index);
1443           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1444                               s1->per_user_list_head_index,
1445                               s1->per_user_index);
1446         trace1:
1447
1448           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1449                             && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1450             {
1451               snat_out2in_trace_t *t =
1452                  vlib_add_trace (vm, node, b1, sizeof (*t));
1453               t->sw_if_index = sw_if_index1;
1454               t->next_index = next1;
1455               t->session_index = ~0;
1456               if (s1)
1457                 t->session_index = s1 - sm->per_thread_data[thread_index].sessions;
1458             }
1459
1460           pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
1461
1462           /* verify speculative enqueues, maybe switch current next frame */
1463           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1464                                            to_next, n_left_to_next,
1465                                            bi0, bi1, next0, next1);
1466         }
1467
1468       while (n_left_from > 0 && n_left_to_next > 0)
1469         {
1470           u32 bi0;
1471           vlib_buffer_t * b0;
1472           u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1473           u32 sw_if_index0;
1474           ip4_header_t * ip0;
1475           ip_csum_t sum0;
1476           u32 new_addr0, old_addr0;
1477           u16 new_port0, old_port0;
1478           udp_header_t * udp0;
1479           tcp_header_t * tcp0;
1480           icmp46_header_t * icmp0;
1481           snat_session_key_t key0, sm0;
1482           u32 rx_fib_index0;
1483           u32 proto0;
1484           snat_session_t * s0 = 0;
1485           clib_bihash_kv_8_8_t kv0, value0;
1486
1487           /* speculatively enqueue b0 to the current next frame */
1488           bi0 = from[0];
1489           to_next[0] = bi0;
1490           from += 1;
1491           to_next += 1;
1492           n_left_from -= 1;
1493           n_left_to_next -= 1;
1494
1495           b0 = vlib_get_buffer (vm, bi0);
1496
1497           vnet_buffer (b0)->snat.flags = 0;
1498
1499           ip0 = vlib_buffer_get_current (b0);
1500           udp0 = ip4_next_header (ip0);
1501           tcp0 = (tcp_header_t *) udp0;
1502           icmp0 = (icmp46_header_t *) udp0;
1503
1504           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1505           rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
1506                                    sw_if_index0);
1507
1508           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1509
1510           if (PREDICT_FALSE (proto0 == ~0))
1511             {
1512               s0 = snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0,
1513                                              thread_index, now, vm, node);
1514               if (!sm->forwarding_enabled)
1515                 if (!s0)
1516                   next0 = SNAT_OUT2IN_NEXT_DROP;
1517               goto trace00;
1518             }
1519
1520           if (PREDICT_FALSE(ip0->ttl == 1))
1521             {
1522               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1523               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1524                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
1525                                            0);
1526               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
1527               goto trace00;
1528             }
1529
1530           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
1531             {
1532               next0 = icmp_out2in_slow_path
1533                 (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
1534                  next0, now, thread_index, &s0);
1535               goto trace00;
1536             }
1537
1538           if (PREDICT_FALSE (ip4_is_fragment (ip0)))
1539             {
1540               next0 = SNAT_OUT2IN_NEXT_REASS;
1541               goto trace00;
1542             }
1543
1544           key0.addr = ip0->dst_address;
1545           key0.port = udp0->dst_port;
1546           key0.protocol = proto0;
1547           key0.fib_index = rx_fib_index0;
1548
1549           kv0.key = key0.as_u64;
1550
1551           if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in,
1552                                       &kv0, &value0))
1553             {
1554               /* Try to match static mapping by external address and port,
1555                  destination address and port in packet */
1556               if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
1557                 {
1558                   if (!sm->forwarding_enabled)
1559                     {
1560                       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1561                       /*
1562                        * Send DHCP packets to the ipv4 stack, or we won't
1563                        * be able to use dhcp client on the outside interface
1564                        */
1565                       if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP
1566                           || (udp0->dst_port
1567                               != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1568                         next0 = SNAT_OUT2IN_NEXT_DROP;
1569                       else
1570                         vnet_feature_next
1571                           (vnet_buffer (b0)->sw_if_index[VLIB_RX],
1572                            &next0, b0);
1573                       goto trace00;
1574                     }
1575                   else
1576                     {
1577                       if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1578                         {
1579                           next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1580                           goto trace00;
1581                         }
1582                       create_bypass_for_fwd(sm, ip0);
1583                       goto trace00;
1584                     }
1585                 }
1586
1587               /* Create session initiated by host from external network */
1588               s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1589                                                      thread_index);
1590               if (!s0)
1591                 {
1592                   next0 = SNAT_OUT2IN_NEXT_DROP;
1593                   goto trace00;
1594                 }
1595             }
1596           else
1597             {
1598               if (PREDICT_FALSE (value0.value == ~0ULL))
1599                 {
1600                   s0 = snat_out2in_lb(sm, b0, ip0, rx_fib_index0, thread_index,
1601                                       now, vm, node);
1602                   if (!s0)
1603                     next0 = SNAT_OUT2IN_NEXT_DROP;
1604                   goto trace00;
1605                 }
1606               else
1607                 {
1608                   s0 = pool_elt_at_index (
1609                     sm->per_thread_data[thread_index].sessions,
1610                     value0.value);
1611                 }
1612             }
1613
1614           old_addr0 = ip0->dst_address.as_u32;
1615           ip0->dst_address = s0->in2out.addr;
1616           new_addr0 = ip0->dst_address.as_u32;
1617           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1618
1619           sum0 = ip0->checksum;
1620           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1621                                  ip4_header_t,
1622                                  dst_address /* changed member */);
1623           ip0->checksum = ip_csum_fold (sum0);
1624
1625           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1626             {
1627               old_port0 = tcp0->dst_port;
1628               tcp0->dst_port = s0->in2out.port;
1629               new_port0 = tcp0->dst_port;
1630
1631               sum0 = tcp0->checksum;
1632               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1633                                      ip4_header_t,
1634                                      dst_address /* changed member */);
1635
1636               sum0 = ip_csum_update (sum0, old_port0, new_port0,
1637                                      ip4_header_t /* cheat */,
1638                                      length /* changed member */);
1639               tcp0->checksum = ip_csum_fold(sum0);
1640             }
1641           else
1642             {
1643               old_port0 = udp0->dst_port;
1644               udp0->dst_port = s0->in2out.port;
1645               udp0->checksum = 0;
1646             }
1647
1648           /* Accounting */
1649           s0->last_heard = now;
1650           s0->total_pkts++;
1651           s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1652           /* Per-user LRU list maintenance */
1653           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1654                              s0->per_user_index);
1655           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1656                               s0->per_user_list_head_index,
1657                               s0->per_user_index);
1658         trace00:
1659
1660           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1661                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1662             {
1663               snat_out2in_trace_t *t =
1664                  vlib_add_trace (vm, node, b0, sizeof (*t));
1665               t->sw_if_index = sw_if_index0;
1666               t->next_index = next0;
1667               t->session_index = ~0;
1668               if (s0)
1669                 t->session_index = s0 - sm->per_thread_data[thread_index].sessions;
1670             }
1671
1672           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1673
1674           /* verify speculative enqueue, maybe switch current next frame */
1675           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1676                                            to_next, n_left_to_next,
1677                                            bi0, next0);
1678         }
1679
1680       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1681     }
1682
1683   vlib_node_increment_counter (vm, snat_out2in_node.index,
1684                                SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1685                                pkts_processed);
1686   return frame->n_vectors;
1687 }
1688
1689 VLIB_REGISTER_NODE (snat_out2in_node) = {
1690   .function = snat_out2in_node_fn,
1691   .name = "nat44-out2in",
1692   .vector_size = sizeof (u32),
1693   .format_trace = format_snat_out2in_trace,
1694   .type = VLIB_NODE_TYPE_INTERNAL,
1695
1696   .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1697   .error_strings = snat_out2in_error_strings,
1698
1699   .runtime_data_bytes = sizeof (snat_runtime_t),
1700
1701   .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1702
1703   /* edit / add dispositions here */
1704   .next_nodes = {
1705     [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
1706     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1707     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1708     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
1709     [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
1710   },
1711 };
1712 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_node, snat_out2in_node_fn);
1713
1714 static uword
1715 nat44_out2in_reass_node_fn (vlib_main_t * vm,
1716                             vlib_node_runtime_t * node,
1717                             vlib_frame_t * frame)
1718 {
1719   u32 n_left_from, *from, *to_next;
1720   snat_out2in_next_t next_index;
1721   u32 pkts_processed = 0;
1722   snat_main_t *sm = &snat_main;
1723   f64 now = vlib_time_now (vm);
1724   u32 thread_index = vlib_get_thread_index ();
1725   snat_main_per_thread_data_t *per_thread_data =
1726     &sm->per_thread_data[thread_index];
1727   u32 *fragments_to_drop = 0;
1728   u32 *fragments_to_loopback = 0;
1729
1730   from = vlib_frame_vector_args (frame);
1731   n_left_from = frame->n_vectors;
1732   next_index = node->cached_next_index;
1733
1734   while (n_left_from > 0)
1735     {
1736       u32 n_left_to_next;
1737
1738       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1739
1740       while (n_left_from > 0 && n_left_to_next > 0)
1741        {
1742           u32 bi0, sw_if_index0, proto0, rx_fib_index0, new_addr0, old_addr0;
1743           vlib_buffer_t *b0;
1744           u32 next0;
1745           u8 cached0 = 0;
1746           ip4_header_t *ip0;
1747           nat_reass_ip4_t *reass0;
1748           udp_header_t * udp0;
1749           tcp_header_t * tcp0;
1750           snat_session_key_t key0, sm0;
1751           clib_bihash_kv_8_8_t kv0, value0;
1752           snat_session_t * s0 = 0;
1753           u16 old_port0, new_port0;
1754           ip_csum_t sum0;
1755
1756           /* speculatively enqueue b0 to the current next frame */
1757           bi0 = from[0];
1758           to_next[0] = bi0;
1759           from += 1;
1760           to_next += 1;
1761           n_left_from -= 1;
1762           n_left_to_next -= 1;
1763
1764           b0 = vlib_get_buffer (vm, bi0);
1765           next0 = SNAT_OUT2IN_NEXT_LOOKUP;
1766
1767           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1768           rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1769                                                                sw_if_index0);
1770
1771           if (PREDICT_FALSE (nat_reass_is_drop_frag(0)))
1772             {
1773               next0 = SNAT_OUT2IN_NEXT_DROP;
1774               b0->error = node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT];
1775               goto trace0;
1776             }
1777
1778           ip0 = (ip4_header_t *) vlib_buffer_get_current (b0);
1779           udp0 = ip4_next_header (ip0);
1780           tcp0 = (tcp_header_t *) udp0;
1781           proto0 = ip_proto_to_snat_proto (ip0->protocol);
1782
1783           reass0 = nat_ip4_reass_find_or_create (ip0->src_address,
1784                                                  ip0->dst_address,
1785                                                  ip0->fragment_id,
1786                                                  ip0->protocol,
1787                                                  1,
1788                                                  &fragments_to_drop);
1789
1790           if (PREDICT_FALSE (!reass0))
1791             {
1792               next0 = SNAT_OUT2IN_NEXT_DROP;
1793               b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS];
1794               goto trace0;
1795             }
1796
1797           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1798             {
1799               key0.addr = ip0->dst_address;
1800               key0.port = udp0->dst_port;
1801               key0.protocol = proto0;
1802               key0.fib_index = rx_fib_index0;
1803               kv0.key = key0.as_u64;
1804
1805               if (clib_bihash_search_8_8 (&per_thread_data->out2in, &kv0, &value0))
1806                 {
1807                   /* Try to match static mapping by external address and port,
1808                      destination address and port in packet */
1809                   if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
1810                     {
1811                       if (!sm->forwarding_enabled)
1812                         {
1813                           b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1814                           /*
1815                            * Send DHCP packets to the ipv4 stack, or we won't
1816                            * be able to use dhcp client on the outside interface
1817                            */
1818                           if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP
1819                               || (udp0->dst_port
1820                                   != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))))
1821                             next0 = SNAT_OUT2IN_NEXT_DROP;
1822                           else
1823                             vnet_feature_next
1824                               (vnet_buffer (b0)->sw_if_index[VLIB_RX],
1825                                &next0, b0);
1826                           goto trace0;
1827                         }
1828                       else
1829                         {
1830                           if (next_src_nat(sm, ip0, proto0, udp0->src_port, thread_index))
1831                             {
1832                               next0 = SNAT_OUT2IN_NEXT_IN2OUT;
1833                               goto trace0;
1834                             }
1835                           create_bypass_for_fwd(sm, ip0);
1836                           goto trace0;
1837                         }
1838                     }
1839
1840                   /* Create session initiated by host from external network */
1841                   s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node,
1842                                                          thread_index);
1843                   if (!s0)
1844                     {
1845                       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
1846                       next0 = SNAT_OUT2IN_NEXT_DROP;
1847                       goto trace0;
1848                     }
1849                   reass0->sess_index = s0 - per_thread_data->sessions;
1850                   reass0->thread_index = thread_index;
1851                 }
1852               else
1853                 {
1854                   s0 = pool_elt_at_index (per_thread_data->sessions,
1855                                           value0.value);
1856                   reass0->sess_index = value0.value;
1857                 }
1858               nat_ip4_reass_get_frags (reass0, &fragments_to_loopback);
1859             }
1860           else
1861             {
1862               if (PREDICT_FALSE (reass0->sess_index == (u32) ~0))
1863                 {
1864                   if (nat_ip4_reass_add_fragment (reass0, bi0))
1865                     {
1866                       b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG];
1867                       next0 = SNAT_OUT2IN_NEXT_DROP;
1868                       goto trace0;
1869                     }
1870                   cached0 = 1;
1871                   goto trace0;
1872                 }
1873               s0 = pool_elt_at_index (per_thread_data->sessions,
1874                                       reass0->sess_index);
1875             }
1876
1877           old_addr0 = ip0->dst_address.as_u32;
1878           ip0->dst_address = s0->in2out.addr;
1879           new_addr0 = ip0->dst_address.as_u32;
1880           vnet_buffer(b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1881
1882           sum0 = ip0->checksum;
1883           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1884                                  ip4_header_t,
1885                                  dst_address /* changed member */);
1886           ip0->checksum = ip_csum_fold (sum0);
1887
1888           if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
1889             {
1890               if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
1891                 {
1892                   old_port0 = tcp0->dst_port;
1893                   tcp0->dst_port = s0->in2out.port;
1894                   new_port0 = tcp0->dst_port;
1895
1896                   sum0 = tcp0->checksum;
1897                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1898                                          ip4_header_t,
1899                                          dst_address /* changed member */);
1900
1901                   sum0 = ip_csum_update (sum0, old_port0, new_port0,
1902                                          ip4_header_t /* cheat */,
1903                                          length /* changed member */);
1904                   tcp0->checksum = ip_csum_fold(sum0);
1905                 }
1906               else
1907                 {
1908                   old_port0 = udp0->dst_port;
1909                   udp0->dst_port = s0->in2out.port;
1910                   udp0->checksum = 0;
1911                 }
1912             }
1913
1914           /* Accounting */
1915           s0->last_heard = now;
1916           s0->total_pkts++;
1917           s0->total_bytes += vlib_buffer_length_in_chain (vm, b0);
1918           /* Per-user LRU list maintenance */
1919           clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
1920                              s0->per_user_index);
1921           clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
1922                               s0->per_user_list_head_index,
1923                               s0->per_user_index);
1924
1925         trace0:
1926           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
1927                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1928             {
1929               nat44_out2in_reass_trace_t *t =
1930                  vlib_add_trace (vm, node, b0, sizeof (*t));
1931               t->cached = cached0;
1932               t->sw_if_index = sw_if_index0;
1933               t->next_index = next0;
1934             }
1935
1936           if (cached0)
1937             {
1938               n_left_to_next++;
1939               to_next--;
1940             }
1941           else
1942             {
1943               pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
1944
1945               /* verify speculative enqueue, maybe switch current next frame */
1946               vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1947                                                to_next, n_left_to_next,
1948                                                bi0, next0);
1949             }
1950
1951           if (n_left_from == 0 && vec_len (fragments_to_loopback))
1952             {
1953               from = vlib_frame_vector_args (frame);
1954               u32 len = vec_len (fragments_to_loopback);
1955               if (len <= VLIB_FRAME_SIZE)
1956                 {
1957                   clib_memcpy (from, fragments_to_loopback, sizeof (u32) * len);
1958                   n_left_from = len;
1959                   vec_reset_length (fragments_to_loopback);
1960                 }
1961               else
1962                 {
1963                   clib_memcpy (from,
1964                                fragments_to_loopback + (len - VLIB_FRAME_SIZE),
1965                                sizeof (u32) * VLIB_FRAME_SIZE);
1966                   n_left_from = VLIB_FRAME_SIZE;
1967                   _vec_len (fragments_to_loopback) = len - VLIB_FRAME_SIZE;
1968                 }
1969             }
1970        }
1971
1972       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1973     }
1974
1975   vlib_node_increment_counter (vm, nat44_out2in_reass_node.index,
1976                                SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
1977                                pkts_processed);
1978
1979   nat_send_all_to_node (vm, fragments_to_drop, node,
1980                         &node->errors[SNAT_OUT2IN_ERROR_DROP_FRAGMENT],
1981                         SNAT_OUT2IN_NEXT_DROP);
1982
1983   vec_free (fragments_to_drop);
1984   vec_free (fragments_to_loopback);
1985   return frame->n_vectors;
1986 }
1987
1988 VLIB_REGISTER_NODE (nat44_out2in_reass_node) = {
1989   .function = nat44_out2in_reass_node_fn,
1990   .name = "nat44-out2in-reass",
1991   .vector_size = sizeof (u32),
1992   .format_trace = format_nat44_out2in_reass_trace,
1993   .type = VLIB_NODE_TYPE_INTERNAL,
1994
1995   .n_errors = ARRAY_LEN(snat_out2in_error_strings),
1996   .error_strings = snat_out2in_error_strings,
1997
1998   .n_next_nodes = SNAT_OUT2IN_N_NEXT,
1999
2000   /* edit / add dispositions here */
2001   .next_nodes = {
2002     [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2003     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2004     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2005     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2006     [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
2007   },
2008 };
2009 VLIB_NODE_FUNCTION_MULTIARCH (nat44_out2in_reass_node,
2010                               nat44_out2in_reass_node_fn);
2011
2012 /**************************/
2013 /*** deterministic mode ***/
2014 /**************************/
2015 static uword
2016 snat_det_out2in_node_fn (vlib_main_t * vm,
2017                          vlib_node_runtime_t * node,
2018                          vlib_frame_t * frame)
2019 {
2020   u32 n_left_from, * from, * to_next;
2021   snat_out2in_next_t next_index;
2022   u32 pkts_processed = 0;
2023   snat_main_t * sm = &snat_main;
2024   u32 thread_index = vlib_get_thread_index ();
2025
2026   from = vlib_frame_vector_args (frame);
2027   n_left_from = frame->n_vectors;
2028   next_index = node->cached_next_index;
2029
2030   while (n_left_from > 0)
2031     {
2032       u32 n_left_to_next;
2033
2034       vlib_get_next_frame (vm, node, next_index,
2035                            to_next, n_left_to_next);
2036
2037       while (n_left_from >= 4 && n_left_to_next >= 2)
2038         {
2039           u32 bi0, bi1;
2040           vlib_buffer_t * b0, * b1;
2041           u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
2042           u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
2043           u32 sw_if_index0, sw_if_index1;
2044           ip4_header_t * ip0, * ip1;
2045           ip_csum_t sum0, sum1;
2046           ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
2047           u16 new_port0, old_port0, old_port1, new_port1;
2048           udp_header_t * udp0, * udp1;
2049           tcp_header_t * tcp0, * tcp1;
2050           u32 proto0, proto1;
2051           snat_det_out_key_t key0, key1;
2052           snat_det_map_t * dm0, * dm1;
2053           snat_det_session_t * ses0 = 0, * ses1 = 0;
2054           u32 rx_fib_index0, rx_fib_index1;
2055           icmp46_header_t * icmp0, * icmp1;
2056
2057           /* Prefetch next iteration. */
2058           {
2059             vlib_buffer_t * p2, * p3;
2060
2061             p2 = vlib_get_buffer (vm, from[2]);
2062             p3 = vlib_get_buffer (vm, from[3]);
2063
2064             vlib_prefetch_buffer_header (p2, LOAD);
2065             vlib_prefetch_buffer_header (p3, LOAD);
2066
2067             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
2068             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
2069           }
2070
2071           /* speculatively enqueue b0 and b1 to the current next frame */
2072           to_next[0] = bi0 = from[0];
2073           to_next[1] = bi1 = from[1];
2074           from += 2;
2075           to_next += 2;
2076           n_left_from -= 2;
2077           n_left_to_next -= 2;
2078
2079           b0 = vlib_get_buffer (vm, bi0);
2080           b1 = vlib_get_buffer (vm, bi1);
2081
2082           ip0 = vlib_buffer_get_current (b0);
2083           udp0 = ip4_next_header (ip0);
2084           tcp0 = (tcp_header_t *) udp0;
2085
2086           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2087
2088           if (PREDICT_FALSE(ip0->ttl == 1))
2089             {
2090               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2091               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2092                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2093                                            0);
2094               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
2095               goto trace0;
2096             }
2097
2098           proto0 = ip_proto_to_snat_proto (ip0->protocol);
2099
2100           if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2101             {
2102               rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2103               icmp0 = (icmp46_header_t *) udp0;
2104
2105               next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2106                                   rx_fib_index0, node, next0, thread_index,
2107                                   &ses0, &dm0);
2108               goto trace0;
2109             }
2110
2111           key0.ext_host_addr = ip0->src_address;
2112           key0.ext_host_port = tcp0->src;
2113           key0.out_port = tcp0->dst;
2114
2115           dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
2116           if (PREDICT_FALSE(!dm0))
2117             {
2118               clib_warning("unknown dst address:  %U",
2119                            format_ip4_address, &ip0->dst_address);
2120               next0 = SNAT_OUT2IN_NEXT_DROP;
2121               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2122               goto trace0;
2123             }
2124
2125           snat_det_reverse(dm0, &ip0->dst_address,
2126                            clib_net_to_host_u16(tcp0->dst), &new_addr0);
2127
2128           ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2129           if (PREDICT_FALSE(!ses0))
2130             {
2131               clib_warning("no match src %U:%d dst %U:%d for user %U",
2132                            format_ip4_address, &ip0->src_address,
2133                            clib_net_to_host_u16 (tcp0->src),
2134                            format_ip4_address, &ip0->dst_address,
2135                            clib_net_to_host_u16 (tcp0->dst),
2136                            format_ip4_address, &new_addr0);
2137               next0 = SNAT_OUT2IN_NEXT_DROP;
2138               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2139               goto trace0;
2140             }
2141           new_port0 = ses0->in_port;
2142
2143           old_addr0 = ip0->dst_address;
2144           ip0->dst_address = new_addr0;
2145           vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2146
2147           sum0 = ip0->checksum;
2148           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2149                                  ip4_header_t,
2150                                  dst_address /* changed member */);
2151           ip0->checksum = ip_csum_fold (sum0);
2152
2153           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2154             {
2155               if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2156                 ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2157               else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
2158                 snat_det_ses_close(dm0, ses0);
2159
2160               old_port0 = tcp0->dst;
2161               tcp0->dst = new_port0;
2162
2163               sum0 = tcp0->checksum;
2164               sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2165                                      ip4_header_t,
2166                                      dst_address /* changed member */);
2167
2168               sum0 = ip_csum_update (sum0, old_port0, new_port0,
2169                                      ip4_header_t /* cheat */,
2170                                      length /* changed member */);
2171               tcp0->checksum = ip_csum_fold(sum0);
2172             }
2173           else
2174             {
2175               old_port0 = udp0->dst_port;
2176               udp0->dst_port = new_port0;
2177               udp0->checksum = 0;
2178             }
2179
2180         trace0:
2181
2182           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2183                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2184             {
2185               snat_out2in_trace_t *t =
2186                  vlib_add_trace (vm, node, b0, sizeof (*t));
2187               t->sw_if_index = sw_if_index0;
2188               t->next_index = next0;
2189               t->session_index = ~0;
2190               if (ses0)
2191                 t->session_index = ses0 - dm0->sessions;
2192             }
2193
2194           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2195
2196           b1 = vlib_get_buffer (vm, bi1);
2197
2198           ip1 = vlib_buffer_get_current (b1);
2199           udp1 = ip4_next_header (ip1);
2200           tcp1 = (tcp_header_t *) udp1;
2201
2202           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
2203
2204           if (PREDICT_FALSE(ip1->ttl == 1))
2205             {
2206               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2207               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
2208                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2209                                            0);
2210               next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
2211               goto trace1;
2212             }
2213
2214           proto1 = ip_proto_to_snat_proto (ip1->protocol);
2215
2216           if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP))
2217             {
2218               rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1);
2219               icmp1 = (icmp46_header_t *) udp1;
2220
2221               next1 = icmp_out2in(sm, b1, ip1, icmp1, sw_if_index1,
2222                                   rx_fib_index1, node, next1, thread_index,
2223                                   &ses1, &dm1);
2224               goto trace1;
2225             }
2226
2227           key1.ext_host_addr = ip1->src_address;
2228           key1.ext_host_port = tcp1->src;
2229           key1.out_port = tcp1->dst;
2230
2231           dm1 = snat_det_map_by_out(sm, &ip1->dst_address);
2232           if (PREDICT_FALSE(!dm1))
2233             {
2234               clib_warning("unknown dst address:  %U",
2235                            format_ip4_address, &ip1->dst_address);
2236               next1 = SNAT_OUT2IN_NEXT_DROP;
2237               b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2238               goto trace1;
2239             }
2240
2241           snat_det_reverse(dm1, &ip1->dst_address,
2242                            clib_net_to_host_u16(tcp1->dst), &new_addr1);
2243
2244           ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64);
2245           if (PREDICT_FALSE(!ses1))
2246             {
2247               clib_warning("no match src %U:%d dst %U:%d for user %U",
2248                            format_ip4_address, &ip1->src_address,
2249                            clib_net_to_host_u16 (tcp1->src),
2250                            format_ip4_address, &ip1->dst_address,
2251                            clib_net_to_host_u16 (tcp1->dst),
2252                            format_ip4_address, &new_addr1);
2253               next1 = SNAT_OUT2IN_NEXT_DROP;
2254               b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2255               goto trace1;
2256             }
2257           new_port1 = ses1->in_port;
2258
2259           old_addr1 = ip1->dst_address;
2260           ip1->dst_address = new_addr1;
2261           vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2262
2263           sum1 = ip1->checksum;
2264           sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
2265                                  ip4_header_t,
2266                                  dst_address /* changed member */);
2267           ip1->checksum = ip_csum_fold (sum1);
2268
2269           if (PREDICT_TRUE(proto1 == SNAT_PROTOCOL_TCP))
2270             {
2271               if (tcp1->flags & TCP_FLAG_FIN && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
2272                 ses1->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2273               else if (tcp1->flags & TCP_FLAG_ACK && ses1->state == SNAT_SESSION_TCP_LAST_ACK)
2274                 snat_det_ses_close(dm1, ses1);
2275
2276               old_port1 = tcp1->dst;
2277               tcp1->dst = new_port1;
2278
2279               sum1 = tcp1->checksum;
2280               sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
2281                                      ip4_header_t,
2282                                      dst_address /* changed member */);
2283
2284               sum1 = ip_csum_update (sum1, old_port1, new_port1,
2285                                      ip4_header_t /* cheat */,
2286                                      length /* changed member */);
2287               tcp1->checksum = ip_csum_fold(sum1);
2288             }
2289           else
2290             {
2291               old_port1 = udp1->dst_port;
2292               udp1->dst_port = new_port1;
2293               udp1->checksum = 0;
2294             }
2295
2296         trace1:
2297
2298           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2299                             && (b1->flags & VLIB_BUFFER_IS_TRACED)))
2300             {
2301               snat_out2in_trace_t *t =
2302                  vlib_add_trace (vm, node, b1, sizeof (*t));
2303               t->sw_if_index = sw_if_index1;
2304               t->next_index = next1;
2305               t->session_index = ~0;
2306               if (ses1)
2307                 t->session_index = ses1 - dm1->sessions;
2308             }
2309
2310           pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP;
2311
2312           /* verify speculative enqueues, maybe switch current next frame */
2313           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2314                                            to_next, n_left_to_next,
2315                                            bi0, bi1, next0, next1);
2316          }
2317
2318       while (n_left_from > 0 && n_left_to_next > 0)
2319         {
2320           u32 bi0;
2321           vlib_buffer_t * b0;
2322           u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
2323           u32 sw_if_index0;
2324           ip4_header_t * ip0;
2325           ip_csum_t sum0;
2326           ip4_address_t new_addr0, old_addr0;
2327           u16 new_port0, old_port0;
2328           udp_header_t * udp0;
2329           tcp_header_t * tcp0;
2330           u32 proto0;
2331           snat_det_out_key_t key0;
2332           snat_det_map_t * dm0;
2333           snat_det_session_t * ses0 = 0;
2334           u32 rx_fib_index0;
2335           icmp46_header_t * icmp0;
2336
2337           /* speculatively enqueue b0 to the current next frame */
2338           bi0 = from[0];
2339           to_next[0] = bi0;
2340           from += 1;
2341           to_next += 1;
2342           n_left_from -= 1;
2343           n_left_to_next -= 1;
2344
2345           b0 = vlib_get_buffer (vm, bi0);
2346
2347           ip0 = vlib_buffer_get_current (b0);
2348           udp0 = ip4_next_header (ip0);
2349           tcp0 = (tcp_header_t *) udp0;
2350
2351           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2352
2353           if (PREDICT_FALSE(ip0->ttl == 1))
2354             {
2355               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2356               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2357                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2358                                            0);
2359               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
2360               goto trace00;
2361             }
2362
2363           proto0 = ip_proto_to_snat_proto (ip0->protocol);
2364
2365           if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP))
2366             {
2367               rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2368               icmp0 = (icmp46_header_t *) udp0;
2369
2370               next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2371                                   rx_fib_index0, node, next0, thread_index,
2372                                   &ses0, &dm0);
2373               goto trace00;
2374             }
2375
2376           key0.ext_host_addr = ip0->src_address;
2377           key0.ext_host_port = tcp0->src;
2378           key0.out_port = tcp0->dst;
2379
2380           dm0 = snat_det_map_by_out(sm, &ip0->dst_address);
2381           if (PREDICT_FALSE(!dm0))
2382             {
2383               clib_warning("unknown dst address:  %U",
2384                            format_ip4_address, &ip0->dst_address);
2385               next0 = SNAT_OUT2IN_NEXT_DROP;
2386               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2387               goto trace00;
2388             }
2389
2390           snat_det_reverse(dm0, &ip0->dst_address,
2391                            clib_net_to_host_u16(tcp0->dst), &new_addr0);
2392
2393           ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2394           if (PREDICT_FALSE(!ses0))
2395             {
2396               clib_warning("no match src %U:%d dst %U:%d for user %U",
2397                            format_ip4_address, &ip0->src_address,
2398                            clib_net_to_host_u16 (tcp0->src),
2399                            format_ip4_address, &ip0->dst_address,
2400                            clib_net_to_host_u16 (tcp0->dst),
2401                            format_ip4_address, &new_addr0);
2402               next0 = SNAT_OUT2IN_NEXT_DROP;
2403               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2404               goto trace00;
2405             }
2406           new_port0 = ses0->in_port;
2407
2408           old_addr0 = ip0->dst_address;
2409           ip0->dst_address = new_addr0;
2410           vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index;
2411
2412           sum0 = ip0->checksum;
2413           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2414                                  ip4_header_t,
2415                                  dst_address /* changed member */);
2416           ip0->checksum = ip_csum_fold (sum0);
2417
2418           if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2419             {
2420               if (tcp0->flags & TCP_FLAG_FIN && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
2421                 ses0->state = SNAT_SESSION_TCP_CLOSE_WAIT;
2422               else if (tcp0->flags & TCP_FLAG_ACK && ses0->state == SNAT_SESSION_TCP_LAST_ACK)
2423                 snat_det_ses_close(dm0, ses0);
2424
2425               old_port0 = tcp0->dst;
2426               tcp0->dst = new_port0;
2427
2428               sum0 = tcp0->checksum;
2429               sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
2430                                      ip4_header_t,
2431                                      dst_address /* changed member */);
2432
2433               sum0 = ip_csum_update (sum0, old_port0, new_port0,
2434                                      ip4_header_t /* cheat */,
2435                                      length /* changed member */);
2436               tcp0->checksum = ip_csum_fold(sum0);
2437             }
2438           else
2439             {
2440               old_port0 = udp0->dst_port;
2441               udp0->dst_port = new_port0;
2442               udp0->checksum = 0;
2443             }
2444
2445         trace00:
2446
2447           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2448                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2449             {
2450               snat_out2in_trace_t *t =
2451                  vlib_add_trace (vm, node, b0, sizeof (*t));
2452               t->sw_if_index = sw_if_index0;
2453               t->next_index = next0;
2454               t->session_index = ~0;
2455               if (ses0)
2456                 t->session_index = ses0 - dm0->sessions;
2457             }
2458
2459           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2460
2461           /* verify speculative enqueue, maybe switch current next frame */
2462           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2463                                            to_next, n_left_to_next,
2464                                            bi0, next0);
2465         }
2466
2467       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2468     }
2469
2470   vlib_node_increment_counter (vm, snat_det_out2in_node.index,
2471                                SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2472                                pkts_processed);
2473   return frame->n_vectors;
2474 }
2475
2476 VLIB_REGISTER_NODE (snat_det_out2in_node) = {
2477   .function = snat_det_out2in_node_fn,
2478   .name = "nat44-det-out2in",
2479   .vector_size = sizeof (u32),
2480   .format_trace = format_snat_out2in_trace,
2481   .type = VLIB_NODE_TYPE_INTERNAL,
2482
2483   .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2484   .error_strings = snat_out2in_error_strings,
2485
2486   .runtime_data_bytes = sizeof (snat_runtime_t),
2487
2488   .n_next_nodes = SNAT_OUT2IN_N_NEXT,
2489
2490   /* edit / add dispositions here */
2491   .next_nodes = {
2492     [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2493     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2494     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2495     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2496     [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
2497   },
2498 };
2499 VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn);
2500
2501 /**
2502  * Get address and port values to be used for ICMP packet translation
2503  * and create session if needed
2504  *
2505  * @param[in,out] sm             NAT main
2506  * @param[in,out] node           NAT node runtime
2507  * @param[in] thread_index       thread index
2508  * @param[in,out] b0             buffer containing packet to be translated
2509  * @param[out] p_proto           protocol used for matching
2510  * @param[out] p_value           address and port after NAT translation
2511  * @param[out] p_dont_translate  if packet should not be translated
2512  * @param d                      optional parameter
2513  * @param e                      optional parameter
2514  */
2515 u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node,
2516                           u32 thread_index, vlib_buffer_t *b0,
2517                           ip4_header_t *ip0, u8 *p_proto,
2518                           snat_session_key_t *p_value,
2519                           u8 *p_dont_translate, void *d, void *e)
2520 {
2521   icmp46_header_t *icmp0;
2522   u32 sw_if_index0;
2523   u8 protocol;
2524   snat_det_out_key_t key0;
2525   u8 dont_translate = 0;
2526   u32 next0 = ~0;
2527   icmp_echo_header_t *echo0, *inner_echo0 = 0;
2528   ip4_header_t *inner_ip0;
2529   void *l4_header = 0;
2530   icmp46_header_t *inner_icmp0;
2531   snat_det_map_t * dm0 = 0;
2532   ip4_address_t new_addr0 = {{0}};
2533   snat_det_session_t * ses0 = 0;
2534   ip4_address_t out_addr;
2535
2536   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
2537   echo0 = (icmp_echo_header_t *)(icmp0+1);
2538   sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2539
2540   if (!icmp_is_error_message (icmp0))
2541     {
2542       protocol = SNAT_PROTOCOL_ICMP;
2543       key0.ext_host_addr = ip0->src_address;
2544       key0.ext_host_port = 0;
2545       key0.out_port = echo0->identifier;
2546       out_addr = ip0->dst_address;
2547     }
2548   else
2549     {
2550       inner_ip0 = (ip4_header_t *)(echo0+1);
2551       l4_header = ip4_next_header (inner_ip0);
2552       protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
2553       key0.ext_host_addr = inner_ip0->dst_address;
2554       out_addr = inner_ip0->src_address;
2555       switch (protocol)
2556         {
2557         case SNAT_PROTOCOL_ICMP:
2558           inner_icmp0 = (icmp46_header_t*)l4_header;
2559           inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1);
2560           key0.ext_host_port = 0;
2561           key0.out_port = inner_echo0->identifier;
2562           break;
2563         case SNAT_PROTOCOL_UDP:
2564         case SNAT_PROTOCOL_TCP:
2565           key0.ext_host_port = ((tcp_udp_header_t*)l4_header)->dst_port;
2566           key0.out_port = ((tcp_udp_header_t*)l4_header)->src_port;
2567           break;
2568         default:
2569           b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
2570           next0 = SNAT_OUT2IN_NEXT_DROP;
2571           goto out;
2572         }
2573     }
2574
2575   dm0 = snat_det_map_by_out(sm, &out_addr);
2576   if (PREDICT_FALSE(!dm0))
2577     {
2578       /* Don't NAT packet aimed at the intfc address */
2579       if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
2580                                           ip0->dst_address.as_u32)))
2581         {
2582           dont_translate = 1;
2583           goto out;
2584         }
2585       clib_warning("unknown dst address:  %U",
2586                    format_ip4_address, &ip0->dst_address);
2587       goto out;
2588     }
2589
2590   snat_det_reverse(dm0, &ip0->dst_address,
2591                    clib_net_to_host_u16(key0.out_port), &new_addr0);
2592
2593   ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64);
2594   if (PREDICT_FALSE(!ses0))
2595     {
2596       /* Don't NAT packet aimed at the intfc address */
2597       if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0,
2598                                           ip0->dst_address.as_u32)))
2599         {
2600           dont_translate = 1;
2601           goto out;
2602         }
2603       clib_warning("no match src %U:%d dst %U:%d for user %U",
2604                    format_ip4_address, &key0.ext_host_addr,
2605                    clib_net_to_host_u16 (key0.ext_host_port),
2606                    format_ip4_address, &out_addr,
2607                    clib_net_to_host_u16 (key0.out_port),
2608                    format_ip4_address, &new_addr0);
2609       b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2610       next0 = SNAT_OUT2IN_NEXT_DROP;
2611       goto out;
2612     }
2613
2614   if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply &&
2615                     !icmp_is_error_message (icmp0)))
2616     {
2617       b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
2618       next0 = SNAT_OUT2IN_NEXT_DROP;
2619       goto out;
2620     }
2621
2622   goto out;
2623
2624 out:
2625   *p_proto = protocol;
2626   if (ses0)
2627     {
2628       p_value->addr = new_addr0;
2629       p_value->fib_index = sm->inside_fib_index;
2630       p_value->port = ses0->in_port;
2631     }
2632   *p_dont_translate = dont_translate;
2633   if (d)
2634     *(snat_det_session_t**)d = ses0;
2635   if (e)
2636     *(snat_det_map_t**)e = dm0;
2637   return next0;
2638 }
2639
2640 /**********************/
2641 /*** worker handoff ***/
2642 /**********************/
2643 static uword
2644 snat_out2in_worker_handoff_fn (vlib_main_t * vm,
2645                                vlib_node_runtime_t * node,
2646                                vlib_frame_t * frame)
2647 {
2648   snat_main_t *sm = &snat_main;
2649   vlib_thread_main_t *tm = vlib_get_thread_main ();
2650   u32 n_left_from, *from, *to_next = 0;
2651   static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index;
2652   static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index
2653     = 0;
2654   vlib_frame_queue_elt_t *hf = 0;
2655   vlib_frame_t *f = 0;
2656   int i;
2657   u32 n_left_to_next_worker = 0, *to_next_worker = 0;
2658   u32 next_worker_index = 0;
2659   u32 current_worker_index = ~0;
2660   u32 thread_index = vlib_get_thread_index ();
2661
2662   ASSERT (vec_len (sm->workers));
2663
2664   if (PREDICT_FALSE (handoff_queue_elt_by_worker_index == 0))
2665     {
2666       vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1);
2667
2668       vec_validate_init_empty (congested_handoff_queue_by_worker_index,
2669                                sm->first_worker_index + sm->num_workers - 1,
2670                                (vlib_frame_queue_t *) (~0));
2671     }
2672
2673   from = vlib_frame_vector_args (frame);
2674   n_left_from = frame->n_vectors;
2675
2676   while (n_left_from > 0)
2677     {
2678       u32 bi0;
2679       vlib_buffer_t *b0;
2680       u32 sw_if_index0;
2681       u32 rx_fib_index0;
2682       ip4_header_t * ip0;
2683       u8 do_handoff;
2684
2685       bi0 = from[0];
2686       from += 1;
2687       n_left_from -= 1;
2688
2689       b0 = vlib_get_buffer (vm, bi0);
2690
2691       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2692       rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2693
2694       ip0 = vlib_buffer_get_current (b0);
2695
2696       next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0);
2697
2698       if (PREDICT_FALSE (next_worker_index != thread_index))
2699         {
2700           do_handoff = 1;
2701
2702           if (next_worker_index != current_worker_index)
2703             {
2704               if (hf)
2705                 hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2706
2707               hf = vlib_get_worker_handoff_queue_elt (sm->fq_out2in_index,
2708                                                       next_worker_index,
2709                                                       handoff_queue_elt_by_worker_index);
2710
2711               n_left_to_next_worker = VLIB_FRAME_SIZE - hf->n_vectors;
2712               to_next_worker = &hf->buffer_index[hf->n_vectors];
2713               current_worker_index = next_worker_index;
2714             }
2715
2716           /* enqueue to correct worker thread */
2717           to_next_worker[0] = bi0;
2718           to_next_worker++;
2719           n_left_to_next_worker--;
2720
2721           if (n_left_to_next_worker == 0)
2722             {
2723               hf->n_vectors = VLIB_FRAME_SIZE;
2724               vlib_put_frame_queue_elt (hf);
2725               current_worker_index = ~0;
2726               handoff_queue_elt_by_worker_index[next_worker_index] = 0;
2727               hf = 0;
2728             }
2729         }
2730       else
2731         {
2732           do_handoff = 0;
2733           /* if this is 1st frame */
2734           if (!f)
2735             {
2736               f = vlib_get_frame_to_node (vm, sm->out2in_node_index);
2737               to_next = vlib_frame_vector_args (f);
2738             }
2739
2740           to_next[0] = bi0;
2741           to_next += 1;
2742           f->n_vectors++;
2743         }
2744
2745       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
2746                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2747         {
2748           snat_out2in_worker_handoff_trace_t *t =
2749             vlib_add_trace (vm, node, b0, sizeof (*t));
2750           t->next_worker_index = next_worker_index;
2751           t->do_handoff = do_handoff;
2752         }
2753     }
2754
2755   if (f)
2756     vlib_put_frame_to_node (vm, sm->out2in_node_index, f);
2757
2758   if (hf)
2759     hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker;
2760
2761   /* Ship frames to the worker nodes */
2762   for (i = 0; i < vec_len (handoff_queue_elt_by_worker_index); i++)
2763     {
2764       if (handoff_queue_elt_by_worker_index[i])
2765         {
2766           hf = handoff_queue_elt_by_worker_index[i];
2767           /*
2768            * It works better to let the handoff node
2769            * rate-adapt, always ship the handoff queue element.
2770            */
2771           if (1 || hf->n_vectors == hf->last_n_vectors)
2772             {
2773               vlib_put_frame_queue_elt (hf);
2774               handoff_queue_elt_by_worker_index[i] = 0;
2775             }
2776           else
2777             hf->last_n_vectors = hf->n_vectors;
2778         }
2779       congested_handoff_queue_by_worker_index[i] =
2780         (vlib_frame_queue_t *) (~0);
2781     }
2782   hf = 0;
2783   current_worker_index = ~0;
2784   return frame->n_vectors;
2785 }
2786
2787 VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = {
2788   .function = snat_out2in_worker_handoff_fn,
2789   .name = "nat44-out2in-worker-handoff",
2790   .vector_size = sizeof (u32),
2791   .format_trace = format_snat_out2in_worker_handoff_trace,
2792   .type = VLIB_NODE_TYPE_INTERNAL,
2793
2794   .n_next_nodes = 1,
2795
2796   .next_nodes = {
2797     [0] = "error-drop",
2798   },
2799 };
2800
2801 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_worker_handoff_node, snat_out2in_worker_handoff_fn);
2802
2803 static uword
2804 snat_out2in_fast_node_fn (vlib_main_t * vm,
2805                           vlib_node_runtime_t * node,
2806                           vlib_frame_t * frame)
2807 {
2808   u32 n_left_from, * from, * to_next;
2809   snat_out2in_next_t next_index;
2810   u32 pkts_processed = 0;
2811   snat_main_t * sm = &snat_main;
2812
2813   from = vlib_frame_vector_args (frame);
2814   n_left_from = frame->n_vectors;
2815   next_index = node->cached_next_index;
2816
2817   while (n_left_from > 0)
2818     {
2819       u32 n_left_to_next;
2820
2821       vlib_get_next_frame (vm, node, next_index,
2822                            to_next, n_left_to_next);
2823
2824       while (n_left_from > 0 && n_left_to_next > 0)
2825         {
2826           u32 bi0;
2827           vlib_buffer_t * b0;
2828           u32 next0 = SNAT_OUT2IN_NEXT_DROP;
2829           u32 sw_if_index0;
2830           ip4_header_t * ip0;
2831           ip_csum_t sum0;
2832           u32 new_addr0, old_addr0;
2833           u16 new_port0, old_port0;
2834           udp_header_t * udp0;
2835           tcp_header_t * tcp0;
2836           icmp46_header_t * icmp0;
2837           snat_session_key_t key0, sm0;
2838           u32 proto0;
2839           u32 rx_fib_index0;
2840
2841           /* speculatively enqueue b0 to the current next frame */
2842           bi0 = from[0];
2843           to_next[0] = bi0;
2844           from += 1;
2845           to_next += 1;
2846           n_left_from -= 1;
2847           n_left_to_next -= 1;
2848
2849           b0 = vlib_get_buffer (vm, bi0);
2850
2851           ip0 = vlib_buffer_get_current (b0);
2852           udp0 = ip4_next_header (ip0);
2853           tcp0 = (tcp_header_t *) udp0;
2854           icmp0 = (icmp46_header_t *) udp0;
2855
2856           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2857           rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0);
2858
2859           vnet_feature_next (sw_if_index0, &next0, b0);
2860
2861           if (PREDICT_FALSE(ip0->ttl == 1))
2862             {
2863               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2864               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
2865                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
2866                                            0);
2867               next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
2868               goto trace00;
2869             }
2870
2871           proto0 = ip_proto_to_snat_proto (ip0->protocol);
2872
2873           if (PREDICT_FALSE (proto0 == ~0))
2874               goto trace00;
2875
2876           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
2877             {
2878               next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0,
2879                                   rx_fib_index0, node, next0, ~0, 0, 0);
2880               goto trace00;
2881             }
2882
2883           key0.addr = ip0->dst_address;
2884           key0.port = udp0->dst_port;
2885           key0.fib_index = rx_fib_index0;
2886
2887           if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0, 0))
2888             {
2889               b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
2890               goto trace00;
2891             }
2892
2893           new_addr0 = sm0.addr.as_u32;
2894           new_port0 = sm0.port;
2895           vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm0.fib_index;
2896           old_addr0 = ip0->dst_address.as_u32;
2897           ip0->dst_address.as_u32 = new_addr0;
2898
2899           sum0 = ip0->checksum;
2900           sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2901                                  ip4_header_t,
2902                                  dst_address /* changed member */);
2903           ip0->checksum = ip_csum_fold (sum0);
2904
2905           if (PREDICT_FALSE(new_port0 != udp0->dst_port))
2906             {
2907                if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2908                 {
2909                   old_port0 = tcp0->dst_port;
2910                   tcp0->dst_port = new_port0;
2911
2912                   sum0 = tcp0->checksum;
2913                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2914                                          ip4_header_t,
2915                                          dst_address /* changed member */);
2916
2917                   sum0 = ip_csum_update (sum0, old_port0, new_port0,
2918                                          ip4_header_t /* cheat */,
2919                                          length /* changed member */);
2920                   tcp0->checksum = ip_csum_fold(sum0);
2921                 }
2922               else
2923                 {
2924                   old_port0 = udp0->dst_port;
2925                   udp0->dst_port = new_port0;
2926                   udp0->checksum = 0;
2927                 }
2928             }
2929           else
2930             {
2931               if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
2932                 {
2933                   sum0 = tcp0->checksum;
2934                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
2935                                          ip4_header_t,
2936                                          dst_address /* changed member */);
2937
2938                   tcp0->checksum = ip_csum_fold(sum0);
2939                 }
2940             }
2941
2942         trace00:
2943
2944           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
2945                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2946             {
2947               snat_out2in_trace_t *t =
2948                  vlib_add_trace (vm, node, b0, sizeof (*t));
2949               t->sw_if_index = sw_if_index0;
2950               t->next_index = next0;
2951             }
2952
2953           pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP;
2954
2955           /* verify speculative enqueue, maybe switch current next frame */
2956           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2957                                            to_next, n_left_to_next,
2958                                            bi0, next0);
2959         }
2960
2961       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2962     }
2963
2964   vlib_node_increment_counter (vm, snat_out2in_fast_node.index,
2965                                SNAT_OUT2IN_ERROR_OUT2IN_PACKETS,
2966                                pkts_processed);
2967   return frame->n_vectors;
2968 }
2969
2970 VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
2971   .function = snat_out2in_fast_node_fn,
2972   .name = "nat44-out2in-fast",
2973   .vector_size = sizeof (u32),
2974   .format_trace = format_snat_out2in_fast_trace,
2975   .type = VLIB_NODE_TYPE_INTERNAL,
2976
2977   .n_errors = ARRAY_LEN(snat_out2in_error_strings),
2978   .error_strings = snat_out2in_error_strings,
2979
2980   .runtime_data_bytes = sizeof (snat_runtime_t),
2981
2982   .n_next_nodes = SNAT_OUT2IN_N_NEXT,
2983
2984   /* edit / add dispositions here */
2985   .next_nodes = {
2986     [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
2987     [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
2988     [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2989     [SNAT_OUT2IN_NEXT_REASS] = "nat44-out2in-reass",
2990     [SNAT_OUT2IN_NEXT_IN2OUT] = "nat44-in2out",
2991   },
2992 };
2993 VLIB_NODE_FUNCTION_MULTIARCH (snat_out2in_fast_node, snat_out2in_fast_node_fn);